diff options
author | Jiri Kosina <jkosina@suse.cz> | 2014-11-20 16:42:02 +0300 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-11-20 16:42:02 +0300 |
commit | a02001086bbfb4da35d1228bebc2f1b442db455f (patch) | |
tree | 62ab47936cef06fd08657ca5b6cd1df98c19be57 /drivers/gpu/drm/nouveau | |
parent | eff264efeeb0898408e8c9df72d8a32621035bed (diff) | |
parent | fc14f9c1272f62c3e8d01300f52467c0d9af50f9 (diff) | |
download | linux-a02001086bbfb4da35d1228bebc2f1b442db455f.tar.xz |
Merge Linus' tree to be be to apply submitted patches to newer code than
current trivial.git base
Diffstat (limited to 'drivers/gpu/drm/nouveau')
330 files changed, 18017 insertions, 8226 deletions
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 637c29a33127..40afc69a3778 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -1,5 +1,5 @@ config DRM_NOUVEAU - tristate "Nouveau (nVidia) cards" + tristate "Nouveau (NVIDIA) cards" depends on DRM && PCI select FW_LOADER select DRM_KMS_HELPER @@ -23,7 +23,15 @@ config DRM_NOUVEAU select THERMAL if ACPI && X86 select ACPI_VIDEO if ACPI && X86 help - Choose this option for open-source nVidia support. + Choose this option for open-source NVIDIA support. + +config NOUVEAU_PLATFORM_DRIVER + tristate "Nouveau (NVIDIA) SoC GPUs" + depends on DRM_NOUVEAU && ARCH_TEGRA + default y + help + Support for Nouveau platform driver, used for SoC GPUs as found + on NVIDIA Tegra K1. config NOUVEAU_DEBUG int "Maximum debug level" diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 8b307e143632..12c24c8abf7f 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -14,8 +14,10 @@ nouveau-y += core/core/enum.o nouveau-y += core/core/event.o nouveau-y += core/core/gpuobj.o nouveau-y += core/core/handle.o +nouveau-y += core/core/ioctl.o nouveau-y += core/core/mm.o nouveau-y += core/core/namedb.o +nouveau-y += core/core/notify.o nouveau-y += core/core/object.o nouveau-y += core/core/option.o nouveau-y += core/core/parent.o @@ -26,6 +28,7 @@ nouveau-y += core/core/subdev.o nouveau-y += core/subdev/bar/base.o nouveau-y += core/subdev/bar/nv50.o nouveau-y += core/subdev/bar/nvc0.o +nouveau-y += core/subdev/bar/gk20a.o nouveau-y += core/subdev/bios/base.o nouveau-y += core/subdev/bios/bit.o nouveau-y += core/subdev/bios/boost.o @@ -35,6 +38,7 @@ nouveau-y += core/subdev/bios/dcb.o nouveau-y += core/subdev/bios/disp.o nouveau-y += core/subdev/bios/dp.o nouveau-y += core/subdev/bios/extdev.o +nouveau-y += core/subdev/bios/fan.o nouveau-y += core/subdev/bios/gpio.o nouveau-y += core/subdev/bios/i2c.o nouveau-y += core/subdev/bios/init.o @@ -48,6 +52,8 @@ nouveau-y += core/subdev/bios/therm.o nouveau-y += core/subdev/bios/vmap.o nouveau-y += core/subdev/bios/volt.o nouveau-y += core/subdev/bios/xpio.o +nouveau-y += core/subdev/bios/M0205.o +nouveau-y += core/subdev/bios/M0209.o nouveau-y += core/subdev/bios/P0260.o nouveau-y += core/subdev/bus/hwsq.o nouveau-y += core/subdev/bus/nv04.o @@ -64,6 +70,7 @@ nouveau-y += core/subdev/clock/nva3.o nouveau-y += core/subdev/clock/nvaa.o nouveau-y += core/subdev/clock/nvc0.o nouveau-y += core/subdev/clock/nve0.o +nouveau-y += core/subdev/clock/gk20a.o nouveau-y += core/subdev/clock/pllnv04.o nouveau-y += core/subdev/clock/pllnva3.o nouveau-y += core/subdev/devinit/base.o @@ -120,12 +127,17 @@ nouveau-y += core/subdev/fb/ramnvc0.o nouveau-y += core/subdev/fb/ramnve0.o nouveau-y += core/subdev/fb/ramgk20a.o nouveau-y += core/subdev/fb/ramgm107.o +nouveau-y += core/subdev/fb/sddr2.o nouveau-y += core/subdev/fb/sddr3.o nouveau-y += core/subdev/fb/gddr5.o +nouveau-y += core/subdev/fuse/base.o +nouveau-y += core/subdev/fuse/g80.o +nouveau-y += core/subdev/fuse/gf100.o +nouveau-y += core/subdev/fuse/gm107.o nouveau-y += core/subdev/gpio/base.o nouveau-y += core/subdev/gpio/nv10.o nouveau-y += core/subdev/gpio/nv50.o -nouveau-y += core/subdev/gpio/nv92.o +nouveau-y += core/subdev/gpio/nv94.o nouveau-y += core/subdev/gpio/nvd0.o nouveau-y += core/subdev/gpio/nve0.o nouveau-y += core/subdev/i2c/base.o @@ -149,8 +161,10 @@ nouveau-y += core/subdev/instmem/base.o nouveau-y += core/subdev/instmem/nv04.o nouveau-y += core/subdev/instmem/nv40.o nouveau-y += core/subdev/instmem/nv50.o -nouveau-y += core/subdev/ltcg/gf100.o -nouveau-y += core/subdev/ltcg/gm107.o +nouveau-y += core/subdev/ltc/base.o +nouveau-y += core/subdev/ltc/gf100.o +nouveau-y += core/subdev/ltc/gk104.o +nouveau-y += core/subdev/ltc/gm107.o nouveau-y += core/subdev/mc/base.o nouveau-y += core/subdev/mc/nv04.o nouveau-y += core/subdev/mc/nv40.o @@ -161,6 +175,7 @@ nouveau-y += core/subdev/mc/nv94.o nouveau-y += core/subdev/mc/nv98.o nouveau-y += core/subdev/mc/nvc0.o nouveau-y += core/subdev/mc/nvc3.o +nouveau-y += core/subdev/mc/gk20a.o nouveau-y += core/subdev/mxm/base.o nouveau-y += core/subdev/mxm/mxms.o nouveau-y += core/subdev/mxm/nv50.o @@ -169,6 +184,7 @@ nouveau-y += core/subdev/pwr/memx.o nouveau-y += core/subdev/pwr/nva3.o nouveau-y += core/subdev/pwr/nvc0.o nouveau-y += core/subdev/pwr/nvd0.o +nouveau-y += core/subdev/pwr/gk104.o nouveau-y += core/subdev/pwr/nv108.o nouveau-y += core/subdev/therm/base.o nouveau-y += core/subdev/therm/fan.o @@ -182,6 +198,7 @@ nouveau-y += core/subdev/therm/nv50.o nouveau-y += core/subdev/therm/nv84.o nouveau-y += core/subdev/therm/nva3.o nouveau-y += core/subdev/therm/nvd0.o +nouveau-y += core/subdev/therm/gm107.o nouveau-y += core/subdev/timer/base.o nouveau-y += core/subdev/timer/nv04.o nouveau-y += core/subdev/timer/gk20a.o @@ -211,6 +228,7 @@ nouveau-y += core/engine/copy/nvc0.o nouveau-y += core/engine/copy/nve0.o nouveau-y += core/engine/crypt/nv84.o nouveau-y += core/engine/crypt/nv98.o +nouveau-y += core/engine/device/acpi.o nouveau-y += core/engine/device/base.o nouveau-y += core/engine/device/ctrl.o nouveau-y += core/engine/device/nv04.o @@ -243,6 +261,7 @@ nouveau-y += core/engine/disp/hdanvd0.o nouveau-y += core/engine/disp/hdminv84.o nouveau-y += core/engine/disp/hdminva3.o nouveau-y += core/engine/disp/hdminvd0.o +nouveau-y += core/engine/disp/hdminve0.o nouveau-y += core/engine/disp/piornv50.o nouveau-y += core/engine/disp/sornv50.o nouveau-y += core/engine/disp/sornv94.o @@ -270,6 +289,7 @@ nouveau-y += core/engine/graph/ctxnvd9.o nouveau-y += core/engine/graph/ctxnve4.o nouveau-y += core/engine/graph/ctxgk20a.o nouveau-y += core/engine/graph/ctxnvf0.o +nouveau-y += core/engine/graph/ctxgk110b.o nouveau-y += core/engine/graph/ctxnv108.o nouveau-y += core/engine/graph/ctxgm107.o nouveau-y += core/engine/graph/nv04.o @@ -291,6 +311,7 @@ nouveau-y += core/engine/graph/nvd9.o nouveau-y += core/engine/graph/nve4.o nouveau-y += core/engine/graph/gk20a.o nouveau-y += core/engine/graph/nvf0.o +nouveau-y += core/engine/graph/gk110b.o nouveau-y += core/engine/graph/nv108.o nouveau-y += core/engine/graph/gm107.o nouveau-y += core/engine/mpeg/nv31.o @@ -318,11 +339,18 @@ nouveau-y += core/engine/vp/nv98.o nouveau-y += core/engine/vp/nvc0.o nouveau-y += core/engine/vp/nve0.o +# nvif +nouveau-y += nvif/object.o +nouveau-y += nvif/client.o +nouveau-y += nvif/device.o +nouveau-y += nvif/notify.o + # drm/core nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o nouveau-y += nouveau_vga.o nouveau_agp.o nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o nouveau-y += nouveau_prime.o nouveau_abi16.o +nouveau-y += nouveau_nvif.o nouveau_usif.o nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o @@ -349,3 +377,6 @@ nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o + +# platform driver +obj-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c index 9079c0ac58e6..e962433294c3 100644 --- a/drivers/gpu/drm/nouveau/core/core/client.c +++ b/drivers/gpu/drm/nouveau/core/core/client.c @@ -26,13 +26,168 @@ #include <core/client.h> #include <core/handle.h> #include <core/option.h> +#include <nvif/unpack.h> +#include <nvif/class.h> + +#include <nvif/unpack.h> +#include <nvif/event.h> #include <engine/device.h> +struct nvkm_client_notify { + struct nouveau_client *client; + struct nvkm_notify n; + u8 version; + u8 size; + union { + struct nvif_notify_rep_v0 v0; + } rep; +}; + +static int +nvkm_client_notify(struct nvkm_notify *n) +{ + struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n); + struct nouveau_client *client = notify->client; + return client->ntfy(¬ify->rep, notify->size, n->data, n->size); +} + +int +nvkm_client_notify_put(struct nouveau_client *client, int index) +{ + if (index < ARRAY_SIZE(client->notify)) { + if (client->notify[index]) { + nvkm_notify_put(&client->notify[index]->n); + return 0; + } + } + return -ENOENT; +} + +int +nvkm_client_notify_get(struct nouveau_client *client, int index) +{ + if (index < ARRAY_SIZE(client->notify)) { + if (client->notify[index]) { + nvkm_notify_get(&client->notify[index]->n); + return 0; + } + } + return -ENOENT; +} + +int +nvkm_client_notify_del(struct nouveau_client *client, int index) +{ + if (index < ARRAY_SIZE(client->notify)) { + if (client->notify[index]) { + nvkm_notify_fini(&client->notify[index]->n); + kfree(client->notify[index]); + client->notify[index] = NULL; + return 0; + } + } + return -ENOENT; +} + +int +nvkm_client_notify_new(struct nouveau_object *object, + struct nvkm_event *event, void *data, u32 size) +{ + struct nouveau_client *client = nouveau_client(object); + struct nvkm_client_notify *notify; + union { + struct nvif_notify_req_v0 v0; + } *req = data; + u8 index, reply; + int ret; + + for (index = 0; index < ARRAY_SIZE(client->notify); index++) { + if (!client->notify[index]) + break; + } + + if (index == ARRAY_SIZE(client->notify)) + return -ENOSPC; + + notify = kzalloc(sizeof(*notify), GFP_KERNEL); + if (!notify) + return -ENOMEM; + + nv_ioctl(client, "notify new size %d\n", size); + if (nvif_unpack(req->v0, 0, 0, true)) { + nv_ioctl(client, "notify new vers %d reply %d route %02x " + "token %llx\n", req->v0.version, + req->v0.reply, req->v0.route, req->v0.token); + notify->version = req->v0.version; + notify->size = sizeof(notify->rep.v0); + notify->rep.v0.version = req->v0.version; + notify->rep.v0.route = req->v0.route; + notify->rep.v0.token = req->v0.token; + reply = req->v0.reply; + } + + if (ret == 0) { + ret = nvkm_notify_init(object, event, nvkm_client_notify, + false, data, size, reply, ¬ify->n); + if (ret == 0) { + client->notify[index] = notify; + notify->client = client; + return index; + } + } + + kfree(notify); + return ret; +} + +static int +nouveau_client_devlist(struct nouveau_object *object, void *data, u32 size) +{ + union { + struct nv_client_devlist_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "client devlist size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "client devlist vers %d count %d\n", + args->v0.version, args->v0.count); + if (size == sizeof(args->v0.device[0]) * args->v0.count) { + ret = nouveau_device_list(args->v0.device, + args->v0.count); + if (ret >= 0) { + args->v0.count = ret; + ret = 0; + } + } else { + ret = -EINVAL; + } + } + + return ret; +} + +static int +nouveau_client_mthd(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + switch (mthd) { + case NV_CLIENT_DEVLIST: + return nouveau_client_devlist(object, data, size); + default: + break; + } + return -EINVAL; +} + static void nouveau_client_dtor(struct nouveau_object *object) { struct nouveau_client *client = (void *)object; + int i; + for (i = 0; i < ARRAY_SIZE(client->notify); i++) + nvkm_client_notify_del(client, i); nouveau_object_ref(NULL, &client->device); nouveau_handle_destroy(client->root); nouveau_namedb_destroy(&client->base); @@ -42,6 +197,7 @@ static struct nouveau_oclass nouveau_client_oclass = { .ofuncs = &(struct nouveau_ofuncs) { .dtor = nouveau_client_dtor, + .mthd = nouveau_client_mthd, }, }; @@ -93,9 +249,12 @@ int nouveau_client_fini(struct nouveau_client *client, bool suspend) { const char *name[2] = { "fini", "suspend" }; - int ret; - + int ret, i; nv_debug(client, "%s running\n", name[suspend]); + nv_debug(client, "%s notify\n", name[suspend]); + for (i = 0; i < ARRAY_SIZE(client->notify); i++) + nvkm_client_notify_put(client, i); + nv_debug(client, "%s object\n", name[suspend]); ret = nouveau_handle_fini(client->root, suspend); nv_debug(client, "%s completed with %d\n", name[suspend], ret); return ret; diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c index ae81d3b5d8b7..ff2b434b3db4 100644 --- a/drivers/gpu/drm/nouveau/core/core/event.c +++ b/drivers/gpu/drm/nouveau/core/core/event.c @@ -1,5 +1,5 @@ /* - * Copyright 2013 Red Hat Inc. + * Copyright 2013-2014 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"), @@ -20,177 +20,81 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include <core/os.h> +#include <core/object.h> #include <core/event.h> void -nouveau_event_put(struct nouveau_eventh *handler) +nvkm_event_put(struct nvkm_event *event, u32 types, int index) { - struct nouveau_event *event = handler->event; - unsigned long flags; - u32 m, t; - - if (!__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags)) - return; - - spin_lock_irqsave(&event->refs_lock, flags); - for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) { - if (!--event->refs[handler->index * event->types_nr + t]) { - if (event->disable) - event->disable(event, 1 << t, handler->index); + BUG_ON(!spin_is_locked(&event->refs_lock)); + while (types) { + int type = __ffs(types); types &= ~(1 << type); + if (--event->refs[index * event->types_nr + type] == 0) { + if (event->func->fini) + event->func->fini(event, 1 << type, index); } - } - spin_unlock_irqrestore(&event->refs_lock, flags); } void -nouveau_event_get(struct nouveau_eventh *handler) +nvkm_event_get(struct nvkm_event *event, u32 types, int index) { - struct nouveau_event *event = handler->event; - unsigned long flags; - u32 m, t; - - if (__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) - return; - - spin_lock_irqsave(&event->refs_lock, flags); - for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) { - if (!event->refs[handler->index * event->types_nr + t]++) { - if (event->enable) - event->enable(event, 1 << t, handler->index); + BUG_ON(!spin_is_locked(&event->refs_lock)); + while (types) { + int type = __ffs(types); types &= ~(1 << type); + if (++event->refs[index * event->types_nr + type] == 1) { + if (event->func->init) + event->func->init(event, 1 << type, index); } - } - spin_unlock_irqrestore(&event->refs_lock, flags); -} - -static void -nouveau_event_fini(struct nouveau_eventh *handler) -{ - struct nouveau_event *event = handler->event; - unsigned long flags; - nouveau_event_put(handler); - spin_lock_irqsave(&event->list_lock, flags); - list_del(&handler->head); - spin_unlock_irqrestore(&event->list_lock, flags); -} - -static int -nouveau_event_init(struct nouveau_event *event, u32 types, int index, - int (*func)(void *, u32, int), void *priv, - struct nouveau_eventh *handler) -{ - unsigned long flags; - - if (types & ~((1 << event->types_nr) - 1)) - return -EINVAL; - if (index >= event->index_nr) - return -EINVAL; - - handler->event = event; - handler->flags = 0; - handler->types = types; - handler->index = index; - handler->func = func; - handler->priv = priv; - - spin_lock_irqsave(&event->list_lock, flags); - list_add_tail(&handler->head, &event->list[index]); - spin_unlock_irqrestore(&event->list_lock, flags); - return 0; -} - -int -nouveau_event_new(struct nouveau_event *event, u32 types, int index, - int (*func)(void *, u32, int), void *priv, - struct nouveau_eventh **phandler) -{ - struct nouveau_eventh *handler; - int ret = -ENOMEM; - - if (event->check) { - ret = event->check(event, types, index); - if (ret) - return ret; - } - - handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL); - if (handler) { - ret = nouveau_event_init(event, types, index, func, priv, handler); - if (ret) - kfree(handler); - } - - return ret; -} - -void -nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref) -{ - BUG_ON(handler != NULL); - if (*ref) { - nouveau_event_fini(*ref); - kfree(*ref); - } - *ref = handler; } void -nouveau_event_trigger(struct nouveau_event *event, u32 types, int index) +nvkm_event_send(struct nvkm_event *event, u32 types, int index, + void *data, u32 size) { - struct nouveau_eventh *handler; + struct nvkm_notify *notify; unsigned long flags; - if (WARN_ON(index >= event->index_nr)) + if (!event->refs || WARN_ON(index >= event->index_nr)) return; spin_lock_irqsave(&event->list_lock, flags); - list_for_each_entry(handler, &event->list[index], head) { - if (!test_bit(NVKM_EVENT_ENABLE, &handler->flags)) - continue; - if (!(handler->types & types)) - continue; - if (handler->func(handler->priv, handler->types & types, index) - != NVKM_EVENT_DROP) - continue; - nouveau_event_put(handler); + list_for_each_entry(notify, &event->list, head) { + if (notify->index == index && (notify->types & types)) { + if (event->func->send) { + event->func->send(data, size, notify); + continue; + } + nvkm_notify_send(notify, data, size); + } } spin_unlock_irqrestore(&event->list_lock, flags); } void -nouveau_event_destroy(struct nouveau_event **pevent) +nvkm_event_fini(struct nvkm_event *event) { - struct nouveau_event *event = *pevent; - if (event) { - kfree(event); - *pevent = NULL; + if (event->refs) { + kfree(event->refs); + event->refs = NULL; } } int -nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **pevent) +nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr, + struct nvkm_event *event) { - struct nouveau_event *event; - int i; - - event = *pevent = kzalloc(sizeof(*event) + (index_nr * types_nr) * - sizeof(event->refs[0]), GFP_KERNEL); - if (!event) - return -ENOMEM; - - event->list = kmalloc(sizeof(*event->list) * index_nr, GFP_KERNEL); - if (!event->list) { - kfree(event); + event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr, + GFP_KERNEL); + if (!event->refs) return -ENOMEM; - } - spin_lock_init(&event->list_lock); - spin_lock_init(&event->refs_lock); - for (i = 0; i < index_nr; i++) - INIT_LIST_HEAD(&event->list[i]); + event->func = func; event->types_nr = types_nr; event->index_nr = index_nr; + spin_lock_init(&event->refs_lock); + spin_lock_init(&event->list_lock); + INIT_LIST_HEAD(&event->list); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/core/gpuobj.c b/drivers/gpu/drm/nouveau/core/core/gpuobj.c index 560b2214cf1c..daee87702502 100644 --- a/drivers/gpu/drm/nouveau/core/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/core/core/gpuobj.c @@ -115,7 +115,7 @@ nouveau_gpuobj_create_(struct nouveau_object *parent, gpuobj->size = size; if (heap) { - ret = nouveau_mm_head(heap, 1, size, size, + ret = nouveau_mm_head(heap, 0, 1, size, size, max(align, (u32)1), &gpuobj->node); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/core/handle.c b/drivers/gpu/drm/nouveau/core/core/handle.c index 264c2b338ac3..a490b805d7e3 100644 --- a/drivers/gpu/drm/nouveau/core/core/handle.c +++ b/drivers/gpu/drm/nouveau/core/core/handle.c @@ -146,9 +146,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, } hprintk(handle, TRACE, "created\n"); - *phandle = handle; - return 0; } @@ -224,3 +222,116 @@ nouveau_handle_put(struct nouveau_handle *handle) if (handle) nouveau_namedb_put(handle); } + +int +nouveau_handle_new(struct nouveau_object *client, u32 _parent, u32 _handle, + u16 _oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_object *parent = NULL; + struct nouveau_object *engctx = NULL; + struct nouveau_object *object = NULL; + struct nouveau_object *engine; + struct nouveau_oclass *oclass; + struct nouveau_handle *handle; + int ret; + + /* lookup parent object and ensure it *is* a parent */ + parent = nouveau_handle_ref(client, _parent); + if (!parent) { + nv_error(client, "parent 0x%08x not found\n", _parent); + return -ENOENT; + } + + if (!nv_iclass(parent, NV_PARENT_CLASS)) { + nv_error(parent, "cannot have children\n"); + ret = -EINVAL; + goto fail_class; + } + + /* check that parent supports the requested subclass */ + ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass); + if (ret) { + nv_debug(parent, "illegal class 0x%04x\n", _oclass); + goto fail_class; + } + + /* make sure engine init has been completed *before* any objects + * it controls are created - the constructors may depend on + * state calculated at init (ie. default context construction) + */ + if (engine) { + ret = nouveau_object_inc(engine); + if (ret) + goto fail_class; + } + + /* if engine requires it, create a context object to insert + * between the parent and its children (eg. PGRAPH context) + */ + if (engine && nv_engine(engine)->cclass) { + ret = nouveau_object_ctor(parent, engine, + nv_engine(engine)->cclass, + data, size, &engctx); + if (ret) + goto fail_engctx; + } else { + nouveau_object_ref(parent, &engctx); + } + + /* finally, create new object and bind it to its handle */ + ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object); + *pobject = object; + if (ret) + goto fail_ctor; + + ret = nouveau_object_inc(object); + if (ret) + goto fail_init; + + ret = nouveau_handle_create(parent, _parent, _handle, object, &handle); + if (ret) + goto fail_handle; + + ret = nouveau_handle_init(handle); + if (ret) + nouveau_handle_destroy(handle); + +fail_handle: + nouveau_object_dec(object, false); +fail_init: + nouveau_object_ref(NULL, &object); +fail_ctor: + nouveau_object_ref(NULL, &engctx); +fail_engctx: + if (engine) + nouveau_object_dec(engine, false); +fail_class: + nouveau_object_ref(NULL, &parent); + return ret; +} + +int +nouveau_handle_del(struct nouveau_object *client, u32 _parent, u32 _handle) +{ + struct nouveau_object *parent = NULL; + struct nouveau_object *namedb = NULL; + struct nouveau_handle *handle = NULL; + + parent = nouveau_handle_ref(client, _parent); + if (!parent) + return -ENOENT; + + namedb = nv_pclass(parent, NV_NAMEDB_CLASS); + if (namedb) { + handle = nouveau_namedb_get(nv_namedb(namedb), _handle); + if (handle) { + nouveau_namedb_put(handle); + nouveau_handle_fini(handle, false); + nouveau_handle_destroy(handle); + } + } + + nouveau_object_ref(NULL, &parent); + return handle ? 0 : -EINVAL; +} diff --git a/drivers/gpu/drm/nouveau/core/core/ioctl.c b/drivers/gpu/drm/nouveau/core/core/ioctl.c new file mode 100644 index 000000000000..692aa92dd850 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/ioctl.c @@ -0,0 +1,530 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +#include <core/object.h> +#include <core/parent.h> +#include <core/handle.h> +#include <core/namedb.h> +#include <core/client.h> +#include <core/device.h> +#include <core/ioctl.h> +#include <core/event.h> + +#include <nvif/unpack.h> +#include <nvif/ioctl.h> + +static int +nvkm_ioctl_nop(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + union { + struct nvif_ioctl_nop none; + } *args = data; + int ret; + + nv_ioctl(object, "nop size %d\n", size); + if (nvif_unvers(args->none)) { + nv_ioctl(object, "nop\n"); + } + + return ret; +} + +static int +nvkm_ioctl_sclass(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + union { + struct nvif_ioctl_sclass_v0 v0; + } *args = data; + int ret; + + if (!nv_iclass(object, NV_PARENT_CLASS)) { + nv_debug(object, "cannot have children (sclass)\n"); + return -ENODEV; + } + + nv_ioctl(object, "sclass size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "sclass vers %d count %d\n", + args->v0.version, args->v0.count); + if (size == args->v0.count * sizeof(args->v0.oclass[0])) { + ret = nouveau_parent_lclass(object, args->v0.oclass, + args->v0.count); + if (ret >= 0) { + args->v0.count = ret; + ret = 0; + } + } else { + ret = -EINVAL; + } + } + + return ret; +} + +static int +nvkm_ioctl_new(struct nouveau_handle *parent, void *data, u32 size) +{ + union { + struct nvif_ioctl_new_v0 v0; + } *args = data; + struct nouveau_client *client = nouveau_client(parent->object); + struct nouveau_object *engctx = NULL; + struct nouveau_object *object = NULL; + struct nouveau_object *engine; + struct nouveau_oclass *oclass; + struct nouveau_handle *handle; + u32 _handle, _oclass; + int ret; + + nv_ioctl(client, "new size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + _handle = args->v0.handle; + _oclass = args->v0.oclass; + } else + return ret; + + nv_ioctl(client, "new vers %d handle %08x class %08x " + "route %02x token %llx\n", + args->v0.version, _handle, _oclass, + args->v0.route, args->v0.token); + + if (!nv_iclass(parent->object, NV_PARENT_CLASS)) { + nv_debug(parent->object, "cannot have children (ctor)\n"); + ret = -ENODEV; + goto fail_class; + } + + /* check that parent supports the requested subclass */ + ret = nouveau_parent_sclass(parent->object, _oclass, &engine, &oclass); + if (ret) { + nv_debug(parent->object, "illegal class 0x%04x\n", _oclass); + goto fail_class; + } + + /* make sure engine init has been completed *before* any objects + * it controls are created - the constructors may depend on + * state calculated at init (ie. default context construction) + */ + if (engine) { + ret = nouveau_object_inc(engine); + if (ret) + goto fail_class; + } + + /* if engine requires it, create a context object to insert + * between the parent and its children (eg. PGRAPH context) + */ + if (engine && nv_engine(engine)->cclass) { + ret = nouveau_object_ctor(parent->object, engine, + nv_engine(engine)->cclass, + data, size, &engctx); + if (ret) + goto fail_engctx; + } else { + nouveau_object_ref(parent->object, &engctx); + } + + /* finally, create new object and bind it to its handle */ + ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object); + client->data = object; + if (ret) + goto fail_ctor; + + ret = nouveau_object_inc(object); + if (ret) + goto fail_init; + + ret = nouveau_handle_create(parent->object, parent->name, + _handle, object, &handle); + if (ret) + goto fail_handle; + + ret = nouveau_handle_init(handle); + handle->route = args->v0.route; + handle->token = args->v0.token; + if (ret) + nouveau_handle_destroy(handle); + +fail_handle: + nouveau_object_dec(object, false); +fail_init: + nouveau_object_ref(NULL, &object); +fail_ctor: + nouveau_object_ref(NULL, &engctx); +fail_engctx: + if (engine) + nouveau_object_dec(engine, false); +fail_class: + return ret; +} + +static int +nvkm_ioctl_del(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + union { + struct nvif_ioctl_del none; + } *args = data; + int ret; + + nv_ioctl(object, "delete size %d\n", size); + if (nvif_unvers(args->none)) { + nv_ioctl(object, "delete\n"); + nouveau_handle_fini(handle, false); + nouveau_handle_destroy(handle); + } + + return ret; +} + +static int +nvkm_ioctl_mthd(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs; + union { + struct nvif_ioctl_mthd_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "mthd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "mthd vers %d mthd %02x\n", + args->v0.version, args->v0.method); + if (ret = -ENODEV, ofuncs->mthd) + ret = ofuncs->mthd(object, args->v0.method, data, size); + } + + return ret; +} + + +static int +nvkm_ioctl_rd(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs; + union { + struct nvif_ioctl_rd_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "rd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "rd vers %d size %d addr %016llx\n", + args->v0.version, args->v0.size, args->v0.addr); + switch (args->v0.size) { + case 1: + if (ret = -ENODEV, ofuncs->rd08) { + args->v0.data = nv_ro08(object, args->v0.addr); + ret = 0; + } + break; + case 2: + if (ret = -ENODEV, ofuncs->rd16) { + args->v0.data = nv_ro16(object, args->v0.addr); + ret = 0; + } + break; + case 4: + if (ret = -ENODEV, ofuncs->rd32) { + args->v0.data = nv_ro32(object, args->v0.addr); + ret = 0; + } + break; + default: + ret = -EINVAL; + break; + } + } + + return ret; +} + +static int +nvkm_ioctl_wr(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs; + union { + struct nvif_ioctl_wr_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "wr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n", + args->v0.version, args->v0.size, args->v0.addr, + args->v0.data); + switch (args->v0.size) { + case 1: + if (ret = -ENODEV, ofuncs->wr08) { + nv_wo08(object, args->v0.addr, args->v0.data); + ret = 0; + } + break; + case 2: + if (ret = -ENODEV, ofuncs->wr16) { + nv_wo16(object, args->v0.addr, args->v0.data); + ret = 0; + } + break; + case 4: + if (ret = -ENODEV, ofuncs->wr32) { + nv_wo32(object, args->v0.addr, args->v0.data); + ret = 0; + } + break; + default: + ret = -EINVAL; + break; + } + } + + return ret; +} + +static int +nvkm_ioctl_map(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs; + union { + struct nvif_ioctl_map_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "map size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "map vers %d\n", args->v0.version); + if (ret = -ENODEV, ofuncs->map) { + ret = ofuncs->map(object, &args->v0.handle, + &args->v0.length); + } + } + + return ret; +} + +static int +nvkm_ioctl_unmap(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + union { + struct nvif_ioctl_unmap none; + } *args = data; + int ret; + + nv_ioctl(object, "unmap size %d\n", size); + if (nvif_unvers(args->none)) { + nv_ioctl(object, "unmap\n"); + } + + return ret; +} + +static int +nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_object *object = handle->object; + struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs; + union { + struct nvif_ioctl_ntfy_new_v0 v0; + } *args = data; + struct nvkm_event *event; + int ret; + + nv_ioctl(object, "ntfy new size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "ntfy new vers %d event %02x\n", + args->v0.version, args->v0.event); + if (ret = -ENODEV, ofuncs->ntfy) + ret = ofuncs->ntfy(object, args->v0.event, &event); + if (ret == 0) { + ret = nvkm_client_notify_new(object, event, data, size); + if (ret >= 0) { + args->v0.index = ret; + ret = 0; + } + } + } + + return ret; +} + +static int +nvkm_ioctl_ntfy_del(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_client *client = nouveau_client(handle->object); + struct nouveau_object *object = handle->object; + union { + struct nvif_ioctl_ntfy_del_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "ntfy del size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "ntfy del vers %d index %d\n", + args->v0.version, args->v0.index); + ret = nvkm_client_notify_del(client, args->v0.index); + } + + return ret; +} + +static int +nvkm_ioctl_ntfy_get(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_client *client = nouveau_client(handle->object); + struct nouveau_object *object = handle->object; + union { + struct nvif_ioctl_ntfy_get_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "ntfy get size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "ntfy get vers %d index %d\n", + args->v0.version, args->v0.index); + ret = nvkm_client_notify_get(client, args->v0.index); + } + + return ret; +} + +static int +nvkm_ioctl_ntfy_put(struct nouveau_handle *handle, void *data, u32 size) +{ + struct nouveau_client *client = nouveau_client(handle->object); + struct nouveau_object *object = handle->object; + union { + struct nvif_ioctl_ntfy_put_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "ntfy put size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "ntfy put vers %d index %d\n", + args->v0.version, args->v0.index); + ret = nvkm_client_notify_put(client, args->v0.index); + } + + return ret; +} + +static struct { + int version; + int (*func)(struct nouveau_handle *, void *, u32); +} +nvkm_ioctl_v0[] = { + { 0x00, nvkm_ioctl_nop }, + { 0x00, nvkm_ioctl_sclass }, + { 0x00, nvkm_ioctl_new }, + { 0x00, nvkm_ioctl_del }, + { 0x00, nvkm_ioctl_mthd }, + { 0x00, nvkm_ioctl_rd }, + { 0x00, nvkm_ioctl_wr }, + { 0x00, nvkm_ioctl_map }, + { 0x00, nvkm_ioctl_unmap }, + { 0x00, nvkm_ioctl_ntfy_new }, + { 0x00, nvkm_ioctl_ntfy_del }, + { 0x00, nvkm_ioctl_ntfy_get }, + { 0x00, nvkm_ioctl_ntfy_put }, +}; + +static int +nvkm_ioctl_path(struct nouveau_handle *parent, u32 type, u32 nr, + u32 *path, void *data, u32 size, + u8 owner, u8 *route, u64 *token) +{ + struct nouveau_handle *handle = parent; + struct nouveau_namedb *namedb; + struct nouveau_object *object; + int ret; + + while ((object = parent->object), nr--) { + nv_ioctl(object, "path 0x%08x\n", path[nr]); + if (!nv_iclass(object, NV_PARENT_CLASS)) { + nv_debug(object, "cannot have children (path)\n"); + return -EINVAL; + } + + if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) || + !(handle = nouveau_namedb_get(namedb, path[nr]))) { + nv_debug(object, "handle 0x%08x not found\n", path[nr]); + return -ENOENT; + } + nouveau_namedb_put(handle); + parent = handle; + } + + if (owner != NVIF_IOCTL_V0_OWNER_ANY && + owner != handle->route) { + nv_ioctl(object, "object route != owner\n"); + return -EACCES; + } + *route = handle->route; + *token = handle->token; + + if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) { + if (nvkm_ioctl_v0[type].version == 0) { + ret = nvkm_ioctl_v0[type].func(handle, data, size); + } + } + + return ret; +} + +int +nvkm_ioctl(struct nouveau_client *client, bool supervisor, + void *data, u32 size, void **hack) +{ + union { + struct nvif_ioctl_v0 v0; + } *args = data; + int ret; + + client->super = supervisor; + nv_ioctl(client, "size %d\n", size); + + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(client, "vers %d type %02x path %d owner %02x\n", + args->v0.version, args->v0.type, args->v0.path_nr, + args->v0.owner); + ret = nvkm_ioctl_path(client->root, args->v0.type, + args->v0.path_nr, args->v0.path, + data, size, args->v0.owner, + &args->v0.route, &args->v0.token); + } + + nv_ioctl(client, "return %d\n", ret); + if (hack) { + *hack = client->data; + client->data = NULL; + } + client->super = false; + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c index 7a4e0891c5f8..b4f5db66d5b5 100644 --- a/drivers/gpu/drm/nouveau/core/core/mm.c +++ b/drivers/gpu/drm/nouveau/core/core/mm.c @@ -28,6 +28,24 @@ #define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \ list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) +static void +nouveau_mm_dump(struct nouveau_mm *mm, const char *header) +{ + struct nouveau_mm_node *node; + + printk(KERN_ERR "nouveau: %s\n", header); + printk(KERN_ERR "nouveau: node list:\n"); + list_for_each_entry(node, &mm->nodes, nl_entry) { + printk(KERN_ERR "nouveau: \t%08x %08x %d\n", + node->offset, node->length, node->type); + } + printk(KERN_ERR "nouveau: free list:\n"); + list_for_each_entry(node, &mm->free, fl_entry) { + printk(KERN_ERR "nouveau: \t%08x %08x %d\n", + node->offset, node->length, node->type); + } +} + void nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis) { @@ -37,29 +55,29 @@ nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis) struct nouveau_mm_node *prev = node(this, prev); struct nouveau_mm_node *next = node(this, next); - if (prev && prev->type == 0) { + if (prev && prev->type == NVKM_MM_TYPE_NONE) { prev->length += this->length; list_del(&this->nl_entry); kfree(this); this = prev; } - if (next && next->type == 0) { + if (next && next->type == NVKM_MM_TYPE_NONE) { next->offset = this->offset; next->length += this->length; - if (this->type == 0) + if (this->type == NVKM_MM_TYPE_NONE) list_del(&this->fl_entry); list_del(&this->nl_entry); kfree(this); this = NULL; } - if (this && this->type != 0) { + if (this && this->type != NVKM_MM_TYPE_NONE) { list_for_each_entry(prev, &mm->free, fl_entry) { if (this->offset < prev->offset) break; } list_add_tail(&this->fl_entry, &prev->fl_entry); - this->type = 0; + this->type = NVKM_MM_TYPE_NONE; } } @@ -80,27 +98,32 @@ region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) b->offset = a->offset; b->length = size; + b->heap = a->heap; b->type = a->type; a->offset += size; a->length -= size; list_add_tail(&b->nl_entry, &a->nl_entry); - if (b->type == 0) + if (b->type == NVKM_MM_TYPE_NONE) list_add_tail(&b->fl_entry, &a->fl_entry); return b; } int -nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, - u32 align, struct nouveau_mm_node **pnode) +nouveau_mm_head(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max, + u32 size_min, u32 align, struct nouveau_mm_node **pnode) { struct nouveau_mm_node *prev, *this, *next; u32 mask = align - 1; u32 splitoff; u32 s, e; - BUG_ON(!type); + BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE); list_for_each_entry(this, &mm->free, fl_entry) { + if (unlikely(heap != NVKM_MM_HEAP_ANY)) { + if (this->heap != heap) + continue; + } e = this->offset + this->length; s = this->offset; @@ -149,27 +172,32 @@ region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) a->length -= size; b->offset = a->offset + a->length; b->length = size; + b->heap = a->heap; b->type = a->type; list_add(&b->nl_entry, &a->nl_entry); - if (b->type == 0) + if (b->type == NVKM_MM_TYPE_NONE) list_add(&b->fl_entry, &a->fl_entry); return b; } int -nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, - u32 align, struct nouveau_mm_node **pnode) +nouveau_mm_tail(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max, + u32 size_min, u32 align, struct nouveau_mm_node **pnode) { struct nouveau_mm_node *prev, *this, *next; u32 mask = align - 1; - BUG_ON(!type); + BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE); list_for_each_entry_reverse(this, &mm->free, fl_entry) { u32 e = this->offset + this->length; u32 s = this->offset; u32 c = 0, a; + if (unlikely(heap != NVKM_MM_HEAP_ANY)) { + if (this->heap != heap) + continue; + } prev = node(this, prev); if (prev && prev->type != type) @@ -209,9 +237,23 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, int nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) { - struct nouveau_mm_node *node; + struct nouveau_mm_node *node, *prev; + u32 next; - if (block) { + if (nouveau_mm_initialised(mm)) { + prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry); + next = prev->offset + prev->length; + if (next != offset) { + BUG_ON(next > offset); + if (!(node = kzalloc(sizeof(*node), GFP_KERNEL))) + return -ENOMEM; + node->type = NVKM_MM_TYPE_HOLE; + node->offset = next; + node->length = offset - next; + list_add_tail(&node->nl_entry, &mm->nodes); + } + BUG_ON(block != mm->block_size); + } else { INIT_LIST_HEAD(&mm->nodes); INIT_LIST_HEAD(&mm->free); mm->block_size = block; @@ -230,25 +272,32 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) list_add_tail(&node->nl_entry, &mm->nodes); list_add_tail(&node->fl_entry, &mm->free); - mm->heap_nodes++; + node->heap = ++mm->heap_nodes; return 0; } int nouveau_mm_fini(struct nouveau_mm *mm) { - if (nouveau_mm_initialised(mm)) { - struct nouveau_mm_node *node, *heap = - list_first_entry(&mm->nodes, typeof(*heap), nl_entry); - int nodes = 0; + struct nouveau_mm_node *node, *temp; + int nodes = 0; - list_for_each_entry(node, &mm->nodes, nl_entry) { - if (WARN_ON(nodes++ == mm->heap_nodes)) + if (!nouveau_mm_initialised(mm)) + return 0; + + list_for_each_entry(node, &mm->nodes, nl_entry) { + if (node->type != NVKM_MM_TYPE_HOLE) { + if (++nodes > mm->heap_nodes) { + nouveau_mm_dump(mm, "mm not clean!"); return -EBUSY; + } } - - kfree(heap); } + list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) { + list_del(&node->nl_entry); + kfree(node); + } + mm->heap_nodes = 0; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/core/notify.c b/drivers/gpu/drm/nouveau/core/core/notify.c new file mode 100644 index 000000000000..d1bcde55e9d7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/notify.c @@ -0,0 +1,168 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +#include <core/client.h> +#include <core/event.h> +#include <core/notify.h> + +#include <nvif/unpack.h> +#include <nvif/event.h> + +static inline void +nvkm_notify_put_locked(struct nvkm_notify *notify) +{ + if (notify->block++ == 0) + nvkm_event_put(notify->event, notify->types, notify->index); +} + +void +nvkm_notify_put(struct nvkm_notify *notify) +{ + struct nvkm_event *event = notify->event; + unsigned long flags; + if (likely(event) && + test_and_clear_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { + spin_lock_irqsave(&event->refs_lock, flags); + nvkm_notify_put_locked(notify); + spin_unlock_irqrestore(&event->refs_lock, flags); + if (test_bit(NVKM_NOTIFY_WORK, ¬ify->flags)) + flush_work(¬ify->work); + } +} + +static inline void +nvkm_notify_get_locked(struct nvkm_notify *notify) +{ + if (--notify->block == 0) + nvkm_event_get(notify->event, notify->types, notify->index); +} + +void +nvkm_notify_get(struct nvkm_notify *notify) +{ + struct nvkm_event *event = notify->event; + unsigned long flags; + if (likely(event) && + !test_and_set_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { + spin_lock_irqsave(&event->refs_lock, flags); + nvkm_notify_get_locked(notify); + spin_unlock_irqrestore(&event->refs_lock, flags); + } +} + +static inline void +nvkm_notify_func(struct nvkm_notify *notify) +{ + struct nvkm_event *event = notify->event; + int ret = notify->func(notify); + unsigned long flags; + if ((ret == NVKM_NOTIFY_KEEP) || + !test_and_clear_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { + spin_lock_irqsave(&event->refs_lock, flags); + nvkm_notify_get_locked(notify); + spin_unlock_irqrestore(&event->refs_lock, flags); + } +} + +static void +nvkm_notify_work(struct work_struct *work) +{ + struct nvkm_notify *notify = container_of(work, typeof(*notify), work); + nvkm_notify_func(notify); +} + +void +nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size) +{ + struct nvkm_event *event = notify->event; + unsigned long flags; + + BUG_ON(!spin_is_locked(&event->list_lock)); + BUG_ON(size != notify->size); + + spin_lock_irqsave(&event->refs_lock, flags); + if (notify->block) { + spin_unlock_irqrestore(&event->refs_lock, flags); + return; + } + nvkm_notify_put_locked(notify); + spin_unlock_irqrestore(&event->refs_lock, flags); + + if (test_bit(NVKM_NOTIFY_WORK, ¬ify->flags)) { + memcpy((void *)notify->data, data, size); + schedule_work(¬ify->work); + } else { + notify->data = data; + nvkm_notify_func(notify); + notify->data = NULL; + } +} + +void +nvkm_notify_fini(struct nvkm_notify *notify) +{ + unsigned long flags; + if (notify->event) { + nvkm_notify_put(notify); + spin_lock_irqsave(¬ify->event->list_lock, flags); + list_del(¬ify->head); + spin_unlock_irqrestore(¬ify->event->list_lock, flags); + kfree((void *)notify->data); + notify->event = NULL; + } +} + +int +nvkm_notify_init(struct nouveau_object *object, struct nvkm_event *event, + int (*func)(struct nvkm_notify *), bool work, + void *data, u32 size, u32 reply, + struct nvkm_notify *notify) +{ + unsigned long flags; + int ret = -ENODEV; + if ((notify->event = event), event->refs) { + ret = event->func->ctor(object, data, size, notify); + if (ret == 0 && (ret = -EINVAL, notify->size == reply)) { + notify->flags = 0; + notify->block = 1; + notify->func = func; + notify->data = NULL; + if (ret = 0, work) { + INIT_WORK(¬ify->work, nvkm_notify_work); + set_bit(NVKM_NOTIFY_WORK, ¬ify->flags); + notify->data = kmalloc(reply, GFP_KERNEL); + if (!notify->data) + ret = -ENOMEM; + } + } + if (ret == 0) { + spin_lock_irqsave(&event->list_lock, flags); + list_add_tail(¬ify->head, &event->list); + spin_unlock_irqrestore(&event->list_lock, flags); + } + } + if (ret) + notify->event = NULL; + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/core/object.c b/drivers/gpu/drm/nouveau/core/core/object.c index 124538555904..b08630577c82 100644 --- a/drivers/gpu/drm/nouveau/core/core/object.c +++ b/drivers/gpu/drm/nouveau/core/core/object.c @@ -23,9 +23,6 @@ */ #include <core/object.h> -#include <core/parent.h> -#include <core/namedb.h> -#include <core/handle.h> #include <core/engine.h> #ifdef NOUVEAU_OBJECT_MAGIC @@ -61,21 +58,15 @@ nouveau_object_create_(struct nouveau_object *parent, return 0; } -static int +int _nouveau_object_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nouveau_object *object; - int ret; - - ret = nouveau_object_create(parent, engine, oclass, 0, &object); - *pobject = nv_object(object); - if (ret) - return ret; - - return 0; + if (size != 0) + return -ENOSYS; + return nouveau_object_create(parent, engine, oclass, 0, pobject); } void @@ -91,42 +82,24 @@ nouveau_object_destroy(struct nouveau_object *object) kfree(object); } -static void -_nouveau_object_dtor(struct nouveau_object *object) -{ - nouveau_object_destroy(object); -} - int nouveau_object_init(struct nouveau_object *object) { return 0; } -static int -_nouveau_object_init(struct nouveau_object *object) -{ - return nouveau_object_init(object); -} - int nouveau_object_fini(struct nouveau_object *object, bool suspend) { return 0; } -static int -_nouveau_object_fini(struct nouveau_object *object, bool suspend) -{ - return nouveau_object_fini(object, suspend); -} - struct nouveau_ofuncs nouveau_object_ofuncs = { .ctor = _nouveau_object_ctor, - .dtor = _nouveau_object_dtor, - .init = _nouveau_object_init, - .fini = _nouveau_object_fini, + .dtor = nouveau_object_destroy, + .init = nouveau_object_init, + .fini = nouveau_object_fini, }; int @@ -189,119 +162,6 @@ nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref) } int -nouveau_object_new(struct nouveau_object *client, u32 _parent, u32 _handle, - u16 _oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nouveau_object *parent = NULL; - struct nouveau_object *engctx = NULL; - struct nouveau_object *object = NULL; - struct nouveau_object *engine; - struct nouveau_oclass *oclass; - struct nouveau_handle *handle; - int ret; - - /* lookup parent object and ensure it *is* a parent */ - parent = nouveau_handle_ref(client, _parent); - if (!parent) { - nv_error(client, "parent 0x%08x not found\n", _parent); - return -ENOENT; - } - - if (!nv_iclass(parent, NV_PARENT_CLASS)) { - nv_error(parent, "cannot have children\n"); - ret = -EINVAL; - goto fail_class; - } - - /* check that parent supports the requested subclass */ - ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass); - if (ret) { - nv_debug(parent, "illegal class 0x%04x\n", _oclass); - goto fail_class; - } - - /* make sure engine init has been completed *before* any objects - * it controls are created - the constructors may depend on - * state calculated at init (ie. default context construction) - */ - if (engine) { - ret = nouveau_object_inc(engine); - if (ret) - goto fail_class; - } - - /* if engine requires it, create a context object to insert - * between the parent and its children (eg. PGRAPH context) - */ - if (engine && nv_engine(engine)->cclass) { - ret = nouveau_object_ctor(parent, engine, - nv_engine(engine)->cclass, - data, size, &engctx); - if (ret) - goto fail_engctx; - } else { - nouveau_object_ref(parent, &engctx); - } - - /* finally, create new object and bind it to its handle */ - ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object); - *pobject = object; - if (ret) - goto fail_ctor; - - ret = nouveau_object_inc(object); - if (ret) - goto fail_init; - - ret = nouveau_handle_create(parent, _parent, _handle, object, &handle); - if (ret) - goto fail_handle; - - ret = nouveau_handle_init(handle); - if (ret) - nouveau_handle_destroy(handle); - -fail_handle: - nouveau_object_dec(object, false); -fail_init: - nouveau_object_ref(NULL, &object); -fail_ctor: - nouveau_object_ref(NULL, &engctx); -fail_engctx: - if (engine) - nouveau_object_dec(engine, false); -fail_class: - nouveau_object_ref(NULL, &parent); - return ret; -} - -int -nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle) -{ - struct nouveau_object *parent = NULL; - struct nouveau_object *namedb = NULL; - struct nouveau_handle *handle = NULL; - - parent = nouveau_handle_ref(client, _parent); - if (!parent) - return -ENOENT; - - namedb = nv_pclass(parent, NV_NAMEDB_CLASS); - if (namedb) { - handle = nouveau_namedb_get(nv_namedb(namedb), _handle); - if (handle) { - nouveau_namedb_put(handle); - nouveau_handle_fini(handle, false); - nouveau_handle_destroy(handle); - } - } - - nouveau_object_ref(NULL, &parent); - return handle ? 0 : -EINVAL; -} - -int nouveau_object_inc(struct nouveau_object *object) { int ref = atomic_add_return(1, &object->usecount); diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c index dee5d1235e9b..30a2911878f8 100644 --- a/drivers/gpu/drm/nouveau/core/core/parent.c +++ b/drivers/gpu/drm/nouveau/core/core/parent.c @@ -75,6 +75,39 @@ nouveau_parent_sclass(struct nouveau_object *parent, u16 handle, } int +nouveau_parent_lclass(struct nouveau_object *parent, u32 *lclass, int size) +{ + struct nouveau_sclass *sclass; + struct nouveau_engine *engine; + struct nouveau_oclass *oclass; + int nr = -1, i; + u64 mask; + + sclass = nv_parent(parent)->sclass; + while (sclass) { + if (++nr < size) + lclass[nr] = sclass->oclass->handle & 0xffff; + sclass = sclass->sclass; + } + + mask = nv_parent(parent)->engine; + while (i = __ffs64(mask), mask) { + engine = nouveau_engine(parent, i); + if (engine && (oclass = engine->sclass)) { + while (oclass->ofuncs) { + if (++nr < size) + lclass[nr] = oclass->handle & 0xffff; + oclass++; + } + } + + mask &= ~(1ULL << i); + } + + return nr + 1; +} + +int nouveau_parent_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, u32 pclass, diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c index f31527733e00..abb410ef09ea 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c @@ -30,7 +30,6 @@ #include <subdev/vm.h> #include <core/client.h> -#include <core/class.h> #include <core/enum.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c index ac3291f781f6..9261694d0d35 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c @@ -26,9 +26,7 @@ #include <engine/fifo.h> #include <engine/copy.h> -#include <core/class.h> #include <core/enum.h> -#include <core/class.h> #include <core/enum.h> #include "fuc/nvc0.fuc.h" diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c index 748a61eb3c6f..c7194b354605 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c @@ -24,7 +24,6 @@ #include <core/os.h> #include <core/enum.h> -#include <core/class.h> #include <core/engctx.h> #include <engine/copy.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c index 2551dafbec73..ea5c42f31791 100644 --- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c @@ -25,7 +25,6 @@ #include <core/client.h> #include <core/os.h> #include <core/enum.h> -#include <core/class.h> #include <core/engctx.h> #include <core/gpuobj.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c index c7082377ec76..5571c09534cb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c +++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c @@ -25,7 +25,6 @@ #include <core/client.h> #include <core/os.h> #include <core/enum.h> -#include <core/class.h> #include <core/engctx.h> #include <subdev/timer.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/device/acpi.c b/drivers/gpu/drm/nouveau/core/engine/device/acpi.c new file mode 100644 index 000000000000..4dbf0ba89e5c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/device/acpi.c @@ -0,0 +1,59 @@ +/* + * Copyright 2014 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 "acpi.h" + +#ifdef CONFIG_ACPI +static int +nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data) +{ + struct nouveau_device *device = + container_of(nb, typeof(*device), acpi.nb); + struct acpi_bus_event *info = data; + + if (!strcmp(info->device_class, "ac_adapter")) + nvkm_event_send(&device->event, 1, 0, NULL, 0); + + return NOTIFY_DONE; +} +#endif + +int +nvkm_acpi_fini(struct nouveau_device *device, bool suspend) +{ +#ifdef CONFIG_ACPI + unregister_acpi_notifier(&device->acpi.nb); +#endif + return 0; +} + +int +nvkm_acpi_init(struct nouveau_device *device) +{ +#ifdef CONFIG_ACPI + device->acpi.nb.notifier_call = nvkm_acpi_ntfy; + register_acpi_notifier(&device->acpi.nb); +#endif + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/device/acpi.h b/drivers/gpu/drm/nouveau/core/engine/device/acpi.h new file mode 100644 index 000000000000..cc49f4f568cd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/device/acpi.h @@ -0,0 +1,9 @@ +#ifndef __NVKM_DEVICE_ACPI_H__ +#define __NVKM_DEVICE_ACPI_H__ + +#include <engine/device.h> + +int nvkm_acpi_init(struct nouveau_device *); +int nvkm_acpi_fini(struct nouveau_device *, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c index 18c8c7245b73..0ef5a5713182 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c @@ -26,10 +26,14 @@ #include <core/device.h> #include <core/client.h> #include <core/option.h> +#include <nvif/unpack.h> +#include <nvif/class.h> -#include <core/class.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> #include "priv.h" +#include "acpi.h" static DEFINE_MUTEX(nv_devices_mutex); static LIST_HEAD(nv_devices); @@ -49,74 +53,258 @@ nouveau_device_find(u64 name) return match; } +int +nouveau_device_list(u64 *name, int size) +{ + struct nouveau_device *device; + int nr = 0; + mutex_lock(&nv_devices_mutex); + list_for_each_entry(device, &nv_devices, head) { + if (nr++ < size) + name[nr - 1] = device->handle; + } + mutex_unlock(&nv_devices_mutex); + return nr; +} + /****************************************************************************** * nouveau_devobj (0x0080): class implementation *****************************************************************************/ + struct nouveau_devobj { struct nouveau_parent base; struct nouveau_object *subdev[NVDEV_SUBDEV_NR]; }; +static int +nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size) +{ + struct nouveau_device *device = nv_device(object); + struct nouveau_fb *pfb = nouveau_fb(device); + struct nouveau_instmem *imem = nouveau_instmem(device); + union { + struct nv_device_info_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "device info size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "device info vers %d\n", args->v0.version); + } else + return ret; + + switch (device->chipset) { + case 0x01a: + case 0x01f: + case 0x04c: + case 0x04e: + case 0x063: + case 0x067: + case 0x068: + case 0x0aa: + case 0x0ac: + case 0x0af: + args->v0.platform = NV_DEVICE_INFO_V0_IGP; + break; + default: + if (device->pdev) { + if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP)) + args->v0.platform = NV_DEVICE_INFO_V0_AGP; + else + if (pci_is_pcie(device->pdev)) + args->v0.platform = NV_DEVICE_INFO_V0_PCIE; + else + args->v0.platform = NV_DEVICE_INFO_V0_PCI; + } else { + args->v0.platform = NV_DEVICE_INFO_V0_SOC; + } + break; + } + + switch (device->card_type) { + case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break; + case NV_10: + case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break; + case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break; + case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break; + case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break; + case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break; + case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break; + case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break; + case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break; + default: + args->v0.family = 0; + break; + } + + args->v0.chipset = device->chipset; + args->v0.revision = device->chipset >= 0x10 ? nv_rd32(device, 0) : 0x00; + if (pfb) args->v0.ram_size = args->v0.ram_user = pfb->ram->size; + else args->v0.ram_size = args->v0.ram_user = 0; + if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved; + return 0; +} + +static int +nouveau_devobj_mthd(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + switch (mthd) { + case NV_DEVICE_V0_INFO: + return nouveau_devobj_info(object, data, size); + default: + break; + } + return -EINVAL; +} + +static u8 +nouveau_devobj_rd08(struct nouveau_object *object, u64 addr) +{ + return nv_rd08(object->engine, addr); +} + +static u16 +nouveau_devobj_rd16(struct nouveau_object *object, u64 addr) +{ + return nv_rd16(object->engine, addr); +} + +static u32 +nouveau_devobj_rd32(struct nouveau_object *object, u64 addr) +{ + return nv_rd32(object->engine, addr); +} + +static void +nouveau_devobj_wr08(struct nouveau_object *object, u64 addr, u8 data) +{ + nv_wr08(object->engine, addr, data); +} + +static void +nouveau_devobj_wr16(struct nouveau_object *object, u64 addr, u16 data) +{ + nv_wr16(object->engine, addr, data); +} + +static void +nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data) +{ + nv_wr32(object->engine, addr, data); +} + +static int +nouveau_devobj_map(struct nouveau_object *object, u64 *addr, u32 *size) +{ + struct nouveau_device *device = nv_device(object); + *addr = nv_device_resource_start(device, 0); + *size = nv_device_resource_len(device, 0); + return 0; +} + static const u64 disable_map[] = { - [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_DISABLE_VBIOS, - [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_GPIO] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_I2C] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_MXM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_MC] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_BUS] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_TIMER] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_FB] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_LTCG] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_IBUS] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_VM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE, - [NVDEV_SUBDEV_PWR] = NV_DEVICE_DISABLE_CORE, - [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE, - [NVDEV_ENGINE_PERFMON] = NV_DEVICE_DISABLE_CORE, - [NVDEV_ENGINE_FIFO] = NV_DEVICE_DISABLE_FIFO, - [NVDEV_ENGINE_SW] = NV_DEVICE_DISABLE_FIFO, - [NVDEV_ENGINE_GR] = NV_DEVICE_DISABLE_GRAPH, - [NVDEV_ENGINE_MPEG] = NV_DEVICE_DISABLE_MPEG, - [NVDEV_ENGINE_ME] = NV_DEVICE_DISABLE_ME, - [NVDEV_ENGINE_VP] = NV_DEVICE_DISABLE_VP, - [NVDEV_ENGINE_CRYPT] = NV_DEVICE_DISABLE_CRYPT, - [NVDEV_ENGINE_BSP] = NV_DEVICE_DISABLE_BSP, - [NVDEV_ENGINE_PPP] = NV_DEVICE_DISABLE_PPP, - [NVDEV_ENGINE_COPY0] = NV_DEVICE_DISABLE_COPY0, - [NVDEV_ENGINE_COPY1] = NV_DEVICE_DISABLE_COPY1, - [NVDEV_ENGINE_VIC] = NV_DEVICE_DISABLE_VIC, - [NVDEV_ENGINE_VENC] = NV_DEVICE_DISABLE_VENC, - [NVDEV_ENGINE_DISP] = NV_DEVICE_DISABLE_DISP, + [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS, + [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_LTC] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_VM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE, + [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO, + [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO, + [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GRAPH, + [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG, + [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME, + [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP, + [NVDEV_ENGINE_CRYPT] = NV_DEVICE_V0_DISABLE_CRYPT, + [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP, + [NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP, + [NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0, + [NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1, + [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC, + [NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC, + [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP, [NVDEV_SUBDEV_NR] = 0, }; +static void +nouveau_devobj_dtor(struct nouveau_object *object) +{ + struct nouveau_devobj *devobj = (void *)object; + int i; + + for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) + nouveau_object_ref(NULL, &devobj->subdev[i]); + + nouveau_parent_destroy(&devobj->base); +} + +static struct nouveau_oclass +nouveau_devobj_oclass_super = { + .handle = NV_DEVICE, + .ofuncs = &(struct nouveau_ofuncs) { + .dtor = nouveau_devobj_dtor, + .init = _nouveau_parent_init, + .fini = _nouveau_parent_fini, + .mthd = nouveau_devobj_mthd, + .map = nouveau_devobj_map, + .rd08 = nouveau_devobj_rd08, + .rd16 = nouveau_devobj_rd16, + .rd32 = nouveau_devobj_rd32, + .wr08 = nouveau_devobj_wr08, + .wr16 = nouveau_devobj_wr16, + .wr32 = nouveau_devobj_wr32, + } +}; + static int nouveau_devobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv_device_v0 v0; + } *args = data; struct nouveau_client *client = nv_client(parent); struct nouveau_device *device; struct nouveau_devobj *devobj; - struct nv_device_class *args = data; u32 boot0, strap; u64 disable, mmio_base, mmio_size; void __iomem *map; int ret, i, c; - if (size < sizeof(struct nv_device_class)) - return -EINVAL; + nv_ioctl(parent, "create device size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create device v%d device %016llx " + "disable %016llx debug0 %016llx\n", + args->v0.version, args->v0.device, + args->v0.disable, args->v0.debug0); + } else + return ret; + + /* give priviledged clients register access */ + if (client->super) + oclass = &nouveau_devobj_oclass_super; /* find the device subdev that matches what the client requested */ device = nv_device(client->device); - if (args->device != ~0) { - device = nouveau_device_find(args->device); + if (args->v0.device != ~0) { + device = nouveau_device_find(args->v0.device); if (!device) return -ENODEV; } @@ -135,14 +323,14 @@ nouveau_devobj_ctor(struct nouveau_object *parent, mmio_size = nv_device_resource_len(device, 0); /* translate api disable mask into internal mapping */ - disable = args->debug0; + disable = args->v0.debug0; for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if (args->disable & disable_map[i]) + if (args->v0.disable & disable_map[i]) disable |= (1ULL << i); } /* identify the chipset, and determine classes of subdev/engines */ - if (!(args->disable & NV_DEVICE_DISABLE_IDENTIFY) && + if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) && !device->card_type) { map = ioremap(mmio_base, 0x102000); if (map == NULL) @@ -180,8 +368,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent, case 0x080: case 0x090: case 0x0a0: device->card_type = NV_50; break; - case 0x0c0: device->card_type = NV_C0; break; - case 0x0d0: device->card_type = NV_D0; break; + case 0x0c0: + case 0x0d0: device->card_type = NV_C0; break; case 0x0e0: case 0x0f0: case 0x100: device->card_type = NV_E0; break; @@ -206,8 +394,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent, case NV_30: ret = nv30_identify(device); break; case NV_40: ret = nv40_identify(device); break; case NV_50: ret = nv50_identify(device); break; - case NV_C0: - case NV_D0: ret = nvc0_identify(device); break; + case NV_C0: ret = nvc0_identify(device); break; case NV_E0: ret = nve0_identify(device); break; case GM100: ret = gm100_identify(device); break; default: @@ -242,7 +429,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent, nv_debug(device, "crystal freq: %dKHz\n", device->crystal); } - if (!(args->disable & NV_DEVICE_DISABLE_MMIO) && + if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && !nv_subdev(device)->mmio) { nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size); if (!nv_subdev(device)->mmio) { @@ -298,71 +485,19 @@ nouveau_devobj_ctor(struct nouveau_object *parent, return 0; } -static void -nouveau_devobj_dtor(struct nouveau_object *object) -{ - struct nouveau_devobj *devobj = (void *)object; - int i; - - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) - nouveau_object_ref(NULL, &devobj->subdev[i]); - - nouveau_parent_destroy(&devobj->base); -} - -static u8 -nouveau_devobj_rd08(struct nouveau_object *object, u64 addr) -{ - return nv_rd08(object->engine, addr); -} - -static u16 -nouveau_devobj_rd16(struct nouveau_object *object, u64 addr) -{ - return nv_rd16(object->engine, addr); -} - -static u32 -nouveau_devobj_rd32(struct nouveau_object *object, u64 addr) -{ - return nv_rd32(object->engine, addr); -} - -static void -nouveau_devobj_wr08(struct nouveau_object *object, u64 addr, u8 data) -{ - nv_wr08(object->engine, addr, data); -} - -static void -nouveau_devobj_wr16(struct nouveau_object *object, u64 addr, u16 data) -{ - nv_wr16(object->engine, addr, data); -} - -static void -nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data) -{ - nv_wr32(object->engine, addr, data); -} - static struct nouveau_ofuncs nouveau_devobj_ofuncs = { .ctor = nouveau_devobj_ctor, .dtor = nouveau_devobj_dtor, .init = _nouveau_parent_init, .fini = _nouveau_parent_fini, - .rd08 = nouveau_devobj_rd08, - .rd16 = nouveau_devobj_rd16, - .rd32 = nouveau_devobj_rd32, - .wr08 = nouveau_devobj_wr08, - .wr16 = nouveau_devobj_wr16, - .wr32 = nouveau_devobj_wr32, + .mthd = nouveau_devobj_mthd, }; /****************************************************************************** * nouveau_device: engine functions *****************************************************************************/ + static struct nouveau_oclass nouveau_device_sclass[] = { { 0x0080, &nouveau_devobj_ofuncs }, @@ -370,6 +505,24 @@ nouveau_device_sclass[] = { }; static int +nouveau_device_event_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + if (!WARN_ON(size != 0)) { + notify->size = 0; + notify->types = 1; + notify->index = 0; + return 0; + } + return -EINVAL; +} + +static const struct nvkm_event_func +nouveau_device_event_func = { + .ctor = nouveau_device_event_ctor, +}; + +static int nouveau_device_fini(struct nouveau_object *object, bool suspend) { struct nouveau_device *device = (void *)object; @@ -386,7 +539,7 @@ nouveau_device_fini(struct nouveau_object *object, bool suspend) } } - ret = 0; + ret = nvkm_acpi_fini(device, suspend); fail: for (; ret && i < NVDEV_SUBDEV_NR; i++) { if ((subdev = device->subdev[i])) { @@ -407,7 +560,11 @@ nouveau_device_init(struct nouveau_object *object) { struct nouveau_device *device = (void *)object; struct nouveau_object *subdev; - int ret, i; + int ret, i = 0; + + ret = nvkm_acpi_init(device); + if (ret) + goto fail; for (i = 0; i < NVDEV_SUBDEV_NR; i++) { if ((subdev = device->subdev[i])) { @@ -430,6 +587,8 @@ fail: } } + if (ret) + nvkm_acpi_fini(device, false); return ret; } @@ -438,6 +597,8 @@ nouveau_device_dtor(struct nouveau_object *object) { struct nouveau_device *device = (void *)object; + nvkm_event_fini(&device->event); + mutex_lock(&nv_devices_mutex); list_del(&device->head); mutex_unlock(&nv_devices_mutex); @@ -478,31 +639,6 @@ nv_device_resource_len(struct nouveau_device *device, unsigned int bar) } } -dma_addr_t -nv_device_map_page(struct nouveau_device *device, struct page *page) -{ - dma_addr_t ret; - - if (nv_device_is_pci(device)) { - ret = pci_map_page(device->pdev, page, 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(device->pdev, ret)) - ret = 0; - } else { - ret = page_to_phys(page); - } - - return ret; -} - -void -nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr) -{ - if (nv_device_is_pci(device)) - pci_unmap_page(device->pdev, addr, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); -} - int nv_device_get_irq(struct nouveau_device *device, bool stall) { @@ -560,6 +696,9 @@ nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name, nv_subdev(device)->debug = nouveau_dbgopt(device->dbgopt, "DEVICE"); nv_engine(device)->sclass = nouveau_device_sclass; list_add(&device->head, &nv_devices); + + ret = nvkm_event_init(&nouveau_device_event_func, 1, 1, + &device->event); done: mutex_unlock(&nv_devices_mutex); return ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c index 4b69bf56ed01..e34101a3490e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c @@ -22,55 +22,82 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ +#include <core/client.h> #include <core/object.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> +#include <nvif/ioctl.h> #include <subdev/clock.h> #include "priv.h" static int -nouveau_control_mthd_pstate_info(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nouveau_control_mthd_pstate_info(struct nouveau_object *object, + void *data, u32 size) { + union { + struct nvif_control_pstate_info_v0 v0; + } *args = data; struct nouveau_clock *clk = nouveau_clock(object); - struct nv_control_pstate_info *args = data; + int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(object, "control pstate info size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "control pstate info vers %d\n", + args->v0.version); + } else + return ret; if (clk) { - args->count = clk->state_nr; - args->ustate = clk->ustate; - args->pstate = clk->pstate; + args->v0.count = clk->state_nr; + args->v0.ustate_ac = clk->ustate_ac; + args->v0.ustate_dc = clk->ustate_dc; + args->v0.pwrsrc = clk->pwrsrc; + args->v0.pstate = clk->pstate; } else { - args->count = 0; - args->ustate = NV_CONTROL_PSTATE_INFO_USTATE_DISABLE; - args->pstate = NV_CONTROL_PSTATE_INFO_PSTATE_UNKNOWN; + args->v0.count = 0; + args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE; + args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE; + args->v0.pwrsrc = -ENOSYS; + args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN; } return 0; } static int -nouveau_control_mthd_pstate_attr(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nouveau_control_mthd_pstate_attr(struct nouveau_object *object, + void *data, u32 size) { + union { + struct nvif_control_pstate_attr_v0 v0; + } *args = data; struct nouveau_clock *clk = nouveau_clock(object); - struct nv_control_pstate_attr *args = data; struct nouveau_clocks *domain; struct nouveau_pstate *pstate; struct nouveau_cstate *cstate; int i = 0, j = -1; u32 lo, hi; - - if ((size < sizeof(*args)) || !clk || - (args->state >= 0 && args->state >= clk->state_nr)) - return -EINVAL; + int ret; + + nv_ioctl(object, "control pstate attr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "control pstate attr vers %d state %d " + "index %d\n", + args->v0.version, args->v0.state, args->v0.index); + if (!clk) + return -ENODEV; + if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) + return -EINVAL; + if (args->v0.state >= clk->state_nr) + return -EINVAL; + } else + return ret; domain = clk->domains; while (domain->name != nv_clk_src_max) { - if (domain->mname && ++j == args->index) + if (domain->mname && ++j == args->v0.index) break; domain++; } @@ -78,9 +105,9 @@ nouveau_control_mthd_pstate_attr(struct nouveau_object *object, u32 mthd, if (domain->name == nv_clk_src_max) return -EINVAL; - if (args->state != NV_CONTROL_PSTATE_ATTR_STATE_CURRENT) { + if (args->v0.state != NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) { list_for_each_entry(pstate, &clk->states, head) { - if (i++ == args->state) + if (i++ == args->v0.state) break; } @@ -91,21 +118,21 @@ nouveau_control_mthd_pstate_attr(struct nouveau_object *object, u32 mthd, hi = max(hi, cstate->domain[domain->name]); } - args->state = pstate->pstate; + args->v0.state = pstate->pstate; } else { lo = max(clk->read(clk, domain->name), 0); hi = lo; } - snprintf(args->name, sizeof(args->name), "%s", domain->mname); - snprintf(args->unit, sizeof(args->unit), "MHz"); - args->min = lo / domain->mdiv; - args->max = hi / domain->mdiv; + snprintf(args->v0.name, sizeof(args->v0.name), "%s", domain->mname); + snprintf(args->v0.unit, sizeof(args->v0.unit), "MHz"); + args->v0.min = lo / domain->mdiv; + args->v0.max = hi / domain->mdiv; - args->index = 0; + args->v0.index = 0; while ((++domain)->name != nv_clk_src_max) { if (domain->mname) { - args->index = ++j; + args->v0.index = ++j; break; } } @@ -114,31 +141,65 @@ nouveau_control_mthd_pstate_attr(struct nouveau_object *object, u32 mthd, } static int -nouveau_control_mthd_pstate_user(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nouveau_control_mthd_pstate_user(struct nouveau_object *object, + void *data, u32 size) { + union { + struct nvif_control_pstate_user_v0 v0; + } *args = data; struct nouveau_clock *clk = nouveau_clock(object); - struct nv_control_pstate_user *args = data; + int ret; + + nv_ioctl(object, "control pstate user size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "control pstate user vers %d ustate %d " + "pwrsrc %d\n", args->v0.version, + args->v0.ustate, args->v0.pwrsrc); + if (!clk) + return -ENODEV; + } else + return ret; + + if (args->v0.pwrsrc >= 0) { + ret |= nouveau_clock_ustate(clk, args->v0.ustate, args->v0.pwrsrc); + } else { + ret |= nouveau_clock_ustate(clk, args->v0.ustate, 0); + ret |= nouveau_clock_ustate(clk, args->v0.ustate, 1); + } - if (size < sizeof(*args) || !clk) - return -EINVAL; + return ret; +} - return nouveau_clock_ustate(clk, args->state); +static int +nouveau_control_mthd(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + switch (mthd) { + case NVIF_CONTROL_PSTATE_INFO: + return nouveau_control_mthd_pstate_info(object, data, size); + case NVIF_CONTROL_PSTATE_ATTR: + return nouveau_control_mthd_pstate_attr(object, data, size); + case NVIF_CONTROL_PSTATE_USER: + return nouveau_control_mthd_pstate_user(object, data, size); + default: + break; + } + return -EINVAL; } +static struct nouveau_ofuncs +nouveau_control_ofuncs = { + .ctor = _nouveau_object_ctor, + .dtor = nouveau_object_destroy, + .init = nouveau_object_init, + .fini = nouveau_object_fini, + .mthd = nouveau_control_mthd, +}; + struct nouveau_oclass nouveau_control_oclass[] = { - { .handle = NV_CONTROL_CLASS, - .ofuncs = &nouveau_object_ofuncs, - .omthds = (struct nouveau_omthds[]) { - { NV_CONTROL_PSTATE_INFO, - NV_CONTROL_PSTATE_INFO, nouveau_control_mthd_pstate_info }, - { NV_CONTROL_PSTATE_ATTR, - NV_CONTROL_PSTATE_ATTR, nouveau_control_mthd_pstate_attr }, - { NV_CONTROL_PSTATE_USER, - NV_CONTROL_PSTATE_USER, nouveau_control_mthd_pstate_user }, - {}, - }, + { .handle = NVIF_IOCTL_NEW_V0_CONTROL, + .ofuncs = &nouveau_control_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c index a520029e25d9..6295668e29a5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c @@ -26,6 +26,7 @@ #include <subdev/bus.h> #include <subdev/gpio.h> #include <subdev/i2c.h> +#include <subdev/fuse.h> #include <subdev/clock.h> #include <subdev/therm.h> #include <subdev/mxm.h> @@ -33,7 +34,7 @@ #include <subdev/mc.h> #include <subdev/timer.h> #include <subdev/fb.h> -#include <subdev/ltcg.h> +#include <subdev/ltc.h> #include <subdev/ibus.h> #include <subdev/instmem.h> #include <subdev/vm.h> @@ -62,26 +63,26 @@ gm100_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; -#if 0 - device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; -#endif + device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gm107_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass; + #if 0 - device->oclass[NVDEV_SUBDEV_PWR ] = &nv108_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c index 40b29d0214cb..573b55f5c2f9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c @@ -56,7 +56,7 @@ nv04_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass; @@ -74,7 +74,7 @@ nv04_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c index 5f7c25ff523d..183a85a6204e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c @@ -58,7 +58,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; @@ -75,7 +75,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; @@ -94,7 +94,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; @@ -113,7 +113,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; @@ -132,7 +132,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; @@ -151,7 +151,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; @@ -170,7 +170,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; @@ -189,7 +189,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c index 75fed11bba0a..aa564c68a920 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c @@ -59,7 +59,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv20_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv20_graph_oclass; @@ -78,7 +78,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass; @@ -97,7 +97,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass; @@ -116,7 +116,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv2a_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c index 36919d7db7cc..11bd31da82ab 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c @@ -59,7 +59,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass; @@ -78,7 +78,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv35_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass; @@ -97,7 +97,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass; @@ -117,7 +117,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv36_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass; @@ -137,7 +137,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv34_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c index 1130a62be2c7..e96c223cb797 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c @@ -65,7 +65,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -88,7 +88,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -111,7 +111,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -134,7 +134,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -157,7 +157,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -180,7 +180,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -203,7 +203,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -226,7 +226,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -249,7 +249,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -272,7 +272,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -295,7 +295,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -318,7 +318,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -341,7 +341,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -364,7 +364,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -387,7 +387,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; @@ -410,7 +410,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c index ef0b0bde1a91..96f568d1321b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c @@ -26,6 +26,7 @@ #include <subdev/bus.h> #include <subdev/gpio.h> #include <subdev/i2c.h> +#include <subdev/fuse.h> #include <subdev/clock.h> #include <subdev/therm.h> #include <subdev/mxm.h> @@ -62,6 +63,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -74,7 +76,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -87,6 +89,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -99,7 +102,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -115,6 +118,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -127,7 +131,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -141,8 +145,9 @@ nv50_identify(struct nouveau_device *device) case 0x92: device->cname = "G92"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -155,7 +160,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -169,8 +174,9 @@ nv50_identify(struct nouveau_device *device) case 0x94: device->cname = "G94"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -183,7 +189,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -197,8 +203,9 @@ nv50_identify(struct nouveau_device *device) case 0x96: device->cname = "G96"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -211,7 +218,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -225,8 +232,9 @@ nv50_identify(struct nouveau_device *device) case 0x98: device->cname = "G98"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -239,7 +247,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -253,8 +261,9 @@ nv50_identify(struct nouveau_device *device) case 0xa0: device->cname = "G200"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -267,7 +276,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -281,8 +290,9 @@ nv50_identify(struct nouveau_device *device) case 0xaa: device->cname = "MCP77/MCP78"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -295,7 +305,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -309,8 +319,9 @@ nv50_identify(struct nouveau_device *device) case 0xac: device->cname = "MCP79/MCP7A"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -323,7 +334,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -337,8 +348,9 @@ nv50_identify(struct nouveau_device *device) case 0xa3: device->cname = "GT215"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -350,9 +362,9 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nva3_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -367,8 +379,9 @@ nv50_identify(struct nouveau_device *device) case 0xa5: device->cname = "GT216"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -380,9 +393,9 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nva3_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -396,8 +409,9 @@ nv50_identify(struct nouveau_device *device) case 0xa8: device->cname = "GT218"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -409,9 +423,9 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nva3_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; @@ -425,8 +439,9 @@ nv50_identify(struct nouveau_device *device) case 0xaf: device->cname = "MCP89"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -438,9 +453,9 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nva3_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index 8d55ed633b19..cd05677ad4b7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -26,6 +26,7 @@ #include <subdev/bus.h> #include <subdev/gpio.h> #include <subdev/i2c.h> +#include <subdev/fuse.h> #include <subdev/clock.h> #include <subdev/therm.h> #include <subdev/mxm.h> @@ -33,7 +34,7 @@ #include <subdev/mc.h> #include <subdev/timer.h> #include <subdev/fb.h> -#include <subdev/ltcg.h> +#include <subdev/ltc.h> #include <subdev/ibus.h> #include <subdev/instmem.h> #include <subdev/vm.h> @@ -60,8 +61,9 @@ nvc0_identify(struct nouveau_device *device) case 0xc0: device->cname = "GF100"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -70,14 +72,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvc0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc0_graph_oclass; @@ -92,8 +94,9 @@ nvc0_identify(struct nouveau_device *device) case 0xc4: device->cname = "GF104"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -102,14 +105,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvc0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; @@ -124,8 +127,9 @@ nvc0_identify(struct nouveau_device *device) case 0xc3: device->cname = "GF106"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -134,14 +138,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvc0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; @@ -155,8 +159,9 @@ nvc0_identify(struct nouveau_device *device) case 0xce: device->cname = "GF114"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -165,14 +170,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvc0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; @@ -187,8 +192,9 @@ nvc0_identify(struct nouveau_device *device) case 0xcf: device->cname = "GF116"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -197,14 +203,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvc0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; @@ -219,8 +225,9 @@ nvc0_identify(struct nouveau_device *device) case 0xc1: device->cname = "GF108"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -229,14 +236,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvc0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc1_graph_oclass; @@ -250,8 +257,9 @@ nvc0_identify(struct nouveau_device *device) case 0xc8: device->cname = "GF110"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -260,14 +268,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvc0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc8_graph_oclass; @@ -284,6 +292,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -292,14 +301,14 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvd0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvd9_graph_oclass; @@ -315,6 +324,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -323,12 +333,12 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvd7_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c index 2d1e97d4264f..b1b2e484ecfa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c @@ -26,6 +26,7 @@ #include <subdev/bus.h> #include <subdev/gpio.h> #include <subdev/i2c.h> +#include <subdev/fuse.h> #include <subdev/clock.h> #include <subdev/therm.h> #include <subdev/mxm.h> @@ -33,7 +34,7 @@ #include <subdev/mc.h> #include <subdev/timer.h> #include <subdev/fb.h> -#include <subdev/ltcg.h> +#include <subdev/ltc.h> #include <subdev/ibus.h> #include <subdev/instmem.h> #include <subdev/vm.h> @@ -62,6 +63,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -70,14 +72,14 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvd0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = gk104_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; @@ -95,6 +97,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -103,14 +106,14 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvd0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; @@ -128,6 +131,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -136,14 +140,14 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvd0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = gk104_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; @@ -158,15 +162,18 @@ nve0_identify(struct nouveau_device *device) break; case 0xea: device->cname = "GK20A"; - device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &gk20a_clock_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass; @@ -178,6 +185,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -186,14 +194,14 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvd0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvf0_graph_oclass; @@ -211,6 +219,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -219,17 +228,17 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nvd0_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; - device->oclass[NVDEV_ENGINE_GR ] = nvf0_graph_oclass; + device->oclass[NVDEV_ENGINE_GR ] = gk110b_graph_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; @@ -244,22 +253,23 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; - device->oclass[NVDEV_SUBDEV_PWR ] = &nv108_pwr_oclass; + device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nv108_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c index 9c38c5e40500..64b84667f3a5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/base.c @@ -22,23 +22,95 @@ * Authors: Ben Skeggs */ +#include <core/os.h> +#include <nvif/unpack.h> +#include <nvif/class.h> +#include <nvif/event.h> + #include "priv.h" #include "outp.h" #include "conn.h" +int +nouveau_disp_vblank_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + struct nouveau_disp *disp = + container_of(notify->event, typeof(*disp), vblank); + union { + struct nvif_notify_head_req_v0 v0; + } *req = data; + int ret; + + if (nvif_unpack(req->v0, 0, 0, false)) { + notify->size = sizeof(struct nvif_notify_head_rep_v0); + if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) { + notify->types = 1; + notify->index = req->v0.head; + return 0; + } + } + + return ret; +} + +void +nouveau_disp_vblank(struct nouveau_disp *disp, int head) +{ + struct nvif_notify_head_rep_v0 rep = {}; + nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep)); +} + static int -nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index) +nouveau_disp_hpd_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) { - struct nouveau_disp *disp = event->priv; + struct nouveau_disp *disp = + container_of(notify->event, typeof(*disp), hpd); + union { + struct nvif_notify_conn_req_v0 v0; + } *req = data; struct nvkm_output *outp; - list_for_each_entry(outp, &disp->outp, head) { - if (outp->conn->index == index) { - if (outp->conn->hpd.event) - return 0; - break; + int ret; + + if (nvif_unpack(req->v0, 0, 0, false)) { + notify->size = sizeof(struct nvif_notify_conn_rep_v0); + list_for_each_entry(outp, &disp->outp, head) { + if (ret = -ENXIO, outp->conn->index == req->v0.conn) { + if (ret = -ENODEV, outp->conn->hpd.event) { + notify->types = req->v0.mask; + notify->index = req->v0.conn; + ret = 0; + } + break; + } } } - return -ENOSYS; + + return ret; +} + +static const struct nvkm_event_func +nouveau_disp_hpd_func = { + .ctor = nouveau_disp_hpd_ctor +}; + +int +nouveau_disp_ntfy(struct nouveau_object *object, u32 type, + struct nvkm_event **event) +{ + struct nouveau_disp *disp = (void *)object->engine; + switch (type) { + case NV04_DISP_NTFY_VBLANK: + *event = &disp->vblank; + return 0; + case NV04_DISP_NTFY_CONN: + *event = &disp->hpd; + return 0; + default: + break; + } + return -EINVAL; } int @@ -97,7 +169,8 @@ _nouveau_disp_dtor(struct nouveau_object *object) struct nouveau_disp *disp = (void *)object; struct nvkm_output *outp, *outt; - nouveau_event_destroy(&disp->vblank); + nvkm_event_fini(&disp->vblank); + nvkm_event_fini(&disp->hpd); if (disp->outp.next) { list_for_each_entry_safe(outp, outt, &disp->outp, head) { @@ -157,14 +230,11 @@ nouveau_disp_create_(struct nouveau_object *parent, hpd = max(hpd, (u8)(dcbE.connector + 1)); } - ret = nouveau_event_create(3, hpd, &disp->hpd); + ret = nvkm_event_init(&nouveau_disp_hpd_func, 3, hpd, &disp->hpd); if (ret) return ret; - disp->hpd->priv = disp; - disp->hpd->check = nouveau_disp_hpd_check; - - ret = nouveau_event_create(1, heads, &disp->vblank); + ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c index 4ffbc70ecf5a..1496b567dd4a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c @@ -22,39 +22,41 @@ * Authors: Ben Skeggs */ +#include <core/os.h> +#include <nvif/event.h> + #include <subdev/gpio.h> #include "conn.h" #include "outp.h" -static void -nvkm_connector_hpd_work(struct work_struct *w) +static int +nvkm_connector_hpd(struct nvkm_notify *notify) { - struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work); + struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); struct nouveau_disp *disp = nouveau_disp(conn); struct nouveau_gpio *gpio = nouveau_gpio(conn); - u32 send = NVKM_HPD_UNPLUG; - if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index)) - send = NVKM_HPD_PLUG; - nouveau_event_trigger(disp->hpd, send, conn->index); - nouveau_event_get(conn->hpd.event); -} + const struct nvkm_gpio_ntfy_rep *line = notify->data; + struct nvif_notify_conn_rep_v0 rep; + int index = conn->index; -static int -nvkm_connector_hpd(void *data, u32 type, int index) -{ - struct nvkm_connector *conn = data; - DBG("HPD: %d\n", type); - schedule_work(&conn->hpd.work); - return NVKM_EVENT_DROP; + DBG("HPD: %d\n", line->mask); + + if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) + rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; + else + rep.mask = NVIF_NOTIFY_CONN_V0_PLUG; + rep.version = 0; + + nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; } int _nvkm_connector_fini(struct nouveau_object *object, bool suspend) { struct nvkm_connector *conn = (void *)object; - if (conn->hpd.event) - nouveau_event_put(conn->hpd.event); + nvkm_notify_put(&conn->hpd); return nouveau_object_fini(&conn->base, suspend); } @@ -63,10 +65,8 @@ _nvkm_connector_init(struct nouveau_object *object) { struct nvkm_connector *conn = (void *)object; int ret = nouveau_object_init(&conn->base); - if (ret == 0) { - if (conn->hpd.event) - nouveau_event_get(conn->hpd.event); - } + if (ret == 0) + nvkm_notify_get(&conn->hpd); return ret; } @@ -74,7 +74,7 @@ void _nvkm_connector_dtor(struct nouveau_object *object) { struct nvkm_connector *conn = (void *)object; - nouveau_event_ref(NULL, &conn->hpd.event); + nvkm_notify_fini(&conn->hpd); nouveau_object_destroy(&conn->base); } @@ -116,19 +116,24 @@ nvkm_connector_create_(struct nouveau_object *parent, if ((info->hpd = ffs(info->hpd))) { if (--info->hpd >= ARRAY_SIZE(hpd)) { ERR("hpd %02x unknown\n", info->hpd); - goto done; + return 0; } info->hpd = hpd[info->hpd]; ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); if (ret) { ERR("func %02x lookup failed, %d\n", info->hpd, ret); - goto done; + return 0; } - ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED, - func.line, nvkm_connector_hpd, - conn, &conn->hpd.event); + ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd, + true, &(struct nvkm_gpio_ntfy_req) { + .mask = NVKM_GPIO_TOGGLED, + .line = func.line, + }, + sizeof(struct nvkm_gpio_ntfy_req), + sizeof(struct nvkm_gpio_ntfy_rep), + &conn->hpd); if (ret) { ERR("func %02x failed, %d\n", info->hpd, ret); } else { @@ -136,8 +141,6 @@ nvkm_connector_create_(struct nouveau_object *parent, } } -done: - INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h index 035ebeacbb1c..55e5f5c82c14 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h @@ -10,10 +10,7 @@ struct nvkm_connector { struct nvbios_connE info; int index; - struct { - struct nouveau_eventh *event; - struct work_struct work; - } hpd; + struct nvkm_notify hpd; }; #define nvkm_connector_create(p,e,c,b,i,d) \ diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c index a66b27c0fcab..b36addff06a9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c @@ -22,8 +22,9 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -32,13 +33,28 @@ #include "nv50.h" int -nv50_dac_power(struct nv50_disp_priv *priv, int or, u32 data) +nv50_dac_power(NV50_DISP_MTHD_V1) { - const u32 stat = (data & NV50_DISP_DAC_PWR_HSYNC) | - (data & NV50_DISP_DAC_PWR_VSYNC) | - (data & NV50_DISP_DAC_PWR_DATA) | - (data & NV50_DISP_DAC_PWR_STATE); - const u32 doff = (or * 0x800); + const u32 doff = outp->or * 0x800; + union { + struct nv50_disp_dac_pwr_v0 v0; + } *args = data; + u32 stat; + int ret; + + nv_ioctl(object, "disp dac pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp dac pwr vers %d state %d data %d " + "vsync %d hsync %d\n", + args->v0.version, args->v0.state, args->v0.data, + args->v0.vsync, args->v0.hsync); + stat = 0x00000040 * !args->v0.state; + stat |= 0x00000010 * !args->v0.data; + stat |= 0x00000004 * !args->v0.vsync; + stat |= 0x00000001 * !args->v0.hsync; + } else + return ret; + nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); @@ -46,9 +62,24 @@ nv50_dac_power(struct nv50_disp_priv *priv, int or, u32 data) } int -nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval) +nv50_dac_sense(NV50_DISP_MTHD_V1) { - const u32 doff = (or * 0x800); + union { + struct nv50_disp_dac_load_v0 v0; + } *args = data; + const u32 doff = outp->or * 0x800; + u32 loadval; + int ret; + + nv_ioctl(object, "disp dac load size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp dac load vers %d data %08x\n", + args->v0.version, args->v0.data); + if (args->v0.data & 0xfff00000) + return -EINVAL; + loadval = args->v0.data; + } else + return ret; nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); @@ -61,38 +92,10 @@ nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval) nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); - nv_debug(priv, "DAC%d sense: 0x%08x\n", or, loadval); + nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval); if (!(loadval & 0x80000000)) return -ETIMEDOUT; - return (loadval & 0x38000000) >> 27; -} - -int -nv50_dac_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - const u8 or = (mthd & NV50_DISP_DAC_MTHD_OR); - u32 *data = args; - int ret; - - if (size < sizeof(u32)) - return -EINVAL; - - switch (mthd & ~0x3f) { - case NV50_DISP_DAC_PWR: - ret = priv->dac.power(priv, or, data[0]); - break; - case NV50_DISP_DAC_LOAD: - ret = priv->dac.sense(priv, or, data[0]); - if (ret >= 0) { - data[0] = ret; - ret = 0; - } - break; - default: - BUG_ON(1); - } - - return ret; + args->v0.load = (loadval & 0x38000000) >> 27; + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c index 5a5b59b21130..39890221b91c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c @@ -30,7 +30,7 @@ #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "dport.h" #include "outpdp.h" @@ -335,7 +335,7 @@ nouveau_dp_train(struct work_struct *w) int ret; /* bring capabilities within encoder limits */ - if (nv_mclass(disp) < NVD0_DISP_CLASS) + if (nv_mclass(disp) < GF110_DISP) outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; @@ -354,7 +354,7 @@ nouveau_dp_train(struct work_struct *w) cfg--; /* disable link interrupt handling during link training */ - nouveau_event_put(outp->irq); + nvkm_notify_put(&outp->irq); /* enable down-spreading and execute pre-train script from vbios */ dp_link_train_init(dp, outp->dpcd[3] & 0x01); @@ -395,5 +395,5 @@ nouveau_dp_train(struct work_struct *w) DBG("training complete\n"); atomic_set(&outp->lt.done, 1); wake_up(&outp->lt.wait); - nouveau_event_get(outp->irq); + nvkm_notify_get(&outp->irq); } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c index 9fc7447fec90..b3df3fe2dc09 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c @@ -25,7 +25,7 @@ #include <engine/software.h> #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "nv50.h" @@ -35,17 +35,17 @@ static struct nouveau_oclass gm107_disp_sclass[] = { - { GM107_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, - { GM107_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs }, - { GM107_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs }, - { GM107_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs }, - { GM107_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs }, + { GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, + { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, + { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, + { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, + { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, {} }; static struct nouveau_oclass gm107_disp_base_oclass[] = { - { GM107_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, + { GM107_DISP, &nvd0_disp_base_ofuncs }, {} }; @@ -68,6 +68,10 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = gm107_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nvd0_disp_intr; @@ -80,7 +84,7 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; - priv->sor.hdmi = nvd0_hdmi_ctrl; + priv->sor.hdmi = nve0_hdmi_ctrl; return 0; } @@ -93,9 +97,11 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nve0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.prev = -0x020000, + .head.scanoutpos = nvd0_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c index a19e7d79b847..fe9ef5894dd4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c @@ -22,28 +22,47 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> + +#include <subdev/timer.h> #include "nv50.h" int -nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size) +nva3_hda_eld(NV50_DISP_MTHD_V1) { - const u32 soff = (or * 0x800); - int i; + union { + struct nv50_disp_sor_hda_eld_v0 v0; + } *args = data; + const u32 soff = outp->or * 0x800; + int ret, i; + + nv_ioctl(object, "disp sor hda eld size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version); + if (size > 0x60) + return -E2BIG; + } else + return ret; - if (data && data[0]) { + if (size && args->v0.data[0]) { + if (outp->info.type == DCB_OUTPUT_DP) { + nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001); + nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000); + } for (i = 0; i < size; i++) - nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]); + nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]); for (; i < 0x60; i++) nv_wr32(priv, 0x61c440 + soff, (i << 8)); nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003); - } else - if (data) { - nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000001); } else { - nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000); + if (outp->info.type == DCB_OUTPUT_DP) { + nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000); + nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000); + } + nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c index 717639386ced..1d4e8432d857 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c @@ -22,33 +22,49 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> -#include <subdev/bios.h> -#include <subdev/bios/dcb.h> -#include <subdev/bios/dp.h> -#include <subdev/bios/init.h> +#include <subdev/timer.h> #include "nv50.h" int -nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size) +nvd0_hda_eld(NV50_DISP_MTHD_V1) { - const u32 soff = (or * 0x030); - int i; + union { + struct nv50_disp_sor_hda_eld_v0 v0; + } *args = data; + const u32 soff = outp->or * 0x030; + const u32 hoff = head * 0x800; + int ret, i; - if (data && data[0]) { + nv_ioctl(object, "disp sor hda eld size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version); + if (size > 0x60) + return -E2BIG; + } else + return ret; + + if (size && args->v0.data[0]) { + if (outp->info.type == DCB_OUTPUT_DP) { + nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001); + nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000); + } + nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]); + nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); for (; i < 0x60; i++) nv_wr32(priv, 0x10ec00 + soff, (i << 8)); nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003); - } else - if (data) { - nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000001); } else { - nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000); + if (outp->info.type == DCB_OUTPUT_DP) { + nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000); + nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000); + } + nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c index 7fdade6e604d..fa276dede9cd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c @@ -22,17 +22,38 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include "nv50.h" int -nv84_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) +nv84_hdmi_ctrl(NV50_DISP_MTHD_V1) { const u32 hoff = (head * 0x800); + union { + struct nv50_disp_sor_hdmi_pwr_v0 v0; + } *args = data; + u32 ctrl; + int ret; - if (!(data & NV84_DISP_SOR_HDMI_PWR_STATE_ON)) { + nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); + if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) + return -EINVAL; + ctrl = 0x40000000 * !!args->v0.state; + ctrl |= args->v0.max_ac_packet << 16; + ctrl |= args->v0.rekey; + ctrl |= 0x1f000000; /* ??? */ + } else + return ret; + + if (!(ctrl & 0x40000000)) { nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000); nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000); nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000); @@ -65,6 +86,6 @@ nv84_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, data | 0x1f000000 /* ??? */); + nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c index db8c6fd46278..57eeed1d1942 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c @@ -22,17 +22,38 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include "nv50.h" int -nva3_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) +nva3_hdmi_ctrl(NV50_DISP_MTHD_V1) { - const u32 soff = (or * 0x800); + const u32 soff = outp->or * 0x800; + union { + struct nv50_disp_sor_hdmi_pwr_v0 v0; + } *args = data; + u32 ctrl; + int ret; - if (!(data & NV84_DISP_SOR_HDMI_PWR_STATE_ON)) { + nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); + if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) + return -EINVAL; + ctrl = 0x40000000 * !!args->v0.state; + ctrl |= args->v0.max_ac_packet << 16; + ctrl |= args->v0.rekey; + ctrl |= 0x1f000000; /* ??? */ + } else + return ret; + + if (!(ctrl & 0x40000000)) { nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000); nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000); nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000); @@ -65,6 +86,6 @@ nva3_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, data | 0x1f000000 /* ??? */); + nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c index 5151bb261832..bac4fc4570f0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c @@ -22,17 +22,37 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include "nv50.h" int -nvd0_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) +nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1) { const u32 hoff = (head * 0x800); + union { + struct nv50_disp_sor_hdmi_pwr_v0 v0; + } *args = data; + u32 ctrl; + int ret; - if (!(data & NV84_DISP_SOR_HDMI_PWR_STATE_ON)) { + nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); + if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) + return -EINVAL; + ctrl = 0x40000000 * !!args->v0.state; + ctrl |= args->v0.max_ac_packet << 16; + ctrl |= args->v0.rekey; + } else + return ret; + + if (!(ctrl & 0x40000000)) { nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000); nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000); @@ -54,9 +74,6 @@ nvd0_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001); /* HDMI_CTRL */ - nv_mask(priv, 0x616798 + hoff, 0x401f007f, data); - - /* NFI, audio doesn't work without it though.. */ - nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000); + nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c new file mode 100644 index 000000000000..528d14ec2f7f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c @@ -0,0 +1,83 @@ +/* + * Copyright 2014 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 <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> + +#include "nv50.h" + +int +nve0_hdmi_ctrl(NV50_DISP_MTHD_V1) +{ + const u32 hoff = (head * 0x800); + const u32 hdmi = (head * 0x400); + union { + struct nv50_disp_sor_hdmi_pwr_v0 v0; + } *args = data; + u32 ctrl; + int ret; + + nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); + if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) + return -EINVAL; + ctrl = 0x40000000 * !!args->v0.state; + ctrl |= args->v0.max_ac_packet << 16; + ctrl |= args->v0.rekey; + } else + return ret; + + if (!(ctrl & 0x40000000)) { + nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); + nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); + return 0; + } + + /* AVI InfoFrame */ + nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); + nv_wr32(priv, 0x690008 + hdmi, 0x000d0282); + nv_wr32(priv, 0x69000c + hdmi, 0x0000006f); + nv_wr32(priv, 0x690010 + hdmi, 0x00000000); + nv_wr32(priv, 0x690014 + hdmi, 0x00000000); + nv_wr32(priv, 0x690018 + hdmi, 0x00000000); + nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001); + + /* ??? InfoFrame? */ + nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nv_wr32(priv, 0x6900cc + hdmi, 0x00000010); + nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001); + + /* ??? */ + nv_wr32(priv, 0x690080 + hdmi, 0x82000000); + + /* HDMI_CTRL */ + nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c index a32666ed0c47..366f315fc9a5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c @@ -24,60 +24,100 @@ #include "priv.h" +#include <core/client.h> #include <core/event.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> struct nv04_disp_priv { struct nouveau_disp base; }; static int -nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nv04_disp_scanoutpos(struct nouveau_object *object, struct nv04_disp_priv *priv, + void *data, u32 size, int head) { - struct nv04_disp_priv *priv = (void *)object->engine; - struct nv04_display_scanoutpos *args = data; - const int head = (mthd & NV04_DISP_MTHD_HEAD); + const u32 hoff = head * 0x2000; + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; u32 line; + int ret; + + nv_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); + args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff; + args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff; + args->v0.vblanke = args->v0.vtotal - 1; + + args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff; + args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff; + args->v0.hblanke = args->v0.htotal - 1; + + /* + * If output is vga instead of digital then vtotal/htotal is + * invalid so we have to give up and trigger the timestamping + * fallback in the drm core. + */ + if (!args->v0.vtotal || !args->v0.htotal) + return -ENOTSUPP; + + args->v0.time[0] = ktime_to_ns(ktime_get()); + line = nv_rd32(priv, 0x600868 + hoff); + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = (line & 0xffff0000) >> 16; + args->v0.vline = (line & 0x0000ffff); + } else + return ret; - if (size < sizeof(*args)) - return -EINVAL; - - args->vblanks = nv_rd32(priv, 0x680800 + (head * 0x2000)) & 0xffff; - args->vtotal = nv_rd32(priv, 0x680804 + (head * 0x2000)) & 0xffff; - args->vblanke = args->vtotal - 1; - - args->hblanks = nv_rd32(priv, 0x680820 + (head * 0x2000)) & 0xffff; - args->htotal = nv_rd32(priv, 0x680824 + (head * 0x2000)) & 0xffff; - args->hblanke = args->htotal - 1; - - /* - * If output is vga instead of digital then vtotal/htotal is invalid - * so we have to give up and trigger the timestamping fallback in the - * drm core. - */ - if (!args->vtotal || !args->htotal) - return -ENOTSUPP; - - args->time[0] = ktime_to_ns(ktime_get()); - line = nv_rd32(priv, 0x600868 + (head * 0x2000)); - args->time[1] = ktime_to_ns(ktime_get()); - args->hline = (line & 0xffff0000) >> 16; - args->vline = (line & 0x0000ffff); return 0; } -#define HEAD_MTHD(n) (n), (n) + 0x01 +static int +nv04_disp_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size) +{ + union { + struct nv04_disp_mthd_v0 v0; + } *args = data; + struct nv04_disp_priv *priv = (void *)object->engine; + int head, ret; + + nv_ioctl(object, "disp mthd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); + mthd = args->v0.method; + head = args->v0.head; + } else + return ret; -static struct nouveau_omthds -nv04_disp_omthds[] = { - { HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos }, - {} + if (head < 0 || head >= 2) + return -ENXIO; + + switch (mthd) { + case NV04_DISP_SCANOUTPOS: + return nv04_disp_scanoutpos(object, priv, data, size, head); + default: + break; + } + + return -EINVAL; +} + +static struct nouveau_ofuncs +nv04_disp_ofuncs = { + .ctor = _nouveau_object_ctor, + .dtor = nouveau_object_destroy, + .init = nouveau_object_init, + .fini = nouveau_object_fini, + .mthd = nv04_disp_mthd, + .ntfy = nouveau_disp_ntfy, }; static struct nouveau_oclass nv04_disp_sclass[] = { - { NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds }, + { NV04_DISP, &nv04_disp_ofuncs }, {}, }; @@ -86,17 +126,26 @@ nv04_disp_sclass[] = { ******************************************************************************/ static void -nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head) +nv04_disp_vblank_init(struct nvkm_event *event, int type, int head) { - nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001); + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001); } static void -nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head) +nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head) { - nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000); + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000); } +static const struct nvkm_event_func +nv04_disp_vblank_func = { + .ctor = nouveau_disp_vblank_ctor, + .init = nv04_disp_vblank_init, + .fini = nv04_disp_vblank_fini, +}; + static void nv04_disp_intr(struct nouveau_subdev *subdev) { @@ -106,12 +155,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev) u32 pvideo; if (crtc0 & 0x00000001) { - nouveau_event_trigger(priv->base.vblank, 1, 0); + nouveau_disp_vblank(&priv->base, 0); nv_wr32(priv, 0x600100, 0x00000001); } if (crtc1 & 0x00000001) { - nouveau_event_trigger(priv->base.vblank, 1, 1); + nouveau_disp_vblank(&priv->base, 1); nv_wr32(priv, 0x602100, 0x00000001); } @@ -140,9 +189,6 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_engine(priv)->sclass = nv04_disp_sclass; nv_subdev(priv)->intr = nv04_disp_intr; - priv->base.vblank->priv = priv; - priv->base.vblank->enable = nv04_disp_vblank_enable; - priv->base.vblank->disable = nv04_disp_vblank_disable; return 0; } @@ -155,4 +201,5 @@ nv04_disp_oclass = &(struct nouveau_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .vblank = &nv04_disp_vblank_func, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 2283c442a10d..2df3a937037d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -23,10 +23,13 @@ */ #include <core/object.h> +#include <core/client.h> #include <core/parent.h> #include <core/handle.h> -#include <core/class.h> #include <core/enum.h> +#include <nvif/unpack.h> +#include <nvif/class.h> +#include <nvif/event.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -43,14 +46,16 @@ * EVO channel base class ******************************************************************************/ -int +static int nv50_disp_chan_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, int chid, + struct nouveau_oclass *oclass, int head, int length, void **pobject) { + const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs; struct nv50_disp_base *base = (void *)parent; struct nv50_disp_chan *chan; + int chid = impl->chid + head; int ret; if (base->chan & (1 << chid)) @@ -63,12 +68,14 @@ nv50_disp_chan_create_(struct nouveau_object *parent, chan = *pobject; if (ret) return ret; - chan->chid = chid; + + nv_parent(chan)->object_attach = impl->attach; + nv_parent(chan)->object_detach = impl->detach; return 0; } -void +static void nv50_disp_chan_destroy(struct nv50_disp_chan *chan) { struct nv50_disp_base *base = (void *)nv_object(chan)->parent; @@ -76,6 +83,81 @@ nv50_disp_chan_destroy(struct nv50_disp_chan *chan) nouveau_namedb_destroy(&chan->base); } +static void +nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); + nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index); +} + +static void +nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) +{ + struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); + nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index); +} + +void +nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid) +{ + struct nvif_notify_uevent_rep { + } rep; + + nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep)); +} + +int +nv50_disp_chan_uevent_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + struct nv50_disp_dmac *dmac = (void *)object; + union { + struct nvif_notify_uevent_req none; + } *args = data; + int ret; + + if (nvif_unvers(args->none)) { + notify->size = sizeof(struct nvif_notify_uevent_rep); + notify->types = 1; + notify->index = dmac->base.chid; + return 0; + } + + return ret; +} + +const struct nvkm_event_func +nv50_disp_chan_uevent = { + .ctor = nv50_disp_chan_uevent_ctor, + .init = nv50_disp_chan_uevent_init, + .fini = nv50_disp_chan_uevent_fini, +}; + +int +nv50_disp_chan_ntfy(struct nouveau_object *object, u32 type, + struct nvkm_event **pevent) +{ + struct nv50_disp_priv *priv = (void *)object->engine; + switch (type) { + case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: + *pevent = &priv->uevent; + return 0; + default: + break; + } + return -EINVAL; +} + +int +nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size) +{ + struct nv50_disp_chan *chan = (void *)object; + *addr = nv_device_resource_start(nv_device(object), 0) + + 0x640000 + (chan->chid * 0x1000); + *size = 0x001000; + return 0; +} + u32 nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr) { @@ -115,16 +197,16 @@ nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie) nouveau_ramht_remove(base->ramht, cookie); } -int +static int nv50_disp_dmac_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, u32 pushbuf, int chid, + struct nouveau_oclass *oclass, u32 pushbuf, int head, int length, void **pobject) { struct nv50_disp_dmac *dmac; int ret; - ret = nv50_disp_chan_create_(parent, engine, oclass, chid, + ret = nv50_disp_chan_create_(parent, engine, oclass, head, length, pobject); dmac = *pobject; if (ret) @@ -179,7 +261,7 @@ nv50_disp_dmac_init(struct nouveau_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid); + nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid); /* initialise channel for dma command submission */ nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push); @@ -216,7 +298,7 @@ nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend) return -EBUSY; } - /* disable error reporting */ + /* disable error reporting and completion notifications */ nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid); return nv50_disp_chan_fini(&dmac->base, suspend); @@ -397,27 +479,32 @@ nv50_disp_mast_mthd_chan = { } }; -static int +int nv50_disp_mast_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_display_mast_class *args = data; + union { + struct nv50_disp_core_channel_dma_v0 v0; + } *args = data; struct nv50_disp_dmac *mast; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create disp core channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create disp core channel dma vers %d " + "pushbuf %08x\n", + args->v0.version, args->v0.pushbuf); + } else + return ret; - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, 0, sizeof(*mast), (void **)&mast); *pobject = nv_object(mast); if (ret) return ret; - nv_parent(mast)->object_attach = nv50_disp_dmac_object_attach; - nv_parent(mast)->object_detach = nv50_disp_dmac_object_detach; return 0; } @@ -433,7 +520,7 @@ nv50_disp_mast_init(struct nouveau_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x610028, 0x00010001, 0x00010001); + nv_mask(priv, 0x610028, 0x00010000, 0x00010000); /* attempt to unstick channel from some unknown state */ if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000) @@ -473,20 +560,25 @@ nv50_disp_mast_fini(struct nouveau_object *object, bool suspend) return -EBUSY; } - /* disable error reporting */ + /* disable error reporting and completion notifications */ nv_mask(priv, 0x610028, 0x00010001, 0x00000000); return nv50_disp_chan_fini(&mast->base, suspend); } -struct nouveau_ofuncs +struct nv50_disp_chan_impl nv50_disp_mast_ofuncs = { - .ctor = nv50_disp_mast_ctor, - .dtor = nv50_disp_dmac_dtor, - .init = nv50_disp_mast_init, - .fini = nv50_disp_mast_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_mast_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nv50_disp_mast_init, + .base.fini = nv50_disp_mast_fini, + .base.map = nv50_disp_chan_map, + .base.ntfy = nv50_disp_chan_ntfy, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 0, + .attach = nv50_disp_dmac_object_attach, + .detach = nv50_disp_dmac_object_detach, }; /******************************************************************************* @@ -543,39 +635,52 @@ nv50_disp_sync_mthd_chan = { } }; -static int +int nv50_disp_sync_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_display_sync_class *args = data; + union { + struct nv50_disp_base_channel_dma_v0 v0; + } *args = data; + struct nv50_disp_priv *priv = (void *)engine; struct nv50_disp_dmac *dmac; int ret; - if (size < sizeof(*args) || args->head > 1) - return -EINVAL; + nv_ioctl(parent, "create disp base channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create disp base channel dma vers %d " + "pushbuf %08x head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > priv->head.nr) + return -EINVAL; + } else + return ret; - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, - 1 + args->head, sizeof(*dmac), + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, + args->v0.head, sizeof(*dmac), (void **)&dmac); *pobject = nv_object(dmac); if (ret) return ret; - nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach; - nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach; return 0; } -struct nouveau_ofuncs +struct nv50_disp_chan_impl nv50_disp_sync_ofuncs = { - .ctor = nv50_disp_sync_ctor, - .dtor = nv50_disp_dmac_dtor, - .init = nv50_disp_dmac_init, - .fini = nv50_disp_dmac_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_sync_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nv50_disp_dmac_init, + .base.fini = nv50_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 1, + .attach = nv50_disp_dmac_object_attach, + .detach = nv50_disp_dmac_object_detach, }; /******************************************************************************* @@ -620,39 +725,52 @@ nv50_disp_ovly_mthd_chan = { } }; -static int +int nv50_disp_ovly_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_display_ovly_class *args = data; + union { + struct nv50_disp_overlay_channel_dma_v0 v0; + } *args = data; + struct nv50_disp_priv *priv = (void *)engine; struct nv50_disp_dmac *dmac; int ret; - if (size < sizeof(*args) || args->head > 1) - return -EINVAL; + nv_ioctl(parent, "create disp overlay channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create disp overlay channel dma vers %d " + "pushbuf %08x head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > priv->head.nr) + return -EINVAL; + } else + return ret; - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, - 3 + args->head, sizeof(*dmac), + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, + args->v0.head, sizeof(*dmac), (void **)&dmac); *pobject = nv_object(dmac); if (ret) return ret; - nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach; - nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach; return 0; } -struct nouveau_ofuncs +struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs = { - .ctor = nv50_disp_ovly_ctor, - .dtor = nv50_disp_dmac_dtor, - .init = nv50_disp_dmac_init, - .fini = nv50_disp_dmac_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_ovly_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nv50_disp_dmac_init, + .base.fini = nv50_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 3, + .attach = nv50_disp_dmac_object_attach, + .detach = nv50_disp_dmac_object_detach, }; /******************************************************************************* @@ -662,14 +780,14 @@ nv50_disp_ovly_ofuncs = { static int nv50_disp_pioc_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, int chid, + struct nouveau_oclass *oclass, int head, int length, void **pobject) { - return nv50_disp_chan_create_(parent, engine, oclass, chid, + return nv50_disp_chan_create_(parent, engine, oclass, head, length, pobject); } -static void +void nv50_disp_pioc_dtor(struct nouveau_object *object) { struct nv50_disp_pioc *pioc = (void *)object; @@ -727,20 +845,29 @@ nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend) * EVO immediate overlay channel objects ******************************************************************************/ -static int +int nv50_disp_oimm_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_display_oimm_class *args = data; + union { + struct nv50_disp_overlay_v0 v0; + } *args = data; + struct nv50_disp_priv *priv = (void *)engine; struct nv50_disp_pioc *pioc; int ret; - if (size < sizeof(*args) || args->head > 1) - return -EINVAL; + nv_ioctl(parent, "create disp overlay size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create disp overlay vers %d head %d\n", + args->v0.version, args->v0.head); + if (args->v0.head > priv->head.nr) + return -EINVAL; + } else + return ret; - ret = nv50_disp_pioc_create_(parent, engine, oclass, 5 + args->head, + ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, sizeof(*pioc), (void **)&pioc); *pobject = nv_object(pioc); if (ret) @@ -749,34 +876,46 @@ nv50_disp_oimm_ctor(struct nouveau_object *parent, return 0; } -struct nouveau_ofuncs +struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs = { - .ctor = nv50_disp_oimm_ctor, - .dtor = nv50_disp_pioc_dtor, - .init = nv50_disp_pioc_init, - .fini = nv50_disp_pioc_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_oimm_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = nv50_disp_pioc_init, + .base.fini = nv50_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 5, }; /******************************************************************************* * EVO cursor channel objects ******************************************************************************/ -static int +int nv50_disp_curs_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_display_curs_class *args = data; + union { + struct nv50_disp_cursor_v0 v0; + } *args = data; + struct nv50_disp_priv *priv = (void *)engine; struct nv50_disp_pioc *pioc; int ret; - if (size < sizeof(*args) || args->head > 1) - return -EINVAL; + nv_ioctl(parent, "create disp cursor size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create disp cursor vers %d head %d\n", + args->v0.version, args->v0.head); + if (args->v0.head > priv->head.nr) + return -EINVAL; + } else + return ret; - ret = nv50_disp_pioc_create_(parent, engine, oclass, 7 + args->head, + ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, sizeof(*pioc), (void **)&pioc); *pobject = nv_object(pioc); if (ret) @@ -785,14 +924,17 @@ nv50_disp_curs_ctor(struct nouveau_object *parent, return 0; } -struct nouveau_ofuncs +struct nv50_disp_chan_impl nv50_disp_curs_ofuncs = { - .ctor = nv50_disp_curs_ctor, - .dtor = nv50_disp_pioc_dtor, - .init = nv50_disp_pioc_init, - .fini = nv50_disp_pioc_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_curs_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = nv50_disp_pioc_init, + .base.fini = nv50_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 7, }; /******************************************************************************* @@ -800,47 +942,162 @@ nv50_disp_curs_ofuncs = { ******************************************************************************/ int -nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0) { - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv04_display_scanoutpos *args = data; - const int head = (mthd & NV50_DISP_MTHD_HEAD); - u32 blanke, blanks, total; + const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540)); + const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540)); + const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540)); + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + int ret; + + nv_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); + args->v0.vblanke = (blanke & 0xffff0000) >> 16; + args->v0.hblanke = (blanke & 0x0000ffff); + args->v0.vblanks = (blanks & 0xffff0000) >> 16; + args->v0.hblanks = (blanks & 0x0000ffff); + args->v0.vtotal = ( total & 0xffff0000) >> 16; + args->v0.htotal = ( total & 0x0000ffff); + args->v0.time[0] = ktime_to_ns(ktime_get()); + args->v0.vline = /* vline read locks hline */ + nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = + nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; + } else + return ret; - if (size < sizeof(*args) || head >= priv->head.nr) - return -EINVAL; - blanke = nv_rd32(priv, 0x610aec + (head * 0x540)); - blanks = nv_rd32(priv, 0x610af4 + (head * 0x540)); - total = nv_rd32(priv, 0x610afc + (head * 0x540)); - - args->vblanke = (blanke & 0xffff0000) >> 16; - args->hblanke = (blanke & 0x0000ffff); - args->vblanks = (blanks & 0xffff0000) >> 16; - args->hblanks = (blanks & 0x0000ffff); - args->vtotal = ( total & 0xffff0000) >> 16; - args->htotal = ( total & 0x0000ffff); - - args->time[0] = ktime_to_ns(ktime_get()); - args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; - args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */ - args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; return 0; } -static void -nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head) +int +nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd, + void *data, u32 size) { - nv_mask(event->priv, 0x61002c, (4 << head), (4 << head)); -} + const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); + union { + struct nv50_disp_mthd_v0 v0; + struct nv50_disp_mthd_v1 v1; + } *args = data; + struct nv50_disp_priv *priv = (void *)object->engine; + struct nvkm_output *outp = NULL; + struct nvkm_output *temp; + u16 type, mask = 0; + int head, ret; -static void -nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head) -{ - nv_mask(event->priv, 0x61002c, (4 << head), 0); + if (mthd != NV50_DISP_MTHD) + return -EINVAL; + + nv_ioctl(object, "disp mthd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); + mthd = args->v0.method; + head = args->v0.head; + } else + if (nvif_unpack(args->v1, 1, 1, true)) { + nv_ioctl(object, "disp mthd vers %d mthd %02x " + "type %04x mask %04x\n", + args->v1.version, args->v1.method, + args->v1.hasht, args->v1.hashm); + mthd = args->v1.method; + type = args->v1.hasht; + mask = args->v1.hashm; + head = ffs((mask >> 8) & 0x0f) - 1; + } else + return ret; + + if (head < 0 || head >= priv->head.nr) + return -ENXIO; + + if (mask) { + list_for_each_entry(temp, &priv->base.outp, head) { + if ((temp->info.hasht == type) && + (temp->info.hashm & mask) == mask) { + outp = temp; + break; + } + } + if (outp == NULL) + return -ENXIO; + } + + switch (mthd) { + case NV50_DISP_SCANOUTPOS: + return impl->head.scanoutpos(object, priv, data, size, head); + default: + break; + } + + switch (mthd * !!outp) { + case NV50_DISP_MTHD_V1_DAC_PWR: + return priv->dac.power(object, priv, data, size, head, outp); + case NV50_DISP_MTHD_V1_DAC_LOAD: + return priv->dac.sense(object, priv, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_PWR: + return priv->sor.power(object, priv, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_HDA_ELD: + if (!priv->sor.hda_eld) + return -ENODEV; + return priv->sor.hda_eld(object, priv, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: + if (!priv->sor.hdmi) + return -ENODEV; + return priv->sor.hdmi(object, priv, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { + union { + struct nv50_disp_sor_lvds_script_v0 v0; + } *args = data; + nv_ioctl(object, "disp sor lvds script size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp sor lvds script " + "vers %d name %04x\n", + args->v0.version, args->v0.script); + priv->sor.lvdsconf = args->v0.script; + return 0; + } else + return ret; + } + break; + case NV50_DISP_MTHD_V1_SOR_DP_PWR: { + struct nvkm_output_dp *outpdp = (void *)outp; + union { + struct nv50_disp_sor_dp_pwr_v0 v0; + } *args = data; + nv_ioctl(object, "disp sor dp pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp sor dp pwr vers %d state %d\n", + args->v0.version, args->v0.state); + if (args->v0.state == 0) { + nvkm_notify_put(&outpdp->irq); + ((struct nvkm_output_dp_impl *)nv_oclass(outp)) + ->lnk_pwr(outpdp, 0); + atomic_set(&outpdp->lt.done, 0); + return 0; + } else + if (args->v0.state != 0) { + nvkm_output_dp_train(&outpdp->base, 0, true); + return 0; + } + } else + return ret; + } + break; + case NV50_DISP_MTHD_V1_PIOR_PWR: + if (!priv->pior.power) + return -ENODEV; + return priv->pior.power(object, priv, data, size, head, outp); + default: + break; + } + + return -EINVAL; } -static int +int nv50_disp_base_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -856,14 +1113,11 @@ nv50_disp_base_ctor(struct nouveau_object *parent, if (ret) return ret; - priv->base.vblank->priv = priv; - priv->base.vblank->enable = nv50_disp_base_vblank_enable; - priv->base.vblank->disable = nv50_disp_base_vblank_disable; return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0, &base->ramht); } -static void +void nv50_disp_base_dtor(struct nouveau_object *object) { struct nv50_disp_base *base = (void *)object; @@ -958,34 +1212,23 @@ nv50_disp_base_ofuncs = { .dtor = nv50_disp_base_dtor, .init = nv50_disp_base_init, .fini = nv50_disp_base_fini, -}; - -static struct nouveau_omthds -nv50_disp_base_omthds[] = { - { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, - { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, - { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, - { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, - {}, + .mthd = nv50_disp_base_mthd, + .ntfy = nouveau_disp_ntfy, }; static struct nouveau_oclass nv50_disp_base_oclass[] = { - { NV50_DISP_CLASS, &nv50_disp_base_ofuncs, nv50_disp_base_omthds }, + { NV50_DISP, &nv50_disp_base_ofuncs }, {} }; static struct nouveau_oclass nv50_disp_sclass[] = { - { NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, - { NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, - { NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, - { NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, - { NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, + { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, + { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, + { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, {} }; @@ -1005,7 +1248,7 @@ nv50_disp_data_ctor(struct nouveau_object *parent, int ret = -EBUSY; /* no context needed for channel objects... */ - if (nv_mclass(parent) != NV_DEVICE_CLASS) { + if (nv_mclass(parent) != NV_DEVICE) { atomic_inc(&parent->refcount); *pobject = parent; return 1; @@ -1040,6 +1283,27 @@ nv50_disp_cclass = { * Display engine implementation ******************************************************************************/ +static void +nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x61002c, (4 << head), 0); +} + +static void +nv50_disp_vblank_init(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x61002c, (4 << head), (4 << head)); +} + +const struct nvkm_event_func +nv50_disp_vblank_func = { + .ctor = nouveau_disp_vblank_ctor, + .init = nv50_disp_vblank_init, + .fini = nv50_disp_vblank_fini, +}; + static const struct nouveau_enum nv50_disp_intr_error_type[] = { { 3, "ILLEGAL_MTHD" }, @@ -1366,7 +1630,7 @@ nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head) } static void -nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, +nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, struct dcb_output *outp, u32 pclk) { const int link = !(outp->sorconf.link & 1); @@ -1375,24 +1639,36 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, const u32 loff = (link * 0x080) + soff; const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8)); const u32 symbol = 100000; - u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000; + const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff; + const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff; + const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff; + u32 dpctrl = nv_rd32(priv, 0x61c10c + loff); u32 clksor = nv_rd32(priv, 0x614300 + soff); int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; int TU, VTUi, VTUf, VTUa; u64 link_data_rate, link_ratio, unk; u32 best_diff = 64 * symbol; - u32 link_nr, link_bw, bits, r; - - /* calculate packed data rate for each lane */ - if (dpctrl > 0x00030000) link_nr = 4; - else if (dpctrl > 0x00010000) link_nr = 2; - else link_nr = 1; - - if (clksor & 0x000c0000) - link_bw = 270000; - else - link_bw = 162000; - + u32 link_nr, link_bw, bits; + u64 value; + + link_bw = (clksor & 0x000c0000) ? 270000 : 162000; + link_nr = hweight32(dpctrl & 0x000f0000); + + /* symbols/hblank - algorithm taken from comments in tegra driver */ + value = vblanke + vactive - vblanks - 7; + value = value * link_bw; + do_div(value, pclk); + value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); + nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value); + + /* symbols/vblank - algorithm taken from comments in tegra driver */ + value = vblanks - vblanke - 25; + value = value * link_bw; + do_div(value, pclk); + value = value - ((36 / link_nr) + 3) - 1; + nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value); + + /* watermark / activesym */ if ((ctrl & 0xf0000) == 0x60000) bits = 30; else if ((ctrl & 0xf0000) == 0x50000) bits = 24; else bits = 18; @@ -1401,7 +1677,7 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, /* calculate ratio of packed data rate to link symbol rate */ link_ratio = link_data_rate * symbol; - r = do_div(link_ratio, link_bw); + do_div(link_ratio, link_bw); for (TU = 64; TU >= 32; TU--) { /* calculate average number of valid symbols in each TU */ @@ -1462,8 +1738,8 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, /* XXX close to vbios numbers, but not right */ unk = (symbol - link_ratio) * bestTU; unk *= link_ratio; - r = do_div(unk, symbol); - r = do_div(unk, symbol); + do_div(unk, symbol); + do_div(unk, symbol); unk += 6; nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2); @@ -1538,7 +1814,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) } else if (!outp->info.location) { if (outp->info.type == DCB_OUTPUT_DP) - nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk); + nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk); oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800; oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; hval = 0x00000000; @@ -1570,9 +1846,10 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp const int or = ffs(outp->or) - 1; const u32 loff = (or * 0x800) + (link * 0x80); const u16 mask = (outp->sorconf.link << 6) | outp->or; + struct dcb_output match; u8 ver, hdr; - if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp)) + if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000); } @@ -1653,14 +1930,20 @@ nv50_disp_intr(struct nouveau_subdev *subdev) intr0 &= ~(0x00010000 << chid); } + while (intr0 & 0x0000001f) { + u32 chid = __ffs(intr0 & 0x0000001f); + nv50_disp_chan_uevent_send(priv, chid); + intr0 &= ~(0x00000001 << chid); + } + if (intr1 & 0x00000004) { - nouveau_event_trigger(priv->base.vblank, 1, 0); + nouveau_disp_vblank(&priv->base, 0); nv_wr32(priv, 0x610024, 0x00000004); intr1 &= ~0x00000004; } if (intr1 & 0x00000008) { - nouveau_event_trigger(priv->base.vblank, 1, 1); + nouveau_disp_vblank(&priv->base, 1); nv_wr32(priv, 0x610024, 0x00000008); intr1 &= ~0x00000008; } @@ -1687,6 +1970,10 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nv50_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nv50_disp_intr; @@ -1718,9 +2005,11 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv50_disp_mast_mthd_chan, .mthd.base = &nv50_disp_sync_mthd_chan, .mthd.ovly = &nv50_disp_ovly_mthd_chan, .mthd.prev = 0x000004, + .head.scanoutpos = nv50_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index 1a886472b6f5..5279feefec06 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -14,15 +14,10 @@ #include "outp.h" #include "outpdp.h" -struct nv50_disp_impl { - struct nouveau_disp_impl base; - struct { - const struct nv50_disp_mthd_chan *core; - const struct nv50_disp_mthd_chan *base; - const struct nv50_disp_mthd_chan *ovly; - int prev; - } mthd; -}; +#define NV50_DISP_MTHD_ struct nouveau_object *object, \ + struct nv50_disp_priv *priv, void *data, u32 size +#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head +#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp struct nv50_disp_priv { struct nouveau_disp base; @@ -31,49 +26,60 @@ struct nv50_disp_priv { struct work_struct supervisor; u32 super; + struct nvkm_event uevent; + struct { int nr; } head; struct { int nr; - int (*power)(struct nv50_disp_priv *, int dac, u32 data); - int (*sense)(struct nv50_disp_priv *, int dac, u32 load); + int (*power)(NV50_DISP_MTHD_V1); + int (*sense)(NV50_DISP_MTHD_V1); } dac; struct { int nr; - int (*power)(struct nv50_disp_priv *, int sor, u32 data); - int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); - int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); + int (*power)(NV50_DISP_MTHD_V1); + int (*hda_eld)(NV50_DISP_MTHD_V1); + int (*hdmi)(NV50_DISP_MTHD_V1); u32 lvdsconf; } sor; struct { int nr; - int (*power)(struct nv50_disp_priv *, int ext, u32 data); + int (*power)(NV50_DISP_MTHD_V1); u8 type[3]; } pior; }; -#define HEAD_MTHD(n) (n), (n) + 0x03 - -int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32); +struct nv50_disp_impl { + struct nouveau_disp_impl base; + struct { + const struct nv50_disp_mthd_chan *core; + const struct nv50_disp_mthd_chan *base; + const struct nv50_disp_mthd_chan *ovly; + int prev; + } mthd; + struct { + int (*scanoutpos)(NV50_DISP_MTHD_V0); + } head; +}; -#define DAC_MTHD(n) (n), (n) + 0x03 +int nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0); +int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32); -int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32); -int nv50_dac_power(struct nv50_disp_priv *, int, u32); -int nv50_dac_sense(struct nv50_disp_priv *, int, u32); +int nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0); -#define SOR_MTHD(n) (n), (n) + 0x3f +int nv50_dac_power(NV50_DISP_MTHD_V1); +int nv50_dac_sense(NV50_DISP_MTHD_V1); -int nva3_hda_eld(struct nv50_disp_priv *, int, u8 *, u32); -int nvd0_hda_eld(struct nv50_disp_priv *, int, u8 *, u32); +int nva3_hda_eld(NV50_DISP_MTHD_V1); +int nvd0_hda_eld(NV50_DISP_MTHD_V1); -int nv84_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32); -int nva3_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32); -int nvd0_hdmi_ctrl(struct nv50_disp_priv *, int, int, u32); +int nv84_hdmi_ctrl(NV50_DISP_MTHD_V1); +int nva3_hdmi_ctrl(NV50_DISP_MTHD_V1); +int nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1); +int nve0_hdmi_ctrl(NV50_DISP_MTHD_V1); -int nv50_sor_mthd(struct nouveau_object *, u32, void *, u32); -int nv50_sor_power(struct nv50_disp_priv *, int, u32); +int nv50_sor_power(NV50_DISP_MTHD_V1); int nv94_sor_dp_train_init(struct nv50_disp_priv *, int, int, int, u16, u16, u32, struct dcb_output *); @@ -93,10 +99,7 @@ int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32, struct dcb_output *); -#define PIOR_MTHD(n) (n), (n) + 0x03 - -int nv50_pior_mthd(struct nouveau_object *, u32, void *, u32); -int nv50_pior_power(struct nv50_disp_priv *, int, u32); +int nv50_pior_power(NV50_DISP_MTHD_V1); struct nv50_disp_base { struct nouveau_parent base; @@ -104,36 +107,48 @@ struct nv50_disp_base { u32 chan; }; +struct nv50_disp_chan_impl { + struct nouveau_ofuncs base; + int chid; + int (*attach)(struct nouveau_object *, struct nouveau_object *, u32); + void (*detach)(struct nouveau_object *, int); +}; + struct nv50_disp_chan { struct nouveau_namedb base; int chid; }; -int nv50_disp_chan_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, int, void **); -void nv50_disp_chan_destroy(struct nv50_disp_chan *); +int nv50_disp_chan_ntfy(struct nouveau_object *, u32, struct nvkm_event **); +int nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *); u32 nv50_disp_chan_rd32(struct nouveau_object *, u64); void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32); +extern const struct nvkm_event_func nv50_disp_chan_uevent; +int nv50_disp_chan_uevent_ctor(struct nouveau_object *, void *, u32, + struct nvkm_notify *); +void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int); + +extern const struct nvkm_event_func nvd0_disp_chan_uevent; #define nv50_disp_chan_init(a) \ nouveau_namedb_init(&(a)->base) #define nv50_disp_chan_fini(a,b) \ nouveau_namedb_fini(&(a)->base, (b)) -int nv50_disp_dmac_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, u32, int, int, void **); -void nv50_disp_dmac_dtor(struct nouveau_object *); - struct nv50_disp_dmac { struct nv50_disp_chan base; struct nouveau_dmaobj *pushdma; u32 push; }; +void nv50_disp_dmac_dtor(struct nouveau_object *); + struct nv50_disp_pioc { struct nv50_disp_chan base; }; +void nv50_disp_pioc_dtor(struct nouveau_object *); + struct nv50_disp_mthd_list { u32 mthd; u32 addr; @@ -154,47 +169,67 @@ struct nv50_disp_mthd_chan { } data[]; }; -extern struct nouveau_ofuncs nv50_disp_mast_ofuncs; +extern struct nv50_disp_chan_impl nv50_disp_mast_ofuncs; +int nv50_disp_mast_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_base; extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_sor; extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_pior; -extern struct nouveau_ofuncs nv50_disp_sync_ofuncs; +extern struct nv50_disp_chan_impl nv50_disp_sync_ofuncs; +int nv50_disp_sync_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); extern const struct nv50_disp_mthd_list nv50_disp_sync_mthd_image; -extern struct nouveau_ofuncs nv50_disp_ovly_ofuncs; +extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs; +int nv50_disp_ovly_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; -extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs; -extern struct nouveau_ofuncs nv50_disp_curs_ofuncs; +extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs; +int nv50_disp_oimm_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs; +int nv50_disp_curs_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); extern struct nouveau_ofuncs nv50_disp_base_ofuncs; +int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nv50_disp_base_dtor(struct nouveau_object *); +extern struct nouveau_omthds nv50_disp_base_omthds[]; extern struct nouveau_oclass nv50_disp_cclass; void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head, const struct nv50_disp_mthd_chan *); void nv50_disp_intr_supervisor(struct work_struct *); void nv50_disp_intr(struct nouveau_subdev *); +extern const struct nvkm_event_func nv50_disp_vblank_func; extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac; extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head; extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan; extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan; -extern struct nouveau_omthds nv84_disp_base_omthds[]; extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan; -extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs; +extern struct nv50_disp_chan_impl nvd0_disp_mast_ofuncs; extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_base; extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_dac; extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_sor; extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_pior; -extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs; -extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs; +extern struct nv50_disp_chan_impl nvd0_disp_sync_ofuncs; +extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs; extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan; -extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs; -extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs; -extern struct nouveau_omthds nvd0_disp_base_omthds[]; +extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs; +extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs; extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; extern struct nouveau_oclass nvd0_disp_cclass; void nvd0_disp_intr_supervisor(struct work_struct *); void nvd0_disp_intr(struct nouveau_subdev *); +extern const struct nvkm_event_func nvd0_disp_vblank_func; extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index 1cc62e434683..d36284715b2a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c @@ -25,7 +25,7 @@ #include <engine/software.h> #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "nv50.h" @@ -204,31 +204,17 @@ nv84_disp_ovly_mthd_chan = { static struct nouveau_oclass nv84_disp_sclass[] = { - { NV84_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, - { NV84_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, - { NV84_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, - { NV84_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, - { NV84_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, + { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, + { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, + { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, {} }; -struct nouveau_omthds -nv84_disp_base_omthds[] = { - { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, - { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, - { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, - { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, - {}, -}; - static struct nouveau_oclass nv84_disp_base_oclass[] = { - { NV84_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds }, + { G82_DISP, &nv50_disp_base_ofuncs }, {} }; @@ -250,6 +236,10 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nv84_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nv50_disp_intr; @@ -276,9 +266,11 @@ nv84_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv84_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.prev = 0x000004, + .head.scanoutpos = nv50_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c index 4f718a9f5aef..a117064002b1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c @@ -25,7 +25,7 @@ #include <engine/software.h> #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "nv50.h" @@ -63,32 +63,17 @@ nv94_disp_mast_mthd_chan = { static struct nouveau_oclass nv94_disp_sclass[] = { - { NV94_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, - { NV94_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, - { NV94_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, - { NV94_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, - { NV94_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, + { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, + { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, + { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, {} }; -static struct nouveau_omthds -nv94_disp_base_omthds[] = { - { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, - { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, - { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd }, - { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, - { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, - {}, -}; - static struct nouveau_oclass nv94_disp_base_oclass[] = { - { NV94_DISP_CLASS, &nv50_disp_base_ofuncs, nv94_disp_base_omthds }, + { GT206_DISP, &nv50_disp_base_ofuncs }, {} }; @@ -110,6 +95,10 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nv94_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nv50_disp_intr; @@ -143,9 +132,11 @@ nv94_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv94_disp_outp_sclass, .mthd.core = &nv94_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.prev = 0x000004, + .head.scanoutpos = nv50_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c index 6237a9a36f70..c67e68aadd45 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c @@ -25,7 +25,7 @@ #include <engine/software.h> #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "nv50.h" @@ -80,17 +80,17 @@ nva0_disp_ovly_mthd_chan = { static struct nouveau_oclass nva0_disp_sclass[] = { - { NVA0_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, - { NVA0_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, - { NVA0_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, - { NVA0_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, - { NVA0_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, + { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, + { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, + { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, {} }; static struct nouveau_oclass nva0_disp_base_oclass[] = { - { NVA0_DISP_CLASS, &nv50_disp_base_ofuncs, nv84_disp_base_omthds }, + { GT200_DISP, &nv50_disp_base_ofuncs }, {} }; @@ -112,6 +112,10 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nva0_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nv50_disp_intr; @@ -138,9 +142,11 @@ nva0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv84_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, .mthd.ovly = &nva0_disp_ovly_mthd_chan, .mthd.prev = 0x000004, + .head.scanoutpos = nv50_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index 019124d4782b..22969f355aae 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c @@ -25,7 +25,7 @@ #include <engine/software.h> #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "nv50.h" @@ -35,33 +35,17 @@ static struct nouveau_oclass nva3_disp_sclass[] = { - { NVA3_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, - { NVA3_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, - { NVA3_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, - { NVA3_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, - { NVA3_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, + { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, + { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, + { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, {} }; -static struct nouveau_omthds -nva3_disp_base_omthds[] = { - { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, - { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, - { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, - { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd }, - { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, - { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, - {}, -}; - static struct nouveau_oclass nva3_disp_base_oclass[] = { - { NVA3_DISP_CLASS, &nv50_disp_base_ofuncs, nva3_disp_base_omthds }, + { GT214_DISP, &nv50_disp_base_ofuncs }, {} }; @@ -83,6 +67,10 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nva3_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nv50_disp_intr; @@ -110,9 +98,11 @@ nva3_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nv50_disp_vblank_func, .base.outp = nv94_disp_outp_sclass, .mthd.core = &nv94_disp_mast_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.prev = 0x000004, + .head.scanoutpos = nv50_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index fa30d8196f35..747e64bb9c06 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -23,9 +23,11 @@ */ #include <core/object.h> +#include <core/client.h> #include <core/parent.h> #include <core/handle.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <engine/disp.h> @@ -41,6 +43,31 @@ #include "nv50.h" /******************************************************************************* + * EVO channel base class + ******************************************************************************/ + +static void +nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); + nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index); +} + +static void +nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) +{ + struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); + nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index); +} + +const struct nvkm_event_func +nvd0_disp_chan_uevent = { + .ctor = nv50_disp_chan_uevent_ctor, + .init = nvd0_disp_chan_uevent_init, + .fini = nvd0_disp_chan_uevent_fini, +}; + +/******************************************************************************* * EVO DMA channel base class ******************************************************************************/ @@ -75,7 +102,6 @@ nvd0_disp_dmac_init(struct nouveau_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid); nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); /* initialise channel for dma command submission */ @@ -113,7 +139,7 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend) return -EBUSY; } - /* disable error reporting */ + /* disable error reporting and completion notification */ nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000); nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000); @@ -265,30 +291,6 @@ nvd0_disp_mast_mthd_chan = { }; static int -nvd0_disp_mast_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_display_mast_class *args = data; - struct nv50_disp_dmac *mast; - int ret; - - if (size < sizeof(*args)) - return -EINVAL; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, - 0, sizeof(*mast), (void **)&mast); - *pobject = nv_object(mast); - if (ret) - return ret; - - nv_parent(mast)->object_attach = nvd0_disp_dmac_object_attach; - nv_parent(mast)->object_detach = nvd0_disp_dmac_object_detach; - return 0; -} - -static int nvd0_disp_mast_init(struct nouveau_object *object) { struct nv50_disp_priv *priv = (void *)object->engine; @@ -300,7 +302,6 @@ nvd0_disp_mast_init(struct nouveau_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x610090, 0x00000001, 0x00000001); nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001); /* initialise channel for dma command submission */ @@ -335,21 +336,26 @@ nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend) return -EBUSY; } - /* disable error reporting */ + /* disable error reporting and completion notification */ nv_mask(priv, 0x610090, 0x00000001, 0x00000000); nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000); return nv50_disp_chan_fini(&mast->base, suspend); } -struct nouveau_ofuncs +struct nv50_disp_chan_impl nvd0_disp_mast_ofuncs = { - .ctor = nvd0_disp_mast_ctor, - .dtor = nv50_disp_dmac_dtor, - .init = nvd0_disp_mast_init, - .fini = nvd0_disp_mast_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_mast_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nvd0_disp_mast_init, + .base.fini = nvd0_disp_mast_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 0, + .attach = nvd0_disp_dmac_object_attach, + .detach = nvd0_disp_dmac_object_detach, }; /******************************************************************************* @@ -431,40 +437,19 @@ nvd0_disp_sync_mthd_chan = { } }; -static int -nvd0_disp_sync_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_display_sync_class *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - if (size < sizeof(*args) || args->head >= priv->head.nr) - return -EINVAL; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, - 1 + args->head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach; - nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach; - return 0; -} - -struct nouveau_ofuncs +struct nv50_disp_chan_impl nvd0_disp_sync_ofuncs = { - .ctor = nvd0_disp_sync_ctor, - .dtor = nv50_disp_dmac_dtor, - .init = nvd0_disp_dmac_init, - .fini = nvd0_disp_dmac_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_sync_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nvd0_disp_dmac_init, + .base.fini = nvd0_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 1, + .attach = nvd0_disp_dmac_object_attach, + .detach = nvd0_disp_dmac_object_detach, }; /******************************************************************************* @@ -533,40 +518,19 @@ nvd0_disp_ovly_mthd_chan = { } }; -static int -nvd0_disp_ovly_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_display_ovly_class *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - if (size < sizeof(*args) || args->head >= priv->head.nr) - return -EINVAL; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, - 5 + args->head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach; - nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach; - return 0; -} - -struct nouveau_ofuncs +struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs = { - .ctor = nvd0_disp_ovly_ctor, - .dtor = nv50_disp_dmac_dtor, - .init = nvd0_disp_dmac_init, - .fini = nvd0_disp_dmac_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_ovly_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nvd0_disp_dmac_init, + .base.fini = nvd0_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 5, + .attach = nvd0_disp_dmac_object_attach, + .detach = nvd0_disp_dmac_object_detach, }; /******************************************************************************* @@ -574,23 +538,6 @@ nvd0_disp_ovly_ofuncs = { ******************************************************************************/ static int -nvd0_disp_pioc_create_(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, int chid, - int length, void **pobject) -{ - return nv50_disp_chan_create_(parent, engine, oclass, chid, - length, pobject); -} - -static void -nvd0_disp_pioc_dtor(struct nouveau_object *object) -{ - struct nv50_disp_pioc *pioc = (void *)object; - nv50_disp_chan_destroy(&pioc->base); -} - -static int nvd0_disp_pioc_init(struct nouveau_object *object) { struct nv50_disp_priv *priv = (void *)object->engine; @@ -603,7 +550,6 @@ nvd0_disp_pioc_init(struct nouveau_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid); nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); /* activate channel */ @@ -632,7 +578,7 @@ nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend) return -EBUSY; } - /* disable error reporting */ + /* disable error reporting and completion notification */ nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000); nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000); @@ -643,152 +589,70 @@ nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend) * EVO immediate overlay channel objects ******************************************************************************/ -static int -nvd0_disp_oimm_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_display_oimm_class *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; - - if (size < sizeof(*args) || args->head >= priv->head.nr) - return -EINVAL; - - ret = nvd0_disp_pioc_create_(parent, engine, oclass, 9 + args->head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; -} - -struct nouveau_ofuncs +struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs = { - .ctor = nvd0_disp_oimm_ctor, - .dtor = nvd0_disp_pioc_dtor, - .init = nvd0_disp_pioc_init, - .fini = nvd0_disp_pioc_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_oimm_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = nvd0_disp_pioc_init, + .base.fini = nvd0_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 9, }; /******************************************************************************* * EVO cursor channel objects ******************************************************************************/ -static int -nvd0_disp_curs_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_display_curs_class *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; - - if (size < sizeof(*args) || args->head >= priv->head.nr) - return -EINVAL; - - ret = nvd0_disp_pioc_create_(parent, engine, oclass, 13 + args->head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; -} - -struct nouveau_ofuncs +struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs = { - .ctor = nvd0_disp_curs_ctor, - .dtor = nvd0_disp_pioc_dtor, - .init = nvd0_disp_pioc_init, - .fini = nvd0_disp_pioc_fini, - .rd32 = nv50_disp_chan_rd32, - .wr32 = nv50_disp_chan_wr32, + .base.ctor = nv50_disp_curs_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = nvd0_disp_pioc_init, + .base.fini = nvd0_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 13, }; /******************************************************************************* * Base display object ******************************************************************************/ -static int -nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, - void *data, u32 size) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv04_display_scanoutpos *args = data; - const int head = (mthd & NV50_DISP_MTHD_HEAD); - u32 blanke, blanks, total; - - if (size < sizeof(*args) || head >= priv->head.nr) - return -EINVAL; - - total = nv_rd32(priv, 0x640414 + (head * 0x300)); - blanke = nv_rd32(priv, 0x64041c + (head * 0x300)); - blanks = nv_rd32(priv, 0x640420 + (head * 0x300)); - - args->vblanke = (blanke & 0xffff0000) >> 16; - args->hblanke = (blanke & 0x0000ffff); - args->vblanks = (blanks & 0xffff0000) >> 16; - args->hblanks = (blanks & 0x0000ffff); - args->vtotal = ( total & 0xffff0000) >> 16; - args->htotal = ( total & 0x0000ffff); - - args->time[0] = ktime_to_ns(ktime_get()); - args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; - args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */ - args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; - return 0; -} - -static void -nvd0_disp_base_vblank_enable(struct nouveau_event *event, int type, int head) -{ - nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); -} - -static void -nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head) -{ - nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); -} - -static int -nvd0_disp_base_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +int +nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0) { - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_base *base; + const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300)); + const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300)); + const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300)); + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; int ret; - ret = nouveau_parent_create(parent, engine, oclass, 0, - priv->sclass, 0, &base); - *pobject = nv_object(base); - if (ret) + nv_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); + args->v0.vblanke = (blanke & 0xffff0000) >> 16; + args->v0.hblanke = (blanke & 0x0000ffff); + args->v0.vblanks = (blanks & 0xffff0000) >> 16; + args->v0.hblanks = (blanks & 0x0000ffff); + args->v0.vtotal = ( total & 0xffff0000) >> 16; + args->v0.htotal = ( total & 0x0000ffff); + args->v0.time[0] = ktime_to_ns(ktime_get()); + args->v0.vline = /* vline read locks hline */ + nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = + nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; + } else return ret; - priv->base.vblank->priv = priv; - priv->base.vblank->enable = nvd0_disp_base_vblank_enable; - priv->base.vblank->disable = nvd0_disp_base_vblank_disable; - - return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0, - &base->ramht); -} - -static void -nvd0_disp_base_dtor(struct nouveau_object *object) -{ - struct nv50_disp_base *base = (void *)object; - nouveau_ramht_ref(NULL, &base->ramht); - nouveau_parent_destroy(&base->base); + return 0; } static int @@ -874,41 +738,27 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend) struct nouveau_ofuncs nvd0_disp_base_ofuncs = { - .ctor = nvd0_disp_base_ctor, - .dtor = nvd0_disp_base_dtor, + .ctor = nv50_disp_base_ctor, + .dtor = nv50_disp_base_dtor, .init = nvd0_disp_base_init, .fini = nvd0_disp_base_fini, -}; - -struct nouveau_omthds -nvd0_disp_base_omthds[] = { - { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nvd0_disp_base_scanoutpos }, - { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, - { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, - { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, - { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd }, - { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, - { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, - { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd }, - {}, + .mthd = nv50_disp_base_mthd, + .ntfy = nouveau_disp_ntfy, }; static struct nouveau_oclass nvd0_disp_base_oclass[] = { - { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, + { GF110_DISP, &nvd0_disp_base_ofuncs }, {} }; static struct nouveau_oclass nvd0_disp_sclass[] = { - { NVD0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, - { NVD0_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs }, - { NVD0_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs }, - { NVD0_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs }, - { NVD0_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs }, + { GF110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, + { GF110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, + { GF110_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, + { GF110_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, + { GF110_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, {} }; @@ -916,6 +766,27 @@ nvd0_disp_sclass[] = { * Display engine implementation ******************************************************************************/ +static void +nvd0_disp_vblank_init(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); +} + +static void +nvd0_disp_vblank_fini(struct nvkm_event *event, int type, int head) +{ + struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank); + nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); +} + +const struct nvkm_event_func +nvd0_disp_vblank_func = { + .ctor = nouveau_disp_vblank_ctor, + .init = nvd0_disp_vblank_init, + .fini = nvd0_disp_vblank_fini, +}; + static struct nvkm_output * exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, @@ -1105,6 +976,9 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, const int or = ffs(outp->or) - 1; const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020)); const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300)); + const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff; + const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff; + const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff; const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; const u32 hoff = (head * 0x800); @@ -1112,23 +986,35 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, const u32 loff = (link * 0x080) + soff; const u32 symbol = 100000; const u32 TU = 64; - u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x000f0000; + u32 dpctrl = nv_rd32(priv, 0x61c10c + loff); u32 clksor = nv_rd32(priv, 0x612300 + soff); u32 datarate, link_nr, link_bw, bits; u64 ratio, value; + link_nr = hweight32(dpctrl & 0x000f0000); + link_bw = (clksor & 0x007c0000) >> 18; + link_bw *= 27000; + + /* symbols/hblank - algorithm taken from comments in tegra driver */ + value = vblanke + vactive - vblanks - 7; + value = value * link_bw; + do_div(value, pclk); + value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); + nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value); + + /* symbols/vblank - algorithm taken from comments in tegra driver */ + value = vblanks - vblanke - 25; + value = value * link_bw; + do_div(value, pclk); + value = value - ((36 / link_nr) + 3) - 1; + nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value); + + /* watermark */ if ((conf & 0x3c0) == 0x180) bits = 30; else if ((conf & 0x3c0) == 0x140) bits = 24; else bits = 18; datarate = (pclk * bits) / 8; - if (dpctrl > 0x00030000) link_nr = 4; - else if (dpctrl > 0x00010000) link_nr = 2; - else link_nr = 1; - - link_bw = (clksor & 0x007c0000) >> 18; - link_bw *= 27000; - ratio = datarate; ratio *= symbol; do_div(ratio, link_nr * link_bw); @@ -1309,7 +1195,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) if (intr & 0x00000001) { u32 stat = nv_rd32(priv, 0x61008c); - nv_wr32(priv, 0x61008c, stat); + while (stat) { + int chid = __ffs(stat); stat &= ~(1 << chid); + nv50_disp_chan_uevent_send(priv, chid); + nv_wr32(priv, 0x61008c, 1 << chid); + } intr &= ~0x00000001; } @@ -1343,7 +1233,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) if (mask & intr) { u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); if (stat & 0x00000001) - nouveau_event_trigger(priv->base.vblank, 1, i); + nouveau_disp_vblank(&priv->base, i); nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); nv_rd32(priv, 0x6100c0 + (i * 0x800)); } @@ -1365,6 +1255,10 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nvd0_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nvd0_disp_intr; @@ -1396,9 +1290,11 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nvd0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.ovly = &nvd0_disp_ovly_mthd_chan, .mthd.prev = -0x020000, + .head.scanoutpos = nvd0_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index 11328e3f5df1..db144b2cf06b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c @@ -25,7 +25,7 @@ #include <engine/software.h> #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "nv50.h" @@ -200,17 +200,17 @@ nve0_disp_ovly_mthd_chan = { static struct nouveau_oclass nve0_disp_sclass[] = { - { NVE0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, - { NVE0_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs }, - { NVE0_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs }, - { NVE0_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs }, - { NVE0_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs }, + { GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, + { GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, + { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, + { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, + { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, {} }; static struct nouveau_oclass nve0_disp_base_oclass[] = { - { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, + { GK104_DISP, &nvd0_disp_base_ofuncs }, {} }; @@ -233,6 +233,10 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nve0_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nvd0_disp_intr; @@ -245,7 +249,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; - priv->sor.hdmi = nvd0_hdmi_ctrl; + priv->sor.hdmi = nve0_hdmi_ctrl; return 0; } @@ -258,9 +262,11 @@ nve0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nve0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.prev = -0x020000, + .head.scanoutpos = nvd0_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c index 104388081d73..402d7d67d806 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c @@ -25,7 +25,7 @@ #include <engine/software.h> #include <engine/disp.h> -#include <core/class.h> +#include <nvif/class.h> #include "nv50.h" @@ -35,17 +35,17 @@ static struct nouveau_oclass nvf0_disp_sclass[] = { - { NVF0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, - { NVF0_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs }, - { NVF0_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs }, - { NVF0_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs }, - { NVF0_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs }, + { GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, + { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, + { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, + { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, + { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, {} }; static struct nouveau_oclass nvf0_disp_base_oclass[] = { - { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, + { GK110_DISP, &nvd0_disp_base_ofuncs }, {} }; @@ -68,6 +68,10 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent); + if (ret) + return ret; + nv_engine(priv)->sclass = nvf0_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nvd0_disp_intr; @@ -80,7 +84,7 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; - priv->sor.hdmi = nvd0_hdmi_ctrl; + priv->sor.hdmi = nve0_hdmi_ctrl; return 0; } @@ -93,9 +97,11 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) { .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, + .base.vblank = &nvd0_disp_vblank_func, .base.outp = nvd0_disp_outp_sclass, .mthd.core = &nve0_disp_mast_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.prev = -0x020000, + .head.scanoutpos = nvd0_disp_base_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c index ad9ba7ccec7f..a5ff00a9cedc 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c @@ -78,6 +78,7 @@ nvkm_output_create_(struct nouveau_object *parent, outp->info = *dcbE; outp->index = index; + outp->or = ffs(outp->info.or) - 1; DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n", dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ? diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h index bc76fbf85710..187f435ad0e2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h @@ -9,6 +9,7 @@ struct nvkm_output { struct dcb_output info; int index; + int or; struct nouveau_i2c_port *port; struct nouveau_i2c_port *edid; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c index eb2d7789555d..667a9070e006 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ +#include <core/os.h> +#include <nvif/event.h> + #include <subdev/i2c.h> #include "outpdp.h" @@ -86,7 +89,7 @@ done: atomic_set(&outp->lt.done, 0); schedule_work(&outp->lt.work); } else { - nouveau_event_get(outp->irq); + nvkm_notify_get(&outp->irq); } if (wait) { @@ -133,46 +136,59 @@ nvkm_output_dp_detect(struct nvkm_output_dp *outp) } } -static void -nvkm_output_dp_service_work(struct work_struct *work) +static int +nvkm_output_dp_hpd(struct nvkm_notify *notify) { - struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work); - struct nouveau_disp *disp = nouveau_disp(outp); - int type = atomic_xchg(&outp->pending, 0); - u32 send = 0; - - if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) { - nvkm_output_dp_detect(outp); - if (type & NVKM_I2C_UNPLUG) - send |= NVKM_HPD_UNPLUG; - if (type & NVKM_I2C_PLUG) - send |= NVKM_HPD_PLUG; - nouveau_event_get(outp->base.conn->hpd.event); - } - - if (type & NVKM_I2C_IRQ) { - nvkm_output_dp_train(&outp->base, 0, true); - send |= NVKM_HPD_IRQ; + struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); + struct nvkm_output_dp *outp; + struct nouveau_disp *disp = nouveau_disp(conn); + const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvif_notify_conn_rep_v0 rep = {}; + + list_for_each_entry(outp, &disp->outp, base.head) { + if (outp->base.conn == conn && + outp->info.type == DCB_OUTPUT_DP) { + DBG("HPD: %d\n", line->mask); + nvkm_output_dp_detect(outp); + + if (line->mask & NVKM_I2C_UNPLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; + if (line->mask & NVKM_I2C_PLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; + + nvkm_event_send(&disp->hpd, rep.mask, conn->index, + &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; + } } - nouveau_event_trigger(disp->hpd, send, outp->base.info.connector); + WARN_ON(1); + return NVKM_NOTIFY_DROP; } static int -nvkm_output_dp_service(void *data, u32 type, int index) +nvkm_output_dp_irq(struct nvkm_notify *notify) { - struct nvkm_output_dp *outp = data; - DBG("HPD: %d\n", type); - atomic_or(type, &outp->pending); - schedule_work(&outp->work); - return NVKM_EVENT_DROP; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); + struct nouveau_disp *disp = nouveau_disp(outp); + const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvif_notify_conn_rep_v0 rep = { + .mask = NVIF_NOTIFY_CONN_V0_IRQ, + }; + int index = outp->base.info.connector; + + DBG("IRQ: %d\n", line->mask); + nvkm_output_dp_train(&outp->base, 0, true); + + nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); + return NVKM_NOTIFY_DROP; } int _nvkm_output_dp_fini(struct nouveau_object *object, bool suspend) { struct nvkm_output_dp *outp = (void *)object; - nouveau_event_put(outp->irq); + nvkm_notify_put(&outp->irq); nvkm_output_dp_enable(outp, false); return nvkm_output_fini(&outp->base, suspend); } @@ -189,7 +205,7 @@ void _nvkm_output_dp_dtor(struct nouveau_object *object) { struct nvkm_output_dp *outp = (void *)object; - nouveau_event_ref(NULL, &outp->irq); + nvkm_notify_fini(&outp->irq); nvkm_output_destroy(&outp->base); } @@ -213,7 +229,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent, if (ret) return ret; - nouveau_event_ref(NULL, &outp->base.conn->hpd.event); + nvkm_notify_fini(&outp->base.conn->hpd); /* access to the aux channel is not optional... */ if (!outp->base.edid) { @@ -238,20 +254,28 @@ nvkm_output_dp_create_(struct nouveau_object *parent, atomic_set(&outp->lt.done, 0); /* link maintenance */ - ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_IRQ, outp->base.edid->index, - nvkm_output_dp_service, outp, &outp->irq); + ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true, + &(struct nvkm_i2c_ntfy_req) { + .mask = NVKM_I2C_IRQ, + .port = outp->base.edid->index, + }, + sizeof(struct nvkm_i2c_ntfy_req), + sizeof(struct nvkm_i2c_ntfy_rep), + &outp->irq); if (ret) { ERR("error monitoring aux irq event: %d\n", ret); return ret; } - INIT_WORK(&outp->work, nvkm_output_dp_service_work); - /* hotplug detect, replaces gpio-based mechanism with aux events */ - ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, - outp->base.edid->index, - nvkm_output_dp_service, outp, - &outp->base.conn->hpd.event); + ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true, + &(struct nvkm_i2c_ntfy_req) { + .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, + .port = outp->base.edid->index, + }, + sizeof(struct nvkm_i2c_ntfy_req), + sizeof(struct nvkm_i2c_ntfy_rep), + &outp->base.conn->hpd); if (ret) { ERR("error monitoring aux hpd events: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h index ff33ba12cb67..1fac367cc867 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h @@ -12,10 +12,7 @@ struct nvkm_output_dp { struct nvbios_dpout info; u8 version; - struct nouveau_eventh *irq; - struct nouveau_eventh *hpd; - struct work_struct work; - atomic_t pending; + struct nvkm_notify irq; bool present; u8 dpcd[16]; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c index fe0f256f11bf..d00f89a468a7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c @@ -22,8 +22,9 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -143,38 +144,29 @@ nv50_pior_dp_impl = { *****************************************************************************/ int -nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data) +nv50_pior_power(NV50_DISP_MTHD_V1) { - const u32 stat = data & NV50_DISP_PIOR_PWR_STATE; - const u32 soff = (or * 0x800); + const u32 soff = outp->or * 0x800; + union { + struct nv50_disp_pior_pwr_v0 v0; + } *args = data; + u32 ctrl, type; + int ret; + + nv_ioctl(object, "disp pior pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n", + args->v0.version, args->v0.state, args->v0.type); + if (args->v0.type > 0x0f) + return -EINVAL; + ctrl = !!args->v0.state; + type = args->v0.type; + } else + return ret; + nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); - nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | stat); + nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); + priv->pior.type[outp->or] = type; return 0; } - -int -nv50_pior_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - const u8 type = (mthd & NV50_DISP_PIOR_MTHD_TYPE) >> 12; - const u8 or = (mthd & NV50_DISP_PIOR_MTHD_OR); - u32 *data = args; - int ret; - - if (size < sizeof(u32)) - return -EINVAL; - - mthd &= ~NV50_DISP_PIOR_MTHD_TYPE; - mthd &= ~NV50_DISP_PIOR_MTHD_OR; - switch (mthd) { - case NV50_DISP_PIOR_PWR: - ret = priv->pior.power(priv, or, data[0]); - priv->pior.type[or] = type; - break; - default: - return -EINVAL; - } - - return ret; -} diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h index 26e9a42569c7..6a0511d54ce6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h @@ -11,6 +11,7 @@ struct nouveau_disp_impl { struct nouveau_oclass base; struct nouveau_oclass **outp; struct nouveau_oclass **conn; + const struct nvkm_event_func *vblank; }; #define nouveau_disp_create(p,e,c,h,i,x,d) \ @@ -39,4 +40,9 @@ int _nouveau_disp_fini(struct nouveau_object *, bool); extern struct nouveau_oclass *nvkm_output_oclass; extern struct nouveau_oclass *nvkm_connector_oclass; +int nouveau_disp_vblank_ctor(struct nouveau_object *, void *data, u32 size, + struct nvkm_notify *); +void nouveau_disp_vblank(struct nouveau_disp *, int head); +int nouveau_disp_ntfy(struct nouveau_object *, u32, struct nvkm_event **); + #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c index 7a1ebdfa9e1b..ddf1760c4400 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c @@ -22,8 +22,9 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -32,77 +33,26 @@ #include "nv50.h" int -nv50_sor_power(struct nv50_disp_priv *priv, int or, u32 data) +nv50_sor_power(NV50_DISP_MTHD_V1) { - const u32 stat = data & NV50_DISP_SOR_PWR_STATE; - const u32 soff = (or * 0x800); + union { + struct nv50_disp_sor_pwr_v0 v0; + } *args = data; + const u32 soff = outp->or * 0x800; + u32 stat; + int ret; + + nv_ioctl(object, "disp sor pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "disp sor pwr vers %d state %d\n", + args->v0.version, args->v0.state); + stat = !!args->v0.state; + } else + return ret; + nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000); return 0; } - -int -nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - const u8 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12; - const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3; - const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2; - const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR); - const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or); - struct nvkm_output *outp = NULL, *temp; - u32 data; - int ret = -EINVAL; - - if (size < sizeof(u32)) - return -EINVAL; - data = *(u32 *)args; - - list_for_each_entry(temp, &priv->base.outp, head) { - if ((temp->info.hasht & 0xff) == type && - (temp->info.hashm & mask) == mask) { - outp = temp; - break; - } - } - - switch (mthd & ~0x3f) { - case NV50_DISP_SOR_PWR: - ret = priv->sor.power(priv, or, data); - break; - case NVA3_DISP_SOR_HDA_ELD: - ret = priv->sor.hda_eld(priv, or, args, size); - break; - case NV84_DISP_SOR_HDMI_PWR: - ret = priv->sor.hdmi(priv, head, or, data); - break; - case NV50_DISP_SOR_LVDS_SCRIPT: - priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID; - ret = 0; - break; - case NV94_DISP_SOR_DP_PWR: - if (outp) { - struct nvkm_output_dp *outpdp = (void *)outp; - switch (data) { - case NV94_DISP_SOR_DP_PWR_STATE_OFF: - nouveau_event_put(outpdp->irq); - ((struct nvkm_output_dp_impl *)nv_oclass(outp)) - ->lnk_pwr(outpdp, 0); - atomic_set(&outpdp->lt.done, 0); - break; - case NV94_DISP_SOR_DP_PWR_STATE_ON: - nvkm_output_dp_train(&outpdp->base, 0, true); - break; - default: - return -EINVAL; - } - } - break; - default: - BUG_ON(1); - } - - return ret; -} diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c index 05487cda84a8..39f85d627336 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c index 97f0e9cd3d40..7b7bbc3e459e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c index 5103e88d1877..e1500f77a56a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c @@ -23,98 +23,143 @@ */ #include <core/object.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/fb.h> -#include <engine/dmaobj.h> +#include <subdev/instmem.h> + +#include "priv.h" static int -nouveau_dmaobj_ctor(struct nouveau_object *parent, +nvkm_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent, + struct nouveau_gpuobj **pgpuobj) +{ + const struct nvkm_dmaeng_impl *impl = (void *) + nv_oclass(nv_object(dmaobj)->engine); + int ret = 0; + + if (nv_object(dmaobj) == parent) { /* ctor bind */ + if (nv_mclass(parent->parent) == NV_DEVICE) { + /* delayed, or no, binding */ + return 0; + } + ret = impl->bind(dmaobj, parent, pgpuobj); + if (ret == 0) + nouveau_object_ref(NULL, &parent); + return ret; + } + + return impl->bind(dmaobj, parent, pgpuobj); +} + +int +nvkm_dmaobj_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) + struct nouveau_oclass *oclass, void **pdata, u32 *psize, + int length, void **pobject) { - struct nouveau_dmaeng *dmaeng = (void *)engine; + union { + struct nv_dma_v0 v0; + } *args = *pdata; + struct nouveau_instmem *instmem = nouveau_instmem(parent); + struct nouveau_client *client = nouveau_client(parent); + struct nouveau_device *device = nv_device(parent); + struct nouveau_fb *pfb = nouveau_fb(parent); struct nouveau_dmaobj *dmaobj; - struct nouveau_gpuobj *gpuobj; - struct nv_dma_class *args = data; + void *data = *pdata; + u32 size = *psize; int ret; - if (size < sizeof(*args)) - return -EINVAL; - - ret = nouveau_object_create(parent, engine, oclass, 0, &dmaobj); - *pobject = nv_object(dmaobj); + ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject); + dmaobj = *pobject; if (ret) return ret; - switch (args->flags & NV_DMA_TARGET_MASK) { - case NV_DMA_TARGET_VM: + nv_ioctl(parent, "create dma size %d\n", *psize); + if (nvif_unpack(args->v0, 0, 0, true)) { + nv_ioctl(parent, "create dma vers %d target %d access %d " + "start %016llx limit %016llx\n", + args->v0.version, args->v0.target, args->v0.access, + args->v0.start, args->v0.limit); + dmaobj->target = args->v0.target; + dmaobj->access = args->v0.access; + dmaobj->start = args->v0.start; + dmaobj->limit = args->v0.limit; + } else + return ret; + + *pdata = data; + *psize = size; + + if (dmaobj->start > dmaobj->limit) + return -EINVAL; + + switch (dmaobj->target) { + case NV_DMA_V0_TARGET_VM: dmaobj->target = NV_MEM_TARGET_VM; break; - case NV_DMA_TARGET_VRAM: + case NV_DMA_V0_TARGET_VRAM: + if (!client->super) { + if (dmaobj->limit >= pfb->ram->size - instmem->reserved) + return -EACCES; + if (device->card_type >= NV_50) + return -EACCES; + } dmaobj->target = NV_MEM_TARGET_VRAM; break; - case NV_DMA_TARGET_PCI: + case NV_DMA_V0_TARGET_PCI: + if (!client->super) + return -EACCES; dmaobj->target = NV_MEM_TARGET_PCI; break; - case NV_DMA_TARGET_PCI_US: - case NV_DMA_TARGET_AGP: + case NV_DMA_V0_TARGET_PCI_US: + case NV_DMA_V0_TARGET_AGP: + if (!client->super) + return -EACCES; dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP; break; default: return -EINVAL; } - switch (args->flags & NV_DMA_ACCESS_MASK) { - case NV_DMA_ACCESS_VM: + switch (dmaobj->access) { + case NV_DMA_V0_ACCESS_VM: dmaobj->access = NV_MEM_ACCESS_VM; break; - case NV_DMA_ACCESS_RD: + case NV_DMA_V0_ACCESS_RD: dmaobj->access = NV_MEM_ACCESS_RO; break; - case NV_DMA_ACCESS_WR: + case NV_DMA_V0_ACCESS_WR: dmaobj->access = NV_MEM_ACCESS_WO; break; - case NV_DMA_ACCESS_RDWR: + case NV_DMA_V0_ACCESS_RDWR: dmaobj->access = NV_MEM_ACCESS_RW; break; default: return -EINVAL; } - dmaobj->start = args->start; - dmaobj->limit = args->limit; - dmaobj->conf0 = args->conf0; - - switch (nv_mclass(parent)) { - case NV_DEVICE_CLASS: - /* delayed, or no, binding */ - break; - default: - ret = dmaeng->bind(dmaeng, *pobject, dmaobj, &gpuobj); - if (ret == 0) { - nouveau_object_ref(NULL, pobject); - *pobject = nv_object(gpuobj); - } - break; - } - return ret; } -static struct nouveau_ofuncs -nouveau_dmaobj_ofuncs = { - .ctor = nouveau_dmaobj_ctor, - .dtor = nouveau_object_destroy, - .init = nouveau_object_init, - .fini = nouveau_object_fini, -}; - -struct nouveau_oclass -nouveau_dmaobj_sclass[] = { - { NV_DMA_FROM_MEMORY_CLASS, &nouveau_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY_CLASS, &nouveau_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY_CLASS, &nouveau_dmaobj_ofuncs }, - {} -}; +int +_nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + const struct nvkm_dmaeng_impl *impl = (void *)oclass; + struct nouveau_dmaeng *dmaeng; + int ret; + + ret = nouveau_engine_create(parent, engine, oclass, true, "DMAOBJ", + "dmaobj", &dmaeng); + *pobject = nv_object(dmaeng); + if (ret) + return ret; + + nv_engine(dmaeng)->sclass = impl->sclass; + dmaeng->bind = nvkm_dmaobj_bind; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c index 027d8217c0fa..20c9dbfe3b2e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c @@ -23,121 +23,143 @@ */ #include <core/gpuobj.h> -#include <core/class.h> +#include <nvif/class.h> #include <subdev/fb.h> #include <subdev/vm/nv04.h> -#include <engine/dmaobj.h> +#include "priv.h" -struct nv04_dmaeng_priv { - struct nouveau_dmaeng base; +struct nv04_dmaobj_priv { + struct nouveau_dmaobj base; + bool clone; + u32 flags0; + u32 flags2; }; static int -nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng, +nv04_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent, - struct nouveau_dmaobj *dmaobj, struct nouveau_gpuobj **pgpuobj) { - struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaeng); + struct nv04_dmaobj_priv *priv = (void *)dmaobj; struct nouveau_gpuobj *gpuobj; - u32 flags0 = nv_mclass(dmaobj); - u32 flags2 = 0x00000000; - u64 offset = dmaobj->start & 0xfffff000; - u64 adjust = dmaobj->start & 0x00000fff; - u32 length = dmaobj->limit - dmaobj->start; + u64 offset = priv->base.start & 0xfffff000; + u64 adjust = priv->base.start & 0x00000fff; + u32 length = priv->base.limit - priv->base.start; int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { switch (nv_mclass(parent->parent)) { - case NV03_CHANNEL_DMA_CLASS: - case NV10_CHANNEL_DMA_CLASS: - case NV17_CHANNEL_DMA_CLASS: - case NV40_CHANNEL_DMA_CLASS: + case NV03_CHANNEL_DMA: + case NV10_CHANNEL_DMA: + case NV17_CHANNEL_DMA: + case NV40_CHANNEL_DMA: break; default: return -EINVAL; } } - if (dmaobj->target == NV_MEM_TARGET_VM) { - if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) { - struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0]; - if (!dmaobj->start) - return nouveau_gpuobj_dup(parent, pgt, pgpuobj); - offset = nv_ro32(pgt, 8 + (offset >> 10)); - offset &= 0xfffff000; - } + if (priv->clone) { + struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaobj); + struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0]; + if (!dmaobj->start) + return nouveau_gpuobj_dup(parent, pgt, pgpuobj); + offset = nv_ro32(pgt, 8 + (offset >> 10)); + offset &= 0xfffff000; + } + + ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); + *pgpuobj = gpuobj; + if (ret == 0) { + nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20)); + nv_wo32(*pgpuobj, 0x04, length); + nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset); + nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset); + } + + return ret; +} + +static int +nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_dmaeng *dmaeng = (void *)engine; + struct nv04_vmmgr_priv *vmm = nv04_vmmgr(engine); + struct nv04_dmaobj_priv *priv; + int ret; + + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); + *pobject = nv_object(priv); + if (ret || (ret = -ENOSYS, size)) + return ret; - dmaobj->target = NV_MEM_TARGET_PCI; - dmaobj->access = NV_MEM_ACCESS_RW; + if (priv->base.target == NV_MEM_TARGET_VM) { + if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass) + priv->clone = true; + priv->base.target = NV_MEM_TARGET_PCI; + priv->base.access = NV_MEM_ACCESS_RW; } - switch (dmaobj->target) { + priv->flags0 = nv_mclass(priv); + switch (priv->base.target) { case NV_MEM_TARGET_VRAM: - flags0 |= 0x00003000; + priv->flags0 |= 0x00003000; break; case NV_MEM_TARGET_PCI: - flags0 |= 0x00023000; + priv->flags0 |= 0x00023000; break; case NV_MEM_TARGET_PCI_NOSNOOP: - flags0 |= 0x00033000; + priv->flags0 |= 0x00033000; break; default: return -EINVAL; } - switch (dmaobj->access) { + switch (priv->base.access) { case NV_MEM_ACCESS_RO: - flags0 |= 0x00004000; + priv->flags0 |= 0x00004000; break; case NV_MEM_ACCESS_WO: - flags0 |= 0x00008000; + priv->flags0 |= 0x00008000; case NV_MEM_ACCESS_RW: - flags2 |= 0x00000002; + priv->flags2 |= 0x00000002; break; default: return -EINVAL; } - ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); - *pgpuobj = gpuobj; - if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, flags0 | (adjust << 20)); - nv_wo32(*pgpuobj, 0x04, length); - nv_wo32(*pgpuobj, 0x08, flags2 | offset); - nv_wo32(*pgpuobj, 0x0c, flags2 | offset); - } - - return ret; + return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); } -static int -nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv04_dmaeng_priv *priv; - int ret; - - ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static struct nouveau_ofuncs +nv04_dmaobj_ofuncs = { + .ctor = nv04_dmaobj_ctor, + .dtor = _nvkm_dmaobj_dtor, + .init = _nvkm_dmaobj_init, + .fini = _nvkm_dmaobj_fini, +}; - nv_engine(priv)->sclass = nouveau_dmaobj_sclass; - priv->base.bind = nv04_dmaobj_bind; - return 0; -} +static struct nouveau_oclass +nv04_dmaeng_sclass[] = { + { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs }, + { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs }, + { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs }, + {} +}; -struct nouveau_oclass -nv04_dmaeng_oclass = { - .handle = NV_ENGINE(DMAOBJ, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv04_dmaeng_ctor, - .dtor = _nouveau_dmaeng_dtor, - .init = _nouveau_dmaeng_init, - .fini = _nouveau_dmaeng_fini, +struct nouveau_oclass * +nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_dmaeng_ctor, + .dtor = _nvkm_dmaeng_dtor, + .init = _nvkm_dmaeng_init, + .fini = _nvkm_dmaeng_fini, }, -}; + .sclass = nv04_dmaeng_sclass, + .bind = nv04_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c index 750183f7c057..a740ddba2ee2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c @@ -22,140 +22,176 @@ * Authors: Ben Skeggs */ +#include <core/client.h> #include <core/gpuobj.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/fb.h> -#include <engine/dmaobj.h> -struct nv50_dmaeng_priv { - struct nouveau_dmaeng base; +#include "priv.h" + +struct nv50_dmaobj_priv { + struct nouveau_dmaobj base; + u32 flags0; + u32 flags5; }; static int -nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng, +nv50_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent, - struct nouveau_dmaobj *dmaobj, struct nouveau_gpuobj **pgpuobj) { - u32 flags0 = nv_mclass(dmaobj); - u32 flags5 = 0x00000000; + struct nv50_dmaobj_priv *priv = (void *)dmaobj; int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { switch (nv_mclass(parent->parent)) { - case NV50_CHANNEL_DMA_CLASS: - case NV84_CHANNEL_DMA_CLASS: - case NV50_CHANNEL_IND_CLASS: - case NV84_CHANNEL_IND_CLASS: - case NV50_DISP_MAST_CLASS: - case NV84_DISP_MAST_CLASS: - case NV94_DISP_MAST_CLASS: - case NVA0_DISP_MAST_CLASS: - case NVA3_DISP_MAST_CLASS: - case NV50_DISP_SYNC_CLASS: - case NV84_DISP_SYNC_CLASS: - case NV94_DISP_SYNC_CLASS: - case NVA0_DISP_SYNC_CLASS: - case NVA3_DISP_SYNC_CLASS: - case NV50_DISP_OVLY_CLASS: - case NV84_DISP_OVLY_CLASS: - case NV94_DISP_OVLY_CLASS: - case NVA0_DISP_OVLY_CLASS: - case NVA3_DISP_OVLY_CLASS: + case NV40_CHANNEL_DMA: + case NV50_CHANNEL_GPFIFO: + case G82_CHANNEL_GPFIFO: + case NV50_DISP_CORE_CHANNEL_DMA: + case G82_DISP_CORE_CHANNEL_DMA: + case GT206_DISP_CORE_CHANNEL_DMA: + case GT200_DISP_CORE_CHANNEL_DMA: + case GT214_DISP_CORE_CHANNEL_DMA: + case NV50_DISP_BASE_CHANNEL_DMA: + case G82_DISP_BASE_CHANNEL_DMA: + case GT200_DISP_BASE_CHANNEL_DMA: + case GT214_DISP_BASE_CHANNEL_DMA: + case NV50_DISP_OVERLAY_CHANNEL_DMA: + case G82_DISP_OVERLAY_CHANNEL_DMA: + case GT200_DISP_OVERLAY_CHANNEL_DMA: + case GT214_DISP_OVERLAY_CHANNEL_DMA: break; default: return -EINVAL; } } - if (!(dmaobj->conf0 & NV50_DMA_CONF0_ENABLE)) { - if (dmaobj->target == NV_MEM_TARGET_VM) { - dmaobj->conf0 = NV50_DMA_CONF0_PRIV_VM; - dmaobj->conf0 |= NV50_DMA_CONF0_PART_VM; - dmaobj->conf0 |= NV50_DMA_CONF0_COMP_VM; - dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_VM; + ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); + if (ret == 0) { + nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj)); + nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit)); + nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start)); + nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 | + upper_32_bits(priv->base.start)); + nv_wo32(*pgpuobj, 0x10, 0x00000000); + nv_wo32(*pgpuobj, 0x14, priv->flags5); + } + + return ret; +} + +static int +nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_dmaeng *dmaeng = (void *)engine; + union { + struct nv50_dma_v0 v0; + } *args; + struct nv50_dmaobj_priv *priv; + u32 user, part, comp, kind; + int ret; + + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + args = data; + + nv_ioctl(parent, "create nv50 dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d " + "comp %d kind %02x\n", args->v0.version, + args->v0.priv, args->v0.part, args->v0.comp, + args->v0.kind); + user = args->v0.priv; + part = args->v0.part; + comp = args->v0.comp; + kind = args->v0.kind; + } else + if (size == 0) { + if (priv->base.target != NV_MEM_TARGET_VM) { + user = NV50_DMA_V0_PRIV_US; + part = NV50_DMA_V0_PART_256; + comp = NV50_DMA_V0_COMP_NONE; + kind = NV50_DMA_V0_KIND_PITCH; } else { - dmaobj->conf0 = NV50_DMA_CONF0_PRIV_US; - dmaobj->conf0 |= NV50_DMA_CONF0_PART_256; - dmaobj->conf0 |= NV50_DMA_CONF0_COMP_NONE; - dmaobj->conf0 |= NV50_DMA_CONF0_TYPE_LINEAR; + user = NV50_DMA_V0_PRIV_VM; + part = NV50_DMA_V0_PART_VM; + comp = NV50_DMA_V0_COMP_VM; + kind = NV50_DMA_V0_KIND_VM; } - } + } else + return ret; - flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_COMP) << 22; - flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_TYPE) << 22; - flags0 |= (dmaobj->conf0 & NV50_DMA_CONF0_PRIV); - flags5 |= (dmaobj->conf0 & NV50_DMA_CONF0_PART); + if (user > 2 || part > 2 || comp > 3 || kind > 0x7f) + return -EINVAL; + priv->flags0 = (comp << 29) | (kind << 22) | (user << 20); + priv->flags5 = (part << 16); - switch (dmaobj->target) { + switch (priv->base.target) { case NV_MEM_TARGET_VM: - flags0 |= 0x00000000; + priv->flags0 |= 0x00000000; break; case NV_MEM_TARGET_VRAM: - flags0 |= 0x00010000; + priv->flags0 |= 0x00010000; break; case NV_MEM_TARGET_PCI: - flags0 |= 0x00020000; + priv->flags0 |= 0x00020000; break; case NV_MEM_TARGET_PCI_NOSNOOP: - flags0 |= 0x00030000; + priv->flags0 |= 0x00030000; break; default: return -EINVAL; } - switch (dmaobj->access) { + switch (priv->base.access) { case NV_MEM_ACCESS_VM: break; case NV_MEM_ACCESS_RO: - flags0 |= 0x00040000; + priv->flags0 |= 0x00040000; break; case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_RW: - flags0 |= 0x00080000; + priv->flags0 |= 0x00080000; break; + default: + return -EINVAL; } - ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); - if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, flags0); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 | - upper_32_bits(dmaobj->start)); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, flags5); - } - - return ret; + return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); } -static int -nv50_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_dmaeng_priv *priv; - int ret; - - ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static struct nouveau_ofuncs +nv50_dmaobj_ofuncs = { + .ctor = nv50_dmaobj_ctor, + .dtor = _nvkm_dmaobj_dtor, + .init = _nvkm_dmaobj_init, + .fini = _nvkm_dmaobj_fini, +}; - nv_engine(priv)->sclass = nouveau_dmaobj_sclass; - priv->base.bind = nv50_dmaobj_bind; - return 0; -} +static struct nouveau_oclass +nv50_dmaeng_sclass[] = { + { NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs }, + { NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs }, + { NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs }, + {} +}; -struct nouveau_oclass -nv50_dmaeng_oclass = { - .handle = NV_ENGINE(DMAOBJ, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_dmaeng_ctor, - .dtor = _nouveau_dmaeng_dtor, - .init = _nouveau_dmaeng_init, - .fini = _nouveau_dmaeng_fini, +struct nouveau_oclass * +nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_dmaeng_ctor, + .dtor = _nvkm_dmaeng_dtor, + .init = _nvkm_dmaeng_init, + .fini = _nvkm_dmaeng_fini, }, -}; + .sclass = nv50_dmaeng_sclass, + .bind = nv50_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c index cd3970d03b80..88ec33b20048 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c @@ -22,32 +22,35 @@ * Authors: Ben Skeggs */ +#include <core/client.h> #include <core/device.h> #include <core/gpuobj.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/fb.h> -#include <engine/dmaobj.h> -struct nvc0_dmaeng_priv { - struct nouveau_dmaeng base; +#include "priv.h" + +struct nvc0_dmaobj_priv { + struct nouveau_dmaobj base; + u32 flags0; + u32 flags5; }; static int -nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, +nvc0_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent, - struct nouveau_dmaobj *dmaobj, struct nouveau_gpuobj **pgpuobj) { - u32 flags0 = nv_mclass(dmaobj); - u32 flags5 = 0x00000000; + struct nvc0_dmaobj_priv *priv = (void *)dmaobj; int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { switch (nv_mclass(parent->parent)) { - case NVA3_DISP_MAST_CLASS: - case NVA3_DISP_SYNC_CLASS: - case NVA3_DISP_OVLY_CLASS: + case GT214_DISP_CORE_CHANNEL_DMA: + case GT214_DISP_BASE_CHANNEL_DMA: + case GT214_DISP_OVERLAY_CHANNEL_DMA: break; default: return -EINVAL; @@ -55,89 +58,122 @@ nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, } else return 0; - if (!(dmaobj->conf0 & NVC0_DMA_CONF0_ENABLE)) { - if (dmaobj->target == NV_MEM_TARGET_VM) { - dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_VM; - dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_VM; + ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); + if (ret == 0) { + nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj)); + nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit)); + nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start)); + nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 | + upper_32_bits(priv->base.start)); + nv_wo32(*pgpuobj, 0x10, 0x00000000); + nv_wo32(*pgpuobj, 0x14, priv->flags5); + } + + return ret; +} + +static int +nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_dmaeng *dmaeng = (void *)engine; + union { + struct gf100_dma_v0 v0; + } *args; + struct nvc0_dmaobj_priv *priv; + u32 kind, user, unkn; + int ret; + + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + args = data; + + nv_ioctl(parent, "create gf100 dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n", + args->v0.version, args->v0.priv, args->v0.kind); + kind = args->v0.kind; + user = args->v0.priv; + unkn = 0; + } else + if (size == 0) { + if (priv->base.target != NV_MEM_TARGET_VM) { + kind = GF100_DMA_V0_KIND_PITCH; + user = GF100_DMA_V0_PRIV_US; + unkn = 2; } else { - dmaobj->conf0 = NVC0_DMA_CONF0_PRIV_US; - dmaobj->conf0 |= NVC0_DMA_CONF0_TYPE_LINEAR; - dmaobj->conf0 |= 0x00020000; + kind = GF100_DMA_V0_KIND_VM; + user = GF100_DMA_V0_PRIV_VM; + unkn = 0; } - } + } else + return ret; - flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_TYPE) << 22; - flags0 |= (dmaobj->conf0 & NVC0_DMA_CONF0_PRIV); - flags5 |= (dmaobj->conf0 & NVC0_DMA_CONF0_UNKN); + if (user > 2) + return -EINVAL; + priv->flags0 |= (kind << 22) | (user << 20); + priv->flags5 |= (unkn << 16); - switch (dmaobj->target) { + switch (priv->base.target) { case NV_MEM_TARGET_VM: - flags0 |= 0x00000000; + priv->flags0 |= 0x00000000; break; case NV_MEM_TARGET_VRAM: - flags0 |= 0x00010000; + priv->flags0 |= 0x00010000; break; case NV_MEM_TARGET_PCI: - flags0 |= 0x00020000; + priv->flags0 |= 0x00020000; break; case NV_MEM_TARGET_PCI_NOSNOOP: - flags0 |= 0x00030000; + priv->flags0 |= 0x00030000; break; default: return -EINVAL; } - switch (dmaobj->access) { + switch (priv->base.access) { case NV_MEM_ACCESS_VM: break; case NV_MEM_ACCESS_RO: - flags0 |= 0x00040000; + priv->flags0 |= 0x00040000; break; case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_RW: - flags0 |= 0x00080000; + priv->flags0 |= 0x00080000; break; } - ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); - if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, flags0); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 | - upper_32_bits(dmaobj->start)); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, flags5); - } - - return ret; + return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); } -static int -nvc0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvc0_dmaeng_priv *priv; - int ret; - - ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static struct nouveau_ofuncs +nvc0_dmaobj_ofuncs = { + .ctor = nvc0_dmaobj_ctor, + .dtor = _nvkm_dmaobj_dtor, + .init = _nvkm_dmaobj_init, + .fini = _nvkm_dmaobj_fini, +}; - nv_engine(priv)->sclass = nouveau_dmaobj_sclass; - priv->base.bind = nvc0_dmaobj_bind; - return 0; -} +static struct nouveau_oclass +nvc0_dmaeng_sclass[] = { + { NV_DMA_FROM_MEMORY, &nvc0_dmaobj_ofuncs }, + { NV_DMA_TO_MEMORY, &nvc0_dmaobj_ofuncs }, + { NV_DMA_IN_MEMORY, &nvc0_dmaobj_ofuncs }, + {} +}; -struct nouveau_oclass -nvc0_dmaeng_oclass = { - .handle = NV_ENGINE(DMAOBJ, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_dmaeng_ctor, - .dtor = _nouveau_dmaeng_dtor, - .init = _nouveau_dmaeng_init, - .fini = _nouveau_dmaeng_fini, +struct nouveau_oclass * +nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_dmaeng_ctor, + .dtor = _nvkm_dmaeng_dtor, + .init = _nvkm_dmaeng_init, + .fini = _nvkm_dmaeng_fini, }, -}; + .sclass = nvc0_dmaeng_sclass, + .bind = nvc0_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c index 1cfb3bb90131..3fc4f0b0eaca 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c @@ -22,40 +22,40 @@ * Authors: Ben Skeggs */ +#include <core/client.h> #include <core/device.h> #include <core/gpuobj.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/fb.h> -#include <engine/dmaobj.h> -struct nvd0_dmaeng_priv { - struct nouveau_dmaeng base; +#include "priv.h" + +struct nvd0_dmaobj_priv { + struct nouveau_dmaobj base; + u32 flags0; }; static int -nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, +nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent, - struct nouveau_dmaobj *dmaobj, struct nouveau_gpuobj **pgpuobj) { - u32 flags0 = 0x00000000; + struct nvd0_dmaobj_priv *priv = (void *)dmaobj; int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { switch (nv_mclass(parent->parent)) { - case NVD0_DISP_MAST_CLASS: - case NVD0_DISP_SYNC_CLASS: - case NVD0_DISP_OVLY_CLASS: - case NVE0_DISP_MAST_CLASS: - case NVE0_DISP_SYNC_CLASS: - case NVE0_DISP_OVLY_CLASS: - case NVF0_DISP_MAST_CLASS: - case NVF0_DISP_SYNC_CLASS: - case NVF0_DISP_OVLY_CLASS: - case GM107_DISP_MAST_CLASS: - case GM107_DISP_SYNC_CLASS: - case GM107_DISP_OVLY_CLASS: + case GF110_DISP_CORE_CHANNEL_DMA: + case GK104_DISP_CORE_CHANNEL_DMA: + case GK110_DISP_CORE_CHANNEL_DMA: + case GM107_DISP_CORE_CHANNEL_DMA: + case GF110_DISP_BASE_CHANNEL_DMA: + case GK104_DISP_BASE_CHANNEL_DMA: + case GK110_DISP_BASE_CHANNEL_DMA: + case GF110_DISP_OVERLAY_CONTROL_DMA: + case GK104_DISP_OVERLAY_CONTROL_DMA: break; default: return -EINVAL; @@ -63,33 +63,11 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, } else return 0; - if (!(dmaobj->conf0 & NVD0_DMA_CONF0_ENABLE)) { - if (dmaobj->target == NV_MEM_TARGET_VM) { - dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_VM; - dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_LP; - } else { - dmaobj->conf0 |= NVD0_DMA_CONF0_TYPE_LINEAR; - dmaobj->conf0 |= NVD0_DMA_CONF0_PAGE_SP; - } - } - - flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_TYPE) << 20; - flags0 |= (dmaobj->conf0 & NVD0_DMA_CONF0_PAGE) >> 4; - - switch (dmaobj->target) { - case NV_MEM_TARGET_VRAM: - flags0 |= 0x00000009; - break; - default: - return -EINVAL; - break; - } - ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, flags0); - nv_wo32(*pgpuobj, 0x04, dmaobj->start >> 8); - nv_wo32(*pgpuobj, 0x08, dmaobj->limit >> 8); + nv_wo32(*pgpuobj, 0x00, priv->flags0); + nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8); + nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8); nv_wo32(*pgpuobj, 0x0c, 0x00000000); nv_wo32(*pgpuobj, 0x10, 0x00000000); nv_wo32(*pgpuobj, 0x14, 0x00000000); @@ -99,30 +77,91 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, } static int -nvd0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine, +nvd0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nvd0_dmaeng_priv *priv; + struct nouveau_dmaeng *dmaeng = (void *)engine; + union { + struct gf110_dma_v0 v0; + } *args; + struct nvd0_dmaobj_priv *priv; + u32 kind, page; int ret; - ret = nouveau_dmaeng_create(parent, engine, oclass, &priv); + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); *pobject = nv_object(priv); if (ret) return ret; + args = data; - nv_engine(priv)->sclass = nouveau_dmaobj_sclass; - priv->base.bind = nvd0_dmaobj_bind; - return 0; + nv_ioctl(parent, "create gf110 dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n", + args->v0.version, args->v0.page, args->v0.kind); + kind = args->v0.kind; + page = args->v0.page; + } else + if (size == 0) { + if (priv->base.target != NV_MEM_TARGET_VM) { + kind = GF110_DMA_V0_KIND_PITCH; + page = GF110_DMA_V0_PAGE_SP; + } else { + kind = GF110_DMA_V0_KIND_VM; + page = GF110_DMA_V0_PAGE_LP; + } + } else + return ret; + + if (page > 1) + return -EINVAL; + priv->flags0 = (kind << 20) | (page << 6); + + switch (priv->base.target) { + case NV_MEM_TARGET_VRAM: + priv->flags0 |= 0x00000009; + break; + case NV_MEM_TARGET_VM: + case NV_MEM_TARGET_PCI: + case NV_MEM_TARGET_PCI_NOSNOOP: + /* XXX: don't currently know how to construct a real one + * of these. we only use them to represent pushbufs + * on these chipsets, and the classes that use them + * deal with the target themselves. + */ + break; + default: + return -EINVAL; + } + + return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); } -struct nouveau_oclass -nvd0_dmaeng_oclass = { - .handle = NV_ENGINE(DMAOBJ, 0xd0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvd0_dmaeng_ctor, - .dtor = _nouveau_dmaeng_dtor, - .init = _nouveau_dmaeng_init, - .fini = _nouveau_dmaeng_fini, - }, +static struct nouveau_ofuncs +nvd0_dmaobj_ofuncs = { + .ctor = nvd0_dmaobj_ctor, + .dtor = _nvkm_dmaobj_dtor, + .init = _nvkm_dmaobj_init, + .fini = _nvkm_dmaobj_fini, }; + +static struct nouveau_oclass +nvd0_dmaeng_sclass[] = { + { NV_DMA_FROM_MEMORY, &nvd0_dmaobj_ofuncs }, + { NV_DMA_TO_MEMORY, &nvd0_dmaobj_ofuncs }, + { NV_DMA_IN_MEMORY, &nvd0_dmaobj_ofuncs }, + {} +}; + +struct nouveau_oclass * +nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0xd0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_dmaeng_ctor, + .dtor = _nvkm_dmaeng_dtor, + .init = _nvkm_dmaeng_init, + .fini = _nvkm_dmaeng_fini, + }, + .sclass = nvd0_dmaeng_sclass, + .bind = nvd0_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h new file mode 100644 index 000000000000..36f743866937 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h @@ -0,0 +1,30 @@ +#ifndef __NVKM_DMAOBJ_PRIV_H__ +#define __NVKM_DMAOBJ_PRIV_H__ + +#include <engine/dmaobj.h> + +#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \ + nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d) + +int nvkm_dmaobj_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void **, u32 *, + int, void **); +#define _nvkm_dmaobj_dtor nouveau_object_destroy +#define _nvkm_dmaobj_init nouveau_object_init +#define _nvkm_dmaobj_fini nouveau_object_fini + +int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +#define _nvkm_dmaeng_dtor _nouveau_engine_dtor +#define _nvkm_dmaeng_init _nouveau_engine_init +#define _nvkm_dmaeng_fini _nouveau_engine_fini + +struct nvkm_dmaeng_impl { + struct nouveau_oclass base; + struct nouveau_oclass *sclass; + int (*bind)(struct nouveau_dmaobj *, struct nouveau_object *, + struct nouveau_gpuobj **); +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c index 56ed3d73bf8e..ac8375cf4eef 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c @@ -26,11 +26,31 @@ #include <core/object.h> #include <core/handle.h> #include <core/event.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> +#include <nvif/event.h> #include <engine/dmaobj.h> #include <engine/fifo.h> +static int +nouveau_fifo_event_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + if (size == 0) { + notify->size = 0; + notify->types = 1; + notify->index = 0; + return 0; + } + return -ENOSYS; +} + +static const struct nvkm_event_func +nouveau_fifo_event_func = { + .ctor = nouveau_fifo_event_ctor, +}; + int nouveau_fifo_channel_create_(struct nouveau_object *parent, struct nouveau_object *engine, @@ -59,14 +79,14 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent, dmaeng = (void *)chan->pushdma->base.engine; switch (chan->pushdma->base.oclass->handle) { - case NV_DMA_FROM_MEMORY_CLASS: - case NV_DMA_IN_MEMORY_CLASS: + case NV_DMA_FROM_MEMORY: + case NV_DMA_IN_MEMORY: break; default: return -EINVAL; } - ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu); + ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu); if (ret) return ret; @@ -85,15 +105,10 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent, return -ENOSPC; } - /* map fifo control registers */ - chan->user = ioremap(nv_device_resource_start(device, bar) + addr + - (chan->chid * size), size); - if (!chan->user) - return -EFAULT; - - nouveau_event_trigger(priv->cevent, 1, 0); - + chan->addr = nv_device_resource_start(device, bar) + + addr + size * chan->chid; chan->size = size; + nvkm_event_send(&priv->cevent, 1, 0, NULL, 0); return 0; } @@ -103,7 +118,8 @@ nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan) struct nouveau_fifo *priv = (void *)nv_object(chan)->engine; unsigned long flags; - iounmap(chan->user); + if (chan->user) + iounmap(chan->user); spin_lock_irqsave(&priv->lock, flags); priv->channel[chan->chid] = NULL; @@ -121,10 +137,24 @@ _nouveau_fifo_channel_dtor(struct nouveau_object *object) nouveau_fifo_channel_destroy(chan); } +int +_nouveau_fifo_channel_map(struct nouveau_object *object, u64 *addr, u32 *size) +{ + struct nouveau_fifo_chan *chan = (void *)object; + *addr = chan->addr; + *size = chan->size; + return 0; +} + u32 _nouveau_fifo_channel_rd32(struct nouveau_object *object, u64 addr) { struct nouveau_fifo_chan *chan = (void *)object; + if (unlikely(!chan->user)) { + chan->user = ioremap(chan->addr, chan->size); + if (WARN_ON_ONCE(chan->user == NULL)) + return 0; + } return ioread32_native(chan->user + addr); } @@ -132,9 +162,58 @@ void _nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data) { struct nouveau_fifo_chan *chan = (void *)object; + if (unlikely(!chan->user)) { + chan->user = ioremap(chan->addr, chan->size); + if (WARN_ON_ONCE(chan->user == NULL)) + return; + } iowrite32_native(data, chan->user + addr); } +int +nouveau_fifo_uevent_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + union { + struct nvif_notify_uevent_req none; + } *req = data; + int ret; + + if (nvif_unvers(req->none)) { + notify->size = sizeof(struct nvif_notify_uevent_rep); + notify->types = 1; + notify->index = 0; + } + + return ret; +} + +void +nouveau_fifo_uevent(struct nouveau_fifo *fifo) +{ + struct nvif_notify_uevent_rep rep = { + }; + nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); +} + +int +_nouveau_fifo_channel_ntfy(struct nouveau_object *object, u32 type, + struct nvkm_event **event) +{ + struct nouveau_fifo *fifo = (void *)object->engine; + switch (type) { + case G82_CHANNEL_DMA_V0_NTFY_UEVENT: + if (nv_mclass(object) >= G82_CHANNEL_DMA) { + *event = &fifo->uevent; + return 0; + } + break; + default: + break; + } + return -EINVAL; +} + static int nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object) { @@ -168,8 +247,8 @@ void nouveau_fifo_destroy(struct nouveau_fifo *priv) { kfree(priv->channel); - nouveau_event_destroy(&priv->uevent); - nouveau_event_destroy(&priv->cevent); + nvkm_event_fini(&priv->uevent); + nvkm_event_fini(&priv->cevent); nouveau_engine_destroy(&priv->base); } @@ -194,11 +273,7 @@ nouveau_fifo_create_(struct nouveau_object *parent, if (!priv->channel) return -ENOMEM; - ret = nouveau_event_create(1, 1, &priv->cevent); - if (ret) - return ret; - - ret = nouveau_event_create(1, 1, &priv->uevent); + ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c index c61b16a63884..5ae6a43893b5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c @@ -22,8 +22,9 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <core/engctx.h> #include <core/namedb.h> #include <core/handle.h> @@ -117,16 +118,23 @@ nv04_fifo_chan_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv03_channel_dma_v0 v0; + } *args = data; struct nv04_fifo_priv *priv = (void *)engine; struct nv04_fifo_chan *chan; - struct nv03_channel_dma_class *args = data; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->pushbuf, + 0x10000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR), &chan); @@ -134,13 +142,15 @@ nv04_fifo_chan_ctor(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->object_attach = nv04_fifo_object_attach; nv_parent(chan)->object_detach = nv04_fifo_object_detach; nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); nv_wo32(priv->ramfc, chan->ramfc + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | @@ -242,13 +252,15 @@ nv04_fifo_ofuncs = { .dtor = nv04_fifo_chan_dtor, .init = nv04_fifo_chan_init, .fini = nv04_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nv04_fifo_sclass[] = { - { NV03_CHANNEL_DMA_CLASS, &nv04_fifo_ofuncs }, + { NV03_CHANNEL_DMA, &nv04_fifo_ofuncs }, {} }; @@ -539,7 +551,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) } if (status & 0x40000000) { - nouveau_event_trigger(priv->base.uevent, 1, 0); + nouveau_fifo_uevent(&priv->base); nv_wr32(priv, 0x002100, 0x40000000); status &= ~0x40000000; } diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c index 571a22aa1ae5..2a32add51c81 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c @@ -22,8 +22,9 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <core/engctx.h> #include <core/ramht.h> @@ -59,16 +60,23 @@ nv10_fifo_chan_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv03_channel_dma_v0 v0; + } *args = data; struct nv04_fifo_priv *priv = (void *)engine; struct nv04_fifo_chan *chan; - struct nv03_channel_dma_class *args = data; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->pushbuf, + 0x10000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR), &chan); @@ -76,13 +84,15 @@ nv10_fifo_chan_ctor(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->object_attach = nv04_fifo_object_attach; nv_parent(chan)->object_detach = nv04_fifo_object_detach; nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); nv_wo32(priv->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | @@ -100,13 +110,15 @@ nv10_fifo_ofuncs = { .dtor = nv04_fifo_chan_dtor, .init = nv04_fifo_chan_init, .fini = nv04_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nv10_fifo_sclass[] = { - { NV10_CHANNEL_DMA_CLASS, &nv10_fifo_ofuncs }, + { NV10_CHANNEL_DMA, &nv10_fifo_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c index f25760209316..12d76c8adb23 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c @@ -22,8 +22,9 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <core/engctx.h> #include <core/ramht.h> @@ -64,16 +65,23 @@ nv17_fifo_chan_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv03_channel_dma_v0 v0; + } *args = data; struct nv04_fifo_priv *priv = (void *)engine; struct nv04_fifo_chan *chan; - struct nv03_channel_dma_class *args = data; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->pushbuf, + 0x10000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | @@ -83,13 +91,15 @@ nv17_fifo_chan_ctor(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->object_attach = nv04_fifo_object_attach; nv_parent(chan)->object_detach = nv04_fifo_object_detach; nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 64; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); nv_wo32(priv->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | @@ -107,13 +117,15 @@ nv17_fifo_ofuncs = { .dtor = nv04_fifo_chan_dtor, .init = nv04_fifo_chan_init, .fini = nv04_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nv17_fifo_sclass[] = { - { NV17_CHANNEL_DMA_CLASS, &nv17_fifo_ofuncs }, + { NV17_CHANNEL_DMA, &nv17_fifo_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c index 343487ed2238..9f49c3a24dc6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c @@ -22,8 +22,9 @@ * Authors: Ben Skeggs */ -#include <core/os.h> -#include <core/class.h> +#include <core/client.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <core/engctx.h> #include <core/ramht.h> @@ -182,16 +183,23 @@ nv40_fifo_chan_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv03_channel_dma_v0 v0; + } *args = data; struct nv04_fifo_priv *priv = (void *)engine; struct nv04_fifo_chan *chan; - struct nv03_channel_dma_class *args = data; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x1000, args->pushbuf, + 0x1000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | @@ -200,14 +208,16 @@ nv40_fifo_chan_ctor(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->context_attach = nv40_fifo_context_attach; nv_parent(chan)->context_detach = nv40_fifo_context_detach; nv_parent(chan)->object_attach = nv40_fifo_object_attach; nv_parent(chan)->object_detach = nv04_fifo_object_detach; chan->ramfc = chan->base.chid * 128; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | @@ -226,13 +236,15 @@ nv40_fifo_ofuncs = { .dtor = nv04_fifo_chan_dtor, .init = nv04_fifo_chan_init, .fini = nv04_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nv40_fifo_sclass[] = { - { NV40_CHANNEL_DMA_CLASS, &nv40_fifo_ofuncs }, + { NV40_CHANNEL_DMA, &nv40_fifo_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c index e6352bd5b4ff..5d1e86bc244c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c @@ -25,7 +25,8 @@ #include <core/client.h> #include <core/engctx.h> #include <core/ramht.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/timer.h> #include <subdev/bar.h> @@ -194,17 +195,24 @@ nv50_fifo_chan_ctor_dma(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv03_channel_dma_v0 v0; + } *args = data; struct nouveau_bar *bar = nouveau_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; - struct nv03_channel_dma_class *args = data; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->pushbuf, + 0x2000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | @@ -213,6 +221,8 @@ nv50_fifo_chan_ctor_dma(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->context_attach = nv50_fifo_context_attach; nv_parent(chan)->context_detach = nv50_fifo_context_detach; nv_parent(chan)->object_attach = nv50_fifo_object_attach; @@ -223,10 +233,10 @@ nv50_fifo_chan_ctor_dma(struct nouveau_object *parent, if (ret) return ret; - nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset)); - nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset)); - nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset)); - nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); nv_wo32(base->ramfc, 0x3c, 0x003f6078); nv_wo32(base->ramfc, 0x44, 0x01003fff); nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); @@ -247,18 +257,26 @@ nv50_fifo_chan_ctor_ind(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_channel_ind_class *args = data; + union { + struct nv50_channel_gpfifo_v0 v0; + } *args = data; struct nouveau_bar *bar = nouveau_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; u64 ioffset, ilength; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->pushbuf, + 0x2000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | @@ -267,6 +285,8 @@ nv50_fifo_chan_ctor_ind(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->context_attach = nv50_fifo_context_attach; nv_parent(chan)->context_detach = nv50_fifo_context_detach; nv_parent(chan)->object_attach = nv50_fifo_object_attach; @@ -277,8 +297,8 @@ nv50_fifo_chan_ctor_ind(struct nouveau_object *parent, if (ret) return ret; - ioffset = args->ioffset; - ilength = order_base_2(args->ilength / 8); + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); nv_wo32(base->ramfc, 0x3c, 0x403f6078); nv_wo32(base->ramfc, 0x44, 0x01003fff); @@ -343,8 +363,10 @@ nv50_fifo_ofuncs_dma = { .dtor = nv50_fifo_chan_dtor, .init = nv50_fifo_chan_init, .fini = nv50_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_ofuncs @@ -353,14 +375,16 @@ nv50_fifo_ofuncs_ind = { .dtor = nv50_fifo_chan_dtor, .init = nv50_fifo_chan_init, .fini = nv50_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nv50_fifo_sclass[] = { - { NV50_CHANNEL_DMA_CLASS, &nv50_fifo_ofuncs_dma }, - { NV50_CHANNEL_IND_CLASS, &nv50_fifo_ofuncs_ind }, + { NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma }, + { NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c index 6e5ac16e5460..1f42996b354a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c @@ -27,7 +27,8 @@ #include <core/engctx.h> #include <core/ramht.h> #include <core/event.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <subdev/timer.h> #include <subdev/bar.h> @@ -160,17 +161,24 @@ nv84_fifo_chan_ctor_dma(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv03_channel_dma_v0 v0; + } *args = data; struct nouveau_bar *bar = nouveau_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; - struct nv03_channel_dma_class *args = data; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->pushbuf, + 0x2000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | @@ -186,6 +194,8 @@ nv84_fifo_chan_ctor_dma(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, &chan->ramht); if (ret) @@ -196,10 +206,10 @@ nv84_fifo_chan_ctor_dma(struct nouveau_object *parent, nv_parent(chan)->object_attach = nv84_fifo_object_attach; nv_parent(chan)->object_detach = nv50_fifo_object_detach; - nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset)); - nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset)); - nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset)); - nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset)); + nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); nv_wo32(base->ramfc, 0x3c, 0x003f6078); nv_wo32(base->ramfc, 0x44, 0x01003fff); nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); @@ -222,18 +232,26 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv50_channel_gpfifo_v0 v0; + } *args = data; struct nouveau_bar *bar = nouveau_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; - struct nv50_channel_ind_class *args = data; u64 ioffset, ilength; int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->pushbuf, + 0x2000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | @@ -249,6 +267,8 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, &chan->ramht); if (ret) @@ -259,8 +279,8 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent, nv_parent(chan)->object_attach = nv84_fifo_object_attach; nv_parent(chan)->object_detach = nv50_fifo_object_detach; - ioffset = args->ioffset; - ilength = order_base_2(args->ilength / 8); + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); nv_wo32(base->ramfc, 0x3c, 0x403f6078); nv_wo32(base->ramfc, 0x44, 0x01003fff); @@ -304,8 +324,10 @@ nv84_fifo_ofuncs_dma = { .dtor = nv50_fifo_chan_dtor, .init = nv84_fifo_chan_init, .fini = nv50_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_ofuncs @@ -314,14 +336,16 @@ nv84_fifo_ofuncs_ind = { .dtor = nv50_fifo_chan_dtor, .init = nv84_fifo_chan_init, .fini = nv50_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nv84_fifo_sclass[] = { - { NV84_CHANNEL_DMA_CLASS, &nv84_fifo_ofuncs_dma }, - { NV84_CHANNEL_IND_CLASS, &nv84_fifo_ofuncs_ind }, + { G82_CHANNEL_DMA, &nv84_fifo_ofuncs_dma }, + { G82_CHANNEL_GPFIFO, &nv84_fifo_ofuncs_ind }, {} }; @@ -389,19 +413,26 @@ nv84_fifo_cclass = { ******************************************************************************/ static void -nv84_fifo_uevent_enable(struct nouveau_event *event, int type, int index) +nv84_fifo_uevent_init(struct nvkm_event *event, int type, int index) { - struct nv84_fifo_priv *priv = event->priv; - nv_mask(priv, 0x002140, 0x40000000, 0x40000000); + struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent); + nv_mask(fifo, 0x002140, 0x40000000, 0x40000000); } static void -nv84_fifo_uevent_disable(struct nouveau_event *event, int type, int index) +nv84_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { - struct nv84_fifo_priv *priv = event->priv; - nv_mask(priv, 0x002140, 0x40000000, 0x00000000); + struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent); + nv_mask(fifo, 0x002140, 0x40000000, 0x00000000); } +static const struct nvkm_event_func +nv84_fifo_uevent_func = { + .ctor = nouveau_fifo_uevent_ctor, + .init = nv84_fifo_uevent_init, + .fini = nv84_fifo_uevent_fini, +}; + static int nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -425,9 +456,9 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.uevent->enable = nv84_fifo_uevent_enable; - priv->base.uevent->disable = nv84_fifo_uevent_disable; - priv->base.uevent->priv = priv; + ret = nvkm_event_init(&nv84_fifo_uevent_func, 1, 1, &priv->base.uevent); + if (ret) + return ret; nv_subdev(priv)->unit = 0x00000100; nv_subdev(priv)->intr = nv04_fifo_intr; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index ae4a4dc5642a..1fe1f8fbda0c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -28,7 +28,8 @@ #include <core/gpuobj.h> #include <core/engctx.h> #include <core/event.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <core/enum.h> #include <subdev/timer.h> @@ -187,20 +188,28 @@ nvc0_fifo_chan_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nv50_channel_gpfifo_v0 v0; + } *args = data; struct nouveau_bar *bar = nouveau_bar(parent); struct nvc0_fifo_priv *priv = (void *)engine; struct nvc0_fifo_base *base = (void *)parent; struct nvc0_fifo_chan *chan; - struct nv50_channel_ind_class *args = data; u64 usermem, ioffset, ilength; int ret, i; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength); + } else + return ret; ret = nouveau_fifo_channel_create(parent, engine, oclass, 1, priv->user.bar.offset, 0x1000, - args->pushbuf, + args->v0.pushbuf, (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | (1ULL << NVDEV_ENGINE_COPY0) | @@ -212,12 +221,14 @@ nvc0_fifo_chan_ctor(struct nouveau_object *parent, if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->context_attach = nvc0_fifo_context_attach; nv_parent(chan)->context_detach = nvc0_fifo_context_detach; usermem = chan->base.chid * 0x1000; - ioffset = args->ioffset; - ilength = order_base_2(args->ilength / 8); + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); for (i = 0; i < 0x1000; i += 4) nv_wo32(priv->user.mem, usermem + i, 0x00000000); @@ -291,13 +302,15 @@ nvc0_fifo_ofuncs = { .dtor = _nouveau_fifo_channel_dtor, .init = nvc0_fifo_chan_init, .fini = nvc0_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nvc0_fifo_sclass[] = { - { NVC0_CHANNEL_IND_CLASS, &nvc0_fifo_ofuncs }, + { FERMI_CHANNEL_GPFIFO, &nvc0_fifo_ofuncs }, {} }; @@ -654,7 +667,7 @@ nvc0_fifo_intr_fault(struct nvc0_fifo_priv *priv, int unit) object = engctx; while (object) { switch (nv_mclass(object)) { - case NVC0_CHANNEL_IND_CLASS: + case FERMI_CHANNEL_GPFIFO: nvc0_fifo_recover(priv, engine, (void *)object); break; } @@ -730,7 +743,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) for (unkn = 0; unkn < 8; unkn++) { u32 ints = (intr >> (unkn * 0x04)) & inte; if (ints & 0x1) { - nouveau_event_trigger(priv->base.uevent, 1, 0); + nouveau_fifo_uevent(&priv->base); ints &= ~1; } if (ints) { @@ -827,19 +840,26 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) } static void -nvc0_fifo_uevent_enable(struct nouveau_event *event, int type, int index) +nvc0_fifo_uevent_init(struct nvkm_event *event, int type, int index) { - struct nvc0_fifo_priv *priv = event->priv; - nv_mask(priv, 0x002140, 0x80000000, 0x80000000); + struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent); + nv_mask(fifo, 0x002140, 0x80000000, 0x80000000); } static void -nvc0_fifo_uevent_disable(struct nouveau_event *event, int type, int index) +nvc0_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { - struct nvc0_fifo_priv *priv = event->priv; - nv_mask(priv, 0x002140, 0x80000000, 0x00000000); + struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent); + nv_mask(fifo, 0x002140, 0x80000000, 0x00000000); } +static const struct nvkm_event_func +nvc0_fifo_uevent_func = { + .ctor = nouveau_fifo_uevent_ctor, + .init = nvc0_fifo_uevent_init, + .fini = nvc0_fifo_uevent_fini, +}; + static int nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -877,9 +897,9 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.uevent->enable = nvc0_fifo_uevent_enable; - priv->base.uevent->disable = nvc0_fifo_uevent_disable; - priv->base.uevent->priv = priv; + ret = nvkm_event_init(&nvc0_fifo_uevent_func, 1, 1, &priv->base.uevent); + if (ret) + return ret; nv_subdev(priv)->unit = 0x00000100; nv_subdev(priv)->intr = nvc0_fifo_intr; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 298063edb92d..d2f0fd39c145 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -28,7 +28,8 @@ #include <core/gpuobj.h> #include <core/engctx.h> #include <core/event.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> #include <core/enum.h> #include <subdev/timer.h> @@ -216,46 +217,56 @@ nve0_fifo_chan_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct kepler_channel_gpfifo_a_v0 v0; + } *args = data; struct nouveau_bar *bar = nouveau_bar(parent); struct nve0_fifo_priv *priv = (void *)engine; struct nve0_fifo_base *base = (void *)parent; struct nve0_fifo_chan *chan; - struct nve0_channel_ind_class *args = data; u64 usermem, ioffset, ilength; int ret, i; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x engine %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength, args->v0.engine); + } else + return ret; for (i = 0; i < FIFO_ENGINE_NR; i++) { - if (args->engine & (1 << i)) { + if (args->v0.engine & (1 << i)) { if (nouveau_engine(parent, fifo_engine[i].subdev)) { - args->engine = (1 << i); + args->v0.engine = (1 << i); break; } } } if (i == FIFO_ENGINE_NR) { - nv_error(priv, "unsupported engines 0x%08x\n", args->engine); + nv_error(priv, "unsupported engines 0x%08x\n", args->v0.engine); return -ENODEV; } ret = nouveau_fifo_channel_create(parent, engine, oclass, 1, priv->user.bar.offset, 0x200, - args->pushbuf, + args->v0.pushbuf, fifo_engine[i].mask, &chan); *pobject = nv_object(chan); if (ret) return ret; + args->v0.chid = chan->base.chid; + nv_parent(chan)->context_attach = nve0_fifo_context_attach; nv_parent(chan)->context_detach = nve0_fifo_context_detach; chan->engine = i; usermem = chan->base.chid * 0x200; - ioffset = args->ioffset; - ilength = order_base_2(args->ilength / 8); + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); for (i = 0; i < 0x200; i += 4) nv_wo32(priv->user.mem, usermem + i, 0x00000000); @@ -325,13 +336,15 @@ nve0_fifo_ofuncs = { .dtor = _nouveau_fifo_channel_dtor, .init = nve0_fifo_chan_init, .fini = nve0_fifo_chan_fini, + .map = _nouveau_fifo_channel_map, .rd32 = _nouveau_fifo_channel_rd32, .wr32 = _nouveau_fifo_channel_wr32, + .ntfy = _nouveau_fifo_channel_ntfy }; static struct nouveau_oclass nve0_fifo_sclass[] = { - { NVE0_CHANNEL_IND_CLASS, &nve0_fifo_ofuncs }, + { KEPLER_CHANNEL_GPFIFO_A, &nve0_fifo_ofuncs }, {} }; @@ -769,7 +782,7 @@ nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit) object = engctx; while (object) { switch (nv_mclass(object)) { - case NVE0_CHANNEL_IND_CLASS: + case KEPLER_CHANNEL_GPFIFO_A: nve0_fifo_recover(priv, engine, (void *)object); break; } @@ -859,7 +872,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv) static void nve0_fifo_intr_engine(struct nve0_fifo_priv *priv) { - nouveau_event_trigger(priv->base.uevent, 1, 0); + nouveau_fifo_uevent(&priv->base); } static void @@ -952,19 +965,26 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) } static void -nve0_fifo_uevent_enable(struct nouveau_event *event, int type, int index) +nve0_fifo_uevent_init(struct nvkm_event *event, int type, int index) { - struct nve0_fifo_priv *priv = event->priv; - nv_mask(priv, 0x002140, 0x80000000, 0x80000000); + struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent); + nv_mask(fifo, 0x002140, 0x80000000, 0x80000000); } static void -nve0_fifo_uevent_disable(struct nouveau_event *event, int type, int index) +nve0_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { - struct nve0_fifo_priv *priv = event->priv; - nv_mask(priv, 0x002140, 0x80000000, 0x00000000); + struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent); + nv_mask(fifo, 0x002140, 0x80000000, 0x00000000); } +static const struct nvkm_event_func +nve0_fifo_uevent_func = { + .ctor = nouveau_fifo_uevent_ctor, + .init = nve0_fifo_uevent_init, + .fini = nve0_fifo_uevent_fini, +}; + int nve0_fifo_fini(struct nouveau_object *object, bool suspend) { @@ -1067,9 +1087,9 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.uevent->enable = nve0_fifo_uevent_enable; - priv->base.uevent->disable = nve0_fifo_uevent_disable; - priv->base.uevent->priv = priv; + ret = nvkm_event_init(&nve0_fifo_uevent_func, 1, 1, &priv->base.uevent); + if (ret) + return ret; nv_subdev(priv)->unit = 0x00000100; nv_subdev(priv)->intr = nve0_fifo_intr; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c new file mode 100644 index 000000000000..3adb7fe91772 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c @@ -0,0 +1,104 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#include "ctxnvc0.h" + +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +gk110b_grctx_init_sm_0[] = { + { 0x419e04, 1, 0x04, 0x00000000 }, + { 0x419e08, 1, 0x04, 0x0000001d }, + { 0x419e0c, 1, 0x04, 0x00000000 }, + { 0x419e10, 1, 0x04, 0x00001c02 }, + { 0x419e44, 1, 0x04, 0x0013eff2 }, + { 0x419e48, 1, 0x04, 0x00000000 }, + { 0x419e4c, 1, 0x04, 0x0000007f }, + { 0x419e50, 2, 0x04, 0x00000000 }, + { 0x419e58, 1, 0x04, 0x00000001 }, + { 0x419e5c, 3, 0x04, 0x00000000 }, + { 0x419e68, 1, 0x04, 0x00000002 }, + { 0x419e6c, 12, 0x04, 0x00000000 }, + { 0x419eac, 1, 0x04, 0x00001f8f }, + { 0x419eb0, 1, 0x04, 0x0db00d2f }, + { 0x419eb8, 1, 0x04, 0x00000000 }, + { 0x419ec8, 1, 0x04, 0x0001304f }, + { 0x419f30, 4, 0x04, 0x00000000 }, + { 0x419f40, 1, 0x04, 0x00000018 }, + { 0x419f44, 3, 0x04, 0x00000000 }, + { 0x419f58, 1, 0x04, 0x00000000 }, + { 0x419f70, 1, 0x04, 0x00006300 }, + { 0x419f78, 1, 0x04, 0x000000eb }, + { 0x419f7c, 1, 0x04, 0x00000404 }, + {} +}; + +static const struct nvc0_graph_pack +gk110b_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nvf0_grctx_init_tex_0 }, + { nvf0_grctx_init_mpc_0 }, + { nvf0_grctx_init_l1c_0 }, + { gk110b_grctx_init_sm_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + +struct nouveau_oclass * +gk110b_grctx_oclass = &(struct nvc0_grctx_oclass) { + .base.handle = NV_ENGCTX(GR, 0xf1), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_context_ctor, + .dtor = nvc0_graph_context_dtor, + .init = _nouveau_graph_context_init, + .fini = _nouveau_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, + .main = nve4_grctx_generate_main, + .unkn = nve4_grctx_generate_unkn, + .hub = nvf0_grctx_pack_hub, + .gpc = nvf0_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = gk110b_grctx_pack_tpc, + .ppc = nvf0_grctx_pack_ppc, + .icmd = nvf0_grctx_pack_icmd, + .mthd = nvf0_grctx_pack_mthd, + .bundle = nve4_grctx_generate_bundle, + .bundle_size = 0x3000, + .bundle_min_gpm_fifo_depth = 0x180, + .bundle_token_limit = 0x600, + .pagepool = nve4_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvd7_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, + .alpha_nr_max = 0x7ff, + .alpha_nr = 0x648, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c index 224ee0287ab7..36fc9831cc93 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c @@ -41,7 +41,6 @@ gk20a_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nve4_grctx_generate_main, - .mods = nve4_grctx_generate_mods, .unkn = nve4_grctx_generate_unkn, .hub = nve4_grctx_pack_hub, .gpc = nve4_grctx_pack_gpc, @@ -50,4 +49,15 @@ gk20a_grctx_oclass = &(struct nvc0_grctx_oclass) { .ppc = nve4_grctx_pack_ppc, .icmd = nve4_grctx_pack_icmd, .mthd = gk20a_grctx_pack_mthd, + .bundle = nve4_grctx_generate_bundle, + .bundle_size = 0x1800, + .bundle_min_gpm_fifo_depth = 0x62, + .bundle_token_limit = 0x100, + .pagepool = nve4_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvd7_grctx_generate_attrib, + .attrib_nr_max = 0x240, + .attrib_nr = 0x240, + .alpha_nr_max = 0x648 + (0x648 / 2), + .alpha_nr = 0x648, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c index b0d0fb2f4d08..62e918b9fa81 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c @@ -859,45 +859,74 @@ gm107_grctx_pack_ppc[] = { ******************************************************************************/ static void -gm107_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +gm107_grctx_generate_bundle(struct nvc0_grctx *info) { - mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x200000, 0x1000, NV_MEM_ACCESS_RW); - - mmio_list(0x40800c, 0x00000000, 8, 1); - mmio_list(0x408010, 0x80000000, 0, 0); - mmio_list(0x419004, 0x00000000, 8, 1); - mmio_list(0x419008, 0x00000000, 0, 0); - mmio_list(0x4064cc, 0x80000000, 0, 0); - mmio_list(0x418e30, 0x80000000, 0, 0); - - mmio_list(0x408004, 0x00000000, 8, 0); - mmio_list(0x408008, 0x80000030, 0, 0); - mmio_list(0x418e24, 0x00000000, 8, 0); - mmio_list(0x418e28, 0x80000030, 0, 0); - - mmio_list(0x4064c8, 0x018002c0, 0, 0); - - mmio_list(0x418810, 0x80000000, 12, 2); - mmio_list(0x419848, 0x10000000, 12, 2); - mmio_list(0x419c2c, 0x10000000, 12, 2); - - mmio_list(0x405830, 0x0aa01000, 0, 0); - mmio_list(0x4064c4, 0x0400ffff, 0, 0); - - /*XXX*/ - mmio_list(0x5030c0, 0x00001540, 0, 0); - mmio_list(0x5030f4, 0x00000000, 0, 0); - mmio_list(0x5030e4, 0x00002000, 0, 0); - mmio_list(0x5030f8, 0x00003fc0, 0, 0); - mmio_list(0x418ea0, 0x07151540, 0, 0); - - mmio_list(0x5032c0, 0x00001540, 0, 0); - mmio_list(0x5032f4, 0x00001fe0, 0, 0); - mmio_list(0x5032e4, 0x00002000, 0, 0); - mmio_list(0x5032f8, 0x00006fc0, 0, 0); - mmio_list(0x418ea4, 0x07151540, 0, 0); + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv); + const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, + impl->bundle_size / 0x20); + const u32 token_limit = impl->bundle_token_limit; + const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; + const int s = 8; + const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + mmio_refn(info, 0x408004, 0x00000000, s, b); + mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b); + mmio_refn(info, 0x418e24, 0x00000000, s, b); + mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b); + mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); +} + +static void +gm107_grctx_generate_pagepool(struct nvc0_grctx *info) +{ + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv); + const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; + const int s = 8; + const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + mmio_refn(info, 0x40800c, 0x00000000, s, b); + mmio_wr32(info, 0x408010, 0x80000000); + mmio_refn(info, 0x419004, 0x00000000, s, b); + mmio_wr32(info, 0x419008, 0x00000000); + mmio_wr32(info, 0x4064cc, 0x80000000); + mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */ +} + +static void +gm107_grctx_generate_attrib(struct nvc0_grctx *info) +{ + struct nvc0_graph_priv *priv = info->priv; + const struct nvc0_grctx_oclass *impl = (void *)nvc0_grctx_impl(priv); + const u32 alpha = impl->alpha_nr; + const u32 attrib = impl->attrib_nr; + const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const u32 access = NV_MEM_ACCESS_RW; + const int s = 12; + const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int max_batches = 0xffff; + u32 bo = 0; + u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + int gpc, ppc, n = 0; + + mmio_refn(info, 0x418810, 0x80000000, s, b); + mmio_refn(info, 0x419848, 0x10000000, s, b); + mmio_refn(info, 0x419c2c, 0x10000000, s, b); + mmio_wr32(info, 0x405830, (attrib << 16) | alpha); + mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++, n++) { + const u32 as = alpha * priv->ppc_tpc_nr[gpc][ppc]; + const u32 bs = attrib * priv->ppc_tpc_nr[gpc][ppc]; + const u32 u = 0x418ea0 + (n * 0x04); + const u32 o = PPC_UNIT(gpc, ppc, 0); + mmio_wr32(info, o + 0xc0, bs); + mmio_wr32(info, o + 0xf4, bo); + bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + mmio_wr32(info, o + 0xe4, as); + mmio_wr32(info, o + 0xf8, ao); + ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + mmio_wr32(info, u, (0x715 /*XXX*/ << 16) | bs); + } + } } static void @@ -934,7 +963,9 @@ gm107_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_wr32(priv, 0x404154, 0x00000000); - oclass->mods(priv, info); + oclass->bundle(info); + oclass->pagepool(info); + oclass->attrib(info); oclass->unkn(priv); gm107_grctx_generate_tpcid(priv); @@ -979,7 +1010,6 @@ gm107_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = gm107_grctx_generate_main, - .mods = gm107_grctx_generate_mods, .unkn = nve4_grctx_generate_unkn, .hub = gm107_grctx_pack_hub, .gpc = gm107_grctx_pack_gpc, @@ -988,4 +1018,15 @@ gm107_grctx_oclass = &(struct nvc0_grctx_oclass) { .ppc = gm107_grctx_pack_ppc, .icmd = gm107_grctx_pack_icmd, .mthd = gm107_grctx_pack_mthd, + .bundle = gm107_grctx_generate_bundle, + .bundle_size = 0x3000, + .bundle_min_gpm_fifo_depth = 0x180, + .bundle_token_limit = 0x2c0, + .pagepool = gm107_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = gm107_grctx_generate_attrib, + .attrib_nr_max = 0xff0, + .attrib_nr = 0xaa0, + .alpha_nr_max = 0x1800, + .alpha_nr = 0x1000, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c index 8de4a4291548..ce252adbef81 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c @@ -531,50 +531,6 @@ nv108_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -static void -nv108_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) -{ - u32 magic[GPC_MAX][2]; - u32 offset; - int gpc; - - mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); - mmio_list(0x40800c, 0x00000000, 8, 1); - mmio_list(0x408010, 0x80000000, 0, 0); - mmio_list(0x419004, 0x00000000, 8, 1); - mmio_list(0x419008, 0x00000000, 0, 0); - mmio_list(0x4064cc, 0x80000000, 0, 0); - mmio_list(0x408004, 0x00000000, 8, 0); - mmio_list(0x408008, 0x80000030, 0, 0); - mmio_list(0x418808, 0x00000000, 8, 0); - mmio_list(0x41880c, 0x80000030, 0, 0); - mmio_list(0x4064c8, 0x00c20200, 0, 0); - mmio_list(0x418810, 0x80000000, 12, 2); - mmio_list(0x419848, 0x10000000, 12, 2); - - mmio_list(0x405830, 0x02180648, 0, 0); - mmio_list(0x4064c4, 0x0192ffff, 0, 0); - - for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) { - u16 magic0 = 0x0218 * priv->tpc_nr[gpc]; - u16 magic1 = 0x0648 * priv->tpc_nr[gpc]; - magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset; - magic[gpc][1] = 0x00000000 | (magic1 << 16); - offset += 0x0324 * priv->tpc_nr[gpc]; - } - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0); - mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0); - offset += 0x07ff * priv->tpc_nr[gpc]; - } - - mmio_list(0x17e91c, 0x0b040a0b, 0, 0); - mmio_list(0x17e920, 0x00090d08, 0, 0); -} - struct nouveau_oclass * nv108_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0x08), @@ -587,7 +543,6 @@ nv108_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nve4_grctx_generate_main, - .mods = nv108_grctx_generate_mods, .unkn = nve4_grctx_generate_unkn, .hub = nv108_grctx_pack_hub, .gpc = nv108_grctx_pack_gpc, @@ -596,4 +551,15 @@ nv108_grctx_oclass = &(struct nvc0_grctx_oclass) { .ppc = nv108_grctx_pack_ppc, .icmd = nv108_grctx_pack_icmd, .mthd = nvf0_grctx_pack_mthd, + .bundle = nve4_grctx_generate_bundle, + .bundle_size = 0x3000, + .bundle_min_gpm_fifo_depth = 0xc2, + .bundle_token_limit = 0x200, + .pagepool = nve4_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvd7_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, + .alpha_nr_max = 0x7ff, + .alpha_nr = 0x648, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c index 552fdbd45ebe..1d0e33fb5f61 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c @@ -113,6 +113,8 @@ #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) #define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac) +#include <subdev/fb.h> + /* * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's * the GPU itself that does context-switching, but it needs a special @@ -569,8 +571,12 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, 0x407d08, 0x00010040); else if (device->chipset < 0xa0) gr_def(ctx, 0x407d08, 0x00390040); - else - gr_def(ctx, 0x407d08, 0x003d0040); + else { + if (nouveau_fb(device)->ram->type != NV_MEM_TYPE_GDDR5) + gr_def(ctx, 0x407d08, 0x003d0040); + else + gr_def(ctx, 0x407d08, 0x003c0040); + } gr_def(ctx, 0x407d0c, 0x00000022); } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c index 833a96508c4e..b8e5fe60a1eb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c @@ -982,34 +982,93 @@ nvc0_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ +int +nvc0_grctx_mmio_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access) +{ + if (info->data) { + info->buffer[info->buffer_nr] = round_up(info->addr, align); + info->addr = info->buffer[info->buffer_nr] + size; + info->data->size = size; + info->data->align = align; + info->data->access = access; + info->data++; + return info->buffer_nr++; + } + return -1; +} + +void +nvc0_grctx_mmio_item(struct nvc0_grctx *info, u32 addr, u32 data, + int shift, int buffer) +{ + if (info->data) { + if (shift >= 0) { + info->mmio->addr = addr; + info->mmio->data = data; + info->mmio->shift = shift; + info->mmio->buffer = buffer; + if (buffer >= 0) + data |= info->buffer[buffer] >> shift; + info->mmio++; + } else + return; + } else { + if (buffer >= 0) + return; + } + + nv_wr32(info->priv, addr, data); +} + +void +nvc0_grctx_generate_bundle(struct nvc0_grctx *info) +{ + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv); + const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; + const int s = 8; + const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + mmio_refn(info, 0x408004, 0x00000000, s, b); + mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b); + mmio_refn(info, 0x418808, 0x00000000, s, b); + mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b); +} + void -nvc0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +nvc0_grctx_generate_pagepool(struct nvc0_grctx *info) { + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv); + const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; + const int s = 8; + const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + mmio_refn(info, 0x40800c, 0x00000000, s, b); + mmio_wr32(info, 0x408010, 0x80000000); + mmio_refn(info, 0x419004, 0x00000000, s, b); + mmio_wr32(info, 0x419008, 0x00000000); +} + +void +nvc0_grctx_generate_attrib(struct nvc0_grctx *info) +{ + struct nvc0_graph_priv *priv = info->priv; + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv); + const u32 attrib = impl->attrib_nr; + const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const u32 access = NV_MEM_ACCESS_RW; + const int s = 12; + const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); int gpc, tpc; - u32 offset; - - mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); - - mmio_list(0x408004, 0x00000000, 8, 0); - mmio_list(0x408008, 0x80000018, 0, 0); - mmio_list(0x40800c, 0x00000000, 8, 1); - mmio_list(0x408010, 0x80000000, 0, 0); - mmio_list(0x418810, 0x80000000, 12, 2); - mmio_list(0x419848, 0x10000000, 12, 2); - mmio_list(0x419004, 0x00000000, 8, 1); - mmio_list(0x419008, 0x00000000, 0, 0); - mmio_list(0x418808, 0x00000000, 8, 0); - mmio_list(0x41880c, 0x80000018, 0, 0); - - mmio_list(0x405830, 0x02180000, 0, 0); - - for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) { + u32 bo = 0; + + mmio_refn(info, 0x418810, 0x80000000, s, b); + mmio_refn(info, 0x419848, 0x10000000, s, b); + mmio_wr32(info, 0x405830, (attrib << 16)); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - u32 addr = TPC_UNIT(gpc, tpc, 0x0520); - mmio_list(addr, 0x02180000 | offset, 0, 0); - offset += 0x0324; + const u32 o = TPC_UNIT(gpc, tpc, 0x0520); + mmio_skip(info, o, (attrib << 16) | ++bo); + mmio_wr32(info, o, (attrib << 16) | --bo); + bo += impl->attrib_nr_max; } } } @@ -1170,7 +1229,7 @@ nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; - nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 0); nvc0_graph_mmio(priv, oclass->hub); nvc0_graph_mmio(priv, oclass->gpc); @@ -1180,7 +1239,9 @@ nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_wr32(priv, 0x404154, 0x00000000); - oclass->mods(priv, info); + oclass->bundle(info); + oclass->pagepool(info); + oclass->attrib(info); oclass->unkn(priv); nvc0_grctx_generate_tpcid(priv); @@ -1192,7 +1253,7 @@ nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nvc0_graph_icmd(priv, oclass->icmd); nv_wr32(priv, 0x404154, 0x00000400); nvc0_graph_mthd(priv, oclass->mthd); - nv_mask(priv, 0x000260, 0x00000001, 0x00000001); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 1); } int @@ -1308,7 +1369,6 @@ nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, .unkn = nvc0_grctx_generate_unkn, .hub = nvc0_grctx_pack_hub, .gpc = nvc0_grctx_pack_gpc, @@ -1316,4 +1376,11 @@ nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) { .tpc = nvc0_grctx_pack_tpc, .icmd = nvc0_grctx_pack_icmd, .mthd = nvc0_grctx_pack_mthd, + .bundle = nvc0_grctx_generate_bundle, + .bundle_size = 0x1800, + .pagepool = nvc0_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvc0_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h index 8da8b627b9d0..c776cd715e33 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h @@ -12,12 +12,19 @@ struct nvc0_grctx { u64 addr; }; +int nvc0_grctx_mmio_data(struct nvc0_grctx *, u32 size, u32 align, u32 access); +void nvc0_grctx_mmio_item(struct nvc0_grctx *, u32 addr, u32 data, int s, int); + +#define mmio_vram(a,b,c,d) nvc0_grctx_mmio_data((a), (b), (c), (d)) +#define mmio_refn(a,b,c,d,e) nvc0_grctx_mmio_item((a), (b), (c), (d), (e)) +#define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1) +#define mmio_wr32(a,b,c) mmio_refn((a), (b), (c), 0, -1) + struct nvc0_grctx_oclass { struct nouveau_oclass base; /* main context generation function */ void (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *); /* context-specific modify-on-first-load list generation function */ - void (*mods)(struct nvc0_graph_priv *, struct nvc0_grctx *); void (*unkn)(struct nvc0_graph_priv *); /* mmio context data */ const struct nvc0_graph_pack *hub; @@ -28,30 +35,34 @@ struct nvc0_grctx_oclass { /* indirect context data, generated with icmds/mthds */ const struct nvc0_graph_pack *icmd; const struct nvc0_graph_pack *mthd; + /* bundle circular buffer */ + void (*bundle)(struct nvc0_grctx *); + u32 bundle_size; + u32 bundle_min_gpm_fifo_depth; + u32 bundle_token_limit; + /* pagepool */ + void (*pagepool)(struct nvc0_grctx *); + u32 pagepool_size; + /* attribute(/alpha) circular buffer */ + void (*attrib)(struct nvc0_grctx *); + u32 attrib_nr_max; + u32 attrib_nr; + u32 alpha_nr_max; + u32 alpha_nr; }; -#define mmio_data(s,a,p) do { \ - info->buffer[info->buffer_nr] = round_up(info->addr, (a)); \ - info->addr = info->buffer[info->buffer_nr++] + (s); \ - info->data->size = (s); \ - info->data->align = (a); \ - info->data->access = (p); \ - info->data++; \ -} while(0) - -#define mmio_list(r,d,s,b) do { \ - info->mmio->addr = (r); \ - info->mmio->data = (d); \ - info->mmio->shift = (s); \ - info->mmio->buffer = (b); \ - info->mmio++; \ - nv_wr32(priv, (r), (d) | ((s) ? (info->buffer[(b)] >> (s)) : 0)); \ -} while(0) +static inline const struct nvc0_grctx_oclass * +nvc0_grctx_impl(struct nvc0_graph_priv *priv) +{ + return (void *)nv_engine(priv)->cclass; +} extern struct nouveau_oclass *nvc0_grctx_oclass; int nvc0_grctx_generate(struct nvc0_graph_priv *); void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); +void nvc0_grctx_generate_bundle(struct nvc0_grctx *); +void nvc0_grctx_generate_pagepool(struct nvc0_grctx *); +void nvc0_grctx_generate_attrib(struct nvc0_grctx *); void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *); void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *); void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *); @@ -60,22 +71,27 @@ void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *); void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *); extern struct nouveau_oclass *nvc1_grctx_oclass; -void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); +void nvc1_grctx_generate_attrib(struct nvc0_grctx *); void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *); extern struct nouveau_oclass *nvc4_grctx_oclass; extern struct nouveau_oclass *nvc8_grctx_oclass; + extern struct nouveau_oclass *nvd7_grctx_oclass; +void nvd7_grctx_generate_attrib(struct nvc0_grctx *); + extern struct nouveau_oclass *nvd9_grctx_oclass; extern struct nouveau_oclass *nve4_grctx_oclass; extern struct nouveau_oclass *gk20a_grctx_oclass; void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nve4_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); +void nve4_grctx_generate_bundle(struct nvc0_grctx *); +void nve4_grctx_generate_pagepool(struct nvc0_grctx *); void nve4_grctx_generate_unkn(struct nvc0_graph_priv *); void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *); extern struct nouveau_oclass *nvf0_grctx_oclass; +extern struct nouveau_oclass *gk110b_grctx_oclass; extern struct nouveau_oclass *nv108_grctx_oclass; extern struct nouveau_oclass *gm107_grctx_oclass; @@ -160,16 +176,23 @@ extern const struct nvc0_graph_pack nve4_grctx_pack_ppc[]; extern const struct nvc0_graph_pack nve4_grctx_pack_icmd[]; extern const struct nvc0_graph_init nve4_grctx_init_a097_0[]; +extern const struct nvc0_graph_pack nvf0_grctx_pack_icmd[]; + extern const struct nvc0_graph_pack nvf0_grctx_pack_mthd[]; +extern const struct nvc0_graph_pack nvf0_grctx_pack_hub[]; extern const struct nvc0_graph_init nvf0_grctx_init_pri_0[]; extern const struct nvc0_graph_init nvf0_grctx_init_cwd_0[]; +extern const struct nvc0_graph_pack nvf0_grctx_pack_gpc[]; extern const struct nvc0_graph_init nvf0_grctx_init_gpc_unk_2[]; +extern const struct nvc0_graph_init nvf0_grctx_init_tex_0[]; extern const struct nvc0_graph_init nvf0_grctx_init_mpc_0[]; extern const struct nvc0_graph_init nvf0_grctx_init_l1c_0[]; +extern const struct nvc0_graph_pack nvf0_grctx_pack_ppc[]; + extern const struct nvc0_graph_init nv108_grctx_init_rstr2d_0[]; extern const struct nvc0_graph_init nv108_grctx_init_prop_0[]; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c index 24a92c569c0a..c6ba8fed18f1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c @@ -727,38 +727,38 @@ nvc1_grctx_pack_tpc[] = { ******************************************************************************/ void -nvc1_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +nvc1_grctx_generate_attrib(struct nvc0_grctx *info) { + struct nvc0_graph_priv *priv = info->priv; + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv); + const u32 alpha = impl->alpha_nr; + const u32 beta = impl->attrib_nr; + const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const u32 access = NV_MEM_ACCESS_RW; + const int s = 12; + const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int timeslice_mode = 1; + const int max_batches = 0xffff; + u32 bo = 0; + u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; int gpc, tpc; - u32 offset; - mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); - mmio_list(0x408004, 0x00000000, 8, 0); - mmio_list(0x408008, 0x80000018, 0, 0); - mmio_list(0x40800c, 0x00000000, 8, 1); - mmio_list(0x408010, 0x80000000, 0, 0); - mmio_list(0x418810, 0x80000000, 12, 2); - mmio_list(0x419848, 0x10000000, 12, 2); - mmio_list(0x419004, 0x00000000, 8, 1); - mmio_list(0x419008, 0x00000000, 0, 0); - mmio_list(0x418808, 0x00000000, 8, 0); - mmio_list(0x41880c, 0x80000018, 0, 0); + mmio_refn(info, 0x418810, 0x80000000, s, b); + mmio_refn(info, 0x419848, 0x10000000, s, b); + mmio_wr32(info, 0x405830, (beta << 16) | alpha); + mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); - mmio_list(0x405830, 0x02180218, 0, 0); - mmio_list(0x4064c4, 0x0086ffff, 0, 0); - - for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) { - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - u32 addr = TPC_UNIT(gpc, tpc, 0x0520); - mmio_list(addr, 0x12180000 | offset, 0, 0); - offset += 0x0324; - } + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - u32 addr = TPC_UNIT(gpc, tpc, 0x0544); - mmio_list(addr, 0x02180000 | offset, 0, 0); - offset += 0x0324; + const u32 a = alpha; + const u32 b = beta; + const u32 t = timeslice_mode; + const u32 o = TPC_UNIT(gpc, tpc, 0x500); + mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo); + mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo); + bo += impl->attrib_nr_max; + mmio_wr32(info, o + 0x44, (a << 16) | ao); + ao += impl->alpha_nr_max; } } } @@ -786,7 +786,6 @@ nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nvc0_grctx_generate_main, - .mods = nvc1_grctx_generate_mods, .unkn = nvc1_grctx_generate_unkn, .hub = nvc1_grctx_pack_hub, .gpc = nvc1_grctx_pack_gpc, @@ -794,4 +793,13 @@ nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) { .tpc = nvc1_grctx_pack_tpc, .icmd = nvc1_grctx_pack_icmd, .mthd = nvc1_grctx_pack_mthd, + .bundle = nvc0_grctx_generate_bundle, + .bundle_size = 0x1800, + .pagepool = nvc0_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvc1_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, + .alpha_nr_max = 0x324, + .alpha_nr = 0x218, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c index e11ed5538193..41705c60cc47 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c @@ -92,7 +92,6 @@ nvc4_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, .unkn = nvc0_grctx_generate_unkn, .hub = nvc0_grctx_pack_hub, .gpc = nvc0_grctx_pack_gpc, @@ -100,4 +99,11 @@ nvc4_grctx_oclass = &(struct nvc0_grctx_oclass) { .tpc = nvc4_grctx_pack_tpc, .icmd = nvc0_grctx_pack_icmd, .mthd = nvc0_grctx_pack_mthd, + .bundle = nvc0_grctx_generate_bundle, + .bundle_size = 0x1800, + .pagepool = nvc0_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvc0_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c index feebd58dfe8d..8f804cd8f9c7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c @@ -343,7 +343,6 @@ nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, .unkn = nvc0_grctx_generate_unkn, .hub = nvc0_grctx_pack_hub, .gpc = nvc8_grctx_pack_gpc, @@ -351,4 +350,11 @@ nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) { .tpc = nvc0_grctx_pack_tpc, .icmd = nvc8_grctx_pack_icmd, .mthd = nvc8_grctx_pack_mthd, + .bundle = nvc0_grctx_generate_bundle, + .bundle_size = 0x1800, + .pagepool = nvc0_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvc0_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c index 1dbc8d7f2e86..fcf534fd9e65 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c @@ -177,44 +177,41 @@ nvd7_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -static void -nvd7_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +void +nvd7_grctx_generate_attrib(struct nvc0_grctx *info) { - u32 magic[GPC_MAX][2]; - u32 offset; - int gpc; - - mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); - mmio_list(0x40800c, 0x00000000, 8, 1); - mmio_list(0x408010, 0x80000000, 0, 0); - mmio_list(0x419004, 0x00000000, 8, 1); - mmio_list(0x419008, 0x00000000, 0, 0); - mmio_list(0x408004, 0x00000000, 8, 0); - mmio_list(0x408008, 0x80000018, 0, 0); - mmio_list(0x418808, 0x00000000, 8, 0); - mmio_list(0x41880c, 0x80000018, 0, 0); - mmio_list(0x418810, 0x80000000, 12, 2); - mmio_list(0x419848, 0x10000000, 12, 2); + struct nvc0_graph_priv *priv = info->priv; + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv); + const u32 alpha = impl->alpha_nr; + const u32 beta = impl->attrib_nr; + const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const u32 access = NV_MEM_ACCESS_RW; + const int s = 12; + const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int timeslice_mode = 1; + const int max_batches = 0xffff; + u32 bo = 0; + u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + int gpc, ppc; - mmio_list(0x405830, 0x02180324, 0, 0); - mmio_list(0x4064c4, 0x00c9ffff, 0, 0); - - for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) { - u16 magic0 = 0x0218 * priv->tpc_nr[gpc]; - u16 magic1 = 0x0324 * priv->tpc_nr[gpc]; - magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset; - magic[gpc][1] = 0x00000000 | (magic1 << 16); - offset += 0x0324 * priv->tpc_nr[gpc]; - } + mmio_refn(info, 0x418810, 0x80000000, s, b); + mmio_refn(info, 0x419848, 0x10000000, s, b); + mmio_wr32(info, 0x405830, (beta << 16) | alpha); + mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0); - mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0); - offset += 0x07ff * priv->tpc_nr[gpc]; + for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) { + const u32 a = alpha * priv->ppc_tpc_nr[gpc][ppc]; + const u32 b = beta * priv->ppc_tpc_nr[gpc][ppc]; + const u32 t = timeslice_mode; + const u32 o = PPC_UNIT(gpc, ppc, 0); + mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo); + mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo); + bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + mmio_wr32(info, o + 0xe4, (a << 16) | ao); + ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + } } - mmio_list(0x17e91c, 0x03060609, 0, 0); /* different from kepler */ } void @@ -223,7 +220,7 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; int i; - nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 0); nvc0_graph_mmio(priv, oclass->hub); nvc0_graph_mmio(priv, oclass->gpc); @@ -233,7 +230,9 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_wr32(priv, 0x404154, 0x00000000); - oclass->mods(priv, info); + oclass->bundle(info); + oclass->pagepool(info); + oclass->attrib(info); oclass->unkn(priv); nvc0_grctx_generate_tpcid(priv); @@ -248,7 +247,7 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nvc0_graph_icmd(priv, oclass->icmd); nv_wr32(priv, 0x404154, 0x00000400); nvc0_graph_mthd(priv, oclass->mthd); - nv_mask(priv, 0x000260, 0x00000001, 0x00000001); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 1); } struct nouveau_oclass * @@ -263,7 +262,6 @@ nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nvd7_grctx_generate_main, - .mods = nvd7_grctx_generate_mods, .unkn = nve4_grctx_generate_unkn, .hub = nvd7_grctx_pack_hub, .gpc = nvd7_grctx_pack_gpc, @@ -272,4 +270,13 @@ nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) { .ppc = nvd7_grctx_pack_ppc, .icmd = nvd9_grctx_pack_icmd, .mthd = nvd9_grctx_pack_mthd, + .bundle = nvc0_grctx_generate_bundle, + .bundle_size = 0x1800, + .pagepool = nvc0_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvd7_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, + .alpha_nr_max = 0x7ff, + .alpha_nr = 0x324, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c index c665fb7e4660..b9a301b6fd9f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c @@ -511,7 +511,6 @@ nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nvc0_grctx_generate_main, - .mods = nvc1_grctx_generate_mods, .unkn = nvc1_grctx_generate_unkn, .hub = nvd9_grctx_pack_hub, .gpc = nvd9_grctx_pack_gpc, @@ -519,4 +518,13 @@ nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) { .tpc = nvd9_grctx_pack_tpc, .icmd = nvd9_grctx_pack_icmd, .mthd = nvd9_grctx_pack_mthd, + .bundle = nvc0_grctx_generate_bundle, + .bundle_size = 0x1800, + .pagepool = nvc0_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvc1_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, + .alpha_nr_max = 0x324, + .alpha_nr = 0x218, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c index c5b249238587..ccac2ee1a1cb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c @@ -839,47 +839,34 @@ nve4_grctx_pack_ppc[] = { ******************************************************************************/ void -nve4_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +nve4_grctx_generate_bundle(struct nvc0_grctx *info) { - u32 magic[GPC_MAX][2]; - u32 offset; - int gpc; - - mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); - mmio_list(0x40800c, 0x00000000, 8, 1); - mmio_list(0x408010, 0x80000000, 0, 0); - mmio_list(0x419004, 0x00000000, 8, 1); - mmio_list(0x419008, 0x00000000, 0, 0); - mmio_list(0x4064cc, 0x80000000, 0, 0); - mmio_list(0x408004, 0x00000000, 8, 0); - mmio_list(0x408008, 0x80000030, 0, 0); - mmio_list(0x418808, 0x00000000, 8, 0); - mmio_list(0x41880c, 0x80000030, 0, 0); - mmio_list(0x4064c8, 0x01800600, 0, 0); - mmio_list(0x418810, 0x80000000, 12, 2); - mmio_list(0x419848, 0x10000000, 12, 2); - - mmio_list(0x405830, 0x02180648, 0, 0); - mmio_list(0x4064c4, 0x0192ffff, 0, 0); - - for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) { - u16 magic0 = 0x0218 * priv->tpc_nr[gpc]; - u16 magic1 = 0x0648 * priv->tpc_nr[gpc]; - magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset; - magic[gpc][1] = 0x00000000 | (magic1 << 16); - offset += 0x0324 * priv->tpc_nr[gpc]; - } - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0); - mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0); - offset += 0x07ff * priv->tpc_nr[gpc]; - } + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv); + const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, + impl->bundle_size / 0x20); + const u32 token_limit = impl->bundle_token_limit; + const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; + const int s = 8; + const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + mmio_refn(info, 0x408004, 0x00000000, s, b); + mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b); + mmio_refn(info, 0x418808, 0x00000000, s, b); + mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b); + mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); +} - mmio_list(0x17e91c, 0x06060609, 0, 0); - mmio_list(0x17e920, 0x00090a05, 0, 0); +void +nve4_grctx_generate_pagepool(struct nvc0_grctx *info) +{ + const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv); + const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; + const int s = 8; + const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + mmio_refn(info, 0x40800c, 0x00000000, s, b); + mmio_wr32(info, 0x408010, 0x80000000); + mmio_refn(info, 0x419004, 0x00000000, s, b); + mmio_wr32(info, 0x419008, 0x00000000); + mmio_wr32(info, 0x4064cc, 0x80000000); } void @@ -957,7 +944,7 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; int i; - nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 0); nvc0_graph_mmio(priv, oclass->hub); nvc0_graph_mmio(priv, oclass->gpc); @@ -967,7 +954,9 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_wr32(priv, 0x404154, 0x00000000); - oclass->mods(priv, info); + oclass->bundle(info); + oclass->pagepool(info); + oclass->attrib(info); oclass->unkn(priv); nvc0_grctx_generate_tpcid(priv); @@ -991,7 +980,7 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nvc0_graph_icmd(priv, oclass->icmd); nv_wr32(priv, 0x404154, 0x00000400); nvc0_graph_mthd(priv, oclass->mthd); - nv_mask(priv, 0x000260, 0x00000001, 0x00000001); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 1); nv_mask(priv, 0x418800, 0x00200000, 0x00200000); nv_mask(priv, 0x41be10, 0x00800000, 0x00800000); @@ -1009,7 +998,6 @@ nve4_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nve4_grctx_generate_main, - .mods = nve4_grctx_generate_mods, .unkn = nve4_grctx_generate_unkn, .hub = nve4_grctx_pack_hub, .gpc = nve4_grctx_pack_gpc, @@ -1018,4 +1006,15 @@ nve4_grctx_oclass = &(struct nvc0_grctx_oclass) { .ppc = nve4_grctx_pack_ppc, .icmd = nve4_grctx_pack_icmd, .mthd = nve4_grctx_pack_mthd, + .bundle = nve4_grctx_generate_bundle, + .bundle_size = 0x3000, + .bundle_min_gpm_fifo_depth = 0x180, + .bundle_token_limit = 0x600, + .pagepool = nve4_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvd7_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, + .alpha_nr_max = 0x7ff, + .alpha_nr = 0x648, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c index dec03f04114d..e9b0dcf95a49 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c @@ -279,7 +279,7 @@ nvf0_grctx_init_icmd_0[] = { {} }; -static const struct nvc0_graph_pack +const struct nvc0_graph_pack nvf0_grctx_pack_icmd[] = { { nvf0_grctx_init_icmd_0 }, {} @@ -668,7 +668,7 @@ nvf0_grctx_init_be_0[] = { {} }; -static const struct nvc0_graph_pack +const struct nvc0_graph_pack nvf0_grctx_pack_hub[] = { { nvc0_grctx_init_main_0 }, { nvf0_grctx_init_fe_0 }, @@ -704,7 +704,7 @@ nvf0_grctx_init_gpc_unk_2[] = { {} }; -static const struct nvc0_graph_pack +const struct nvc0_graph_pack nvf0_grctx_pack_gpc[] = { { nvc0_grctx_init_gpc_unk_0 }, { nvd9_grctx_init_prop_0 }, @@ -718,7 +718,7 @@ nvf0_grctx_pack_gpc[] = { {} }; -static const struct nvc0_graph_init +const struct nvc0_graph_init nvf0_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000000f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, @@ -797,7 +797,7 @@ nvf0_grctx_init_cbm_0[] = { {} }; -static const struct nvc0_graph_pack +const struct nvc0_graph_pack nvf0_grctx_pack_ppc[] = { { nve4_grctx_init_pes_0 }, { nvf0_grctx_init_cbm_0 }, @@ -809,58 +809,6 @@ nvf0_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -static void -nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) -{ - u32 magic[GPC_MAX][4]; - u32 offset; - int gpc; - - mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); - mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); - mmio_list(0x40800c, 0x00000000, 8, 1); - mmio_list(0x408010, 0x80000000, 0, 0); - mmio_list(0x419004, 0x00000000, 8, 1); - mmio_list(0x419008, 0x00000000, 0, 0); - mmio_list(0x4064cc, 0x80000000, 0, 0); - mmio_list(0x408004, 0x00000000, 8, 0); - mmio_list(0x408008, 0x80000030, 0, 0); - mmio_list(0x418808, 0x00000000, 8, 0); - mmio_list(0x41880c, 0x80000030, 0, 0); - mmio_list(0x4064c8, 0x01800600, 0, 0); - mmio_list(0x418810, 0x80000000, 12, 2); - mmio_list(0x419848, 0x10000000, 12, 2); - - mmio_list(0x405830, 0x02180648, 0, 0); - mmio_list(0x4064c4, 0x0192ffff, 0, 0); - - for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) { - u16 magic0 = 0x0218 * (priv->tpc_nr[gpc] - 1); - u16 magic1 = 0x0648 * (priv->tpc_nr[gpc] - 1); - u16 magic2 = 0x0218; - u16 magic3 = 0x0648; - magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset; - magic[gpc][1] = 0x00000000 | (magic1 << 16); - offset += 0x0324 * (priv->tpc_nr[gpc] - 1); - magic[gpc][2] = 0x10000000 | (magic2 << 16) | offset; - magic[gpc][3] = 0x00000000 | (magic3 << 16); - offset += 0x0324; - } - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0); - mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0); - offset += 0x07ff * (priv->tpc_nr[gpc] - 1); - mmio_list(GPC_UNIT(gpc, 0x32c0), magic[gpc][2], 0, 0); - mmio_list(GPC_UNIT(gpc, 0x32e4), magic[gpc][3] | offset, 0, 0); - offset += 0x07ff; - } - - mmio_list(0x17e91c, 0x06060609, 0, 0); - mmio_list(0x17e920, 0x00090a05, 0, 0); -} - struct nouveau_oclass * nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xf0), @@ -873,7 +821,6 @@ nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) { .wr32 = _nouveau_graph_context_wr32, }, .main = nve4_grctx_generate_main, - .mods = nvf0_grctx_generate_mods, .unkn = nve4_grctx_generate_unkn, .hub = nvf0_grctx_pack_hub, .gpc = nvf0_grctx_pack_gpc, @@ -882,4 +829,15 @@ nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) { .ppc = nvf0_grctx_pack_ppc, .icmd = nvf0_grctx_pack_icmd, .mthd = nvf0_grctx_pack_mthd, + .bundle = nve4_grctx_generate_bundle, + .bundle_size = 0x3000, + .bundle_min_gpm_fifo_depth = 0x180, + .bundle_token_limit = 0x7c0, + .pagepool = nve4_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = nvd7_grctx_generate_attrib, + .attrib_nr_max = 0x324, + .attrib_nr = 0x218, + .alpha_nr_max = 0x7ff, + .alpha_nr = 0x648, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c b/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c new file mode 100644 index 000000000000..d07b19dc168d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c @@ -0,0 +1,117 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#include "nvc0.h" +#include "ctxnvc0.h" + +/******************************************************************************* + * PGRAPH register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +gk110b_graph_init_l1c_0[] = { + { 0x419c98, 1, 0x04, 0x00000000 }, + { 0x419ca8, 1, 0x04, 0x00000000 }, + { 0x419cb0, 1, 0x04, 0x09000000 }, + { 0x419cb4, 1, 0x04, 0x00000000 }, + { 0x419cb8, 1, 0x04, 0x00b08bea }, + { 0x419c84, 1, 0x04, 0x00010384 }, + { 0x419cbc, 1, 0x04, 0x281b3646 }, + { 0x419cc0, 2, 0x04, 0x00000000 }, + { 0x419c80, 1, 0x04, 0x00020230 }, + { 0x419ccc, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gk110b_graph_init_sm_0[] = { + { 0x419e00, 1, 0x04, 0x00000080 }, + { 0x419ea0, 1, 0x04, 0x00000000 }, + { 0x419ee4, 1, 0x04, 0x00000000 }, + { 0x419ea4, 1, 0x04, 0x00000100 }, + { 0x419ea8, 1, 0x04, 0x00000000 }, + { 0x419eb4, 1, 0x04, 0x00000000 }, + { 0x419ebc, 2, 0x04, 0x00000000 }, + { 0x419edc, 1, 0x04, 0x00000000 }, + { 0x419f00, 1, 0x04, 0x00000000 }, + { 0x419ed0, 1, 0x04, 0x00002616 }, + { 0x419f74, 1, 0x04, 0x00015555 }, + { 0x419f80, 4, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gk110b_graph_pack_mmio[] = { + { nve4_graph_init_main_0 }, + { nvf0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nvf0_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvf0_graph_init_sked_0 }, + { nvf0_graph_init_cwd_0 }, + { nvd9_graph_init_prop_0 }, + { nvc1_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc1_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvd9_graph_init_gpm_0 }, + { nvf0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nve4_graph_init_tpccs_0 }, + { nvf0_graph_init_tex_0 }, + { nve4_graph_init_pe_0 }, + { gk110b_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { gk110b_graph_init_sm_0 }, + { nvd7_graph_init_pes_0 }, + { nvd7_graph_init_wwdx_0 }, + { nvd7_graph_init_cbm_0 }, + { nve4_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +struct nouveau_oclass * +gk110b_graph_oclass = &(struct nvc0_graph_oclass) { + .base.handle = NV_ENGINE(GR, 0xf1), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_ctor, + .dtor = nvc0_graph_dtor, + .init = nve4_graph_init, + .fini = nvf0_graph_fini, + }, + .cclass = &gk110b_grctx_oclass, + .sclass = nvf0_graph_sclass, + .mmio = gk110b_graph_pack_mmio, + .fecs.ucode = &nvf0_graph_fecs_ucode, + .gpccs.ucode = &nvf0_graph_gpccs_ucode, + .ppc_nr = 2, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c index 83048a56430d..7d0abe9f3fe7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c @@ -27,8 +27,8 @@ static struct nouveau_oclass gk20a_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0xa040, &nouveau_object_ofuncs }, - { 0xa297, &nouveau_object_ofuncs }, - { 0xa0c0, &nouveau_object_ofuncs }, + { KEPLER_C, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { KEPLER_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds }, {} }; @@ -39,9 +39,10 @@ gk20a_graph_oclass = &(struct nvc0_graph_oclass) { .ctor = nvc0_graph_ctor, .dtor = nvc0_graph_dtor, .init = nve4_graph_init, - .fini = nve4_graph_fini, + .fini = _nouveau_graph_fini, }, .cclass = &gk20a_grctx_oclass, .sclass = gk20a_graph_sclass, .mmio = nve4_graph_pack_mmio, + .ppc_nr = 1, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c index 21c5f31d607f..4bdbdab2fd9a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c @@ -36,8 +36,8 @@ static struct nouveau_oclass gm107_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0xa140, &nouveau_object_ofuncs }, - { 0xb097, &nouveau_object_ofuncs }, - { 0xb0c0, &nouveau_object_ofuncs }, + { MAXWELL_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { MAXWELL_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds }, {} }; @@ -425,6 +425,9 @@ gm107_graph_init(struct nouveau_object *object) nv_wr32(priv, 0x400134, 0xffffffff); nv_wr32(priv, 0x400054, 0x2c350f63); + + nvc0_graph_zbc_init(priv); + return nvc0_graph_init_ctxctl(priv); } @@ -462,4 +465,5 @@ gm107_graph_oclass = &(struct nvc0_graph_oclass) { .mmio = gm107_graph_pack_mmio, .fecs.ucode = 0 ? &gm107_graph_fecs_ucode : NULL, .gpccs.ucode = &gm107_graph_gpccs_ucode, + .ppc_nr = 2, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c index ad13dcdd15f9..f70e2f67a4dd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c @@ -24,7 +24,6 @@ #include <core/client.h> #include <core/os.h> -#include <core/class.h> #include <core/handle.h> #include <core/namedb.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c index 4532f7e5618c..2b12b09683c8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c @@ -24,7 +24,6 @@ #include <core/client.h> #include <core/os.h> -#include <core/class.h> #include <core/handle.h> #include <subdev/fb.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c index 00ea1a089822..2b0e8f48c029 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c @@ -33,7 +33,7 @@ static struct nouveau_oclass nv108_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0xa140, &nouveau_object_ofuncs }, - { 0xa197, &nouveau_object_ofuncs }, + { KEPLER_B, &nvc0_fermi_ofuncs }, { 0xa1c0, &nouveau_object_ofuncs }, {} }; @@ -220,4 +220,5 @@ nv108_graph_oclass = &(struct nvc0_graph_oclass) { .mmio = nv108_graph_pack_mmio, .fecs.ucode = &nv108_graph_fecs_ucode, .gpccs.ucode = &nv108_graph_gpccs_ucode, + .ppc_nr = 1, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c index d145e080899a..ceb9c746d94e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c @@ -1,6 +1,5 @@ #include <core/client.h> #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/handle.h> #include <core/enum.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c index 7a80d005a974..f8a6fdd7d5e8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c @@ -1,5 +1,4 @@ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/enum.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c index 3e1f32ee43d4..5de9caa2ef67 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c @@ -1,5 +1,4 @@ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/enum.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c index e451db32e92a..2f9dbc709389 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c @@ -1,5 +1,4 @@ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/enum.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c index 9385ac7b44a4..34dd26c70b64 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c @@ -1,5 +1,4 @@ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/enum.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c index 9ce84b73f86a..2fb5756d9f66 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c @@ -1,5 +1,4 @@ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/enum.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 6477fbf6a550..4f401174868d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -24,7 +24,6 @@ #include <core/client.h> #include <core/os.h> -#include <core/class.h> #include <core/handle.h> #include <core/engctx.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c index 20665c21d80e..38e0aa26f1cd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/client.h> #include <core/handle.h> #include <core/engctx.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index aa0838916354..30fd1dc64f93 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -26,15 +26,232 @@ #include "ctxnvc0.h" /******************************************************************************* + * Zero Bandwidth Clear + ******************************************************************************/ + +static void +nvc0_graph_zbc_clear_color(struct nvc0_graph_priv *priv, int zbc) +{ + if (priv->zbc_color[zbc].format) { + nv_wr32(priv, 0x405804, priv->zbc_color[zbc].ds[0]); + nv_wr32(priv, 0x405808, priv->zbc_color[zbc].ds[1]); + nv_wr32(priv, 0x40580c, priv->zbc_color[zbc].ds[2]); + nv_wr32(priv, 0x405810, priv->zbc_color[zbc].ds[3]); + } + nv_wr32(priv, 0x405814, priv->zbc_color[zbc].format); + nv_wr32(priv, 0x405820, zbc); + nv_wr32(priv, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ +} + +static int +nvc0_graph_zbc_color_get(struct nvc0_graph_priv *priv, int format, + const u32 ds[4], const u32 l2[4]) +{ + struct nouveau_ltc *ltc = nouveau_ltc(priv); + int zbc = -ENOSPC, i; + + for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + if (priv->zbc_color[i].format) { + if (priv->zbc_color[i].format != format) + continue; + if (memcmp(priv->zbc_color[i].ds, ds, sizeof( + priv->zbc_color[i].ds))) + continue; + if (memcmp(priv->zbc_color[i].l2, l2, sizeof( + priv->zbc_color[i].l2))) { + WARN_ON(1); + return -EINVAL; + } + return i; + } else { + zbc = (zbc < 0) ? i : zbc; + } + } + + if (zbc < 0) + return zbc; + + memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds)); + memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2)); + priv->zbc_color[zbc].format = format; + ltc->zbc_color_get(ltc, zbc, l2); + nvc0_graph_zbc_clear_color(priv, zbc); + return zbc; +} + +static void +nvc0_graph_zbc_clear_depth(struct nvc0_graph_priv *priv, int zbc) +{ + if (priv->zbc_depth[zbc].format) + nv_wr32(priv, 0x405818, priv->zbc_depth[zbc].ds); + nv_wr32(priv, 0x40581c, priv->zbc_depth[zbc].format); + nv_wr32(priv, 0x405820, zbc); + nv_wr32(priv, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ +} + +static int +nvc0_graph_zbc_depth_get(struct nvc0_graph_priv *priv, int format, + const u32 ds, const u32 l2) +{ + struct nouveau_ltc *ltc = nouveau_ltc(priv); + int zbc = -ENOSPC, i; + + for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + if (priv->zbc_depth[i].format) { + if (priv->zbc_depth[i].format != format) + continue; + if (priv->zbc_depth[i].ds != ds) + continue; + if (priv->zbc_depth[i].l2 != l2) { + WARN_ON(1); + return -EINVAL; + } + return i; + } else { + zbc = (zbc < 0) ? i : zbc; + } + } + + if (zbc < 0) + return zbc; + + priv->zbc_depth[zbc].format = format; + priv->zbc_depth[zbc].ds = ds; + priv->zbc_depth[zbc].l2 = l2; + ltc->zbc_depth_get(ltc, zbc, l2); + nvc0_graph_zbc_clear_depth(priv, zbc); + return zbc; +} + +/******************************************************************************* * Graphics object classes ******************************************************************************/ +static int +nvc0_fermi_mthd_zbc_color(struct nouveau_object *object, void *data, u32 size) +{ + struct nvc0_graph_priv *priv = (void *)object->engine; + union { + struct fermi_a_zbc_color_v0 v0; + } *args = data; + int ret; + + if (nvif_unpack(args->v0, 0, 0, false)) { + switch (args->v0.format) { + case FERMI_A_ZBC_COLOR_V0_FMT_ZERO: + case FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE: + case FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32: + case FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16: + case FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16: + case FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16: + case FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16: + case FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16: + case FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8: + case FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8: + case FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10: + case FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10: + case FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8: + case FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8: + case FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8: + case FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8: + case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8: + case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10: + case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11: + ret = nvc0_graph_zbc_color_get(priv, args->v0.format, + args->v0.ds, + args->v0.l2); + if (ret >= 0) { + args->v0.index = ret; + return 0; + } + break; + default: + return -EINVAL; + } + } + + return ret; +} + +static int +nvc0_fermi_mthd_zbc_depth(struct nouveau_object *object, void *data, u32 size) +{ + struct nvc0_graph_priv *priv = (void *)object->engine; + union { + struct fermi_a_zbc_depth_v0 v0; + } *args = data; + int ret; + + if (nvif_unpack(args->v0, 0, 0, false)) { + switch (args->v0.format) { + case FERMI_A_ZBC_DEPTH_V0_FMT_FP32: + ret = nvc0_graph_zbc_depth_get(priv, args->v0.format, + args->v0.ds, + args->v0.l2); + return (ret >= 0) ? 0 : -ENOSPC; + default: + return -EINVAL; + } + } + + return ret; +} + +static int +nvc0_fermi_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size) +{ + switch (mthd) { + case FERMI_A_ZBC_COLOR: + return nvc0_fermi_mthd_zbc_color(object, data, size); + case FERMI_A_ZBC_DEPTH: + return nvc0_fermi_mthd_zbc_depth(object, data, size); + default: + break; + } + return -EINVAL; +} + +struct nouveau_ofuncs +nvc0_fermi_ofuncs = { + .ctor = _nouveau_object_ctor, + .dtor = nouveau_object_destroy, + .init = nouveau_object_init, + .fini = nouveau_object_fini, + .mthd = nvc0_fermi_mthd, +}; + +static int +nvc0_graph_set_shader_exceptions(struct nouveau_object *object, u32 mthd, + void *pdata, u32 size) +{ + struct nvc0_graph_priv *priv = (void *)nv_engine(object); + if (size >= sizeof(u32)) { + u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000; + nv_wr32(priv, 0x419e44, data); + nv_wr32(priv, 0x419e4c, data); + return 0; + } + return -EINVAL; +} + +struct nouveau_omthds +nvc0_graph_9097_omthds[] = { + { 0x1528, 0x1528, nvc0_graph_set_shader_exceptions }, + {} +}; + +struct nouveau_omthds +nvc0_graph_90c0_omthds[] = { + { 0x1528, 0x1528, nvc0_graph_set_shader_exceptions }, + {} +}; + struct nouveau_oclass nvc0_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0x9039, &nouveau_object_ofuncs }, - { 0x9097, &nouveau_object_ofuncs }, - { 0x90c0, &nouveau_object_ofuncs }, + { FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds }, {} }; @@ -98,7 +315,7 @@ nvc0_graph_context_ctor(struct nouveau_object *parent, u32 addr = mmio->addr; u32 data = mmio->data; - if (mmio->shift) { + if (mmio->buffer >= 0) { u64 info = chan->data[mmio->buffer].vma.offset; data |= info >> mmio->shift; } @@ -407,6 +624,35 @@ nvc0_graph_pack_mmio[] = { ******************************************************************************/ void +nvc0_graph_zbc_init(struct nvc0_graph_priv *priv) +{ + const u32 zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + const u32 one[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; + const u32 f32_0[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, + 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; + struct nouveau_ltc *ltc = nouveau_ltc(priv); + int index; + + if (!priv->zbc_color[0].format) { + nvc0_graph_zbc_color_get(priv, 1, & zero[0], &zero[4]); + nvc0_graph_zbc_color_get(priv, 2, & one[0], &one[4]); + nvc0_graph_zbc_color_get(priv, 4, &f32_0[0], &f32_0[4]); + nvc0_graph_zbc_color_get(priv, 4, &f32_1[0], &f32_1[4]); + nvc0_graph_zbc_depth_get(priv, 1, 0x00000000, 0x00000000); + nvc0_graph_zbc_depth_get(priv, 1, 0x3f800000, 0x3f800000); + } + + for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) + nvc0_graph_zbc_clear_color(priv, index); + for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) + nvc0_graph_zbc_clear_depth(priv, index); +} + +void nvc0_graph_mmio(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p) { const struct nvc0_graph_pack *pack; @@ -969,17 +1215,16 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) { struct nvc0_graph_oclass *oclass = (void *)nv_object(priv)->oclass; struct nvc0_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass; - u32 r000260; int i; if (priv->firmware) { /* load fuc microcode */ - r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 0); nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d); nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad); - nv_wr32(priv, 0x000260, r000260); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 1); /* start both of them running */ nv_wr32(priv, 0x409840, 0xffffffff); @@ -1066,7 +1311,7 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) } /* load HUB microcode */ - r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 0); nv_wr32(priv, 0x4091c0, 0x01000000); for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++) nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]); @@ -1089,7 +1334,7 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) nv_wr32(priv, 0x41a188, i >> 6); nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]); } - nv_wr32(priv, 0x000260, r000260); + nouveau_mc(priv)->unk260(nouveau_mc(priv), 1); /* load register lists */ nvc0_graph_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000); @@ -1224,6 +1469,9 @@ nvc0_graph_init(struct nouveau_object *object) nv_wr32(priv, 0x400134, 0xffffffff); nv_wr32(priv, 0x400054, 0x34ce3464); + + nvc0_graph_zbc_init(priv); + return nvc0_graph_init_ctxctl(priv); } @@ -1287,7 +1535,7 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_device *device = nv_device(parent); struct nvc0_graph_priv *priv; bool use_ext_fw, enable; - int ret, i; + int ret, i, j; use_ext_fw = nouveau_boolopt(device->cfgopt, "NvGrUseFW", oclass->fecs.ucode == NULL); @@ -1333,6 +1581,11 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, for (i = 0; i < priv->gpc_nr; i++) { priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608)); priv->tpc_total += priv->tpc_nr[i]; + priv->ppc_nr[i] = oclass->ppc_nr; + for (j = 0; j < priv->ppc_nr[i]; j++) { + u8 mask = nv_rd32(priv, GPC_UNIT(i, 0x0c30 + (j * 4))); + priv->ppc_tpc_nr[i][j] = hweight8(mask); + } } /*XXX: these need figuring out... though it might not even matter */ diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h index ffc289198dd8..7ed9e89c3435 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h @@ -30,10 +30,15 @@ #include <core/gpuobj.h> #include <core/option.h> +#include <nvif/unpack.h> +#include <nvif/class.h> + #include <subdev/fb.h> #include <subdev/vm.h> #include <subdev/bar.h> #include <subdev/timer.h> +#include <subdev/mc.h> +#include <subdev/ltc.h> #include <engine/fifo.h> #include <engine/graph.h> @@ -60,7 +65,7 @@ struct nvc0_graph_mmio { u32 addr; u32 data; u32 shift; - u32 buffer; + int buffer; }; struct nvc0_graph_fuc { @@ -68,6 +73,18 @@ struct nvc0_graph_fuc { u32 size; }; +struct nvc0_graph_zbc_color { + u32 format; + u32 ds[4]; + u32 l2[4]; +}; + +struct nvc0_graph_zbc_depth { + u32 format; + u32 ds; + u32 l2; +}; + struct nvc0_graph_priv { struct nouveau_graph base; @@ -77,10 +94,15 @@ struct nvc0_graph_priv { struct nvc0_graph_fuc fuc41ad; bool firmware; + struct nvc0_graph_zbc_color zbc_color[NOUVEAU_LTC_MAX_ZBC_CNT]; + struct nvc0_graph_zbc_depth zbc_depth[NOUVEAU_LTC_MAX_ZBC_CNT]; + u8 rop_nr; u8 gpc_nr; u8 tpc_nr[GPC_MAX]; u8 tpc_total; + u8 ppc_nr[GPC_MAX]; + u8 ppc_tpc_nr[GPC_MAX][4]; struct nouveau_gpuobj *unk4188b4; struct nouveau_gpuobj *unk4188b8; @@ -118,12 +140,20 @@ int nvc0_graph_ctor(struct nouveau_object *, struct nouveau_object *, struct nouveau_object **); void nvc0_graph_dtor(struct nouveau_object *); int nvc0_graph_init(struct nouveau_object *); +void nvc0_graph_zbc_init(struct nvc0_graph_priv *); + int nve4_graph_fini(struct nouveau_object *, bool); int nve4_graph_init(struct nouveau_object *); -extern struct nouveau_oclass nvc0_graph_sclass[]; +int nvf0_graph_fini(struct nouveau_object *, bool); + +extern struct nouveau_ofuncs nvc0_fermi_ofuncs; +extern struct nouveau_oclass nvc0_graph_sclass[]; +extern struct nouveau_omthds nvc0_graph_9097_omthds[]; +extern struct nouveau_omthds nvc0_graph_90c0_omthds[]; extern struct nouveau_oclass nvc8_graph_sclass[]; +extern struct nouveau_oclass nvf0_graph_sclass[]; struct nvc0_graph_init { u32 addr; @@ -149,6 +179,9 @@ struct nvc0_graph_ucode { extern struct nvc0_graph_ucode nvc0_graph_fecs_ucode; extern struct nvc0_graph_ucode nvc0_graph_gpccs_ucode; +extern struct nvc0_graph_ucode nvf0_graph_fecs_ucode; +extern struct nvc0_graph_ucode nvf0_graph_gpccs_ucode; + struct nvc0_graph_oclass { struct nouveau_oclass base; struct nouveau_oclass **cclass; @@ -160,6 +193,7 @@ struct nvc0_graph_oclass { struct { struct nvc0_graph_ucode *ucode; } gpccs; + int ppc_nr; }; void nvc0_graph_mmio(struct nvc0_graph_priv *, const struct nvc0_graph_pack *); @@ -223,9 +257,11 @@ extern const struct nvc0_graph_init nve4_graph_init_be_0[]; extern const struct nvc0_graph_pack nve4_graph_pack_mmio[]; extern const struct nvc0_graph_init nvf0_graph_init_fe_0[]; +extern const struct nvc0_graph_init nvf0_graph_init_ds_0[]; extern const struct nvc0_graph_init nvf0_graph_init_sked_0[]; extern const struct nvc0_graph_init nvf0_graph_init_cwd_0[]; extern const struct nvc0_graph_init nvf0_graph_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvf0_graph_init_tex_0[]; extern const struct nvc0_graph_init nvf0_graph_init_sm_0[]; extern const struct nvc0_graph_init nv108_graph_init_gpc_unk_0[]; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c index 30cab0b2eba1..93d58e5b82c2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c @@ -33,9 +33,9 @@ static struct nouveau_oclass nvc1_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0x9039, &nouveau_object_ofuncs }, - { 0x9097, &nouveau_object_ofuncs }, - { 0x90c0, &nouveau_object_ofuncs }, - { 0x9197, &nouveau_object_ofuncs }, + { FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { FERMI_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c index a6bf783e1256..692e1eda0eb4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c @@ -33,10 +33,10 @@ struct nouveau_oclass nvc8_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0x9039, &nouveau_object_ofuncs }, - { 0x9097, &nouveau_object_ofuncs }, - { 0x90c0, &nouveau_object_ofuncs }, - { 0x9197, &nouveau_object_ofuncs }, - { 0x9297, &nouveau_object_ofuncs }, + { FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { FERMI_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { FERMI_C, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c index 2a6a94e2a041..41e8445c7eea 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c @@ -133,4 +133,5 @@ nvd7_graph_oclass = &(struct nvc0_graph_oclass) { .mmio = nvd7_graph_pack_mmio, .fecs.ucode = &nvd7_graph_fecs_ucode, .gpccs.ucode = &nvd7_graph_gpccs_ucode, + .ppc_nr = 1, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c index 51e0c075ad34..0c71f5c67ae0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c @@ -22,6 +22,8 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ +#include <subdev/pwr.h> + #include "nvc0.h" #include "ctxnvc0.h" @@ -33,8 +35,8 @@ static struct nouveau_oclass nve4_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0xa040, &nouveau_object_ofuncs }, - { 0xa097, &nouveau_object_ofuncs }, - { 0xa0c0, &nouveau_object_ofuncs }, + { KEPLER_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { KEPLER_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds }, {} }; @@ -190,39 +192,20 @@ nve4_graph_pack_mmio[] = { ******************************************************************************/ int -nve4_graph_fini(struct nouveau_object *object, bool suspend) -{ - struct nvc0_graph_priv *priv = (void *)object; - - /*XXX: this is a nasty hack to power on gr on certain boards - * where it's disabled by therm, somehow. ideally it'd - * be nice to know when we should be doing this, and why, - * but, it's yet to be determined. for now we test for - * the particular mmio error that occurs in the situation, - * and then bash therm in the way nvidia do. - */ - nv_mask(priv, 0x000200, 0x08001000, 0x08001000); - nv_rd32(priv, 0x000200); - if (nv_rd32(priv, 0x400700) == 0xbadf1000) { - nv_mask(priv, 0x000200, 0x08001000, 0x00000000); - nv_rd32(priv, 0x000200); - nv_mask(priv, 0x020004, 0xc0000000, 0x40000000); - } - - return nouveau_graph_fini(&priv->base, suspend); -} - -int nve4_graph_init(struct nouveau_object *object) { struct nvc0_graph_oclass *oclass = (void *)object->oclass; struct nvc0_graph_priv *priv = (void *)object; + struct nouveau_pwr *ppwr = nouveau_pwr(priv); const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, rop; int ret, i; + if (ppwr) + ppwr->pgob(ppwr, false); + ret = nouveau_graph_init(&priv->base); if (ret) return ret; @@ -320,6 +303,9 @@ nve4_graph_init(struct nouveau_object *object) nv_wr32(priv, 0x400134, 0xffffffff); nv_wr32(priv, 0x400054, 0x34ce3464); + + nvc0_graph_zbc_init(priv); + return nvc0_graph_init_ctxctl(priv); } @@ -350,11 +336,12 @@ nve4_graph_oclass = &(struct nvc0_graph_oclass) { .ctor = nvc0_graph_ctor, .dtor = nvc0_graph_dtor, .init = nve4_graph_init, - .fini = nve4_graph_fini, + .fini = _nouveau_graph_fini, }, .cclass = &nve4_grctx_oclass, .sclass = nve4_graph_sclass, .mmio = nve4_graph_pack_mmio, .fecs.ucode = &nve4_graph_fecs_ucode, .gpccs.ucode = &nve4_graph_gpccs_ucode, + .ppc_nr = 1, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c index c96762122b9b..c306c0f2fc84 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c @@ -29,12 +29,12 @@ * Graphics object classes ******************************************************************************/ -static struct nouveau_oclass +struct nouveau_oclass nvf0_graph_sclass[] = { { 0x902d, &nouveau_object_ofuncs }, { 0xa140, &nouveau_object_ofuncs }, - { 0xa197, &nouveau_object_ofuncs }, - { 0xa1c0, &nouveau_object_ofuncs }, + { KEPLER_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds }, + { KEPLER_COMPUTE_B, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds }, {} }; @@ -50,7 +50,7 @@ nvf0_graph_init_fe_0[] = { {} }; -static const struct nvc0_graph_init +const struct nvc0_graph_init nvf0_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, @@ -88,7 +88,7 @@ nvf0_graph_init_gpc_unk_1[] = { {} }; -static const struct nvc0_graph_init +const struct nvc0_graph_init nvf0_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, @@ -170,7 +170,7 @@ nvf0_graph_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ -static int +int nvf0_graph_fini(struct nouveau_object *object, bool suspend) { struct nvc0_graph_priv *priv = (void *)object; @@ -209,7 +209,7 @@ nvf0_graph_fini(struct nouveau_object *object, bool suspend) #include "fuc/hubnvf0.fuc.h" -static struct nvc0_graph_ucode +struct nvc0_graph_ucode nvf0_graph_fecs_ucode = { .code.data = nvf0_grhub_code, .code.size = sizeof(nvf0_grhub_code), @@ -219,7 +219,7 @@ nvf0_graph_fecs_ucode = { #include "fuc/gpcnvf0.fuc.h" -static struct nvc0_graph_ucode +struct nvc0_graph_ucode nvf0_graph_gpccs_ucode = { .code.data = nvf0_grgpc_code, .code.size = sizeof(nvf0_grgpc_code), @@ -241,4 +241,5 @@ nvf0_graph_oclass = &(struct nvc0_graph_oclass) { .mmio = nvf0_graph_pack_mmio, .fecs.ucode = &nvf0_graph_fecs_ucode, .gpccs.ucode = &nvf0_graph_gpccs_ucode, + .ppc_nr = 2, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c index 7eb6d94c84e2..d88c700b2f69 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c @@ -24,7 +24,6 @@ #include <core/client.h> #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/handle.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c index d4e7ec0ba68c..bdb2f20ff7b1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <subdev/fb.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c index 3d8c2133e0e8..72c7f33fd29b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/client.h> #include <core/engctx.h> #include <core/handle.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c index 37a2bd9e8078..cae33f86b11a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <subdev/vm.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c index 96f5aa92677b..e9cc8b116a24 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <subdev/vm.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c index e9c5e51943ef..63013812f7c9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c @@ -22,8 +22,11 @@ * Authors: Ben Skeggs */ +#include <core/client.h> #include <core/option.h> -#include <core/class.h> +#include <nvif/unpack.h> +#include <nvif/class.h> +#include <nvif/ioctl.h> #include <subdev/clock.h> @@ -101,24 +104,28 @@ nouveau_perfsig_wrap(struct nouveau_perfmon *ppm, const char *name, * Perfmon object classes ******************************************************************************/ static int -nouveau_perfctr_query(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nouveau_perfctr_query(struct nouveau_object *object, void *data, u32 size) { + union { + struct nvif_perfctr_query_v0 v0; + } *args = data; struct nouveau_device *device = nv_device(object); struct nouveau_perfmon *ppm = (void *)object->engine; struct nouveau_perfdom *dom = NULL, *chk; - struct nv_perfctr_query *args = data; const bool all = nouveau_boolopt(device->cfgopt, "NvPmShowAll", false); const bool raw = nouveau_boolopt(device->cfgopt, "NvPmUnnamed", all); const char *name; int tmp = 0, di, si; - char path[64]; - - if (size < sizeof(*args)) - return -EINVAL; + int ret; - di = (args->iter & 0xff000000) >> 24; - si = (args->iter & 0x00ffffff) - 1; + nv_ioctl(object, "perfctr query size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "perfctr query vers %d iter %08x\n", + args->v0.version, args->v0.iter); + di = (args->v0.iter & 0xff000000) >> 24; + si = (args->v0.iter & 0x00ffffff) - 1; + } else + return ret; list_for_each_entry(chk, &ppm->domains, head) { if (tmp++ == di) { @@ -132,19 +139,17 @@ nouveau_perfctr_query(struct nouveau_object *object, u32 mthd, if (si >= 0) { if (raw || !(name = dom->signal[si].name)) { - snprintf(path, sizeof(path), "/%s/%02x", dom->name, si); - name = path; + snprintf(args->v0.name, sizeof(args->v0.name), + "/%s/%02x", dom->name, si); + } else { + strncpy(args->v0.name, name, sizeof(args->v0.name)); } - - if (args->name) - strncpy(args->name, name, args->size); - args->size = strlen(name) + 1; } do { while (++si < dom->signal_nr) { if (all || dom->signal[si].name) { - args->iter = (di << 24) | ++si; + args->v0.iter = (di << 24) | ++si; return 0; } } @@ -153,21 +158,26 @@ nouveau_perfctr_query(struct nouveau_object *object, u32 mthd, dom = list_entry(dom->head.next, typeof(*dom), head); } while (&dom->head != &ppm->domains); - args->iter = 0xffffffff; + args->v0.iter = 0xffffffff; return 0; } static int -nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nouveau_perfctr_sample(struct nouveau_object *object, void *data, u32 size) { + union { + struct nvif_perfctr_sample none; + } *args = data; struct nouveau_perfmon *ppm = (void *)object->engine; struct nouveau_perfctr *ctr, *tmp; struct nouveau_perfdom *dom; - struct nv_perfctr_sample *args = data; + int ret; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(object, "perfctr sample size %d\n", size); + if (nvif_unvers(args->none)) { + nv_ioctl(object, "perfctr sample\n"); + } else + return ret; ppm->sequence++; list_for_each_entry(dom, &ppm->domains, head) { @@ -206,22 +216,45 @@ nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd, } static int -nouveau_perfctr_read(struct nouveau_object *object, u32 mthd, - void *data, u32 size) +nouveau_perfctr_read(struct nouveau_object *object, void *data, u32 size) { + union { + struct nvif_perfctr_read_v0 v0; + } *args = data; struct nouveau_perfctr *ctr = (void *)object; - struct nv_perfctr_read *args = data; + int ret; + + nv_ioctl(object, "perfctr read size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "perfctr read vers %d\n", args->v0.version); + } else + return ret; - if (size < sizeof(*args)) - return -EINVAL; if (!ctr->clk) return -EAGAIN; - args->clk = ctr->clk; - args->ctr = ctr->ctr; + args->v0.clk = ctr->clk; + args->v0.ctr = ctr->ctr; return 0; } +static int +nouveau_perfctr_mthd(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + switch (mthd) { + case NVIF_PERFCTR_V0_QUERY: + return nouveau_perfctr_query(object, data, size); + case NVIF_PERFCTR_V0_SAMPLE: + return nouveau_perfctr_sample(object, data, size); + case NVIF_PERFCTR_V0_READ: + return nouveau_perfctr_read(object, data, size); + default: + break; + } + return -EINVAL; +} + static void nouveau_perfctr_dtor(struct nouveau_object *object) { @@ -237,19 +270,27 @@ nouveau_perfctr_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + union { + struct nvif_perfctr_v0 v0; + } *args = data; struct nouveau_perfmon *ppm = (void *)engine; struct nouveau_perfdom *dom = NULL; struct nouveau_perfsig *sig[4] = {}; struct nouveau_perfctr *ctr; - struct nv_perfctr_class *args = data; int ret, i; - if (size < sizeof(*args)) - return -EINVAL; + nv_ioctl(parent, "create perfctr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n", + args->v0.version, args->v0.logic_op); + } else + return ret; - for (i = 0; i < ARRAY_SIZE(args->signal) && args->signal[i].name; i++) { - sig[i] = nouveau_perfsig_find(ppm, args->signal[i].name, - args->signal[i].size, &dom); + for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) { + sig[i] = nouveau_perfsig_find(ppm, args->v0.name[i], + strnlen(args->v0.name[i], + sizeof(args->v0.name[i])), + &dom); if (!sig[i]) return -EINVAL; } @@ -260,7 +301,7 @@ nouveau_perfctr_ctor(struct nouveau_object *parent, return ret; ctr->slot = -1; - ctr->logic_op = args->logic_op; + ctr->logic_op = args->v0.logic_op; ctr->signal[0] = sig[0]; ctr->signal[1] = sig[1]; ctr->signal[2] = sig[2]; @@ -276,21 +317,13 @@ nouveau_perfctr_ofuncs = { .dtor = nouveau_perfctr_dtor, .init = nouveau_object_init, .fini = nouveau_object_fini, -}; - -static struct nouveau_omthds -nouveau_perfctr_omthds[] = { - { NV_PERFCTR_QUERY, NV_PERFCTR_QUERY, nouveau_perfctr_query }, - { NV_PERFCTR_SAMPLE, NV_PERFCTR_SAMPLE, nouveau_perfctr_sample }, - { NV_PERFCTR_READ, NV_PERFCTR_READ, nouveau_perfctr_read }, - {} + .mthd = nouveau_perfctr_mthd, }; struct nouveau_oclass nouveau_perfmon_sclass[] = { - { .handle = NV_PERFCTR_CLASS, + { .handle = NVIF_IOCTL_NEW_V0_PERFCTR, .ofuncs = &nouveau_perfctr_ofuncs, - .omthds = nouveau_perfctr_omthds, }, {}, }; @@ -303,6 +336,7 @@ nouveau_perfctx_dtor(struct nouveau_object *object) { struct nouveau_perfmon *ppm = (void *)object->engine; mutex_lock(&nv_subdev(ppm)->mutex); + nouveau_engctx_destroy(&ppm->context->base); ppm->context = NULL; mutex_unlock(&nv_subdev(ppm)->mutex); } diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c index c571758e4a27..64df15c7f051 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <engine/software.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c index a62f11a78430..f54a2253deca 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <engine/software.h> diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c index f3b4d9dbf23c..a0fec205f9db 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c @@ -23,12 +23,12 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/namedb.h> #include <core/handle.h> #include <core/gpuobj.h> #include <core/event.h> +#include <nvif/event.h> #include <subdev/bar.h> @@ -86,10 +86,10 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, { struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); u32 head = *(u32 *)args; - if (head >= chan->vblank.nr_event) + if (head >= nouveau_disp(chan)->vblank.index_nr) return -EINVAL; - nouveau_event_get(chan->vblank.event[head]); + nvkm_notify_get(&chan->vblank.notify[head]); return 0; } @@ -124,9 +124,10 @@ nv50_software_sclass[] = { ******************************************************************************/ static int -nv50_software_vblsem_release(void *data, u32 type, int head) +nv50_software_vblsem_release(struct nvkm_notify *notify) { - struct nv50_software_chan *chan = data; + struct nv50_software_chan *chan = + container_of(notify, typeof(*chan), vblank.notify[notify->index]); struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nouveau_bar *bar = nouveau_bar(priv); @@ -142,7 +143,7 @@ nv50_software_vblsem_release(void *data, u32 type, int head) nv_wr32(priv, 0x060014, chan->vblank.value); } - return NVKM_EVENT_DROP; + return NVKM_NOTIFY_DROP; } void @@ -151,11 +152,8 @@ nv50_software_context_dtor(struct nouveau_object *object) struct nv50_software_chan *chan = (void *)object; int i; - if (chan->vblank.event) { - for (i = 0; i < chan->vblank.nr_event; i++) - nouveau_event_ref(NULL, &chan->vblank.event[i]); - kfree(chan->vblank.event); - } + for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++) + nvkm_notify_fini(&chan->vblank.notify[i]); nouveau_software_context_destroy(&chan->base); } @@ -176,15 +174,15 @@ nv50_software_context_ctor(struct nouveau_object *parent, if (ret) return ret; - chan->vblank.nr_event = pdisp ? pdisp->vblank->index_nr : 0; - chan->vblank.event = kzalloc(chan->vblank.nr_event * - sizeof(*chan->vblank.event), GFP_KERNEL); - if (!chan->vblank.event) - return -ENOMEM; - - for (i = 0; i < chan->vblank.nr_event; i++) { - ret = nouveau_event_new(pdisp->vblank, 1, i, pclass->vblank, - chan, &chan->vblank.event[i]); + for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) { + ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank, + false, + &(struct nvif_notify_head_req_v0) { + .head = i, + }, + sizeof(struct nvif_notify_head_req_v0), + sizeof(struct nvif_notify_head_rep_v0), + &chan->vblank.notify[i]); if (ret) return ret; } @@ -198,7 +196,7 @@ nv50_software_cclass = { .base.handle = NV_ENGCTX(SW, 0x50), .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_software_context_ctor, - .dtor = _nouveau_software_context_dtor, + .dtor = nv50_software_context_dtor, .init = _nouveau_software_context_init, .fini = _nouveau_software_context_fini, }, diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h index bb49a7a20857..41542e725b4b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h @@ -19,14 +19,13 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *, struct nv50_software_cclass { struct nouveau_oclass base; - int (*vblank)(void *, u32, int); + int (*vblank)(struct nvkm_notify *); }; struct nv50_software_chan { struct nouveau_software_chan base; struct { - struct nouveau_eventh **event; - int nr_event; + struct nvkm_notify notify[4]; u32 channel; u32 ctxdma; u64 offset; diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c index 135c20f38356..6af370d3a06d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c @@ -23,7 +23,6 @@ */ #include <core/os.h> -#include <core/class.h> #include <core/engctx.h> #include <core/event.h> @@ -104,9 +103,10 @@ nvc0_software_sclass[] = { ******************************************************************************/ static int -nvc0_software_vblsem_release(void *data, u32 type, int head) +nvc0_software_vblsem_release(struct nvkm_notify *notify) { - struct nv50_software_chan *chan = data; + struct nv50_software_chan *chan = + container_of(notify, typeof(*chan), vblank.notify[notify->index]); struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nouveau_bar *bar = nouveau_bar(priv); @@ -116,7 +116,7 @@ nvc0_software_vblsem_release(void *data, u32 type, int head) nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); nv_wr32(priv, 0x060014, chan->vblank.value); - return NVKM_EVENT_DROP; + return NVKM_NOTIFY_DROP; } static struct nv50_software_cclass @@ -124,7 +124,7 @@ nvc0_software_cclass = { .base.handle = NV_ENGCTX(SW, 0xc0), .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_software_context_ctor, - .dtor = _nouveau_software_context_dtor, + .dtor = nv50_software_context_dtor, .init = _nouveau_software_context_init, .fini = _nouveau_software_context_fini, }, diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h deleted file mode 100644 index e0c812bc884f..000000000000 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ /dev/null @@ -1,470 +0,0 @@ -#ifndef __NOUVEAU_CLASS_H__ -#define __NOUVEAU_CLASS_H__ - -/* Device class - * - * 0080: NV_DEVICE - */ -#define NV_DEVICE_CLASS 0x00000080 - -#define NV_DEVICE_DISABLE_IDENTIFY 0x0000000000000001ULL -#define NV_DEVICE_DISABLE_MMIO 0x0000000000000002ULL -#define NV_DEVICE_DISABLE_VBIOS 0x0000000000000004ULL -#define NV_DEVICE_DISABLE_CORE 0x0000000000000008ULL -#define NV_DEVICE_DISABLE_DISP 0x0000000000010000ULL -#define NV_DEVICE_DISABLE_FIFO 0x0000000000020000ULL -#define NV_DEVICE_DISABLE_GRAPH 0x0000000100000000ULL -#define NV_DEVICE_DISABLE_MPEG 0x0000000200000000ULL -#define NV_DEVICE_DISABLE_ME 0x0000000400000000ULL -#define NV_DEVICE_DISABLE_VP 0x0000000800000000ULL -#define NV_DEVICE_DISABLE_CRYPT 0x0000001000000000ULL -#define NV_DEVICE_DISABLE_BSP 0x0000002000000000ULL -#define NV_DEVICE_DISABLE_PPP 0x0000004000000000ULL -#define NV_DEVICE_DISABLE_COPY0 0x0000008000000000ULL -#define NV_DEVICE_DISABLE_COPY1 0x0000010000000000ULL -#define NV_DEVICE_DISABLE_VIC 0x0000020000000000ULL -#define NV_DEVICE_DISABLE_VENC 0x0000040000000000ULL - -struct nv_device_class { - u64 device; /* device identifier, ~0 for client default */ - u64 disable; /* disable particular subsystems */ - u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */ -}; - -/* DMA object classes - * - * 0002: NV_DMA_FROM_MEMORY - * 0003: NV_DMA_TO_MEMORY - * 003d: NV_DMA_IN_MEMORY - */ -#define NV_DMA_FROM_MEMORY_CLASS 0x00000002 -#define NV_DMA_TO_MEMORY_CLASS 0x00000003 -#define NV_DMA_IN_MEMORY_CLASS 0x0000003d - -#define NV_DMA_TARGET_MASK 0x000000ff -#define NV_DMA_TARGET_VM 0x00000000 -#define NV_DMA_TARGET_VRAM 0x00000001 -#define NV_DMA_TARGET_PCI 0x00000002 -#define NV_DMA_TARGET_PCI_US 0x00000003 -#define NV_DMA_TARGET_AGP 0x00000004 -#define NV_DMA_ACCESS_MASK 0x00000f00 -#define NV_DMA_ACCESS_VM 0x00000000 -#define NV_DMA_ACCESS_RD 0x00000100 -#define NV_DMA_ACCESS_WR 0x00000200 -#define NV_DMA_ACCESS_RDWR 0x00000300 - -/* NV50:NVC0 */ -#define NV50_DMA_CONF0_ENABLE 0x80000000 -#define NV50_DMA_CONF0_PRIV 0x00300000 -#define NV50_DMA_CONF0_PRIV_VM 0x00000000 -#define NV50_DMA_CONF0_PRIV_US 0x00100000 -#define NV50_DMA_CONF0_PRIV__S 0x00200000 -#define NV50_DMA_CONF0_PART 0x00030000 -#define NV50_DMA_CONF0_PART_VM 0x00000000 -#define NV50_DMA_CONF0_PART_256 0x00010000 -#define NV50_DMA_CONF0_PART_1KB 0x00020000 -#define NV50_DMA_CONF0_COMP 0x00000180 -#define NV50_DMA_CONF0_COMP_NONE 0x00000000 -#define NV50_DMA_CONF0_COMP_VM 0x00000180 -#define NV50_DMA_CONF0_TYPE 0x0000007f -#define NV50_DMA_CONF0_TYPE_LINEAR 0x00000000 -#define NV50_DMA_CONF0_TYPE_VM 0x0000007f - -/* NVC0:NVD9 */ -#define NVC0_DMA_CONF0_ENABLE 0x80000000 -#define NVC0_DMA_CONF0_PRIV 0x00300000 -#define NVC0_DMA_CONF0_PRIV_VM 0x00000000 -#define NVC0_DMA_CONF0_PRIV_US 0x00100000 -#define NVC0_DMA_CONF0_PRIV__S 0x00200000 -#define NVC0_DMA_CONF0_UNKN /* PART? */ 0x00030000 -#define NVC0_DMA_CONF0_TYPE 0x000000ff -#define NVC0_DMA_CONF0_TYPE_LINEAR 0x00000000 -#define NVC0_DMA_CONF0_TYPE_VM 0x000000ff - -/* NVD9- */ -#define NVD0_DMA_CONF0_ENABLE 0x80000000 -#define NVD0_DMA_CONF0_PAGE 0x00000400 -#define NVD0_DMA_CONF0_PAGE_LP 0x00000000 -#define NVD0_DMA_CONF0_PAGE_SP 0x00000400 -#define NVD0_DMA_CONF0_TYPE 0x000000ff -#define NVD0_DMA_CONF0_TYPE_LINEAR 0x00000000 -#define NVD0_DMA_CONF0_TYPE_VM 0x000000ff - -struct nv_dma_class { - u32 flags; - u32 pad0; - u64 start; - u64 limit; - u32 conf0; -}; - -/* Perfmon counter class - * - * XXXX: NV_PERFCTR - */ -#define NV_PERFCTR_CLASS 0x0000ffff -#define NV_PERFCTR_QUERY 0x00000000 -#define NV_PERFCTR_SAMPLE 0x00000001 -#define NV_PERFCTR_READ 0x00000002 - -struct nv_perfctr_class { - u16 logic_op; - struct { - char __user *name; /*XXX: use cfu when exposed to userspace */ - u32 size; - } signal[4]; -}; - -struct nv_perfctr_query { - u32 iter; - u32 size; - char __user *name; /*XXX: use ctu when exposed to userspace */ -}; - -struct nv_perfctr_sample { -}; - -struct nv_perfctr_read { - u32 ctr; - u32 clk; -}; - -/* Device control class - * - * XXXX: NV_CONTROL - */ -#define NV_CONTROL_CLASS 0x0000fffe - -#define NV_CONTROL_PSTATE_INFO 0x00000000 -#define NV_CONTROL_PSTATE_INFO_USTATE_DISABLE (-1) -#define NV_CONTROL_PSTATE_INFO_USTATE_PERFMON (-2) -#define NV_CONTROL_PSTATE_INFO_PSTATE_UNKNOWN (-1) -#define NV_CONTROL_PSTATE_INFO_PSTATE_PERFMON (-2) -#define NV_CONTROL_PSTATE_ATTR 0x00000001 -#define NV_CONTROL_PSTATE_ATTR_STATE_CURRENT (-1) -#define NV_CONTROL_PSTATE_USER 0x00000002 -#define NV_CONTROL_PSTATE_USER_STATE_UNKNOWN (-1) -#define NV_CONTROL_PSTATE_USER_STATE_PERFMON (-2) - -struct nv_control_pstate_info { - u32 count; /* out: number of power states */ - s32 ustate; /* out: current target pstate index */ - u32 pstate; /* out: current pstate index */ -}; - -struct nv_control_pstate_attr { - s32 state; /* in: index of pstate to query - * out: pstate identifier - */ - u32 index; /* in: index of attribute to query - * out: index of next attribute, or 0 if no more - */ - char name[32]; - char unit[16]; - u32 min; - u32 max; -}; - -struct nv_control_pstate_user { - s32 state; /* in: pstate identifier */ -}; - -/* DMA FIFO channel classes - * - * 006b: NV03_CHANNEL_DMA - * 006e: NV10_CHANNEL_DMA - * 176e: NV17_CHANNEL_DMA - * 406e: NV40_CHANNEL_DMA - * 506e: NV50_CHANNEL_DMA - * 826e: NV84_CHANNEL_DMA - */ -#define NV03_CHANNEL_DMA_CLASS 0x0000006b -#define NV10_CHANNEL_DMA_CLASS 0x0000006e -#define NV17_CHANNEL_DMA_CLASS 0x0000176e -#define NV40_CHANNEL_DMA_CLASS 0x0000406e -#define NV50_CHANNEL_DMA_CLASS 0x0000506e -#define NV84_CHANNEL_DMA_CLASS 0x0000826e - -struct nv03_channel_dma_class { - u32 pushbuf; - u32 pad0; - u64 offset; -}; - -/* Indirect FIFO channel classes - * - * 506f: NV50_CHANNEL_IND - * 826f: NV84_CHANNEL_IND - * 906f: NVC0_CHANNEL_IND - * a06f: NVE0_CHANNEL_IND - */ - -#define NV50_CHANNEL_IND_CLASS 0x0000506f -#define NV84_CHANNEL_IND_CLASS 0x0000826f -#define NVC0_CHANNEL_IND_CLASS 0x0000906f -#define NVE0_CHANNEL_IND_CLASS 0x0000a06f - -struct nv50_channel_ind_class { - u32 pushbuf; - u32 ilength; - u64 ioffset; -}; - -#define NVE0_CHANNEL_IND_ENGINE_GR 0x00000001 -#define NVE0_CHANNEL_IND_ENGINE_VP 0x00000002 -#define NVE0_CHANNEL_IND_ENGINE_PPP 0x00000004 -#define NVE0_CHANNEL_IND_ENGINE_BSP 0x00000008 -#define NVE0_CHANNEL_IND_ENGINE_CE0 0x00000010 -#define NVE0_CHANNEL_IND_ENGINE_CE1 0x00000020 -#define NVE0_CHANNEL_IND_ENGINE_ENC 0x00000040 - -struct nve0_channel_ind_class { - u32 pushbuf; - u32 ilength; - u64 ioffset; - u32 engine; -}; - -/* 0046: NV04_DISP - */ - -#define NV04_DISP_CLASS 0x00000046 - -#define NV04_DISP_MTHD 0x00000000 -#define NV04_DISP_MTHD_HEAD 0x00000001 - -#define NV04_DISP_SCANOUTPOS 0x00000000 - -struct nv04_display_class { -}; - -struct nv04_display_scanoutpos { - s64 time[2]; - u32 vblanks; - u32 vblanke; - u32 vtotal; - u32 vline; - u32 hblanks; - u32 hblanke; - u32 htotal; - u32 hline; -}; - -/* 5070: NV50_DISP - * 8270: NV84_DISP - * 8370: NVA0_DISP - * 8870: NV94_DISP - * 8570: NVA3_DISP - * 9070: NVD0_DISP - * 9170: NVE0_DISP - * 9270: NVF0_DISP - * 9470: GM107_DISP - */ - -#define NV50_DISP_CLASS 0x00005070 -#define NV84_DISP_CLASS 0x00008270 -#define NVA0_DISP_CLASS 0x00008370 -#define NV94_DISP_CLASS 0x00008870 -#define NVA3_DISP_CLASS 0x00008570 -#define NVD0_DISP_CLASS 0x00009070 -#define NVE0_DISP_CLASS 0x00009170 -#define NVF0_DISP_CLASS 0x00009270 -#define GM107_DISP_CLASS 0x00009470 - -#define NV50_DISP_MTHD 0x00000000 -#define NV50_DISP_MTHD_HEAD 0x00000003 - -#define NV50_DISP_SCANOUTPOS 0x00000000 - -#define NV50_DISP_SOR_MTHD 0x00010000 -#define NV50_DISP_SOR_MTHD_TYPE 0x0000f000 -#define NV50_DISP_SOR_MTHD_HEAD 0x00000018 -#define NV50_DISP_SOR_MTHD_LINK 0x00000004 -#define NV50_DISP_SOR_MTHD_OR 0x00000003 - -#define NV50_DISP_SOR_PWR 0x00010000 -#define NV50_DISP_SOR_PWR_STATE 0x00000001 -#define NV50_DISP_SOR_PWR_STATE_ON 0x00000001 -#define NV50_DISP_SOR_PWR_STATE_OFF 0x00000000 -#define NVA3_DISP_SOR_HDA_ELD 0x00010100 -#define NV84_DISP_SOR_HDMI_PWR 0x00012000 -#define NV84_DISP_SOR_HDMI_PWR_STATE 0x40000000 -#define NV84_DISP_SOR_HDMI_PWR_STATE_OFF 0x00000000 -#define NV84_DISP_SOR_HDMI_PWR_STATE_ON 0x40000000 -#define NV84_DISP_SOR_HDMI_PWR_MAX_AC_PACKET 0x001f0000 -#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f -#define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000 -#define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff -#define NV94_DISP_SOR_DP_PWR 0x00016000 -#define NV94_DISP_SOR_DP_PWR_STATE 0x00000001 -#define NV94_DISP_SOR_DP_PWR_STATE_OFF 0x00000000 -#define NV94_DISP_SOR_DP_PWR_STATE_ON 0x00000001 - -#define NV50_DISP_DAC_MTHD 0x00020000 -#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000 -#define NV50_DISP_DAC_MTHD_OR 0x00000003 - -#define NV50_DISP_DAC_PWR 0x00020000 -#define NV50_DISP_DAC_PWR_HSYNC 0x00000001 -#define NV50_DISP_DAC_PWR_HSYNC_ON 0x00000000 -#define NV50_DISP_DAC_PWR_HSYNC_LO 0x00000001 -#define NV50_DISP_DAC_PWR_VSYNC 0x00000004 -#define NV50_DISP_DAC_PWR_VSYNC_ON 0x00000000 -#define NV50_DISP_DAC_PWR_VSYNC_LO 0x00000004 -#define NV50_DISP_DAC_PWR_DATA 0x00000010 -#define NV50_DISP_DAC_PWR_DATA_ON 0x00000000 -#define NV50_DISP_DAC_PWR_DATA_LO 0x00000010 -#define NV50_DISP_DAC_PWR_STATE 0x00000040 -#define NV50_DISP_DAC_PWR_STATE_ON 0x00000000 -#define NV50_DISP_DAC_PWR_STATE_OFF 0x00000040 -#define NV50_DISP_DAC_LOAD 0x00020100 -#define NV50_DISP_DAC_LOAD_VALUE 0x00000007 - -#define NV50_DISP_PIOR_MTHD 0x00030000 -#define NV50_DISP_PIOR_MTHD_TYPE 0x0000f000 -#define NV50_DISP_PIOR_MTHD_OR 0x00000003 - -#define NV50_DISP_PIOR_PWR 0x00030000 -#define NV50_DISP_PIOR_PWR_STATE 0x00000001 -#define NV50_DISP_PIOR_PWR_STATE_ON 0x00000001 -#define NV50_DISP_PIOR_PWR_STATE_OFF 0x00000000 -#define NV50_DISP_PIOR_TMDS_PWR 0x00032000 -#define NV50_DISP_PIOR_TMDS_PWR_STATE 0x00000001 -#define NV50_DISP_PIOR_TMDS_PWR_STATE_ON 0x00000001 -#define NV50_DISP_PIOR_TMDS_PWR_STATE_OFF 0x00000000 -#define NV50_DISP_PIOR_DP_PWR 0x00036000 -#define NV50_DISP_PIOR_DP_PWR_STATE 0x00000001 -#define NV50_DISP_PIOR_DP_PWR_STATE_ON 0x00000001 -#define NV50_DISP_PIOR_DP_PWR_STATE_OFF 0x00000000 - -struct nv50_display_class { -}; - -/* 507a: NV50_DISP_CURS - * 827a: NV84_DISP_CURS - * 837a: NVA0_DISP_CURS - * 887a: NV94_DISP_CURS - * 857a: NVA3_DISP_CURS - * 907a: NVD0_DISP_CURS - * 917a: NVE0_DISP_CURS - * 927a: NVF0_DISP_CURS - * 947a: GM107_DISP_CURS - */ - -#define NV50_DISP_CURS_CLASS 0x0000507a -#define NV84_DISP_CURS_CLASS 0x0000827a -#define NVA0_DISP_CURS_CLASS 0x0000837a -#define NV94_DISP_CURS_CLASS 0x0000887a -#define NVA3_DISP_CURS_CLASS 0x0000857a -#define NVD0_DISP_CURS_CLASS 0x0000907a -#define NVE0_DISP_CURS_CLASS 0x0000917a -#define NVF0_DISP_CURS_CLASS 0x0000927a -#define GM107_DISP_CURS_CLASS 0x0000947a - -struct nv50_display_curs_class { - u32 head; -}; - -/* 507b: NV50_DISP_OIMM - * 827b: NV84_DISP_OIMM - * 837b: NVA0_DISP_OIMM - * 887b: NV94_DISP_OIMM - * 857b: NVA3_DISP_OIMM - * 907b: NVD0_DISP_OIMM - * 917b: NVE0_DISP_OIMM - * 927b: NVE0_DISP_OIMM - * 947b: GM107_DISP_OIMM - */ - -#define NV50_DISP_OIMM_CLASS 0x0000507b -#define NV84_DISP_OIMM_CLASS 0x0000827b -#define NVA0_DISP_OIMM_CLASS 0x0000837b -#define NV94_DISP_OIMM_CLASS 0x0000887b -#define NVA3_DISP_OIMM_CLASS 0x0000857b -#define NVD0_DISP_OIMM_CLASS 0x0000907b -#define NVE0_DISP_OIMM_CLASS 0x0000917b -#define NVF0_DISP_OIMM_CLASS 0x0000927b -#define GM107_DISP_OIMM_CLASS 0x0000947b - -struct nv50_display_oimm_class { - u32 head; -}; - -/* 507c: NV50_DISP_SYNC - * 827c: NV84_DISP_SYNC - * 837c: NVA0_DISP_SYNC - * 887c: NV94_DISP_SYNC - * 857c: NVA3_DISP_SYNC - * 907c: NVD0_DISP_SYNC - * 917c: NVE0_DISP_SYNC - * 927c: NVF0_DISP_SYNC - * 947c: GM107_DISP_SYNC - */ - -#define NV50_DISP_SYNC_CLASS 0x0000507c -#define NV84_DISP_SYNC_CLASS 0x0000827c -#define NVA0_DISP_SYNC_CLASS 0x0000837c -#define NV94_DISP_SYNC_CLASS 0x0000887c -#define NVA3_DISP_SYNC_CLASS 0x0000857c -#define NVD0_DISP_SYNC_CLASS 0x0000907c -#define NVE0_DISP_SYNC_CLASS 0x0000917c -#define NVF0_DISP_SYNC_CLASS 0x0000927c -#define GM107_DISP_SYNC_CLASS 0x0000947c - -struct nv50_display_sync_class { - u32 pushbuf; - u32 head; -}; - -/* 507d: NV50_DISP_MAST - * 827d: NV84_DISP_MAST - * 837d: NVA0_DISP_MAST - * 887d: NV94_DISP_MAST - * 857d: NVA3_DISP_MAST - * 907d: NVD0_DISP_MAST - * 917d: NVE0_DISP_MAST - * 927d: NVF0_DISP_MAST - * 947d: GM107_DISP_MAST - */ - -#define NV50_DISP_MAST_CLASS 0x0000507d -#define NV84_DISP_MAST_CLASS 0x0000827d -#define NVA0_DISP_MAST_CLASS 0x0000837d -#define NV94_DISP_MAST_CLASS 0x0000887d -#define NVA3_DISP_MAST_CLASS 0x0000857d -#define NVD0_DISP_MAST_CLASS 0x0000907d -#define NVE0_DISP_MAST_CLASS 0x0000917d -#define NVF0_DISP_MAST_CLASS 0x0000927d -#define GM107_DISP_MAST_CLASS 0x0000947d - -struct nv50_display_mast_class { - u32 pushbuf; -}; - -/* 507e: NV50_DISP_OVLY - * 827e: NV84_DISP_OVLY - * 837e: NVA0_DISP_OVLY - * 887e: NV94_DISP_OVLY - * 857e: NVA3_DISP_OVLY - * 907e: NVD0_DISP_OVLY - * 917e: NVE0_DISP_OVLY - * 927e: NVF0_DISP_OVLY - * 947e: GM107_DISP_OVLY - */ - -#define NV50_DISP_OVLY_CLASS 0x0000507e -#define NV84_DISP_OVLY_CLASS 0x0000827e -#define NVA0_DISP_OVLY_CLASS 0x0000837e -#define NV94_DISP_OVLY_CLASS 0x0000887e -#define NVA3_DISP_OVLY_CLASS 0x0000857e -#define NVD0_DISP_OVLY_CLASS 0x0000907e -#define NVE0_DISP_OVLY_CLASS 0x0000917e -#define NVF0_DISP_OVLY_CLASS 0x0000927e -#define GM107_DISP_OVLY_CLASS 0x0000947e - -struct nv50_display_ovly_class { - u32 pushbuf; - u32 head; -}; - -#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h index c66eac513803..b0ce9f6680b5 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/client.h +++ b/drivers/gpu/drm/nouveau/core/include/core/client.h @@ -10,6 +10,11 @@ struct nouveau_client { char name[32]; u32 debug; struct nouveau_vm *vm; + bool super; + void *data; + + int (*ntfy)(const void *, u32, const void *, u32); + struct nvkm_client_notify *notify[16]; }; static inline struct nouveau_client * @@ -43,4 +48,10 @@ int nouveau_client_init(struct nouveau_client *); int nouveau_client_fini(struct nouveau_client *, bool suspend); const char *nouveau_client_name(void *obj); +int nvkm_client_notify_new(struct nouveau_object *, struct nvkm_event *, + void *data, u32 size); +int nvkm_client_notify_del(struct nouveau_client *, int index); +int nvkm_client_notify_get(struct nouveau_client *, int index); +int nvkm_client_notify_put(struct nouveau_client *, int index); + #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h index a8a9a9cf16cb..1d9d893929bb 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/device.h +++ b/drivers/gpu/drm/nouveau/core/include/core/device.h @@ -4,6 +4,7 @@ #include <core/object.h> #include <core/subdev.h> #include <core/engine.h> +#include <core/event.h> enum nv_subdev_type { NVDEV_ENGINE_DEVICE, @@ -23,12 +24,13 @@ enum nv_subdev_type { * been created, and are allowed to assume any subdevs in the * list above them exist and have been initialised. */ + NVDEV_SUBDEV_FUSE, NVDEV_SUBDEV_MXM, NVDEV_SUBDEV_MC, NVDEV_SUBDEV_BUS, NVDEV_SUBDEV_TIMER, NVDEV_SUBDEV_FB, - NVDEV_SUBDEV_LTCG, + NVDEV_SUBDEV_LTC, NVDEV_SUBDEV_IBUS, NVDEV_SUBDEV_INSTMEM, NVDEV_SUBDEV_VM, @@ -69,6 +71,8 @@ struct nouveau_device { struct platform_device *platformdev; u64 handle; + struct nvkm_event event; + const char *cfgopt; const char *dbgopt; const char *name; @@ -84,7 +88,6 @@ struct nouveau_device { NV_40 = 0x40, NV_50 = 0x50, NV_C0 = 0xc0, - NV_D0 = 0xd0, NV_E0 = 0xe0, GM100 = 0x110, } card_type; @@ -93,8 +96,14 @@ struct nouveau_device { struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR]; struct nouveau_object *subdev[NVDEV_SUBDEV_NR]; + + struct { + struct notifier_block nb; + } acpi; }; +int nouveau_device_list(u64 *name, int size); + static inline struct nouveau_device * nv_device(void *obj) { @@ -162,12 +171,6 @@ nv_device_resource_start(struct nouveau_device *device, unsigned int bar); resource_size_t nv_device_resource_len(struct nouveau_device *device, unsigned int bar); -dma_addr_t -nv_device_map_page(struct nouveau_device *device, struct page *page); - -void -nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr); - int nv_device_get_irq(struct nouveau_device *device, bool stall); diff --git a/drivers/gpu/drm/nouveau/core/include/core/event.h b/drivers/gpu/drm/nouveau/core/include/core/event.h index ba3f1a76a815..92876528972f 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/event.h +++ b/drivers/gpu/drm/nouveau/core/include/core/event.h @@ -1,47 +1,35 @@ #ifndef __NVKM_EVENT_H__ #define __NVKM_EVENT_H__ -/* return codes from event handlers */ -#define NVKM_EVENT_DROP 0 -#define NVKM_EVENT_KEEP 1 - -/* nouveau_eventh.flags bit #s */ -#define NVKM_EVENT_ENABLE 0 - -struct nouveau_eventh { - struct nouveau_event *event; - struct list_head head; - unsigned long flags; - u32 types; - int index; - int (*func)(void *, u32, int); - void *priv; +#include <core/notify.h> + +struct nvkm_event_func { + int (*ctor)(struct nouveau_object *, void *data, u32 size, + struct nvkm_notify *); + void (*send)(void *data, u32 size, struct nvkm_notify *); + void (*init)(struct nvkm_event *, int type, int index); + void (*fini)(struct nvkm_event *, int type, int index); }; -struct nouveau_event { - void *priv; - int (*check)(struct nouveau_event *, u32 type, int index); - void (*enable)(struct nouveau_event *, int type, int index); - void (*disable)(struct nouveau_event *, int type, int index); +struct nvkm_event { + const struct nvkm_event_func *func; int types_nr; int index_nr; - spinlock_t list_lock; - struct list_head *list; spinlock_t refs_lock; - int refs[]; + spinlock_t list_lock; + struct list_head list; + int *refs; }; -int nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **); -void nouveau_event_destroy(struct nouveau_event **); -void nouveau_event_trigger(struct nouveau_event *, u32 types, int index); - -int nouveau_event_new(struct nouveau_event *, u32 types, int index, - int (*func)(void *, u32, int), void *, - struct nouveau_eventh **); -void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **); -void nouveau_event_get(struct nouveau_eventh *); -void nouveau_event_put(struct nouveau_eventh *); +int nvkm_event_init(const struct nvkm_event_func *func, + int types_nr, int index_nr, + struct nvkm_event *); +void nvkm_event_fini(struct nvkm_event *); +void nvkm_event_get(struct nvkm_event *, u32 types, int index); +void nvkm_event_put(struct nvkm_event *, u32 types, int index); +void nvkm_event_send(struct nvkm_event *, u32 types, int index, + void *data, u32 size); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/handle.h b/drivers/gpu/drm/nouveau/core/include/core/handle.h index 363674cdf8ab..ceb67d770875 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/handle.h +++ b/drivers/gpu/drm/nouveau/core/include/core/handle.h @@ -10,6 +10,9 @@ struct nouveau_handle { u32 name; u32 priv; + u8 route; + u64 token; + struct nouveau_handle *parent; struct nouveau_object *object; }; @@ -20,6 +23,11 @@ void nouveau_handle_destroy(struct nouveau_handle *); int nouveau_handle_init(struct nouveau_handle *); int nouveau_handle_fini(struct nouveau_handle *, bool suspend); +int nouveau_handle_new(struct nouveau_object *, u32 parent, u32 handle, + u16 oclass, void *data, u32 size, + struct nouveau_object **); +int nouveau_handle_del(struct nouveau_object *, u32 parent, u32 handle); + struct nouveau_object * nouveau_handle_ref(struct nouveau_object *, u32 name); diff --git a/drivers/gpu/drm/nouveau/core/include/core/ioctl.h b/drivers/gpu/drm/nouveau/core/include/core/ioctl.h new file mode 100644 index 000000000000..ac7935c2474e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/ioctl.h @@ -0,0 +1,6 @@ +#ifndef __NVKM_IOCTL_H__ +#define __NVKM_IOCTL_H__ + +int nvkm_ioctl(struct nouveau_client *, bool, void *, u32, void **); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h index 2bf7d0e32261..bfe6931544fe 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/mm.h +++ b/drivers/gpu/drm/nouveau/core/include/core/mm.h @@ -6,6 +6,10 @@ struct nouveau_mm_node { struct list_head fl_entry; struct list_head rl_entry; +#define NVKM_MM_HEAP_ANY 0x00 + u8 heap; +#define NVKM_MM_TYPE_NONE 0x00 +#define NVKM_MM_TYPE_HOLE 0xff u8 type; u32 offset; u32 length; @@ -27,10 +31,10 @@ nouveau_mm_initialised(struct nouveau_mm *mm) int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block); int nouveau_mm_fini(struct nouveau_mm *); -int nouveau_mm_head(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min, - u32 align, struct nouveau_mm_node **); -int nouveau_mm_tail(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min, - u32 align, struct nouveau_mm_node **); +int nouveau_mm_head(struct nouveau_mm *, u8 heap, u8 type, u32 size_max, + u32 size_min, u32 align, struct nouveau_mm_node **); +int nouveau_mm_tail(struct nouveau_mm *, u8 heap, u8 type, u32 size_max, + u32 size_min, u32 align, struct nouveau_mm_node **); void nouveau_mm_free(struct nouveau_mm *, struct nouveau_mm_node **); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/notify.h b/drivers/gpu/drm/nouveau/core/include/core/notify.h new file mode 100644 index 000000000000..a7c3c5f578cc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/notify.h @@ -0,0 +1,37 @@ +#ifndef __NVKM_NOTIFY_H__ +#define __NVKM_NOTIFY_H__ + +struct nvkm_notify { + struct nvkm_event *event; + struct list_head head; +#define NVKM_NOTIFY_USER 0 +#define NVKM_NOTIFY_WORK 1 + unsigned long flags; + int block; +#define NVKM_NOTIFY_DROP 0 +#define NVKM_NOTIFY_KEEP 1 + int (*func)(struct nvkm_notify *); + + /* set by nvkm_event ctor */ + u32 types; + int index; + u32 size; + + struct work_struct work; + /* this is const for a *very* good reason - the data might be on the + * stack from an irq handler. if you're not core/notify.c then you + * should probably think twice before casting it away... + */ + const void *data; +}; + +int nvkm_notify_init(struct nouveau_object *, struct nvkm_event *, + int (*func)(struct nvkm_notify *), bool work, + void *data, u32 size, u32 reply, + struct nvkm_notify *); +void nvkm_notify_fini(struct nvkm_notify *); +void nvkm_notify_get(struct nvkm_notify *); +void nvkm_notify_put(struct nvkm_notify *); +void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index 62e68baef087..d7039482d6fd 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h @@ -48,6 +48,10 @@ void nouveau_object_destroy(struct nouveau_object *); int nouveau_object_init(struct nouveau_object *); int nouveau_object_fini(struct nouveau_object *, bool suspend); +int _nouveau_object_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); + extern struct nouveau_ofuncs nouveau_object_ofuncs; /* Don't allocate dynamically, because lockdep needs lock_class_keys to be in @@ -78,6 +82,7 @@ struct nouveau_omthds { int (*call)(struct nouveau_object *, u32, void *, u32); }; +struct nvkm_event; struct nouveau_ofuncs { int (*ctor)(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, void *data, u32 size, @@ -85,6 +90,9 @@ struct nouveau_ofuncs { void (*dtor)(struct nouveau_object *); int (*init)(struct nouveau_object *); int (*fini)(struct nouveau_object *, bool suspend); + int (*mthd)(struct nouveau_object *, u32, void *, u32); + int (*ntfy)(struct nouveau_object *, u32, struct nvkm_event **); + int (* map)(struct nouveau_object *, u64 *, u32 *); u8 (*rd08)(struct nouveau_object *, u64 offset); u16 (*rd16)(struct nouveau_object *, u64 offset); u32 (*rd32)(struct nouveau_object *, u64 offset); @@ -106,10 +114,6 @@ void nouveau_object_ref(struct nouveau_object *, struct nouveau_object **); int nouveau_object_inc(struct nouveau_object *); int nouveau_object_dec(struct nouveau_object *, bool suspend); -int nouveau_object_new(struct nouveau_object *, u32 parent, u32 handle, - u16 oclass, void *data, u32 size, - struct nouveau_object **); -int nouveau_object_del(struct nouveau_object *, u32 parent, u32 handle); void nouveau_object_debug(void); static inline int @@ -199,4 +203,21 @@ nv_memcmp(void *obj, u32 addr, const char *str, u32 len) return 0; } +#include <core/handle.h> + +static inline int +nouveau_object_new(struct nouveau_object *client, u32 parent, u32 handle, + u16 oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + return nouveau_handle_new(client, parent, handle, oclass, + data, size, pobject); +} + +static inline int +nouveau_object_del(struct nouveau_object *client, u32 parent, u32 handle) +{ + return nouveau_handle_del(client, parent, handle); +} + #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h index 9f5ea900ff00..12da418ec70a 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/parent.h +++ b/drivers/gpu/drm/nouveau/core/include/core/parent.h @@ -57,5 +57,6 @@ void _nouveau_parent_dtor(struct nouveau_object *); int nouveau_parent_sclass(struct nouveau_object *, u16 handle, struct nouveau_object **pengine, struct nouveau_oclass **poclass); +int nouveau_parent_lclass(struct nouveau_object *, u32 *, int); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/printk.h b/drivers/gpu/drm/nouveau/core/include/core/printk.h index 0f9a37bd32b0..451b6ed20b7e 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/printk.h +++ b/drivers/gpu/drm/nouveau/core/include/core/printk.h @@ -21,6 +21,7 @@ nv_printk_(struct nouveau_object *, int, const char *, ...); #define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a) #define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a) #define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a) +#define nv_ioctl(o,f,a...) nv_trace(nouveau_client(o), "ioctl: "f, ##a) #define nv_assert(f,a...) do { \ if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG) \ diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h index fde842896806..7a64f347b385 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h @@ -6,20 +6,13 @@ #include <core/device.h> #include <core/event.h> -enum nvkm_hpd_event { - NVKM_HPD_PLUG = 1, - NVKM_HPD_UNPLUG = 2, - NVKM_HPD_IRQ = 4, - NVKM_HPD = (NVKM_HPD_PLUG | NVKM_HPD_UNPLUG | NVKM_HPD_IRQ) -}; - struct nouveau_disp { struct nouveau_engine base; struct list_head outp; - struct nouveau_event *hpd; - struct nouveau_event *vblank; + struct nvkm_event hpd; + struct nvkm_event vblank; }; static inline struct nouveau_disp * diff --git a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h index b28914ed1752..1b283a7b78e6 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h @@ -12,37 +12,20 @@ struct nouveau_dmaobj { u32 access; u64 start; u64 limit; - u32 conf0; }; struct nouveau_dmaeng { struct nouveau_engine base; /* creates a "physical" dma object from a struct nouveau_dmaobj */ - int (*bind)(struct nouveau_dmaeng *dmaeng, + int (*bind)(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent, - struct nouveau_dmaobj *dmaobj, struct nouveau_gpuobj **); }; -#define nouveau_dmaeng_create(p,e,c,d) \ - nouveau_engine_create((p), (e), (c), true, "DMAOBJ", "dmaobj", (d)) -#define nouveau_dmaeng_destroy(p) \ - nouveau_engine_destroy(&(p)->base) -#define nouveau_dmaeng_init(p) \ - nouveau_engine_init(&(p)->base) -#define nouveau_dmaeng_fini(p,s) \ - nouveau_engine_fini(&(p)->base, (s)) - -#define _nouveau_dmaeng_dtor _nouveau_engine_dtor -#define _nouveau_dmaeng_init _nouveau_engine_init -#define _nouveau_dmaeng_fini _nouveau_engine_fini - -extern struct nouveau_oclass nv04_dmaeng_oclass; -extern struct nouveau_oclass nv50_dmaeng_oclass; -extern struct nouveau_oclass nvc0_dmaeng_oclass; -extern struct nouveau_oclass nvd0_dmaeng_oclass; - -extern struct nouveau_oclass nouveau_dmaobj_sclass[]; +extern struct nouveau_oclass *nv04_dmaeng_oclass; +extern struct nouveau_oclass *nv50_dmaeng_oclass; +extern struct nouveau_oclass *nvc0_dmaeng_oclass; +extern struct nouveau_oclass *nvd0_dmaeng_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h index b639eb2c74ff..2007453f6fce 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h @@ -4,12 +4,14 @@ #include <core/namedb.h> #include <core/gpuobj.h> #include <core/engine.h> +#include <core/event.h> struct nouveau_fifo_chan { struct nouveau_namedb base; struct nouveau_dmaobj *pushdma; struct nouveau_gpuobj *pushgpu; void __iomem *user; + u64 addr; u32 size; u16 chid; atomic_t refcnt; /* NV04_NVSW_SET_REF */ @@ -40,8 +42,10 @@ void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *); #define _nouveau_fifo_channel_fini _nouveau_namedb_fini void _nouveau_fifo_channel_dtor(struct nouveau_object *); +int _nouveau_fifo_channel_map(struct nouveau_object *, u64 *, u32 *); u32 _nouveau_fifo_channel_rd32(struct nouveau_object *, u64); void _nouveau_fifo_channel_wr32(struct nouveau_object *, u64, u32); +int _nouveau_fifo_channel_ntfy(struct nouveau_object *, u32, struct nvkm_event **); struct nouveau_fifo_base { struct nouveau_gpuobj base; @@ -65,8 +69,8 @@ struct nouveau_fifo_base { struct nouveau_fifo { struct nouveau_engine base; - struct nouveau_event *cevent; /* channel creation event */ - struct nouveau_event *uevent; /* async user trigger */ + struct nvkm_event cevent; /* channel creation event */ + struct nvkm_event uevent; /* async user trigger */ struct nouveau_object **channel; spinlock_t lock; @@ -112,6 +116,10 @@ extern struct nouveau_oclass *nve0_fifo_oclass; extern struct nouveau_oclass *gk20a_fifo_oclass; extern struct nouveau_oclass *nv108_fifo_oclass; +int nouveau_fifo_uevent_ctor(struct nouveau_object *, void *, u32, + struct nvkm_notify *); +void nouveau_fifo_uevent(struct nouveau_fifo *); + void nv04_fifo_intr(struct nouveau_subdev *); int nv04_fifo_context_attach(struct nouveau_object *, struct nouveau_object *); diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h index 8c1d4772da0c..d5055570d01b 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/graph.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/graph.h @@ -70,6 +70,7 @@ extern struct nouveau_oclass *nvd9_graph_oclass; extern struct nouveau_oclass *nve4_graph_oclass; extern struct nouveau_oclass *gk20a_graph_oclass; extern struct nouveau_oclass *nvf0_graph_oclass; +extern struct nouveau_oclass *gk110b_graph_oclass; extern struct nouveau_oclass *nv108_graph_oclass; extern struct nouveau_oclass *gm107_graph_oclass; diff --git a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h b/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h index 49b0024910fe..88cc812baaa3 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h @@ -4,7 +4,6 @@ #include <core/device.h> #include <core/engine.h> #include <core/engctx.h> -#include <core/class.h> struct nouveau_perfdom; struct nouveau_perfctr; diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/class.h b/drivers/gpu/drm/nouveau/core/include/nvif/class.h new file mode 120000 index 000000000000..f1ac4859edd4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/nvif/class.h @@ -0,0 +1 @@ +../../../nvif/class.h
\ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/event.h b/drivers/gpu/drm/nouveau/core/include/nvif/event.h new file mode 120000 index 000000000000..1b798538a725 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/nvif/event.h @@ -0,0 +1 @@ +../../../nvif/event.h
\ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h new file mode 120000 index 000000000000..8569c86907c5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h @@ -0,0 +1 @@ +../../../nvif/ioctl.h
\ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h b/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h new file mode 120000 index 000000000000..69d99292bca4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h @@ -0,0 +1 @@ +../../../nvif/unpack.h
\ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h index 9faa98e67ad8..257ddf6d36d4 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h @@ -12,7 +12,6 @@ struct nouveau_bar { int (*alloc)(struct nouveau_bar *, struct nouveau_object *, struct nouveau_mem *, struct nouveau_object **); - void __iomem *iomem; int (*kmap)(struct nouveau_bar *, struct nouveau_mem *, u32 flags, struct nouveau_vma *); @@ -20,6 +19,9 @@ struct nouveau_bar { u32 flags, struct nouveau_vma *); void (*unmap)(struct nouveau_bar *, struct nouveau_vma *); void (*flush)(struct nouveau_bar *); + + /* whether the BAR supports to be ioremapped WC or should be uncached */ + bool iomap_uncached; }; static inline struct nouveau_bar * @@ -30,5 +32,6 @@ nouveau_bar(void *obj) extern struct nouveau_oclass nv50_bar_oclass; extern struct nouveau_oclass nvc0_bar_oclass; +extern struct nouveau_oclass gk20a_bar_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h new file mode 100644 index 000000000000..e171120cec81 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h @@ -0,0 +1,32 @@ +#ifndef __NVBIOS_M0205_H__ +#define __NVBIOS_M0205_H__ + +struct nvbios_M0205T { + u16 freq; +}; + +u32 nvbios_M0205Te(struct nouveau_bios *, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz); +u32 nvbios_M0205Tp(struct nouveau_bios *, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz, + struct nvbios_M0205T *); + +struct nvbios_M0205E { + u8 type; +}; + +u32 nvbios_M0205Ee(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u32 nvbios_M0205Ep(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_M0205E *); + +struct nvbios_M0205S { + u8 data; +}; + +u32 nvbios_M0205Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr); +u32 nvbios_M0205Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr, + struct nvbios_M0205S *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h new file mode 100644 index 000000000000..67dc50d837bc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h @@ -0,0 +1,30 @@ +#ifndef __NVBIOS_M0209_H__ +#define __NVBIOS_M0209_H__ + +u32 nvbios_M0209Te(struct nouveau_bios *, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz); + +struct nvbios_M0209E { + u8 v00_40; + u8 bits; + u8 modulo; + u8 v02_40; + u8 v02_07; + u8 v03; +}; + +u32 nvbios_M0209Ee(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u32 nvbios_M0209Ep(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_M0209E *); + +struct nvbios_M0209S { + u32 data[0x200]; +}; + +u32 nvbios_M0209Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr); +u32 nvbios_M0209Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr, + struct nvbios_M0209S *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h new file mode 100644 index 000000000000..119d0874e041 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h @@ -0,0 +1,8 @@ +#ifndef __NVBIOS_FAN_H__ +#define __NVBIOS_FAN_H__ + +#include <subdev/bios/therm.h> + +u16 nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h index c086ac6d677d..a685bbd04568 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h @@ -4,60 +4,118 @@ struct nouveau_bios; struct nvbios_ramcfg { - unsigned rammap_11_08_01:1; - unsigned rammap_11_08_0c:2; - unsigned rammap_11_08_10:1; - unsigned rammap_11_11_0c:2; + unsigned rammap_ver; + unsigned rammap_hdr; + unsigned rammap_min; + unsigned rammap_max; + union { + struct { + unsigned rammap_10_04_02:1; + unsigned rammap_10_04_08:1; + }; + struct { + unsigned rammap_11_08_01:1; + unsigned rammap_11_08_0c:2; + unsigned rammap_11_08_10:1; + unsigned rammap_11_09_01ff:9; + unsigned rammap_11_0a_03fe:9; + unsigned rammap_11_0a_0400:1; + unsigned rammap_11_0a_0800:1; + unsigned rammap_11_0b_01f0:5; + unsigned rammap_11_0b_0200:1; + unsigned rammap_11_0b_0400:1; + unsigned rammap_11_0b_0800:1; + unsigned rammap_11_0d:8; + unsigned rammap_11_0e:8; + unsigned rammap_11_0f:8; + unsigned rammap_11_11_0c:2; + }; + }; - unsigned ramcfg_11_01_01:1; - unsigned ramcfg_11_01_02:1; - unsigned ramcfg_11_01_04:1; - unsigned ramcfg_11_01_08:1; - unsigned ramcfg_11_01_10:1; - unsigned ramcfg_11_01_20:1; - unsigned ramcfg_11_01_40:1; - unsigned ramcfg_11_01_80:1; - unsigned ramcfg_11_02_03:2; - unsigned ramcfg_11_02_04:1; - unsigned ramcfg_11_02_08:1; - unsigned ramcfg_11_02_10:1; - unsigned ramcfg_11_02_40:1; - unsigned ramcfg_11_02_80:1; - unsigned ramcfg_11_03_0f:4; - unsigned ramcfg_11_03_30:2; - unsigned ramcfg_11_03_c0:2; - unsigned ramcfg_11_03_f0:4; - unsigned ramcfg_11_04:8; - unsigned ramcfg_11_06:8; - unsigned ramcfg_11_07_02:1; - unsigned ramcfg_11_07_04:1; - unsigned ramcfg_11_07_08:1; - unsigned ramcfg_11_07_10:1; - unsigned ramcfg_11_07_40:1; - unsigned ramcfg_11_07_80:1; - unsigned ramcfg_11_08_01:1; - unsigned ramcfg_11_08_02:1; - unsigned ramcfg_11_08_04:1; - unsigned ramcfg_11_08_08:1; - unsigned ramcfg_11_08_10:1; - unsigned ramcfg_11_08_20:1; - unsigned ramcfg_11_09:8; + unsigned ramcfg_ver; + unsigned ramcfg_hdr; + unsigned ramcfg_timing; + union { + struct { + unsigned ramcfg_10_02_01:1; + unsigned ramcfg_10_02_02:1; + unsigned ramcfg_10_02_04:1; + unsigned ramcfg_10_02_08:1; + unsigned ramcfg_10_02_10:1; + unsigned ramcfg_10_02_20:1; + unsigned ramcfg_10_02_40:1; + unsigned ramcfg_10_03_0f:4; + unsigned ramcfg_10_05:8; + unsigned ramcfg_10_06:8; + unsigned ramcfg_10_07:8; + unsigned ramcfg_10_08:8; + unsigned ramcfg_10_09_0f:4; + unsigned ramcfg_10_09_f0:4; + }; + struct { + unsigned ramcfg_11_01_01:1; + unsigned ramcfg_11_01_02:1; + unsigned ramcfg_11_01_04:1; + unsigned ramcfg_11_01_08:1; + unsigned ramcfg_11_01_10:1; + unsigned ramcfg_11_01_20:1; + unsigned ramcfg_11_01_40:1; + unsigned ramcfg_11_01_80:1; + unsigned ramcfg_11_02_03:2; + unsigned ramcfg_11_02_04:1; + unsigned ramcfg_11_02_08:1; + unsigned ramcfg_11_02_10:1; + unsigned ramcfg_11_02_40:1; + unsigned ramcfg_11_02_80:1; + unsigned ramcfg_11_03_0f:4; + unsigned ramcfg_11_03_30:2; + unsigned ramcfg_11_03_c0:2; + unsigned ramcfg_11_03_f0:4; + unsigned ramcfg_11_04:8; + unsigned ramcfg_11_06:8; + unsigned ramcfg_11_07_02:1; + unsigned ramcfg_11_07_04:1; + unsigned ramcfg_11_07_08:1; + unsigned ramcfg_11_07_10:1; + unsigned ramcfg_11_07_40:1; + unsigned ramcfg_11_07_80:1; + unsigned ramcfg_11_08_01:1; + unsigned ramcfg_11_08_02:1; + unsigned ramcfg_11_08_04:1; + unsigned ramcfg_11_08_08:1; + unsigned ramcfg_11_08_10:1; + unsigned ramcfg_11_08_20:1; + unsigned ramcfg_11_09:8; + }; + }; + unsigned timing_ver; + unsigned timing_hdr; unsigned timing[11]; - unsigned timing_20_2e_03:2; - unsigned timing_20_2e_30:2; - unsigned timing_20_2e_c0:2; - unsigned timing_20_2f_03:2; - unsigned timing_20_2c_003f:6; - unsigned timing_20_2c_1fc0:7; - unsigned timing_20_30_f8:5; - unsigned timing_20_30_07:3; - unsigned timing_20_31_0007:3; - unsigned timing_20_31_0078:4; - unsigned timing_20_31_0780:4; - unsigned timing_20_31_0800:1; - unsigned timing_20_31_7000:3; - unsigned timing_20_31_8000:1; + union { + struct { + unsigned timing_10_WR:8; + unsigned timing_10_CL:8; + unsigned timing_10_ODT:3; + unsigned timing_10_CWL:8; + }; + struct { + unsigned timing_20_2e_03:2; + unsigned timing_20_2e_30:2; + unsigned timing_20_2e_c0:2; + unsigned timing_20_2f_03:2; + unsigned timing_20_2c_003f:6; + unsigned timing_20_2c_1fc0:7; + unsigned timing_20_30_f8:5; + unsigned timing_20_30_07:3; + unsigned timing_20_31_0007:3; + unsigned timing_20_31_0078:4; + unsigned timing_20_31_0780:4; + unsigned timing_20_31_0800:1; + unsigned timing_20_31_7000:3; + unsigned timing_20_31_8000:1; + }; + }; }; u8 nvbios_ramcfg_count(struct nouveau_bios *); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h index 5bdf8e4db40a..47e021d3e20d 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h @@ -8,9 +8,10 @@ u32 nvbios_rammapTe(struct nouveau_bios *, u8 *ver, u8 *hdr, u32 nvbios_rammapEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u32 nvbios_rammapEp(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_ramcfg *); u32 nvbios_rammapEm(struct nouveau_bios *, u16 mhz, - u8 *ver, u8 *hdr, u8 *cnt, u8 *len); -u32 nvbios_rammapEp(struct nouveau_bios *, u16 mhz, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h index 8dc5051df55d..295d093f3b30 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h @@ -23,6 +23,12 @@ struct nvbios_therm_sensor { struct nvbios_therm_threshold thrs_shutdown; }; +enum nvbios_therm_fan_type { + NVBIOS_THERM_FAN_UNK = 0, + NVBIOS_THERM_FAN_TOGGLE = 1, + NVBIOS_THERM_FAN_PWM = 2, +}; + /* no vbios have more than 6 */ #define NOUVEAU_TEMP_FAN_TRIP_MAX 10 struct nouveau_therm_trip_point { @@ -38,7 +44,9 @@ enum nvbios_therm_fan_mode { }; struct nvbios_therm_fan { - u16 pwm_freq; + enum nvbios_therm_fan_type type; + + u32 pwm_freq; u8 min_duty; u8 max_duty; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index c01e29c9f89a..36ed035d4d42 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -29,6 +29,7 @@ enum nv_clk_src { nv_clk_src_mdiv, nv_clk_src_core, + nv_clk_src_core_intm, nv_clk_src_shader, nv_clk_src_mem, @@ -71,8 +72,15 @@ struct nouveau_clock { struct list_head states; int state_nr; + struct work_struct work; + wait_queue_head_t wait; + atomic_t waiting; + + struct nvkm_notify pwrsrc_ntfy; + int pwrsrc; int pstate; /* current */ - int ustate; /* user-requested (-1 disabled, -2 perfmon) */ + int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */ + int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */ int astate; /* perfmon adjustment (base) */ int tstate; /* thermal adjustment (max-) */ int dstate; /* display adjustment (min+) */ @@ -108,8 +116,9 @@ struct nouveau_clocks { int mdiv; }; -#define nouveau_clock_create(p,e,o,i,r,d) \ - nouveau_clock_create_((p), (e), (o), (i), (r), sizeof(**d), (void **)d) +#define nouveau_clock_create(p,e,o,i,r,s,n,d) \ + nouveau_clock_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d), \ + (void **)d) #define nouveau_clock_destroy(p) ({ \ struct nouveau_clock *clk = (p); \ _nouveau_clock_dtor(nv_object(clk)); \ @@ -118,15 +127,18 @@ struct nouveau_clocks { struct nouveau_clock *clk = (p); \ _nouveau_clock_init(nv_object(clk)); \ }) -#define nouveau_clock_fini(p,s) \ - nouveau_subdev_fini(&(p)->base, (s)) +#define nouveau_clock_fini(p,s) ({ \ + struct nouveau_clock *clk = (p); \ + _nouveau_clock_fini(nv_object(clk), (s)); \ +}) int nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, - struct nouveau_clocks *, bool, int, void **); + struct nouveau_clocks *, struct nouveau_pstate *, + int, bool, int, void **); void _nouveau_clock_dtor(struct nouveau_object *); -int _nouveau_clock_init(struct nouveau_object *); -#define _nouveau_clock_fini _nouveau_subdev_fini +int _nouveau_clock_init(struct nouveau_object *); +int _nouveau_clock_fini(struct nouveau_object *, bool); extern struct nouveau_oclass nv04_clock_oclass; extern struct nouveau_oclass nv40_clock_oclass; @@ -136,6 +148,7 @@ extern struct nouveau_oclass *nvaa_clock_oclass; extern struct nouveau_oclass nva3_clock_oclass; extern struct nouveau_oclass nvc0_clock_oclass; extern struct nouveau_oclass nve0_clock_oclass; +extern struct nouveau_oclass gk20a_clock_oclass; int nv04_clock_pll_set(struct nouveau_clock *, u32 type, u32 freq); int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, @@ -145,7 +158,7 @@ int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1, int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, int clk, struct nouveau_pll_vals *); -int nouveau_clock_ustate(struct nouveau_clock *, int req); +int nouveau_clock_ustate(struct nouveau_clock *, int req, int pwr); int nouveau_clock_astate(struct nouveau_clock *, int req, int rel); int nouveau_clock_dstate(struct nouveau_clock *, int req, int rel); int nouveau_clock_tstate(struct nouveau_clock *, int req, int rel); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h index 871e73914b24..8d0032f15205 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h @@ -111,6 +111,7 @@ extern struct nouveau_oclass *gm107_fb_oclass; #include <subdev/bios/ramcfg.h> struct nouveau_ram_data { + struct list_head head; struct nvbios_ramcfg bios; u32 freq; }; @@ -136,6 +137,7 @@ struct nouveau_ram { int ranks; int parts; + int part_mask; int (*get)(struct nouveau_fb *, u64 size, u32 align, u32 size_nc, u32 type, struct nouveau_mem **); @@ -144,11 +146,6 @@ struct nouveau_ram { int (*calc)(struct nouveau_fb *, u32 freq); int (*prog)(struct nouveau_fb *); void (*tidy)(struct nouveau_fb *); - struct { - u8 version; - u32 data; - u8 size; - } rammap, ramcfg, timing; u32 freq; u32 mr[16]; u32 mr1_nuts; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h new file mode 100644 index 000000000000..0f7fc0c52ab2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h @@ -0,0 +1,21 @@ +#ifndef __NOUVEAU_FB_REGS_04_H__ +#define __NOUVEAU_FB_REGS_04_H__ + +#define NV04_PFB_BOOT_0 0x00100000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 +# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 +# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 +# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 +# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h b/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h new file mode 100644 index 000000000000..2b1ddb2a9a7d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h @@ -0,0 +1,30 @@ +#ifndef __NOUVEAU_FUSE_H__ +#define __NOUVEAU_FUSE_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_fuse { + struct nouveau_subdev base; +}; + +static inline struct nouveau_fuse * +nouveau_fuse(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FUSE]; +} + +#define nouveau_fuse_create(p, e, o, d) \ + nouveau_fuse_create_((p), (e), (o), sizeof(**d), (void **)d) + +int nouveau_fuse_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void _nouveau_fuse_dtor(struct nouveau_object *); +int _nouveau_fuse_init(struct nouveau_object *); +#define _nouveau_fuse_fini _nouveau_subdev_fini + +extern struct nouveau_oclass g80_fuse_oclass; +extern struct nouveau_oclass gf100_fuse_oclass; +extern struct nouveau_oclass gm107_fuse_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h index 612d82ab683d..f855140dbcb7 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h @@ -8,16 +8,22 @@ #include <subdev/bios.h> #include <subdev/bios/gpio.h> -enum nvkm_gpio_event { - NVKM_GPIO_HI = 1, - NVKM_GPIO_LO = 2, - NVKM_GPIO_TOGGLED = (NVKM_GPIO_HI | NVKM_GPIO_LO), +struct nvkm_gpio_ntfy_req { +#define NVKM_GPIO_HI 0x01 +#define NVKM_GPIO_LO 0x02 +#define NVKM_GPIO_TOGGLED 0x03 + u8 mask; + u8 line; +}; + +struct nvkm_gpio_ntfy_rep { + u8 mask; }; struct nouveau_gpio { struct nouveau_subdev base; - struct nouveau_event *events; + struct nvkm_event event; void (*reset)(struct nouveau_gpio *, u8 func); int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, @@ -34,7 +40,7 @@ nouveau_gpio(void *obj) extern struct nouveau_oclass *nv10_gpio_oclass; extern struct nouveau_oclass *nv50_gpio_oclass; -extern struct nouveau_oclass *nv92_gpio_oclass; +extern struct nouveau_oclass *nv94_gpio_oclass; extern struct nouveau_oclass *nvd0_gpio_oclass; extern struct nouveau_oclass *nve0_gpio_oclass; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h index 825f7bb46b67..1b937c2c25ae 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h @@ -14,15 +14,18 @@ #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) -enum nvkm_i2c_event { - NVKM_I2C_PLUG = 1, - NVKM_I2C_UNPLUG = 2, - NVKM_I2C_IRQ = 4, - NVKM_I2C_DONE = 8, - NVKM_I2C_ANY = (NVKM_I2C_PLUG | - NVKM_I2C_UNPLUG | - NVKM_I2C_IRQ | - NVKM_I2C_DONE), +struct nvkm_i2c_ntfy_req { +#define NVKM_I2C_PLUG 0x01 +#define NVKM_I2C_UNPLUG 0x02 +#define NVKM_I2C_IRQ 0x04 +#define NVKM_I2C_DONE 0x08 +#define NVKM_I2C_ANY 0x0f + u8 mask; + u8 port; +}; + +struct nvkm_i2c_ntfy_rep { + u8 mask; }; struct nouveau_i2c_port { @@ -56,7 +59,7 @@ struct nouveau_i2c_board_info { struct nouveau_i2c { struct nouveau_subdev base; - struct nouveau_event *ntfy; + struct nvkm_event event; struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h new file mode 100644 index 000000000000..b909a7363f6b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h @@ -0,0 +1,35 @@ +#ifndef __NOUVEAU_LTC_H__ +#define __NOUVEAU_LTC_H__ + +#include <core/subdev.h> +#include <core/device.h> + +#define NOUVEAU_LTC_MAX_ZBC_CNT 16 + +struct nouveau_mm_node; + +struct nouveau_ltc { + struct nouveau_subdev base; + + int (*tags_alloc)(struct nouveau_ltc *, u32 count, + struct nouveau_mm_node **); + void (*tags_free)(struct nouveau_ltc *, struct nouveau_mm_node **); + void (*tags_clear)(struct nouveau_ltc *, u32 first, u32 count); + + int zbc_min; + int zbc_max; + int (*zbc_color_get)(struct nouveau_ltc *, int index, const u32[4]); + int (*zbc_depth_get)(struct nouveau_ltc *, int index, const u32); +}; + +static inline struct nouveau_ltc * +nouveau_ltc(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_LTC]; +} + +extern struct nouveau_oclass *gf100_ltc_oclass; +extern struct nouveau_oclass *gk104_ltc_oclass; +extern struct nouveau_oclass *gm107_ltc_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h deleted file mode 100644 index c9c1950b7743..000000000000 --- a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __NOUVEAU_LTCG_H__ -#define __NOUVEAU_LTCG_H__ - -#include <core/subdev.h> -#include <core/device.h> - -struct nouveau_mm_node; - -struct nouveau_ltcg { - struct nouveau_subdev base; - - int (*tags_alloc)(struct nouveau_ltcg *, u32 count, - struct nouveau_mm_node **); - void (*tags_free)(struct nouveau_ltcg *, struct nouveau_mm_node **); - void (*tags_clear)(struct nouveau_ltcg *, u32 first, u32 count); -}; - -static inline struct nouveau_ltcg * -nouveau_ltcg(void *obj) -{ - return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_LTCG]; -} - -#define nouveau_ltcg_create(p,e,o,d) \ - nouveau_subdev_create_((p), (e), (o), 0, "PLTCG", "level2", \ - sizeof(**d), (void **)d) -#define nouveau_ltcg_destroy(p) \ - nouveau_subdev_destroy(&(p)->base) -#define nouveau_ltcg_init(p) \ - nouveau_subdev_init(&(p)->base) -#define nouveau_ltcg_fini(p,s) \ - nouveau_subdev_fini(&(p)->base, (s)) - -#define _nouveau_ltcg_dtor _nouveau_subdev_dtor -#define _nouveau_ltcg_init _nouveau_subdev_init -#define _nouveau_ltcg_fini _nouveau_subdev_fini - -extern struct nouveau_oclass *gf100_ltcg_oclass; -extern struct nouveau_oclass *gm107_ltcg_oclass; - -#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h index 72b176831be6..568e4dfc5e9e 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h @@ -4,15 +4,11 @@ #include <core/subdev.h> #include <core/device.h> -struct nouveau_mc_intr { - u32 stat; - u32 unit; -}; - struct nouveau_mc { struct nouveau_subdev base; bool use_msi; unsigned int irq; + void (*unk260)(struct nouveau_mc *, u32); }; static inline struct nouveau_mc * @@ -21,30 +17,6 @@ nouveau_mc(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC]; } -#define nouveau_mc_create(p,e,o,d) \ - nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nouveau_mc_destroy(p) ({ \ - struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \ -}) -#define nouveau_mc_init(p) ({ \ - struct nouveau_mc *pmc = (p); _nouveau_mc_init(nv_object(pmc)); \ -}) -#define nouveau_mc_fini(p,s) ({ \ - struct nouveau_mc *pmc = (p); _nouveau_mc_fini(nv_object(pmc), (s)); \ -}) - -int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); -void _nouveau_mc_dtor(struct nouveau_object *); -int _nouveau_mc_init(struct nouveau_object *); -int _nouveau_mc_fini(struct nouveau_object *, bool); - -struct nouveau_mc_oclass { - struct nouveau_oclass base; - const struct nouveau_mc_intr *intr; - void (*msi_rearm)(struct nouveau_mc *); -}; - extern struct nouveau_oclass *nv04_mc_oclass; extern struct nouveau_oclass *nv40_mc_oclass; extern struct nouveau_oclass *nv44_mc_oclass; @@ -54,5 +26,6 @@ extern struct nouveau_oclass *nv94_mc_oclass; extern struct nouveau_oclass *nv98_mc_oclass; extern struct nouveau_oclass *nvc0_mc_oclass; extern struct nouveau_oclass *nvc3_mc_oclass; +extern struct nouveau_oclass *gk20a_mc_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h b/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h index c5c92cbed33f..bf3d1f611333 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h @@ -8,18 +8,6 @@ struct nouveau_pwr { struct nouveau_subdev base; struct { - u32 limit; - u32 *data; - u32 size; - } code; - - struct { - u32 limit; - u32 *data; - u32 size; - } data; - - struct { u32 base; u32 size; } send; @@ -35,7 +23,8 @@ struct nouveau_pwr { u32 data[2]; } recv; - int (*message)(struct nouveau_pwr *, u32[2], u32, u32, u32, u32); + int (*message)(struct nouveau_pwr *, u32[2], u32, u32, u32, u32); + void (*pgob)(struct nouveau_pwr *, bool); }; static inline struct nouveau_pwr * @@ -44,29 +33,11 @@ nouveau_pwr(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_PWR]; } -#define nouveau_pwr_create(p, e, o, d) \ - nouveau_pwr_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nouveau_pwr_destroy(p) \ - nouveau_subdev_destroy(&(p)->base) -#define nouveau_pwr_init(p) ({ \ - struct nouveau_pwr *ppwr = (p); \ - _nouveau_pwr_init(nv_object(ppwr)); \ -}) -#define nouveau_pwr_fini(p,s) ({ \ - struct nouveau_pwr *ppwr = (p); \ - _nouveau_pwr_fini(nv_object(ppwr), (s)); \ -}) - -int nouveau_pwr_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); -#define _nouveau_pwr_dtor _nouveau_subdev_dtor -int _nouveau_pwr_init(struct nouveau_object *); -int _nouveau_pwr_fini(struct nouveau_object *, bool); - -extern struct nouveau_oclass nva3_pwr_oclass; -extern struct nouveau_oclass nvc0_pwr_oclass; -extern struct nouveau_oclass nvd0_pwr_oclass; -extern struct nouveau_oclass nv108_pwr_oclass; +extern struct nouveau_oclass *nva3_pwr_oclass; +extern struct nouveau_oclass *nvc0_pwr_oclass; +extern struct nouveau_oclass *nvd0_pwr_oclass; +extern struct nouveau_oclass *gk104_pwr_oclass; +extern struct nouveau_oclass *nv108_pwr_oclass; /* interface to MEMX process running on PPWR */ struct nouveau_memx; @@ -76,5 +47,8 @@ void nouveau_memx_wr32(struct nouveau_memx *, u32 addr, u32 data); void nouveau_memx_wait(struct nouveau_memx *, u32 addr, u32 mask, u32 data, u32 nsec); void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec); +void nouveau_memx_wait_vblank(struct nouveau_memx *); +void nouveau_memx_block(struct nouveau_memx *); +void nouveau_memx_unblock(struct nouveau_memx *); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h index d4a68179e586..a437597dcafc 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h @@ -78,5 +78,6 @@ extern struct nouveau_oclass nv50_therm_oclass; extern struct nouveau_oclass nv84_therm_oclass; extern struct nouveau_oclass nva3_therm_oclass; extern struct nouveau_oclass nvd0_therm_oclass; +extern struct nouveau_oclass gm107_therm_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h index d0ced94ca54c..ccfa21d72ddc 100644 --- a/drivers/gpu/drm/nouveau/core/os.h +++ b/drivers/gpu/drm/nouveau/core/os.h @@ -21,6 +21,8 @@ #include <linux/interrupt.h> #include <linux/log2.h> #include <linux/pm_runtime.h> +#include <linux/power_supply.h> +#include <linux/clk.h> #include <asm/unaligned.h> diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c index 73b1ed20c8d5..b1adc69efd88 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c @@ -38,10 +38,12 @@ struct nouveau_barobj { static int nouveau_barobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *mem, u32 size, + struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + struct nouveau_device *device = nv_device(parent); struct nouveau_bar *bar = (void *)engine; + struct nouveau_mem *mem = data; struct nouveau_barobj *barobj; int ret; @@ -54,7 +56,13 @@ nouveau_barobj_ctor(struct nouveau_object *parent, if (ret) return ret; - barobj->iomem = bar->iomem + (u32)barobj->vma.offset; + barobj->iomem = ioremap(nv_device_resource_start(device, 3) + + (u32)barobj->vma.offset, mem->size << 12); + if (!barobj->iomem) { + nv_warn(bar, "PRAMIN ioremap failed\n"); + return -ENOMEM; + } + return 0; } @@ -63,8 +71,11 @@ nouveau_barobj_dtor(struct nouveau_object *object) { struct nouveau_bar *bar = (void *)object->engine; struct nouveau_barobj *barobj = (void *)object; - if (barobj->vma.node) + if (barobj->vma.node) { + if (barobj->iomem) + iounmap(barobj->iomem); bar->unmap(bar, &barobj->vma); + } nouveau_object_destroy(&barobj->base); } @@ -99,8 +110,12 @@ nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent, struct nouveau_mem *mem, struct nouveau_object **pobject) { struct nouveau_object *engine = nv_object(bar); - return nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass, - mem, 0, pobject); + struct nouveau_object *gpuobj; + int ret = nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass, + mem, 0, &gpuobj); + if (ret == 0) + *pobject = gpuobj; + return ret; } int @@ -108,7 +123,6 @@ nouveau_bar_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, int length, void **pobject) { - struct nouveau_device *device = nv_device(parent); struct nouveau_bar *bar; int ret; @@ -118,18 +132,12 @@ nouveau_bar_create_(struct nouveau_object *parent, if (ret) return ret; - if (nv_device_resource_len(device, 3) != 0) - bar->iomem = ioremap(nv_device_resource_start(device, 3), - nv_device_resource_len(device, 3)); - return 0; } void nouveau_bar_destroy(struct nouveau_bar *bar) { - if (bar->iomem) - iounmap(bar->iomem); nouveau_subdev_destroy(&bar->base); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c new file mode 100644 index 000000000000..bf877af9d3bd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014, 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 <subdev/bar.h> + +#include "priv.h" + +int +gk20a_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_bar *bar; + int ret; + + ret = nvc0_bar_ctor(parent, engine, oclass, data, size, pobject); + if (ret) + return ret; + + bar = (struct nouveau_bar *)*pobject; + bar->iomap_uncached = true; + + return 0; +} + +struct nouveau_oclass +gk20a_bar_oclass = { + .handle = NV_SUBDEV(BAR, 0xea), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gk20a_bar_ctor, + .dtor = nvc0_bar_dtor, + .init = nvc0_bar_init, + .fini = _nouveau_bar_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c index ca8139b9ab27..05a278bab247 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c @@ -133,7 +133,7 @@ nvc0_bar_init_vm(struct nvc0_bar_priv *priv, struct nvc0_bar_priv_vm *bar_vm, return 0; } -static int +int nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -169,7 +169,7 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -static void +void nvc0_bar_dtor(struct nouveau_object *object) { struct nvc0_bar_priv *priv = (void *)object; @@ -188,7 +188,7 @@ nvc0_bar_dtor(struct nouveau_object *object) nouveau_bar_destroy(&priv->base); } -static int +int nvc0_bar_init(struct nouveau_object *object) { struct nvc0_bar_priv *priv = (void *)object; @@ -200,7 +200,6 @@ nvc0_bar_init(struct nouveau_object *object) nv_mask(priv, 0x000200, 0x00000100, 0x00000000); nv_mask(priv, 0x000200, 0x00000100, 0x00000100); - nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12); if (priv->bar[0].mem) diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h index ffad8f337ead..3ee8b1476d00 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h @@ -23,4 +23,10 @@ int nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *, void nv84_bar_flush(struct nouveau_bar *); +int nvc0_bar_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nvc0_bar_dtor(struct nouveau_object *); +int nvc0_bar_init(struct nouveau_object *); + #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c new file mode 100644 index 000000000000..ac9617c5fc2a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c @@ -0,0 +1,136 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/M0205.h> + +u32 +nvbios_M0205Te(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) +{ + struct bit_entry bit_M; + u32 data = 0x00000000; + + if (!bit_entry(bios, 'M', &bit_M)) { + if (bit_M.version == 2 && bit_M.length > 0x08) + data = nv_ro32(bios, bit_M.offset + 0x05); + if (data) { + *ver = nv_ro08(bios, data + 0x00); + switch (*ver) { + case 0x10: + *hdr = nv_ro08(bios, data + 0x01); + *len = nv_ro08(bios, data + 0x02); + *ssz = nv_ro08(bios, data + 0x03); + *snr = nv_ro08(bios, data + 0x04); + *cnt = nv_ro08(bios, data + 0x05); + return data; + default: + break; + } + } + } + + return 0x00000000; +} + +u32 +nvbios_M0205Tp(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz, + struct nvbios_M0205T *info) +{ + u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, snr, ssz); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->freq = nv_ro16(bios, data + 0x06); + break; + default: + break; + } + return data; +} + +u32 +nvbios_M0205Ee(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u8 snr, ssz; + u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, &snr, &ssz); + if (data && idx < *cnt) { + data = data + *hdr + idx * (*len + (snr * ssz)); + *hdr = *len; + *cnt = snr; + *len = ssz; + return data; + } + return 0x00000000; +} + +u32 +nvbios_M0205Ep(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_M0205E *info) +{ + u32 data = nvbios_M0205Ee(bios, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->type = nv_ro08(bios, data + 0x00) & 0x0f; + return data; + default: + break; + } + return 0x00000000; +} + +u32 +nvbios_M0205Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr) +{ + + u8 cnt, len; + u32 data = nvbios_M0205Ee(bios, ent, ver, hdr, &cnt, &len); + if (data && idx < cnt) { + data = data + *hdr + idx * len; + *hdr = len; + return data; + } + return 0x00000000; +} + +u32 +nvbios_M0205Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr, + struct nvbios_M0205S *info) +{ + u32 data = nvbios_M0205Se(bios, ent, idx, ver, hdr); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->data = nv_ro08(bios, data + 0x00); + return data; + default: + break; + } + return 0x00000000; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c new file mode 100644 index 000000000000..b142a510e89f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c @@ -0,0 +1,137 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/M0209.h> + +u32 +nvbios_M0209Te(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) +{ + struct bit_entry bit_M; + u32 data = 0x00000000; + + if (!bit_entry(bios, 'M', &bit_M)) { + if (bit_M.version == 2 && bit_M.length > 0x0c) + data = nv_ro32(bios, bit_M.offset + 0x09); + if (data) { + *ver = nv_ro08(bios, data + 0x00); + switch (*ver) { + case 0x10: + *hdr = nv_ro08(bios, data + 0x01); + *len = nv_ro08(bios, data + 0x02); + *ssz = nv_ro08(bios, data + 0x03); + *snr = 1; + *cnt = nv_ro08(bios, data + 0x04); + return data; + default: + break; + } + } + } + + return 0x00000000; +} + +u32 +nvbios_M0209Ee(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u8 snr, ssz; + u32 data = nvbios_M0209Te(bios, ver, hdr, cnt, len, &snr, &ssz); + if (data && idx < *cnt) { + data = data + *hdr + idx * (*len + (snr * ssz)); + *hdr = *len; + *cnt = snr; + *len = ssz; + return data; + } + return 0x00000000; +} + +u32 +nvbios_M0209Ep(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_M0209E *info) +{ + u32 data = nvbios_M0209Ee(bios, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6; + info->bits = nv_ro08(bios, data + 0x00) & 0x3f; + info->modulo = nv_ro08(bios, data + 0x01); + info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; + info->v02_07 = nv_ro08(bios, data + 0x02) & 0x07; + info->v03 = nv_ro08(bios, data + 0x03); + return data; + default: + break; + } + return 0x00000000; +} + +u32 +nvbios_M0209Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr) +{ + + u8 cnt, len; + u32 data = nvbios_M0209Ee(bios, ent, ver, hdr, &cnt, &len); + if (data && idx < cnt) { + data = data + *hdr + idx * len; + *hdr = len; + return data; + } + return 0x00000000; +} + +u32 +nvbios_M0209Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr, + struct nvbios_M0209S *info) +{ + struct nvbios_M0209E M0209E; + u8 cnt, len; + u32 data = nvbios_M0209Ep(bios, ent, ver, hdr, &cnt, &len, &M0209E); + if (data) { + u32 i, data = nvbios_M0209Se(bios, ent, idx, ver, hdr); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + for (i = 0; i < ARRAY_SIZE(info->data); i++) { + u32 bits = (i % M0209E.modulo) * M0209E.bits; + u32 mask = (1ULL << M0209E.bits) - 1; + u16 off = bits / 8; + u8 mod = bits % 8; + info->data[i] = nv_ro32(bios, data + off); + info->data[i] = info->data[i] >> mod; + info->data[i] = info->data[i] & mask; + } + return data; + default: + break; + } + } + return 0x00000000; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 88606bfaf847..bd8d348385b3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -124,6 +124,7 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, struct dcb_output *outp) { u16 dcb = dcb_outp(bios, idx, ver, len); + memset(outp, 0x00, sizeof(*outp)); if (dcb) { if (*ver >= 0x20) { u32 conn = nv_ro32(bios, dcb + 0x00); diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c new file mode 100644 index 000000000000..e419892240f5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c @@ -0,0 +1,93 @@ +/* + * Copyright 2014 Martin Peres + * + * 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: Martin Peres + */ + +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/fan.h> + +u16 +nvbios_fan_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + struct bit_entry bit_P; + u16 fan = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2 && bit_P.length >= 0x5a) + fan = nv_ro16(bios, bit_P.offset + 0x58); + + if (fan) { + *ver = nv_ro08(bios, fan + 0); + switch (*ver) { + case 0x10: + *hdr = nv_ro08(bios, fan + 1); + *len = nv_ro08(bios, fan + 2); + *cnt = nv_ro08(bios, fan + 3); + return fan; + default: + break; + } + } + } + + return 0x0000; +} + +u16 +nvbios_fan_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr, + u8 *cnt, u8 *len) +{ + u16 data = nvbios_fan_table(bios, ver, hdr, cnt, len); + if (data && idx < *cnt) + return data + *hdr + (idx * (*len)); + return 0x0000; +} + +u16 +nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan) +{ + u8 ver, hdr, cnt, len; + + u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len); + if (data) { + u8 type = nv_ro08(bios, data + 0x00); + switch (type) { + case 0: + fan->type = NVBIOS_THERM_FAN_TOGGLE; + break; + case 1: + case 2: + /* TODO: Understand the difference between the two! */ + fan->type = NVBIOS_THERM_FAN_PWM; + break; + default: + fan->type = NVBIOS_THERM_FAN_UNK; + } + + fan->min_duty = nv_ro08(bios, data + 0x02); + fan->max_duty = nv_ro08(bios, data + 0x03); + + fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff; + } + return data; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c index 1811b2cb0472..585e69331ccc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c @@ -75,31 +75,39 @@ nvbios_rammapEe(struct nouveau_bios *bios, int idx, } u32 -nvbios_rammapEm(struct nouveau_bios *bios, u16 khz, - u8 *ver, u8 *hdr, u8 *cnt, u8 *len) -{ - int idx = 0; - u32 data; - while ((data = nvbios_rammapEe(bios, idx++, ver, hdr, cnt, len))) { - if (khz >= nv_ro16(bios, data + 0x00) && - khz <= nv_ro16(bios, data + 0x02)) - break; - } - return data; -} - -u32 -nvbios_rammapEp(struct nouveau_bios *bios, u16 khz, +nvbios_rammapEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p) { - u32 data = nvbios_rammapEm(bios, khz, ver, hdr, cnt, len); + u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp; memset(p, 0x00, sizeof(*p)); + p->rammap_ver = *ver; + p->rammap_hdr = *hdr; switch (!!data * *ver) { + case 0x10: + p->rammap_min = nv_ro16(bios, data + 0x00); + p->rammap_max = nv_ro16(bios, data + 0x02); + p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1; + p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3; + break; case 0x11: + p->rammap_min = nv_ro16(bios, data + 0x00); + p->rammap_max = nv_ro16(bios, data + 0x02); p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0; p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2; p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4; + temp = nv_ro32(bios, data + 0x09); + p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0; + p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9; + p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18; + p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19; + p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20; + p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25; + p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26; + p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27; + p->rammap_11_0d = nv_ro08(bios, data + 0x0d); + p->rammap_11_0e = nv_ro08(bios, data + 0x0e); + p->rammap_11_0f = nv_ro08(bios, data + 0x0f); p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2; break; default: @@ -110,6 +118,20 @@ nvbios_rammapEp(struct nouveau_bios *bios, u16 khz, } u32 +nvbios_rammapEm(struct nouveau_bios *bios, u16 mhz, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_ramcfg *info) +{ + int idx = 0; + u32 data; + while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) { + if (mhz >= info->rammap_min && mhz <= info->rammap_max) + break; + } + return data; +} + +u32 nvbios_rammapSe(struct nouveau_bios *bios, u32 data, u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr) @@ -129,8 +151,28 @@ nvbios_rammapSp(struct nouveau_bios *bios, u32 data, u8 *ver, u8 *hdr, struct nvbios_ramcfg *p) { data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr); + p->ramcfg_ver = *ver; + p->ramcfg_hdr = *hdr; switch (!!data * *ver) { + case 0x10: + p->ramcfg_timing = nv_ro08(bios, data + 0x01); + p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0; + p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1; + p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2; + p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; + p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; + p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5; + p->ramcfg_10_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; + p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; + p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0; + p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0; + p->ramcfg_10_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0; + p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0; + p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4; + break; case 0x11: + p->ramcfg_timing = nv_ro08(bios, data + 0x00); p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0; p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1; p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c index 350d44ab2ba2..46d955eb51eb 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c @@ -89,7 +89,15 @@ nvbios_timingEp(struct nouveau_bios *bios, int idx, struct nvbios_ramcfg *p) { u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp; + p->timing_ver = *ver; + p->timing_hdr = *hdr; switch (!!data * *ver) { + case 0x10: + p->timing_10_WR = nv_ro08(bios, data + 0x00); + p->timing_10_CL = nv_ro08(bios, data + 0x02); + p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07; + p->timing_10_CWL = nv_ro08(bios, data + 0x13); + break; case 0x20: p->timing[0] = nv_ro32(bios, data + 0x00); p->timing[1] = nv_ro32(bios, data + 0x04); diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c index 22351f594d2a..e51b72d47129 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c @@ -90,16 +90,20 @@ nouveau_cstate_prog(struct nouveau_clock *clk, cstate = &pstate->base; } - ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, +1); - if (ret && ret != -ENODEV) { - nv_error(clk, "failed to raise fan speed: %d\n", ret); - return ret; + if (ptherm) { + ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, +1); + if (ret && ret != -ENODEV) { + nv_error(clk, "failed to raise fan speed: %d\n", ret); + return ret; + } } - ret = volt->set_id(volt, cstate->voltage, +1); - if (ret && ret != -ENODEV) { - nv_error(clk, "failed to raise voltage: %d\n", ret); - return ret; + if (volt) { + ret = volt->set_id(volt, cstate->voltage, +1); + if (ret && ret != -ENODEV) { + nv_error(clk, "failed to raise voltage: %d\n", ret); + return ret; + } } ret = clk->calc(clk, cstate); @@ -108,13 +112,17 @@ nouveau_cstate_prog(struct nouveau_clock *clk, clk->tidy(clk); } - ret = volt->set_id(volt, cstate->voltage, -1); - if (ret && ret != -ENODEV) - nv_error(clk, "failed to lower voltage: %d\n", ret); + if (volt) { + ret = volt->set_id(volt, cstate->voltage, -1); + if (ret && ret != -ENODEV) + nv_error(clk, "failed to lower voltage: %d\n", ret); + } - ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, -1); - if (ret && ret != -ENODEV) - nv_error(clk, "failed to lower fan speed: %d\n", ret); + if (ptherm) { + ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, -1); + if (ret && ret != -ENODEV) + nv_error(clk, "failed to lower fan speed: %d\n", ret); + } return 0; } @@ -194,16 +202,23 @@ nouveau_pstate_prog(struct nouveau_clock *clk, int pstatei) return nouveau_cstate_prog(clk, pstate, 0); } -static int -nouveau_pstate_calc(struct nouveau_clock *clk) +static void +nouveau_pstate_work(struct work_struct *work) { - int pstate, ret = 0; + struct nouveau_clock *clk = container_of(work, typeof(*clk), work); + int pstate; - nv_trace(clk, "P %d U %d A %d T %d D %d\n", clk->pstate, - clk->ustate, clk->astate, clk->tstate, clk->dstate); + if (!atomic_xchg(&clk->waiting, 0)) + return; + clk->pwrsrc = power_supply_is_system_supplied(); - if (clk->state_nr && clk->ustate != -1) { - pstate = (clk->ustate < 0) ? clk->astate : clk->ustate; + nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n", + clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, + clk->astate, clk->tstate, clk->dstate); + + pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; + if (clk->state_nr && pstate != -1) { + pstate = (pstate < 0) ? clk->astate : pstate; pstate = min(pstate, clk->state_nr - 1 - clk->tstate); pstate = max(pstate, clk->dstate); } else { @@ -211,9 +226,26 @@ nouveau_pstate_calc(struct nouveau_clock *clk) } nv_trace(clk, "-> %d\n", pstate); - if (pstate != clk->pstate) - ret = nouveau_pstate_prog(clk, pstate); - return ret; + if (pstate != clk->pstate) { + int ret = nouveau_pstate_prog(clk, pstate); + if (ret) { + nv_error(clk, "error setting pstate %d: %d\n", + pstate, ret); + } + } + + wake_up_all(&clk->wait); + nvkm_notify_get(&clk->pwrsrc_ntfy); +} + +static int +nouveau_pstate_calc(struct nouveau_clock *clk, bool wait) +{ + atomic_set(&clk->waiting, 1); + schedule_work(&clk->work); + if (wait) + wait_event(clk->wait, !atomic_read(&clk->waiting)); + return 0; } static void @@ -361,17 +393,40 @@ nouveau_clock_ustate_update(struct nouveau_clock *clk, int req) req = i; } - clk->ustate = req; - return 0; + return req + 2; +} + +static int +nouveau_clock_nstate(struct nouveau_clock *clk, const char *mode, int arglen) +{ + int ret = 1; + + if (strncasecmpz(mode, "disabled", arglen)) { + char save = mode[arglen]; + long v; + + ((char *)mode)[arglen] = '\0'; + if (!kstrtol(mode, 0, &v)) { + ret = nouveau_clock_ustate_update(clk, v); + if (ret < 0) + ret = 1; + } + ((char *)mode)[arglen] = save; + } + + return ret - 2; } int -nouveau_clock_ustate(struct nouveau_clock *clk, int req) +nouveau_clock_ustate(struct nouveau_clock *clk, int req, int pwr) { int ret = nouveau_clock_ustate_update(clk, req); - if (ret) - return ret; - return nouveau_pstate_calc(clk); + if (ret >= 0) { + if (ret -= 2, pwr) clk->ustate_ac = ret; + else clk->ustate_dc = ret; + return nouveau_pstate_calc(clk, true); + } + return ret; } int @@ -381,7 +436,7 @@ nouveau_clock_astate(struct nouveau_clock *clk, int req, int rel) if ( rel) clk->astate += rel; clk->astate = min(clk->astate, clk->state_nr - 1); clk->astate = max(clk->astate, 0); - return nouveau_pstate_calc(clk); + return nouveau_pstate_calc(clk, true); } int @@ -391,7 +446,7 @@ nouveau_clock_tstate(struct nouveau_clock *clk, int req, int rel) if ( rel) clk->tstate += rel; clk->tstate = min(clk->tstate, 0); clk->tstate = max(clk->tstate, -(clk->state_nr - 1)); - return nouveau_pstate_calc(clk); + return nouveau_pstate_calc(clk, true); } int @@ -401,12 +456,30 @@ nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel) if ( rel) clk->dstate += rel; clk->dstate = min(clk->dstate, clk->state_nr - 1); clk->dstate = max(clk->dstate, 0); - return nouveau_pstate_calc(clk); + return nouveau_pstate_calc(clk, true); +} + +static int +nouveau_clock_pwrsrc(struct nvkm_notify *notify) +{ + struct nouveau_clock *clk = + container_of(notify, typeof(*clk), pwrsrc_ntfy); + nouveau_pstate_calc(clk, false); + return NVKM_NOTIFY_DROP; } /****************************************************************************** * subdev base class implementation *****************************************************************************/ + +int +_nouveau_clock_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_clock *clk = (void *)object; + nvkm_notify_put(&clk->pwrsrc_ntfy); + return nouveau_subdev_fini(&clk->base, suspend); +} + int _nouveau_clock_init(struct nouveau_object *object) { @@ -414,6 +487,10 @@ _nouveau_clock_init(struct nouveau_object *object) struct nouveau_clocks *clock = clk->domains; int ret; + ret = nouveau_subdev_init(&clk->base); + if (ret) + return ret; + memset(&clk->bstate, 0x00, sizeof(clk->bstate)); INIT_LIST_HEAD(&clk->bstate.list); clk->bstate.pstate = 0xff; @@ -434,7 +511,7 @@ _nouveau_clock_init(struct nouveau_object *object) clk->tstate = 0; clk->dstate = 0; clk->pstate = -1; - nouveau_pstate_calc(clk); + nouveau_pstate_calc(clk, true); return 0; } @@ -444,6 +521,8 @@ _nouveau_clock_dtor(struct nouveau_object *object) struct nouveau_clock *clk = (void *)object; struct nouveau_pstate *pstate, *temp; + nvkm_notify_fini(&clk->pwrsrc_ntfy); + list_for_each_entry_safe(pstate, temp, &clk->states, head) { nouveau_pstate_del(pstate); } @@ -456,6 +535,7 @@ nouveau_clock_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, struct nouveau_clocks *clocks, + struct nouveau_pstate *pstates, int nb_pstates, bool allow_reclock, int length, void **object) { @@ -472,29 +552,46 @@ nouveau_clock_create_(struct nouveau_object *parent, INIT_LIST_HEAD(&clk->states); clk->domains = clocks; - clk->ustate = -1; + clk->ustate_ac = -1; + clk->ustate_dc = -1; + + INIT_WORK(&clk->work, nouveau_pstate_work); + init_waitqueue_head(&clk->wait); + atomic_set(&clk->waiting, 0); - idx = 0; - do { - ret = nouveau_pstate_new(clk, idx++); - } while (ret == 0); + /* If no pstates are provided, try and fetch them from the BIOS */ + if (!pstates) { + idx = 0; + do { + ret = nouveau_pstate_new(clk, idx++); + } while (ret == 0); + } else { + for (idx = 0; idx < nb_pstates; idx++) + list_add_tail(&pstates[idx].head, &clk->states); + clk->state_nr = nb_pstates; + } clk->allow_reclock = allow_reclock; + ret = nvkm_notify_init(NULL, &device->event, nouveau_clock_pwrsrc, true, + NULL, 0, 0, &clk->pwrsrc_ntfy); + if (ret) + return ret; + mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen); if (mode) { - if (!strncasecmpz(mode, "disabled", arglen)) { - clk->ustate = -1; - } else { - char save = mode[arglen]; - long v; - - ((char *)mode)[arglen] = '\0'; - if (!kstrtol(mode, 0, &v)) - nouveau_clock_ustate_update(clk, v); - ((char *)mode)[arglen] = save; - } + clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen); + clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen); } + mode = nouveau_stropt(device->cfgopt, "NvClkModeAC", &arglen); + if (mode) + clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen); + + mode = nouveau_stropt(device->cfgopt, "NvClkModeDC", &arglen); + if (mode) + clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen); + + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c new file mode 100644 index 000000000000..425a8d5e9129 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c @@ -0,0 +1,665 @@ +/* + * Copyright (c) 2014, 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. + * + * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c + * + */ + +#define MHZ (1000 * 1000) + +#define MASK(w) ((1 << w) - 1) + +#define SYS_GPCPLL_CFG_BASE 0x00137000 +#define GPC_BCASE_GPCPLL_CFG_BASE 0x00132800 + +#define GPCPLL_CFG (SYS_GPCPLL_CFG_BASE + 0) +#define GPCPLL_CFG_ENABLE BIT(0) +#define GPCPLL_CFG_IDDQ BIT(1) +#define GPCPLL_CFG_LOCK_DET_OFF BIT(4) +#define GPCPLL_CFG_LOCK BIT(17) + +#define GPCPLL_COEFF (SYS_GPCPLL_CFG_BASE + 4) +#define GPCPLL_COEFF_M_SHIFT 0 +#define GPCPLL_COEFF_M_WIDTH 8 +#define GPCPLL_COEFF_N_SHIFT 8 +#define GPCPLL_COEFF_N_WIDTH 8 +#define GPCPLL_COEFF_P_SHIFT 16 +#define GPCPLL_COEFF_P_WIDTH 6 + +#define GPCPLL_CFG2 (SYS_GPCPLL_CFG_BASE + 0xc) +#define GPCPLL_CFG2_SETUP2_SHIFT 16 +#define GPCPLL_CFG2_PLL_STEPA_SHIFT 24 + +#define GPCPLL_CFG3 (SYS_GPCPLL_CFG_BASE + 0x18) +#define GPCPLL_CFG3_PLL_STEPB_SHIFT 16 + +#define GPCPLL_NDIV_SLOWDOWN (SYS_GPCPLL_CFG_BASE + 0x1c) +#define GPCPLL_NDIV_SLOWDOWN_NDIV_LO_SHIFT 0 +#define GPCPLL_NDIV_SLOWDOWN_NDIV_MID_SHIFT 8 +#define GPCPLL_NDIV_SLOWDOWN_STEP_SIZE_LO2MID_SHIFT 16 +#define GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT 22 +#define GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT 31 + +#define SEL_VCO (SYS_GPCPLL_CFG_BASE + 0x100) +#define SEL_VCO_GPC2CLK_OUT_SHIFT 0 + +#define GPC2CLK_OUT (SYS_GPCPLL_CFG_BASE + 0x250) +#define GPC2CLK_OUT_SDIV14_INDIV4_WIDTH 1 +#define GPC2CLK_OUT_SDIV14_INDIV4_SHIFT 31 +#define GPC2CLK_OUT_SDIV14_INDIV4_MODE 1 +#define GPC2CLK_OUT_VCODIV_WIDTH 6 +#define GPC2CLK_OUT_VCODIV_SHIFT 8 +#define GPC2CLK_OUT_VCODIV1 0 +#define GPC2CLK_OUT_VCODIV_MASK (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \ + GPC2CLK_OUT_VCODIV_SHIFT) +#define GPC2CLK_OUT_BYPDIV_WIDTH 6 +#define GPC2CLK_OUT_BYPDIV_SHIFT 0 +#define GPC2CLK_OUT_BYPDIV31 0x3c +#define GPC2CLK_OUT_INIT_MASK ((MASK(GPC2CLK_OUT_SDIV14_INDIV4_WIDTH) << \ + GPC2CLK_OUT_SDIV14_INDIV4_SHIFT)\ + | (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << GPC2CLK_OUT_VCODIV_SHIFT)\ + | (MASK(GPC2CLK_OUT_BYPDIV_WIDTH) << GPC2CLK_OUT_BYPDIV_SHIFT)) +#define GPC2CLK_OUT_INIT_VAL ((GPC2CLK_OUT_SDIV14_INDIV4_MODE << \ + GPC2CLK_OUT_SDIV14_INDIV4_SHIFT) \ + | (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT) \ + | (GPC2CLK_OUT_BYPDIV31 << GPC2CLK_OUT_BYPDIV_SHIFT)) + +#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG (GPC_BCASE_GPCPLL_CFG_BASE + 0xa0) +#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT 24 +#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \ + (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT) + +#include <subdev/clock.h> +#include <subdev/timer.h> + +#ifdef __KERNEL__ +#include <nouveau_platform.h> +#endif + +static const u8 pl_to_div[] = { +/* PL: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ +/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32, +}; + +/* All frequencies in Mhz */ +struct gk20a_clk_pllg_params { + u32 min_vco, max_vco; + u32 min_u, max_u; + u32 min_m, max_m; + u32 min_n, max_n; + u32 min_pl, max_pl; +}; + +static const struct gk20a_clk_pllg_params gk20a_pllg_params = { + .min_vco = 1000, .max_vco = 1700, + .min_u = 12, .max_u = 38, + .min_m = 1, .max_m = 255, + .min_n = 8, .max_n = 255, + .min_pl = 1, .max_pl = 32, +}; + +struct gk20a_clock_priv { + struct nouveau_clock base; + const struct gk20a_clk_pllg_params *params; + u32 m, n, pl; + u32 parent_rate; +}; +#define to_gk20a_clock(base) container_of(base, struct gk20a_clock_priv, base) + +static void +gk20a_pllg_read_mnp(struct gk20a_clock_priv *priv) +{ + u32 val; + + val = nv_rd32(priv, GPCPLL_COEFF); + priv->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); + priv->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH); + priv->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); +} + +static u32 +gk20a_pllg_calc_rate(struct gk20a_clock_priv *priv) +{ + u32 rate; + u32 divider; + + rate = priv->parent_rate * priv->n; + divider = priv->m * pl_to_div[priv->pl]; + do_div(rate, divider); + + return rate / 2; +} + +static int +gk20a_pllg_calc_mnp(struct gk20a_clock_priv *priv, unsigned long rate) +{ + u32 target_clk_f, ref_clk_f, target_freq; + u32 min_vco_f, max_vco_f; + u32 low_pl, high_pl, best_pl; + u32 target_vco_f, vco_f; + u32 best_m, best_n; + u32 u_f; + u32 m, n, n2; + u32 delta, lwv, best_delta = ~0; + u32 pl; + + target_clk_f = rate * 2 / MHZ; + ref_clk_f = priv->parent_rate / MHZ; + + max_vco_f = priv->params->max_vco; + min_vco_f = priv->params->min_vco; + best_m = priv->params->max_m; + best_n = priv->params->min_n; + best_pl = priv->params->min_pl; + + target_vco_f = target_clk_f + target_clk_f / 50; + if (max_vco_f < target_vco_f) + max_vco_f = target_vco_f; + + /* min_pl <= high_pl <= max_pl */ + high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f; + high_pl = min(high_pl, priv->params->max_pl); + high_pl = max(high_pl, priv->params->min_pl); + + /* min_pl <= low_pl <= max_pl */ + low_pl = min_vco_f / target_vco_f; + low_pl = min(low_pl, priv->params->max_pl); + low_pl = max(low_pl, priv->params->min_pl); + + /* Find Indices of high_pl and low_pl */ + for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) { + if (pl_to_div[pl] >= low_pl) { + low_pl = pl; + break; + } + } + for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) { + if (pl_to_div[pl] >= high_pl) { + high_pl = pl; + break; + } + } + + nv_debug(priv, "low_PL %d(div%d), high_PL %d(div%d)", low_pl, + pl_to_div[low_pl], high_pl, pl_to_div[high_pl]); + + /* Select lowest possible VCO */ + for (pl = low_pl; pl <= high_pl; pl++) { + target_vco_f = target_clk_f * pl_to_div[pl]; + for (m = priv->params->min_m; m <= priv->params->max_m; m++) { + u_f = ref_clk_f / m; + + if (u_f < priv->params->min_u) + break; + if (u_f > priv->params->max_u) + continue; + + n = (target_vco_f * m) / ref_clk_f; + n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f; + + if (n > priv->params->max_n) + break; + + for (; n <= n2; n++) { + if (n < priv->params->min_n) + continue; + if (n > priv->params->max_n) + break; + + vco_f = ref_clk_f * n / m; + + if (vco_f >= min_vco_f && vco_f <= max_vco_f) { + lwv = (vco_f + (pl_to_div[pl] / 2)) + / pl_to_div[pl]; + delta = abs(lwv - target_clk_f); + + if (delta < best_delta) { + best_delta = delta; + best_m = m; + best_n = n; + best_pl = pl; + + if (best_delta == 0) + goto found_match; + } + } + } + } + } + +found_match: + WARN_ON(best_delta == ~0); + + if (best_delta != 0) + nv_debug(priv, "no best match for target @ %dMHz on gpc_pll", + target_clk_f); + + priv->m = best_m; + priv->n = best_n; + priv->pl = best_pl; + + target_freq = gk20a_pllg_calc_rate(priv) / MHZ; + + nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", + target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]); + + return 0; +} + +static int +gk20a_pllg_slide(struct gk20a_clock_priv *priv, u32 n) +{ + u32 val; + int ramp_timeout; + + /* get old coefficients */ + val = nv_rd32(priv, GPCPLL_COEFF); + /* do nothing if NDIV is the same */ + if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH))) + return 0; + + /* setup */ + nv_mask(priv, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, + 0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT); + nv_mask(priv, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, + 0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT); + + /* pll slowdown mode */ + nv_mask(priv, GPCPLL_NDIV_SLOWDOWN, + BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT), + BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT)); + + /* new ndiv ready for ramp */ + val = nv_rd32(priv, GPCPLL_COEFF); + val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT); + val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT; + udelay(1); + nv_wr32(priv, GPCPLL_COEFF, val); + + /* dynamic ramp to new ndiv */ + val = nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN); + val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT; + udelay(1); + nv_wr32(priv, GPCPLL_NDIV_SLOWDOWN, val); + + for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) { + udelay(1); + val = nv_rd32(priv, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); + if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK) + break; + } + + /* exit slowdown mode */ + nv_mask(priv, GPCPLL_NDIV_SLOWDOWN, + BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) | + BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0); + nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN); + + if (ramp_timeout <= 0) { + nv_error(priv, "gpcpll dynamic ramp timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void +_gk20a_pllg_enable(struct gk20a_clock_priv *priv) +{ + nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); + nv_rd32(priv, GPCPLL_CFG); +} + +static void +_gk20a_pllg_disable(struct gk20a_clock_priv *priv) +{ + nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); + nv_rd32(priv, GPCPLL_CFG); +} + +static int +_gk20a_pllg_program_mnp(struct gk20a_clock_priv *priv, bool allow_slide) +{ + u32 val, cfg; + u32 m_old, pl_old, n_lo; + + /* get old coefficients */ + val = nv_rd32(priv, GPCPLL_COEFF); + m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); + pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); + + /* do NDIV slide if there is no change in M and PL */ + cfg = nv_rd32(priv, GPCPLL_CFG); + if (allow_slide && priv->m == m_old && priv->pl == pl_old && + (cfg & GPCPLL_CFG_ENABLE)) { + return gk20a_pllg_slide(priv, priv->n); + } + + /* slide down to NDIV_LO */ + n_lo = DIV_ROUND_UP(m_old * priv->params->min_vco, + priv->parent_rate / MHZ); + if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) { + int ret = gk20a_pllg_slide(priv, n_lo); + + if (ret) + return ret; + } + + /* split FO-to-bypass jump in halfs by setting out divider 1:2 */ + nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + 0x2 << GPC2CLK_OUT_VCODIV_SHIFT); + + /* put PLL in bypass before programming it */ + val = nv_rd32(priv, SEL_VCO); + val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); + udelay(2); + nv_wr32(priv, SEL_VCO, val); + + /* get out from IDDQ */ + val = nv_rd32(priv, GPCPLL_CFG); + if (val & GPCPLL_CFG_IDDQ) { + val &= ~GPCPLL_CFG_IDDQ; + nv_wr32(priv, GPCPLL_CFG, val); + nv_rd32(priv, GPCPLL_CFG); + udelay(2); + } + + _gk20a_pllg_disable(priv); + + nv_debug(priv, "%s: m=%d n=%d pl=%d\n", __func__, priv->m, priv->n, + priv->pl); + + n_lo = DIV_ROUND_UP(priv->m * priv->params->min_vco, + priv->parent_rate / MHZ); + val = priv->m << GPCPLL_COEFF_M_SHIFT; + val |= (allow_slide ? n_lo : priv->n) << GPCPLL_COEFF_N_SHIFT; + val |= priv->pl << GPCPLL_COEFF_P_SHIFT; + nv_wr32(priv, GPCPLL_COEFF, val); + + _gk20a_pllg_enable(priv); + + val = nv_rd32(priv, GPCPLL_CFG); + if (val & GPCPLL_CFG_LOCK_DET_OFF) { + val &= ~GPCPLL_CFG_LOCK_DET_OFF; + nv_wr32(priv, GPCPLL_CFG, val); + } + + if (!nouveau_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, + GPCPLL_CFG_LOCK)) { + nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__); + return -ETIMEDOUT; + } + + /* switch to VCO mode */ + nv_mask(priv, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); + + /* restore out divider 1:1 */ + val = nv_rd32(priv, GPC2CLK_OUT); + val &= ~GPC2CLK_OUT_VCODIV_MASK; + udelay(2); + nv_wr32(priv, GPC2CLK_OUT, val); + + /* slide up to new NDIV */ + return allow_slide ? gk20a_pllg_slide(priv, priv->n) : 0; +} + +static int +gk20a_pllg_program_mnp(struct gk20a_clock_priv *priv) +{ + int err; + + err = _gk20a_pllg_program_mnp(priv, true); + if (err) + err = _gk20a_pllg_program_mnp(priv, false); + + return err; +} + +static void +gk20a_pllg_disable(struct gk20a_clock_priv *priv) +{ + u32 val; + + /* slide to VCO min */ + val = nv_rd32(priv, GPCPLL_CFG); + if (val & GPCPLL_CFG_ENABLE) { + u32 coeff, m, n_lo; + + coeff = nv_rd32(priv, GPCPLL_COEFF); + m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); + n_lo = DIV_ROUND_UP(m * priv->params->min_vco, + priv->parent_rate / MHZ); + gk20a_pllg_slide(priv, n_lo); + } + + /* put PLL in bypass before disabling it */ + nv_mask(priv, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); + + _gk20a_pllg_disable(priv); +} + +#define GK20A_CLK_GPC_MDIV 1000 + +static struct nouveau_clocks +gk20a_domains[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, + { nv_clk_src_max } +}; + +static struct nouveau_pstate +gk20a_pstates[] = { + { + .base = { + .domain[nv_clk_src_gpc] = 72000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 108000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 180000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 252000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 324000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 396000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 468000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 540000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 612000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 648000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 684000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 708000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 756000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 804000, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 852000, + }, + }, +}; + +static int +gk20a_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) +{ + struct gk20a_clock_priv *priv = (void *)clk; + + switch (src) { + case nv_clk_src_crystal: + return nv_device(clk)->crystal; + case nv_clk_src_gpc: + gk20a_pllg_read_mnp(priv); + return gk20a_pllg_calc_rate(priv) / GK20A_CLK_GPC_MDIV; + default: + nv_error(clk, "invalid clock source %d\n", src); + return -EINVAL; + } +} + +static int +gk20a_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) +{ + struct gk20a_clock_priv *priv = (void *)clk; + + return gk20a_pllg_calc_mnp(priv, cstate->domain[nv_clk_src_gpc] * + GK20A_CLK_GPC_MDIV); +} + +static int +gk20a_clock_prog(struct nouveau_clock *clk) +{ + struct gk20a_clock_priv *priv = (void *)clk; + + return gk20a_pllg_program_mnp(priv); +} + +static void +gk20a_clock_tidy(struct nouveau_clock *clk) +{ +} + +static int +gk20a_clock_fini(struct nouveau_object *object, bool suspend) +{ + struct gk20a_clock_priv *priv = (void *)object; + int ret; + + ret = nouveau_clock_fini(&priv->base, false); + + gk20a_pllg_disable(priv); + + return ret; +} + +static int +gk20a_clock_init(struct nouveau_object *object) +{ + struct gk20a_clock_priv *priv = (void *)object; + int ret; + + nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); + + ret = nouveau_clock_init(&priv->base); + if (ret) + return ret; + + ret = gk20a_clock_prog(&priv->base); + if (ret) { + nv_error(priv, "cannot initialize clock\n"); + return ret; + } + + return 0; +} + +static int +gk20a_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gk20a_clock_priv *priv; + struct nouveau_platform_device *plat; + int ret; + int i; + + /* Finish initializing the pstates */ + for (i = 0; i < ARRAY_SIZE(gk20a_pstates); i++) { + INIT_LIST_HEAD(&gk20a_pstates[i].list); + gk20a_pstates[i].pstate = i + 1; + } + + ret = nouveau_clock_create(parent, engine, oclass, gk20a_domains, + gk20a_pstates, ARRAY_SIZE(gk20a_pstates), true, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->params = &gk20a_pllg_params; + + plat = nv_device_to_platform(nv_device(parent)); + priv->parent_rate = clk_get_rate(plat->gpu->clk); + nv_info(priv, "parent clock rate: %d Mhz\n", priv->parent_rate / MHZ); + + priv->base.read = gk20a_clock_read; + priv->base.calc = gk20a_clock_calc; + priv->base.prog = gk20a_clock_prog; + priv->base.tidy = gk20a_clock_tidy; + + return 0; +} + +struct nouveau_oclass +gk20a_clock_oclass = { + .handle = NV_SUBDEV(CLOCK, 0xea), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gk20a_clock_ctor, + .dtor = _nouveau_subdev_dtor, + .init = gk20a_clock_init, + .fini = gk20a_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c index eb2d4425a49e..4c48232686be 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c @@ -82,8 +82,8 @@ nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv04_clock_priv *priv; int ret; - ret = nouveau_clock_create(parent, engine, oclass, nv04_domain, false, - &priv); + ret = nouveau_clock_create(parent, engine, oclass, nv04_domain, NULL, 0, + false, &priv); *pobject = nv_object(priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c index 8a9e16839791..08368fe97029 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c @@ -213,8 +213,8 @@ nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv40_clock_priv *priv; int ret; - ret = nouveau_clock_create(parent, engine, oclass, nv40_domain, true, - &priv); + ret = nouveau_clock_create(parent, engine, oclass, nv40_domain, NULL, 0, + true, &priv); *pobject = nv_object(priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c index 8c132772ba9e..5070ebc260f8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c @@ -507,7 +507,7 @@ nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, int ret; ret = nouveau_clock_create(parent, engine, oclass, pclass->domains, - false, &priv); + NULL, 0, false, &priv); *pobject = nv_object(priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index 9fb58354a80b..094551d8ad9b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -20,8 +20,10 @@ * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Ben Skeggs + * Roy Spliet */ +#include <engine/fifo.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> #include <subdev/timer.h> @@ -42,9 +44,17 @@ static u32 read_vco(struct nva3_clock_priv *priv, int clk) { u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4)); - if ((sctl & 0x00000030) != 0x00000030) + + switch (sctl & 0x00000030) { + case 0x00000000: + return nv_device(priv)->crystal; + case 0x00000020: return read_pll(priv, 0x41, 0x00e820); - return read_pll(priv, 0x42, 0x00e8a0); + case 0x00000030: + return read_pll(priv, 0x42, 0x00e8a0); + default: + return 0; + } } static u32 @@ -66,14 +76,25 @@ read_clk(struct nva3_clock_priv *priv, int clk, bool ignore_en) if (!ignore_en && !(sctl & 0x00000100)) return 0; + /* out_alt */ + if (sctl & 0x00000400) + return 108000; + + /* vco_out */ switch (sctl & 0x00003000) { case 0x00000000: - return nv_device(priv)->crystal; + if (!(sctl & 0x00000200)) + return nv_device(priv)->crystal; + return 0; case 0x00002000: if (sctl & 0x00000040) return 108000; return 100000; case 0x00003000: + /* vco_enable */ + if (!(sctl & 0x00000001)) + return 0; + sclk = read_vco(priv, clk); sdiv = ((sctl & 0x003f0000) >> 16) + 2; return (sclk * 2) / sdiv; @@ -95,7 +116,9 @@ read_pll(struct nva3_clock_priv *priv, int clk, u32 pll) N = (coef & 0x0000ff00) >> 8; P = (coef & 0x003f0000) >> 16; - /* no post-divider on these.. */ + /* no post-divider on these.. + * XXX: it looks more like two post-"dividers" that + * cross each other out in the default RPLL config */ if ((pll & 0x00ff00) == 0x00e800) P = 1; @@ -114,13 +137,13 @@ static int nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) { struct nva3_clock_priv *priv = (void *)clk; + u32 hsrc; switch (src) { case nv_clk_src_crystal: return nv_device(priv)->crystal; - case nv_clk_src_href: - return 100000; case nv_clk_src_core: + case nv_clk_src_core_intm: return read_pll(priv, 0x00, 0x4200); case nv_clk_src_shader: return read_pll(priv, 0x01, 0x4220); @@ -132,24 +155,33 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) return read_clk(priv, 0x21, false); case nv_clk_src_daemon: return read_clk(priv, 0x25, false); + case nv_clk_src_host: + hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28; + switch (hsrc) { + case 0: + return read_clk(priv, 0x1d, false); + case 2: + case 3: + return 277000; + default: + nv_error(clk, "unknown HOST clock source %d\n", hsrc); + return -EINVAL; + } default: nv_error(clk, "invalid clock source %d\n", src); return -EINVAL; } + + return 0; } int -nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, +nva3_clk_info(struct nouveau_clock *clock, int clk, u32 khz, struct nva3_clock_info *info) { - struct nouveau_bios *bios = nouveau_bios(clock); struct nva3_clock_priv *priv = (void *)clock; - struct nvbios_pll limits; - u32 oclk, sclk, sdiv; - int P, N, M, diff; - int ret; + u32 oclk, sclk, sdiv, diff; - info->pll = 0; info->clk = 0; switch (khz) { @@ -164,43 +196,69 @@ nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, return khz; default: sclk = read_vco(priv, clk); - sdiv = min((sclk * 2) / (khz - 2999), (u32)65); - /* if the clock has a PLL attached, and we can get a within - * [-2, 3) MHz of a divider, we'll disable the PLL and use - * the divider instead. - * - * divider can go as low as 2, limited here because NVIDIA + sdiv = min((sclk * 2) / khz, (u32)65); + oclk = (sclk * 2) / sdiv; + diff = ((khz + 3000) - oclk); + + /* When imprecise, play it safe and aim for a clock lower than + * desired rather than higher */ + if (diff < 0) { + sdiv++; + oclk = (sclk * 2) / sdiv; + } + + /* divider can go as low as 2, limited here because NVIDIA * and the VBIOS on my NVA8 seem to prefer using the PLL * for 810MHz - is there a good reason? - */ + * XXX: PLLs with refclk 810MHz? */ if (sdiv > 4) { - oclk = (sclk * 2) / sdiv; - diff = khz - oclk; - if (!pll || (diff >= -2000 && diff < 3000)) { - info->clk = (((sdiv - 2) << 16) | 0x00003100); - return oclk; - } + info->clk = (((sdiv - 2) << 16) | 0x00003100); + return oclk; } - if (!pll) - return -ERANGE; break; } + return -ERANGE; +} + +int +nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, + struct nva3_clock_info *info) +{ + struct nouveau_bios *bios = nouveau_bios(clock); + struct nva3_clock_priv *priv = (void *)clock; + struct nvbios_pll limits; + int P, N, M, diff; + int ret; + + info->pll = 0; + + /* If we can get a within [-2, 3) MHz of a divider, we'll disable the + * PLL and use the divider instead. */ + ret = nva3_clk_info(clock, clk, khz, info); + diff = khz - ret; + if (!pll || (diff >= -2000 && diff < 3000)) { + goto out; + } + + /* Try with PLL */ ret = nvbios_pll_parse(bios, pll, &limits); if (ret) return ret; - limits.refclk = read_clk(priv, clk - 0x10, true); - if (!limits.refclk) + ret = nva3_clk_info(clock, clk - 0x10, limits.refclk, info); + if (ret != limits.refclk) return -EINVAL; ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); if (ret >= 0) { - info->clk = nv_rd32(priv, 0x4120 + (clk * 4)); info->pll = (P << 16) | (N << 8) | M; } +out: + info->fb_delay = max(((khz + 7566) / 15133), (u32) 18); + return ret ? ret : -ERANGE; } @@ -208,13 +266,76 @@ static int calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate, int clk, u32 pll, int idx) { - int ret = nva3_clock_info(&priv->base, clk, pll, cstate->domain[idx], + int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx], &priv->eng[idx]); if (ret >= 0) return 0; return ret; } +static int +calc_host(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate) +{ + int ret = 0; + u32 kHz = cstate->domain[nv_clk_src_host]; + struct nva3_clock_info *info = &priv->eng[nv_clk_src_host]; + + if (kHz == 277000) { + info->clk = 0; + info->host_out = NVA3_HOST_277; + return 0; + } + + info->host_out = NVA3_HOST_CLK; + + ret = nva3_clk_info(&priv->base, 0x1d, kHz, info); + if (ret >= 0) + return 0; + return ret; +} + +int +nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(clk); + + /* halt and idle execution engines */ + nv_mask(clk, 0x020060, 0x00070000, 0x00000000); + nv_mask(clk, 0x002504, 0x00000001, 0x00000001); + /* Wait until the interrupt handler is finished */ + if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) + return -EBUSY; + + if (pfifo) + pfifo->pause(pfifo, flags); + + if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) + return -EIO; + if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) + return -EIO; + + return 0; +} + +void +nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(clk); + + if (pfifo && flags) + pfifo->start(pfifo, flags); + + nv_mask(clk, 0x002504, 0x00000001, 0x00000000); + nv_mask(clk, 0x020060, 0x00070000, 0x00040000); +} + +static void +disable_clk_src(struct nva3_clock_priv *priv, u32 src) +{ + nv_mask(priv, src, 0x00000100, 0x00000000); + nv_mask(priv, src, 0x00000001, 0x00000000); +} + static void prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx) { @@ -223,24 +344,35 @@ prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx) const u32 src1 = 0x004160 + (clk * 4); const u32 ctrl = pll + 0; const u32 coef = pll + 4; + u32 bypass; if (info->pll) { - nv_mask(priv, src0, 0x00000101, 0x00000101); + /* Always start from a non-PLL clock */ + bypass = nv_rd32(priv, ctrl) & 0x00000008; + if (!bypass) { + nv_mask(priv, src1, 0x00000101, 0x00000101); + nv_mask(priv, ctrl, 0x00000008, 0x00000008); + udelay(20); + } + + nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk); nv_wr32(priv, coef, info->pll); nv_mask(priv, ctrl, 0x00000015, 0x00000015); nv_mask(priv, ctrl, 0x00000010, 0x00000000); - nv_wait(priv, ctrl, 0x00020000, 0x00020000); + if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) { + nv_mask(priv, ctrl, 0x00000010, 0x00000010); + nv_mask(priv, src0, 0x00000101, 0x00000000); + return; + } nv_mask(priv, ctrl, 0x00000010, 0x00000010); nv_mask(priv, ctrl, 0x00000008, 0x00000000); - nv_mask(priv, src1, 0x00000100, 0x00000000); - nv_mask(priv, src1, 0x00000001, 0x00000000); + disable_clk_src(priv, src1); } else { nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk); nv_mask(priv, ctrl, 0x00000018, 0x00000018); udelay(20); nv_mask(priv, ctrl, 0x00000001, 0x00000000); - nv_mask(priv, src0, 0x00000100, 0x00000000); - nv_mask(priv, src0, 0x00000001, 0x00000000); + disable_clk_src(priv, src0); } } @@ -251,18 +383,72 @@ prog_clk(struct nva3_clock_priv *priv, int clk, int idx) nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk); } +static void +prog_host(struct nva3_clock_priv *priv) +{ + struct nva3_clock_info *info = &priv->eng[nv_clk_src_host]; + u32 hsrc = (nv_rd32(priv, 0xc040)); + + switch (info->host_out) { + case NVA3_HOST_277: + if ((hsrc & 0x30000000) == 0) { + nv_wr32(priv, 0xc040, hsrc | 0x20000000); + disable_clk_src(priv, 0x4194); + } + break; + case NVA3_HOST_CLK: + prog_clk(priv, 0x1d, nv_clk_src_host); + if ((hsrc & 0x30000000) >= 0x20000000) { + nv_wr32(priv, 0xc040, hsrc & ~0x30000000); + } + break; + default: + break; + } + + /* This seems to be a clock gating factor on idle, always set to 64 */ + nv_wr32(priv, 0xc044, 0x3e); +} + +static void +prog_core(struct nva3_clock_priv *priv, int idx) +{ + struct nva3_clock_info *info = &priv->eng[idx]; + u32 fb_delay = nv_rd32(priv, 0x10002c); + + if (fb_delay < info->fb_delay) + nv_wr32(priv, 0x10002c, info->fb_delay); + + prog_pll(priv, 0x00, 0x004200, idx); + + if (fb_delay > info->fb_delay) + nv_wr32(priv, 0x10002c, info->fb_delay); +} + static int nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) { struct nva3_clock_priv *priv = (void *)clk; + struct nva3_clock_info *core = &priv->eng[nv_clk_src_core]; int ret; if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) || (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) || (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) || - (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec))) + (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) || + (ret = calc_host(priv, cstate))) return ret; + /* XXX: Should be reading the highest bit in the VBIOS clock to decide + * whether to use a PLL or not... but using a PLL defeats the purpose */ + if (core->pll) { + ret = nva3_clk_info(clk, 0x10, + cstate->domain[nv_clk_src_core_intm], + &priv->eng[nv_clk_src_core_intm]); + if (ret < 0) + return ret; + } + return 0; } @@ -270,11 +456,31 @@ static int nva3_clock_prog(struct nouveau_clock *clk) { struct nva3_clock_priv *priv = (void *)clk; - prog_pll(priv, 0x00, 0x004200, nv_clk_src_core); + struct nva3_clock_info *core = &priv->eng[nv_clk_src_core]; + int ret = 0; + unsigned long flags; + unsigned long *f = &flags; + + ret = nva3_clock_pre(clk, f); + if (ret) + goto out; + + if (core->pll) + prog_core(priv, nv_clk_src_core_intm); + + prog_core(priv, nv_clk_src_core); prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader); prog_clk(priv, 0x20, nv_clk_src_disp); prog_clk(priv, 0x21, nv_clk_src_vdec); - return 0; + prog_host(priv); + +out: + if (ret == -EBUSY) + f = NULL; + + nva3_clock_post(clk, f); + + return ret; } static void @@ -284,13 +490,14 @@ nva3_clock_tidy(struct nouveau_clock *clk) static struct nouveau_clocks nva3_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0x00, 0, "core", 1000 }, - { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, - { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0x03 }, - { nv_clk_src_disp , 0x04 }, + { nv_clk_src_crystal , 0xff }, + { nv_clk_src_core , 0x00, 0, "core", 1000 }, + { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, + { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x03 }, + { nv_clk_src_disp , 0x04 }, + { nv_clk_src_host , 0x05 }, + { nv_clk_src_core_intm, 0x06 }, { nv_clk_src_max } }; @@ -302,8 +509,8 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nva3_clock_priv *priv; int ret; - ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, false, - &priv); + ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, NULL, 0, + false, &priv); *pobject = nv_object(priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h index 6229a509b42e..a45a1038b12f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h @@ -6,9 +6,15 @@ struct nva3_clock_info { u32 clk; u32 pll; + enum { + NVA3_HOST_277, + NVA3_HOST_CLK, + } host_out; + u32 fb_delay; }; -int nva3_clock_info(struct nouveau_clock *, int, u32, u32, +int nva3_pll_info(struct nouveau_clock *, int, u32, u32, struct nva3_clock_info *); - +int nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags); +void nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c index 6a65fc9e9663..54aeab8005a0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c @@ -28,6 +28,7 @@ #include <subdev/timer.h> #include <subdev/clock.h> +#include "nva3.h" #include "pll.h" struct nvaa_clock_priv { @@ -299,25 +300,14 @@ static int nvaa_clock_prog(struct nouveau_clock *clk) { struct nvaa_clock_priv *priv = (void *)clk; - struct nouveau_fifo *pfifo = nouveau_fifo(clk); + u32 pllmask = 0, mast; unsigned long flags; - u32 pllmask = 0, mast, ptherm_gate; - int ret = -EBUSY; - - /* halt and idle execution engines */ - ptherm_gate = nv_mask(clk, 0x020060, 0x00070000, 0x00000000); - nv_mask(clk, 0x002504, 0x00000001, 0x00000001); - /* Wait until the interrupt handler is finished */ - if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) - goto resume; - - if (pfifo) - pfifo->pause(pfifo, &flags); + unsigned long *f = &flags; + int ret = 0; - if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) - goto resume; - if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) - goto resume; + ret = nva3_clock_pre(clk, f); + if (ret) + goto out; /* First switch to safe clocks: href */ mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640); @@ -375,15 +365,8 @@ nvaa_clock_prog(struct nouveau_clock *clk) } nv_wr32(clk, 0xc054, mast); - ret = 0; resume: - if (pfifo) - pfifo->start(pfifo, &flags); - - nv_mask(clk, 0x002504, 0x00000001, 0x00000000); - nv_wr32(clk, 0x020060, ptherm_gate); - /* Disable some PLLs and dividers when unused */ if (priv->csrc != nv_clk_src_core) { nv_wr32(clk, 0x4040, 0x00000000); @@ -395,6 +378,12 @@ resume: nv_mask(clk, 0x4020, 0x80000000, 0x00000000); } +out: + if (ret == -EBUSY) + f = NULL; + + nva3_clock_post(clk, f); + return ret; } @@ -421,8 +410,8 @@ nvaa_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvaa_clock_priv *priv; int ret; - ret = nouveau_clock_create(parent, engine, oclass, nvaa_domains, true, - &priv); + ret = nouveau_clock_create(parent, engine, oclass, nvaa_domains, NULL, + 0, true, &priv); *pobject = nv_object(priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index dbf8517f54da..1234abaab2db 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -437,8 +437,8 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_clock_priv *priv; int ret; - ret = nouveau_clock_create(parent, engine, oclass, nvc0_domain, false, - &priv); + ret = nouveau_clock_create(parent, engine, oclass, nvc0_domain, NULL, 0, + false, &priv); *pobject = nv_object(priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c index 0e62a3240144..7eccad57512e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c @@ -475,8 +475,8 @@ nve0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nve0_clock_priv *priv; int ret; - ret = nouveau_clock_create(parent, engine, oclass, nve0_domain, true, - &priv); + ret = nouveau_clock_create(parent, engine, oclass, nve0_domain, NULL, 0, + true, &priv); *pobject = nv_object(priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h index 4fe49cf4c99a..6103484fea72 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h @@ -26,22 +26,8 @@ #include <core/device.h> -#define NV04_PFB_BOOT_0 0x00100000 -# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 -# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 -# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 -# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 -# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 +#include <subdev/fb/regsnv04.h> + #define NV04_PFB_DEBUG_0 0x00100080 # define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001 # define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010 diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c index 66fe959b4f74..7fbbe05d5c60 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c @@ -40,7 +40,7 @@ nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts) int WL, CL, WR, at[2], dt, ds; int rq = ram->freq < 1000000; /* XXX */ - switch (ram->ramcfg.version) { + switch (ram->next->bios.ramcfg_ver) { case 0x11: pd = ram->next->bios.ramcfg_11_01_80; lf = ram->next->bios.ramcfg_11_01_40; @@ -54,7 +54,7 @@ nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts) return -ENOSYS; } - switch (ram->timing.version) { + switch (ram->next->bios.timing_ver) { case 0x20: WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7; CL = (ram->next->bios.timing[1] & 0x0000001f); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c index a16024a74771..fde42e4d1b56 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c @@ -27,6 +27,20 @@ struct gk20a_fb_priv { }; static int +gk20a_fb_init(struct nouveau_object *object) +{ + struct gk20a_fb_priv *priv = (void *)object; + int ret; + + ret = nouveau_fb_init(&priv->base); + if (ret) + return ret; + + nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ + return 0; +} + +static int gk20a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -48,7 +62,7 @@ gk20a_fb_oclass = &(struct nouveau_fb_impl) { .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = gk20a_fb_ctor, .dtor = _nouveau_fb_dtor, - .init = _nouveau_fb_init, + .init = gk20a_fb_init, .fini = _nouveau_fb_fini, }, .memtype = nvc0_fb_memtype_valid, diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c index f003c1b1893f..2209ade63339 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c @@ -45,7 +45,7 @@ nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { + if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */ else tile->zcomp = 0x04000000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c index f34f4223210b..e2a66c355c50 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c @@ -32,7 +32,7 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { + if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */ else tile->zcomp = 0x00200000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c index 69093f7151f0..cbec402ba5b9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c @@ -51,7 +51,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { + if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */ else tile->zcomp |= 0x02000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c index 161b06e8fc3f..b2cf8c69fb2e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c @@ -32,7 +32,7 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { + if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */ else tile->zcomp |= 0x08000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c index 2dd3d0aab6bb..b4cdae2a3b2f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c @@ -32,7 +32,7 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { + if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */ else tile->zcomp |= 0x20000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c index 95a115ab0c86..52814258c212 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c @@ -33,7 +33,7 @@ nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, u32 tiles = DIV_ROUND_UP(size, 0x80); u32 tags = round_up(tiles / pfb->ram->parts, 0x100); if ( (flags & 2) && - !nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { + !nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */ tile->zcomp |= ((tile->tag->offset ) >> 8); tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index 1fc55c1e91a1..4150b0d10af8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -250,9 +250,11 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (priv->r100c08_page) { - priv->r100c08 = nv_device_map_page(device, priv->r100c08_page); - if (!priv->r100c08) - nv_warn(priv, "failed 0x100c08 page map\n"); + priv->r100c08 = dma_map_page(nv_device_base(device), + priv->r100c08_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(nv_device_base(device), priv->r100c08)) + return -EFAULT; } else { nv_warn(priv, "failed 0x100c08 page alloc\n"); } @@ -268,7 +270,8 @@ nv50_fb_dtor(struct nouveau_object *object) struct nv50_fb_priv *priv = (void *)object; if (priv->r100c08_page) { - nv_device_unmap_page(device, priv->r100c08); + dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE, + DMA_BIDIRECTIONAL); __free_page(priv->r100c08_page); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c index 0670ae33ee45..32f28dc73ef2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c @@ -60,6 +60,7 @@ nvc0_fb_init(struct nouveau_object *object) if (priv->r100c10_page) nv_wr32(priv, 0x100c10, priv->r100c10 >> 8); + nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ return 0; } @@ -70,7 +71,8 @@ nvc0_fb_dtor(struct nouveau_object *object) struct nvc0_fb_priv *priv = (void *)object; if (priv->r100c10_page) { - nv_device_unmap_page(device, priv->r100c10); + dma_unmap_page(nv_device_base(device), priv->r100c10, PAGE_SIZE, + DMA_BIDIRECTIONAL); __free_page(priv->r100c10_page); } @@ -93,8 +95,10 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (priv->r100c10_page) { - priv->r100c10 = nv_device_map_page(device, priv->r100c10_page); - if (!priv->r100c10) + priv->r100c10 = dma_map_page(nv_device_base(device), + priv->r100c10_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(nv_device_base(device), priv->r100c10)) return -EFAULT; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h index 82273f832e42..60322e906dd4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h @@ -35,6 +35,7 @@ extern struct nouveau_oclass nve0_ram_oclass; extern struct nouveau_oclass gk20a_ram_oclass; extern struct nouveau_oclass gm107_ram_oclass; +int nouveau_sddr2_calc(struct nouveau_ram *ram); int nouveau_sddr3_calc(struct nouveau_ram *ram); int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h index 2af9cfd2c60f..d1fbbe4b00a2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h @@ -12,16 +12,32 @@ struct ramfuc { struct ramfuc_reg { int sequence; bool force; - u32 addr[2]; + u32 addr; + u32 stride; /* in bytes */ + u32 mask; u32 data; }; static inline struct ramfuc_reg +ramfuc_stride(u32 addr, u32 stride, u32 mask) +{ + return (struct ramfuc_reg) { + .sequence = 0, + .addr = addr, + .stride = stride, + .mask = mask, + .data = 0xdeadbeef, + }; +} + +static inline struct ramfuc_reg ramfuc_reg2(u32 addr1, u32 addr2) { return (struct ramfuc_reg) { .sequence = 0, - .addr = { addr1, addr2 }, + .addr = addr1, + .stride = addr2 - addr1, + .mask = 0x3, .data = 0xdeadbeef, }; } @@ -29,7 +45,13 @@ ramfuc_reg2(u32 addr1, u32 addr2) static noinline struct ramfuc_reg ramfuc_reg(u32 addr) { - return ramfuc_reg2(addr, addr); + return (struct ramfuc_reg) { + .sequence = 0, + .addr = addr, + .stride = 0, + .mask = 0x1, + .data = 0xdeadbeef, + }; } static inline int @@ -62,18 +84,25 @@ static inline u32 ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg) { if (reg->sequence != ram->sequence) - reg->data = nv_rd32(ram->pfb, reg->addr[0]); + reg->data = nv_rd32(ram->pfb, reg->addr); return reg->data; } static inline void ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data) { + unsigned int mask, off = 0; + reg->sequence = ram->sequence; reg->data = data; - if (reg->addr[0] != reg->addr[1]) - nouveau_memx_wr32(ram->memx, reg->addr[1], reg->data); - nouveau_memx_wr32(ram->memx, reg->addr[0], reg->data); + + for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) { + if (mask & 1) { + nouveau_memx_wr32(ram->memx, reg->addr+off, reg->data); + } + + off += reg->stride; + } } static inline void @@ -105,14 +134,35 @@ ramfuc_nsec(struct ramfuc *ram, u32 nsec) nouveau_memx_nsec(ram->memx, nsec); } -#define ram_init(s,p) ramfuc_init(&(s)->base, (p)) -#define ram_exec(s,e) ramfuc_exec(&(s)->base, (e)) -#define ram_have(s,r) ((s)->r_##r.addr[0] != 0x000000) -#define ram_rd32(s,r) ramfuc_rd32(&(s)->base, &(s)->r_##r) -#define ram_wr32(s,r,d) ramfuc_wr32(&(s)->base, &(s)->r_##r, (d)) -#define ram_nuke(s,r) ramfuc_nuke(&(s)->base, &(s)->r_##r) -#define ram_mask(s,r,m,d) ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d)) -#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n)) -#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n)) +static inline void +ramfuc_wait_vblank(struct ramfuc *ram) +{ + nouveau_memx_wait_vblank(ram->memx); +} + +static inline void +ramfuc_block(struct ramfuc *ram) +{ + nouveau_memx_block(ram->memx); +} + +static inline void +ramfuc_unblock(struct ramfuc *ram) +{ + nouveau_memx_unblock(ram->memx); +} + +#define ram_init(s,p) ramfuc_init(&(s)->base, (p)) +#define ram_exec(s,e) ramfuc_exec(&(s)->base, (e)) +#define ram_have(s,r) ((s)->r_##r.addr != 0x000000) +#define ram_rd32(s,r) ramfuc_rd32(&(s)->base, &(s)->r_##r) +#define ram_wr32(s,r,d) ramfuc_wr32(&(s)->base, &(s)->r_##r, (d)) +#define ram_nuke(s,r) ramfuc_nuke(&(s)->base, &(s)->r_##r) +#define ram_mask(s,r,m,d) ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d)) +#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n)) +#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n)) +#define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base) +#define ram_block(s) ramfuc_block(&(s)->base) +#define ram_unblock(s) ramfuc_unblock(&(s)->base) #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c index e781080d3327..1972268d1410 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c @@ -22,22 +22,7 @@ * Authors: Ben Skeggs */ -#define NV04_PFB_BOOT_0 0x00100000 -# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 -# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 -# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 -# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 -# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 +#include <subdev/fb/regsnv04.h> #include "priv.h" diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c index e5d12c24cc43..64a983c96625 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c @@ -280,7 +280,7 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, if (align == 16) { int n = (max >> 4) * comp; - ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag); + ret = nouveau_mm_head(tags, 0, 1, n, n, 1, &mem->tag); if (ret) mem->tag = NULL; } @@ -296,9 +296,9 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, type = nv50_fb_memtype[type]; do { if (back) - ret = nouveau_mm_tail(heap, type, max, min, align, &r); + ret = nouveau_mm_tail(heap, 0, type, max, min, align, &r); else - ret = nouveau_mm_head(heap, type, max, min, align, &r); + ret = nouveau_mm_head(heap, 0, type, max, min, align, &r); if (ret) { mutex_unlock(&pfb->base.mutex); pfb->ram->put(pfb, &mem); @@ -319,27 +319,22 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, static u32 nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram) { - int i, parts, colbits, rowbitsa, rowbitsb, banks; + int colbits, rowbitsa, rowbitsb, banks; u64 rowsize, predicted; - u32 r0, r4, rt, ru, rblock_size; + u32 r0, r4, rt, rblock_size; r0 = nv_rd32(pfb, 0x100200); r4 = nv_rd32(pfb, 0x100204); rt = nv_rd32(pfb, 0x100250); - ru = nv_rd32(pfb, 0x001540); - nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); - - for (i = 0, parts = 0; i < 8; i++) { - if (ru & (0x00010000 << i)) - parts++; - } + nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, + nv_rd32(pfb, 0x001540)); colbits = (r4 & 0x0000f000) >> 12; rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; banks = 1 << (((r4 & 0x03000000) >> 24) + 2); - rowsize = parts * banks * (1 << colbits) * 8; + rowsize = ram->parts * banks * (1 << colbits) * 8; predicted = rowsize << rowbitsa; if (r0 & 0x00000004) predicted += rowsize << rowbitsb; @@ -376,6 +371,9 @@ nv50_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine, ram->size = nv_rd32(pfb, 0x10020c); ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); + ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16; + ram->parts = hweight8(ram->part_mask); + switch (nv_rd32(pfb, 0x100714) & 0x00000007) { case 0: ram->type = NV_MEM_TYPE_DDR1; break; case 1: diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c index 8076fb195dd5..3601deca0bd5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c @@ -79,20 +79,27 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) struct nva3_ram *ram = (void *)pfb->ram; struct nva3_ramfuc *fuc = &ram->fuc; struct nva3_clock_info mclk; - u8 ver, cnt, len, strap; + struct nouveau_ram_data *next; + u8 ver, hdr, cnt, len, strap; u32 data; - struct { - u32 data; - u8 size; - } rammap, ramcfg, timing; u32 r004018, r100760, ctrl; u32 unk714, unk718, unk71c; - int ret; + int ret, i; + + next = &ram->base.target; + next->freq = freq; + ram->base.next = next; /* lookup memory config data relevant to the target frequency */ - rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size, - &cnt, &ramcfg.size); - if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) { + i = 0; + while ((data = nvbios_rammapEp(bios, i++, &ver, &hdr, &cnt, &len, + &next->bios))) { + if (freq / 1000 >= next->bios.rammap_min && + freq / 1000 <= next->bios.rammap_max) + break; + } + + if (!data || ver != 0x10 || hdr < 0x0e) { nv_error(pfb, "invalid/missing rammap entry\n"); return -EINVAL; } @@ -104,26 +111,25 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) return -EINVAL; } - ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); - if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) { + data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap, + &ver, &hdr, &next->bios); + if (!data || ver != 0x10 || hdr < 0x0e) { nv_error(pfb, "invalid/missing ramcfg entry\n"); return -EINVAL; } /* lookup memory timings, if bios says they're present */ - strap = nv_ro08(bios, ramcfg.data + 0x01); - if (strap != 0xff) { - timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size, - &cnt, &len); - if (!timing.data || ver != 0x10 || timing.size < 0x19) { + if (next->bios.ramcfg_timing != 0xff) { + data = nvbios_timingEp(bios, next->bios.ramcfg_timing, + &ver, &hdr, &cnt, &len, + &next->bios); + if (!data || ver != 0x10 || hdr < 0x19) { nv_error(pfb, "invalid/missing timing entry\n"); return -EINVAL; } - } else { - timing.data = 0; } - ret = nva3_clock_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk); + ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk); if (ret < 0) { nv_error(pfb, "failed mclk calculation\n"); return ret; @@ -163,17 +169,17 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x004168, 0x003f3141, ctrl); } - if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) { + if (next->bios.ramcfg_10_02_10) { ram_mask(fuc, 0x111104, 0x00000600, 0x00000000); } else { ram_mask(fuc, 0x111100, 0x40000000, 0x40000000); ram_mask(fuc, 0x111104, 0x00000180, 0x00000000); } - if (!(nv_ro08(bios, rammap.data + 0x04) & 0x02)) + if (!next->bios.rammap_10_04_02) ram_mask(fuc, 0x100200, 0x00000800, 0x00000000); ram_wr32(fuc, 0x611200, 0x00003300); - if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) + if (!next->bios.ramcfg_10_02_10) ram_wr32(fuc, 0x111100, 0x4c020000); /*XXX*/ ram_wr32(fuc, 0x1002d4, 0x00000001); @@ -202,17 +208,16 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) ram_wr32(fuc, 0x004018, 0x0000d000 | r004018); } - if ( (nv_ro08(bios, rammap.data + 0x04) & 0x08)) { - u32 unk5a0 = (nv_ro16(bios, ramcfg.data + 0x05) << 8) | - nv_ro08(bios, ramcfg.data + 0x05); - u32 unk5a4 = (nv_ro16(bios, ramcfg.data + 0x07)); - u32 unk804 = (nv_ro08(bios, ramcfg.data + 0x09) & 0xf0) << 16 | - (nv_ro08(bios, ramcfg.data + 0x03) & 0x0f) << 16 | - (nv_ro08(bios, ramcfg.data + 0x09) & 0x0f) | - 0x80000000; - ram_wr32(fuc, 0x1005a0, unk5a0); - ram_wr32(fuc, 0x1005a4, unk5a4); - ram_wr32(fuc, 0x10f804, unk804); + if (next->bios.rammap_10_04_08) { + ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 | + next->bios.ramcfg_10_05 << 8 | + next->bios.ramcfg_10_05); + ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 | + next->bios.ramcfg_10_07); + ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 | + next->bios.ramcfg_10_03_0f << 16 | + next->bios.ramcfg_10_09_0f | + 0x80000000); ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000); } else { ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000); @@ -250,27 +255,26 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x100220[0], 0x00000000, 0x00000000); ram_mask(fuc, 0x100220[8], 0x00000000, 0x00000000); - data = (nv_ro08(bios, ramcfg.data + 0x02) & 0x08) ? 0x00000000 : 0x00001000; - ram_mask(fuc, 0x100200, 0x00001000, data); + ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12); unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000010; unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100; unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100; - if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x20)) + if (next->bios.ramcfg_10_02_20) unk714 |= 0xf0000000; - if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x04)) + if (!next->bios.ramcfg_10_02_04) unk714 |= 0x00000010; ram_wr32(fuc, 0x100714, unk714); - if (nv_ro08(bios, ramcfg.data + 0x02) & 0x01) + if (next->bios.ramcfg_10_02_01) unk71c |= 0x00000100; ram_wr32(fuc, 0x10071c, unk71c); - if (nv_ro08(bios, ramcfg.data + 0x02) & 0x02) + if (next->bios.ramcfg_10_02_02) unk718 |= 0x00000100; ram_wr32(fuc, 0x100718, unk718); - if (nv_ro08(bios, ramcfg.data + 0x02) & 0x10) + if (next->bios.ramcfg_10_02_10) ram_wr32(fuc, 0x111100, 0x48000000); /*XXX*/ ram_mask(fuc, mr[0], 0x100, 0x100); @@ -282,9 +286,9 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) ram_nsec(fuc, 12000); ram_wr32(fuc, 0x611200, 0x00003330); - if ( (nv_ro08(bios, rammap.data + 0x04) & 0x02)) + if (next->bios.rammap_10_04_02) ram_mask(fuc, 0x100200, 0x00000800, 0x00000800); - if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) { + if (next->bios.ramcfg_10_02_10) { ram_mask(fuc, 0x111104, 0x00000180, 0x00000180); ram_mask(fuc, 0x111100, 0x40000000, 0x00000000); } else { @@ -404,11 +408,11 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ram->fuc.r_0x100714 = ramfuc_reg(0x100714); ram->fuc.r_0x100718 = ramfuc_reg(0x100718); ram->fuc.r_0x10071c = ramfuc_reg(0x10071c); - ram->fuc.r_0x100760 = ramfuc_reg(0x100760); - ram->fuc.r_0x1007a0 = ramfuc_reg(0x1007a0); - ram->fuc.r_0x1007e0 = ramfuc_reg(0x1007e0); + ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask); + ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask); + ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask); ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804); - ram->fuc.r_0x1110e0 = ramfuc_reg(0x1110e0); + ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask); ram->fuc.r_0x111100 = ramfuc_reg(0x111100); ram->fuc.r_0x111104 = ramfuc_reg(0x111104); ram->fuc.r_0x611200 = ramfuc_reg(0x611200); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c index 5a6a5027f749..735cb9580abe 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c @@ -26,7 +26,7 @@ #include <subdev/bios/pll.h> #include <subdev/bios/rammap.h> #include <subdev/bios/timing.h> -#include <subdev/ltcg.h> +#include <subdev/ltc.h> #include <subdev/clock.h> #include <subdev/clock/pll.h> @@ -133,6 +133,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq) struct nouveau_bios *bios = nouveau_bios(pfb); struct nvc0_ram *ram = (void *)pfb->ram; struct nvc0_ramfuc *fuc = &ram->fuc; + struct nvbios_ramcfg cfg; u8 ver, cnt, len, strap; struct { u32 data; @@ -145,7 +146,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq) /* lookup memory config data relevant to the target frequency */ rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size, - &cnt, &ramcfg.size); + &cnt, &ramcfg.size, &cfg); if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) { nv_error(pfb, "invalid/missing rammap entry\n"); return -EINVAL; @@ -425,7 +426,7 @@ extern const u8 nvc0_pte_storage_type_map[256]; void nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) { - struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); + struct nouveau_ltc *ltc = nouveau_ltc(pfb); struct nouveau_mem *mem = *pmem; *pmem = NULL; @@ -434,7 +435,7 @@ nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) mutex_lock(&pfb->base.mutex); if (mem->tag) - ltcg->tags_free(ltcg, &mem->tag); + ltc->tags_free(ltc, &mem->tag); __nv50_ram_put(pfb, mem); mutex_unlock(&pfb->base.mutex); @@ -468,12 +469,12 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, mutex_lock(&pfb->base.mutex); if (comp) { - struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); + struct nouveau_ltc *ltc = nouveau_ltc(pfb); /* compression only works with lpages */ if (align == (1 << (17 - 12))) { int n = size >> 5; - ltcg->tags_alloc(ltcg, n, &mem->tag); + ltc->tags_alloc(ltc, n, &mem->tag); } if (unlikely(!mem->tag)) @@ -483,9 +484,9 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, do { if (back) - ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); + ret = nouveau_mm_tail(mm, 0, 1, size, ncmin, align, &r); else - ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); + ret = nouveau_mm_head(mm, 0, 1, size, ncmin, align, &r); if (ret) { mutex_unlock(&pfb->base.mutex); pfb->ram->put(pfb, &mem); @@ -554,15 +555,15 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine, } else { /* otherwise, address lowest common amount from 0GiB */ ret = nouveau_mm_init(&pfb->vram, rsvd_head, - (bsize << 8) * parts, 1); + (bsize << 8) * parts - rsvd_head, 1); if (ret) return ret; /* and the rest starting from (8GiB + common_size) */ offset = (0x0200000000ULL >> 12) + (bsize << 8); - length = (ram->size >> 12) - (bsize << 8) - rsvd_tail; + length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail; - ret = nouveau_mm_init(&pfb->vram, offset, length, 0); + ret = nouveau_mm_init(&pfb->vram, offset, length, 1); if (ret) nouveau_mm_fini(&pfb->vram); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c index c5b46e302319..6bae474abb44 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c @@ -29,6 +29,8 @@ #include <subdev/bios/init.h> #include <subdev/bios/rammap.h> #include <subdev/bios/timing.h> +#include <subdev/bios/M0205.h> +#include <subdev/bios/M0209.h> #include <subdev/clock.h> #include <subdev/clock/pll.h> @@ -41,14 +43,6 @@ #include "ramfuc.h" -/* binary driver only executes this path if the condition (a) is true - * for any configuration (combination of rammap+ramcfg+timing) that - * can be reached on a given card. for now, we will execute the branch - * unconditionally in the hope that a "false everywhere" in the bios - * tables doesn't actually mean "don't touch this". - */ -#define NOTE00(a) 1 - struct nve0_ramfuc { struct ramfuc base; @@ -134,10 +128,12 @@ struct nve0_ram { struct nouveau_ram base; struct nve0_ramfuc fuc; + struct list_head cfg; u32 parts; u32 pmask; u32 pnuts; + struct nvbios_ramcfg diff; int from; int mode; int N1, fN1, M1, P1; @@ -241,7 +237,7 @@ nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg, { struct nve0_fb_priv *priv = (void *)nouveau_fb(ram); struct ramfuc *fuc = &ram->fuc.base; - u32 addr = 0x110000 + (reg->addr[0] & 0xfff); + u32 addr = 0x110000 + (reg->addr & 0xfff); u32 mask = _mask | _copy; u32 data = (_data & _mask) | (reg->data & _copy); u32 i; @@ -268,6 +264,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) u32 mask, data; ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); + ram_block(fuc); ram_wr32(fuc, 0x62c000, 0x0f0f0000); /* MR1: turn termination on early, for some reason.. */ @@ -478,7 +475,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]); data = mask = 0x00000000; - if (NOTE00(ramcfg_08_20)) { + if (ram->diff.ramcfg_11_08_20) { if (next->bios.ramcfg_11_08_20) data |= 0x01000000; mask |= 0x01000000; @@ -486,11 +483,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x10f200, mask, data); data = mask = 0x00000000; - if (NOTE00(ramcfg_02_03 != 0)) { + if (ram->diff.ramcfg_11_02_03) { data |= next->bios.ramcfg_11_02_03 << 8; mask |= 0x00000300; } - if (NOTE00(ramcfg_01_10)) { + if (ram->diff.ramcfg_11_01_10) { if (next->bios.ramcfg_11_01_10) data |= 0x70000000; mask |= 0x70000000; @@ -498,11 +495,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x10f604, mask, data); data = mask = 0x00000000; - if (NOTE00(timing_30_07 != 0)) { + if (ram->diff.timing_20_30_07) { data |= next->bios.timing_20_30_07 << 28; mask |= 0x70000000; } - if (NOTE00(ramcfg_01_01)) { + if (ram->diff.ramcfg_11_01_01) { if (next->bios.ramcfg_11_01_01) data |= 0x00000100; mask |= 0x00000100; @@ -510,11 +507,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x10f614, mask, data); data = mask = 0x00000000; - if (NOTE00(timing_30_07 != 0)) { + if (ram->diff.timing_20_30_07) { data |= next->bios.timing_20_30_07 << 28; mask |= 0x70000000; } - if (NOTE00(ramcfg_01_02)) { + if (ram->diff.ramcfg_11_01_02) { if (next->bios.ramcfg_11_01_02) data |= 0x00000100; mask |= 0x00000100; @@ -548,11 +545,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f); data = mask = 0x00000000; - if (NOTE00(ramcfg_02_03 != 0)) { + if (ram->diff.ramcfg_11_02_03) { data |= next->bios.ramcfg_11_02_03; mask |= 0x00000003; } - if (NOTE00(ramcfg_01_10)) { + if (ram->diff.ramcfg_11_01_10) { if (next->bios.ramcfg_11_01_10) data |= 0x00000004; mask |= 0x00000004; @@ -666,6 +663,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) if (next->bios.ramcfg_11_07_02) nve0_ram_train(fuc, 0x80020000, 0x01000000); + ram_unblock(fuc); ram_wr32(fuc, 0x62c000, 0x0f0f0f00); if (next->bios.rammap_11_08_01) @@ -695,6 +693,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) u32 mask, data; ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); + ram_block(fuc); ram_wr32(fuc, 0x62c000, 0x0f0f0000); if (vc == 1 && ram_have(fuc, gpio2E)) { @@ -917,6 +916,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000); ram_nsec(fuc, 1000); + ram_unblock(fuc); ram_wr32(fuc, 0x62c000, 0x0f0f0f00); if (next->bios.rammap_11_08_01) @@ -932,58 +932,24 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) ******************************************************************************/ static int -nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq, +nve0_ram_calc_data(struct nouveau_fb *pfb, u32 khz, struct nouveau_ram_data *data) { - struct nouveau_bios *bios = nouveau_bios(pfb); struct nve0_ram *ram = (void *)pfb->ram; - u8 strap, cnt, len; - - /* lookup memory config data relevant to the target frequency */ - ram->base.rammap.data = nvbios_rammapEp(bios, freq / 1000, - &ram->base.rammap.version, - &ram->base.rammap.size, - &cnt, &len, &data->bios); - if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 || - ram->base.rammap.size < 0x09) { - nv_error(pfb, "invalid/missing rammap entry\n"); - return -EINVAL; - } - - /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(pfb)); - ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data, - ram->base.rammap.version, - ram->base.rammap.size, - cnt, len, strap, - &ram->base.ramcfg.version, - &ram->base.ramcfg.size, - &data->bios); - if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 || - ram->base.ramcfg.size < 0x08) { - nv_error(pfb, "invalid/missing ramcfg entry\n"); - return -EINVAL; - } - - /* lookup memory timings, if bios says they're present */ - strap = nv_ro08(bios, ram->base.ramcfg.data + 0x00); - if (strap != 0xff) { - ram->base.timing.data = - nvbios_timingEp(bios, strap, &ram->base.timing.version, - &ram->base.timing.size, &cnt, &len, - &data->bios); - if (!ram->base.timing.data || - ram->base.timing.version != 0x20 || - ram->base.timing.size < 0x33) { - nv_error(pfb, "invalid/missing timing entry\n"); - return -EINVAL; + struct nouveau_ram_data *cfg; + u32 mhz = khz / 1000; + + list_for_each_entry(cfg, &ram->cfg, head) { + if (mhz >= cfg->bios.rammap_min && + mhz <= cfg->bios.rammap_max) { + *data = *cfg; + data->freq = khz; + return 0; } - } else { - ram->base.timing.data = 0; } - data->freq = freq; - return 0; + nv_error(ram, "ramcfg data for %dMHz not found\n", mhz); + return -EINVAL; } static int @@ -1106,13 +1072,99 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq) return nve0_ram_calc_xits(pfb, ram->base.next); } +static void +nve0_ram_prog_0(struct nouveau_fb *pfb, u32 freq) +{ + struct nve0_ram *ram = (void *)pfb->ram; + struct nouveau_ram_data *cfg; + u32 mhz = freq / 1000; + u32 mask, data; + + list_for_each_entry(cfg, &ram->cfg, head) { + if (mhz >= cfg->bios.rammap_min && + mhz <= cfg->bios.rammap_max) + break; + } + + if (&cfg->head == &ram->cfg) + return; + + if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) { + data |= cfg->bios.rammap_11_0a_03fe << 12; + mask |= 0x001ff000; + } + if (ram->diff.rammap_11_09_01ff) { + data |= cfg->bios.rammap_11_09_01ff; + mask |= 0x000001ff; + } + nv_mask(pfb, 0x10f468, mask, data); + + if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) { + data |= cfg->bios.rammap_11_0a_0400; + mask |= 0x00000001; + } + nv_mask(pfb, 0x10f420, mask, data); + + if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) { + data |= cfg->bios.rammap_11_0a_0800; + mask |= 0x00000001; + } + nv_mask(pfb, 0x10f430, mask, data); + + if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) { + data |= cfg->bios.rammap_11_0b_01f0; + mask |= 0x0000001f; + } + nv_mask(pfb, 0x10f400, mask, data); + + if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) { + data |= cfg->bios.rammap_11_0b_0200 << 9; + mask |= 0x00000200; + } + nv_mask(pfb, 0x10f410, mask, data); + + if (mask = 0, data = 0, ram->diff.rammap_11_0d) { + data |= cfg->bios.rammap_11_0d << 16; + mask |= 0x00ff0000; + } + if (ram->diff.rammap_11_0f) { + data |= cfg->bios.rammap_11_0f << 8; + mask |= 0x0000ff00; + } + nv_mask(pfb, 0x10f440, mask, data); + + if (mask = 0, data = 0, ram->diff.rammap_11_0e) { + data |= cfg->bios.rammap_11_0e << 8; + mask |= 0x0000ff00; + } + if (ram->diff.rammap_11_0b_0800) { + data |= cfg->bios.rammap_11_0b_0800 << 7; + mask |= 0x00000080; + } + if (ram->diff.rammap_11_0b_0400) { + data |= cfg->bios.rammap_11_0b_0400 << 5; + mask |= 0x00000020; + } + nv_mask(pfb, 0x10f444, mask, data); +} + static int nve0_ram_prog(struct nouveau_fb *pfb) { struct nouveau_device *device = nv_device(pfb); struct nve0_ram *ram = (void *)pfb->ram; struct nve0_ramfuc *fuc = &ram->fuc; - ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true)); + struct nouveau_ram_data *next = ram->base.next; + + if (!nouveau_boolopt(device->cfgopt, "NvMemExec", true)) { + ram_exec(fuc, false); + return (ram->base.next == &ram->base.xition); + } + + nve0_ram_prog_0(pfb, 1000); + ram_exec(fuc, true); + nve0_ram_prog_0(pfb, next->freq); + return (ram->base.next == &ram->base.xition); } @@ -1125,24 +1177,147 @@ nve0_ram_tidy(struct nouveau_fb *pfb) ram_exec(fuc, false); } +struct nve0_ram_train { + u16 mask; + struct nvbios_M0209S remap; + struct nvbios_M0209S type00; + struct nvbios_M0209S type01; + struct nvbios_M0209S type04; + struct nvbios_M0209S type06; + struct nvbios_M0209S type07; + struct nvbios_M0209S type08; + struct nvbios_M0209S type09; +}; + +static int +nve0_ram_train_type(struct nouveau_fb *pfb, int i, u8 ramcfg, + struct nve0_ram_train *train) +{ + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nvbios_M0205E M0205E; + struct nvbios_M0205S M0205S; + struct nvbios_M0209E M0209E; + struct nvbios_M0209S *remap = &train->remap; + struct nvbios_M0209S *value; + u8 ver, hdr, cnt, len; + u32 data; + + /* determine type of data for this index */ + if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))) + return -ENOENT; + + switch (M0205E.type) { + case 0x00: value = &train->type00; break; + case 0x01: value = &train->type01; break; + case 0x04: value = &train->type04; break; + case 0x06: value = &train->type06; break; + case 0x07: value = &train->type07; break; + case 0x08: value = &train->type08; break; + case 0x09: value = &train->type09; break; + default: + return 0; + } + + /* training data index determined by ramcfg strap */ + if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S))) + return -EINVAL; + i = M0205S.data; + + /* training data format information */ + if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E))) + return -EINVAL; + + /* ... and the raw data */ + if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value))) + return -EINVAL; + + if (M0209E.v02_07 == 2) { + /* of course! why wouldn't we have a pointer to another entry + * in the same table, and use the first one as an array of + * remap indices... + */ + if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr, + remap))) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(value->data); i++) + value->data[i] = remap->data[value->data[i]]; + } else + if (M0209E.v02_07 != 1) + return -EINVAL; + + train->mask |= 1 << M0205E.type; + return 0; +} + +static int +nve0_ram_train_init_0(struct nouveau_fb *pfb, struct nve0_ram_train *train) +{ + int i, j; + + if ((train->mask & 0x03d3) != 0x03d3) { + nv_warn(pfb, "missing link training data\n"); + return -EINVAL; + } + + for (i = 0; i < 0x30; i++) { + for (j = 0; j < 8; j += 4) { + nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8)); + nv_wr32(pfb, 0x10f920 + j, 0x00000000 | + train->type08.data[i] << 4 | + train->type06.data[i]); + nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]); + nv_wr32(pfb, 0x10f920 + j, 0x00000100 | + train->type09.data[i] << 4 | + train->type07.data[i]); + nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]); + } + } + + for (j = 0; j < 8; j += 4) { + for (i = 0; i < 0x100; i++) { + nv_wr32(pfb, 0x10f968 + j, i); + nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]); + } + } + + return 0; +} + +static int +nve0_ram_train_init(struct nouveau_fb *pfb) +{ + u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb)); + struct nve0_ram_train *train; + int ret = -ENOMEM, i; + + if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) { + for (i = 0; i < 0x100; i++) { + ret = nve0_ram_train_type(pfb, i, ramcfg, train); + if (ret && ret != -ENOENT) + break; + } + } + + switch (pfb->ram->type) { + case NV_MEM_TYPE_GDDR5: + ret = nve0_ram_train_init_0(pfb, train); + break; + default: + ret = 0; + break; + } + + kfree(train); + return ret; +} + int nve0_ram_init(struct nouveau_object *object) { struct nouveau_fb *pfb = (void *)object->parent; struct nve0_ram *ram = (void *)object; struct nouveau_bios *bios = nouveau_bios(pfb); - static const u8 train0[] = { - 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, - 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, - }; - static const u32 train1[] = { - 0x00000000, 0xffffffff, - 0x55555555, 0xaaaaaaaa, - 0x33333333, 0xcccccccc, - 0xf0f0f0f0, 0x0f0f0f0f, - 0x00ff00ff, 0xff00ff00, - 0x0000ffff, 0xffff0000, - }; u8 ver, hdr, cnt, len, snr, ssz; u32 data, save; int ret, i; @@ -1168,51 +1343,107 @@ nve0_ram_init(struct nouveau_object *object) cnt = nv_ro08(bios, data + 0x14); /* guess at count */ data = nv_ro32(bios, data + 0x10); /* guess u32... */ - save = nv_rd32(pfb, 0x10f65c); - for (i = 0; i < cnt; i++) { - nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4); - nvbios_exec(&(struct nvbios_init) { - .subdev = nv_subdev(pfb), - .bios = bios, - .offset = nv_ro32(bios, data), /* guess u32 */ - .execute = 1, - }); - data += 4; - } - nv_wr32(pfb, 0x10f65c, save); + save = nv_rd32(pfb, 0x10f65c) & 0x000000f0; + for (i = 0; i < cnt; i++, data += 4) { + if (i != save >> 4) { + nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4); + nvbios_exec(&(struct nvbios_init) { + .subdev = nv_subdev(pfb), + .bios = bios, + .offset = nv_ro32(bios, data), + .execute = 1, + }); + } + } + nv_mask(pfb, 0x10f65c, 0x000000f0, save); nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000); + nv_wr32(pfb, 0x10ecc0, 0xffffffff); + nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010); - switch (ram->base.type) { - case NV_MEM_TYPE_GDDR5: - for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]); - nv_wr32(pfb, 0x10f918, train1[i % 12]); - nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]); - nv_wr32(pfb, 0x10f918, train1[i % 12]); - - nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]); - nv_wr32(pfb, 0x10f91c, train1[i % 12]); - nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]); - nv_wr32(pfb, 0x10f91c, train1[i % 12]); - } + return nve0_ram_train_init(pfb); +} - for (i = 0; i < 0x100; i++) { - nv_wr32(pfb, 0x10f968, i); - nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]); - } +static int +nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i) +{ + struct nouveau_fb *pfb = (void *)nv_object(ram)->parent; + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nouveau_ram_data *cfg; + struct nvbios_ramcfg *d = &ram->diff; + struct nvbios_ramcfg *p, *n; + u8 ver, hdr, cnt, len; + u32 data; + int ret; - for (i = 0; i < 0x100; i++) { - nv_wr32(pfb, 0x10f96c, i); - nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]); - } - break; - default: - break; + if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL))) + return -ENOMEM; + p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios; + n = &cfg->bios; + + /* memory config data for a range of target frequencies */ + data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios); + if (ret = -ENOENT, !data) + goto done; + if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12) + goto done; + + /* ... and a portion specific to the attached memory */ + data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg, + &ver, &hdr, &cfg->bios); + if (ret = -EINVAL, !data) + goto done; + if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a) + goto done; + + /* lookup memory timings, if bios says they're present */ + if (cfg->bios.ramcfg_timing != 0xff) { + data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing, + &ver, &hdr, &cnt, &len, + &cfg->bios); + if (ret = -EINVAL, !data) + goto done; + if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33) + goto done; } - return 0; + list_add_tail(&cfg->head, &ram->cfg); + if (ret = 0, i == 0) + goto done; + + d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe; + d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff; + d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400; + d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800; + d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0; + d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200; + d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d; + d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f; + d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e; + d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800; + d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400; + d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01; + d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02; + d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10; + d->ramcfg_11_02_03 |= p->ramcfg_11_02_03 != n->ramcfg_11_02_03; + d->ramcfg_11_08_20 |= p->ramcfg_11_08_20 != n->ramcfg_11_08_20; + d->timing_20_30_07 |= p->timing_20_30_07 != n->timing_20_30_07; +done: + if (ret) + kfree(cfg); + return ret; +} + +static void +nve0_ram_dtor(struct nouveau_object *object) +{ + struct nve0_ram *ram = (void *)object; + struct nouveau_ram_data *cfg, *tmp; + + list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) { + kfree(cfg); + } + + nouveau_ram_destroy(&ram->base); } static int @@ -1226,6 +1457,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct dcb_gpio_func func; struct nve0_ram *ram; int ret, i; + u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb)); u32 tmp; ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram); @@ -1233,6 +1465,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + INIT_LIST_HEAD(&ram->cfg); + switch (ram->base.type) { case NV_MEM_TYPE_DDR3: case NV_MEM_TYPE_GDDR5: @@ -1264,7 +1498,26 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, } } - // parse bios data for both pll's + /* parse bios data for all rammap table entries up-front, and + * build information on whether certain fields differ between + * any of the entries. + * + * the binary driver appears to completely ignore some fields + * when all entries contain the same value. at first, it was + * hoped that these were mere optimisations and the bios init + * tables had configured as per the values here, but there is + * evidence now to suggest that this isn't the case and we do + * need to treat this condition as a "don't touch" indicator. + */ + for (i = 0; !ret; i++) { + ret = nve0_ram_ctor_data(ram, ramcfg, i); + if (ret && ret != -ENOENT) { + nv_error(pfb, "failed to parse ramcfg data\n"); + return ret; + } + } + + /* parse bios data for both pll's */ ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); if (ret) { nv_error(pfb, "mclk refpll data not found\n"); @@ -1277,6 +1530,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; } + /* lookup memory voltage gpios */ ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func); if (ret == 0) { ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04)); @@ -1385,7 +1639,7 @@ nve0_ram_oclass = { .handle = 0, .ofuncs = &(struct nouveau_ofuncs) { .ctor = nve0_ram_ctor, - .dtor = _nouveau_ram_dtor, + .dtor = nve0_ram_dtor, .init = nve0_ram_init, .fini = _nouveau_ram_fini, } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c new file mode 100644 index 000000000000..bb1eb8f3e639 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c @@ -0,0 +1,94 @@ +/* + * Copyright 2014 Roy Spliet + * + * 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: Roy Spliet <rspliet@eclipso.eu> + * Ben Skeggs + */ + +#include "priv.h" + +struct ramxlat { + int id; + u8 enc; +}; + +static inline int +ramxlat(const struct ramxlat *xlat, int id) +{ + while (xlat->id >= 0) { + if (xlat->id == id) + return xlat->enc; + xlat++; + } + return -EINVAL; +} + +static const struct ramxlat +ramddr2_cl[] = { + { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, + /* The following are available in some, but not all DDR2 docs */ + { 7, 7 }, + { -1 } +}; + +static const struct ramxlat +ramddr2_wr[] = { + { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 }, + /* The following are available in some, but not all DDR2 docs */ + { 7, 6 }, + { -1 } +}; + +int +nouveau_sddr2_calc(struct nouveau_ram *ram) +{ + int CL, WR, DLL = 0, ODT = 0; + + switch (ram->next->bios.timing_ver) { + case 0x10: + CL = ram->next->bios.timing_10_CL; + WR = ram->next->bios.timing_10_WR; + DLL = !ram->next->bios.ramcfg_10_02_40; + ODT = ram->next->bios.timing_10_ODT & 3; + break; + case 0x20: + CL = (ram->next->bios.timing[1] & 0x0000001f); + WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16; + break; + default: + return -ENOSYS; + } + + CL = ramxlat(ramddr2_cl, CL); + WR = ramxlat(ramddr2_wr, WR); + if (CL < 0 || WR < 0) + return -EINVAL; + + ram->mr[0] &= ~0xf70; + ram->mr[0] |= (WR & 0x07) << 9; + ram->mr[0] |= (CL & 0x07) << 4; + + ram->mr[1] &= ~0x045; + ram->mr[1] |= (ODT & 0x1) << 2; + ram->mr[1] |= (ODT & 0x2) << 5; + ram->mr[1] |= !DLL; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c index ebd4cd9c35d9..83949b11833a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c @@ -20,9 +20,9 @@ * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Ben Skeggs <bskeggs@redhat.com> + * Roy Spliet <rspliet@eclipso.eu> */ -#include <subdev/bios.h> #include "priv.h" struct ramxlat { @@ -69,31 +69,52 @@ ramddr3_cwl[] = { int nouveau_sddr3_calc(struct nouveau_ram *ram) { - struct nouveau_bios *bios = nouveau_bios(ram); - int WL, CL, WR; + int CWL, CL, WR, DLL = 0, ODT = 0; - switch (!!ram->timing.data * ram->timing.version) { + switch (ram->next->bios.timing_ver) { + case 0x10: + if (ram->next->bios.timing_hdr < 0x17) { + /* XXX: NV50: Get CWL from the timing register */ + return -ENOSYS; + } + CWL = ram->next->bios.timing_10_CWL; + CL = ram->next->bios.timing_10_CL; + WR = ram->next->bios.timing_10_WR; + DLL = !ram->next->bios.ramcfg_10_02_40; + ODT = ram->next->bios.timing_10_ODT; + break; case 0x20: - WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7; - CL = nv_ro08(bios, ram->timing.data + 0x04) & 0x1f; - WR = nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f; + CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7; + CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0; + WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16; + /* XXX: Get these values from the VBIOS instead */ + DLL = !(ram->mr[1] & 0x1); + ODT = (ram->mr[1] & 0x004) >> 2 | + (ram->mr[1] & 0x040) >> 5 | + (ram->mr[1] & 0x200) >> 7; break; default: return -ENOSYS; } - WL = ramxlat(ramddr3_cwl, WL); - CL = ramxlat(ramddr3_cl, CL); - WR = ramxlat(ramddr3_wr, WR); - if (WL < 0 || CL < 0 || WR < 0) + CWL = ramxlat(ramddr3_cwl, CWL); + CL = ramxlat(ramddr3_cl, CL); + WR = ramxlat(ramddr3_wr, WR); + if (CL < 0 || CWL < 0 || WR < 0) return -EINVAL; - ram->mr[0] &= ~0xe74; + ram->mr[0] &= ~0xf74; ram->mr[0] |= (WR & 0x07) << 9; ram->mr[0] |= (CL & 0x0e) << 3; ram->mr[0] |= (CL & 0x01) << 2; + ram->mr[1] &= ~0x245; + ram->mr[1] |= (ODT & 0x1) << 2; + ram->mr[1] |= (ODT & 0x2) << 5; + ram->mr[1] |= (ODT & 0x4) << 7; + ram->mr[1] |= !DLL; + ram->mr[2] &= ~0x038; - ram->mr[2] |= (WL & 0x07) << 3; + ram->mr[2] |= (CWL & 0x07) << 3; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c new file mode 100644 index 000000000000..9e8e92127715 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c @@ -0,0 +1,54 @@ +/* + * Copyright 2014 Martin Peres + * + * 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: Martin Peres + */ + +#include <subdev/fuse.h> + +int +_nouveau_fuse_init(struct nouveau_object *object) +{ + struct nouveau_fuse *fuse = (void *)object; + return nouveau_subdev_init(&fuse->base); +} + +void +_nouveau_fuse_dtor(struct nouveau_object *object) +{ + struct nouveau_fuse *fuse = (void *)object; + nouveau_subdev_destroy(&fuse->base); +} + +int +nouveau_fuse_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) +{ + struct nouveau_fuse *fuse; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "FUSE", + "fuse", length, pobject); + fuse = *pobject; + + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c new file mode 100644 index 000000000000..a374ade485be --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c @@ -0,0 +1,81 @@ +/* + * Copyright 2014 Martin Peres + * + * 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: Martin Peres + */ + +#include "priv.h" + +struct g80_fuse_priv { + struct nouveau_fuse base; + + spinlock_t fuse_enable_lock; +}; + +static u32 +g80_fuse_rd32(struct nouveau_object *object, u64 addr) +{ + struct g80_fuse_priv *priv = (void *)object; + unsigned long flags; + u32 fuse_enable, val; + + spin_lock_irqsave(&priv->fuse_enable_lock, flags); + + /* racy if another part of nouveau start writing to this reg */ + fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800); + val = nv_rd32(priv, 0x21000 + addr); + nv_wr32(priv, 0x1084, fuse_enable); + + spin_unlock_irqrestore(&priv->fuse_enable_lock, flags); + + return val; +} + + +static int +g80_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct g80_fuse_priv *priv; + int ret; + + ret = nouveau_fuse_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + spin_lock_init(&priv->fuse_enable_lock); + + return 0; +} + +struct nouveau_oclass +g80_fuse_oclass = { + .handle = NV_SUBDEV(FUSE, 0x50), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = g80_fuse_ctor, + .dtor = _nouveau_fuse_dtor, + .init = _nouveau_fuse_init, + .fini = _nouveau_fuse_fini, + .rd32 = g80_fuse_rd32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c new file mode 100644 index 000000000000..5ed03f54b3d4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c @@ -0,0 +1,83 @@ +/* + * Copyright 2014 Martin Peres + * + * 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: Martin Peres + */ + +#include "priv.h" + +struct gf100_fuse_priv { + struct nouveau_fuse base; + + spinlock_t fuse_enable_lock; +}; + +static u32 +gf100_fuse_rd32(struct nouveau_object *object, u64 addr) +{ + struct gf100_fuse_priv *priv = (void *)object; + unsigned long flags; + u32 fuse_enable, unk, val; + + spin_lock_irqsave(&priv->fuse_enable_lock, flags); + + /* racy if another part of nouveau start writing to these regs */ + fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800); + unk = nv_mask(priv, 0x21000, 0x1, 0x1); + val = nv_rd32(priv, 0x21100 + addr); + nv_wr32(priv, 0x21000, unk); + nv_wr32(priv, 0x22400, fuse_enable); + + spin_unlock_irqrestore(&priv->fuse_enable_lock, flags); + + return val; +} + + +static int +gf100_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gf100_fuse_priv *priv; + int ret; + + ret = nouveau_fuse_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + spin_lock_init(&priv->fuse_enable_lock); + + return 0; +} + +struct nouveau_oclass +gf100_fuse_oclass = { + .handle = NV_SUBDEV(FUSE, 0xC0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gf100_fuse_ctor, + .dtor = _nouveau_fuse_dtor, + .init = _nouveau_fuse_init, + .fini = _nouveau_fuse_fini, + .rd32 = gf100_fuse_rd32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c new file mode 100644 index 000000000000..4f1a636c6538 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c @@ -0,0 +1,66 @@ +/* + * Copyright 2014 Martin Peres + * + * 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: Martin Peres + */ + +#include "priv.h" + +struct gm107_fuse_priv { + struct nouveau_fuse base; +}; + +static u32 +gm107_fuse_rd32(struct nouveau_object *object, u64 addr) +{ + struct gf100_fuse_priv *priv = (void *)object; + + return nv_rd32(priv, 0x21100 + addr); +} + + +static int +gm107_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gm107_fuse_priv *priv; + int ret; + + ret = nouveau_fuse_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass +gm107_fuse_oclass = { + .handle = NV_SUBDEV(FUSE, 0x117), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_fuse_ctor, + .dtor = _nouveau_fuse_dtor, + .init = _nouveau_fuse_init, + .fini = _nouveau_fuse_fini, + .rd32 = gm107_fuse_rd32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h new file mode 100644 index 000000000000..d2085411a5cb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h @@ -0,0 +1,9 @@ +#ifndef __NVKM_FUSE_PRIV_H__ +#define __NVKM_FUSE_PRIV_H__ + +#include <subdev/fuse.h> + +int _nouveau_fuse_init(struct nouveau_object *object); +void _nouveau_fuse_dtor(struct nouveau_object *object); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index 45e0202f3151..7ad99b763f4c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -106,39 +106,60 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) } static void -nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index) +nouveau_gpio_intr_fini(struct nvkm_event *event, int type, int index) { - struct nouveau_gpio *gpio = nouveau_gpio(event->priv); + struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event); const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; impl->intr_mask(gpio, type, 1 << index, 0); } static void -nouveau_gpio_intr_enable(struct nouveau_event *event, int type, int index) +nouveau_gpio_intr_init(struct nvkm_event *event, int type, int index) { - struct nouveau_gpio *gpio = nouveau_gpio(event->priv); + struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event); const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; impl->intr_mask(gpio, type, 1 << index, 1 << index); } +static int +nouveau_gpio_intr_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + struct nvkm_gpio_ntfy_req *req = data; + if (!WARN_ON(size != sizeof(*req))) { + notify->size = sizeof(struct nvkm_gpio_ntfy_rep); + notify->types = req->mask; + notify->index = req->line; + return 0; + } + return -EINVAL; +} + static void nouveau_gpio_intr(struct nouveau_subdev *subdev) { struct nouveau_gpio *gpio = nouveau_gpio(subdev); const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - u32 hi, lo, e, i; + u32 hi, lo, i; impl->intr_stat(gpio, &hi, &lo); - for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) { - if (hi & (1 << i)) - e |= NVKM_GPIO_HI; - if (lo & (1 << i)) - e |= NVKM_GPIO_LO; - nouveau_event_trigger(gpio->events, e, i); + for (i = 0; (hi | lo) && i < impl->lines; i++) { + struct nvkm_gpio_ntfy_rep rep = { + .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) | + (NVKM_GPIO_LO * !!(lo & (1 << i))), + }; + nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep)); } } +static const struct nvkm_event_func +nouveau_gpio_intr_func = { + .ctor = nouveau_gpio_intr_ctor, + .init = nouveau_gpio_intr_init, + .fini = nouveau_gpio_intr_fini, +}; + int _nouveau_gpio_fini(struct nouveau_object *object, bool suspend) { @@ -183,7 +204,7 @@ void _nouveau_gpio_dtor(struct nouveau_object *object) { struct nouveau_gpio *gpio = (void *)object; - nouveau_event_destroy(&gpio->events); + nvkm_event_fini(&gpio->event); nouveau_subdev_destroy(&gpio->base); } @@ -208,13 +229,11 @@ nouveau_gpio_create_(struct nouveau_object *parent, gpio->get = nouveau_gpio_get; gpio->reset = impl->reset; - ret = nouveau_event_create(2, impl->lines, &gpio->events); + ret = nvkm_event_init(&nouveau_gpio_intr_func, 2, impl->lines, + &gpio->event); if (ret) return ret; - gpio->events->priv = gpio; - gpio->events->enable = nouveau_gpio_intr_enable; - gpio->events->disable = nouveau_gpio_intr_disable; nv_subdev(gpio)->intr = nouveau_gpio_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c index 252083d376f5..cae404ccadac 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c @@ -25,7 +25,7 @@ #include "priv.h" void -nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) +nv94_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) { u32 intr0 = nv_rd32(gpio, 0x00e054); u32 intr1 = nv_rd32(gpio, 0x00e074); @@ -38,7 +38,7 @@ nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) } void -nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) +nv94_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) { u32 inte0 = nv_rd32(gpio, 0x00e050); u32 inte1 = nv_rd32(gpio, 0x00e070); @@ -57,8 +57,8 @@ nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) } struct nouveau_oclass * -nv92_gpio_oclass = &(struct nouveau_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0x92), +nv94_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0x94), .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = _nouveau_gpio_ctor, .dtor = _nouveau_gpio_dtor, @@ -66,8 +66,8 @@ nv92_gpio_oclass = &(struct nouveau_gpio_impl) { .fini = _nouveau_gpio_fini, }, .lines = 32, - .intr_stat = nv92_gpio_intr_stat, - .intr_mask = nv92_gpio_intr_mask, + .intr_stat = nv94_gpio_intr_stat, + .intr_mask = nv94_gpio_intr_mask, .drive = nv50_gpio_drive, .sense = nv50_gpio_sense, .reset = nv50_gpio_reset, diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c index a4682b0956ad..480d6d2af770 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c @@ -77,8 +77,8 @@ nvd0_gpio_oclass = &(struct nouveau_gpio_impl) { .fini = _nouveau_gpio_fini, }, .lines = 32, - .intr_stat = nv92_gpio_intr_stat, - .intr_mask = nv92_gpio_intr_mask, + .intr_stat = nv94_gpio_intr_stat, + .intr_mask = nv94_gpio_intr_mask, .drive = nvd0_gpio_drive, .sense = nvd0_gpio_sense, .reset = nvd0_gpio_reset, diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h index e1724dfc86ae..bff98b86e2b5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h @@ -56,8 +56,8 @@ void nv50_gpio_reset(struct nouveau_gpio *, u8); int nv50_gpio_drive(struct nouveau_gpio *, int, int, int); int nv50_gpio_sense(struct nouveau_gpio *, int); -void nv92_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *); -void nv92_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32); +void nv94_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *); +void nv94_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32); void nvd0_gpio_reset(struct nouveau_gpio *, u8); int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int); diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index 09ba2cc851cf..2b1bf545e488 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c @@ -23,6 +23,7 @@ */ #include <core/option.h> +#include <core/object.h> #include <core/event.h> #include <subdev/bios.h> @@ -326,9 +327,9 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, } static void -nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index) +nouveau_i2c_intr_fini(struct nvkm_event *event, int type, int index) { - struct nouveau_i2c *i2c = nouveau_i2c(event->priv); + struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event); struct nouveau_i2c_port *port = i2c->find(i2c, index); const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (port && port->aux >= 0) @@ -336,15 +337,29 @@ nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index) } static void -nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index) +nouveau_i2c_intr_init(struct nvkm_event *event, int type, int index) { - struct nouveau_i2c *i2c = nouveau_i2c(event->priv); + struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event); struct nouveau_i2c_port *port = i2c->find(i2c, index); const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (port && port->aux >= 0) impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux); } +static int +nouveau_i2c_intr_ctor(struct nouveau_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + struct nvkm_i2c_ntfy_req *req = data; + if (!WARN_ON(size != sizeof(*req))) { + notify->size = sizeof(struct nvkm_i2c_ntfy_rep); + notify->types = req->mask; + notify->index = req->port; + return 0; + } + return -EINVAL; +} + static void nouveau_i2c_intr(struct nouveau_subdev *subdev) { @@ -364,13 +379,26 @@ nouveau_i2c_intr(struct nouveau_subdev *subdev) if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG; if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ; if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE; - - nouveau_event_trigger(i2c->ntfy, e, port->index); + if (e) { + struct nvkm_i2c_ntfy_rep rep = { + .mask = e, + }; + nvkm_event_send(&i2c->event, rep.mask, + port->index, &rep, + sizeof(rep)); + } } } } } +static const struct nvkm_event_func +nouveau_i2c_intr_func = { + .ctor = nouveau_i2c_intr_ctor, + .init = nouveau_i2c_intr_init, + .fini = nouveau_i2c_intr_fini, +}; + int _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) { @@ -431,7 +459,7 @@ _nouveau_i2c_dtor(struct nouveau_object *object) struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port, *temp; - nouveau_event_destroy(&i2c->ntfy); + nvkm_event_fini(&i2c->event); list_for_each_entry_safe(port, temp, &i2c->ports, head) { nouveau_object_ref(NULL, (struct nouveau_object **)&port); @@ -547,13 +575,10 @@ nouveau_i2c_create_(struct nouveau_object *parent, } } - ret = nouveau_event_create(4, index, &i2c->ntfy); + ret = nvkm_event_init(&nouveau_i2c_intr_func, 4, index, &i2c->event); if (ret) return ret; - i2c->ntfy->priv = i2c; - i2c->ntfy->enable = nouveau_i2c_intr_enable; - i2c->ntfy->disable = nouveau_i2c_intr_disable; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c index 7b64befee48f..e8b1401c59c0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c @@ -69,7 +69,7 @@ nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - ret = nouveau_mm_head(&priv->heap, 1, args->size, args->size, + ret = nouveau_mm_head(&priv->heap, 0, 1, args->size, args->size, args->align, &node->mem); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c new file mode 100644 index 000000000000..7fa331516f84 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c @@ -0,0 +1,126 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +#include "priv.h" + +static int +nvkm_ltc_tags_alloc(struct nouveau_ltc *ltc, u32 n, + struct nouveau_mm_node **pnode) +{ + struct nvkm_ltc_priv *priv = (void *)ltc; + int ret; + + ret = nouveau_mm_head(&priv->tags, 0, 1, n, n, 1, pnode); + if (ret) + *pnode = NULL; + + return ret; +} + +static void +nvkm_ltc_tags_free(struct nouveau_ltc *ltc, struct nouveau_mm_node **pnode) +{ + struct nvkm_ltc_priv *priv = (void *)ltc; + nouveau_mm_free(&priv->tags, pnode); +} + +static void +nvkm_ltc_tags_clear(struct nouveau_ltc *ltc, u32 first, u32 count) +{ + const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); + struct nvkm_ltc_priv *priv = (void *)ltc; + const u32 limit = first + count - 1; + + BUG_ON((first > limit) || (limit >= priv->num_tags)); + + impl->cbc_clear(priv, first, limit); + impl->cbc_wait(priv); +} + +static int +nvkm_ltc_zbc_color_get(struct nouveau_ltc *ltc, int index, const u32 color[4]) +{ + const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); + struct nvkm_ltc_priv *priv = (void *)ltc; + memcpy(priv->zbc_color[index], color, sizeof(priv->zbc_color[index])); + impl->zbc_clear_color(priv, index, color); + return index; +} + +static int +nvkm_ltc_zbc_depth_get(struct nouveau_ltc *ltc, int index, const u32 depth) +{ + const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); + struct nvkm_ltc_priv *priv = (void *)ltc; + priv->zbc_depth[index] = depth; + impl->zbc_clear_depth(priv, index, depth); + return index; +} + +int +_nvkm_ltc_init(struct nouveau_object *object) +{ + const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object); + struct nvkm_ltc_priv *priv = (void *)object; + int ret, i; + + ret = nouveau_subdev_init(&priv->base.base); + if (ret) + return ret; + + for (i = priv->base.zbc_min; i <= priv->base.zbc_max; i++) { + impl->zbc_clear_color(priv, i, priv->zbc_color[i]); + impl->zbc_clear_depth(priv, i, priv->zbc_depth[i]); + } + + return 0; +} + +int +nvkm_ltc_create_(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) +{ + const struct nvkm_ltc_impl *impl = (void *)oclass; + struct nvkm_ltc_priv *priv; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PLTCG", + "l2c", length, pobject); + priv = *pobject; + if (ret) + return ret; + + memset(priv->zbc_color, 0x00, sizeof(priv->zbc_color)); + memset(priv->zbc_depth, 0x00, sizeof(priv->zbc_depth)); + + priv->base.base.intr = impl->intr; + priv->base.tags_alloc = nvkm_ltc_tags_alloc; + priv->base.tags_free = nvkm_ltc_tags_free; + priv->base.tags_clear = nvkm_ltc_tags_clear; + priv->base.zbc_min = 1; /* reserve 0 for disabled */ + priv->base.zbc_max = min(impl->zbc, NOUVEAU_LTC_MAX_ZBC_CNT) - 1; + priv->base.zbc_color_get = nvkm_ltc_zbc_color_get; + priv->base.zbc_depth_get = nvkm_ltc_zbc_depth_get; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c index f2f3338a967a..2db0977284f8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c @@ -25,86 +25,126 @@ #include <subdev/fb.h> #include <subdev/timer.h> -#include "gf100.h" +#include "priv.h" + +void +gf100_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit) +{ + nv_wr32(priv, 0x17e8cc, start); + nv_wr32(priv, 0x17e8d0, limit); + nv_wr32(priv, 0x17e8c8, 0x00000004); +} + +void +gf100_ltc_cbc_wait(struct nvkm_ltc_priv *priv) +{ + int c, s; + for (c = 0; c < priv->ltc_nr; c++) { + for (s = 0; s < priv->lts_nr; s++) + nv_wait(priv, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0); + } +} + +void +gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) +{ + nv_mask(priv, 0x17ea44, 0x0000000f, i); + nv_wr32(priv, 0x17ea48, color[0]); + nv_wr32(priv, 0x17ea4c, color[1]); + nv_wr32(priv, 0x17ea50, color[2]); + nv_wr32(priv, 0x17ea54, color[3]); +} + +void +gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth) +{ + nv_mask(priv, 0x17ea44, 0x0000000f, i); + nv_wr32(priv, 0x17ea58, depth); +} + +static const struct nouveau_bitfield +gf100_ltc_lts_intr_name[] = { + { 0x00000001, "IDLE_ERROR_IQ" }, + { 0x00000002, "IDLE_ERROR_CBC" }, + { 0x00000004, "IDLE_ERROR_TSTG" }, + { 0x00000008, "IDLE_ERROR_DSTG" }, + { 0x00000010, "EVICTED_CB" }, + { 0x00000020, "ILLEGAL_COMPSTAT" }, + { 0x00000040, "BLOCKLINEAR_CB" }, + { 0x00000100, "ECC_SEC_ERROR" }, + { 0x00000200, "ECC_DED_ERROR" }, + { 0x00000400, "DEBUG" }, + { 0x00000800, "ATOMIC_TO_Z" }, + { 0x00001000, "ILLEGAL_ATOMIC" }, + { 0x00002000, "BLKACTIVITY_ERR" }, + {} +}; static void -gf100_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) +gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts) { u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400); - u32 stat = nv_rd32(priv, base + 0x020); + u32 intr = nv_rd32(priv, base + 0x020); + u32 stat = intr & 0x0000ffff; if (stat) { - nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); - nv_wr32(priv, base + 0x020, stat); + nv_info(priv, "LTC%d_LTS%d:", ltc, lts); + nouveau_bitfield_print(gf100_ltc_lts_intr_name, stat); + pr_cont("\n"); } + + nv_wr32(priv, base + 0x020, intr); } -static void -gf100_ltcg_intr(struct nouveau_subdev *subdev) +void +gf100_ltc_intr(struct nouveau_subdev *subdev) { - struct gf100_ltcg_priv *priv = (void *)subdev; + struct nvkm_ltc_priv *priv = (void *)subdev; u32 mask; mask = nv_rd32(priv, 0x00017c); while (mask) { u32 lts, ltc = __ffs(mask); for (lts = 0; lts < priv->lts_nr; lts++) - gf100_ltcg_lts_isr(priv, ltc, lts); + gf100_ltc_lts_intr(priv, ltc, lts); mask &= ~(1 << ltc); } - - /* we do something horribly wrong and upset PMFB a lot, so mask off - * interrupts from it after the first one until it's fixed - */ - nv_mask(priv, 0x000640, 0x02000000, 0x00000000); } -int -gf100_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n, - struct nouveau_mm_node **pnode) +static int +gf100_ltc_init(struct nouveau_object *object) { - struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; + struct nvkm_ltc_priv *priv = (void *)object; + u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); int ret; - ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode); + ret = nvkm_ltc_init(priv); if (ret) - *pnode = NULL; + return ret; - return ret; + nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + nv_wr32(priv, 0x17e8d8, priv->ltc_nr); + nv_wr32(priv, 0x17e8d4, priv->tag_base); + nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + return 0; } void -gf100_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode) -{ - struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; - - nouveau_mm_free(&priv->tags, pnode); -} - -static void -gf100_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) +gf100_ltc_dtor(struct nouveau_object *object) { - struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; - u32 last = first + count - 1; - int p, i; + struct nouveau_fb *pfb = nouveau_fb(object); + struct nvkm_ltc_priv *priv = (void *)object; - BUG_ON((first > last) || (last >= priv->num_tags)); - - nv_wr32(priv, 0x17e8cc, first); - nv_wr32(priv, 0x17e8d0, last); - nv_wr32(priv, 0x17e8c8, 0x4); /* trigger clear */ + nouveau_mm_fini(&priv->tags); + nouveau_mm_free(&pfb->vram, &priv->tag_ram); - /* wait until it's finished with clearing */ - for (p = 0; p < priv->ltc_nr; ++p) { - for (i = 0; i < priv->lts_nr; ++i) - nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0); - } + nvkm_ltc_destroy(priv); } /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ int -gf100_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct gf100_ltcg_priv *priv) +gf100_ltc_init_tag_ram(struct nouveau_fb *pfb, struct nvkm_ltc_priv *priv) { u32 tag_size, tag_margin, tag_align; int ret; @@ -130,34 +170,34 @@ gf100_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct gf100_ltcg_priv *priv) tag_size += tag_align; tag_size = (tag_size + 0xfff) >> 12; /* round up */ - ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1, + ret = nouveau_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1, &priv->tag_ram); if (ret) { priv->num_tags = 0; } else { - u64 tag_base = (priv->tag_ram->offset << 12) + tag_margin; + u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin; tag_base += tag_align - 1; ret = do_div(tag_base, tag_align); priv->tag_base = tag_base; } - ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1); + ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1); return ret; } -static int -gf100_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, +int +gf100_ltc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct gf100_ltcg_priv *priv; struct nouveau_fb *pfb = nouveau_fb(parent); + struct nvkm_ltc_priv *priv; u32 parts, mask; int ret, i; - ret = nouveau_ltcg_create(parent, engine, oclass, &priv); + ret = nvkm_ltc_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -170,57 +210,27 @@ gf100_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, } priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; - ret = gf100_ltcg_init_tag_ram(pfb, priv); - if (ret) - return ret; - - priv->base.tags_alloc = gf100_ltcg_tags_alloc; - priv->base.tags_free = gf100_ltcg_tags_free; - priv->base.tags_clear = gf100_ltcg_tags_clear; - - nv_subdev(priv)->intr = gf100_ltcg_intr; - return 0; -} - -void -gf100_ltcg_dtor(struct nouveau_object *object) -{ - struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; - struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; - struct nouveau_fb *pfb = nouveau_fb(ltcg->base.base.parent); - - nouveau_mm_fini(&priv->tags); - nouveau_mm_free(&pfb->vram, &priv->tag_ram); - - nouveau_ltcg_destroy(ltcg); -} - -static int -gf100_ltcg_init(struct nouveau_object *object) -{ - struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; - struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; - int ret; - - ret = nouveau_ltcg_init(ltcg); + ret = gf100_ltc_init_tag_ram(pfb, priv); if (ret) return ret; - nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - nv_wr32(priv, 0x17e8d8, priv->ltc_nr); - if (nv_device(ltcg)->card_type >= NV_E0) - nv_wr32(priv, 0x17e000, priv->ltc_nr); - nv_wr32(priv, 0x17e8d4, priv->tag_base); + nv_subdev(priv)->intr = gf100_ltc_intr; return 0; } struct nouveau_oclass * -gf100_ltcg_oclass = &(struct nouveau_oclass) { - .handle = NV_SUBDEV(LTCG, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = gf100_ltcg_ctor, - .dtor = gf100_ltcg_dtor, - .init = gf100_ltcg_init, - .fini = _nouveau_ltcg_fini, +gf100_ltc_oclass = &(struct nvkm_ltc_impl) { + .base.handle = NV_SUBDEV(LTC, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = gf100_ltc_ctor, + .dtor = gf100_ltc_dtor, + .init = gf100_ltc_init, + .fini = _nvkm_ltc_fini, }, -}; + .intr = gf100_ltc_intr, + .cbc_clear = gf100_ltc_cbc_clear, + .cbc_wait = gf100_ltc_cbc_wait, + .zbc = 16, + .zbc_clear_color = gf100_ltc_zbc_clear_color, + .zbc_clear_depth = gf100_ltc_zbc_clear_depth, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c new file mode 100644 index 000000000000..b39b5d0eb8f9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +gk104_ltc_init(struct nouveau_object *object) +{ + struct nvkm_ltc_priv *priv = (void *)object; + u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); + int ret; + + ret = nvkm_ltc_init(priv); + if (ret) + return ret; + + nv_wr32(priv, 0x17e8d8, priv->ltc_nr); + nv_wr32(priv, 0x17e000, priv->ltc_nr); + nv_wr32(priv, 0x17e8d4, priv->tag_base); + nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + return 0; +} + +struct nouveau_oclass * +gk104_ltc_oclass = &(struct nvkm_ltc_impl) { + .base.handle = NV_SUBDEV(LTC, 0xe4), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = gf100_ltc_ctor, + .dtor = gf100_ltc_dtor, + .init = gk104_ltc_init, + .fini = _nvkm_ltc_fini, + }, + .intr = gf100_ltc_intr, + .cbc_clear = gf100_ltc_cbc_clear, + .cbc_wait = gf100_ltc_cbc_wait, + .zbc = 16, + .zbc_clear_color = gf100_ltc_zbc_clear_color, + .zbc_clear_depth = gf100_ltc_zbc_clear_depth, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c index e79d0e81de40..89fc4238f50c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c @@ -25,10 +25,45 @@ #include <subdev/fb.h> #include <subdev/timer.h> -#include "gf100.h" +#include "priv.h" static void -gm107_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) +gm107_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit) +{ + nv_wr32(priv, 0x17e270, start); + nv_wr32(priv, 0x17e274, limit); + nv_wr32(priv, 0x17e26c, 0x00000004); +} + +static void +gm107_ltc_cbc_wait(struct nvkm_ltc_priv *priv) +{ + int c, s; + for (c = 0; c < priv->ltc_nr; c++) { + for (s = 0; s < priv->lts_nr; s++) + nv_wait(priv, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0); + } +} + +static void +gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) +{ + nv_mask(priv, 0x17e338, 0x0000000f, i); + nv_wr32(priv, 0x17e33c, color[0]); + nv_wr32(priv, 0x17e340, color[1]); + nv_wr32(priv, 0x17e344, color[2]); + nv_wr32(priv, 0x17e348, color[3]); +} + +static void +gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth) +{ + nv_mask(priv, 0x17e338, 0x0000000f, i); + nv_wr32(priv, 0x17e34c, depth); +} + +static void +gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts) { u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400); u32 stat = nv_rd32(priv, base + 0x00c); @@ -40,56 +75,48 @@ gm107_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) } static void -gm107_ltcg_intr(struct nouveau_subdev *subdev) +gm107_ltc_intr(struct nouveau_subdev *subdev) { - struct gf100_ltcg_priv *priv = (void *)subdev; + struct nvkm_ltc_priv *priv = (void *)subdev; u32 mask; mask = nv_rd32(priv, 0x00017c); while (mask) { u32 lts, ltc = __ffs(mask); for (lts = 0; lts < priv->lts_nr; lts++) - gm107_ltcg_lts_isr(priv, ltc, lts); + gm107_ltc_lts_isr(priv, ltc, lts); mask &= ~(1 << ltc); } - - /* we do something horribly wrong and upset PMFB a lot, so mask off - * interrupts from it after the first one until it's fixed - */ - nv_mask(priv, 0x000640, 0x02000000, 0x00000000); } -static void -gm107_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) +static int +gm107_ltc_init(struct nouveau_object *object) { - struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; - u32 last = first + count - 1; - int p, i; - - BUG_ON((first > last) || (last >= priv->num_tags)); + struct nvkm_ltc_priv *priv = (void *)object; + u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); + int ret; - nv_wr32(priv, 0x17e270, first); - nv_wr32(priv, 0x17e274, last); - nv_wr32(priv, 0x17e26c, 0x4); /* trigger clear */ + ret = nvkm_ltc_init(priv); + if (ret) + return ret; - /* wait until it's finished with clearing */ - for (p = 0; p < priv->ltc_nr; ++p) { - for (i = 0; i < priv->lts_nr; ++i) - nv_wait(priv, 0x14046c + p * 0x2000 + i * 0x200, ~0, 0); - } + nv_wr32(priv, 0x17e27c, priv->ltc_nr); + nv_wr32(priv, 0x17e278, priv->tag_base); + nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + return 0; } static int -gm107_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, +gm107_ltc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct gf100_ltcg_priv *priv; struct nouveau_fb *pfb = nouveau_fb(parent); + struct nvkm_ltc_priv *priv; u32 parts, mask; int ret, i; - ret = nouveau_ltcg_create(parent, engine, oclass, &priv); + ret = nvkm_ltc_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -102,41 +129,26 @@ gm107_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, } priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28; - ret = gf100_ltcg_init_tag_ram(pfb, priv); - if (ret) - return ret; - - priv->base.tags_alloc = gf100_ltcg_tags_alloc; - priv->base.tags_free = gf100_ltcg_tags_free; - priv->base.tags_clear = gm107_ltcg_tags_clear; - - nv_subdev(priv)->intr = gm107_ltcg_intr; - return 0; -} - -static int -gm107_ltcg_init(struct nouveau_object *object) -{ - struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; - struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; - int ret; - - ret = nouveau_ltcg_init(ltcg); + ret = gf100_ltc_init_tag_ram(pfb, priv); if (ret) return ret; - nv_wr32(priv, 0x17e27c, priv->ltc_nr); - nv_wr32(priv, 0x17e278, priv->tag_base); return 0; } struct nouveau_oclass * -gm107_ltcg_oclass = &(struct nouveau_oclass) { - .handle = NV_SUBDEV(LTCG, 0xff), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = gm107_ltcg_ctor, - .dtor = gf100_ltcg_dtor, - .init = gm107_ltcg_init, - .fini = _nouveau_ltcg_fini, +gm107_ltc_oclass = &(struct nvkm_ltc_impl) { + .base.handle = NV_SUBDEV(LTC, 0xff), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_ltc_ctor, + .dtor = gf100_ltc_dtor, + .init = gm107_ltc_init, + .fini = _nvkm_ltc_fini, }, -}; + .intr = gm107_ltc_intr, + .cbc_clear = gm107_ltc_cbc_clear, + .cbc_wait = gm107_ltc_cbc_wait, + .zbc = 16, + .zbc_clear_color = gm107_ltc_zbc_clear_color, + .zbc_clear_depth = gm107_ltc_zbc_clear_depth, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h new file mode 100644 index 000000000000..41f179d93da6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h @@ -0,0 +1,71 @@ +#ifndef __NVKM_LTC_PRIV_H__ +#define __NVKM_LTC_PRIV_H__ + +#include <subdev/ltc.h> +#include <subdev/fb.h> + +#include <core/enum.h> + +struct nvkm_ltc_priv { + struct nouveau_ltc base; + u32 ltc_nr; + u32 lts_nr; + + u32 num_tags; + u32 tag_base; + struct nouveau_mm tags; + struct nouveau_mm_node *tag_ram; + + u32 zbc_color[NOUVEAU_LTC_MAX_ZBC_CNT][4]; + u32 zbc_depth[NOUVEAU_LTC_MAX_ZBC_CNT]; +}; + +#define nvkm_ltc_create(p,e,o,d) \ + nvkm_ltc_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nvkm_ltc_destroy(p) ({ \ + struct nvkm_ltc_priv *_priv = (p); \ + _nvkm_ltc_dtor(nv_object(_priv)); \ +}) +#define nvkm_ltc_init(p) ({ \ + struct nvkm_ltc_priv *_priv = (p); \ + _nvkm_ltc_init(nv_object(_priv)); \ +}) +#define nvkm_ltc_fini(p,s) ({ \ + struct nvkm_ltc_priv *_priv = (p); \ + _nvkm_ltc_fini(nv_object(_priv), (s)); \ +}) + +int nvkm_ltc_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); + +#define _nvkm_ltc_dtor _nouveau_subdev_dtor +int _nvkm_ltc_init(struct nouveau_object *); +#define _nvkm_ltc_fini _nouveau_subdev_fini + +int gf100_ltc_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void gf100_ltc_dtor(struct nouveau_object *); +int gf100_ltc_init_tag_ram(struct nouveau_fb *, struct nvkm_ltc_priv *); +int gf100_ltc_tags_alloc(struct nouveau_ltc *, u32, struct nouveau_mm_node **); +void gf100_ltc_tags_free(struct nouveau_ltc *, struct nouveau_mm_node **); + +struct nvkm_ltc_impl { + struct nouveau_oclass base; + void (*intr)(struct nouveau_subdev *); + + void (*cbc_clear)(struct nvkm_ltc_priv *, u32 start, u32 limit); + void (*cbc_wait)(struct nvkm_ltc_priv *); + + int zbc; + void (*zbc_clear_color)(struct nvkm_ltc_priv *, int, const u32[4]); + void (*zbc_clear_depth)(struct nvkm_ltc_priv *, int, const u32); +}; + +void gf100_ltc_intr(struct nouveau_subdev *); +void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *, u32, u32); +void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *); +void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *, int, const u32[4]); +void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *, int, const u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h deleted file mode 100644 index 87b10b8412ea..000000000000 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __NVKM_LTCG_PRIV_GF100_H__ -#define __NVKM_LTCG_PRIV_GF100_H__ - -#include <subdev/ltcg.h> - -struct gf100_ltcg_priv { - struct nouveau_ltcg base; - u32 ltc_nr; - u32 lts_nr; - u32 num_tags; - u32 tag_base; - struct nouveau_mm tags; - struct nouveau_mm_node *tag_ram; -}; - -void gf100_ltcg_dtor(struct nouveau_object *); -int gf100_ltcg_init_tag_ram(struct nouveau_fb *, struct gf100_ltcg_priv *); -int gf100_ltcg_tags_alloc(struct nouveau_ltcg *, u32, struct nouveau_mm_node **); -void gf100_ltcg_tags_free(struct nouveau_ltcg *, struct nouveau_mm_node **); - -#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c index 8a5555192fa5..ca7cee3a314a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c @@ -22,9 +22,17 @@ * Authors: Ben Skeggs */ -#include <subdev/mc.h> +#include "priv.h" #include <core/option.h> +static inline void +nouveau_mc_unk260(struct nouveau_mc *pmc, u32 data) +{ + const struct nouveau_mc_oclass *impl = (void *)nv_oclass(pmc); + if (impl->unk260) + impl->unk260(pmc, data); +} + static inline u32 nouveau_mc_intr_mask(struct nouveau_mc *pmc) { @@ -114,6 +122,8 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + pmc->unk260 = nouveau_mc_unk260; + if (nv_device_is_pci(device)) switch (device->pdev->device & 0x0ff0) { case 0x00f0: diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c new file mode 100644 index 000000000000..b8d6cb435d0a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nv04.h" + +struct nouveau_oclass * +gk20a_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0xea), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv50_mc_init, + .fini = _nouveau_mc_fini, + }, + .intr = nvc0_mc_intr, + .msi_rearm = nv40_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h index 81a408e7d034..4d9ea46c47c2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h @@ -1,7 +1,7 @@ #ifndef __NVKM_MC_NV04_H__ #define __NVKM_MC_NV04_H__ -#include <subdev/mc.h> +#include "priv.h" struct nv04_mc_priv { struct nouveau_mc base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c index f9c6a678b47d..15d41dc176ff 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c @@ -41,7 +41,7 @@ nvc0_mc_intr[] = { { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ { 0x01000000, NVDEV_SUBDEV_PWR }, - { 0x02000000, NVDEV_SUBDEV_LTCG }, + { 0x02000000, NVDEV_SUBDEV_LTC }, { 0x08000000, NVDEV_SUBDEV_FB }, { 0x10000000, NVDEV_SUBDEV_BUS }, { 0x40000000, NVDEV_SUBDEV_IBUS }, @@ -56,6 +56,12 @@ nvc0_mc_msi_rearm(struct nouveau_mc *pmc) nv_wr32(priv, 0x088704, 0x00000000); } +void +nvc0_mc_unk260(struct nouveau_mc *pmc, u32 data) +{ + nv_wr32(pmc, 0x000260, data); +} + struct nouveau_oclass * nvc0_mc_oclass = &(struct nouveau_mc_oclass) { .base.handle = NV_SUBDEV(MC, 0xc0), @@ -67,4 +73,5 @@ nvc0_mc_oclass = &(struct nouveau_mc_oclass) { }, .intr = nvc0_mc_intr, .msi_rearm = nvc0_mc_msi_rearm, + .unk260 = nvc0_mc_unk260, }.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c index 837e545aeb9f..68b5f61aadb5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c @@ -35,4 +35,5 @@ nvc3_mc_oclass = &(struct nouveau_mc_oclass) { }, .intr = nvc0_mc_intr, .msi_rearm = nv40_mc_msi_rearm, + .unk260 = nvc0_mc_unk260, }.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h new file mode 100644 index 000000000000..911e66392587 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h @@ -0,0 +1,38 @@ +#ifndef __NVKM_MC_PRIV_H__ +#define __NVKM_MC_PRIV_H__ + +#include <subdev/mc.h> + +#define nouveau_mc_create(p,e,o,d) \ + nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_mc_destroy(p) ({ \ + struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \ +}) +#define nouveau_mc_init(p) ({ \ + struct nouveau_mc *pmc = (p); _nouveau_mc_init(nv_object(pmc)); \ +}) +#define nouveau_mc_fini(p,s) ({ \ + struct nouveau_mc *pmc = (p); _nouveau_mc_fini(nv_object(pmc), (s)); \ +}) + +int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void _nouveau_mc_dtor(struct nouveau_object *); +int _nouveau_mc_init(struct nouveau_object *); +int _nouveau_mc_fini(struct nouveau_object *, bool); + +struct nouveau_mc_intr { + u32 stat; + u32 unit; +}; + +struct nouveau_mc_oclass { + struct nouveau_oclass base; + const struct nouveau_mc_intr *intr; + void (*msi_rearm)(struct nouveau_mc *); + void (*unk260)(struct nouveau_mc *, u32); +}; + +void nvc0_mc_unk260(struct nouveau_mc *, u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c index d4fd3bc9c66f..0ab55f27ec45 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c @@ -22,9 +22,18 @@ * Authors: Ben Skeggs */ -#include <subdev/pwr.h> #include <subdev/timer.h> +#include "priv.h" + +static void +nouveau_pwr_pgob(struct nouveau_pwr *ppwr, bool enable) +{ + const struct nvkm_pwr_impl *impl = (void *)nv_oclass(ppwr); + if (impl->pgob) + impl->pgob(ppwr, enable); +} + static int nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2], u32 process, u32 message, u32 data0, u32 data1) @@ -177,6 +186,7 @@ _nouveau_pwr_fini(struct nouveau_object *object, bool suspend) int _nouveau_pwr_init(struct nouveau_object *object) { + const struct nvkm_pwr_impl *impl = (void *)object->oclass; struct nouveau_pwr *ppwr = (void *)object; int ret, i; @@ -186,24 +196,27 @@ _nouveau_pwr_init(struct nouveau_object *object) nv_subdev(ppwr)->intr = nouveau_pwr_intr; ppwr->message = nouveau_pwr_send; + ppwr->pgob = nouveau_pwr_pgob; /* prevent previous ucode from running, wait for idle, reset */ nv_wr32(ppwr, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */ nv_wait(ppwr, 0x10a04c, 0xffffffff, 0x00000000); nv_mask(ppwr, 0x000200, 0x00002000, 0x00000000); nv_mask(ppwr, 0x000200, 0x00002000, 0x00002000); + nv_rd32(ppwr, 0x000200); + nv_wait(ppwr, 0x10a10c, 0x00000006, 0x00000000); /* upload data segment */ nv_wr32(ppwr, 0x10a1c0, 0x01000000); - for (i = 0; i < ppwr->data.size / 4; i++) - nv_wr32(ppwr, 0x10a1c4, ppwr->data.data[i]); + for (i = 0; i < impl->data.size / 4; i++) + nv_wr32(ppwr, 0x10a1c4, impl->data.data[i]); /* upload code segment */ nv_wr32(ppwr, 0x10a180, 0x01000000); - for (i = 0; i < ppwr->code.size / 4; i++) { + for (i = 0; i < impl->code.size / 4; i++) { if ((i & 0x3f) == 0) nv_wr32(ppwr, 0x10a188, i >> 6); - nv_wr32(ppwr, 0x10a184, ppwr->code.data[i]); + nv_wr32(ppwr, 0x10a184, impl->code.data[i]); } /* start it running */ @@ -245,3 +258,15 @@ nouveau_pwr_create_(struct nouveau_object *parent, init_waitqueue_head(&ppwr->recv.wait); return 0; } + +int +_nouveau_pwr_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_pwr *ppwr; + int ret = nouveau_pwr_create(parent, engine, oclass, &ppwr); + *pobject = nv_object(ppwr); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc new file mode 100644 index 000000000000..214a6d9e088d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc @@ -0,0 +1,94 @@ +/* + * Copyright 2014 Martin Peres <martin.peres@free.fr> + * + * 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 folloing 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: Martin Peres + */ + +/****************************************************************************** + * arith data segment + *****************************************************************************/ +#ifdef INCLUDE_PROC +#endif + +#ifdef INCLUDE_DATA +#endif + +/****************************************************************************** + * arith code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE + +// does a 32x32 -> 64 multiplication +// +// A * B = A_lo * B_lo +// + ( A_hi * B_lo ) << 16 +// + ( A_lo * B_hi ) << 16 +// + ( A_hi * B_hi ) << 32 +// +// $r15 - current +// $r14 - A +// $r13 - B +// $r12 - mul_lo (return) +// $r11 - mul_hi (return) +// $r0 - zero +mulu32_32_64: + push $r1 // A_hi + push $r2 // B_hi + push $r3 // tmp0 + push $r4 // tmp1 + + shr b32 $r1 $r14 16 + shr b32 $r2 $r13 16 + + clear b32 $r12 + clear b32 $r11 + + // A_lo * B_lo + mulu $r12 $r14 $r13 + + // ( A_hi * B_lo ) << 16 + mulu $r3 $r1 $r13 // tmp0 = A_hi * B_lo + mov b32 $r4 $r3 + and $r3 0xffff // tmp0 = tmp0_lo + shl b32 $r3 16 + shr b32 $r4 16 // tmp1 = tmp0_hi + add b32 $r12 $r3 + adc b32 $r11 $r4 + + // ( A_lo * B_hi ) << 16 + mulu $r3 $r14 $r2 // tmp0 = A_lo * B_hi + mov b32 $r4 $r3 + and $r3 0xffff // tmp0 = tmp0_lo + shl b32 $r3 16 + shr b32 $r4 16 // tmp1 = tmp0_hi + add b32 $r12 $r3 + adc b32 $r11 $r4 + + // ( A_hi * B_hi ) << 32 + mulu $r3 $r1 $r2 // tmp0 = A_hi * B_hi + add b32 $r11 $r3 + + pop $r4 + pop $r3 + pop $r2 + pop $r1 + ret +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc index 8f29badd785f..5cf5be63cbef 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc @@ -98,12 +98,16 @@ wr32: // $r14 - ns // $r0 - zero nsec: + push $r9 + push $r8 nv_iord($r8, NV_PPWR_TIMER_LOW) nsec_loop: nv_iord($r9, NV_PPWR_TIMER_LOW) sub b32 $r9 $r8 cmp b32 $r9 $r14 bra l #nsec_loop + pop $r8 + pop $r9 ret // busy-wait for a period of time @@ -115,6 +119,8 @@ nsec: // $r11 - timeout (ns) // $r0 - zero wait: + push $r9 + push $r8 nv_iord($r8, NV_PPWR_TIMER_LOW) wait_loop: nv_rd32($r10, $r14) @@ -126,6 +132,8 @@ wait: cmp b32 $r9 $r11 bra l #wait_loop wait_done: + pop $r8 + pop $r9 ret // $r15 - current (kern) @@ -242,12 +250,89 @@ intr: bclr $flags $p0 iret -// request the current process be sent a message after a timeout expires +// calculate the number of ticks in the specified nanoseconds delay +// +// $r15 - current +// $r14 - ns +// $r14 - ticks (return) +// $r0 - zero +ticks_from_ns: + push $r12 + push $r11 + + /* try not losing precision (multiply then divide) */ + imm32($r13, HW_TICKS_PER_US) + call #mulu32_32_64 + + /* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */ + div $r12 $r12 1000 + + /* check if there wasn't any overflow */ + cmpu b32 $r11 0 + bra e #ticks_from_ns_quit + + /* let's divide then multiply, too bad for the precision! */ + div $r14 $r14 1000 + imm32($r13, HW_TICKS_PER_US) + call #mulu32_32_64 + + /* this cannot overflow as long as HW_TICKS_PER_US < 1000 */ + +ticks_from_ns_quit: + mov b32 $r14 $r12 + pop $r11 + pop $r12 + ret + +// calculate the number of ticks in the specified microsecond delay +// +// $r15 - current +// $r14 - us +// $r14 - ticks (return) +// $r0 - zero +ticks_from_us: + push $r12 + push $r11 + + /* simply multiply $us by HW_TICKS_PER_US */ + imm32($r13, HW_TICKS_PER_US) + call #mulu32_32_64 + mov b32 $r14 $r12 + + /* check if there wasn't any overflow */ + cmpu b32 $r11 0 + bra e #ticks_from_us_quit + + /* Overflow! */ + clear b32 $r14 + +ticks_from_us_quit: + pop $r11 + pop $r12 + ret + +// calculate the number of ticks in the specified microsecond delay // // $r15 - current // $r14 - ticks +// $r14 - us (return) +// $r0 - zero +ticks_to_us: + /* simply divide $ticks by HW_TICKS_PER_US */ + imm32($r13, HW_TICKS_PER_US) + div $r14 $r14 $r13 + + ret + +// request the current process be sent a message after a timeout expires +// +// $r15 - current +// $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow) // $r0 - zero timer: + push $r9 + push $r8 + // interrupts off to prevent racing with timer isr bclr $flags ie0 @@ -255,13 +340,22 @@ timer: ld b32 $r8 D[$r15 + #proc_time] cmp b32 $r8 0 bra g #timer_done - st b32 D[$r15 + #proc_time] $r14 - // halt watchdog timer temporarily and check for a pending - // interrupt. if there's one already pending, we can just - // bail since the timer isr will queue the next soonest - // right after it's done + // halt watchdog timer temporarily + clear b32 $r8 nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8) + + // find out how much time elapsed since the last update + // of the watchdog and add this time to the wanted ticks + nv_iord($r8, NV_PPWR_WATCHDOG_TIME) + ld b32 $r9 D[$r0 + #time_prev] + sub b32 $r9 $r8 + add b32 $r14 $r9 + st b32 D[$r15 + #proc_time] $r14 + + // check for a pending interrupt. if there's one already + // pending, we can just bail since the timer isr will + // queue the next soonest right after it's done nv_iord($r8, NV_PPWR_INTR) and $r8 NV_PPWR_INTR_WATCHDOG bra nz #timer_enable @@ -272,10 +366,10 @@ timer: cmp b32 $r14 $r0 bra e #timer_reset cmp b32 $r14 $r8 - bra l #timer_done - timer_reset: - nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14) - st b32 D[$r0 + #time_prev] $r14 + bra g #timer_enable + timer_reset: + nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14) + st b32 D[$r0 + #time_prev] $r14 // re-enable the watchdog timer timer_enable: @@ -285,6 +379,9 @@ timer: // interrupts back on timer_done: bset $flags ie0 + + pop $r8 + pop $r9 ret // send message to another process @@ -371,6 +468,9 @@ send: // $r14 - process // $r0 - zero recv: + push $r9 + push $r8 + ld b32 $r8 D[$r14 + #proc_qget] ld b32 $r9 D[$r14 + #proc_qput] bclr $flags $p1 @@ -403,6 +503,8 @@ recv: bset $flags $p1 pop $r15 recv_done: + pop $r8 + pop $r9 ret init: diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc index e2a63ac5422b..96fc984dafdc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc @@ -242,7 +242,7 @@ */ push reg /* */ pop $r13 /* */ pop $r14 /* -*/ call(wr32) /* +*/ call(wr32) #else #define nv_wr32(addr,reg) /* */ sethi $r0 0x14000000 /* @@ -250,3 +250,23 @@ */ st b32 D[$r0] reg /* */ clear b32 $r0 #endif + +#define st(size, addr, reg) /* +*/ movw $r0 addr /* +*/ st size D[$r0] reg /* +*/ clear b32 $r0 + +#define ld(size, reg, addr) /* +*/ movw $r0 addr /* +*/ ld size reg D[$r0] /* +*/ clear b32 $r0 + +// does a 64+64 -> 64 unsigned addition (C = A + B) +#define addu64(reg_a_c_hi, reg_a_c_lo, b_hi, b_lo) /* +*/ add b32 reg_a_c_lo b_lo /* +*/ adc b32 reg_a_c_hi b_hi + +// does a 64+64 -> 64 substraction (C = A - B) +#define subu64(reg_a_c_hi, reg_a_c_lo, b_hi, b_lo) /* +*/ sub b32 reg_a_c_lo b_lo /* +*/ sbb b32 reg_a_c_hi b_hi diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc index d43741eccb11..e89789a53b80 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc @@ -43,17 +43,23 @@ process(PROC_MEMX, #memx_init, #memx_recv) */ .b32 func memx_func_head: -handler(ENTER , 0x0001, 0x0000, #memx_func_enter) +handler(ENTER , 0x0000, 0x0000, #memx_func_enter) memx_func_next: handler(LEAVE , 0x0000, 0x0000, #memx_func_leave) handler(WR32 , 0x0000, 0x0002, #memx_func_wr32) handler(WAIT , 0x0004, 0x0000, #memx_func_wait) handler(DELAY , 0x0001, 0x0000, #memx_func_delay) +handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank) memx_func_tail: .equ #memx_func_size #memx_func_next - #memx_func_head .equ #memx_func_num (#memx_func_tail - #memx_func_head) / #memx_func_size +memx_ts_start: +.b32 0 +memx_ts_end: +.b32 0 + memx_data_head: .skip 0x0800 memx_data_tail: @@ -67,19 +73,44 @@ memx_data_tail: // // $r15 - current (memx) // $r4 - packet length -// +00: bitmask of heads to wait for vblank on // $r3 - opcode desciption // $r0 - zero memx_func_enter: +#if NVKM_PPWR_CHIPSET == GT215 + movw $r8 0x1610 + nv_rd32($r7, $r8) + imm32($r6, 0xfffffffc) + and $r7 $r6 + movw $r6 0x2 + or $r7 $r6 + nv_wr32($r8, $r7) +#else + movw $r6 0x001620 + imm32($r7, ~0x00000aa2); + nv_rd32($r8, $r6) + and $r8 $r7 + nv_wr32($r6, $r8) + + imm32($r7, ~0x00000001) + nv_rd32($r8, $r6) + and $r8 $r7 + nv_wr32($r6, $r8) + + movw $r6 0x0026f0 + nv_rd32($r8, $r6) + and $r8 $r7 + nv_wr32($r6, $r8) +#endif + mov $r6 NV_PPWR_OUTPUT_SET_FB_PAUSE nv_iowr(NV_PPWR_OUTPUT_SET, $r6) memx_func_enter_wait: nv_iord($r6, NV_PPWR_OUTPUT) and $r6 NV_PPWR_OUTPUT_FB_PAUSE bra z #memx_func_enter_wait - //XXX: TODO - ld b32 $r6 D[$r1 + 0x00] - add b32 $r1 0x04 + + nv_iord($r6, NV_PPWR_TIMER_LOW) + st b32 D[$r0 + #memx_ts_start] $r6 ret // description @@ -89,14 +120,93 @@ memx_func_enter: // $r3 - opcode desciption // $r0 - zero memx_func_leave: + nv_iord($r6, NV_PPWR_TIMER_LOW) + st b32 D[$r0 + #memx_ts_end] $r6 + mov $r6 NV_PPWR_OUTPUT_CLR_FB_PAUSE nv_iowr(NV_PPWR_OUTPUT_CLR, $r6) memx_func_leave_wait: nv_iord($r6, NV_PPWR_OUTPUT) and $r6 NV_PPWR_OUTPUT_FB_PAUSE bra nz #memx_func_leave_wait + +#if NVKM_PPWR_CHIPSET == GT215 + movw $r8 0x1610 + nv_rd32($r7, $r8) + imm32($r6, 0xffffffcc) + and $r7 $r6 + nv_wr32($r8, $r7) +#else + movw $r6 0x0026f0 + imm32($r7, 0x00000001) + nv_rd32($r8, $r6) + or $r8 $r7 + nv_wr32($r6, $r8) + + movw $r6 0x001620 + nv_rd32($r8, $r6) + or $r8 $r7 + nv_wr32($r6, $r8) + + imm32($r7, 0x00000aa2); + nv_rd32($r8, $r6) + or $r8 $r7 + nv_wr32($r6, $r8) +#endif + ret + +#if NVKM_PPWR_CHIPSET < GF119 +// description +// +// $r15 - current (memx) +// $r4 - packet length +// +00: head to wait for vblank on +// $r3 - opcode desciption +// $r0 - zero +memx_func_wait_vblank: + ld b32 $r6 D[$r1 + 0x00] + cmp b32 $r6 0x0 + bra z #memx_func_wait_vblank_head0 + cmp b32 $r6 0x1 + bra z #memx_func_wait_vblank_head1 + bra #memx_func_wait_vblank_fini + + memx_func_wait_vblank_head1: + movw $r7 0x20 + bra #memx_func_wait_vblank_0 + + memx_func_wait_vblank_head0: + movw $r7 0x8 + + memx_func_wait_vblank_0: + nv_iord($r6, NV_PPWR_INPUT) + and $r6 $r7 + bra nz #memx_func_wait_vblank_0 + + memx_func_wait_vblank_1: + nv_iord($r6, NV_PPWR_INPUT) + and $r6 $r7 + bra z #memx_func_wait_vblank_1 + + memx_func_wait_vblank_fini: + add b32 $r1 0x4 + ret + +#else + +// XXX: currently no-op +// +// $r15 - current (memx) +// $r4 - packet length +// +00: head to wait for vblank on +// $r3 - opcode desciption +// $r0 - zero +memx_func_wait_vblank: + add b32 $r1 0x4 ret +#endif + // description // // $r15 - current (memx) @@ -160,14 +270,17 @@ memx_exec: push $r13 mov b32 $r1 $r12 mov b32 $r2 $r11 + memx_exec_next: - // fetch the packet header, and locate opcode info + // fetch the packet header ld b32 $r3 D[$r1] add b32 $r1 4 - shr b32 $r4 $r3 16 - mulu $r3 #memx_func_size + extr $r4 $r3 16:31 + extr $r3 $r3 0:15 // execute the opcode handler + sub b32 $r3 1 + mulu $r3 #memx_func_size ld b32 $r5 D[$r3 + #memx_func_head + #memx_func] call $r5 @@ -176,6 +289,10 @@ memx_exec: bra l #memx_exec_next // send completion reply + ld b32 $r11 D[$r0 + #memx_ts_start] + ld b32 $r12 D[$r0 + #memx_ts_end] + sub b32 $r12 $r11 + nv_iord($r11, NV_PPWR_INPUT) pop $r13 pop $r14 call(send) diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc index 17a8a383d91a..b439519ec866 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc @@ -23,6 +23,7 @@ */ #define NVKM_PPWR_CHIPSET GK208 +#define HW_TICKS_PER_US 324 #define NVKM_FALCON_PC24 #define NVKM_FALCON_UNSHIFTED_IO @@ -34,6 +35,7 @@ .section #nv108_pwr_data #define INCLUDE_PROC #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -44,6 +46,7 @@ #define INCLUDE_DATA #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -56,6 +59,7 @@ .section #nv108_pwr_code #define INCLUDE_CODE #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h index 39a5dc150a05..4d278a96b2bb 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h @@ -24,8 +24,8 @@ uint32_t nv108_pwr_data[] = { 0x00000000, /* 0x0058: proc_list_head */ 0x54534f48, - 0x00000379, - 0x0000032a, + 0x00000453, + 0x00000404, 0x00000000, 0x00000000, 0x00000000, @@ -46,8 +46,8 @@ uint32_t nv108_pwr_data[] = { 0x00000000, 0x00000000, 0x584d454d, - 0x0000046f, - 0x00000461, + 0x0000061c, + 0x0000060e, 0x00000000, 0x00000000, 0x00000000, @@ -68,8 +68,8 @@ uint32_t nv108_pwr_data[] = { 0x00000000, 0x00000000, 0x46524550, - 0x00000473, - 0x00000471, + 0x00000620, + 0x0000061e, 0x00000000, 0x00000000, 0x00000000, @@ -90,8 +90,8 @@ uint32_t nv108_pwr_data[] = { 0x00000000, 0x00000000, 0x5f433249, - 0x00000877, - 0x0000071e, + 0x00000a24, + 0x000008cb, 0x00000000, 0x00000000, 0x00000000, @@ -112,8 +112,8 @@ uint32_t nv108_pwr_data[] = { 0x00000000, 0x00000000, 0x54534554, - 0x00000898, - 0x00000879, + 0x00000a45, + 0x00000a26, 0x00000000, 0x00000000, 0x00000000, @@ -134,8 +134,8 @@ uint32_t nv108_pwr_data[] = { 0x00000000, 0x00000000, 0x454c4449, - 0x000008a3, - 0x000008a1, + 0x00000a50, + 0x00000a4e, 0x00000000, 0x00000000, 0x00000000, @@ -227,24 +227,31 @@ uint32_t nv108_pwr_data[] = { 0x00000000, 0x00000000, /* 0x0370: memx_func_head */ - 0x00010000, - 0x00000000, - 0x000003a9, -/* 0x037c: memx_func_next */ 0x00000001, 0x00000000, - 0x000003c7, + 0x00000483, +/* 0x037c: memx_func_next */ 0x00000002, + 0x00000000, + 0x00000500, + 0x00000003, 0x00000002, - 0x000003df, - 0x00040003, + 0x00000580, + 0x00040004, + 0x00000000, + 0x0000059d, + 0x00010005, + 0x00000000, + 0x000005b7, + 0x00010006, + 0x00000000, + 0x0000057b, +/* 0x03b8: memx_func_tail */ +/* 0x03b8: memx_ts_start */ 0x00000000, - 0x00000407, - 0x00010004, +/* 0x03bc: memx_ts_end */ 0x00000000, - 0x00000421, -/* 0x03ac: memx_func_tail */ -/* 0x03ac: memx_data_head */ +/* 0x03c0: memx_data_head */ 0x00000000, 0x00000000, 0x00000000, @@ -757,8 +764,8 @@ uint32_t nv108_pwr_data[] = { 0x00000000, 0x00000000, 0x00000000, -/* 0x0bac: memx_data_tail */ -/* 0x0bac: i2c_scl_map */ +/* 0x0bc0: memx_data_tail */ +/* 0x0bc0: i2c_scl_map */ 0x00000400, 0x00000800, 0x00001000, @@ -769,7 +776,7 @@ uint32_t nv108_pwr_data[] = { 0x00020000, 0x00040000, 0x00080000, -/* 0x0bd4: i2c_sda_map */ +/* 0x0be8: i2c_sda_map */ 0x00100000, 0x00200000, 0x00400000, @@ -781,10 +788,69 @@ uint32_t nv108_pwr_data[] = { 0x10000000, 0x20000000, 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; uint32_t nv108_pwr_code[] = { - 0x02910ef5, + 0x031c0ef5, /* 0x0004: rd32 */ 0xf607a040, 0x04bd000e, @@ -812,15 +878,18 @@ uint32_t nv108_pwr_code[] = { 0x7000d4f1, 0xf8f61bf4, /* 0x005d: nsec */ - 0xcf2c0800, -/* 0x0062: nsec_loop */ + 0xf990f900, + 0xcf2c0880, +/* 0x0066: nsec_loop */ 0x2c090088, 0xbb0099cf, 0x9ea60298, - 0xf8f61ef4, -/* 0x0071: wait */ - 0xcf2c0800, -/* 0x0076: wait_loop */ + 0xfcf61ef4, + 0xf890fc80, +/* 0x0079: wait */ + 0xf990f900, + 0xcf2c0880, +/* 0x0082: wait_loop */ 0xeeb20088, 0x0000047e, 0xadfddab2, @@ -828,28 +897,29 @@ uint32_t nv108_pwr_code[] = { 0x2c09100b, 0xbb0099cf, 0x9ba60298, -/* 0x0093: wait_done */ - 0xf8e61ef4, -/* 0x0095: intr_watchdog */ +/* 0x009f: wait_done */ + 0xfce61ef4, + 0xf890fc80, +/* 0x00a5: intr_watchdog */ 0x03e99800, 0xf40096b0, 0x0a98280b, 0x029abb9a, 0x0d0e1cf4, - 0x01de7e01, + 0x02617e01, 0xf494bd00, -/* 0x00b2: intr_watchdog_next_time */ +/* 0x00c2: intr_watchdog_next_time */ 0x0a98140e, 0x00a6b09b, 0xa6080bf4, 0x061cf49a, -/* 0x00c0: intr_watchdog_next_time_set */ -/* 0x00c3: intr_watchdog_next_proc */ +/* 0x00d0: intr_watchdog_next_time_set */ +/* 0x00d3: intr_watchdog_next_proc */ 0xb59b09b5, 0xe0b603e9, 0x68e6b158, 0xc81bf402, -/* 0x00d2: intr */ +/* 0x00e2: intr */ 0x00f900f8, 0x80f904bd, 0xa0f990f9, @@ -865,13 +935,13 @@ uint32_t nv108_pwr_code[] = { 0xc40088cf, 0x0bf40289, 0x9b00b51f, - 0x957e580e, + 0xa57e580e, 0x09980000, 0x0096b09b, 0x000d0bf4, 0x0009f634, 0x09b504bd, -/* 0x0125: intr_skip_watchdog */ +/* 0x0135: intr_skip_watchdog */ 0x0089e49a, 0x360bf408, 0xcf068849, @@ -881,20 +951,20 @@ uint32_t nv108_pwr_code[] = { 0xc0f900cc, 0xf14f484e, 0x0d5453e3, - 0x023f7e00, + 0x02c27e00, 0x40c0fc00, 0x0cf604c0, -/* 0x0157: intr_subintr_skip_fifo */ +/* 0x0167: intr_subintr_skip_fifo */ 0x4004bd00, 0x09f60688, -/* 0x015f: intr_skip_subintr */ +/* 0x016f: intr_skip_subintr */ 0xc404bd00, 0x0bf42089, 0xbfa4f107, -/* 0x0169: intr_skip_pause */ +/* 0x0179: intr_skip_pause */ 0x4089c4ff, 0xf1070bf4, -/* 0x0173: intr_skip_user0 */ +/* 0x0183: intr_skip_user0 */ 0x00ffbfa4, 0x0008f604, 0x80fc04bd, @@ -904,551 +974,682 @@ uint32_t nv108_pwr_code[] = { 0xfca0fcb0, 0xfc80fc90, 0x0032f400, -/* 0x0196: timer */ - 0x32f401f8, - 0x03f89810, - 0xf40086b0, - 0xfeb53a1c, - 0xf6380003, +/* 0x01a6: ticks_from_ns */ + 0xc0f901f8, + 0xd7f1b0f9, + 0xd3f00144, + 0x7721f500, + 0xe8ccec03, + 0x00b4b003, + 0xec120bf4, + 0xf103e8ee, + 0xf00144d7, + 0x21f500d3, +/* 0x01ce: ticks_from_ns_quit */ + 0xceb20377, + 0xc0fcb0fc, +/* 0x01d6: ticks_from_us */ + 0xc0f900f8, + 0xd7f1b0f9, + 0xd3f00144, + 0x7721f500, + 0xb0ceb203, + 0x0bf400b4, +/* 0x01ef: ticks_from_us_quit */ + 0xfce4bd05, + 0xf8c0fcb0, +/* 0x01f5: ticks_to_us */ + 0x44d7f100, + 0x00d3f001, + 0xf8ecedff, +/* 0x0201: timer */ + 0xf990f900, + 0x1032f480, + 0xb003f898, + 0x1cf40086, + 0x0084bd4a, + 0x0008f638, + 0x340804bd, + 0x980088cf, + 0x98bb9a09, + 0x00e9bb02, + 0x0803feb5, + 0x0088cf08, + 0xf40284f0, + 0x34081c1b, + 0xa60088cf, + 0x080bf4e0, + 0x1cf4e8a6, +/* 0x0245: timer_reset */ + 0xf634000d, + 0x04bd000e, +/* 0x024f: timer_enable */ + 0x089a0eb5, + 0xf6380001, 0x04bd0008, - 0x88cf0808, - 0x0284f000, - 0x081c1bf4, - 0x0088cf34, - 0x0bf4e0a6, - 0xf4e8a608, -/* 0x01c6: timer_reset */ - 0x3400161e, - 0xbd000ef6, - 0x9a0eb504, -/* 0x01d0: timer_enable */ - 0x38000108, - 0xbd0008f6, -/* 0x01d9: timer_done */ - 0x1031f404, -/* 0x01de: send_proc */ - 0x80f900f8, - 0xe89890f9, - 0x04e99805, - 0xa60486f0, - 0x2a0bf489, - 0x940398c4, - 0x80b60488, - 0x008ebb18, - 0xb500fa98, - 0x8db5008a, - 0x028cb501, - 0xb6038bb5, - 0x94f00190, - 0x04e9b507, -/* 0x0217: send_done */ - 0xfc0231f4, - 0xf880fc90, -/* 0x021d: find */ - 0x0880f900, - 0x0131f458, -/* 0x0224: find_loop */ - 0xa6008a98, - 0x100bf4ae, - 0xb15880b6, - 0xf4026886, - 0x32f4f11b, -/* 0x0239: find_done */ - 0xfc8eb201, -/* 0x023f: send */ - 0x7e00f880, - 0xf400021d, - 0x00f89b01, -/* 0x0248: recv */ - 0x9805e898, - 0x32f404e9, - 0xf489a601, - 0x89c43c0b, - 0x0180b603, - 0xb50784f0, - 0xea9805e8, - 0xfef0f902, - 0xf0f9018f, - 0x9994efb2, - 0x00e9bb04, - 0x9818e0b6, - 0xec9803eb, - 0x01ed9802, - 0xf900ee98, - 0xfef0fca5, - 0x31f400f8, -/* 0x028f: recv_done */ - 0xf8f0fc01, -/* 0x0291: init */ - 0x01084100, - 0xe70011cf, - 0xb6010911, - 0x14fe0814, - 0x00e04100, - 0x000013f0, - 0x0001f61c, - 0xff0104bd, - 0x01f61400, - 0x0104bd00, - 0x0015f102, - 0xf6100008, - 0x04bd0001, - 0xf000d241, - 0x10fe0013, - 0x1031f400, - 0x38000101, +/* 0x0258: timer_done */ + 0xfc1031f4, + 0xf890fc80, +/* 0x0261: send_proc */ + 0xf980f900, + 0x05e89890, + 0xf004e998, + 0x89a60486, + 0xc42a0bf4, + 0x88940398, + 0x1880b604, + 0x98008ebb, + 0x8ab500fa, + 0x018db500, + 0xb5028cb5, + 0x90b6038b, + 0x0794f001, + 0xf404e9b5, +/* 0x029a: send_done */ + 0x90fc0231, + 0x00f880fc, +/* 0x02a0: find */ + 0x580880f9, +/* 0x02a7: find_loop */ + 0x980131f4, + 0xaea6008a, + 0xb6100bf4, + 0x86b15880, + 0x1bf40268, + 0x0132f4f1, +/* 0x02bc: find_done */ + 0x80fc8eb2, +/* 0x02c2: send */ + 0xa07e00f8, + 0x01f40002, +/* 0x02cb: recv */ + 0xf900f89b, + 0x9880f990, + 0xe99805e8, + 0x0132f404, + 0x0bf489a6, + 0x0389c43c, + 0xf00180b6, + 0xe8b50784, + 0x02ea9805, + 0x8ffef0f9, + 0xb2f0f901, + 0x049994ef, + 0xb600e9bb, + 0xeb9818e0, + 0x02ec9803, + 0x9801ed98, + 0xa5f900ee, + 0xf8fef0fc, + 0x0131f400, +/* 0x0316: recv_done */ + 0x80fcf0fc, + 0x00f890fc, +/* 0x031c: init */ + 0xcf010841, + 0x11e70011, + 0x14b60109, + 0x0014fe08, + 0xf000e041, + 0x1c000013, 0xbd0001f6, -/* 0x02db: init_proc */ - 0x98580f04, - 0x16b001f1, - 0xfa0bf400, - 0xf0b615f9, - 0xf20ef458, -/* 0x02ec: host_send */ - 0xcf04b041, - 0xa0420011, - 0x0022cf04, - 0x0bf412a6, - 0x071ec42e, - 0xb704ee94, - 0x980270e0, - 0xec9803eb, - 0x01ed9802, - 0x7e00ee98, - 0xb600023f, - 0x1ec40110, - 0x04b0400f, - 0xbd000ef6, - 0xc70ef404, -/* 0x0328: host_send_done */ -/* 0x032a: host_recv */ - 0x494100f8, - 0x5413f14e, - 0xf4e1a652, -/* 0x0336: host_recv_wait */ - 0xcc41b90b, - 0x0011cf04, - 0xcf04c842, - 0x16f00022, - 0xf412a608, - 0x23c4ef0b, - 0x0434b607, - 0x02f030b7, - 0xb5033bb5, - 0x3db5023c, - 0x003eb501, - 0xf00120b6, - 0xc8400f24, - 0x0002f604, - 0x400204bd, - 0x02f60000, - 0xf804bd00, -/* 0x0379: host_init */ - 0x00804100, - 0xf11014b6, - 0x40027015, - 0x01f604d0, + 0x00ff0104, + 0x0001f614, + 0x020104bd, + 0x080015f1, + 0x01f61000, 0x4104bd00, + 0x13f000e2, + 0x0010fe00, + 0x011031f4, + 0xf6380001, + 0x04bd0001, +/* 0x0366: init_proc */ + 0xf198580f, + 0x0016b001, + 0xf9fa0bf4, + 0x58f0b615, +/* 0x0377: mulu32_32_64 */ + 0xf9f20ef4, + 0xf920f910, + 0x9540f930, + 0xd29510e1, + 0xbdc4bd10, + 0xc0edffb4, + 0xb2301dff, + 0xff34f134, + 0x1034b6ff, + 0xbb1045b6, + 0xb4bb00c3, + 0x30e2ff01, + 0x34f134b2, + 0x34b6ffff, + 0x1045b610, + 0xbb00c3bb, + 0x12ff01b4, + 0x00b3bb30, + 0x30fc40fc, + 0x10fc20fc, +/* 0x03c6: host_send */ + 0xb04100f8, + 0x0011cf04, + 0xcf04a042, + 0x12a60022, + 0xc42e0bf4, + 0xee94071e, + 0x70e0b704, + 0x03eb9802, + 0x9802ec98, + 0xee9801ed, + 0x02c27e00, + 0x0110b600, + 0x400f1ec4, + 0x0ef604b0, + 0xf404bd00, +/* 0x0402: host_send_done */ + 0x00f8c70e, +/* 0x0404: host_recv */ + 0xf14e4941, + 0xa6525413, + 0xb90bf4e1, +/* 0x0410: host_recv_wait */ + 0xcf04cc41, + 0xc8420011, + 0x0022cf04, + 0xa60816f0, + 0xef0bf412, + 0xb60723c4, + 0x30b70434, + 0x3bb502f0, + 0x023cb503, + 0xb5013db5, + 0x20b6003e, + 0x0f24f001, + 0xf604c840, + 0x04bd0002, + 0x00004002, + 0xbd0002f6, +/* 0x0453: host_init */ + 0x4100f804, 0x14b60080, - 0xf015f110, - 0x04dc4002, + 0x7015f110, + 0x04d04002, + 0xbd0001f6, + 0x00804104, + 0xf11014b6, + 0x4002f015, + 0x01f604dc, + 0x0104bd00, + 0x04c44001, 0xbd0001f6, - 0x40010104, - 0x01f604c4, - 0xf804bd00, -/* 0x03a9: memx_func_enter */ - 0x40040600, - 0x06f607e0, -/* 0x03b3: memx_func_enter_wait */ - 0x4604bd00, - 0x66cf07c0, - 0x0464f000, - 0x98f70bf4, - 0x10b60016, -/* 0x03c7: memx_func_leave */ - 0x0600f804, - 0x07e44004, - 0xbd0006f6, -/* 0x03d1: memx_func_leave_wait */ - 0x07c04604, - 0xf00066cf, - 0x1bf40464, -/* 0x03df: memx_func_wr32 */ - 0x9800f8f7, - 0x15980016, - 0x0810b601, - 0x50f960f9, +/* 0x0483: memx_func_enter */ + 0xf100f804, + 0xf1162067, + 0xf1f55d77, + 0xb2ffff73, + 0x00047e6e, + 0xfdd8b200, + 0x60f90487, + 0xd0fc80f9, + 0x2e7ee0fc, + 0x77f10000, + 0x73f1fffe, + 0x6eb2ffff, + 0x0000047e, + 0x87fdd8b2, + 0xf960f904, + 0xfcd0fc80, + 0x002e7ee0, + 0xf067f100, + 0x7e6eb226, + 0xb2000004, + 0x0487fdd8, + 0x80f960f9, 0xe0fcd0fc, 0x00002e7e, - 0x140003f1, - 0xa00506fd, - 0xb604bd05, - 0x1bf40242, -/* 0x0407: memx_func_wait */ - 0x0800f8dd, - 0x0088cf2c, - 0x98001e98, - 0x1c98011d, - 0x031b9802, - 0x7e1010b6, - 0xf8000071, -/* 0x0421: memx_func_delay */ - 0x001e9800, - 0x7e0410b6, - 0xf800005d, -/* 0x042d: memx_exec */ - 0xf9e0f900, - 0xb2c1b2d0, -/* 0x0435: memx_exec_next */ - 0x001398b2, - 0x950410b6, - 0x30f01034, - 0xde35980c, - 0x12a655f9, - 0xfced1ef4, + 0xe0400406, + 0x0006f607, +/* 0x04ea: memx_func_enter_wait */ + 0xc04604bd, + 0x0066cf07, + 0xf40464f0, + 0x2c06f70b, + 0xb50066cf, + 0x00f8ee06, +/* 0x0500: memx_func_leave */ + 0x66cf2c06, + 0xef06b500, + 0xe4400406, + 0x0006f607, +/* 0x0512: memx_func_leave_wait */ + 0xc04604bd, + 0x0066cf07, + 0xf40464f0, + 0x67f1f71b, + 0x77f126f0, + 0x73f00001, + 0x7e6eb200, + 0xb2000004, + 0x0587fdd8, + 0x80f960f9, + 0xe0fcd0fc, + 0x00002e7e, + 0x162067f1, + 0x047e6eb2, + 0xd8b20000, + 0xf90587fd, + 0xfc80f960, 0x7ee0fcd0, - 0xf800023f, -/* 0x0455: memx_info */ - 0x03ac4c00, - 0x7e08004b, - 0xf800023f, -/* 0x0461: memx_recv */ - 0x01d6b000, - 0xb0c90bf4, - 0x0bf400d6, -/* 0x046f: memx_init */ - 0xf800f8eb, -/* 0x0471: perf_recv */ -/* 0x0473: perf_init */ - 0xf800f800, -/* 0x0475: i2c_drive_scl */ - 0x0036b000, - 0x400d0bf4, - 0x01f607e0, - 0xf804bd00, -/* 0x0485: i2c_drive_scl_lo */ - 0x07e44000, - 0xbd0001f6, -/* 0x048f: i2c_drive_sda */ - 0xb000f804, - 0x0bf40036, - 0x07e0400d, - 0xbd0002f6, -/* 0x049f: i2c_drive_sda_lo */ - 0x4000f804, - 0x02f607e4, - 0xf804bd00, -/* 0x04a9: i2c_sense_scl */ - 0x0132f400, - 0xcf07c443, - 0x31fd0033, - 0x060bf404, -/* 0x04bb: i2c_sense_scl_done */ - 0xf80131f4, -/* 0x04bd: i2c_sense_sda */ - 0x0132f400, - 0xcf07c443, - 0x32fd0033, - 0x060bf404, -/* 0x04cf: i2c_sense_sda_done */ - 0xf80131f4, -/* 0x04d1: i2c_raise_scl */ - 0x4440f900, - 0x01030898, - 0x0004757e, -/* 0x04dc: i2c_raise_scl_wait */ - 0x7e03e84e, - 0x7e00005d, - 0xf40004a9, - 0x42b60901, - 0xef1bf401, -/* 0x04f0: i2c_raise_scl_done */ - 0x00f840fc, -/* 0x04f4: i2c_start */ - 0x0004a97e, - 0x7e0d11f4, - 0xf40004bd, - 0x0ef40611, -/* 0x0505: i2c_start_rep */ - 0x7e00032e, - 0x03000475, - 0x048f7e01, - 0x0076bb00, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0xd17e50fc, - 0x64b60004, - 0x1d11f404, -/* 0x0530: i2c_start_send */ - 0x8f7e0003, - 0x884e0004, - 0x005d7e13, - 0x7e000300, - 0x4e000475, - 0x5d7e1388, -/* 0x054a: i2c_start_out */ - 0x00f80000, -/* 0x054c: i2c_stop */ - 0x757e0003, - 0x00030004, - 0x00048f7e, - 0x7e03e84e, - 0x0300005d, - 0x04757e01, - 0x13884e00, + 0xf100002e, + 0xf00aa277, + 0x6eb20073, + 0x0000047e, + 0x87fdd8b2, + 0xf960f905, + 0xfcd0fc80, + 0x002e7ee0, +/* 0x057b: memx_func_wait_vblank */ + 0xb600f800, + 0x00f80410, +/* 0x0580: memx_func_wr32 */ + 0x98001698, + 0x10b60115, + 0xf960f908, + 0xfcd0fc50, + 0x002e7ee0, + 0x0242b600, + 0xf8e81bf4, +/* 0x059d: memx_func_wait */ + 0xcf2c0800, + 0x1e980088, + 0x011d9800, + 0x98021c98, + 0x10b6031b, + 0x00797e10, +/* 0x05b7: memx_func_delay */ + 0x9800f800, + 0x10b6001e, + 0x005d7e04, +/* 0x05c3: memx_exec */ + 0xf900f800, + 0xb2d0f9e0, +/* 0x05cb: memx_exec_next */ + 0x98b2b2c1, + 0x10b60013, + 0xf034e704, + 0xe033e701, + 0x0132b601, + 0x980c30f0, + 0x55f9de35, + 0x1ef412a6, + 0xee0b98e5, + 0xbbef0c98, + 0xc44b02cb, + 0x00bbcf07, + 0xe0fcd0fc, + 0x0002c27e, +/* 0x0602: memx_info */ + 0xc04c00f8, + 0x08004b03, + 0x0002c27e, +/* 0x060e: memx_recv */ + 0xd6b000f8, + 0xb20bf401, + 0xf400d6b0, + 0x00f8eb0b, +/* 0x061c: memx_init */ +/* 0x061e: perf_recv */ + 0x00f800f8, +/* 0x0620: perf_init */ +/* 0x0622: i2c_drive_scl */ + 0x36b000f8, + 0x0d0bf400, + 0xf607e040, + 0x04bd0001, +/* 0x0632: i2c_drive_scl_lo */ + 0xe44000f8, + 0x0001f607, + 0x00f804bd, +/* 0x063c: i2c_drive_sda */ + 0xf40036b0, + 0xe0400d0b, + 0x0002f607, + 0x00f804bd, +/* 0x064c: i2c_drive_sda_lo */ + 0xf607e440, + 0x04bd0002, +/* 0x0656: i2c_sense_scl */ + 0x32f400f8, + 0x07c44301, + 0xfd0033cf, + 0x0bf40431, + 0x0131f406, +/* 0x0668: i2c_sense_scl_done */ +/* 0x066a: i2c_sense_sda */ + 0x32f400f8, + 0x07c44301, + 0xfd0033cf, + 0x0bf40432, + 0x0131f406, +/* 0x067c: i2c_sense_sda_done */ +/* 0x067e: i2c_raise_scl */ + 0x40f900f8, + 0x03089844, + 0x06227e01, +/* 0x0689: i2c_raise_scl_wait */ + 0x03e84e00, 0x00005d7e, - 0x8f7e0103, - 0x884e0004, - 0x005d7e13, -/* 0x057b: i2c_bitw */ - 0x7e00f800, - 0x4e00048f, - 0x5d7e03e8, - 0x76bb0000, + 0x0006567e, + 0xb60901f4, + 0x1bf40142, +/* 0x069d: i2c_raise_scl_done */ + 0xf840fcef, +/* 0x06a1: i2c_start */ + 0x06567e00, + 0x0d11f400, + 0x00066a7e, + 0xf40611f4, +/* 0x06b2: i2c_start_rep */ + 0x00032e0e, + 0x0006227e, + 0x3c7e0103, + 0x76bb0006, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0x7e50fc04, - 0xb60004d1, + 0xb600067e, 0x11f40464, - 0x13884e17, - 0x00005d7e, - 0x757e0003, - 0x884e0004, - 0x005d7e13, -/* 0x05b9: i2c_bitw_out */ -/* 0x05bb: i2c_bitr */ - 0x0300f800, - 0x048f7e01, +/* 0x06dd: i2c_start_send */ + 0x7e00031d, + 0x4e00063c, + 0x5d7e1388, + 0x00030000, + 0x0006227e, + 0x7e13884e, +/* 0x06f7: i2c_start_out */ + 0xf800005d, +/* 0x06f9: i2c_stop */ + 0x7e000300, + 0x03000622, + 0x063c7e00, 0x03e84e00, 0x00005d7e, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0x04d17e50, - 0x0464b600, - 0x7e1a11f4, - 0x030004bd, - 0x04757e00, - 0x13884e00, - 0x00005d7e, - 0xf4013cf0, -/* 0x05fe: i2c_bitr_done */ - 0x00f80131, -/* 0x0600: i2c_get_byte */ - 0x08040005, -/* 0x0604: i2c_get_byte_next */ - 0xbb0154b6, + 0x227e0103, + 0x884e0006, + 0x005d7e13, + 0x7e010300, + 0x4e00063c, + 0x5d7e1388, + 0x00f80000, +/* 0x0728: i2c_bitw */ + 0x00063c7e, + 0x7e03e84e, + 0xbb00005d, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x0005bb7e, + 0x00067e7e, 0xf40464b6, - 0x53fd2a11, - 0x0142b605, - 0x03d81bf4, - 0x0076bb01, + 0x884e1711, + 0x005d7e13, + 0x7e000300, + 0x4e000622, + 0x5d7e1388, +/* 0x0766: i2c_bitw_out */ + 0x00f80000, +/* 0x0768: i2c_bitr */ + 0x3c7e0103, + 0xe84e0006, + 0x005d7e03, + 0x0076bb00, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, - 0x7b7e50fc, - 0x64b60005, -/* 0x064d: i2c_get_byte_done */ -/* 0x064f: i2c_put_byte */ - 0x0400f804, -/* 0x0651: i2c_put_byte_next */ - 0x0142b608, - 0xbb3854ff, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x00057b7e, - 0xf40464b6, - 0x46b03411, - 0xd81bf400, + 0x7e7e50fc, + 0x64b60006, + 0x1a11f404, + 0x00066a7e, + 0x227e0003, + 0x884e0006, + 0x005d7e13, + 0x013cf000, +/* 0x07ab: i2c_bitr_done */ + 0xf80131f4, +/* 0x07ad: i2c_get_byte */ + 0x04000500, +/* 0x07b1: i2c_get_byte_next */ + 0x0154b608, 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x05bb7e50, + 0x07687e50, 0x0464b600, - 0xbb0f11f4, - 0x36b00076, - 0x061bf401, -/* 0x06a7: i2c_put_byte_done */ - 0xf80132f4, -/* 0x06a9: i2c_addr */ - 0x0076bb00, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0xf47e50fc, - 0x64b60004, - 0x2911f404, - 0x012ec3e7, - 0xfd0134b6, - 0x76bb0553, + 0xfd2a11f4, + 0x42b60553, + 0xd81bf401, + 0x76bb0103, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0x7e50fc04, - 0xb600064f, -/* 0x06ee: i2c_addr_done */ + 0xb6000728, +/* 0x07fa: i2c_get_byte_done */ 0x00f80464, -/* 0x06f0: i2c_acquire_addr */ - 0xb6f8cec7, - 0xe0b705e4, - 0x00f8d014, -/* 0x06fc: i2c_acquire */ - 0x0006f07e, - 0x0000047e, - 0x7e03d9f0, - 0xf800002e, -/* 0x070d: i2c_release */ - 0x06f07e00, - 0x00047e00, - 0x03daf000, - 0x00002e7e, -/* 0x071e: i2c_recv */ - 0x32f400f8, - 0xf8c1c701, - 0xb00214b6, - 0x1ff52816, - 0x13b80137, - 0x98000bd4, - 0x13b80032, - 0x98000bac, - 0x31f40031, - 0xf9d0f902, - 0xf1d0f9e0, - 0xf1000067, - 0x92100063, - 0x76bb0167, - 0x0465b600, - 0x659450f9, - 0x0256bb04, - 0x75fd50bd, - 0x7e50fc04, - 0xb60006fc, - 0xd0fc0464, - 0xf500d6b0, - 0x0500b01b, - 0x0076bb00, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0xa97e50fc, - 0x64b60006, - 0xcc11f504, - 0xe0c5c700, +/* 0x07fc: i2c_put_byte */ +/* 0x07fe: i2c_put_byte_next */ + 0x42b60804, + 0x3854ff01, 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x064f7e50, + 0x07287e50, 0x0464b600, - 0x00a911f5, - 0x76bb0105, + 0xb03411f4, + 0x1bf40046, + 0x0076bbd8, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x687e50fc, + 0x64b60007, + 0x0f11f404, + 0xb00076bb, + 0x1bf40136, + 0x0132f406, +/* 0x0854: i2c_put_byte_done */ +/* 0x0856: i2c_addr */ + 0x76bb00f8, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0x7e50fc04, - 0xb60006a9, - 0x11f50464, - 0x76bb0087, + 0xb60006a1, + 0x11f40464, + 0x2ec3e729, + 0x0134b601, + 0xbb0553fd, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x0007fc7e, +/* 0x089b: i2c_addr_done */ + 0xf80464b6, +/* 0x089d: i2c_acquire_addr */ + 0xf8cec700, + 0xb705e4b6, + 0xf8d014e0, +/* 0x08a9: i2c_acquire */ + 0x089d7e00, + 0x00047e00, + 0x03d9f000, + 0x00002e7e, +/* 0x08ba: i2c_release */ + 0x9d7e00f8, + 0x047e0008, + 0xdaf00000, + 0x002e7e03, +/* 0x08cb: i2c_recv */ + 0xf400f800, + 0xc1c70132, + 0x0214b6f8, + 0xf52816b0, + 0xb801371f, + 0x000be813, + 0xb8003298, + 0x000bc013, + 0xf4003198, + 0xd0f90231, + 0xd0f9e0f9, + 0x000067f1, + 0x100063f1, + 0xbb016792, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x0008a97e, + 0xfc0464b6, + 0x00d6b0d0, + 0x00b01bf5, + 0x76bb0005, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0x7e50fc04, - 0xb6000600, - 0x11f40464, - 0xe05bcb67, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0x054c7e50, - 0x0464b600, - 0x74bd5bb2, -/* 0x0823: i2c_recv_not_rd08 */ - 0xb0410ef4, - 0x1bf401d6, - 0x7e00053b, - 0xf40006a9, - 0xc5c73211, - 0x064f7ee0, - 0x2811f400, - 0xa97e0005, - 0x11f40006, - 0xe0b5c71f, - 0x00064f7e, - 0x7e1511f4, - 0xbd00054c, - 0x08c5c774, - 0xf4091bf4, - 0x0ef40232, -/* 0x0861: i2c_recv_not_wr08 */ -/* 0x0861: i2c_recv_done */ - 0xf8cec703, - 0x00070d7e, - 0xd0fce0fc, - 0xb20912f4, - 0x023f7e7c, -/* 0x0875: i2c_recv_exit */ -/* 0x0877: i2c_init */ - 0xf800f800, -/* 0x0879: test_recv */ - 0x04584100, - 0xb60011cf, - 0x58400110, - 0x0001f604, - 0xe7f104bd, - 0xe3f1d900, - 0x967e134f, - 0x00f80001, -/* 0x0898: test_init */ - 0x7e08004e, - 0xf8000196, -/* 0x08a1: idle_recv */ -/* 0x08a3: idle */ - 0xf400f800, - 0x54410031, + 0xb6000856, + 0x11f50464, + 0xc5c700cc, + 0x0076bbe0, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0xfc7e50fc, + 0x64b60007, + 0xa911f504, + 0xbb010500, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x0008567e, + 0xf50464b6, + 0xbb008711, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x0007ad7e, + 0xf40464b6, + 0x5bcb6711, + 0x0076bbe0, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0xf97e50fc, + 0x64b60006, + 0xbd5bb204, + 0x410ef474, +/* 0x09d0: i2c_recv_not_rd08 */ + 0xf401d6b0, + 0x00053b1b, + 0x0008567e, + 0xc73211f4, + 0xfc7ee0c5, + 0x11f40007, + 0x7e000528, + 0xf4000856, + 0xb5c71f11, + 0x07fc7ee0, + 0x1511f400, + 0x0006f97e, + 0xc5c774bd, + 0x091bf408, + 0xf40232f4, +/* 0x0a0e: i2c_recv_not_wr08 */ +/* 0x0a0e: i2c_recv_done */ + 0xcec7030e, + 0x08ba7ef8, + 0xfce0fc00, + 0x0912f4d0, + 0xc27e7cb2, +/* 0x0a22: i2c_recv_exit */ + 0x00f80002, +/* 0x0a24: i2c_init */ +/* 0x0a26: test_recv */ + 0x584100f8, 0x0011cf04, 0x400110b6, - 0x01f60454, -/* 0x08b7: idle_loop */ - 0x0104bd00, - 0x0232f458, -/* 0x08bc: idle_proc */ -/* 0x08bc: idle_proc_exec */ - 0x1eb210f9, - 0x0002487e, - 0x11f410fc, - 0x0231f409, -/* 0x08cf: idle_proc_next */ - 0xb6f00ef4, - 0x1fa65810, - 0xf4e81bf4, - 0x28f4e002, - 0xc60ef400, + 0x01f60458, + 0xf104bd00, + 0xf1d900e7, + 0x7e134fe3, + 0xf8000201, +/* 0x0a45: test_init */ + 0x08004e00, + 0x0002017e, +/* 0x0a4e: idle_recv */ + 0x00f800f8, +/* 0x0a50: idle */ + 0x410031f4, + 0x11cf0454, + 0x0110b600, + 0xf6045440, + 0x04bd0001, +/* 0x0a64: idle_loop */ + 0x32f45801, +/* 0x0a69: idle_proc */ +/* 0x0a69: idle_proc_exec */ + 0xb210f902, + 0x02cb7e1e, + 0xf410fc00, + 0x31f40911, + 0xf00ef402, +/* 0x0a7c: idle_proc_next */ + 0xa65810b6, + 0xe81bf41f, + 0xf4e002f4, + 0x0ef40028, + 0x000000c6, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc index 6744fcc06151..daa06c1c655e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc @@ -23,6 +23,7 @@ */ #define NVKM_PPWR_CHIPSET GT215 +#define HW_TICKS_PER_US 203 // should be 202.5 //#define NVKM_FALCON_PC24 //#define NVKM_FALCON_UNSHIFTED_IO @@ -34,6 +35,7 @@ .section #nva3_pwr_data #define INCLUDE_PROC #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -44,6 +46,7 @@ #define INCLUDE_DATA #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -56,6 +59,7 @@ .section #nva3_pwr_code #define INCLUDE_CODE #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h index 254205cd5166..64e97baabc3c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h @@ -24,8 +24,8 @@ uint32_t nva3_pwr_data[] = { 0x00000000, /* 0x0058: proc_list_head */ 0x54534f48, - 0x00000430, - 0x000003cd, + 0x00000512, + 0x000004af, 0x00000000, 0x00000000, 0x00000000, @@ -46,8 +46,8 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, 0x584d454d, - 0x0000054e, - 0x00000540, + 0x000006e0, + 0x000006d2, 0x00000000, 0x00000000, 0x00000000, @@ -68,8 +68,8 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, 0x46524550, - 0x00000552, - 0x00000550, + 0x000006e4, + 0x000006e2, 0x00000000, 0x00000000, 0x00000000, @@ -90,8 +90,8 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, 0x5f433249, - 0x00000982, - 0x00000825, + 0x00000b14, + 0x000009b7, 0x00000000, 0x00000000, 0x00000000, @@ -112,8 +112,8 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, 0x54534554, - 0x000009ab, - 0x00000984, + 0x00000b3d, + 0x00000b16, 0x00000000, 0x00000000, 0x00000000, @@ -134,8 +134,8 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, 0x454c4449, - 0x000009b7, - 0x000009b5, + 0x00000b49, + 0x00000b47, 0x00000000, 0x00000000, 0x00000000, @@ -227,27 +227,31 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, /* 0x0370: memx_func_head */ - 0x00010000, - 0x00000000, - 0x0000046f, -/* 0x037c: memx_func_next */ 0x00000001, 0x00000000, - 0x00000496, + 0x00000551, +/* 0x037c: memx_func_next */ 0x00000002, + 0x00000000, + 0x000005a8, + 0x00000003, 0x00000002, - 0x000004b7, - 0x00040003, + 0x0000063a, + 0x00040004, 0x00000000, - 0x000004df, - 0x00010004, + 0x00000656, + 0x00010005, 0x00000000, - 0x000004fc, -/* 0x03ac: memx_func_tail */ -/* 0x03ac: memx_data_head */ + 0x00000673, + 0x00010006, 0x00000000, + 0x000005f8, +/* 0x03b8: memx_func_tail */ +/* 0x03b8: memx_ts_start */ 0x00000000, +/* 0x03bc: memx_ts_end */ 0x00000000, +/* 0x03c0: memx_data_head */ 0x00000000, 0x00000000, 0x00000000, @@ -757,8 +761,11 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, 0x00000000, -/* 0x0bac: memx_data_tail */ -/* 0x0bac: i2c_scl_map */ + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0bc0: memx_data_tail */ +/* 0x0bc0: i2c_scl_map */ 0x00001000, 0x00004000, 0x00010000, @@ -769,7 +776,7 @@ uint32_t nva3_pwr_data[] = { 0x01000000, 0x04000000, 0x10000000, -/* 0x0bd4: i2c_sda_map */ +/* 0x0be8: i2c_sda_map */ 0x00002000, 0x00008000, 0x00020000, @@ -780,7 +787,7 @@ uint32_t nva3_pwr_data[] = { 0x02000000, 0x08000000, 0x20000000, -/* 0x0bfc: i2c_ctrl */ +/* 0x0c10: i2c_ctrl */ 0x0000e138, 0x0000e150, 0x0000e168, @@ -841,15 +848,10 @@ uint32_t nva3_pwr_data[] = { 0x00000000, 0x00000000, 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, }; uint32_t nva3_pwr_code[] = { - 0x030d0ef5, + 0x039e0ef5, /* 0x0004: rd32 */ 0x07a007f1, 0xd00604b6, @@ -885,19 +887,22 @@ uint32_t nva3_pwr_code[] = { 0xd4f100dd, 0x1bf47000, /* 0x007f: nsec */ - 0xf000f8f2, + 0xf900f8f2, + 0xf080f990, 0x84b62c87, 0x0088cf06, -/* 0x0088: nsec_loop */ +/* 0x008c: nsec_loop */ 0xb62c97f0, 0x99cf0694, 0x0298bb00, 0xf4069eb8, - 0x00f8f11e, -/* 0x009c: wait */ + 0x80fcf11e, + 0x00f890fc, +/* 0x00a4: wait */ + 0x80f990f9, 0xb62c87f0, 0x88cf0684, -/* 0x00a5: wait_loop */ +/* 0x00b1: wait_loop */ 0x02eeb900, 0xb90421f4, 0xadfd02da, @@ -907,28 +912,29 @@ uint32_t nva3_pwr_code[] = { 0x0099cf06, 0xb80298bb, 0x1ef4069b, -/* 0x00c9: wait_done */ -/* 0x00cb: intr_watchdog */ - 0x9800f8df, +/* 0x00d5: wait_done */ + 0xfc80fcdf, +/* 0x00db: intr_watchdog */ + 0x9800f890, 0x96b003e9, 0x2a0bf400, 0xbb9a0a98, 0x1cf4029a, 0x01d7f00f, - 0x025421f5, + 0x02dd21f5, 0x0ef494bd, -/* 0x00e9: intr_watchdog_next_time */ +/* 0x00f9: intr_watchdog_next_time */ 0x9b0a9815, 0xf400a6b0, 0x9ab8090b, 0x061cf406, -/* 0x00f8: intr_watchdog_next_time_set */ -/* 0x00fb: intr_watchdog_next_proc */ +/* 0x0108: intr_watchdog_next_time_set */ +/* 0x010b: intr_watchdog_next_proc */ 0x809b0980, 0xe0b603e9, 0x68e6b158, 0xc61bf402, -/* 0x010a: intr */ +/* 0x011a: intr */ 0x00f900f8, 0x80f904bd, 0xa0f990f9, @@ -948,13 +954,13 @@ uint32_t nva3_pwr_code[] = { 0xf40289c4, 0x0080230b, 0x58e7f09b, - 0x98cb21f4, + 0x98db21f4, 0x96b09b09, 0x110bf400, 0xb63407f0, 0x09d00604, 0x8004bd00, -/* 0x016e: intr_skip_watchdog */ +/* 0x017e: intr_skip_watchdog */ 0x89e49a09, 0x0bf40800, 0x8897f148, @@ -967,22 +973,22 @@ uint32_t nva3_pwr_code[] = { 0x48e7f1c0, 0x53e3f14f, 0x00d7f054, - 0x02b921f5, + 0x034221f5, 0x07f1c0fc, 0x04b604c0, 0x000cd006, -/* 0x01ae: intr_subintr_skip_fifo */ +/* 0x01be: intr_subintr_skip_fifo */ 0x07f104bd, 0x04b60688, 0x0009d006, -/* 0x01ba: intr_skip_subintr */ +/* 0x01ca: intr_skip_subintr */ 0x89c404bd, 0x070bf420, 0xffbfa4f1, -/* 0x01c4: intr_skip_pause */ +/* 0x01d4: intr_skip_pause */ 0xf44089c4, 0xa4f1070b, -/* 0x01ce: intr_skip_user0 */ +/* 0x01de: intr_skip_user0 */ 0x07f0ffbf, 0x0604b604, 0xbd0008d0, @@ -993,597 +999,733 @@ uint32_t nva3_pwr_code[] = { 0x90fca0fc, 0x00fc80fc, 0xf80032f4, -/* 0x01f5: timer */ - 0x1032f401, - 0xb003f898, - 0x1cf40086, - 0x03fe8051, +/* 0x0205: ticks_from_ns */ + 0xf9c0f901, + 0xcbd7f1b0, + 0x00d3f000, + 0x041321f5, + 0x03e8ccec, + 0xf400b4b0, + 0xeeec120b, + 0xd7f103e8, + 0xd3f000cb, + 0x1321f500, +/* 0x022d: ticks_from_ns_quit */ + 0x02ceb904, + 0xc0fcb0fc, +/* 0x0236: ticks_from_us */ + 0xc0f900f8, + 0xd7f1b0f9, + 0xd3f000cb, + 0x1321f500, + 0x02ceb904, + 0xf400b4b0, + 0xe4bd050b, +/* 0x0250: ticks_from_us_quit */ + 0xc0fcb0fc, +/* 0x0256: ticks_to_us */ + 0xd7f100f8, + 0xd3f000cb, + 0xecedff00, +/* 0x0262: timer */ + 0x90f900f8, + 0x32f480f9, + 0x03f89810, + 0xf40086b0, + 0x84bd651c, 0xb63807f0, 0x08d00604, 0xf004bd00, - 0x84b60887, + 0x84b63487, 0x0088cf06, - 0xf40284f0, - 0x87f0261b, - 0x0684b634, - 0xb80088cf, - 0x0bf406e0, - 0x06e8b809, -/* 0x0233: timer_reset */ - 0xf01f1ef4, - 0x04b63407, - 0x000ed006, - 0x0e8004bd, -/* 0x0241: timer_enable */ - 0x0187f09a, + 0xbb9a0998, + 0xe9bb0298, + 0x03fe8000, + 0xb60887f0, + 0x88cf0684, + 0x0284f000, + 0xf0261bf4, + 0x84b63487, + 0x0088cf06, + 0xf406e0b8, + 0xe8b8090b, + 0x111cf406, +/* 0x02b8: timer_reset */ + 0xb63407f0, + 0x0ed00604, + 0x8004bd00, +/* 0x02c6: timer_enable */ + 0x87f09a0e, + 0x3807f001, + 0xd00604b6, + 0x04bd0008, +/* 0x02d4: timer_done */ + 0xfc1031f4, + 0xf890fc80, +/* 0x02dd: send_proc */ + 0xf980f900, + 0x05e89890, + 0xf004e998, + 0x89b80486, + 0x2a0bf406, + 0x940398c4, + 0x80b60488, + 0x008ebb18, + 0x8000fa98, + 0x8d80008a, + 0x028c8001, + 0xb6038b80, + 0x94f00190, + 0x04e98007, +/* 0x0317: send_done */ + 0xfc0231f4, + 0xf880fc90, +/* 0x031d: find */ + 0xf080f900, + 0x31f45887, +/* 0x0325: find_loop */ + 0x008a9801, + 0xf406aeb8, + 0x80b6100b, + 0x6886b158, + 0xf01bf402, +/* 0x033b: find_done */ + 0xb90132f4, + 0x80fc028e, +/* 0x0342: send */ + 0x21f500f8, + 0x01f4031d, +/* 0x034b: recv */ + 0xf900f897, + 0x9880f990, + 0xe99805e8, + 0x0132f404, + 0xf40689b8, + 0x89c43d0b, + 0x0180b603, + 0x800784f0, + 0xea9805e8, + 0xfef0f902, + 0xf0f9018f, + 0x9402efb9, + 0xe9bb0499, + 0x18e0b600, + 0x9803eb98, + 0xed9802ec, + 0x00ee9801, + 0xf0fca5f9, + 0xf400f8fe, + 0xf0fc0131, +/* 0x0398: recv_done */ + 0x90fc80fc, +/* 0x039e: init */ + 0x17f100f8, + 0x14b60108, + 0x0011cf06, + 0x010911e7, + 0xfe0814b6, + 0x17f10014, + 0x13f000e0, + 0x1c07f000, + 0xd00604b6, + 0x04bd0001, + 0xf0ff17f0, + 0x04b61407, + 0x0001d006, + 0x17f004bd, + 0x0015f102, + 0x1007f008, + 0xd00604b6, + 0x04bd0001, + 0x011a17f1, + 0xfe0013f0, + 0x31f40010, + 0x0117f010, 0xb63807f0, - 0x08d00604, -/* 0x024f: timer_done */ - 0xf404bd00, - 0x00f81031, -/* 0x0254: send_proc */ - 0x90f980f9, - 0x9805e898, - 0x86f004e9, - 0x0689b804, - 0xc42a0bf4, - 0x88940398, - 0x1880b604, - 0x98008ebb, - 0x8a8000fa, - 0x018d8000, - 0x80028c80, - 0x90b6038b, - 0x0794f001, - 0xf404e980, -/* 0x028e: send_done */ - 0x90fc0231, - 0x00f880fc, -/* 0x0294: find */ - 0x87f080f9, - 0x0131f458, -/* 0x029c: find_loop */ - 0xb8008a98, - 0x0bf406ae, - 0x5880b610, - 0x026886b1, - 0xf4f01bf4, -/* 0x02b2: find_done */ - 0x8eb90132, - 0xf880fc02, -/* 0x02b9: send */ - 0x9421f500, - 0x9701f402, -/* 0x02c2: recv */ - 0xe89800f8, - 0x04e99805, - 0xb80132f4, - 0x0bf40689, - 0x0389c43d, - 0xf00180b6, - 0xe8800784, - 0x02ea9805, - 0x8ffef0f9, - 0xb9f0f901, - 0x999402ef, - 0x00e9bb04, - 0x9818e0b6, - 0xec9803eb, - 0x01ed9802, - 0xf900ee98, - 0xfef0fca5, - 0x31f400f8, -/* 0x030b: recv_done */ - 0xf8f0fc01, -/* 0x030d: init */ - 0x0817f100, - 0x0614b601, - 0xe70011cf, - 0xb6010911, - 0x14fe0814, - 0xe017f100, - 0x0013f000, - 0xb61c07f0, 0x01d00604, 0xf004bd00, - 0x07f0ff17, - 0x0604b614, - 0xbd0001d0, - 0x0217f004, - 0x080015f1, - 0xb61007f0, - 0x01d00604, - 0xf104bd00, - 0xf0010a17, - 0x10fe0013, - 0x1031f400, - 0xf00117f0, - 0x04b63807, - 0x0001d006, - 0xf7f004bd, -/* 0x0371: init_proc */ - 0x01f19858, - 0xf40016b0, - 0x15f9fa0b, - 0xf458f0b6, -/* 0x0382: host_send */ - 0x17f1f20e, - 0x14b604b0, - 0x0011cf06, - 0x04a027f1, - 0xcf0624b6, - 0x12b80022, - 0x320bf406, - 0x94071ec4, - 0xe0b704ee, - 0xeb980270, - 0x02ec9803, - 0x9801ed98, - 0x21f500ee, - 0x10b602b9, - 0x0f1ec401, - 0x04b007f1, - 0xd00604b6, - 0x04bd000e, -/* 0x03cb: host_send_done */ - 0xf8ba0ef4, -/* 0x03cd: host_recv */ - 0x4917f100, - 0x5413f14e, - 0x06e1b852, -/* 0x03db: host_recv_wait */ - 0xf1aa0bf4, - 0xb604cc17, - 0x11cf0614, - 0xc827f100, - 0x0624b604, - 0xf00022cf, - 0x12b80816, - 0xe60bf406, - 0xb60723c4, - 0x30b70434, - 0x3b8002f0, - 0x023c8003, - 0x80013d80, - 0x20b6003e, - 0x0f24f001, - 0x04c807f1, +/* 0x0402: init_proc */ + 0xf19858f7, + 0x0016b001, + 0xf9fa0bf4, + 0x58f0b615, +/* 0x0413: mulu32_32_64 */ + 0xf9f20ef4, + 0xf920f910, + 0x9540f930, + 0xd29510e1, + 0xbdc4bd10, + 0xc0edffb4, + 0xb9301dff, + 0x34f10234, + 0x34b6ffff, + 0x1045b610, + 0xbb00c3bb, + 0xe2ff01b4, + 0x0234b930, + 0xffff34f1, + 0xb61034b6, + 0xc3bb1045, + 0x01b4bb00, + 0xbb3012ff, + 0x40fc00b3, + 0x20fc30fc, + 0x00f810fc, +/* 0x0464: host_send */ + 0x04b017f1, + 0xcf0614b6, + 0x27f10011, + 0x24b604a0, + 0x0022cf06, + 0xf40612b8, + 0x1ec4320b, + 0x04ee9407, + 0x0270e0b7, + 0x9803eb98, + 0xed9802ec, + 0x00ee9801, + 0x034221f5, + 0xc40110b6, + 0x07f10f1e, + 0x04b604b0, + 0x000ed006, + 0x0ef404bd, +/* 0x04ad: host_send_done */ +/* 0x04af: host_recv */ + 0xf100f8ba, + 0xf14e4917, + 0xb8525413, + 0x0bf406e1, +/* 0x04bd: host_recv_wait */ + 0xcc17f1aa, + 0x0614b604, + 0xf10011cf, + 0xb604c827, + 0x22cf0624, + 0x0816f000, + 0xf40612b8, + 0x23c4e60b, + 0x0434b607, + 0x02f030b7, + 0x80033b80, + 0x3d80023c, + 0x003e8001, + 0xf00120b6, + 0x07f10f24, + 0x04b604c8, + 0x0002d006, + 0x27f004bd, + 0x0007f040, 0xd00604b6, 0x04bd0002, - 0xf04027f0, - 0x04b60007, - 0x0002d006, - 0x00f804bd, -/* 0x0430: host_init */ - 0x008017f1, - 0xf11014b6, - 0xf1027015, - 0xb604d007, - 0x01d00604, - 0xf104bd00, - 0xb6008017, - 0x15f11014, - 0x07f102f0, - 0x04b604dc, - 0x0001d006, - 0x17f004bd, - 0xc407f101, +/* 0x0512: host_init */ + 0x17f100f8, + 0x14b60080, + 0x7015f110, + 0xd007f102, 0x0604b604, 0xbd0001d0, -/* 0x046f: memx_func_enter */ - 0xf000f804, + 0x8017f104, + 0x1014b600, + 0x02f015f1, + 0x04dc07f1, + 0xd00604b6, + 0x04bd0001, + 0xf10117f0, + 0xb604c407, + 0x01d00604, + 0xf804bd00, +/* 0x0551: memx_func_enter */ + 0x1087f100, + 0x028eb916, + 0xb90421f4, + 0x67f102d7, + 0x63f1fffc, + 0x76fdffff, + 0x0267f104, + 0x0576fd00, + 0x70f980f9, + 0xe0fcd0fc, + 0xf03f21f4, 0x07f10467, 0x04b607e0, 0x0006d006, -/* 0x047e: memx_func_enter_wait */ +/* 0x058a: memx_func_enter_wait */ 0x67f104bd, 0x64b607c0, 0x0066cf06, 0xf40464f0, - 0x1698f30b, - 0x0410b600, -/* 0x0496: memx_func_leave */ - 0x67f000f8, - 0xe407f104, - 0x0604b607, - 0xbd0006d0, -/* 0x04a5: memx_func_leave_wait */ - 0xc067f104, + 0x67f0f30b, + 0x0664b62c, + 0x800066cf, + 0x00f8ee06, +/* 0x05a8: memx_func_leave */ + 0xb62c67f0, + 0x66cf0664, + 0xef068000, + 0xf10467f0, + 0xb607e407, + 0x06d00604, +/* 0x05c3: memx_func_leave_wait */ + 0xf104bd00, + 0xb607c067, + 0x66cf0664, + 0x0464f000, + 0xf1f31bf4, + 0xb9161087, + 0x21f4028e, + 0x02d7b904, + 0xffcc67f1, + 0xffff63f1, + 0xf90476fd, + 0xfc70f980, + 0xf4e0fcd0, + 0x00f83f21, +/* 0x05f8: memx_func_wait_vblank */ + 0xb0001698, + 0x0bf40066, + 0x0166b013, + 0xf4060bf4, +/* 0x060a: memx_func_wait_vblank_head1 */ + 0x77f12e0e, + 0x0ef40020, +/* 0x0611: memx_func_wait_vblank_head0 */ + 0x0877f107, +/* 0x0615: memx_func_wait_vblank_0 */ + 0xc467f100, 0x0664b607, - 0xf00066cf, - 0x1bf40464, -/* 0x04b7: memx_func_wr32 */ - 0x9800f8f3, - 0x15980016, - 0x0810b601, - 0x50f960f9, - 0xe0fcd0fc, - 0xf13f21f4, - 0xfd140003, - 0x05800506, - 0xb604bd00, - 0x1bf40242, -/* 0x04df: memx_func_wait */ - 0xf000f8dd, - 0x84b62c87, - 0x0088cf06, - 0x98001e98, - 0x1c98011d, - 0x031b9802, - 0xf41010b6, - 0x00f89c21, -/* 0x04fc: memx_func_delay */ - 0xb6001e98, - 0x21f40410, -/* 0x0507: memx_exec */ - 0xf900f87f, - 0xb9d0f9e0, - 0xb2b902c1, -/* 0x0511: memx_exec_next */ - 0x00139802, - 0x950410b6, - 0x30f01034, - 0xde35980c, - 0x12b855f9, - 0xec1ef406, - 0xe0fcd0fc, - 0x02b921f5, -/* 0x0532: memx_info */ - 0xc7f100f8, - 0xb7f103ac, - 0x21f50800, - 0x00f802b9, -/* 0x0540: memx_recv */ - 0xf401d6b0, - 0xd6b0c40b, - 0xe90bf400, -/* 0x054e: memx_init */ - 0x00f800f8, -/* 0x0550: perf_recv */ -/* 0x0552: perf_init */ + 0xfd0066cf, + 0x1bf40467, +/* 0x0625: memx_func_wait_vblank_1 */ + 0xc467f1f3, + 0x0664b607, + 0xfd0066cf, + 0x0bf40467, +/* 0x0635: memx_func_wait_vblank_fini */ + 0x0410b6f3, +/* 0x063a: memx_func_wr32 */ + 0x169800f8, + 0x01159800, + 0xf90810b6, + 0xfc50f960, + 0xf4e0fcd0, + 0x42b63f21, + 0xe91bf402, +/* 0x0656: memx_func_wait */ + 0x87f000f8, + 0x0684b62c, + 0x980088cf, + 0x1d98001e, + 0x021c9801, + 0xb6031b98, + 0x21f41010, +/* 0x0673: memx_func_delay */ + 0x9800f8a4, + 0x10b6001e, + 0x7f21f404, +/* 0x067e: memx_exec */ + 0xe0f900f8, + 0xc1b9d0f9, + 0x02b2b902, +/* 0x0688: memx_exec_next */ + 0xb6001398, + 0x34e70410, + 0x33e701f0, + 0x32b601e0, + 0x0c30f001, + 0xf9de3598, + 0x0612b855, + 0x98e41ef4, + 0x0c98ee0b, + 0x02cbbbef, + 0x07c4b7f1, + 0xcf06b4b6, + 0xd0fc00bb, + 0x21f5e0fc, + 0x00f80342, +/* 0x06c4: memx_info */ + 0x03c0c7f1, + 0x0800b7f1, + 0x034221f5, +/* 0x06d2: memx_recv */ + 0xd6b000f8, + 0xa90bf401, + 0xf400d6b0, + 0x00f8e90b, +/* 0x06e0: memx_init */ +/* 0x06e2: perf_recv */ 0x00f800f8, -/* 0x0554: i2c_drive_scl */ - 0xf40036b0, - 0x07f1110b, - 0x04b607e0, - 0x0001d006, - 0x00f804bd, -/* 0x0568: i2c_drive_scl_lo */ - 0x07e407f1, - 0xd00604b6, - 0x04bd0001, -/* 0x0576: i2c_drive_sda */ +/* 0x06e4: perf_init */ +/* 0x06e6: i2c_drive_scl */ 0x36b000f8, 0x110bf400, 0x07e007f1, 0xd00604b6, - 0x04bd0002, -/* 0x058a: i2c_drive_sda_lo */ + 0x04bd0001, +/* 0x06fa: i2c_drive_scl_lo */ 0x07f100f8, 0x04b607e4, + 0x0001d006, + 0x00f804bd, +/* 0x0708: i2c_drive_sda */ + 0xf40036b0, + 0x07f1110b, + 0x04b607e0, 0x0002d006, 0x00f804bd, -/* 0x0598: i2c_sense_scl */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0431fd00, - 0xf4060bf4, -/* 0x05ae: i2c_sense_scl_done */ - 0x00f80131, -/* 0x05b0: i2c_sense_sda */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0432fd00, - 0xf4060bf4, -/* 0x05c6: i2c_sense_sda_done */ - 0x00f80131, -/* 0x05c8: i2c_raise_scl */ - 0x47f140f9, - 0x37f00898, - 0x5421f501, -/* 0x05d5: i2c_raise_scl_wait */ - 0xe8e7f105, - 0x7f21f403, - 0x059821f5, - 0xb60901f4, - 0x1bf40142, -/* 0x05e9: i2c_raise_scl_done */ - 0xf840fcef, -/* 0x05ed: i2c_start */ - 0x9821f500, - 0x0d11f405, - 0x05b021f5, - 0xf40611f4, -/* 0x05fe: i2c_start_rep */ - 0x37f0300e, - 0x5421f500, - 0x0137f005, - 0x057621f5, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0xc821f550, - 0x0464b605, -/* 0x062b: i2c_start_send */ - 0xf01f11f4, +/* 0x071c: i2c_drive_sda_lo */ + 0x07e407f1, + 0xd00604b6, + 0x04bd0002, +/* 0x072a: i2c_sense_scl */ + 0x32f400f8, + 0xc437f101, + 0x0634b607, + 0xfd0033cf, + 0x0bf40431, + 0x0131f406, +/* 0x0740: i2c_sense_scl_done */ +/* 0x0742: i2c_sense_sda */ + 0x32f400f8, + 0xc437f101, + 0x0634b607, + 0xfd0033cf, + 0x0bf40432, + 0x0131f406, +/* 0x0758: i2c_sense_sda_done */ +/* 0x075a: i2c_raise_scl */ + 0x40f900f8, + 0x089847f1, + 0xf50137f0, +/* 0x0767: i2c_raise_scl_wait */ + 0xf106e621, + 0xf403e8e7, + 0x21f57f21, + 0x01f4072a, + 0x0142b609, +/* 0x077b: i2c_raise_scl_done */ + 0xfcef1bf4, +/* 0x077f: i2c_start */ + 0xf500f840, + 0xf4072a21, + 0x21f50d11, + 0x11f40742, + 0x300ef406, +/* 0x0790: i2c_start_rep */ + 0xf50037f0, + 0xf006e621, + 0x21f50137, + 0x76bb0708, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb6075a21, + 0x11f40464, +/* 0x07bd: i2c_start_send */ + 0x0037f01f, + 0x070821f5, + 0x1388e7f1, + 0xf07f21f4, 0x21f50037, - 0xe7f10576, + 0xe7f106e6, 0x21f41388, - 0x0037f07f, - 0x055421f5, - 0x1388e7f1, -/* 0x0647: i2c_start_out */ - 0xf87f21f4, -/* 0x0649: i2c_stop */ - 0x0037f000, - 0x055421f5, - 0xf50037f0, - 0xf1057621, - 0xf403e8e7, - 0x37f07f21, - 0x5421f501, - 0x88e7f105, - 0x7f21f413, +/* 0x07d9: i2c_start_out */ +/* 0x07db: i2c_stop */ + 0xf000f87f, + 0x21f50037, + 0x37f006e6, + 0x0821f500, + 0xe8e7f107, + 0x7f21f403, 0xf50137f0, - 0xf1057621, + 0xf106e621, 0xf41388e7, - 0x00f87f21, -/* 0x067c: i2c_bitw */ - 0x057621f5, - 0x03e8e7f1, - 0xbb7f21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x05c821f5, - 0xf40464b6, - 0xe7f11811, - 0x21f41388, - 0x0037f07f, - 0x055421f5, - 0x1388e7f1, -/* 0x06bb: i2c_bitw_out */ - 0xf87f21f4, -/* 0x06bd: i2c_bitr */ - 0x0137f000, - 0x057621f5, - 0x03e8e7f1, - 0xbb7f21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x05c821f5, - 0xf40464b6, - 0x21f51b11, - 0x37f005b0, - 0x5421f500, - 0x88e7f105, + 0x37f07f21, + 0x0821f501, + 0x88e7f107, 0x7f21f413, - 0xf4013cf0, -/* 0x0702: i2c_bitr_done */ - 0x00f80131, -/* 0x0704: i2c_get_byte */ - 0xf00057f0, -/* 0x070a: i2c_get_byte_next */ - 0x54b60847, - 0x0076bb01, +/* 0x080e: i2c_bitw */ + 0x21f500f8, + 0xe7f10708, + 0x21f403e8, + 0x0076bb7f, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b606bd, - 0x2b11f404, - 0xb60553fd, - 0x1bf40142, - 0x0137f0d8, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0x7c21f550, - 0x0464b606, -/* 0x0754: i2c_get_byte_done */ -/* 0x0756: i2c_put_byte */ - 0x47f000f8, -/* 0x0759: i2c_put_byte_next */ - 0x0142b608, - 0xbb3854ff, + 0x64b6075a, + 0x1811f404, + 0x1388e7f1, + 0xf07f21f4, + 0x21f50037, + 0xe7f106e6, + 0x21f41388, +/* 0x084d: i2c_bitw_out */ +/* 0x084f: i2c_bitr */ + 0xf000f87f, + 0x21f50137, + 0xe7f10708, + 0x21f403e8, + 0x0076bb7f, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b6075a, + 0x1b11f404, + 0x074221f5, + 0xf50037f0, + 0xf106e621, + 0xf41388e7, + 0x3cf07f21, + 0x0131f401, +/* 0x0894: i2c_bitr_done */ +/* 0x0896: i2c_get_byte */ + 0x57f000f8, + 0x0847f000, +/* 0x089c: i2c_get_byte_next */ + 0xbb0154b6, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x067c21f5, + 0x084f21f5, 0xf40464b6, - 0x46b03411, - 0xd81bf400, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0xbd21f550, - 0x0464b606, - 0xbb0f11f4, - 0x36b00076, - 0x061bf401, -/* 0x07af: i2c_put_byte_done */ - 0xf80132f4, -/* 0x07b1: i2c_addr */ - 0x0076bb00, + 0x53fd2b11, + 0x0142b605, + 0xf0d81bf4, + 0x76bb0137, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb6080e21, +/* 0x08e6: i2c_get_byte_done */ + 0x00f80464, +/* 0x08e8: i2c_put_byte */ +/* 0x08eb: i2c_put_byte_next */ + 0xb60847f0, + 0x54ff0142, + 0x0076bb38, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b605ed, - 0x2911f404, - 0x012ec3e7, - 0xfd0134b6, - 0x76bb0553, + 0x64b6080e, + 0x3411f404, + 0xf40046b0, + 0x76bbd81b, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb6075621, -/* 0x07f6: i2c_addr_done */ - 0x00f80464, -/* 0x07f8: i2c_acquire_addr */ - 0xb6f8cec7, - 0xe0b702e4, - 0xee980bfc, -/* 0x0807: i2c_acquire */ - 0xf500f800, - 0xf407f821, - 0xd9f00421, - 0x3f21f403, -/* 0x0816: i2c_release */ - 0x21f500f8, - 0x21f407f8, - 0x03daf004, - 0xf83f21f4, -/* 0x0825: i2c_recv */ - 0x0132f400, - 0xb6f8c1c7, - 0x16b00214, - 0x3a1ff528, - 0xd413a001, - 0x0032980b, - 0x0bac13a0, - 0xf4003198, - 0xd0f90231, - 0xd0f9e0f9, - 0x000067f1, - 0x100063f1, - 0xbb016792, + 0xb6084f21, + 0x11f40464, + 0x0076bb0f, + 0xf40136b0, + 0x32f4061b, +/* 0x0941: i2c_put_byte_done */ +/* 0x0943: i2c_addr */ + 0xbb00f801, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x080721f5, - 0xfc0464b6, - 0x00d6b0d0, - 0x00b31bf5, - 0xbb0057f0, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x07b121f5, - 0xf50464b6, - 0xc700d011, - 0x76bbe0c5, - 0x0465b600, - 0x659450f9, - 0x0256bb04, - 0x75fd50bd, - 0xf550fc04, - 0xb6075621, - 0x11f50464, - 0x57f000ad, + 0x077f21f5, + 0xf40464b6, + 0xc3e72911, + 0x34b6012e, + 0x0553fd01, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xe821f550, + 0x0464b608, +/* 0x0988: i2c_addr_done */ +/* 0x098a: i2c_acquire_addr */ + 0xcec700f8, + 0x02e4b6f8, + 0x0c10e0b7, + 0xf800ee98, +/* 0x0999: i2c_acquire */ + 0x8a21f500, + 0x0421f409, + 0xf403d9f0, + 0x00f83f21, +/* 0x09a8: i2c_release */ + 0x098a21f5, + 0xf00421f4, + 0x21f403da, +/* 0x09b7: i2c_recv */ + 0xf400f83f, + 0xc1c70132, + 0x0214b6f8, + 0xf52816b0, + 0xa0013a1f, + 0x980be813, + 0x13a00032, + 0x31980bc0, + 0x0231f400, + 0xe0f9d0f9, + 0x67f1d0f9, + 0x63f10000, + 0x67921000, 0x0076bb01, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b607b1, - 0x8a11f504, + 0x64b60999, + 0xb0d0fc04, + 0x1bf500d6, + 0x57f000b3, 0x0076bb00, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b60704, - 0x6a11f404, - 0xbbe05bcb, + 0x64b60943, + 0xd011f504, + 0xe0c5c700, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xe821f550, + 0x0464b608, + 0x00ad11f5, + 0xbb0157f0, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x064921f5, - 0xb90464b6, - 0x74bd025b, -/* 0x092b: i2c_recv_not_rd08 */ - 0xb0430ef4, - 0x1bf401d6, - 0x0057f03d, - 0x07b121f5, - 0xc73311f4, - 0x21f5e0c5, - 0x11f40756, - 0x0057f029, - 0x07b121f5, - 0xc71f11f4, - 0x21f5e0b5, - 0x11f40756, - 0x4921f515, - 0xc774bd06, - 0x1bf408c5, - 0x0232f409, -/* 0x096b: i2c_recv_not_wr08 */ -/* 0x096b: i2c_recv_done */ - 0xc7030ef4, - 0x21f5f8ce, - 0xe0fc0816, - 0x12f4d0fc, - 0x027cb90a, - 0x02b921f5, -/* 0x0980: i2c_recv_exit */ -/* 0x0982: i2c_init */ - 0x00f800f8, -/* 0x0984: test_recv */ - 0x05d817f1, + 0x094321f5, + 0xf50464b6, + 0xbb008a11, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x089621f5, + 0xf40464b6, + 0x5bcb6a11, + 0x0076bbe0, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b607db, + 0x025bb904, + 0x0ef474bd, +/* 0x0abd: i2c_recv_not_rd08 */ + 0x01d6b043, + 0xf03d1bf4, + 0x21f50057, + 0x11f40943, + 0xe0c5c733, + 0x08e821f5, + 0xf02911f4, + 0x21f50057, + 0x11f40943, + 0xe0b5c71f, + 0x08e821f5, + 0xf51511f4, + 0xbd07db21, + 0x08c5c774, + 0xf4091bf4, + 0x0ef40232, +/* 0x0afd: i2c_recv_not_wr08 */ +/* 0x0afd: i2c_recv_done */ + 0xf8cec703, + 0x09a821f5, + 0xd0fce0fc, + 0xb90a12f4, + 0x21f5027c, +/* 0x0b12: i2c_recv_exit */ + 0x00f80342, +/* 0x0b14: i2c_init */ +/* 0x0b16: test_recv */ + 0x17f100f8, + 0x14b605d8, + 0x0011cf06, + 0xf10110b6, + 0xb605d807, + 0x01d00604, + 0xf104bd00, + 0xf1d900e7, + 0xf5134fe3, + 0xf8026221, +/* 0x0b3d: test_init */ + 0x00e7f100, + 0x6221f508, +/* 0x0b47: idle_recv */ + 0xf800f802, +/* 0x0b49: idle */ + 0x0031f400, + 0x05d417f1, 0xcf0614b6, 0x10b60011, - 0xd807f101, + 0xd407f101, 0x0604b605, 0xbd0001d0, - 0x00e7f104, - 0x4fe3f1d9, - 0xf521f513, -/* 0x09ab: test_init */ - 0xf100f801, - 0xf50800e7, - 0xf801f521, -/* 0x09b5: idle_recv */ -/* 0x09b7: idle */ - 0xf400f800, - 0x17f10031, - 0x14b605d4, - 0x0011cf06, - 0xf10110b6, - 0xb605d407, - 0x01d00604, -/* 0x09d3: idle_loop */ - 0xf004bd00, - 0x32f45817, -/* 0x09d9: idle_proc */ -/* 0x09d9: idle_proc_exec */ - 0xb910f902, - 0x21f5021e, - 0x10fc02c2, - 0xf40911f4, - 0x0ef40231, -/* 0x09ed: idle_proc_next */ - 0x5810b6ef, - 0xf4061fb8, - 0x02f4e61b, - 0x0028f4dd, - 0x00bb0ef4, +/* 0x0b65: idle_loop */ + 0x5817f004, +/* 0x0b6b: idle_proc */ +/* 0x0b6b: idle_proc_exec */ + 0xf90232f4, + 0x021eb910, + 0x034b21f5, + 0x11f410fc, + 0x0231f409, +/* 0x0b7f: idle_proc_next */ + 0xb6ef0ef4, + 0x1fb85810, + 0xe61bf406, + 0xf4dd02f4, + 0x0ef40028, + 0x000000bb, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc index 48f79434a449..21bf8cc7618f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc @@ -23,6 +23,7 @@ */ #define NVKM_PPWR_CHIPSET GF100 +#define HW_TICKS_PER_US 203 // should be 202.5 //#define NVKM_FALCON_PC24 //#define NVKM_FALCON_UNSHIFTED_IO @@ -34,6 +35,7 @@ .section #nvc0_pwr_data #define INCLUDE_PROC #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -44,6 +46,7 @@ #define INCLUDE_DATA #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -56,6 +59,7 @@ .section #nvc0_pwr_code #define INCLUDE_CODE #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h index 7ac87405d01b..ca30fa4011b5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h @@ -24,8 +24,8 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, /* 0x0058: proc_list_head */ 0x54534f48, - 0x00000430, - 0x000003cd, + 0x00000512, + 0x000004af, 0x00000000, 0x00000000, 0x00000000, @@ -46,8 +46,8 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, 0x584d454d, - 0x0000054e, - 0x00000540, + 0x0000074b, + 0x0000073d, 0x00000000, 0x00000000, 0x00000000, @@ -68,8 +68,8 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, 0x46524550, - 0x00000552, - 0x00000550, + 0x0000074f, + 0x0000074d, 0x00000000, 0x00000000, 0x00000000, @@ -90,8 +90,8 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, 0x5f433249, - 0x00000982, - 0x00000825, + 0x00000b7f, + 0x00000a22, 0x00000000, 0x00000000, 0x00000000, @@ -112,8 +112,8 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, 0x54534554, - 0x000009ab, - 0x00000984, + 0x00000ba8, + 0x00000b81, 0x00000000, 0x00000000, 0x00000000, @@ -134,8 +134,8 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, 0x454c4449, - 0x000009b7, - 0x000009b5, + 0x00000bb4, + 0x00000bb2, 0x00000000, 0x00000000, 0x00000000, @@ -227,25 +227,31 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, /* 0x0370: memx_func_head */ - 0x00010000, - 0x00000000, - 0x0000046f, -/* 0x037c: memx_func_next */ 0x00000001, 0x00000000, - 0x00000496, + 0x00000551, +/* 0x037c: memx_func_next */ 0x00000002, + 0x00000000, + 0x000005db, + 0x00000003, 0x00000002, - 0x000004b7, - 0x00040003, + 0x000006a5, + 0x00040004, + 0x00000000, + 0x000006c1, + 0x00010005, + 0x00000000, + 0x000006de, + 0x00010006, 0x00000000, - 0x000004df, - 0x00010004, + 0x00000663, +/* 0x03b8: memx_func_tail */ +/* 0x03b8: memx_ts_start */ 0x00000000, - 0x000004fc, -/* 0x03ac: memx_func_tail */ -/* 0x03ac: memx_data_head */ +/* 0x03bc: memx_ts_end */ 0x00000000, +/* 0x03c0: memx_data_head */ 0x00000000, 0x00000000, 0x00000000, @@ -757,8 +763,9 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, 0x00000000, -/* 0x0bac: memx_data_tail */ -/* 0x0bac: i2c_scl_map */ + 0x00000000, +/* 0x0bc0: memx_data_tail */ +/* 0x0bc0: i2c_scl_map */ 0x00001000, 0x00004000, 0x00010000, @@ -769,7 +776,7 @@ uint32_t nvc0_pwr_data[] = { 0x01000000, 0x04000000, 0x10000000, -/* 0x0bd4: i2c_sda_map */ +/* 0x0be8: i2c_sda_map */ 0x00002000, 0x00008000, 0x00020000, @@ -780,7 +787,7 @@ uint32_t nvc0_pwr_data[] = { 0x02000000, 0x08000000, 0x20000000, -/* 0x0bfc: i2c_ctrl */ +/* 0x0c10: i2c_ctrl */ 0x0000e138, 0x0000e150, 0x0000e168, @@ -841,15 +848,10 @@ uint32_t nvc0_pwr_data[] = { 0x00000000, 0x00000000, 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, }; uint32_t nvc0_pwr_code[] = { - 0x030d0ef5, + 0x039e0ef5, /* 0x0004: rd32 */ 0x07a007f1, 0xd00604b6, @@ -885,19 +887,22 @@ uint32_t nvc0_pwr_code[] = { 0xd4f100dd, 0x1bf47000, /* 0x007f: nsec */ - 0xf000f8f2, + 0xf900f8f2, + 0xf080f990, 0x84b62c87, 0x0088cf06, -/* 0x0088: nsec_loop */ +/* 0x008c: nsec_loop */ 0xb62c97f0, 0x99cf0694, 0x0298bb00, 0xf4069eb8, - 0x00f8f11e, -/* 0x009c: wait */ + 0x80fcf11e, + 0x00f890fc, +/* 0x00a4: wait */ + 0x80f990f9, 0xb62c87f0, 0x88cf0684, -/* 0x00a5: wait_loop */ +/* 0x00b1: wait_loop */ 0x02eeb900, 0xb90421f4, 0xadfd02da, @@ -907,28 +912,29 @@ uint32_t nvc0_pwr_code[] = { 0x0099cf06, 0xb80298bb, 0x1ef4069b, -/* 0x00c9: wait_done */ -/* 0x00cb: intr_watchdog */ - 0x9800f8df, +/* 0x00d5: wait_done */ + 0xfc80fcdf, +/* 0x00db: intr_watchdog */ + 0x9800f890, 0x96b003e9, 0x2a0bf400, 0xbb9a0a98, 0x1cf4029a, 0x01d7f00f, - 0x025421f5, + 0x02dd21f5, 0x0ef494bd, -/* 0x00e9: intr_watchdog_next_time */ +/* 0x00f9: intr_watchdog_next_time */ 0x9b0a9815, 0xf400a6b0, 0x9ab8090b, 0x061cf406, -/* 0x00f8: intr_watchdog_next_time_set */ -/* 0x00fb: intr_watchdog_next_proc */ +/* 0x0108: intr_watchdog_next_time_set */ +/* 0x010b: intr_watchdog_next_proc */ 0x809b0980, 0xe0b603e9, 0x68e6b158, 0xc61bf402, -/* 0x010a: intr */ +/* 0x011a: intr */ 0x00f900f8, 0x80f904bd, 0xa0f990f9, @@ -948,13 +954,13 @@ uint32_t nvc0_pwr_code[] = { 0xf40289c4, 0x0080230b, 0x58e7f09b, - 0x98cb21f4, + 0x98db21f4, 0x96b09b09, 0x110bf400, 0xb63407f0, 0x09d00604, 0x8004bd00, -/* 0x016e: intr_skip_watchdog */ +/* 0x017e: intr_skip_watchdog */ 0x89e49a09, 0x0bf40800, 0x8897f148, @@ -967,22 +973,22 @@ uint32_t nvc0_pwr_code[] = { 0x48e7f1c0, 0x53e3f14f, 0x00d7f054, - 0x02b921f5, + 0x034221f5, 0x07f1c0fc, 0x04b604c0, 0x000cd006, -/* 0x01ae: intr_subintr_skip_fifo */ +/* 0x01be: intr_subintr_skip_fifo */ 0x07f104bd, 0x04b60688, 0x0009d006, -/* 0x01ba: intr_skip_subintr */ +/* 0x01ca: intr_skip_subintr */ 0x89c404bd, 0x070bf420, 0xffbfa4f1, -/* 0x01c4: intr_skip_pause */ +/* 0x01d4: intr_skip_pause */ 0xf44089c4, 0xa4f1070b, -/* 0x01ce: intr_skip_user0 */ +/* 0x01de: intr_skip_user0 */ 0x07f0ffbf, 0x0604b604, 0xbd0008d0, @@ -993,597 +999,733 @@ uint32_t nvc0_pwr_code[] = { 0x90fca0fc, 0x00fc80fc, 0xf80032f4, -/* 0x01f5: timer */ - 0x1032f401, - 0xb003f898, - 0x1cf40086, - 0x03fe8051, +/* 0x0205: ticks_from_ns */ + 0xf9c0f901, + 0xcbd7f1b0, + 0x00d3f000, + 0x041321f5, + 0x03e8ccec, + 0xf400b4b0, + 0xeeec120b, + 0xd7f103e8, + 0xd3f000cb, + 0x1321f500, +/* 0x022d: ticks_from_ns_quit */ + 0x02ceb904, + 0xc0fcb0fc, +/* 0x0236: ticks_from_us */ + 0xc0f900f8, + 0xd7f1b0f9, + 0xd3f000cb, + 0x1321f500, + 0x02ceb904, + 0xf400b4b0, + 0xe4bd050b, +/* 0x0250: ticks_from_us_quit */ + 0xc0fcb0fc, +/* 0x0256: ticks_to_us */ + 0xd7f100f8, + 0xd3f000cb, + 0xecedff00, +/* 0x0262: timer */ + 0x90f900f8, + 0x32f480f9, + 0x03f89810, + 0xf40086b0, + 0x84bd651c, 0xb63807f0, 0x08d00604, 0xf004bd00, - 0x84b60887, + 0x84b63487, 0x0088cf06, - 0xf40284f0, - 0x87f0261b, - 0x0684b634, - 0xb80088cf, - 0x0bf406e0, - 0x06e8b809, -/* 0x0233: timer_reset */ - 0xf01f1ef4, - 0x04b63407, - 0x000ed006, - 0x0e8004bd, -/* 0x0241: timer_enable */ - 0x0187f09a, + 0xbb9a0998, + 0xe9bb0298, + 0x03fe8000, + 0xb60887f0, + 0x88cf0684, + 0x0284f000, + 0xf0261bf4, + 0x84b63487, + 0x0088cf06, + 0xf406e0b8, + 0xe8b8090b, + 0x111cf406, +/* 0x02b8: timer_reset */ + 0xb63407f0, + 0x0ed00604, + 0x8004bd00, +/* 0x02c6: timer_enable */ + 0x87f09a0e, + 0x3807f001, + 0xd00604b6, + 0x04bd0008, +/* 0x02d4: timer_done */ + 0xfc1031f4, + 0xf890fc80, +/* 0x02dd: send_proc */ + 0xf980f900, + 0x05e89890, + 0xf004e998, + 0x89b80486, + 0x2a0bf406, + 0x940398c4, + 0x80b60488, + 0x008ebb18, + 0x8000fa98, + 0x8d80008a, + 0x028c8001, + 0xb6038b80, + 0x94f00190, + 0x04e98007, +/* 0x0317: send_done */ + 0xfc0231f4, + 0xf880fc90, +/* 0x031d: find */ + 0xf080f900, + 0x31f45887, +/* 0x0325: find_loop */ + 0x008a9801, + 0xf406aeb8, + 0x80b6100b, + 0x6886b158, + 0xf01bf402, +/* 0x033b: find_done */ + 0xb90132f4, + 0x80fc028e, +/* 0x0342: send */ + 0x21f500f8, + 0x01f4031d, +/* 0x034b: recv */ + 0xf900f897, + 0x9880f990, + 0xe99805e8, + 0x0132f404, + 0xf40689b8, + 0x89c43d0b, + 0x0180b603, + 0x800784f0, + 0xea9805e8, + 0xfef0f902, + 0xf0f9018f, + 0x9402efb9, + 0xe9bb0499, + 0x18e0b600, + 0x9803eb98, + 0xed9802ec, + 0x00ee9801, + 0xf0fca5f9, + 0xf400f8fe, + 0xf0fc0131, +/* 0x0398: recv_done */ + 0x90fc80fc, +/* 0x039e: init */ + 0x17f100f8, + 0x14b60108, + 0x0011cf06, + 0x010911e7, + 0xfe0814b6, + 0x17f10014, + 0x13f000e0, + 0x1c07f000, + 0xd00604b6, + 0x04bd0001, + 0xf0ff17f0, + 0x04b61407, + 0x0001d006, + 0x17f004bd, + 0x0015f102, + 0x1007f008, + 0xd00604b6, + 0x04bd0001, + 0x011a17f1, + 0xfe0013f0, + 0x31f40010, + 0x0117f010, 0xb63807f0, - 0x08d00604, -/* 0x024f: timer_done */ - 0xf404bd00, - 0x00f81031, -/* 0x0254: send_proc */ - 0x90f980f9, - 0x9805e898, - 0x86f004e9, - 0x0689b804, - 0xc42a0bf4, - 0x88940398, - 0x1880b604, - 0x98008ebb, - 0x8a8000fa, - 0x018d8000, - 0x80028c80, - 0x90b6038b, - 0x0794f001, - 0xf404e980, -/* 0x028e: send_done */ - 0x90fc0231, - 0x00f880fc, -/* 0x0294: find */ - 0x87f080f9, - 0x0131f458, -/* 0x029c: find_loop */ - 0xb8008a98, - 0x0bf406ae, - 0x5880b610, - 0x026886b1, - 0xf4f01bf4, -/* 0x02b2: find_done */ - 0x8eb90132, - 0xf880fc02, -/* 0x02b9: send */ - 0x9421f500, - 0x9701f402, -/* 0x02c2: recv */ - 0xe89800f8, - 0x04e99805, - 0xb80132f4, - 0x0bf40689, - 0x0389c43d, - 0xf00180b6, - 0xe8800784, - 0x02ea9805, - 0x8ffef0f9, - 0xb9f0f901, - 0x999402ef, - 0x00e9bb04, - 0x9818e0b6, - 0xec9803eb, - 0x01ed9802, - 0xf900ee98, - 0xfef0fca5, - 0x31f400f8, -/* 0x030b: recv_done */ - 0xf8f0fc01, -/* 0x030d: init */ - 0x0817f100, - 0x0614b601, - 0xe70011cf, - 0xb6010911, - 0x14fe0814, - 0xe017f100, - 0x0013f000, - 0xb61c07f0, 0x01d00604, 0xf004bd00, - 0x07f0ff17, - 0x0604b614, - 0xbd0001d0, - 0x0217f004, - 0x080015f1, - 0xb61007f0, - 0x01d00604, - 0xf104bd00, - 0xf0010a17, - 0x10fe0013, - 0x1031f400, - 0xf00117f0, - 0x04b63807, - 0x0001d006, - 0xf7f004bd, -/* 0x0371: init_proc */ - 0x01f19858, - 0xf40016b0, - 0x15f9fa0b, - 0xf458f0b6, -/* 0x0382: host_send */ - 0x17f1f20e, - 0x14b604b0, - 0x0011cf06, - 0x04a027f1, - 0xcf0624b6, - 0x12b80022, - 0x320bf406, - 0x94071ec4, - 0xe0b704ee, - 0xeb980270, - 0x02ec9803, - 0x9801ed98, - 0x21f500ee, - 0x10b602b9, - 0x0f1ec401, - 0x04b007f1, - 0xd00604b6, - 0x04bd000e, -/* 0x03cb: host_send_done */ - 0xf8ba0ef4, -/* 0x03cd: host_recv */ - 0x4917f100, - 0x5413f14e, - 0x06e1b852, -/* 0x03db: host_recv_wait */ - 0xf1aa0bf4, - 0xb604cc17, - 0x11cf0614, - 0xc827f100, - 0x0624b604, - 0xf00022cf, - 0x12b80816, - 0xe60bf406, - 0xb60723c4, - 0x30b70434, - 0x3b8002f0, - 0x023c8003, - 0x80013d80, - 0x20b6003e, - 0x0f24f001, - 0x04c807f1, +/* 0x0402: init_proc */ + 0xf19858f7, + 0x0016b001, + 0xf9fa0bf4, + 0x58f0b615, +/* 0x0413: mulu32_32_64 */ + 0xf9f20ef4, + 0xf920f910, + 0x9540f930, + 0xd29510e1, + 0xbdc4bd10, + 0xc0edffb4, + 0xb9301dff, + 0x34f10234, + 0x34b6ffff, + 0x1045b610, + 0xbb00c3bb, + 0xe2ff01b4, + 0x0234b930, + 0xffff34f1, + 0xb61034b6, + 0xc3bb1045, + 0x01b4bb00, + 0xbb3012ff, + 0x40fc00b3, + 0x20fc30fc, + 0x00f810fc, +/* 0x0464: host_send */ + 0x04b017f1, + 0xcf0614b6, + 0x27f10011, + 0x24b604a0, + 0x0022cf06, + 0xf40612b8, + 0x1ec4320b, + 0x04ee9407, + 0x0270e0b7, + 0x9803eb98, + 0xed9802ec, + 0x00ee9801, + 0x034221f5, + 0xc40110b6, + 0x07f10f1e, + 0x04b604b0, + 0x000ed006, + 0x0ef404bd, +/* 0x04ad: host_send_done */ +/* 0x04af: host_recv */ + 0xf100f8ba, + 0xf14e4917, + 0xb8525413, + 0x0bf406e1, +/* 0x04bd: host_recv_wait */ + 0xcc17f1aa, + 0x0614b604, + 0xf10011cf, + 0xb604c827, + 0x22cf0624, + 0x0816f000, + 0xf40612b8, + 0x23c4e60b, + 0x0434b607, + 0x02f030b7, + 0x80033b80, + 0x3d80023c, + 0x003e8001, + 0xf00120b6, + 0x07f10f24, + 0x04b604c8, + 0x0002d006, + 0x27f004bd, + 0x0007f040, 0xd00604b6, 0x04bd0002, - 0xf04027f0, - 0x04b60007, - 0x0002d006, - 0x00f804bd, -/* 0x0430: host_init */ - 0x008017f1, - 0xf11014b6, - 0xf1027015, - 0xb604d007, - 0x01d00604, - 0xf104bd00, - 0xb6008017, - 0x15f11014, - 0x07f102f0, - 0x04b604dc, - 0x0001d006, - 0x17f004bd, - 0xc407f101, +/* 0x0512: host_init */ + 0x17f100f8, + 0x14b60080, + 0x7015f110, + 0xd007f102, 0x0604b604, 0xbd0001d0, -/* 0x046f: memx_func_enter */ - 0xf000f804, + 0x8017f104, + 0x1014b600, + 0x02f015f1, + 0x04dc07f1, + 0xd00604b6, + 0x04bd0001, + 0xf10117f0, + 0xb604c407, + 0x01d00604, + 0xf804bd00, +/* 0x0551: memx_func_enter */ + 0x2067f100, + 0x5d77f116, + 0xff73f1f5, + 0x026eb9ff, + 0xb90421f4, + 0x87fd02d8, + 0xf960f904, + 0xfcd0fc80, + 0x3f21f4e0, + 0xfffe77f1, + 0xffff73f1, + 0xf4026eb9, + 0xd8b90421, + 0x0487fd02, + 0x80f960f9, + 0xe0fcd0fc, + 0xf13f21f4, + 0xb926f067, + 0x21f4026e, + 0x02d8b904, + 0xf90487fd, + 0xfc80f960, + 0xf4e0fcd0, + 0x67f03f21, + 0xe007f104, + 0x0604b607, + 0xbd0006d0, +/* 0x05bd: memx_func_enter_wait */ + 0xc067f104, + 0x0664b607, + 0xf00066cf, + 0x0bf40464, + 0x2c67f0f3, + 0xcf0664b6, + 0x06800066, +/* 0x05db: memx_func_leave */ + 0xf000f8ee, + 0x64b62c67, + 0x0066cf06, + 0xf0ef0680, 0x07f10467, - 0x04b607e0, + 0x04b607e4, 0x0006d006, -/* 0x047e: memx_func_enter_wait */ +/* 0x05f6: memx_func_leave_wait */ 0x67f104bd, 0x64b607c0, 0x0066cf06, 0xf40464f0, - 0x1698f30b, - 0x0410b600, -/* 0x0496: memx_func_leave */ - 0x67f000f8, - 0xe407f104, - 0x0604b607, - 0xbd0006d0, -/* 0x04a5: memx_func_leave_wait */ - 0xc067f104, - 0x0664b607, - 0xf00066cf, - 0x1bf40464, -/* 0x04b7: memx_func_wr32 */ - 0x9800f8f3, - 0x15980016, - 0x0810b601, - 0x50f960f9, + 0x67f1f31b, + 0x77f126f0, + 0x73f00001, + 0x026eb900, + 0xb90421f4, + 0x87fd02d8, + 0xf960f905, + 0xfcd0fc80, + 0x3f21f4e0, + 0x162067f1, + 0xf4026eb9, + 0xd8b90421, + 0x0587fd02, + 0x80f960f9, 0xe0fcd0fc, 0xf13f21f4, - 0xfd140003, - 0x05800506, - 0xb604bd00, - 0x1bf40242, -/* 0x04df: memx_func_wait */ - 0xf000f8dd, - 0x84b62c87, - 0x0088cf06, - 0x98001e98, - 0x1c98011d, - 0x031b9802, - 0xf41010b6, - 0x00f89c21, -/* 0x04fc: memx_func_delay */ - 0xb6001e98, - 0x21f40410, -/* 0x0507: memx_exec */ - 0xf900f87f, - 0xb9d0f9e0, - 0xb2b902c1, -/* 0x0511: memx_exec_next */ - 0x00139802, - 0x950410b6, - 0x30f01034, - 0xde35980c, - 0x12b855f9, - 0xec1ef406, - 0xe0fcd0fc, - 0x02b921f5, -/* 0x0532: memx_info */ - 0xc7f100f8, - 0xb7f103ac, - 0x21f50800, - 0x00f802b9, -/* 0x0540: memx_recv */ - 0xf401d6b0, - 0xd6b0c40b, - 0xe90bf400, -/* 0x054e: memx_init */ - 0x00f800f8, -/* 0x0550: perf_recv */ -/* 0x0552: perf_init */ - 0x00f800f8, -/* 0x0554: i2c_drive_scl */ - 0xf40036b0, - 0x07f1110b, - 0x04b607e0, - 0x0001d006, - 0x00f804bd, -/* 0x0568: i2c_drive_scl_lo */ - 0x07e407f1, - 0xd00604b6, - 0x04bd0001, -/* 0x0576: i2c_drive_sda */ - 0x36b000f8, - 0x110bf400, - 0x07e007f1, - 0xd00604b6, - 0x04bd0002, -/* 0x058a: i2c_drive_sda_lo */ - 0x07f100f8, - 0x04b607e4, - 0x0002d006, - 0x00f804bd, -/* 0x0598: i2c_sense_scl */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0431fd00, - 0xf4060bf4, -/* 0x05ae: i2c_sense_scl_done */ - 0x00f80131, -/* 0x05b0: i2c_sense_sda */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0432fd00, - 0xf4060bf4, -/* 0x05c6: i2c_sense_sda_done */ - 0x00f80131, -/* 0x05c8: i2c_raise_scl */ - 0x47f140f9, - 0x37f00898, - 0x5421f501, -/* 0x05d5: i2c_raise_scl_wait */ - 0xe8e7f105, - 0x7f21f403, - 0x059821f5, - 0xb60901f4, - 0x1bf40142, -/* 0x05e9: i2c_raise_scl_done */ - 0xf840fcef, -/* 0x05ed: i2c_start */ - 0x9821f500, - 0x0d11f405, - 0x05b021f5, - 0xf40611f4, -/* 0x05fe: i2c_start_rep */ - 0x37f0300e, - 0x5421f500, - 0x0137f005, - 0x057621f5, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0xc821f550, - 0x0464b605, -/* 0x062b: i2c_start_send */ - 0xf01f11f4, - 0x21f50037, - 0xe7f10576, - 0x21f41388, - 0x0037f07f, - 0x055421f5, - 0x1388e7f1, -/* 0x0647: i2c_start_out */ + 0xf00aa277, + 0x6eb90073, + 0x0421f402, + 0xfd02d8b9, + 0x60f90587, + 0xd0fc80f9, + 0x21f4e0fc, +/* 0x0663: memx_func_wait_vblank */ + 0x9800f83f, + 0x66b00016, + 0x130bf400, + 0xf40166b0, + 0x0ef4060b, +/* 0x0675: memx_func_wait_vblank_head1 */ + 0x2077f12e, + 0x070ef400, +/* 0x067c: memx_func_wait_vblank_head0 */ + 0x000877f1, +/* 0x0680: memx_func_wait_vblank_0 */ + 0x07c467f1, + 0xcf0664b6, + 0x67fd0066, + 0xf31bf404, +/* 0x0690: memx_func_wait_vblank_1 */ + 0x07c467f1, + 0xcf0664b6, + 0x67fd0066, + 0xf30bf404, +/* 0x06a0: memx_func_wait_vblank_fini */ + 0xf80410b6, +/* 0x06a5: memx_func_wr32 */ + 0x00169800, + 0xb6011598, + 0x60f90810, + 0xd0fc50f9, + 0x21f4e0fc, + 0x0242b63f, + 0xf8e91bf4, +/* 0x06c1: memx_func_wait */ + 0x2c87f000, + 0xcf0684b6, + 0x1e980088, + 0x011d9800, + 0x98021c98, + 0x10b6031b, + 0xa421f410, +/* 0x06de: memx_func_delay */ + 0x1e9800f8, + 0x0410b600, 0xf87f21f4, -/* 0x0649: i2c_stop */ - 0x0037f000, - 0x055421f5, +/* 0x06e9: memx_exec */ + 0xf9e0f900, + 0x02c1b9d0, +/* 0x06f3: memx_exec_next */ + 0x9802b2b9, + 0x10b60013, + 0xf034e704, + 0xe033e701, + 0x0132b601, + 0x980c30f0, + 0x55f9de35, + 0xf40612b8, + 0x0b98e41e, + 0xef0c98ee, + 0xf102cbbb, + 0xb607c4b7, + 0xbbcf06b4, + 0xfcd0fc00, + 0x4221f5e0, +/* 0x072f: memx_info */ + 0xf100f803, + 0xf103c0c7, + 0xf50800b7, + 0xf8034221, +/* 0x073d: memx_recv */ + 0x01d6b000, + 0xb0a90bf4, + 0x0bf400d6, +/* 0x074b: memx_init */ + 0xf800f8e9, +/* 0x074d: perf_recv */ +/* 0x074f: perf_init */ + 0xf800f800, +/* 0x0751: i2c_drive_scl */ + 0x0036b000, + 0xf1110bf4, + 0xb607e007, + 0x01d00604, + 0xf804bd00, +/* 0x0765: i2c_drive_scl_lo */ + 0xe407f100, + 0x0604b607, + 0xbd0001d0, +/* 0x0773: i2c_drive_sda */ + 0xb000f804, + 0x0bf40036, + 0xe007f111, + 0x0604b607, + 0xbd0002d0, +/* 0x0787: i2c_drive_sda_lo */ + 0xf100f804, + 0xb607e407, + 0x02d00604, + 0xf804bd00, +/* 0x0795: i2c_sense_scl */ + 0x0132f400, + 0x07c437f1, + 0xcf0634b6, + 0x31fd0033, + 0x060bf404, +/* 0x07ab: i2c_sense_scl_done */ + 0xf80131f4, +/* 0x07ad: i2c_sense_sda */ + 0x0132f400, + 0x07c437f1, + 0xcf0634b6, + 0x32fd0033, + 0x060bf404, +/* 0x07c3: i2c_sense_sda_done */ + 0xf80131f4, +/* 0x07c5: i2c_raise_scl */ + 0xf140f900, + 0xf0089847, + 0x21f50137, +/* 0x07d2: i2c_raise_scl_wait */ + 0xe7f10751, + 0x21f403e8, + 0x9521f57f, + 0x0901f407, + 0xf40142b6, +/* 0x07e6: i2c_raise_scl_done */ + 0x40fcef1b, +/* 0x07ea: i2c_start */ + 0x21f500f8, + 0x11f40795, + 0xad21f50d, + 0x0611f407, +/* 0x07fb: i2c_start_rep */ + 0xf0300ef4, + 0x21f50037, + 0x37f00751, + 0x7321f501, + 0x0076bb07, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b607c5, + 0x1f11f404, +/* 0x0828: i2c_start_send */ 0xf50037f0, - 0xf1057621, - 0xf403e8e7, + 0xf1077321, + 0xf41388e7, 0x37f07f21, - 0x5421f501, - 0x88e7f105, + 0x5121f500, + 0x88e7f107, 0x7f21f413, - 0xf50137f0, - 0xf1057621, - 0xf41388e7, - 0x00f87f21, -/* 0x067c: i2c_bitw */ - 0x057621f5, +/* 0x0844: i2c_start_out */ +/* 0x0846: i2c_stop */ + 0x37f000f8, + 0x5121f500, + 0x0037f007, + 0x077321f5, 0x03e8e7f1, - 0xbb7f21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x05c821f5, - 0xf40464b6, - 0xe7f11811, + 0xf07f21f4, + 0x21f50137, + 0xe7f10751, 0x21f41388, - 0x0037f07f, - 0x055421f5, + 0x0137f07f, + 0x077321f5, 0x1388e7f1, -/* 0x06bb: i2c_bitw_out */ 0xf87f21f4, -/* 0x06bd: i2c_bitr */ - 0x0137f000, - 0x057621f5, - 0x03e8e7f1, - 0xbb7f21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x05c821f5, - 0xf40464b6, - 0x21f51b11, - 0x37f005b0, - 0x5421f500, - 0x88e7f105, +/* 0x0879: i2c_bitw */ + 0x7321f500, + 0xe8e7f107, + 0x7f21f403, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xc521f550, + 0x0464b607, + 0xf11811f4, + 0xf41388e7, + 0x37f07f21, + 0x5121f500, + 0x88e7f107, 0x7f21f413, - 0xf4013cf0, -/* 0x0702: i2c_bitr_done */ - 0x00f80131, -/* 0x0704: i2c_get_byte */ - 0xf00057f0, -/* 0x070a: i2c_get_byte_next */ - 0x54b60847, +/* 0x08b8: i2c_bitw_out */ +/* 0x08ba: i2c_bitr */ + 0x37f000f8, + 0x7321f501, + 0xe8e7f107, + 0x7f21f403, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xc521f550, + 0x0464b607, + 0xf51b11f4, + 0xf007ad21, + 0x21f50037, + 0xe7f10751, + 0x21f41388, + 0x013cf07f, +/* 0x08ff: i2c_bitr_done */ + 0xf80131f4, +/* 0x0901: i2c_get_byte */ + 0x0057f000, +/* 0x0907: i2c_get_byte_next */ + 0xb60847f0, + 0x76bb0154, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb608ba21, + 0x11f40464, + 0x0553fd2b, + 0xf40142b6, + 0x37f0d81b, 0x0076bb01, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b606bd, - 0x2b11f404, - 0xb60553fd, - 0x1bf40142, - 0x0137f0d8, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0x7c21f550, - 0x0464b606, -/* 0x0754: i2c_get_byte_done */ -/* 0x0756: i2c_put_byte */ - 0x47f000f8, -/* 0x0759: i2c_put_byte_next */ - 0x0142b608, - 0xbb3854ff, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x067c21f5, - 0xf40464b6, - 0x46b03411, - 0xd81bf400, + 0x64b60879, +/* 0x0951: i2c_get_byte_done */ +/* 0x0953: i2c_put_byte */ + 0xf000f804, +/* 0x0956: i2c_put_byte_next */ + 0x42b60847, + 0x3854ff01, 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0xbd21f550, - 0x0464b606, - 0xbb0f11f4, - 0x36b00076, - 0x061bf401, -/* 0x07af: i2c_put_byte_done */ - 0xf80132f4, -/* 0x07b1: i2c_addr */ - 0x0076bb00, + 0x7921f550, + 0x0464b608, + 0xb03411f4, + 0x1bf40046, + 0x0076bbd8, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b605ed, - 0x2911f404, - 0x012ec3e7, - 0xfd0134b6, - 0x76bb0553, + 0x64b608ba, + 0x0f11f404, + 0xb00076bb, + 0x1bf40136, + 0x0132f406, +/* 0x09ac: i2c_put_byte_done */ +/* 0x09ae: i2c_addr */ + 0x76bb00f8, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb6075621, -/* 0x07f6: i2c_addr_done */ - 0x00f80464, -/* 0x07f8: i2c_acquire_addr */ - 0xb6f8cec7, - 0xe0b702e4, - 0xee980bfc, -/* 0x0807: i2c_acquire */ - 0xf500f800, - 0xf407f821, - 0xd9f00421, - 0x3f21f403, -/* 0x0816: i2c_release */ - 0x21f500f8, - 0x21f407f8, - 0x03daf004, - 0xf83f21f4, -/* 0x0825: i2c_recv */ - 0x0132f400, - 0xb6f8c1c7, - 0x16b00214, - 0x3a1ff528, - 0xd413a001, - 0x0032980b, - 0x0bac13a0, - 0xf4003198, - 0xd0f90231, - 0xd0f9e0f9, - 0x000067f1, - 0x100063f1, - 0xbb016792, + 0xb607ea21, + 0x11f40464, + 0x2ec3e729, + 0x0134b601, + 0xbb0553fd, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x080721f5, - 0xfc0464b6, - 0x00d6b0d0, - 0x00b31bf5, - 0xbb0057f0, + 0x095321f5, +/* 0x09f3: i2c_addr_done */ + 0xf80464b6, +/* 0x09f5: i2c_acquire_addr */ + 0xf8cec700, + 0xb702e4b6, + 0x980c10e0, + 0x00f800ee, +/* 0x0a04: i2c_acquire */ + 0x09f521f5, + 0xf00421f4, + 0x21f403d9, +/* 0x0a13: i2c_release */ + 0xf500f83f, + 0xf409f521, + 0xdaf00421, + 0x3f21f403, +/* 0x0a22: i2c_recv */ + 0x32f400f8, + 0xf8c1c701, + 0xb00214b6, + 0x1ff52816, + 0x13a0013a, + 0x32980be8, + 0xc013a000, + 0x0031980b, + 0xf90231f4, + 0xf9e0f9d0, + 0x0067f1d0, + 0x0063f100, + 0x01679210, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x0421f550, + 0x0464b60a, + 0xd6b0d0fc, + 0xb31bf500, + 0x0057f000, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xae21f550, + 0x0464b609, + 0x00d011f5, + 0xbbe0c5c7, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x07b121f5, + 0x095321f5, 0xf50464b6, - 0xc700d011, - 0x76bbe0c5, + 0xf000ad11, + 0x76bb0157, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb6075621, + 0xb609ae21, 0x11f50464, - 0x57f000ad, - 0x0076bb01, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0x21f550fc, - 0x64b607b1, - 0x8a11f504, - 0x0076bb00, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0x21f550fc, - 0x64b60704, - 0x6a11f404, - 0xbbe05bcb, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x064921f5, - 0xb90464b6, - 0x74bd025b, -/* 0x092b: i2c_recv_not_rd08 */ - 0xb0430ef4, - 0x1bf401d6, - 0x0057f03d, - 0x07b121f5, - 0xc73311f4, - 0x21f5e0c5, - 0x11f40756, - 0x0057f029, - 0x07b121f5, - 0xc71f11f4, - 0x21f5e0b5, - 0x11f40756, - 0x4921f515, - 0xc774bd06, - 0x1bf408c5, - 0x0232f409, -/* 0x096b: i2c_recv_not_wr08 */ -/* 0x096b: i2c_recv_done */ - 0xc7030ef4, - 0x21f5f8ce, - 0xe0fc0816, - 0x12f4d0fc, - 0x027cb90a, - 0x02b921f5, -/* 0x0980: i2c_recv_exit */ -/* 0x0982: i2c_init */ + 0x76bb008a, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb6090121, + 0x11f40464, + 0xe05bcb6a, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x4621f550, + 0x0464b608, + 0xbd025bb9, + 0x430ef474, +/* 0x0b28: i2c_recv_not_rd08 */ + 0xf401d6b0, + 0x57f03d1b, + 0xae21f500, + 0x3311f409, + 0xf5e0c5c7, + 0xf4095321, + 0x57f02911, + 0xae21f500, + 0x1f11f409, + 0xf5e0b5c7, + 0xf4095321, + 0x21f51511, + 0x74bd0846, + 0xf408c5c7, + 0x32f4091b, + 0x030ef402, +/* 0x0b68: i2c_recv_not_wr08 */ +/* 0x0b68: i2c_recv_done */ + 0xf5f8cec7, + 0xfc0a1321, + 0xf4d0fce0, + 0x7cb90a12, + 0x4221f502, +/* 0x0b7d: i2c_recv_exit */ +/* 0x0b7f: i2c_init */ + 0xf800f803, +/* 0x0b81: test_recv */ + 0xd817f100, + 0x0614b605, + 0xb60011cf, + 0x07f10110, + 0x04b605d8, + 0x0001d006, + 0xe7f104bd, + 0xe3f1d900, + 0x21f5134f, + 0x00f80262, +/* 0x0ba8: test_init */ + 0x0800e7f1, + 0x026221f5, +/* 0x0bb2: idle_recv */ 0x00f800f8, -/* 0x0984: test_recv */ - 0x05d817f1, - 0xcf0614b6, - 0x10b60011, - 0xd807f101, - 0x0604b605, - 0xbd0001d0, - 0x00e7f104, - 0x4fe3f1d9, - 0xf521f513, -/* 0x09ab: test_init */ - 0xf100f801, - 0xf50800e7, - 0xf801f521, -/* 0x09b5: idle_recv */ -/* 0x09b7: idle */ - 0xf400f800, - 0x17f10031, - 0x14b605d4, - 0x0011cf06, - 0xf10110b6, - 0xb605d407, - 0x01d00604, -/* 0x09d3: idle_loop */ - 0xf004bd00, - 0x32f45817, -/* 0x09d9: idle_proc */ -/* 0x09d9: idle_proc_exec */ - 0xb910f902, - 0x21f5021e, - 0x10fc02c2, - 0xf40911f4, - 0x0ef40231, -/* 0x09ed: idle_proc_next */ - 0x5810b6ef, - 0xf4061fb8, - 0x02f4e61b, - 0x0028f4dd, - 0x00bb0ef4, +/* 0x0bb4: idle */ + 0xf10031f4, + 0xb605d417, + 0x11cf0614, + 0x0110b600, + 0x05d407f1, + 0xd00604b6, + 0x04bd0001, +/* 0x0bd0: idle_loop */ + 0xf45817f0, +/* 0x0bd6: idle_proc */ +/* 0x0bd6: idle_proc_exec */ + 0x10f90232, + 0xf5021eb9, + 0xfc034b21, + 0x0911f410, + 0xf40231f4, +/* 0x0bea: idle_proc_next */ + 0x10b6ef0e, + 0x061fb858, + 0xf4e61bf4, + 0x28f4dd02, + 0xbb0ef400, + 0x00000000, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc index 8a89dfe41ce1..b85443261569 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc @@ -23,6 +23,7 @@ */ #define NVKM_PPWR_CHIPSET GF119 +#define HW_TICKS_PER_US 324 //#define NVKM_FALCON_PC24 #define NVKM_FALCON_UNSHIFTED_IO @@ -34,6 +35,7 @@ .section #nvd0_pwr_data #define INCLUDE_PROC #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -44,6 +46,7 @@ #define INCLUDE_DATA #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" @@ -56,6 +59,7 @@ .section #nvd0_pwr_code #define INCLUDE_CODE #include "kernel.fuc" +#include "arith.fuc" #include "host.fuc" #include "memx.fuc" #include "perf.fuc" diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h index cd9ff1a73284..12d86f72ad10 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h @@ -24,8 +24,8 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, /* 0x0058: proc_list_head */ 0x54534f48, - 0x000003be, - 0x00000367, + 0x0000049d, + 0x00000446, 0x00000000, 0x00000000, 0x00000000, @@ -46,8 +46,8 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, 0x00000000, 0x584d454d, - 0x000004c4, - 0x000004b6, + 0x00000678, + 0x0000066a, 0x00000000, 0x00000000, 0x00000000, @@ -68,8 +68,8 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, 0x00000000, 0x46524550, - 0x000004c8, - 0x000004c6, + 0x0000067c, + 0x0000067a, 0x00000000, 0x00000000, 0x00000000, @@ -90,8 +90,8 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, 0x00000000, 0x5f433249, - 0x000008e3, - 0x00000786, + 0x00000a97, + 0x0000093a, 0x00000000, 0x00000000, 0x00000000, @@ -112,8 +112,8 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, 0x00000000, 0x54534554, - 0x00000906, - 0x000008e5, + 0x00000aba, + 0x00000a99, 0x00000000, 0x00000000, 0x00000000, @@ -134,8 +134,8 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, 0x00000000, 0x454c4449, - 0x00000912, - 0x00000910, + 0x00000ac6, + 0x00000ac4, 0x00000000, 0x00000000, 0x00000000, @@ -227,24 +227,31 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, 0x00000000, /* 0x0370: memx_func_head */ - 0x00010000, - 0x00000000, - 0x000003f4, -/* 0x037c: memx_func_next */ 0x00000001, 0x00000000, - 0x00000415, + 0x000004d3, +/* 0x037c: memx_func_next */ 0x00000002, + 0x00000000, + 0x00000554, + 0x00000003, 0x00000002, - 0x00000430, - 0x00040003, + 0x000005d8, + 0x00040004, + 0x00000000, + 0x000005f4, + 0x00010005, + 0x00000000, + 0x0000060e, + 0x00010006, + 0x00000000, + 0x000005d3, +/* 0x03b8: memx_func_tail */ +/* 0x03b8: memx_ts_start */ 0x00000000, - 0x00000458, - 0x00010004, +/* 0x03bc: memx_ts_end */ 0x00000000, - 0x00000472, -/* 0x03ac: memx_func_tail */ -/* 0x03ac: memx_data_head */ +/* 0x03c0: memx_data_head */ 0x00000000, 0x00000000, 0x00000000, @@ -757,8 +764,8 @@ uint32_t nvd0_pwr_data[] = { 0x00000000, 0x00000000, 0x00000000, -/* 0x0bac: memx_data_tail */ -/* 0x0bac: i2c_scl_map */ +/* 0x0bc0: memx_data_tail */ +/* 0x0bc0: i2c_scl_map */ 0x00000400, 0x00000800, 0x00001000, @@ -769,7 +776,7 @@ uint32_t nvd0_pwr_data[] = { 0x00020000, 0x00040000, 0x00080000, -/* 0x0bd4: i2c_sda_map */ +/* 0x0be8: i2c_sda_map */ 0x00100000, 0x00200000, 0x00400000, @@ -781,10 +788,69 @@ uint32_t nvd0_pwr_data[] = { 0x10000000, 0x20000000, 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; uint32_t nvd0_pwr_code[] = { - 0x02bf0ef5, + 0x034d0ef5, /* 0x0004: rd32 */ 0x07a007f1, 0xbd000ed0, @@ -814,17 +880,20 @@ uint32_t nvd0_pwr_code[] = { 0xd4f100dd, 0x1bf47000, /* 0x0067: nsec */ - 0xf000f8f5, + 0xf900f8f5, + 0xf080f990, 0x88cf2c87, -/* 0x006d: nsec_loop */ +/* 0x0071: nsec_loop */ 0x2c97f000, 0xbb0099cf, 0x9eb80298, 0xf41ef406, -/* 0x007e: wait */ - 0x87f000f8, + 0x90fc80fc, +/* 0x0086: wait */ + 0x90f900f8, + 0x87f080f9, 0x0088cf2c, -/* 0x0084: wait_loop */ +/* 0x0090: wait_loop */ 0xf402eeb9, 0xdab90421, 0x04adfd02, @@ -833,28 +902,29 @@ uint32_t nvd0_pwr_code[] = { 0x0099cf2c, 0xb80298bb, 0x1ef4069b, -/* 0x00a5: wait_done */ -/* 0x00a7: intr_watchdog */ - 0x9800f8e2, +/* 0x00b1: wait_done */ + 0xfc80fce2, +/* 0x00b7: intr_watchdog */ + 0x9800f890, 0x96b003e9, 0x2a0bf400, 0xbb9a0a98, 0x1cf4029a, 0x01d7f00f, - 0x020621f5, + 0x028c21f5, 0x0ef494bd, -/* 0x00c5: intr_watchdog_next_time */ +/* 0x00d5: intr_watchdog_next_time */ 0x9b0a9815, 0xf400a6b0, 0x9ab8090b, 0x061cf406, -/* 0x00d4: intr_watchdog_next_time_set */ -/* 0x00d7: intr_watchdog_next_proc */ +/* 0x00e4: intr_watchdog_next_time_set */ +/* 0x00e7: intr_watchdog_next_proc */ 0x809b0980, 0xe0b603e9, 0x68e6b158, 0xc61bf402, -/* 0x00e6: intr */ +/* 0x00f6: intr */ 0x00f900f8, 0x80f904bd, 0xa0f990f9, @@ -872,12 +942,12 @@ uint32_t nvd0_pwr_code[] = { 0x0bf40289, 0x9b008020, 0xf458e7f0, - 0x0998a721, + 0x0998b721, 0x0096b09b, 0xf00e0bf4, 0x09d03407, 0x8004bd00, -/* 0x013e: intr_skip_watchdog */ +/* 0x014e: intr_skip_watchdog */ 0x89e49a09, 0x0bf40800, 0x8897f13c, @@ -889,20 +959,20 @@ uint32_t nvd0_pwr_code[] = { 0xf14f48e7, 0xf05453e3, 0x21f500d7, - 0xc0fc026b, + 0xc0fc02f1, 0x04c007f1, 0xbd000cd0, -/* 0x0175: intr_subintr_skip_fifo */ +/* 0x0185: intr_subintr_skip_fifo */ 0x8807f104, 0x0009d006, -/* 0x017e: intr_skip_subintr */ +/* 0x018e: intr_skip_subintr */ 0x89c404bd, 0x070bf420, 0xffbfa4f1, -/* 0x0188: intr_skip_pause */ +/* 0x0198: intr_skip_pause */ 0xf44089c4, 0xa4f1070b, -/* 0x0192: intr_skip_user0 */ +/* 0x01a2: intr_skip_user0 */ 0x07f0ffbf, 0x0008d004, 0x80fc04bd, @@ -912,324 +982,436 @@ uint32_t nvd0_pwr_code[] = { 0xfca0fcb0, 0xfc80fc90, 0x0032f400, -/* 0x01b6: timer */ - 0x32f401f8, - 0x03f89810, - 0xf40086b0, - 0xfe80421c, - 0x3807f003, +/* 0x01c6: ticks_from_ns */ + 0xc0f901f8, + 0xd7f1b0f9, + 0xd3f00144, + 0xb321f500, + 0xe8ccec03, + 0x00b4b003, + 0xec120bf4, + 0xf103e8ee, + 0xf00144d7, + 0x21f500d3, +/* 0x01ee: ticks_from_ns_quit */ + 0xceb903b3, + 0xfcb0fc02, +/* 0x01f7: ticks_from_us */ + 0xf900f8c0, + 0xf1b0f9c0, + 0xf00144d7, + 0x21f500d3, + 0xceb903b3, + 0x00b4b002, + 0xbd050bf4, +/* 0x0211: ticks_from_us_quit */ + 0xfcb0fce4, +/* 0x0217: ticks_to_us */ + 0xf100f8c0, + 0xf00144d7, + 0xedff00d3, +/* 0x0223: timer */ + 0xf900f8ec, + 0xf480f990, + 0xf8981032, + 0x0086b003, + 0xbd531cf4, + 0x3807f084, 0xbd0008d0, - 0x0887f004, - 0xf00088cf, - 0x1bf40284, - 0x3487f020, - 0xb80088cf, - 0x0bf406e0, - 0x06e8b809, -/* 0x01eb: timer_reset */ - 0xf0191ef4, - 0x0ed03407, - 0x8004bd00, -/* 0x01f6: timer_enable */ - 0x87f09a0e, - 0x3807f001, - 0xbd0008d0, -/* 0x0201: timer_done */ - 0x1031f404, -/* 0x0206: send_proc */ - 0x80f900f8, - 0xe89890f9, + 0x3487f004, + 0x980088cf, + 0x98bb9a09, + 0x00e9bb02, + 0xf003fe80, + 0x88cf0887, + 0x0284f000, + 0xf0201bf4, + 0x88cf3487, + 0x06e0b800, + 0xb8090bf4, + 0x1cf406e8, +/* 0x026d: timer_reset */ + 0x3407f00e, + 0xbd000ed0, + 0x9a0e8004, +/* 0x0278: timer_enable */ + 0xf00187f0, + 0x08d03807, +/* 0x0283: timer_done */ + 0xf404bd00, + 0x80fc1031, + 0x00f890fc, +/* 0x028c: send_proc */ + 0x90f980f9, + 0x9805e898, + 0x86f004e9, + 0x0689b804, + 0xc42a0bf4, + 0x88940398, + 0x1880b604, + 0x98008ebb, + 0x8a8000fa, + 0x018d8000, + 0x80028c80, + 0x90b6038b, + 0x0794f001, + 0xf404e980, +/* 0x02c6: send_done */ + 0x90fc0231, + 0x00f880fc, +/* 0x02cc: find */ + 0x87f080f9, + 0x0131f458, +/* 0x02d4: find_loop */ + 0xb8008a98, + 0x0bf406ae, + 0x5880b610, + 0x026886b1, + 0xf4f01bf4, +/* 0x02ea: find_done */ + 0x8eb90132, + 0xf880fc02, +/* 0x02f1: send */ + 0xcc21f500, + 0x9701f402, +/* 0x02fa: recv */ + 0x90f900f8, + 0xe89880f9, 0x04e99805, - 0xb80486f0, + 0xb80132f4, 0x0bf40689, - 0x0398c42a, - 0xb6048894, - 0x8ebb1880, - 0x00fa9800, - 0x80008a80, - 0x8c80018d, - 0x038b8002, - 0xf00190b6, - 0xe9800794, - 0x0231f404, -/* 0x0240: send_done */ - 0x80fc90fc, -/* 0x0246: find */ - 0x80f900f8, - 0xf45887f0, -/* 0x024e: find_loop */ - 0x8a980131, - 0x06aeb800, - 0xb6100bf4, - 0x86b15880, - 0x1bf40268, - 0x0132f4f0, -/* 0x0264: find_done */ - 0xfc028eb9, -/* 0x026b: send */ - 0xf500f880, - 0xf4024621, - 0x00f89701, -/* 0x0274: recv */ - 0x9805e898, - 0x32f404e9, - 0x0689b801, - 0xc43d0bf4, - 0x80b60389, - 0x0784f001, - 0x9805e880, - 0xf0f902ea, - 0xf9018ffe, - 0x02efb9f0, - 0xbb049994, - 0xe0b600e9, - 0x03eb9818, - 0x9802ec98, - 0xee9801ed, - 0xfca5f900, - 0x00f8fef0, - 0xfc0131f4, -/* 0x02bd: recv_done */ -/* 0x02bf: init */ - 0xf100f8f0, - 0xcf010817, - 0x11e70011, - 0x14b60109, - 0x0014fe08, - 0x00e017f1, - 0xf00013f0, - 0x01d01c07, - 0xf004bd00, - 0x07f0ff17, - 0x0001d014, - 0x17f004bd, - 0x0015f102, - 0x1007f008, - 0xbd0001d0, - 0xe617f104, - 0x0013f000, - 0xf40010fe, - 0x17f01031, - 0x3807f001, - 0xbd0001d0, - 0x58f7f004, -/* 0x0314: init_proc */ - 0xb001f198, - 0x0bf40016, - 0xb615f9fa, - 0x0ef458f0, -/* 0x0325: host_send */ - 0xb017f1f2, - 0x0011cf04, - 0x04a027f1, - 0xb80022cf, - 0x0bf40612, - 0x071ec42f, - 0xb704ee94, - 0x980270e0, + 0x0389c43d, + 0xf00180b6, + 0xe8800784, + 0x02ea9805, + 0x8ffef0f9, + 0xb9f0f901, + 0x999402ef, + 0x00e9bb04, + 0x9818e0b6, 0xec9803eb, 0x01ed9802, - 0xf500ee98, - 0xb6026b21, - 0x1ec40110, - 0xb007f10f, - 0x000ed004, - 0x0ef404bd, -/* 0x0365: host_send_done */ -/* 0x0367: host_recv */ - 0xf100f8c3, - 0xf14e4917, - 0xb8525413, - 0x0bf406e1, -/* 0x0375: host_recv_wait */ - 0xcc17f1b3, - 0x0011cf04, - 0x04c827f1, - 0xf00022cf, - 0x12b80816, - 0xec0bf406, - 0xb60723c4, - 0x30b70434, - 0x3b8002f0, - 0x023c8003, - 0x80013d80, - 0x20b6003e, - 0x0f24f001, - 0x04c807f1, - 0xbd0002d0, - 0x4027f004, - 0xd00007f0, - 0x04bd0002, -/* 0x03be: host_init */ + 0xf900ee98, + 0xfef0fca5, + 0x31f400f8, +/* 0x0347: recv_done */ + 0xfcf0fc01, + 0xf890fc80, +/* 0x034d: init */ + 0x0817f100, + 0x0011cf01, + 0x010911e7, + 0xfe0814b6, + 0x17f10014, + 0x13f000e0, + 0x1c07f000, + 0xbd0001d0, + 0xff17f004, + 0xd01407f0, + 0x04bd0001, + 0xf10217f0, + 0xf0080015, + 0x01d01007, + 0xf104bd00, + 0xf000f617, + 0x10fe0013, + 0x1031f400, + 0xf00117f0, + 0x01d03807, + 0xf004bd00, +/* 0x03a2: init_proc */ + 0xf19858f7, + 0x0016b001, + 0xf9fa0bf4, + 0x58f0b615, +/* 0x03b3: mulu32_32_64 */ + 0xf9f20ef4, + 0xf920f910, + 0x9540f930, + 0xd29510e1, + 0xbdc4bd10, + 0xc0edffb4, + 0xb9301dff, + 0x34f10234, + 0x34b6ffff, + 0x1045b610, + 0xbb00c3bb, + 0xe2ff01b4, + 0x0234b930, + 0xffff34f1, + 0xb61034b6, + 0xc3bb1045, + 0x01b4bb00, + 0xbb3012ff, + 0x40fc00b3, + 0x20fc30fc, + 0x00f810fc, +/* 0x0404: host_send */ + 0x04b017f1, + 0xf10011cf, + 0xcf04a027, + 0x12b80022, + 0x2f0bf406, + 0x94071ec4, + 0xe0b704ee, + 0xeb980270, + 0x02ec9803, + 0x9801ed98, + 0x21f500ee, + 0x10b602f1, + 0x0f1ec401, + 0x04b007f1, + 0xbd000ed0, + 0xc30ef404, +/* 0x0444: host_send_done */ +/* 0x0446: host_recv */ 0x17f100f8, - 0x14b60080, - 0x7015f110, - 0xd007f102, - 0x0001d004, - 0x17f104bd, - 0x14b60080, - 0xf015f110, - 0xdc07f102, - 0x0001d004, - 0x17f004bd, - 0xc407f101, - 0x0001d004, - 0x00f804bd, -/* 0x03f4: memx_func_enter */ + 0x13f14e49, + 0xe1b85254, + 0xb30bf406, +/* 0x0454: host_recv_wait */ + 0x04cc17f1, + 0xf10011cf, + 0xcf04c827, + 0x16f00022, + 0x0612b808, + 0xc4ec0bf4, + 0x34b60723, + 0xf030b704, + 0x033b8002, + 0x80023c80, + 0x3e80013d, + 0x0120b600, + 0xf10f24f0, + 0xd004c807, + 0x04bd0002, + 0xf04027f0, + 0x02d00007, + 0xf804bd00, +/* 0x049d: host_init */ + 0x8017f100, + 0x1014b600, + 0x027015f1, + 0x04d007f1, + 0xbd0001d0, + 0x8017f104, + 0x1014b600, + 0x02f015f1, + 0x04dc07f1, + 0xbd0001d0, + 0x0117f004, + 0x04c407f1, + 0xbd0001d0, +/* 0x04d3: memx_func_enter */ + 0xf100f804, + 0xf1162067, + 0xf1f55d77, + 0xb9ffff73, + 0x21f4026e, + 0x02d8b904, + 0xf90487fd, + 0xfc80f960, + 0xf4e0fcd0, + 0x77f13321, + 0x73f1fffe, + 0x6eb9ffff, + 0x0421f402, + 0xfd02d8b9, + 0x60f90487, + 0xd0fc80f9, + 0x21f4e0fc, + 0xf067f133, + 0x026eb926, + 0xb90421f4, + 0x87fd02d8, + 0xf960f904, + 0xfcd0fc80, + 0x3321f4e0, 0xf10467f0, 0xd007e007, 0x04bd0006, -/* 0x0400: memx_func_enter_wait */ +/* 0x053c: memx_func_enter_wait */ 0x07c067f1, 0xf00066cf, 0x0bf40464, - 0x001698f6, - 0xf80410b6, -/* 0x0415: memx_func_leave */ - 0x0467f000, + 0x2c67f0f6, + 0x800066cf, + 0x00f8ee06, +/* 0x0554: memx_func_leave */ + 0xcf2c67f0, + 0x06800066, + 0x0467f0ef, 0x07e407f1, 0xbd0006d0, -/* 0x0421: memx_func_leave_wait */ +/* 0x0569: memx_func_leave_wait */ 0xc067f104, 0x0066cf07, 0xf40464f0, - 0x00f8f61b, -/* 0x0430: memx_func_wr32 */ + 0x67f1f61b, + 0x77f126f0, + 0x73f00001, + 0x026eb900, + 0xb90421f4, + 0x87fd02d8, + 0xf960f905, + 0xfcd0fc80, + 0x3321f4e0, + 0x162067f1, + 0xf4026eb9, + 0xd8b90421, + 0x0587fd02, + 0x80f960f9, + 0xe0fcd0fc, + 0xf13321f4, + 0xf00aa277, + 0x6eb90073, + 0x0421f402, + 0xfd02d8b9, + 0x60f90587, + 0xd0fc80f9, + 0x21f4e0fc, +/* 0x05d3: memx_func_wait_vblank */ + 0xb600f833, + 0x00f80410, +/* 0x05d8: memx_func_wr32 */ 0x98001698, 0x10b60115, 0xf960f908, 0xfcd0fc50, 0x3321f4e0, - 0x140003f1, - 0x800506fd, - 0x04bd0005, 0xf40242b6, - 0x00f8dd1b, -/* 0x0458: memx_func_wait */ + 0x00f8e91b, +/* 0x05f4: memx_func_wait */ 0xcf2c87f0, 0x1e980088, 0x011d9800, 0x98021c98, 0x10b6031b, - 0x7e21f410, -/* 0x0472: memx_func_delay */ + 0x8621f410, +/* 0x060e: memx_func_delay */ 0x1e9800f8, 0x0410b600, 0xf86721f4, -/* 0x047d: memx_exec */ +/* 0x0619: memx_exec */ 0xf9e0f900, 0x02c1b9d0, -/* 0x0487: memx_exec_next */ +/* 0x0623: memx_exec_next */ 0x9802b2b9, 0x10b60013, - 0x10349504, + 0xf034e704, + 0xe033e701, + 0x0132b601, 0x980c30f0, 0x55f9de35, 0xf40612b8, - 0xd0fcec1e, + 0x0b98e41e, + 0xef0c98ee, + 0xf102cbbb, + 0xcf07c4b7, + 0xd0fc00bb, 0x21f5e0fc, - 0x00f8026b, -/* 0x04a8: memx_info */ - 0x03acc7f1, + 0x00f802f1, +/* 0x065c: memx_info */ + 0x03c0c7f1, 0x0800b7f1, - 0x026b21f5, -/* 0x04b6: memx_recv */ + 0x02f121f5, +/* 0x066a: memx_recv */ 0xd6b000f8, - 0xc40bf401, + 0xac0bf401, 0xf400d6b0, 0x00f8e90b, -/* 0x04c4: memx_init */ -/* 0x04c6: perf_recv */ +/* 0x0678: memx_init */ +/* 0x067a: perf_recv */ 0x00f800f8, -/* 0x04c8: perf_init */ -/* 0x04ca: i2c_drive_scl */ +/* 0x067c: perf_init */ +/* 0x067e: i2c_drive_scl */ 0x36b000f8, 0x0e0bf400, 0x07e007f1, 0xbd0001d0, -/* 0x04db: i2c_drive_scl_lo */ +/* 0x068f: i2c_drive_scl_lo */ 0xf100f804, 0xd007e407, 0x04bd0001, -/* 0x04e6: i2c_drive_sda */ +/* 0x069a: i2c_drive_sda */ 0x36b000f8, 0x0e0bf400, 0x07e007f1, 0xbd0002d0, -/* 0x04f7: i2c_drive_sda_lo */ +/* 0x06ab: i2c_drive_sda_lo */ 0xf100f804, 0xd007e407, 0x04bd0002, -/* 0x0502: i2c_sense_scl */ +/* 0x06b6: i2c_sense_scl */ 0x32f400f8, 0xc437f101, 0x0033cf07, 0xf40431fd, 0x31f4060b, -/* 0x0515: i2c_sense_scl_done */ -/* 0x0517: i2c_sense_sda */ +/* 0x06c9: i2c_sense_scl_done */ +/* 0x06cb: i2c_sense_sda */ 0xf400f801, 0x37f10132, 0x33cf07c4, 0x0432fd00, 0xf4060bf4, -/* 0x052a: i2c_sense_sda_done */ +/* 0x06de: i2c_sense_sda_done */ 0x00f80131, -/* 0x052c: i2c_raise_scl */ +/* 0x06e0: i2c_raise_scl */ 0x47f140f9, 0x37f00898, - 0xca21f501, -/* 0x0539: i2c_raise_scl_wait */ - 0xe8e7f104, + 0x7e21f501, +/* 0x06ed: i2c_raise_scl_wait */ + 0xe8e7f106, 0x6721f403, - 0x050221f5, + 0x06b621f5, 0xb60901f4, 0x1bf40142, -/* 0x054d: i2c_raise_scl_done */ +/* 0x0701: i2c_raise_scl_done */ 0xf840fcef, -/* 0x0551: i2c_start */ - 0x0221f500, - 0x0d11f405, - 0x051721f5, +/* 0x0705: i2c_start */ + 0xb621f500, + 0x0d11f406, + 0x06cb21f5, 0xf40611f4, -/* 0x0562: i2c_start_rep */ +/* 0x0716: i2c_start_rep */ 0x37f0300e, - 0xca21f500, - 0x0137f004, - 0x04e621f5, + 0x7e21f500, + 0x0137f006, + 0x069a21f5, 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x2c21f550, - 0x0464b605, -/* 0x058f: i2c_start_send */ + 0xe021f550, + 0x0464b606, +/* 0x0743: i2c_start_send */ 0xf01f11f4, 0x21f50037, - 0xe7f104e6, + 0xe7f1069a, 0x21f41388, 0x0037f067, - 0x04ca21f5, + 0x067e21f5, 0x1388e7f1, -/* 0x05ab: i2c_start_out */ +/* 0x075f: i2c_start_out */ 0xf86721f4, -/* 0x05ad: i2c_stop */ +/* 0x0761: i2c_stop */ 0x0037f000, - 0x04ca21f5, + 0x067e21f5, 0xf50037f0, - 0xf104e621, + 0xf1069a21, 0xf403e8e7, 0x37f06721, - 0xca21f501, - 0x88e7f104, + 0x7e21f501, + 0x88e7f106, 0x6721f413, 0xf50137f0, - 0xf104e621, + 0xf1069a21, 0xf41388e7, 0x00f86721, -/* 0x05e0: i2c_bitw */ - 0x04e621f5, +/* 0x0794: i2c_bitw */ + 0x069a21f5, 0x03e8e7f1, 0xbb6721f4, 0x65b60076, @@ -1237,18 +1419,18 @@ uint32_t nvd0_pwr_code[] = { 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x052c21f5, + 0x06e021f5, 0xf40464b6, 0xe7f11811, 0x21f41388, 0x0037f067, - 0x04ca21f5, + 0x067e21f5, 0x1388e7f1, -/* 0x061f: i2c_bitw_out */ +/* 0x07d3: i2c_bitw_out */ 0xf86721f4, -/* 0x0621: i2c_bitr */ +/* 0x07d5: i2c_bitr */ 0x0137f000, - 0x04e621f5, + 0x069a21f5, 0x03e8e7f1, 0xbb6721f4, 0x65b60076, @@ -1256,19 +1438,19 @@ uint32_t nvd0_pwr_code[] = { 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x052c21f5, + 0x06e021f5, 0xf40464b6, 0x21f51b11, - 0x37f00517, - 0xca21f500, - 0x88e7f104, + 0x37f006cb, + 0x7e21f500, + 0x88e7f106, 0x6721f413, 0xf4013cf0, -/* 0x0666: i2c_bitr_done */ +/* 0x081a: i2c_bitr_done */ 0x00f80131, -/* 0x0668: i2c_get_byte */ +/* 0x081c: i2c_get_byte */ 0xf00057f0, -/* 0x066e: i2c_get_byte_next */ +/* 0x0822: i2c_get_byte_next */ 0x54b60847, 0x0076bb01, 0xf90465b6, @@ -1276,7 +1458,7 @@ uint32_t nvd0_pwr_code[] = { 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b60621, + 0x64b607d5, 0x2b11f404, 0xb60553fd, 0x1bf40142, @@ -1286,12 +1468,12 @@ uint32_t nvd0_pwr_code[] = { 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0xe021f550, - 0x0464b605, -/* 0x06b8: i2c_get_byte_done */ -/* 0x06ba: i2c_put_byte */ + 0x9421f550, + 0x0464b607, +/* 0x086c: i2c_get_byte_done */ +/* 0x086e: i2c_put_byte */ 0x47f000f8, -/* 0x06bd: i2c_put_byte_next */ +/* 0x0871: i2c_put_byte_next */ 0x0142b608, 0xbb3854ff, 0x65b60076, @@ -1299,7 +1481,7 @@ uint32_t nvd0_pwr_code[] = { 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x05e021f5, + 0x079421f5, 0xf40464b6, 0x46b03411, 0xd81bf400, @@ -1308,21 +1490,21 @@ uint32_t nvd0_pwr_code[] = { 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x2121f550, - 0x0464b606, + 0xd521f550, + 0x0464b607, 0xbb0f11f4, 0x36b00076, 0x061bf401, -/* 0x0713: i2c_put_byte_done */ +/* 0x08c7: i2c_put_byte_done */ 0xf80132f4, -/* 0x0715: i2c_addr */ +/* 0x08c9: i2c_addr */ 0x0076bb00, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b60551, + 0x64b60705, 0x2911f404, 0x012ec3e7, 0xfd0134b6, @@ -1332,30 +1514,30 @@ uint32_t nvd0_pwr_code[] = { 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb606ba21, -/* 0x075a: i2c_addr_done */ + 0xb6086e21, +/* 0x090e: i2c_addr_done */ 0x00f80464, -/* 0x075c: i2c_acquire_addr */ +/* 0x0910: i2c_acquire_addr */ 0xb6f8cec7, 0xe0b705e4, 0x00f8d014, -/* 0x0768: i2c_acquire */ - 0x075c21f5, +/* 0x091c: i2c_acquire */ + 0x091021f5, 0xf00421f4, 0x21f403d9, -/* 0x0777: i2c_release */ +/* 0x092b: i2c_release */ 0xf500f833, - 0xf4075c21, + 0xf4091021, 0xdaf00421, 0x3321f403, -/* 0x0786: i2c_recv */ +/* 0x093a: i2c_recv */ 0x32f400f8, 0xf8c1c701, 0xb00214b6, 0x1ff52816, 0x13a0013a, - 0x32980bd4, - 0xac13a000, + 0x32980be8, + 0xc013a000, 0x0031980b, 0xf90231f4, 0xf9e0f9d0, @@ -1367,8 +1549,8 @@ uint32_t nvd0_pwr_code[] = { 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x6821f550, - 0x0464b607, + 0x1c21f550, + 0x0464b609, 0xd6b0d0fc, 0xb31bf500, 0x0057f000, @@ -1377,8 +1559,8 @@ uint32_t nvd0_pwr_code[] = { 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x1521f550, - 0x0464b607, + 0xc921f550, + 0x0464b608, 0x00d011f5, 0xbbe0c5c7, 0x65b60076, @@ -1386,7 +1568,7 @@ uint32_t nvd0_pwr_code[] = { 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x06ba21f5, + 0x086e21f5, 0xf50464b6, 0xf000ad11, 0x76bb0157, @@ -1395,7 +1577,7 @@ uint32_t nvd0_pwr_code[] = { 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb6071521, + 0xb608c921, 0x11f50464, 0x76bb008a, 0x0465b600, @@ -1403,7 +1585,7 @@ uint32_t nvd0_pwr_code[] = { 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb6066821, + 0xb6081c21, 0x11f40464, 0xe05bcb6a, 0xb60076bb, @@ -1411,38 +1593,38 @@ uint32_t nvd0_pwr_code[] = { 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0xad21f550, - 0x0464b605, + 0x6121f550, + 0x0464b607, 0xbd025bb9, 0x430ef474, -/* 0x088c: i2c_recv_not_rd08 */ +/* 0x0a40: i2c_recv_not_rd08 */ 0xf401d6b0, 0x57f03d1b, - 0x1521f500, - 0x3311f407, + 0xc921f500, + 0x3311f408, 0xf5e0c5c7, - 0xf406ba21, + 0xf4086e21, 0x57f02911, - 0x1521f500, - 0x1f11f407, + 0xc921f500, + 0x1f11f408, 0xf5e0b5c7, - 0xf406ba21, + 0xf4086e21, 0x21f51511, - 0x74bd05ad, + 0x74bd0761, 0xf408c5c7, 0x32f4091b, 0x030ef402, -/* 0x08cc: i2c_recv_not_wr08 */ -/* 0x08cc: i2c_recv_done */ +/* 0x0a80: i2c_recv_not_wr08 */ +/* 0x0a80: i2c_recv_done */ 0xf5f8cec7, - 0xfc077721, + 0xfc092b21, 0xf4d0fce0, 0x7cb90a12, - 0x6b21f502, -/* 0x08e1: i2c_recv_exit */ -/* 0x08e3: i2c_init */ + 0xf121f502, +/* 0x0a95: i2c_recv_exit */ +/* 0x0a97: i2c_init */ 0xf800f802, -/* 0x08e5: test_recv */ +/* 0x0a99: test_recv */ 0xd817f100, 0x0011cf05, 0xf10110b6, @@ -1450,29 +1632,29 @@ uint32_t nvd0_pwr_code[] = { 0x04bd0001, 0xd900e7f1, 0x134fe3f1, - 0x01b621f5, -/* 0x0906: test_init */ + 0x022321f5, +/* 0x0aba: test_init */ 0xe7f100f8, 0x21f50800, - 0x00f801b6, -/* 0x0910: idle_recv */ -/* 0x0912: idle */ + 0x00f80223, +/* 0x0ac4: idle_recv */ +/* 0x0ac6: idle */ 0x31f400f8, 0xd417f100, 0x0011cf05, 0xf10110b6, 0xd005d407, 0x04bd0001, -/* 0x0928: idle_loop */ +/* 0x0adc: idle_loop */ 0xf45817f0, -/* 0x092e: idle_proc */ -/* 0x092e: idle_proc_exec */ +/* 0x0ae2: idle_proc */ +/* 0x0ae2: idle_proc_exec */ 0x10f90232, 0xf5021eb9, - 0xfc027421, + 0xfc02fa21, 0x0911f410, 0xf40231f4, -/* 0x0942: idle_proc_next */ +/* 0x0af6: idle_proc_next */ 0x10b6ef0e, 0x061fb858, 0xf4e61bf4, @@ -1521,4 +1703,23 @@ uint32_t nvd0_pwr_code[] = { 0x00000000, 0x00000000, 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h index 574acfa44c8c..522e3079f824 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h @@ -19,11 +19,12 @@ #define MEMX_MSG_EXEC 1 /* MEMX: script opcode definitions */ -#define MEMX_ENTER 0 -#define MEMX_LEAVE 1 -#define MEMX_WR32 2 -#define MEMX_WAIT 3 -#define MEMX_DELAY 4 +#define MEMX_ENTER 1 +#define MEMX_LEAVE 2 +#define MEMX_WR32 3 +#define MEMX_WAIT 4 +#define MEMX_DELAY 5 +#define MEMX_VBLANK 6 /* I2C_: message identifiers */ #define I2C__MSG_RD08 0 diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c new file mode 100644 index 000000000000..d76612999b9f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c @@ -0,0 +1,69 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +#define nvd0_pwr_code gk104_pwr_code +#define nvd0_pwr_data gk104_pwr_data +#include "fuc/nvd0.fuc.h" + +static void +gk104_pwr_pgob(struct nouveau_pwr *ppwr, bool enable) +{ + nv_mask(ppwr, 0x000200, 0x00001000, 0x00000000); + nv_rd32(ppwr, 0x000200); + nv_mask(ppwr, 0x000200, 0x08000000, 0x08000000); + msleep(50); + + nv_mask(ppwr, 0x10a78c, 0x00000002, 0x00000002); + nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000001); + nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000000); + + nv_mask(ppwr, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000); + msleep(50); + + nv_mask(ppwr, 0x10a78c, 0x00000002, 0x00000000); + nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000001); + nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000000); + + nv_mask(ppwr, 0x000200, 0x08000000, 0x00000000); + nv_mask(ppwr, 0x000200, 0x00001000, 0x00001000); + nv_rd32(ppwr, 0x000200); +} + +struct nouveau_oclass * +gk104_pwr_oclass = &(struct nvkm_pwr_impl) { + .base.handle = NV_SUBDEV(PWR, 0xe4), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_pwr_ctor, + .dtor = _nouveau_pwr_dtor, + .init = _nouveau_pwr_init, + .fini = _nouveau_pwr_fini, + }, + .code.data = gk104_pwr_code, + .code.size = sizeof(gk104_pwr_code), + .data.data = gk104_pwr_data, + .data.size = sizeof(gk104_pwr_data), + .pgob = gk104_pwr_pgob, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c index 03de3107d29f..65eaa2546cad 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c @@ -1,8 +1,7 @@ #ifndef __NVKM_PWR_MEMX_H__ #define __NVKM_PWR_MEMX_H__ -#include <subdev/pwr.h> -#include <subdev/pwr/fuc/os.h> +#include "priv.h" struct nouveau_memx { struct nouveau_pwr *ppwr; @@ -21,10 +20,11 @@ memx_out(struct nouveau_memx *memx) struct nouveau_pwr *ppwr = memx->ppwr; int i; - if (memx->c.size) { + if (memx->c.mthd) { nv_wr32(ppwr, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd); for (i = 0; i < memx->c.size; i++) nv_wr32(ppwr, 0x10a1c4, memx->c.data[i]); + memx->c.mthd = 0; memx->c.size = 0; } } @@ -33,7 +33,7 @@ static void memx_cmd(struct nouveau_memx *memx, u32 mthd, u32 size, u32 data[]) { if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) || - (memx->c.size && memx->c.mthd != mthd)) + (memx->c.mthd && memx->c.mthd != mthd)) memx_out(memx); memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0])); memx->c.size += size; @@ -63,8 +63,7 @@ nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx) nv_wr32(ppwr, 0x10a580, 0x00000003); } while (nv_rd32(ppwr, 0x10a580) != 0x00000003); nv_wr32(ppwr, 0x10a1c0, 0x01000000 | memx->base); - nv_wr32(ppwr, 0x10a1c4, 0x00010000 | MEMX_ENTER); - nv_wr32(ppwr, 0x10a1c4, 0x00000000); + return 0; } @@ -79,7 +78,6 @@ nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec) memx_out(memx); /* release data segment access */ - nv_wr32(ppwr, 0x10a1c4, 0x00000000 | MEMX_LEAVE); finish = nv_rd32(ppwr, 0x10a1c0) & 0x00ffffff; nv_wr32(ppwr, 0x10a580, 0x00000000); @@ -89,6 +87,8 @@ nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec) memx->base, finish); } + nv_debug(memx->ppwr, "Exec took %uns, PPWR_IN %08x\n", + reply[0], reply[1]); kfree(memx); return 0; } @@ -118,4 +118,51 @@ nouveau_memx_nsec(struct nouveau_memx *memx, u32 nsec) memx_out(memx); /* fuc can't handle multiple */ } +void +nouveau_memx_wait_vblank(struct nouveau_memx *memx) +{ + struct nouveau_pwr *ppwr = memx->ppwr; + u32 heads, x, y, px = 0; + int i, head_sync; + + if (nv_device(ppwr)->chipset < 0xd0) { + heads = nv_rd32(ppwr, 0x610050); + for (i = 0; i < 2; i++) { + /* Heuristic: sync to head with biggest resolution */ + if (heads & (2 << (i << 3))) { + x = nv_rd32(ppwr, 0x610b40 + (0x540 * i)); + y = (x & 0xffff0000) >> 16; + x &= 0x0000ffff; + if ((x * y) > px) { + px = (x * y); + head_sync = i; + } + } + } + } + + if (px == 0) { + nv_debug(memx->ppwr, "WAIT VBLANK !NO ACTIVE HEAD\n"); + return; + } + + nv_debug(memx->ppwr, "WAIT VBLANK HEAD%d\n", head_sync); + memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync }); + memx_out(memx); /* fuc can't handle multiple */ +} + +void +nouveau_memx_block(struct nouveau_memx *memx) +{ + nv_debug(memx->ppwr, " HOST BLOCKED\n"); + memx_cmd(memx, MEMX_ENTER, 0, NULL); +} + +void +nouveau_memx_unblock(struct nouveau_memx *memx) +{ + nv_debug(memx->ppwr, " HOST UNBLOCKED\n"); + memx_cmd(memx, MEMX_LEAVE, 0, NULL); +} + #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c index 52c85414866a..04ff7c3c34e9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c @@ -22,41 +22,20 @@ * Authors: Ben Skeggs */ -#include <subdev/pwr.h> - +#include "priv.h" #include "fuc/nv108.fuc.h" -struct nv108_pwr_priv { - struct nouveau_pwr base; -}; - -static int -nv108_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv108_pwr_priv *priv; - int ret; - - ret = nouveau_pwr_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.code.data = nv108_pwr_code; - priv->base.code.size = sizeof(nv108_pwr_code); - priv->base.data.data = nv108_pwr_data; - priv->base.data.size = sizeof(nv108_pwr_data); - return 0; -} - -struct nouveau_oclass -nv108_pwr_oclass = { - .handle = NV_SUBDEV(PWR, 0x00), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv108_pwr_ctor, +struct nouveau_oclass * +nv108_pwr_oclass = &(struct nvkm_pwr_impl) { + .base.handle = NV_SUBDEV(PWR, 0x00), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_pwr_ctor, .dtor = _nouveau_pwr_dtor, .init = _nouveau_pwr_init, .fini = _nouveau_pwr_fini, }, -}; + .code.data = nv108_pwr_code, + .code.size = sizeof(nv108_pwr_code), + .data.data = nv108_pwr_data, + .data.size = sizeof(nv108_pwr_data), +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c index c132b7ca9747..998d53076b8b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c @@ -22,50 +22,29 @@ * Authors: Ben Skeggs */ -#include <subdev/pwr.h> - +#include "priv.h" #include "fuc/nva3.fuc.h" -struct nva3_pwr_priv { - struct nouveau_pwr base; -}; - static int nva3_pwr_init(struct nouveau_object *object) { - struct nva3_pwr_priv *priv = (void *)object; - nv_mask(priv, 0x022210, 0x00000001, 0x00000000); - nv_mask(priv, 0x022210, 0x00000001, 0x00000001); - return nouveau_pwr_init(&priv->base); -} - -static int -nva3_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nva3_pwr_priv *priv; - int ret; - - ret = nouveau_pwr_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.code.data = nva3_pwr_code; - priv->base.code.size = sizeof(nva3_pwr_code); - priv->base.data.data = nva3_pwr_data; - priv->base.data.size = sizeof(nva3_pwr_data); - return 0; + struct nouveau_pwr *ppwr = (void *)object; + nv_mask(ppwr, 0x022210, 0x00000001, 0x00000000); + nv_mask(ppwr, 0x022210, 0x00000001, 0x00000001); + return nouveau_pwr_init(ppwr); } -struct nouveau_oclass -nva3_pwr_oclass = { - .handle = NV_SUBDEV(PWR, 0xa3), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nva3_pwr_ctor, +struct nouveau_oclass * +nva3_pwr_oclass = &(struct nvkm_pwr_impl) { + .base.handle = NV_SUBDEV(PWR, 0xa3), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_pwr_ctor, .dtor = _nouveau_pwr_dtor, .init = nva3_pwr_init, .fini = _nouveau_pwr_fini, }, -}; + .code.data = nva3_pwr_code, + .code.size = sizeof(nva3_pwr_code), + .data.data = nva3_pwr_data, + .data.size = sizeof(nva3_pwr_data), +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c index 495f6857428d..9a773e66efa4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c @@ -22,41 +22,20 @@ * Authors: Ben Skeggs */ -#include <subdev/pwr.h> - +#include "priv.h" #include "fuc/nvc0.fuc.h" -struct nvc0_pwr_priv { - struct nouveau_pwr base; -}; - -static int -nvc0_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvc0_pwr_priv *priv; - int ret; - - ret = nouveau_pwr_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.code.data = nvc0_pwr_code; - priv->base.code.size = sizeof(nvc0_pwr_code); - priv->base.data.data = nvc0_pwr_data; - priv->base.data.size = sizeof(nvc0_pwr_data); - return 0; -} - -struct nouveau_oclass -nvc0_pwr_oclass = { - .handle = NV_SUBDEV(PWR, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_pwr_ctor, +struct nouveau_oclass * +nvc0_pwr_oclass = &(struct nvkm_pwr_impl) { + .base.handle = NV_SUBDEV(PWR, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_pwr_ctor, .dtor = _nouveau_pwr_dtor, .init = _nouveau_pwr_init, .fini = _nouveau_pwr_fini, }, -}; + .code.data = nvc0_pwr_code, + .code.size = sizeof(nvc0_pwr_code), + .data.data = nvc0_pwr_data, + .data.size = sizeof(nvc0_pwr_data), +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c index 043aa142fe82..2b29be5d08ac 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c @@ -22,41 +22,20 @@ * Authors: Ben Skeggs */ -#include <subdev/pwr.h> - +#include "priv.h" #include "fuc/nvd0.fuc.h" -struct nvd0_pwr_priv { - struct nouveau_pwr base; -}; - -static int -nvd0_pwr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvd0_pwr_priv *priv; - int ret; - - ret = nouveau_pwr_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.code.data = nvd0_pwr_code; - priv->base.code.size = sizeof(nvd0_pwr_code); - priv->base.data.data = nvd0_pwr_data; - priv->base.data.size = sizeof(nvd0_pwr_data); - return 0; -} - -struct nouveau_oclass -nvd0_pwr_oclass = { - .handle = NV_SUBDEV(PWR, 0xd0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvd0_pwr_ctor, +struct nouveau_oclass * +nvd0_pwr_oclass = &(struct nvkm_pwr_impl) { + .base.handle = NV_SUBDEV(PWR, 0xd0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_pwr_ctor, .dtor = _nouveau_pwr_dtor, .init = _nouveau_pwr_init, .fini = _nouveau_pwr_fini, }, -}; + .code.data = nvd0_pwr_code, + .code.size = sizeof(nvd0_pwr_code), + .data.data = nvd0_pwr_data, + .data.size = sizeof(nvd0_pwr_data), +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h new file mode 100644 index 000000000000..3814a341db32 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h @@ -0,0 +1,44 @@ +#ifndef __NVKM_PWR_PRIV_H__ +#define __NVKM_PWR_PRIV_H__ + +#include <subdev/pwr.h> +#include <subdev/pwr/fuc/os.h> + +#define nouveau_pwr_create(p, e, o, d) \ + nouveau_pwr_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_pwr_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_pwr_init(p) ({ \ + struct nouveau_pwr *_ppwr = (p); \ + _nouveau_pwr_init(nv_object(_ppwr)); \ +}) +#define nouveau_pwr_fini(p,s) ({ \ + struct nouveau_pwr *_ppwr = (p); \ + _nouveau_pwr_fini(nv_object(_ppwr), (s)); \ +}) + +int nouveau_pwr_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); + +int _nouveau_pwr_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +#define _nouveau_pwr_dtor _nouveau_subdev_dtor +int _nouveau_pwr_init(struct nouveau_object *); +int _nouveau_pwr_fini(struct nouveau_object *, bool); + +struct nvkm_pwr_impl { + struct nouveau_oclass base; + struct { + u32 *data; + u32 size; + } code; + struct { + u32 *data; + u32 size; + } data; + + void (*pgob)(struct nouveau_pwr *, bool); +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index 016990a8252c..3656d605168f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c @@ -31,6 +31,8 @@ #include <subdev/gpio.h> #include <subdev/timer.h> +#include <subdev/bios/fan.h> + static int nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) { @@ -275,8 +277,11 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) /* other random init... */ nouveau_therm_fan_set_defaults(therm); nvbios_perf_fan_parse(bios, &priv->fan->perf); - if (nvbios_therm_fan_parse(bios, &priv->fan->bios)) - nv_error(therm, "parsing the thermal table failed\n"); + if (!nvbios_fan_parse(bios, &priv->fan->bios)) { + nv_debug(therm, "parsing the fan table failed\n"); + if (nvbios_therm_fan_parse(bios, &priv->fan->bios)) + nv_error(therm, "parsing both fan tables failed\n"); + } nouveau_therm_fan_safety_checks(therm); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c index 9a5c07340263..c629d7f2a6a4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c @@ -25,6 +25,8 @@ #include <core/option.h> #include <subdev/gpio.h> +#include <subdev/bios.h> +#include <subdev/bios/fan.h> #include "priv.h" @@ -86,11 +88,15 @@ nouveau_fanpwm_create(struct nouveau_therm *therm, struct dcb_gpio_func *func) { struct nouveau_device *device = nv_device(therm); struct nouveau_therm_priv *tpriv = (void *)therm; + struct nouveau_bios *bios = nouveau_bios(therm); struct nouveau_fanpwm_priv *priv; + struct nvbios_therm_fan fan; u32 divs, duty; + nvbios_fan_parse(bios, &fan); + if (!nouveau_boolopt(device->cfgopt, "NvFanPWM", func->param) || - !therm->pwm_ctrl || + !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE || therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV) return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c new file mode 100644 index 000000000000..668cf3322285 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c @@ -0,0 +1,93 @@ +/* + * Copyright 2014 Martin Peres + * + * 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: Martin Peres + */ + +#include "priv.h" + +struct gm107_therm_priv { + struct nouveau_therm_priv base; +}; + +static int +gm107_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) +{ + /* nothing to do, it seems hardwired */ + return 0; +} + +static int +gm107_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) +{ + *divs = nv_rd32(therm, 0x10eb20) & 0x1fff; + *duty = nv_rd32(therm, 0x10eb24) & 0x1fff; + return 0; +} + +static int +gm107_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) +{ + nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */ + nv_wr32(therm, 0x10eb14, duty | 0x80000000); + return 0; +} + +static int +gm107_fan_pwm_clock(struct nouveau_therm *therm, int line) +{ + return nv_device(therm)->crystal * 1000; +} + +static int +gm107_therm_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gm107_therm_priv *priv; + int ret; + + ret = nouveau_therm_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl; + priv->base.base.pwm_get = gm107_fan_pwm_get; + priv->base.base.pwm_set = gm107_fan_pwm_set; + priv->base.base.pwm_clock = gm107_fan_pwm_clock; + priv->base.base.temp_get = nv84_temp_get; + priv->base.base.fan_sense = nva3_therm_fan_sense; + priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling; + return nouveau_therm_preinit(&priv->base.base); +} + +struct nouveau_oclass +gm107_therm_oclass = { + .handle = NV_SUBDEV(THERM, 0x117), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_therm_ctor, + .dtor = _nouveau_therm_dtor, + .init = nvd0_therm_init, + .fini = nv84_therm_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c index 1d15c52fad0c..14e2e09bfc24 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c @@ -24,6 +24,7 @@ */ #include "priv.h" +#include <subdev/fuse.h> struct nv84_therm_priv { struct nouveau_therm_priv base; @@ -32,7 +33,25 @@ struct nv84_therm_priv { int nv84_temp_get(struct nouveau_therm *therm) { - return nv_rd32(therm, 0x20400); + struct nouveau_fuse *fuse = nouveau_fuse(therm); + + if (nv_ro32(fuse, 0x1a8) == 1) + return nv_rd32(therm, 0x20400); + else + return -ENODEV; +} + +void +nv84_sensor_setup(struct nouveau_therm *therm) +{ + struct nouveau_fuse *fuse = nouveau_fuse(therm); + + /* enable temperature reading for cards with insane defaults */ + if (nv_ro32(fuse, 0x1a8) == 1) { + nv_mask(therm, 0x20008, 0x80008000, 0x80000000); + nv_mask(therm, 0x2000c, 0x80000003, 0x00000000); + mdelay(20); /* wait for the temperature to stabilize */ + } } static void @@ -171,6 +190,21 @@ nv84_therm_intr(struct nouveau_subdev *subdev) } static int +nv84_therm_init(struct nouveau_object *object) +{ + struct nv84_therm_priv *priv = (void *)object; + int ret; + + ret = nouveau_therm_init(&priv->base.base); + if (ret) + return ret; + + nv84_sensor_setup(&priv->base.base); + + return 0; +} + +static int nv84_therm_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -228,7 +262,7 @@ nv84_therm_oclass = { .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv84_therm_ctor, .dtor = _nouveau_therm_dtor, - .init = _nouveau_therm_init, + .init = nv84_therm_init, .fini = nv84_therm_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c index 0478b2e3fb1d..7893357a7e9f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c @@ -51,6 +51,8 @@ nva3_therm_init(struct nouveau_object *object) if (ret) return ret; + nv84_sensor_setup(&priv->base.base); + /* enable fan tach, count revolutions per-second */ nv_mask(priv, 0x00e720, 0x00000003, 0x00000002); if (tach->func != DCB_GPIO_UNUSED) { diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c index bbf117be572f..b70f7cc649b8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c @@ -114,7 +114,7 @@ nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line) return nv_device(therm)->crystal * 1000 / 10; } -static int +int nvd0_therm_init(struct nouveau_object *object) { struct nvd0_therm_priv *priv = (void *)object; @@ -150,6 +150,8 @@ nvd0_therm_ctor(struct nouveau_object *parent, if (ret) return ret; + nv84_sensor_setup(&priv->base.base); + priv->base.base.pwm_ctrl = nvd0_fan_pwm_ctrl; priv->base.base.pwm_get = nvd0_fan_pwm_get; priv->base.base.pwm_set = nvd0_fan_pwm_set; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index 916fca5c7816..7dba8c281a0b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h @@ -145,10 +145,13 @@ int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *); int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32); int nv50_fan_pwm_clock(struct nouveau_therm *, int); int nv84_temp_get(struct nouveau_therm *therm); +void nv84_sensor_setup(struct nouveau_therm *therm); int nv84_therm_fini(struct nouveau_object *object, bool suspend); int nva3_therm_fan_sense(struct nouveau_therm *); +int nvd0_therm_init(struct nouveau_object *object); + int nouveau_fanpwm_create(struct nouveau_therm *, struct dcb_gpio_func *); int nouveau_fantog_create(struct nouveau_therm *, struct dcb_gpio_func *); int nouveau_fannil_create(struct nouveau_therm *); diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c index 7dd680ff2f6f..f75a683bd47a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c @@ -296,7 +296,7 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, int ret; mutex_lock(&nv_subdev(vmm)->mutex); - ret = nouveau_mm_head(&vm->mm, page_shift, msize, msize, align, + ret = nouveau_mm_head(&vm->mm, 0, page_shift, msize, msize, align, &vma->node); if (unlikely(ret != 0)) { mutex_unlock(&nv_subdev(vmm)->mutex); diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c index 668cf964e4a9..2d0988755530 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c @@ -28,7 +28,7 @@ #include <subdev/timer.h> #include <subdev/fb.h> #include <subdev/vm.h> -#include <subdev/ltcg.h> +#include <subdev/ltc.h> #include <subdev/bar.h> struct nvc0_vmmgr_priv { @@ -116,12 +116,12 @@ nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, pte <<= 3; if (mem->tag) { - struct nouveau_ltcg *ltcg = - nouveau_ltcg(vma->vm->vmm->base.base.parent); + struct nouveau_ltc *ltc = + nouveau_ltc(vma->vm->vmm->base.base.parent); u32 tag = mem->tag->offset + (delta >> 17); phys |= (u64)tag << (32 + 12); next |= (u64)1 << (32 + 12); - ltcg->tags_clear(ltcg, tag, cnt); + ltc->tags_clear(ltc, tag, cnt); } while (cnt--) { diff --git a/drivers/gpu/drm/nouveau/dispnv04/arb.c b/drivers/gpu/drm/nouveau/dispnv04/arb.c index 2a15b98b4d2b..c6361422a0b2 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/arb.c +++ b/drivers/gpu/drm/nouveau/dispnv04/arb.c @@ -198,12 +198,12 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, int *burst, int *lwm) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; struct nv_fifo_info fifo_data; struct nv_sim_state sim_data; int MClk = nouveau_hw_get_clock(dev, PLL_MEMORY); int NVClk = nouveau_hw_get_clock(dev, PLL_CORE); - uint32_t cfg1 = nv_rd32(device, NV04_PFB_CFG1); + uint32_t cfg1 = nvif_rd32(device, NV04_PFB_CFG1); sim_data.pclk_khz = VClk; sim_data.mclk_khz = MClk; @@ -221,13 +221,13 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, sim_data.mem_latency = 3; sim_data.mem_page_miss = 10; } else { - sim_data.memory_type = nv_rd32(device, NV04_PFB_CFG0) & 0x1; - sim_data.memory_width = (nv_rd32(device, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64; + sim_data.memory_type = nvif_rd32(device, NV04_PFB_CFG0) & 0x1; + sim_data.memory_width = (nvif_rd32(device, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64; sim_data.mem_latency = cfg1 & 0xf; sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1); } - if (nv_device(drm->device)->card_type == NV_04) + if (drm->device.info.family == NV_DEVICE_INFO_V0_TNT) nv04_calc_arb(&fifo_data, &sim_data); else nv10_calc_arb(&fifo_data, &sim_data); @@ -254,7 +254,7 @@ nouveau_calc_arb(struct drm_device *dev, int vclk, int bpp, int *burst, int *lwm { struct nouveau_drm *drm = nouveau_drm(dev); - if (nv_device(drm->device)->card_type < NV_20) + if (drm->device.info.family < NV_DEVICE_INFO_V0_KELVIN) nv04_update_arb(dev, vclk, bpp, burst, lwm); else if ((dev->pdev->device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ || (dev->pdev->device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) { diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 41be3424c906..fca6a1f9c20c 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -111,8 +111,8 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod { struct drm_device *dev = crtc->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_bios *bios = nouveau_bios(drm->device); - struct nouveau_clock *clk = nouveau_clock(drm->device); + struct nouveau_bios *bios = nvkm_bios(&drm->device); + struct nouveau_clock *clk = nvkm_clock(&drm->device); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv04_mode_state *state = &nv04_display(dev)->mode_reg; struct nv04_crtc_reg *regp = &state->crtc_reg[nv_crtc->index]; @@ -136,7 +136,7 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod * has yet been observed in allowing the use a single stage pll on all * nv43 however. the behaviour of single stage use is untested on nv40 */ - if (nv_device(drm->device)->chipset > 0x40 && dot_clock <= (pll_lim.vco1.max_freq / 2)) + if (drm->device.info.chipset > 0x40 && dot_clock <= (pll_lim.vco1.max_freq / 2)) memset(&pll_lim.vco2, 0, sizeof(pll_lim.vco2)); @@ -146,10 +146,10 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod state->pllsel &= PLLSEL_VPLL1_MASK | PLLSEL_VPLL2_MASK | PLLSEL_TV_MASK; /* The blob uses this always, so let's do the same */ - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_USE_VPLL2_TRUE; /* again nv40 and some nv43 act more like nv3x as described above */ - if (nv_device(drm->device)->chipset < 0x41) + if (drm->device.info.chipset < 0x41) state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_MPLL | NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_NVPLL; state->pllsel |= nv_crtc->index ? PLLSEL_VPLL2_MASK : PLLSEL_VPLL1_MASK; @@ -275,7 +275,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) horizEnd = horizTotal - 2; horizBlankEnd = horizTotal + 4; #if 0 - if (dev->overlayAdaptor && nv_device(drm->device)->card_type >= NV_10) + if (dev->overlayAdaptor && drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) /* This reportedly works around some video overlay bandwidth problems */ horizTotal += 2; #endif @@ -509,7 +509,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) regp->cursor_cfg = NV_PCRTC_CURSOR_CONFIG_CUR_LINES_64 | NV_PCRTC_CURSOR_CONFIG_CUR_PIXELS_64 | NV_PCRTC_CURSOR_CONFIG_ADDRESS_SPACE_PNVM; - if (nv_device(drm->device)->chipset >= 0x11) + if (drm->device.info.chipset >= 0x11) regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_CUR_BPP_32; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_DOUBLE_SCAN_ENABLE; @@ -550,26 +550,26 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) * 1 << 30 on 0x60.830), for no apparent reason */ regp->CRTC[NV_CIO_CRE_59] = off_chip_digital; - if (nv_device(drm->device)->card_type >= NV_30) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_RANKINE) regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1; regp->crtc_830 = mode->crtc_vdisplay - 3; regp->crtc_834 = mode->crtc_vdisplay - 1; - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) /* This is what the blob does */ regp->crtc_850 = NVReadCRTC(dev, 0, NV_PCRTC_850); - if (nv_device(drm->device)->card_type >= NV_30) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_RANKINE) regp->gpio_ext = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT); - if (nv_device(drm->device)->card_type >= NV_10) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) regp->crtc_cfg = NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC; else regp->crtc_cfg = NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC; /* Some misc regs */ - if (nv_device(drm->device)->card_type == NV_40) { + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) { regp->CRTC[NV_CIO_CRE_85] = 0xFF; regp->CRTC[NV_CIO_CRE_86] = 0x1; } @@ -581,7 +581,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) /* Generic PRAMDAC regs */ - if (nv_device(drm->device)->card_type >= NV_10) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) /* Only bit that bios and blob set. */ regp->nv10_cursync = (1 << 25); @@ -590,7 +590,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON; if (crtc->primary->fb->depth == 16) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; - if (nv_device(drm->device)->chipset >= 0x11) + if (drm->device.info.chipset >= 0x11) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG; regp->ramdac_630 = 0; /* turn off green mode (tv test pattern?) */ @@ -653,7 +653,7 @@ nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, nv_crtc_mode_set_vga(crtc, adjusted_mode); /* calculated in nv04_dfp_prepare, nv40 needs it written before calculating PLLs */ - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, nv04_display(dev)->mode_reg.sel_clk); nv_crtc_mode_set_regs(crtc, adjusted_mode); nv_crtc_calc_state_ext(crtc, mode, adjusted_mode->clock); @@ -714,7 +714,7 @@ static void nv_crtc_prepare(struct drm_crtc *crtc) /* Some more preparation. */ NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_CONFIG, NV_PCRTC_CONFIG_START_ADDRESS_NON_VGA); - if (nv_device(drm->device)->card_type == NV_40) { + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) { uint32_t reg900 = NVReadRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_900); NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_900, reg900 & ~0x10000); } @@ -888,7 +888,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FF_INDEX); crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FFLWM__INDEX); - if (nv_device(drm->device)->card_type >= NV_20) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_KELVIN) { regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8; crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47); } @@ -915,9 +915,9 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_device *dev = drm->dev; if (state == ENTER_ATOMIC_MODE_SET) - nouveau_fbcon_save_disable_accel(dev); + nouveau_fbcon_accel_save_disable(dev); else - nouveau_fbcon_restore_accel(dev); + nouveau_fbcon_accel_restore(dev); return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true); } @@ -969,7 +969,7 @@ static void nv11_cursor_upload(struct drm_device *dev, struct nouveau_bo *src, { struct nouveau_drm *drm = nouveau_drm(dev); - if (nv_device(drm->device)->chipset == 0x11) { + if (drm->device.info.chipset == 0x11) { pixel = ((pixel & 0x000000ff) << 24) | ((pixel & 0x0000ff00) << 8) | ((pixel & 0x00ff0000) >> 8) | @@ -1010,7 +1010,7 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, if (ret) goto out; - if (nv_device(drm->device)->chipset >= 0x11) + if (drm->device.info.chipset >= 0x11) nv11_cursor_upload(dev, cursor, nv_crtc->cursor.nvbo); else nv04_cursor_upload(dev, cursor, nv_crtc->cursor.nvbo); @@ -1127,7 +1127,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, NULL, &nv_crtc->cursor.nvbo); + 0, 0x0000, NULL, NULL, &nv_crtc->cursor.nvbo); if (!ret) { ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) { diff --git a/drivers/gpu/drm/nouveau/dispnv04/cursor.c b/drivers/gpu/drm/nouveau/dispnv04/cursor.c index a810303169de..4e61173c3353 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/cursor.c +++ b/drivers/gpu/drm/nouveau/dispnv04/cursor.c @@ -55,7 +55,7 @@ nv04_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset) crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_HCUR_ADDR2_INDEX); - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) nv_fix_nv40_hw_cursor(dev, nv_crtc->index); } diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index a96dda48718e..2d8056cde996 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -65,8 +65,8 @@ int nv04_dac_output_offset(struct drm_encoder *encoder) static int sample_load_twice(struct drm_device *dev, bool sense[2]) { - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_timer *ptimer = nouveau_timer(device); + struct nvif_device *device = &nouveau_drm(dev)->device; + struct nouveau_timer *ptimer = nvkm_timer(device); int i; for (i = 0; i < 2; i++) { @@ -95,15 +95,15 @@ static int sample_load_twice(struct drm_device *dev, bool sense[2]) udelay(100); /* when level triggers, sense is _LO_ */ - sense_a = nv_rd08(device, NV_PRMCIO_INP0) & 0x10; + sense_a = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10; /* take another reading until it agrees with sense_a... */ do { udelay(100); - sense_b = nv_rd08(device, NV_PRMCIO_INP0) & 0x10; + sense_b = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10; if (sense_a != sense_b) { sense_b_prime = - nv_rd08(device, NV_PRMCIO_INP0) & 0x10; + nvif_rd08(device, NV_PRMCIO_INP0) & 0x10; if (sense_b == sense_b_prime) { /* ... unless two consecutive subsequent * samples agree; sense_a is replaced */ @@ -128,7 +128,7 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; struct nouveau_drm *drm = nouveau_drm(dev); uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode; uint8_t saved_palette0[3], saved_palette_mask; @@ -164,11 +164,11 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, saved_rpc1 = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX); NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1 & ~0xc0); - nv_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS, 0x0); + nvif_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS, 0x0); for (i = 0; i < 3; i++) - saved_palette0[i] = nv_rd08(device, NV_PRMDIO_PALETTE_DATA); - saved_palette_mask = nv_rd08(device, NV_PRMDIO_PIXEL_MASK); - nv_wr08(device, NV_PRMDIO_PIXEL_MASK, 0); + saved_palette0[i] = nvif_rd08(device, NV_PRMDIO_PALETTE_DATA); + saved_palette_mask = nvif_rd08(device, NV_PRMDIO_PIXEL_MASK); + nvif_wr08(device, NV_PRMDIO_PIXEL_MASK, 0); saved_rgen_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, @@ -181,11 +181,11 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, do { bool sense_pair[2]; - nv_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); - nv_wr08(device, NV_PRMDIO_PALETTE_DATA, 0); - nv_wr08(device, NV_PRMDIO_PALETTE_DATA, 0); + nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); + nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0); + nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0); /* testing blue won't find monochrome monitors. I don't care */ - nv_wr08(device, NV_PRMDIO_PALETTE_DATA, blue); + nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, blue); i = 0; /* take sample pairs until both samples in the pair agree */ @@ -208,11 +208,11 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, } while (++blue < 0x18 && sense); out: - nv_wr08(device, NV_PRMDIO_PIXEL_MASK, saved_palette_mask); + nvif_wr08(device, NV_PRMDIO_PIXEL_MASK, saved_palette_mask); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, saved_rgen_ctrl); - nv_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); + nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); for (i = 0; i < 3; i++) - nv_wr08(device, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]); + nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, saved_rtest_ctrl); NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi); NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1); @@ -231,8 +231,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_gpio *gpio = nouveau_gpio(device); + struct nvif_device *device = &nouveau_drm(dev)->device; + struct nouveau_gpio *gpio = nvkm_gpio(device); struct dcb_output *dcb = nouveau_encoder(encoder)->dcb; uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, @@ -256,12 +256,12 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF); - saved_powerctrl_2 = nv_rd32(device, NV_PBUS_POWERCTRL_2); + saved_powerctrl_2 = nvif_rd32(device, NV_PBUS_POWERCTRL_2); - nv_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2 & 0xd7ffffff); + nvif_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2 & 0xd7ffffff); if (regoffset == 0x68) { - saved_powerctrl_4 = nv_rd32(device, NV_PBUS_POWERCTRL_4); - nv_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); + saved_powerctrl_4 = nvif_rd32(device, NV_PBUS_POWERCTRL_4); + nvif_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); } if (gpio) { @@ -283,7 +283,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ routput = (saved_routput & 0xfffffece) | head << 8; - if (nv_device(drm->device)->card_type >= NV_40) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CURIE) { if (dcb->type == DCB_OUTPUT_TV) routput |= 0x1a << 16; else @@ -316,8 +316,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, saved_routput); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl); if (regoffset == 0x68) - nv_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); - nv_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); + nvif_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); + nvif_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); if (gpio) { gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, saved_gpio1); @@ -398,7 +398,7 @@ static void nv04_dac_mode_set(struct drm_encoder *encoder, } /* This could use refinement for flatpanels, but it should work this way */ - if (nv_device(drm->device)->chipset < 0x44) + if (drm->device.info.chipset < 0x44) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000); else NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index e57babb206d3..42a5435259f7 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -281,7 +281,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; @@ -335,7 +335,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, regp->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_MODE_NATIVE; else /* gpu needs to scale */ regp->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_MODE_SCALE; - if (nv_rd32(device, NV_PEXTDEV_BOOT_0) & NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT) + if (nvif_rd32(device, NV_PEXTDEV_BOOT_0) & NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT) regp->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12; if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP && output_mode->clock > 165000) @@ -416,7 +416,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, if ((nv_connector->dithering_mode == DITHERING_MODE_ON) || (nv_connector->dithering_mode == DITHERING_MODE_AUTO && encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) { - if (nv_device(drm->device)->chipset == 0x11) + if (drm->device.info.chipset == 0x11) regp->dither = savep->dither | 0x00010000; else { int i; @@ -427,7 +427,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, } } } else { - if (nv_device(drm->device)->chipset != 0x11) { + if (drm->device.info.chipset != 0x11) { /* reset them */ int i; for (i = 0; i < 3; i++) { @@ -463,7 +463,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL); /* This could use refinement for flatpanels, but it should work this way */ - if (nv_device(drm->device)->chipset < 0x44) + if (drm->device.info.chipset < 0x44) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000); else NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); @@ -485,7 +485,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) { #ifdef __powerpc__ struct drm_device *dev = encoder->dev; - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; /* BIOS scripts usually take care of the backlight, thanks * Apple for your consistency. @@ -623,7 +623,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct dcb_output *dcb = nouveau_encoder(encoder)->dcb; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_i2c *i2c = nouveau_i2c(drm->device); + struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); struct nouveau_i2c_port *port = i2c->find(i2c, 2); struct nouveau_i2c_board_info info[] = { { diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index 4342fdaee707..3d0afa1c6cff 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -22,9 +22,6 @@ * Author: Ben Skeggs */ -#include <core/object.h> -#include <core/class.h> - #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> @@ -34,8 +31,6 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" -#include <subdev/i2c.h> - int nv04_display_early_init(struct drm_device *dev) { @@ -58,7 +53,7 @@ int nv04_display_create(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_i2c *i2c = nouveau_i2c(drm->device); + struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); struct dcb_table *dcb = &drm->vbios.dcb; struct drm_connector *connector, *ct; struct drm_encoder *encoder; @@ -70,6 +65,8 @@ nv04_display_create(struct drm_device *dev) if (!disp) return -ENOMEM; + nvif_object_map(nvif_object(&drm->device)); + nouveau_display(dev)->priv = disp; nouveau_display(dev)->dtor = nv04_display_destroy; nouveau_display(dev)->init = nv04_display_init; @@ -144,6 +141,7 @@ void nv04_display_destroy(struct drm_device *dev) { struct nv04_display *disp = nv04_display(dev); + struct nouveau_drm *drm = nouveau_drm(dev); struct drm_encoder *encoder; struct drm_crtc *crtc; @@ -170,6 +168,8 @@ nv04_display_destroy(struct drm_device *dev) nouveau_display(dev)->priv = NULL; kfree(disp); + + nvif_object_unmap(nvif_object(&drm->device)); } int diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h index 4245fc3dab70..17b899d9aba3 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h @@ -131,7 +131,7 @@ nv_two_heads(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); const int impl = dev->pdev->device & 0x0ff0; - if (nv_device(drm->device)->card_type >= NV_10 && impl != 0x0100 && + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS && impl != 0x0100 && impl != 0x0150 && impl != 0x01a0 && impl != 0x0200) return true; @@ -150,7 +150,7 @@ nv_two_reg_pll(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); const int impl = dev->pdev->device & 0x0ff0; - if (impl == 0x0310 || impl == 0x0340 || nv_device(drm->device)->card_type >= NV_40) + if (impl == 0x0310 || impl == 0x0340 || drm->device.info.family >= NV_DEVICE_INFO_V0_CURIE) return true; return false; } @@ -171,8 +171,8 @@ static inline void nouveau_bios_run_init_table(struct drm_device *dev, u16 table, struct dcb_output *outp, int crtc) { - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_bios *bios = nouveau_bios(device); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_bios *bios = nvkm_bios(&drm->device); struct nvbios_init init = { .subdev = nv_subdev(bios), .bios = bios, diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c index aca76af115b3..3d4c19300768 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.c +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c @@ -27,9 +27,6 @@ #include "hw.h" #include <subdev/bios/pll.h> -#include <subdev/fb.h> -#include <subdev/clock.h> -#include <subdev/timer.h> #define CHIPSET_NFORCE 0x01a0 #define CHIPSET_NFORCE2 0x01f0 @@ -92,7 +89,7 @@ NVSetOwner(struct drm_device *dev, int owner) if (owner == 1) owner *= 3; - if (nv_device(drm->device)->chipset == 0x11) { + if (drm->device.info.chipset == 0x11) { /* This might seem stupid, but the blob does it and * omitting it often locks the system up. */ @@ -103,7 +100,7 @@ NVSetOwner(struct drm_device *dev, int owner) /* CR44 is always changed on CRTC0 */ NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_44, owner); - if (nv_device(drm->device)->chipset == 0x11) { /* set me harder */ + if (drm->device.info.chipset == 0x11) { /* set me harder */ NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_2E, owner); NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_2E, owner); } @@ -152,7 +149,7 @@ nouveau_hw_decode_pll(struct drm_device *dev, uint32_t reg1, uint32_t pll1, pllvals->NM1 = pll1 & 0xffff; if (nv_two_reg_pll(dev) && pll2 & NV31_RAMDAC_ENABLE_VCO2) pllvals->NM2 = pll2 & 0xffff; - else if (nv_device(drm->device)->chipset == 0x30 || nv_device(drm->device)->chipset == 0x35) { + else if (drm->device.info.chipset == 0x30 || drm->device.info.chipset == 0x35) { pllvals->M1 &= 0xf; /* only 4 bits */ if (pll1 & NV30_RAMDAC_ENABLE_VCO2) { pllvals->M2 = (pll1 >> 4) & 0x7; @@ -168,8 +165,8 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum nvbios_pll_type plltype, struct nouveau_pll_vals *pllvals) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_bios *bios = nouveau_bios(device); + struct nvif_device *device = &drm->device; + struct nouveau_bios *bios = nvkm_bios(device); uint32_t reg1, pll1, pll2 = 0; struct nvbios_pll pll_lim; int ret; @@ -178,16 +175,16 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum nvbios_pll_type plltype, if (ret || !(reg1 = pll_lim.reg)) return -ENOENT; - pll1 = nv_rd32(device, reg1); + pll1 = nvif_rd32(device, reg1); if (reg1 <= 0x405c) - pll2 = nv_rd32(device, reg1 + 4); + pll2 = nvif_rd32(device, reg1 + 4); else if (nv_two_reg_pll(dev)) { uint32_t reg2 = reg1 + (reg1 == NV_RAMDAC_VPLL2 ? 0x5c : 0x70); - pll2 = nv_rd32(device, reg2); + pll2 = nvif_rd32(device, reg2); } - if (nv_device(drm->device)->card_type == 0x40 && reg1 >= NV_PRAMDAC_VPLL_COEFF) { + if (drm->device.info.family == NV_DEVICE_INFO_V0_CELSIUS && reg1 >= NV_PRAMDAC_VPLL_COEFF) { uint32_t ramdac580 = NVReadRAMDAC(dev, 0, NV_PRAMDAC_580); /* check whether vpll has been forced into single stage mode */ @@ -255,9 +252,9 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head) */ struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_clock *clk = nouveau_clock(device); - struct nouveau_bios *bios = nouveau_bios(device); + struct nvif_device *device = &drm->device; + struct nouveau_clock *clk = nvkm_clock(device); + struct nouveau_bios *bios = nvkm_bios(device); struct nvbios_pll pll_lim; struct nouveau_pll_vals pv; enum nvbios_pll_type pll = head ? PLL_VPLL1 : PLL_VPLL0; @@ -394,21 +391,21 @@ nv_save_state_ramdac(struct drm_device *dev, int head, struct nv04_crtc_reg *regp = &state->crtc_reg[head]; int i; - if (nv_device(drm->device)->card_type >= NV_10) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) regp->nv10_cursync = NVReadRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC); nouveau_hw_get_pllvals(dev, head ? PLL_VPLL1 : PLL_VPLL0, ®p->pllvals); state->pllsel = NVReadRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT); if (nv_two_heads(dev)) state->sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK); - if (nv_device(drm->device)->chipset == 0x11) + if (drm->device.info.chipset == 0x11) regp->dither = NVReadRAMDAC(dev, head, NV_RAMDAC_DITHER_NV11); regp->ramdac_gen_ctrl = NVReadRAMDAC(dev, head, NV_PRAMDAC_GENERAL_CONTROL); if (nv_gf4_disp_arch(dev)) regp->ramdac_630 = NVReadRAMDAC(dev, head, NV_PRAMDAC_630); - if (nv_device(drm->device)->chipset >= 0x30) + if (drm->device.info.chipset >= 0x30) regp->ramdac_634 = NVReadRAMDAC(dev, head, NV_PRAMDAC_634); regp->tv_setup = NVReadRAMDAC(dev, head, NV_PRAMDAC_TV_SETUP); @@ -450,7 +447,7 @@ nv_save_state_ramdac(struct drm_device *dev, int head, if (nv_gf4_disp_arch(dev)) regp->ramdac_8c0 = NVReadRAMDAC(dev, head, NV_PRAMDAC_8C0); - if (nv_device(drm->device)->card_type == NV_40) { + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) { regp->ramdac_a20 = NVReadRAMDAC(dev, head, NV_PRAMDAC_A20); regp->ramdac_a24 = NVReadRAMDAC(dev, head, NV_PRAMDAC_A24); regp->ramdac_a34 = NVReadRAMDAC(dev, head, NV_PRAMDAC_A34); @@ -466,26 +463,26 @@ nv_load_state_ramdac(struct drm_device *dev, int head, struct nv04_mode_state *state) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_clock *clk = nouveau_clock(drm->device); + struct nouveau_clock *clk = nvkm_clock(&drm->device); struct nv04_crtc_reg *regp = &state->crtc_reg[head]; uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF; int i; - if (nv_device(drm->device)->card_type >= NV_10) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) NVWriteRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC, regp->nv10_cursync); clk->pll_prog(clk, pllreg, ®p->pllvals); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); if (nv_two_heads(dev)) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, state->sel_clk); - if (nv_device(drm->device)->chipset == 0x11) + if (drm->device.info.chipset == 0x11) NVWriteRAMDAC(dev, head, NV_RAMDAC_DITHER_NV11, regp->dither); NVWriteRAMDAC(dev, head, NV_PRAMDAC_GENERAL_CONTROL, regp->ramdac_gen_ctrl); if (nv_gf4_disp_arch(dev)) NVWriteRAMDAC(dev, head, NV_PRAMDAC_630, regp->ramdac_630); - if (nv_device(drm->device)->chipset >= 0x30) + if (drm->device.info.chipset >= 0x30) NVWriteRAMDAC(dev, head, NV_PRAMDAC_634, regp->ramdac_634); NVWriteRAMDAC(dev, head, NV_PRAMDAC_TV_SETUP, regp->tv_setup); @@ -522,7 +519,7 @@ nv_load_state_ramdac(struct drm_device *dev, int head, if (nv_gf4_disp_arch(dev)) NVWriteRAMDAC(dev, head, NV_PRAMDAC_8C0, regp->ramdac_8c0); - if (nv_device(drm->device)->card_type == NV_40) { + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) { NVWriteRAMDAC(dev, head, NV_PRAMDAC_A20, regp->ramdac_a20); NVWriteRAMDAC(dev, head, NV_PRAMDAC_A24, regp->ramdac_a24); NVWriteRAMDAC(dev, head, NV_PRAMDAC_A34, regp->ramdac_a34); @@ -603,10 +600,10 @@ nv_save_state_ext(struct drm_device *dev, int head, rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_21); - if (nv_device(drm->device)->card_type >= NV_20) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_KELVIN) rd_cio_state(dev, head, regp, NV_CIO_CRE_47); - if (nv_device(drm->device)->card_type >= NV_30) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_RANKINE) rd_cio_state(dev, head, regp, 0x9f); rd_cio_state(dev, head, regp, NV_CIO_CRE_49); @@ -615,14 +612,14 @@ nv_save_state_ext(struct drm_device *dev, int head, rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR2_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_ILACE__INDEX); - if (nv_device(drm->device)->card_type >= NV_10) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) { regp->crtc_830 = NVReadCRTC(dev, head, NV_PCRTC_830); regp->crtc_834 = NVReadCRTC(dev, head, NV_PCRTC_834); - if (nv_device(drm->device)->card_type >= NV_30) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_RANKINE) regp->gpio_ext = NVReadCRTC(dev, head, NV_PCRTC_GPIO_EXT); - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) regp->crtc_850 = NVReadCRTC(dev, head, NV_PCRTC_850); if (nv_two_heads(dev)) @@ -634,7 +631,7 @@ nv_save_state_ext(struct drm_device *dev, int head, rd_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH3__INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH4__INDEX); - if (nv_device(drm->device)->card_type >= NV_10) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) { rd_cio_state(dev, head, regp, NV_CIO_CRE_EBR_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_CSB); rd_cio_state(dev, head, regp, NV_CIO_CRE_4B); @@ -663,14 +660,13 @@ nv_load_state_ext(struct drm_device *dev, int head, struct nv04_mode_state *state) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_timer *ptimer = nouveau_timer(device); - struct nouveau_fb *pfb = nouveau_fb(device); + struct nvif_device *device = &drm->device; + struct nouveau_timer *ptimer = nvkm_timer(device); struct nv04_crtc_reg *regp = &state->crtc_reg[head]; uint32_t reg900; int i; - if (nv_device(drm->device)->card_type >= NV_10) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) { if (nv_two_heads(dev)) /* setting ENGINE_CTRL (EC) *must* come before * CIO_CRE_LCD, as writing CRE_LCD sets bits 16 & 17 in @@ -678,24 +674,24 @@ nv_load_state_ext(struct drm_device *dev, int head, */ NVWriteCRTC(dev, head, NV_PCRTC_ENGINE_CTRL, regp->crtc_eng_ctrl); - nv_wr32(device, NV_PVIDEO_STOP, 1); - nv_wr32(device, NV_PVIDEO_INTR_EN, 0); - nv_wr32(device, NV_PVIDEO_OFFSET_BUFF(0), 0); - nv_wr32(device, NV_PVIDEO_OFFSET_BUFF(1), 0); - nv_wr32(device, NV_PVIDEO_LIMIT(0), pfb->ram->size - 1); - nv_wr32(device, NV_PVIDEO_LIMIT(1), pfb->ram->size - 1); - nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), pfb->ram->size - 1); - nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), pfb->ram->size - 1); - nv_wr32(device, NV_PBUS_POWERCTRL_2, 0); + nvif_wr32(device, NV_PVIDEO_STOP, 1); + nvif_wr32(device, NV_PVIDEO_INTR_EN, 0); + nvif_wr32(device, NV_PVIDEO_OFFSET_BUFF(0), 0); + nvif_wr32(device, NV_PVIDEO_OFFSET_BUFF(1), 0); + nvif_wr32(device, NV_PVIDEO_LIMIT(0), device->info.ram_size - 1); + nvif_wr32(device, NV_PVIDEO_LIMIT(1), device->info.ram_size - 1); + nvif_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), device->info.ram_size - 1); + nvif_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), device->info.ram_size - 1); + nvif_wr32(device, NV_PBUS_POWERCTRL_2, 0); NVWriteCRTC(dev, head, NV_PCRTC_CURSOR_CONFIG, regp->cursor_cfg); NVWriteCRTC(dev, head, NV_PCRTC_830, regp->crtc_830); NVWriteCRTC(dev, head, NV_PCRTC_834, regp->crtc_834); - if (nv_device(drm->device)->card_type >= NV_30) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_RANKINE) NVWriteCRTC(dev, head, NV_PCRTC_GPIO_EXT, regp->gpio_ext); - if (nv_device(drm->device)->card_type == NV_40) { + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) { NVWriteCRTC(dev, head, NV_PCRTC_850, regp->crtc_850); reg900 = NVReadRAMDAC(dev, head, NV_PRAMDAC_900); @@ -718,23 +714,23 @@ nv_load_state_ext(struct drm_device *dev, int head, wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); - if (nv_device(drm->device)->card_type >= NV_20) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_KELVIN) wr_cio_state(dev, head, regp, NV_CIO_CRE_47); - if (nv_device(drm->device)->card_type >= NV_30) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_RANKINE) wr_cio_state(dev, head, regp, 0x9f); wr_cio_state(dev, head, regp, NV_CIO_CRE_49); wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR2_INDEX); - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) nv_fix_nv40_hw_cursor(dev, head); wr_cio_state(dev, head, regp, NV_CIO_CRE_ILACE__INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH3__INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_SCRATCH4__INDEX); - if (nv_device(drm->device)->card_type >= NV_10) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) { wr_cio_state(dev, head, regp, NV_CIO_CRE_EBR_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_CSB); wr_cio_state(dev, head, regp, NV_CIO_CRE_4B); @@ -742,7 +738,7 @@ nv_load_state_ext(struct drm_device *dev, int head, } /* NV11 and NV20 stop at 0x52. */ if (nv_gf4_disp_arch(dev)) { - if (nv_device(drm->device)->card_type < NV_20) { + if (drm->device.info.family < NV_DEVICE_INFO_V0_KELVIN) { /* Not waiting for vertical retrace before modifying CRE_53/CRE_54 causes lockups. */ nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); @@ -769,15 +765,15 @@ static void nv_save_state_palette(struct drm_device *dev, int head, struct nv04_mode_state *state) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; int head_offset = head * NV_PRMDIO_SIZE, i; - nv_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset, + nvif_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset, NV_PRMDIO_PIXEL_MASK_MASK); - nv_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS + head_offset, 0x0); + nvif_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS + head_offset, 0x0); for (i = 0; i < 768; i++) { - state->crtc_reg[head].DAC[i] = nv_rd08(device, + state->crtc_reg[head].DAC[i] = nvif_rd08(device, NV_PRMDIO_PALETTE_DATA + head_offset); } @@ -788,15 +784,15 @@ void nouveau_hw_load_state_palette(struct drm_device *dev, int head, struct nv04_mode_state *state) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; int head_offset = head * NV_PRMDIO_SIZE, i; - nv_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset, + nvif_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset, NV_PRMDIO_PIXEL_MASK_MASK); - nv_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS + head_offset, 0x0); + nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS + head_offset, 0x0); for (i = 0; i < 768; i++) { - nv_wr08(device, NV_PRMDIO_PALETTE_DATA + head_offset, + nvif_wr08(device, NV_PRMDIO_PALETTE_DATA + head_offset, state->crtc_reg[head].DAC[i]); } @@ -808,7 +804,7 @@ void nouveau_hw_save_state(struct drm_device *dev, int head, { struct nouveau_drm *drm = nouveau_drm(dev); - if (nv_device(drm->device)->chipset == 0x11) + if (drm->device.info.chipset == 0x11) /* NB: no attempt is made to restore the bad pll later on */ nouveau_hw_fix_bad_vpll(dev, head); nv_save_state_ramdac(dev, head, state); diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.h b/drivers/gpu/drm/nouveau/dispnv04/hw.h index eeb70d912d99..7f53c571f31f 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.h +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.h @@ -60,41 +60,41 @@ extern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp, static inline uint32_t NVReadCRTC(struct drm_device *dev, int head, uint32_t reg) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; uint32_t val; if (head) reg += NV_PCRTC0_SIZE; - val = nv_rd32(device, reg); + val = nvif_rd32(device, reg); return val; } static inline void NVWriteCRTC(struct drm_device *dev, int head, uint32_t reg, uint32_t val) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; if (head) reg += NV_PCRTC0_SIZE; - nv_wr32(device, reg, val); + nvif_wr32(device, reg, val); } static inline uint32_t NVReadRAMDAC(struct drm_device *dev, int head, uint32_t reg) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; uint32_t val; if (head) reg += NV_PRAMDAC0_SIZE; - val = nv_rd32(device, reg); + val = nvif_rd32(device, reg); return val; } static inline void NVWriteRAMDAC(struct drm_device *dev, int head, uint32_t reg, uint32_t val) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; if (head) reg += NV_PRAMDAC0_SIZE; - nv_wr32(device, reg, val); + nvif_wr32(device, reg, val); } static inline uint8_t nv_read_tmds(struct drm_device *dev, @@ -120,18 +120,18 @@ static inline void nv_write_tmds(struct drm_device *dev, static inline void NVWriteVgaCrtc(struct drm_device *dev, int head, uint8_t index, uint8_t value) { - struct nouveau_device *device = nouveau_dev(dev); - nv_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); - nv_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value); + struct nvif_device *device = &nouveau_drm(dev)->device; + nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); + nvif_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value); } static inline uint8_t NVReadVgaCrtc(struct drm_device *dev, int head, uint8_t index) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; uint8_t val; - nv_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); - val = nv_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE); + nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); + val = nvif_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE); return val; } @@ -165,74 +165,74 @@ static inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_ static inline uint8_t NVReadPRMVIO(struct drm_device *dev, int head, uint32_t reg) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; struct nouveau_drm *drm = nouveau_drm(dev); uint8_t val; /* Only NV4x have two pvio ranges; other twoHeads cards MUST call * NVSetOwner for the relevant head to be programmed */ - if (head && nv_device(drm->device)->card_type == NV_40) + if (head && drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) reg += NV_PRMVIO_SIZE; - val = nv_rd08(device, reg); + val = nvif_rd08(device, reg); return val; } static inline void NVWritePRMVIO(struct drm_device *dev, int head, uint32_t reg, uint8_t value) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; struct nouveau_drm *drm = nouveau_drm(dev); /* Only NV4x have two pvio ranges; other twoHeads cards MUST call * NVSetOwner for the relevant head to be programmed */ - if (head && nv_device(drm->device)->card_type == NV_40) + if (head && drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) reg += NV_PRMVIO_SIZE; - nv_wr08(device, reg, value); + nvif_wr08(device, reg, value); } static inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable) { - struct nouveau_device *device = nouveau_dev(dev); - nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); - nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20); + struct nvif_device *device = &nouveau_drm(dev)->device; + nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); + nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20); } static inline bool NVGetEnablePalette(struct drm_device *dev, int head) { - struct nouveau_device *device = nouveau_dev(dev); - nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); - return !(nv_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20); + struct nvif_device *device = &nouveau_drm(dev)->device; + nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); + return !(nvif_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20); } static inline void NVWriteVgaAttr(struct drm_device *dev, int head, uint8_t index, uint8_t value) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; if (NVGetEnablePalette(dev, head)) index &= ~0x20; else index |= 0x20; - nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); - nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index); - nv_wr08(device, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value); + nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); + nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index); + nvif_wr08(device, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value); } static inline uint8_t NVReadVgaAttr(struct drm_device *dev, int head, uint8_t index) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; uint8_t val; if (NVGetEnablePalette(dev, head)) index &= ~0x20; else index |= 0x20; - nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); - nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index); - val = nv_rd08(device, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE); + nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); + nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index); + val = nvif_rd08(device, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE); return val; } @@ -259,11 +259,11 @@ static inline void NVVgaProtect(struct drm_device *dev, int head, bool protect) static inline bool nv_heads_tied(struct drm_device *dev) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; struct nouveau_drm *drm = nouveau_drm(dev); - if (nv_device(drm->device)->chipset == 0x11) - return !!(nv_rd32(device, NV_PBUS_DEBUG_1) & (1 << 28)); + if (drm->device.info.chipset == 0x11) + return !!(nvif_rd32(device, NV_PBUS_DEBUG_1) & (1 << 28)); return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4; } @@ -318,7 +318,7 @@ NVLockVgaCrtcs(struct drm_device *dev, bool lock) NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX, lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE); /* NV11 has independently lockable extended crtcs, except when tied */ - if (nv_device(drm->device)->chipset == 0x11 && !nv_heads_tied(dev)) + if (drm->device.info.chipset == 0x11 && !nv_heads_tied(dev)) NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX, lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE); @@ -335,7 +335,7 @@ static inline int nv_cursor_width(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - return nv_device(drm->device)->card_type >= NV_10 ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE; + return drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE; } static inline void @@ -357,7 +357,7 @@ nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset) NVWriteCRTC(dev, head, NV_PCRTC_START, offset); - if (nv_device(drm->device)->card_type == NV_04) { + if (drm->device.info.family == NV_DEVICE_INFO_V0_TNT) { /* * Hilarious, the 24th bit doesn't want to stick to * PCRTC_START... @@ -382,7 +382,7 @@ nv_show_cursor(struct drm_device *dev, int head, bool show) *curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE); NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1); - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) nv_fix_nv40_hw_cursor(dev, head); } @@ -398,7 +398,7 @@ nv_pitch_align(struct drm_device *dev, uint32_t width, int bpp) bpp = 8; /* Alignment requirements taken from the Haiku driver */ - if (nv_device(drm->device)->card_type == NV_04) + if (drm->device.info.family == NV_DEVICE_INFO_V0_TNT) mask = 128 / bpp - 1; else mask = 512 / bpp - 1; diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index ab03f7719d2d..1e9056a8df94 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -96,8 +96,9 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { - struct nouveau_device *dev = nouveau_dev(plane->dev); - struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; + struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nouveau_plane *nv_plane = + container_of(plane, struct nouveau_plane, base); struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_bo *cur = nv_plane->cur; @@ -117,7 +118,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (format > 0xffff) return -ERANGE; - if (dev->chipset >= 0x30) { + if (dev->info.chipset >= 0x30) { if (crtc_w < (src_w >> 1) || crtc_h < (src_h >> 1)) return -ERANGE; } else { @@ -131,17 +132,17 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, nv_plane->cur = nv_fb->nvbo; - nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY); - nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0); + nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY); + nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0); - nv_wr32(dev, NV_PVIDEO_BASE(flip), 0); - nv_wr32(dev, NV_PVIDEO_OFFSET_BUFF(flip), nv_fb->nvbo->bo.offset); - nv_wr32(dev, NV_PVIDEO_SIZE_IN(flip), src_h << 16 | src_w); - nv_wr32(dev, NV_PVIDEO_POINT_IN(flip), src_y << 16 | src_x); - nv_wr32(dev, NV_PVIDEO_DS_DX(flip), (src_w << 20) / crtc_w); - nv_wr32(dev, NV_PVIDEO_DT_DY(flip), (src_h << 20) / crtc_h); - nv_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x); - nv_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w); + nvif_wr32(dev, NV_PVIDEO_BASE(flip), 0); + nvif_wr32(dev, NV_PVIDEO_OFFSET_BUFF(flip), nv_fb->nvbo->bo.offset); + nvif_wr32(dev, NV_PVIDEO_SIZE_IN(flip), src_h << 16 | src_w); + nvif_wr32(dev, NV_PVIDEO_POINT_IN(flip), src_y << 16 | src_x); + nvif_wr32(dev, NV_PVIDEO_DS_DX(flip), (src_w << 20) / crtc_w); + nvif_wr32(dev, NV_PVIDEO_DT_DY(flip), (src_h << 20) / crtc_h); + nvif_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x); + nvif_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w); if (fb->pixel_format != DRM_FORMAT_UYVY) format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8; @@ -153,14 +154,14 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY; if (fb->pixel_format == DRM_FORMAT_NV12) { - nv_wr32(dev, NV_PVIDEO_UVPLANE_BASE(flip), 0); - nv_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip), + nvif_wr32(dev, NV_PVIDEO_UVPLANE_BASE(flip), 0); + nvif_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip), nv_fb->nvbo->bo.offset + fb->offsets[1]); } - nv_wr32(dev, NV_PVIDEO_FORMAT(flip), format); - nv_wr32(dev, NV_PVIDEO_STOP, 0); + nvif_wr32(dev, NV_PVIDEO_FORMAT(flip), format); + nvif_wr32(dev, NV_PVIDEO_STOP, 0); /* TODO: wait for vblank? */ - nv_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1); + nvif_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1); nv_plane->flip = !flip; if (cur) @@ -172,10 +173,11 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, static int nv10_disable_plane(struct drm_plane *plane) { - struct nouveau_device *dev = nouveau_dev(plane->dev); - struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; + struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nouveau_plane *nv_plane = + container_of(plane, struct nouveau_plane, base); - nv_wr32(dev, NV_PVIDEO_STOP, 1); + nvif_wr32(dev, NV_PVIDEO_STOP, 1); if (nv_plane->cur) { nouveau_bo_unpin(nv_plane->cur); nv_plane->cur = NULL; @@ -195,24 +197,24 @@ nv_destroy_plane(struct drm_plane *plane) static void nv10_set_params(struct nouveau_plane *plane) { - struct nouveau_device *dev = nouveau_dev(plane->base.dev); + struct nvif_device *dev = &nouveau_drm(plane->base.dev)->device; u32 luma = (plane->brightness - 512) << 16 | plane->contrast; u32 chroma = ((sin_mul(plane->hue, plane->saturation) & 0xffff) << 16) | (cos_mul(plane->hue, plane->saturation) & 0xffff); u32 format = 0; - nv_wr32(dev, NV_PVIDEO_LUMINANCE(0), luma); - nv_wr32(dev, NV_PVIDEO_LUMINANCE(1), luma); - nv_wr32(dev, NV_PVIDEO_CHROMINANCE(0), chroma); - nv_wr32(dev, NV_PVIDEO_CHROMINANCE(1), chroma); - nv_wr32(dev, NV_PVIDEO_COLOR_KEY, plane->colorkey & 0xffffff); + nvif_wr32(dev, NV_PVIDEO_LUMINANCE(0), luma); + nvif_wr32(dev, NV_PVIDEO_LUMINANCE(1), luma); + nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(0), chroma); + nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(1), chroma); + nvif_wr32(dev, NV_PVIDEO_COLOR_KEY, plane->colorkey & 0xffffff); if (plane->cur) { if (plane->iturbt_709) format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709; if (plane->colorkey & (1 << 24)) format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY; - nv_mask(dev, NV_PVIDEO_FORMAT(plane->flip), + nvif_mask(dev, NV_PVIDEO_FORMAT(plane->flip), NV_PVIDEO_FORMAT_MATRIX_ITURBT709 | NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY, format); @@ -224,7 +226,8 @@ nv_set_property(struct drm_plane *plane, struct drm_property *property, uint64_t value) { - struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; + struct nouveau_plane *nv_plane = + container_of(plane, struct nouveau_plane, base); if (property == nv_plane->props.colorkey) nv_plane->colorkey = value; @@ -256,7 +259,7 @@ static const struct drm_plane_funcs nv10_plane_funcs = { static void nv10_overlay_init(struct drm_device *device) { - struct nouveau_device *dev = nouveau_dev(device); + struct nouveau_drm *drm = nouveau_drm(device); struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); int num_formats = ARRAY_SIZE(formats); int ret; @@ -264,7 +267,7 @@ nv10_overlay_init(struct drm_device *device) if (!plane) return; - switch (dev->chipset) { + switch (drm->device.info.chipset) { case 0x10: case 0x11: case 0x15: @@ -333,7 +336,7 @@ cleanup: drm_plane_cleanup(&plane->base); err: kfree(plane); - nv_error(dev, "Failed to create plane\n"); + NV_ERROR(drm, "Failed to create plane\n"); } static int @@ -343,8 +346,9 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { - struct nouveau_device *dev = nouveau_dev(plane->dev); - struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; + struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nouveau_plane *nv_plane = + container_of(plane, struct nouveau_plane, base); struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); struct nouveau_bo *cur = nv_plane->cur; uint32_t overlay = 1; @@ -375,43 +379,43 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, nv_plane->cur = nv_fb->nvbo; - nv_wr32(dev, NV_PVIDEO_OE_STATE, 0); - nv_wr32(dev, NV_PVIDEO_SU_STATE, 0); - nv_wr32(dev, NV_PVIDEO_RM_STATE, 0); + nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0); + nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0); + nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0); for (i = 0; i < 2; i++) { - nv_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i, + nvif_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i, nv_fb->nvbo->bo.offset); - nv_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, pitch); - nv_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0); + nvif_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, pitch); + nvif_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0); } - nv_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x); - nv_wr32(dev, NV_PVIDEO_WINDOW_SIZE, crtc_h << 16 | crtc_w); - nv_wr32(dev, NV_PVIDEO_STEP_SIZE, + nvif_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x); + nvif_wr32(dev, NV_PVIDEO_WINDOW_SIZE, crtc_h << 16 | crtc_w); + nvif_wr32(dev, NV_PVIDEO_STEP_SIZE, (uint32_t)(((src_h - 1) << 11) / (crtc_h - 1)) << 16 | (uint32_t)(((src_w - 1) << 11) / (crtc_w - 1))); /* It should be possible to convert hue/contrast to this */ - nv_wr32(dev, NV_PVIDEO_RED_CSC_OFFSET, 0x69 - brightness); - nv_wr32(dev, NV_PVIDEO_GREEN_CSC_OFFSET, 0x3e + brightness); - nv_wr32(dev, NV_PVIDEO_BLUE_CSC_OFFSET, 0x89 - brightness); - nv_wr32(dev, NV_PVIDEO_CSC_ADJUST, 0); + nvif_wr32(dev, NV_PVIDEO_RED_CSC_OFFSET, 0x69 - brightness); + nvif_wr32(dev, NV_PVIDEO_GREEN_CSC_OFFSET, 0x3e + brightness); + nvif_wr32(dev, NV_PVIDEO_BLUE_CSC_OFFSET, 0x89 - brightness); + nvif_wr32(dev, NV_PVIDEO_CSC_ADJUST, 0); - nv_wr32(dev, NV_PVIDEO_CONTROL_Y, 0x001); /* (BLUR_ON, LINE_HALF) */ - nv_wr32(dev, NV_PVIDEO_CONTROL_X, 0x111); /* (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */ + nvif_wr32(dev, NV_PVIDEO_CONTROL_Y, 0x001); /* (BLUR_ON, LINE_HALF) */ + nvif_wr32(dev, NV_PVIDEO_CONTROL_X, 0x111); /* (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */ - nv_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03); - nv_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38); + nvif_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03); + nvif_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38); - nv_wr32(dev, NV_PVIDEO_KEY, nv_plane->colorkey); + nvif_wr32(dev, NV_PVIDEO_KEY, nv_plane->colorkey); if (nv_plane->colorkey & (1 << 24)) overlay |= 0x10; if (fb->pixel_format == DRM_FORMAT_YUYV) overlay |= 0x100; - nv_wr32(dev, NV_PVIDEO_OVERLAY, overlay); + nvif_wr32(dev, NV_PVIDEO_OVERLAY, overlay); - nv_wr32(dev, NV_PVIDEO_SU_STATE, nv_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16)); + nvif_wr32(dev, NV_PVIDEO_SU_STATE, nvif_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16)); if (cur) nouveau_bo_unpin(cur); @@ -422,13 +426,14 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, static int nv04_disable_plane(struct drm_plane *plane) { - struct nouveau_device *dev = nouveau_dev(plane->dev); - struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; - - nv_mask(dev, NV_PVIDEO_OVERLAY, 1, 0); - nv_wr32(dev, NV_PVIDEO_OE_STATE, 0); - nv_wr32(dev, NV_PVIDEO_SU_STATE, 0); - nv_wr32(dev, NV_PVIDEO_RM_STATE, 0); + struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nouveau_plane *nv_plane = + container_of(plane, struct nouveau_plane, base); + + nvif_mask(dev, NV_PVIDEO_OVERLAY, 1, 0); + nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0); + nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0); + nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0); if (nv_plane->cur) { nouveau_bo_unpin(nv_plane->cur); nv_plane->cur = NULL; @@ -447,7 +452,7 @@ static const struct drm_plane_funcs nv04_plane_funcs = { static void nv04_overlay_init(struct drm_device *device) { - struct nouveau_device *dev = nouveau_dev(device); + struct nouveau_drm *drm = nouveau_drm(device); struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); int ret; @@ -483,15 +488,15 @@ cleanup: drm_plane_cleanup(&plane->base); err: kfree(plane); - nv_error(dev, "Failed to create plane\n"); + NV_ERROR(drm, "Failed to create plane\n"); } void nouveau_overlay_init(struct drm_device *device) { - struct nouveau_device *dev = nouveau_dev(device); - if (dev->chipset < 0x10) + struct nvif_device *dev = &nouveau_drm(device)->device; + if (dev->info.chipset < 0x10) nv04_overlay_init(device); - else if (dev->chipset <= 0x40) + else if (dev->info.chipset <= 0x40) nv10_overlay_init(device); } diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c index 8667620b703a..8061d8d0ce79 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c @@ -35,8 +35,6 @@ #include <drm/i2c/ch7006.h> -#include <subdev/i2c.h> - static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = { { { @@ -56,7 +54,7 @@ static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = { int nv04_tv_identify(struct drm_device *dev, int i2c_index) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_i2c *i2c = nouveau_i2c(drm->device); + struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); return i2c->identify(i2c, i2c_index, "TV encoder", nv04_tv_encoder_info, NULL, NULL); @@ -206,7 +204,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) struct drm_encoder *encoder; struct drm_device *dev = connector->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_i2c *i2c = nouveau_i2c(drm->device); + struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); struct nouveau_i2c_port *port = i2c->find(i2c, entry->i2c_index); int type, ret; diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index 195bd8e86c6a..72d2ab04db47 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -34,11 +34,6 @@ #include "hw.h" #include "tvnv17.h" -#include <core/device.h> - -#include <subdev/bios/gpio.h> -#include <subdev/gpio.h> - MODULE_PARM_DESC(tv_norm, "Default TV norm.\n" "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n" "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n" @@ -51,7 +46,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); + struct nouveau_gpio *gpio = nvkm_gpio(&drm->device); uint32_t testval, regoffset = nv04_dac_output_offset(encoder); uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end, fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c; @@ -135,17 +130,17 @@ static bool get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_object *device = drm->device; + struct nvif_device *device = &drm->device; /* Zotac FX5200 */ - if (nv_device_match(device, 0x0322, 0x19da, 0x1035) || - nv_device_match(device, 0x0322, 0x19da, 0x2035)) { + if (nv_device_match(nvkm_object(device), 0x0322, 0x19da, 0x1035) || + nv_device_match(nvkm_object(device), 0x0322, 0x19da, 0x2035)) { *pin_mask = 0xc; return false; } /* MSI nForce2 IGP */ - if (nv_device_match(device, 0x01f0, 0x1462, 0x5710)) { + if (nv_device_match(nvkm_object(device), 0x01f0, 0x1462, 0x5710)) { *pin_mask = 0xc; return false; } @@ -167,8 +162,8 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) return connector_status_disconnected; if (reliable) { - if (nv_device(drm->device)->chipset == 0x42 || - nv_device(drm->device)->chipset == 0x43) + if (drm->device.info.chipset == 0x42 || + drm->device.info.chipset == 0x43) tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe; else @@ -375,7 +370,7 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); + struct nouveau_gpio *gpio = nvkm_gpio(&drm->device); struct nv17_tv_state *regs = &to_tv_enc(encoder)->state; struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); @@ -448,7 +443,7 @@ static void nv17_tv_prepare(struct drm_encoder *encoder) /* Set the DACCLK register */ dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1; - if (nv_device(drm->device)->card_type == NV_40) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE) dacclk |= 0x1a << 16; if (tv_norm->kind == CTV_ENC_MODE) { @@ -505,7 +500,7 @@ static void nv17_tv_mode_set(struct drm_encoder *encoder, tv_regs->ptv_614 = 0x13; } - if (nv_device(drm->device)->card_type >= NV_30) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_RANKINE) { tv_regs->ptv_500 = 0xe8e0; tv_regs->ptv_504 = 0x1710; tv_regs->ptv_604 = 0x0; @@ -600,7 +595,7 @@ static void nv17_tv_commit(struct drm_encoder *encoder) nv17_tv_state_load(dev, &to_tv_enc(encoder)->state); /* This could use refinement for flatpanels, but it should work */ - if (nv_device(drm->device)->chipset < 0x44) + if (drm->device.info.chipset < 0x44) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000); diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h index 7b331543a41b..225894cdcac2 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h @@ -130,14 +130,14 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder); static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, uint32_t val) { - struct nouveau_device *device = nouveau_dev(dev); - nv_wr32(device, reg, val); + struct nvif_device *device = &nouveau_drm(dev)->device; + nvif_wr32(device, reg, val); } static inline uint32_t nv_read_ptv(struct drm_device *dev, uint32_t reg) { - struct nouveau_device *device = nouveau_dev(dev); - return nv_rd32(device, reg); + struct nvif_device *device = &nouveau_drm(dev)->device; + return nvif_rd32(device, reg); } static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index b13f441c6431..a24faa5e2a2a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -21,16 +21,10 @@ * */ -#include <core/object.h> -#include <core/client.h> -#include <core/device.h> -#include <core/class.h> -#include <core/mm.h> - -#include <subdev/fb.h> -#include <subdev/timer.h> -#include <subdev/instmem.h> -#include <engine/graph.h> +#include <nvif/client.h> +#include <nvif/driver.h> +#include <nvif/ioctl.h> +#include <nvif/class.h> #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -47,20 +41,20 @@ nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) struct nouveau_abi16 *abi16; cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL); if (cli->abi16) { + struct nv_device_v0 args = { + .device = ~0ULL, + }; + INIT_LIST_HEAD(&abi16->channels); - abi16->client = nv_object(cli); /* allocate device object targeting client's default * device (ie. the one that belongs to the fd it * opened) */ - if (nouveau_object_new(abi16->client, NVDRM_CLIENT, - NVDRM_DEVICE, 0x0080, - &(struct nv_device_class) { - .device = ~0ULL, - }, - sizeof(struct nv_device_class), - &abi16->device) == 0) + if (nvif_device_init(&cli->base.base, NULL, + NOUVEAU_ABI16_DEVICE, NV_DEVICE, + &args, sizeof(args), + &abi16->device) == 0) return cli->abi16; kfree(cli->abi16); @@ -75,7 +69,7 @@ nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) int nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret) { - struct nouveau_cli *cli = (void *)abi16->client; + struct nouveau_cli *cli = (void *)nvif_client(&abi16->device.base); mutex_unlock(&cli->mutex); return ret; } @@ -83,21 +77,19 @@ nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret) u16 nouveau_abi16_swclass(struct nouveau_drm *drm) { - switch (nv_device(drm->device)->card_type) { - case NV_04: + switch (drm->device.info.family) { + case NV_DEVICE_INFO_V0_TNT: return 0x006e; - case NV_10: - case NV_11: - case NV_20: - case NV_30: - case NV_40: + case NV_DEVICE_INFO_V0_CELSIUS: + case NV_DEVICE_INFO_V0_KELVIN: + case NV_DEVICE_INFO_V0_RANKINE: + case NV_DEVICE_INFO_V0_CURIE: return 0x016e; - case NV_50: + case NV_DEVICE_INFO_V0_TESLA: return 0x506e; - case NV_C0: - case NV_D0: - case NV_E0: - case GM100: + case NV_DEVICE_INFO_V0_FERMI: + case NV_DEVICE_INFO_V0_KEPLER: + case NV_DEVICE_INFO_V0_MAXWELL: return 0x906e; } @@ -140,7 +132,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, /* destroy channel object, all children will be killed too */ if (chan->chan) { - abi16->handles &= ~(1ULL << (chan->chan->handle & 0xffff)); + abi16->handles &= ~(1ULL << (chan->chan->object->handle & 0xffff)); nouveau_channel_del(&chan->chan); } @@ -151,7 +143,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, void nouveau_abi16_fini(struct nouveau_abi16 *abi16) { - struct nouveau_cli *cli = (void *)abi16->client; + struct nouveau_cli *cli = (void *)nvif_client(&abi16->device.base); struct nouveau_abi16_chan *chan, *temp; /* cleanup channels */ @@ -160,7 +152,7 @@ nouveau_abi16_fini(struct nouveau_abi16 *abi16) } /* destroy the device object */ - nouveau_object_del(abi16->client, NVDRM_CLIENT, NVDRM_DEVICE); + nvif_device_fini(&abi16->device); kfree(cli->abi16); cli->abi16 = NULL; @@ -169,30 +161,31 @@ nouveau_abi16_fini(struct nouveau_abi16 *abi16) int nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) { + struct nouveau_cli *cli = nouveau_cli(file_priv); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_timer *ptimer = nouveau_timer(device); - struct nouveau_graph *graph = (void *)nouveau_engine(device, NVDEV_ENGINE_GR); + struct nvif_device *device = &drm->device; + struct nouveau_timer *ptimer = nvkm_timer(device); + struct nouveau_graph *graph = nvkm_gr(device); struct drm_nouveau_getparam *getparam = data; switch (getparam->param) { case NOUVEAU_GETPARAM_CHIPSET_ID: - getparam->value = device->chipset; + getparam->value = device->info.chipset; break; case NOUVEAU_GETPARAM_PCI_VENDOR: - if (nv_device_is_pci(device)) + if (nv_device_is_pci(nvkm_device(device))) getparam->value = dev->pdev->vendor; else getparam->value = 0; break; case NOUVEAU_GETPARAM_PCI_DEVICE: - if (nv_device_is_pci(device)) + if (nv_device_is_pci(nvkm_device(device))) getparam->value = dev->pdev->device; else getparam->value = 0; break; case NOUVEAU_GETPARAM_BUS_TYPE: - if (!nv_device_is_pci(device)) + if (!nv_device_is_pci(nvkm_device(device))) getparam->value = 3; else if (drm_pci_device_is_agp(dev)) @@ -225,7 +218,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = graph->units ? graph->units(graph) : 0; break; default: - nv_debug(device, "unknown parameter %lld\n", getparam->param); + NV_PRINTK(debug, cli, "unknown parameter %lld\n", getparam->param); return -EINVAL; } @@ -246,10 +239,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_abi16_chan *chan; - struct nouveau_client *client; - struct nouveau_device *device; - struct nouveau_instmem *imem; - struct nouveau_fb *pfb; + struct nvif_device *device; int ret; if (unlikely(!abi16)) @@ -258,21 +248,18 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (!drm->channel) return nouveau_abi16_put(abi16, -ENODEV); - client = nv_client(abi16->client); - device = nv_device(abi16->device); - imem = nouveau_instmem(device); - pfb = nouveau_fb(device); + device = &abi16->device; /* hack to allow channel engine type specification on kepler */ - if (device->card_type >= NV_E0) { + if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { if (init->fb_ctxdma_handle != ~0) - init->fb_ctxdma_handle = NVE0_CHANNEL_IND_ENGINE_GR; + init->fb_ctxdma_handle = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR; else init->fb_ctxdma_handle = init->tt_ctxdma_handle; /* allow flips to be executed if this is a graphics channel */ init->tt_ctxdma_handle = 0; - if (init->fb_ctxdma_handle == NVE0_CHANNEL_IND_ENGINE_GR) + if (init->fb_ctxdma_handle == KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR) init->tt_ctxdma_handle = 1; } @@ -293,13 +280,14 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) abi16->handles |= (1ULL << init->channel); /* create channel object and initialise dma and fence management */ - ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN | - init->channel, init->fb_ctxdma_handle, + ret = nouveau_channel_new(drm, device, + NOUVEAU_ABI16_CHAN(init->channel), + init->fb_ctxdma_handle, init->tt_ctxdma_handle, &chan->chan); if (ret) goto done; - if (device->card_type >= NV_50) + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART; else @@ -308,10 +296,10 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) else init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; - if (device->card_type < NV_10) { + if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { init->subchan[0].handle = 0x00000000; init->subchan[0].grclass = 0x0000; - init->subchan[1].handle = NvSw; + init->subchan[1].handle = chan->chan->nvsw.handle; init->subchan[1].grclass = 0x506e; init->nr_subchan = 2; } @@ -324,8 +312,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; - if (device->card_type >= NV_50) { - ret = nouveau_bo_vma_add(chan->ntfy, client->vm, + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_bo_vma_add(chan->ntfy, cli->vm, &chan->ntfy_vma); if (ret) goto done; @@ -343,6 +331,18 @@ done: return nouveau_abi16_put(abi16, ret); } +static struct nouveau_abi16_chan * +nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel) +{ + struct nouveau_abi16_chan *chan; + + list_for_each_entry(chan, &abi16->channels, head) { + if (chan->chan->object->handle == NOUVEAU_ABI16_CHAN(channel)) + return chan; + } + + return NULL; +} int nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS) @@ -350,28 +350,38 @@ nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS) struct drm_nouveau_channel_free *req = data; struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_abi16_chan *chan; - int ret = -ENOENT; if (unlikely(!abi16)) return -ENOMEM; - list_for_each_entry(chan, &abi16->channels, head) { - if (chan->chan->handle == (NVDRM_CHAN | req->channel)) { - nouveau_abi16_chan_fini(abi16, chan); - return nouveau_abi16_put(abi16, 0); - } - } - - return nouveau_abi16_put(abi16, ret); + chan = nouveau_abi16_chan(abi16, req->channel); + if (!chan) + return nouveau_abi16_put(abi16, -ENOENT); + nouveau_abi16_chan_fini(abi16, chan); + return nouveau_abi16_put(abi16, 0); } int nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) { struct drm_nouveau_grobj_alloc *init = data; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_new_v0 new; + } args = { + .ioctl.owner = NVIF_IOCTL_V0_OWNER_ANY, + .ioctl.type = NVIF_IOCTL_V0_NEW, + .ioctl.path_nr = 3, + .ioctl.path[2] = NOUVEAU_ABI16_CLIENT, + .ioctl.path[1] = NOUVEAU_ABI16_DEVICE, + .ioctl.path[0] = NOUVEAU_ABI16_CHAN(init->channel), + .new.route = NVDRM_OBJECT_ABI16, + .new.handle = init->handle, + .new.oclass = init->class, + }; struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_object *object; + struct nvif_client *client; int ret; if (unlikely(!abi16)) @@ -379,6 +389,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if (init->handle == ~0) return nouveau_abi16_put(abi16, -EINVAL); + client = nvif_client(nvif_object(&abi16->device)); /* compatibility with userspace that assumes 506e for all chipsets */ if (init->class == 0x506e) { @@ -387,8 +398,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) return nouveau_abi16_put(abi16, 0); } - ret = nouveau_object_new(abi16->client, NVDRM_CHAN | init->channel, - init->handle, init->class, NULL, 0, &object); + ret = nvif_client_ioctl(client, &args, sizeof(args)); return nouveau_abi16_put(abi16, ret); } @@ -396,29 +406,38 @@ int nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) { struct drm_nouveau_notifierobj_alloc *info = data; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_new_v0 new; + struct nv_dma_v0 ctxdma; + } args = { + .ioctl.owner = NVIF_IOCTL_V0_OWNER_ANY, + .ioctl.type = NVIF_IOCTL_V0_NEW, + .ioctl.path_nr = 3, + .ioctl.path[2] = NOUVEAU_ABI16_CLIENT, + .ioctl.path[1] = NOUVEAU_ABI16_DEVICE, + .ioctl.path[0] = NOUVEAU_ABI16_CHAN(info->channel), + .new.route = NVDRM_OBJECT_ABI16, + .new.handle = info->handle, + .new.oclass = NV_DMA_IN_MEMORY, + }; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); - struct nouveau_abi16_chan *chan = NULL, *temp; + struct nouveau_abi16_chan *chan; struct nouveau_abi16_ntfy *ntfy; - struct nouveau_object *object; - struct nv_dma_class args = {}; + struct nvif_device *device = &abi16->device; + struct nvif_client *client; int ret; if (unlikely(!abi16)) return -ENOMEM; /* completely unnecessary for these chipsets... */ - if (unlikely(nv_device(abi16->device)->card_type >= NV_C0)) + if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI)) return nouveau_abi16_put(abi16, -EINVAL); + client = nvif_client(nvif_object(&abi16->device)); - list_for_each_entry(temp, &abi16->channels, head) { - if (temp->chan->handle == (NVDRM_CHAN | info->channel)) { - chan = temp; - break; - } - } - + chan = nouveau_abi16_chan(abi16, info->channel); if (!chan) return nouveau_abi16_put(abi16, -ENOENT); @@ -429,31 +448,34 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) list_add(&ntfy->head, &chan->notifiers); ntfy->handle = info->handle; - ret = nouveau_mm_head(&chan->heap, 1, info->size, info->size, 1, + ret = nouveau_mm_head(&chan->heap, 0, 1, info->size, info->size, 1, &ntfy->node); if (ret) goto done; - args.start = ntfy->node->offset; - args.limit = ntfy->node->offset + ntfy->node->length - 1; - if (device->card_type >= NV_50) { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; - args.start += chan->ntfy_vma.offset; - args.limit += chan->ntfy_vma.offset; + args.ctxdma.start = ntfy->node->offset; + args.ctxdma.limit = ntfy->node->offset + ntfy->node->length - 1; + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + args.ctxdma.target = NV_DMA_V0_TARGET_VM; + args.ctxdma.access = NV_DMA_V0_ACCESS_VM; + args.ctxdma.start += chan->ntfy_vma.offset; + args.ctxdma.limit += chan->ntfy_vma.offset; } else if (drm->agp.stat == ENABLED) { - args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR; - args.start += drm->agp.base + chan->ntfy->bo.offset; - args.limit += drm->agp.base + chan->ntfy->bo.offset; + args.ctxdma.target = NV_DMA_V0_TARGET_AGP; + args.ctxdma.access = NV_DMA_V0_ACCESS_RDWR; + args.ctxdma.start += drm->agp.base + chan->ntfy->bo.offset; + args.ctxdma.limit += drm->agp.base + chan->ntfy->bo.offset; + client->super = true; } else { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR; - args.start += chan->ntfy->bo.offset; - args.limit += chan->ntfy->bo.offset; + args.ctxdma.target = NV_DMA_V0_TARGET_VM; + args.ctxdma.access = NV_DMA_V0_ACCESS_RDWR; + args.ctxdma.start += chan->ntfy->bo.offset; + args.ctxdma.limit += chan->ntfy->bo.offset; } - ret = nouveau_object_new(abi16->client, chan->chan->handle, - ntfy->handle, 0x003d, &args, - sizeof(args), &object); + ret = nvif_client_ioctl(client, &args, sizeof(args)); + client->super = false; if (ret) goto done; @@ -469,28 +491,36 @@ int nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS) { struct drm_nouveau_gpuobj_free *fini = data; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_del del; + } args = { + .ioctl.owner = NVDRM_OBJECT_ABI16, + .ioctl.type = NVIF_IOCTL_V0_DEL, + .ioctl.path_nr = 4, + .ioctl.path[3] = NOUVEAU_ABI16_CLIENT, + .ioctl.path[2] = NOUVEAU_ABI16_DEVICE, + .ioctl.path[1] = NOUVEAU_ABI16_CHAN(fini->channel), + .ioctl.path[0] = fini->handle, + }; struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); - struct nouveau_abi16_chan *chan = NULL, *temp; + struct nouveau_abi16_chan *chan; struct nouveau_abi16_ntfy *ntfy; + struct nvif_client *client; int ret; if (unlikely(!abi16)) return -ENOMEM; - list_for_each_entry(temp, &abi16->channels, head) { - if (temp->chan->handle == (NVDRM_CHAN | fini->channel)) { - chan = temp; - break; - } - } - + chan = nouveau_abi16_chan(abi16, fini->channel); if (!chan) return nouveau_abi16_put(abi16, -ENOENT); + client = nvif_client(nvif_object(&abi16->device)); /* synchronize with the user channel and destroy the gpu object */ nouveau_channel_idle(chan->chan); - ret = nouveau_object_del(abi16->client, chan->chan->handle, fini->handle); + ret = nvif_client_ioctl(client, &args, sizeof(args)); if (ret) return nouveau_abi16_put(abi16, ret); diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h index 90004081a501..39844e6bfbff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.h +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h @@ -28,8 +28,7 @@ struct nouveau_abi16_chan { }; struct nouveau_abi16 { - struct nouveau_object *client; - struct nouveau_object *device; + struct nvif_device device; struct list_head channels; u64 handles; }; diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 279206997e5c..622424692b3b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -46,7 +46,6 @@ static struct nouveau_dsm_priv { bool dsm_detected; bool optimus_detected; acpi_handle dhandle; - acpi_handle other_handle; acpi_handle rom_handle; } nouveau_dsm_priv; @@ -222,10 +221,9 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) if (!dhandle) return false; - if (!acpi_has_method(dhandle, "_DSM")) { - nouveau_dsm_priv.other_handle = dhandle; + if (!acpi_has_method(dhandle, "_DSM")) return false; - } + if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102, 1 << NOUVEAU_DSM_POWER)) retval |= NOUVEAU_DSM_HAS_MUX; @@ -301,16 +299,6 @@ static bool nouveau_dsm_detect(void) printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", acpi_method_name); nouveau_dsm_priv.dsm_detected = true; - /* - * On some systems hotplug events are generated for the device - * being switched off when _DSM is executed. They cause ACPI - * hotplug to trigger and attempt to remove the device from - * the system, which causes it to break down. Prevent that from - * happening by setting the no_hotplug flag for the involved - * ACPI device objects. - */ - acpi_bus_no_hotplug(nouveau_dsm_priv.dhandle); - acpi_bus_no_hotplug(nouveau_dsm_priv.other_handle); ret = true; } diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c index 51666daddb94..1f6f6ba6847a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_agp.c +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c @@ -1,7 +1,5 @@ #include <linux/module.h> -#include <core/device.h> - #include "nouveau_drm.h" #include "nouveau_agp.h" #include "nouveau_reg.h" @@ -29,7 +27,7 @@ static struct nouveau_agpmode_quirk nouveau_agpmode_quirk_list[] = { static unsigned long get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) { - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list; int agpmode = nouveau_agpmode; unsigned long mode = info->mode; @@ -38,7 +36,7 @@ get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) * FW seems to be broken on nv18, it makes the card lock up * randomly. */ - if (device->chipset == 0x18) + if (device->info.chipset == 0x18) mode &= ~PCI_AGP_COMMAND_FW; /* @@ -47,10 +45,10 @@ get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) while (agpmode == -1 && quirk->hostbridge_vendor) { if (info->id_vendor == quirk->hostbridge_vendor && info->id_device == quirk->hostbridge_device && - device->pdev->vendor == quirk->chip_vendor && - device->pdev->device == quirk->chip_device) { + nvkm_device(device)->pdev->vendor == quirk->chip_vendor && + nvkm_device(device)->pdev->device == quirk->chip_device) { agpmode = quirk->mode; - nv_info(device, "Forcing agp mode to %dX. Use agpmode to override.\n", + NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n", agpmode); break; } @@ -104,7 +102,7 @@ void nouveau_agp_reset(struct nouveau_drm *drm) { #if __OS_HAS_AGP - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct drm_device *dev = drm->dev; u32 save[2]; int ret; @@ -115,7 +113,7 @@ nouveau_agp_reset(struct nouveau_drm *drm) /* First of all, disable fast writes, otherwise if it's * already enabled in the AGP bridge and we disable the card's * AGP controller we might be locking ourselves out of it. */ - if ((nv_rd32(device, NV04_PBUS_PCI_NV_19) | + if ((nvif_rd32(device, NV04_PBUS_PCI_NV_19) | dev->agp->mode) & PCI_AGP_COMMAND_FW) { struct drm_agp_info info; struct drm_agp_mode mode; @@ -134,15 +132,15 @@ nouveau_agp_reset(struct nouveau_drm *drm) /* clear busmaster bit, and disable AGP */ - save[0] = nv_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000); - nv_wr32(device, NV04_PBUS_PCI_NV_19, 0); + save[0] = nvif_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000); + nvif_wr32(device, NV04_PBUS_PCI_NV_19, 0); /* reset PGRAPH, PFIFO and PTIMER */ - save[1] = nv_mask(device, 0x000200, 0x00011100, 0x00000000); - nv_mask(device, 0x000200, 0x00011100, save[1]); + save[1] = nvif_mask(device, 0x000200, 0x00011100, 0x00000000); + nvif_mask(device, 0x000200, 0x00011100, save[1]); /* and restore bustmaster bit (gives effect of resetting AGP) */ - nv_wr32(device, NV04_PBUS_PCI_NV_1, save[0]); + nvif_wr32(device, NV04_PBUS_PCI_NV_1, save[0]); #endif } @@ -150,7 +148,6 @@ void nouveau_agp_init(struct nouveau_drm *drm) { #if __OS_HAS_AGP - struct nouveau_device *device = nv_device(drm->device); struct drm_device *dev = drm->dev; struct drm_agp_info info; struct drm_agp_mode mode; @@ -162,13 +159,13 @@ nouveau_agp_init(struct nouveau_drm *drm) ret = drm_agp_acquire(dev); if (ret) { - nv_error(device, "unable to acquire AGP: %d\n", ret); + NV_ERROR(drm, "unable to acquire AGP: %d\n", ret); return; } ret = drm_agp_info(dev, &info); if (ret) { - nv_error(device, "unable to get AGP info: %d\n", ret); + NV_ERROR(drm, "unable to get AGP info: %d\n", ret); return; } @@ -177,7 +174,7 @@ nouveau_agp_init(struct nouveau_drm *drm) ret = drm_agp_enable(dev, mode); if (ret) { - nv_error(device, "unable to enable AGP: %d\n", ret); + NV_ERROR(drm, "unable to enable AGP: %d\n", ret); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 2c1e4aad7da3..e566c5b53651 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -40,8 +40,8 @@ static int nv40_get_intensity(struct backlight_device *bd) { struct nouveau_drm *drm = bl_get_data(bd); - struct nouveau_device *device = nv_device(drm->device); - int val = (nv_rd32(device, NV40_PMC_BACKLIGHT) & + struct nvif_device *device = &drm->device; + int val = (nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK) >> 16; return val; @@ -51,11 +51,11 @@ static int nv40_set_intensity(struct backlight_device *bd) { struct nouveau_drm *drm = bl_get_data(bd); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int val = bd->props.brightness; - int reg = nv_rd32(device, NV40_PMC_BACKLIGHT); + int reg = nvif_rd32(device, NV40_PMC_BACKLIGHT); - nv_wr32(device, NV40_PMC_BACKLIGHT, + nvif_wr32(device, NV40_PMC_BACKLIGHT, (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK)); return 0; @@ -71,11 +71,11 @@ static int nv40_backlight_init(struct drm_connector *connector) { struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct backlight_properties props; struct backlight_device *bd; - if (!(nv_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) + if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) return 0; memset(&props, 0, sizeof(struct backlight_properties)); @@ -97,12 +97,12 @@ nv50_get_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int or = nv_encoder->or; u32 div = 1025; u32 val; - val = nv_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); + val = nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); val &= NV50_PDISP_SOR_PWM_CTL_VAL; return ((val * 100) + (div / 2)) / div; } @@ -112,12 +112,12 @@ nv50_set_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int or = nv_encoder->or; u32 div = 1025; u32 val = (bd->props.brightness * div) / 100; - nv_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), + nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), NV50_PDISP_SOR_PWM_CTL_NEW | val); return 0; } @@ -133,12 +133,12 @@ nva3_get_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int or = nv_encoder->or; u32 div, val; - div = nv_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); - val = nv_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); + div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); + val = nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(or)); val &= NVA3_PDISP_SOR_PWM_CTL_VAL; if (div && div >= val) return ((val * 100) + (div / 2)) / div; @@ -151,14 +151,14 @@ nva3_set_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int or = nv_encoder->or; u32 div, val; - div = nv_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); + div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or)); val = (bd->props.brightness * div) / 100; if (div) { - nv_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), val | + nvif_wr32(device, NV50_PDISP_SOR_PWM_CTL(or), val | NV50_PDISP_SOR_PWM_CTL_NEW | NVA3_PDISP_SOR_PWM_CTL_UNK); return 0; @@ -177,7 +177,7 @@ static int nv50_backlight_init(struct drm_connector *connector) { struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct nouveau_encoder *nv_encoder; struct backlight_properties props; struct backlight_device *bd; @@ -190,12 +190,12 @@ nv50_backlight_init(struct drm_connector *connector) return -ENODEV; } - if (!nv_rd32(device, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or))) + if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or))) return 0; - if (device->chipset <= 0xa0 || - device->chipset == 0xaa || - device->chipset == 0xac) + if (device->info.chipset <= 0xa0 || + device->info.chipset == 0xaa || + device->info.chipset == 0xac) ops = &nv50_bl_ops; else ops = &nva3_bl_ops; @@ -218,7 +218,7 @@ int nouveau_backlight_init(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct drm_connector *connector; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -226,13 +226,12 @@ nouveau_backlight_init(struct drm_device *dev) connector->connector_type != DRM_MODE_CONNECTOR_eDP) continue; - switch (device->card_type) { - case NV_40: + switch (device->info.family) { + case NV_DEVICE_INFO_V0_CURIE: return nv40_backlight_init(connector); - case NV_50: - case NV_C0: - case NV_D0: - case NV_E0: + case NV_DEVICE_INFO_V0_TESLA: + case NV_DEVICE_INFO_V0_FERMI: + case NV_DEVICE_INFO_V0_KEPLER: return nv50_backlight_init(connector); default: break; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 8268a4ccac15..dae2c96deef8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -22,8 +22,6 @@ * SOFTWARE. */ -#include <subdev/bios.h> - #include <drm/drmP.h> #include "nouveau_drm.h" @@ -217,7 +215,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_output *dcbent, int head */ struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct nvbios *bios = &drm->vbios; uint8_t lvds_ver = bios->data[bios->fp.lvdsmanufacturerpointer]; uint32_t sel_clk_binding, sel_clk; @@ -240,7 +238,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_output *dcbent, int head NV_INFO(drm, "Calling LVDS script %d:\n", script); /* don't let script change pll->head binding */ - sel_clk_binding = nv_rd32(device, NV_PRAMDAC_SEL_CLK) & 0x50000; + sel_clk_binding = nvif_rd32(device, NV_PRAMDAC_SEL_CLK) & 0x50000; if (lvds_ver < 0x30) ret = call_lvds_manufacturer_script(dev, dcbent, head, script); @@ -252,7 +250,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_output *dcbent, int head sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK) & ~0x50000; NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, sel_clk | sel_clk_binding); /* some scripts set a value in NV_PBUS_POWERCTRL_2 and break video overlay */ - nv_wr32(device, NV_PBUS_POWERCTRL_2, 0); + nvif_wr32(device, NV_PBUS_POWERCTRL_2, 0); return ret; } @@ -320,7 +318,7 @@ static int parse_lvds_manufacturer_table_header(struct drm_device *dev, struct n static int get_fp_strap(struct drm_device *dev, struct nvbios *bios) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; /* * The fp strap is normally dictated by the "User Strap" in @@ -334,10 +332,10 @@ 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 (device->card_type >= NV_50) - return (nv_rd32(device, NV_PEXTDEV_BOOT_0) >> 24) & 0xf; + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) + return (nvif_rd32(device, NV_PEXTDEV_BOOT_0) >> 24) & 0xf; else - return (nv_rd32(device, NV_PEXTDEV_BOOT_0) >> 16) & 0xf; + return (nvif_rd32(device, NV_PEXTDEV_BOOT_0) >> 16) & 0xf; } static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios) @@ -636,7 +634,7 @@ int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, */ struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct nvbios *bios = &drm->vbios; int cv = bios->chip_version; uint16_t clktable = 0, scriptptr; @@ -670,7 +668,7 @@ int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, } /* don't let script change pll->head binding */ - sel_clk_binding = nv_rd32(device, NV_PRAMDAC_SEL_CLK) & 0x50000; + sel_clk_binding = nvif_rd32(device, NV_PRAMDAC_SEL_CLK) & 0x50000; run_digital_op_script(dev, scriptptr, dcbent, head, pxclk >= 165000); sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK) & ~0x50000; NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, sel_clk | sel_clk_binding); @@ -1253,7 +1251,7 @@ olddcb_table(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); u8 *dcb = NULL; - if (nv_device(drm->device)->card_type > NV_04) + if (drm->device.info.family > NV_DEVICE_INFO_V0_TNT) dcb = ROMPTR(dev, drm->vbios.data[0x36]); if (!dcb) { NV_WARN(drm, "No DCB data found in VBIOS\n"); @@ -1399,6 +1397,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, uint32_t conn, uint32_t conf, struct dcb_output *entry) { struct nouveau_drm *drm = nouveau_drm(dev); + int link = 0; entry->type = conn & 0xf; entry->i2c_index = (conn >> 4) & 0xf; @@ -1444,6 +1443,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, if (conf & 0x4) entry->lvdsconf.use_power_scripts = true; entry->lvdsconf.sor.link = (conf & 0x00000030) >> 4; + link = entry->lvdsconf.sor.link; } if (conf & mask) { /* @@ -1492,17 +1492,18 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, entry->dpconf.link_nr = 1; break; } + link = entry->dpconf.sor.link; break; case DCB_OUTPUT_TMDS: if (dcb->version >= 0x40) { entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; entry->extdev = (conf & 0x0000ff00) >> 8; + link = entry->tmdsconf.sor.link; } else if (dcb->version >= 0x30) entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8; else if (dcb->version >= 0x22) entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; - break; case DCB_OUTPUT_EOL: /* weird g80 mobile type that "nv" treats as a terminator */ @@ -1526,6 +1527,8 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, if (conf & 0x100000) entry->i2c_upper_default = true; + entry->hasht = (entry->location << 4) | entry->type; + entry->hashm = (entry->heads << 8) | (link << 6) | entry->or; return true; } @@ -1908,7 +1911,7 @@ static int load_nv17_hwsq_ucode_entry(struct drm_device *dev, struct nvbios *bio */ struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; uint8_t bytes_to_write; uint16_t hwsq_entry_offset; int i; @@ -1931,15 +1934,15 @@ static int load_nv17_hwsq_ucode_entry(struct drm_device *dev, struct nvbios *bio hwsq_entry_offset = hwsq_offset + 2 + entry * bytes_to_write; /* set sequencer control */ - nv_wr32(device, 0x00001304, ROM32(bios->data[hwsq_entry_offset])); + nvif_wr32(device, 0x00001304, ROM32(bios->data[hwsq_entry_offset])); bytes_to_write -= 4; /* write ucode */ for (i = 0; i < bytes_to_write; i += 4) - nv_wr32(device, 0x00001400 + i, ROM32(bios->data[hwsq_entry_offset + i + 4])); + nvif_wr32(device, 0x00001400 + i, ROM32(bios->data[hwsq_entry_offset + i + 4])); /* twiddle NV_PBUS_DEBUG_4 */ - nv_wr32(device, NV_PBUS_DEBUG_4, nv_rd32(device, NV_PBUS_DEBUG_4) | 0x18); + nvif_wr32(device, NV_PBUS_DEBUG_4, nvif_rd32(device, NV_PBUS_DEBUG_4) | 0x18); return 0; } @@ -2002,7 +2005,7 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev) static bool NVInitVBIOS(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_bios *bios = nouveau_bios(drm->device); + struct nouveau_bios *bios = nvkm_bios(&drm->device); struct nvbios *legacy = &drm->vbios; memset(legacy, 0, sizeof(struct nvbios)); @@ -2054,7 +2057,7 @@ nouveau_bios_posted(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); unsigned htotal; - if (nv_device(drm->device)->card_type >= NV_50) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) return true; htotal = NVReadVgaCrtc(dev, 0, 0x06); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index b6dc85c614be..3d474ac03f88 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -27,13 +27,9 @@ * Jeremy Kolb <jkolb@brandeis.edu> */ -#include <core/engine.h> +#include <linux/dma-mapping.h> #include <linux/swiotlb.h> -#include <subdev/fb.h> -#include <subdev/vm.h> -#include <subdev/bar.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_fence.h" @@ -52,7 +48,7 @@ nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg, { struct nouveau_drm *drm = nouveau_drm(dev); int i = reg - drm->tile.reg; - struct nouveau_fb *pfb = nouveau_fb(drm->device); + struct nouveau_fb *pfb = nvkm_fb(&drm->device); struct nouveau_fb_tile *tile = &pfb->tile.region[i]; struct nouveau_engine *engine; @@ -92,13 +88,13 @@ nv10_bo_get_tile_region(struct drm_device *dev, int i) static void nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile, - struct nouveau_fence *fence) + struct fence *fence) { struct nouveau_drm *drm = nouveau_drm(dev); if (tile) { spin_lock(&drm->tile.lock); - tile->fence = nouveau_fence_ref(fence); + tile->fence = (struct nouveau_fence *)fence_get(fence); tile->used = false; spin_unlock(&drm->tile.lock); } @@ -109,7 +105,7 @@ nv10_bo_set_tiling(struct drm_device *dev, u32 addr, u32 size, u32 pitch, u32 flags) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fb *pfb = nouveau_fb(drm->device); + struct nouveau_fb *pfb = nvkm_fb(&drm->device); struct nouveau_drm_tile *tile, *found = NULL; int i; @@ -153,23 +149,23 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags, int *align, int *size) { struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; - if (device->card_type < NV_50) { + if (device->info.family < NV_DEVICE_INFO_V0_TESLA) { if (nvbo->tile_mode) { - if (device->chipset >= 0x40) { + if (device->info.chipset >= 0x40) { *align = 65536; *size = roundup(*size, 64 * nvbo->tile_mode); - } else if (device->chipset >= 0x30) { + } else if (device->info.chipset >= 0x30) { *align = 32768; *size = roundup(*size, 64 * nvbo->tile_mode); - } else if (device->chipset >= 0x20) { + } else if (device->info.chipset >= 0x20) { *align = 16384; *size = roundup(*size, 64 * nvbo->tile_mode); - } else if (device->chipset >= 0x10) { + } else if (device->info.chipset >= 0x10) { *align = 16384; *size = roundup(*size, 32 * nvbo->tile_mode); } @@ -185,7 +181,7 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags, int nouveau_bo_new(struct drm_device *dev, int size, int align, uint32_t flags, uint32_t tile_mode, uint32_t tile_flags, - struct sg_table *sg, + struct sg_table *sg, struct reservation_object *robj, struct nouveau_bo **pnvbo) { struct nouveau_drm *drm = nouveau_drm(dev); @@ -196,12 +192,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, int lpg_shift = 12; int max_size; - if (drm->client.base.vm) - lpg_shift = drm->client.base.vm->vmm->lpg_shift; + if (drm->client.vm) + lpg_shift = drm->client.vm->vmm->lpg_shift; max_size = INT_MAX & ~((1 << lpg_shift) - 1); if (size <= 0 || size > max_size) { - nv_warn(drm, "skipped size %x\n", (u32)size); + NV_WARN(drm, "skipped size %x\n", (u32)size); return -EINVAL; } @@ -219,9 +215,9 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, nvbo->bo.bdev = &drm->ttm.bdev; nvbo->page_shift = 12; - if (drm->client.base.vm) { + if (drm->client.vm) { if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024) - nvbo->page_shift = drm->client.base.vm->vmm->lpg_shift; + nvbo->page_shift = drm->client.vm->vmm->lpg_shift; } nouveau_bo_fixup_align(nvbo, flags, &align, &size); @@ -234,7 +230,7 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size, type, &nvbo->placement, align >> PAGE_SHIFT, false, NULL, acc_size, sg, - nouveau_bo_del_ttm); + robj, nouveau_bo_del_ttm); if (ret) { /* ttm will call nouveau_bo_del_ttm if it fails.. */ return ret; @@ -245,27 +241,26 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, } static void -set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags) +set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t type, uint32_t flags) { *n = 0; if (type & TTM_PL_FLAG_VRAM) - pl[(*n)++] = TTM_PL_FLAG_VRAM | flags; + pl[(*n)++].flags = TTM_PL_FLAG_VRAM | flags; if (type & TTM_PL_FLAG_TT) - pl[(*n)++] = TTM_PL_FLAG_TT | flags; + pl[(*n)++].flags = TTM_PL_FLAG_TT | flags; if (type & TTM_PL_FLAG_SYSTEM) - pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags; + pl[(*n)++].flags = TTM_PL_FLAG_SYSTEM | flags; } static void set_placement_range(struct nouveau_bo *nvbo, uint32_t type) { struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); - struct nouveau_fb *pfb = nouveau_fb(drm->device); - u32 vram_pages = pfb->ram->size >> PAGE_SHIFT; + u32 vram_pages = drm->device.info.ram_size >> PAGE_SHIFT; + unsigned i, fpfn, lpfn; - if ((nv_device(drm->device)->card_type == NV_10 || - nv_device(drm->device)->card_type == NV_11) && + if (drm->device.info.family == NV_DEVICE_INFO_V0_CELSIUS && nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && nvbo->bo.mem.num_pages < vram_pages / 4) { /* @@ -275,11 +270,19 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type) * at the same time. */ if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { - nvbo->placement.fpfn = vram_pages / 2; - nvbo->placement.lpfn = ~0; + fpfn = vram_pages / 2; + lpfn = ~0; } else { - nvbo->placement.fpfn = 0; - nvbo->placement.lpfn = vram_pages / 2; + fpfn = 0; + lpfn = vram_pages / 2; + } + for (i = 0; i < nvbo->placement.num_placement; ++i) { + nvbo->placements[i].fpfn = fpfn; + nvbo->placements[i].lpfn = lpfn; + } + for (i = 0; i < nvbo->placement.num_busy_placement; ++i) { + nvbo->busy_placements[i].fpfn = fpfn; + nvbo->busy_placements[i].lpfn = lpfn; } } } @@ -309,7 +312,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) struct ttm_buffer_object *bo = &nvbo->bo; int ret; - ret = ttm_bo_reserve(bo, false, false, false, 0); + ret = ttm_bo_reserve(bo, false, false, false, NULL); if (ret) goto out; @@ -350,7 +353,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) struct ttm_buffer_object *bo = &nvbo->bo; int ret, ref; - ret = ttm_bo_reserve(bo, false, false, false, 0); + ret = ttm_bo_reserve(bo, false, false, false, NULL); if (ret) return ret; @@ -385,7 +388,7 @@ nouveau_bo_map(struct nouveau_bo *nvbo) { int ret; - ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0); + ret = ttm_bo_reserve(&nvbo->bo, false, false, false, NULL); if (ret) return ret; @@ -500,21 +503,28 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->default_caching = TTM_PL_FLAG_CACHED; break; case TTM_PL_VRAM: - if (nv_device(drm->device)->card_type >= NV_50) { + man->flags = TTM_MEMTYPE_FLAG_FIXED | + TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + /* Some BARs do not support being ioremapped WC */ + if (nvkm_bar(&drm->device)->iomap_uncached) { + man->available_caching = TTM_PL_FLAG_UNCACHED; + man->default_caching = TTM_PL_FLAG_UNCACHED; + } + man->func = &nouveau_vram_manager; man->io_reserve_fastpath = false; man->use_io_reserve_lru = true; } else { man->func = &ttm_bo_manager_func; } - man->flags = TTM_MEMTYPE_FLAG_FIXED | - TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; break; case TTM_PL_TT: - if (nv_device(drm->device)->card_type >= NV_50) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) man->func = &nouveau_gart_manager; else if (drm->agp.stat != ENABLED) @@ -763,9 +773,9 @@ nv50_bo_move_init(struct nouveau_channel *chan, u32 handle) BEGIN_NV04(chan, NvSubCopy, 0x0000, 1); OUT_RING (chan, handle); BEGIN_NV04(chan, NvSubCopy, 0x0180, 3); - OUT_RING (chan, NvNotify0); - OUT_RING (chan, NvDmaFB); - OUT_RING (chan, NvDmaFB); + OUT_RING (chan, chan->drm->ntfy.handle); + OUT_RING (chan, chan->vram.handle); + OUT_RING (chan, chan->vram.handle); } return ret; @@ -852,7 +862,7 @@ nv04_bo_move_init(struct nouveau_channel *chan, u32 handle) BEGIN_NV04(chan, NvSubCopy, 0x0000, 1); OUT_RING (chan, handle); BEGIN_NV04(chan, NvSubCopy, 0x0180, 1); - OUT_RING (chan, NvNotify0); + OUT_RING (chan, chan->drm->ntfy.handle); } return ret; @@ -864,7 +874,7 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, { if (mem->mem_type == TTM_PL_TT) return NvDmaTT; - return NvDmaFB; + return chan->vram.handle; } static int @@ -922,12 +932,12 @@ nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo, u64 size = (u64)mem->num_pages << PAGE_SHIFT; int ret; - ret = nouveau_vm_get(nv_client(drm)->vm, size, old_node->page_shift, + ret = nouveau_vm_get(drm->client.vm, size, old_node->page_shift, NV_MEM_ACCESS_RW, &old_node->vma[0]); if (ret) return ret; - ret = nouveau_vm_get(nv_client(drm)->vm, size, new_node->page_shift, + ret = nouveau_vm_get(drm->client.vm, size, new_node->page_shift, NV_MEM_ACCESS_RW, &old_node->vma[1]); if (ret) { nouveau_vm_put(&old_node->vma[0]); @@ -945,6 +955,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_channel *chan = drm->ttm.chan; + struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base); struct nouveau_fence *fence; int ret; @@ -952,20 +963,21 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, * old nouveau_mem node, these will get cleaned up after ttm has * destroyed the ttm_mem_reg */ - if (nv_device(drm->device)->card_type >= NV_50) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ret = nouveau_bo_move_prep(drm, bo, new_mem); if (ret) return ret; } - mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING); - ret = nouveau_fence_sync(bo->sync_obj, chan); + mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING); + ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, intr); if (ret == 0) { ret = drm->ttm.move(chan, bo, &bo->mem, new_mem); if (ret == 0) { ret = nouveau_fence_new(chan, false, &fence); if (ret == 0) { - ret = ttm_bo_move_accel_cleanup(bo, fence, + ret = ttm_bo_move_accel_cleanup(bo, + &fence->base, evict, no_wait_gpu, new_mem); @@ -973,7 +985,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, } } } - mutex_unlock(&chan->cli->mutex); + mutex_unlock(&cli->mutex); return ret; } @@ -1005,9 +1017,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) int ret; do { - struct nouveau_object *object; struct nouveau_channel *chan; - u32 handle = (mthd->engine << 16) | mthd->oclass; if (mthd->engine) chan = drm->cechan; @@ -1016,13 +1026,14 @@ nouveau_bo_move_init(struct nouveau_drm *drm) if (chan == NULL) continue; - ret = nouveau_object_new(nv_object(drm), chan->handle, handle, - mthd->oclass, NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, + mthd->oclass | (mthd->engine << 16), + mthd->oclass, NULL, 0, + &drm->ttm.copy); if (ret == 0) { - ret = mthd->init(chan, handle); + ret = mthd->init(chan, drm->ttm.copy.handle); if (ret) { - nouveau_object_del(nv_object(drm), - chan->handle, handle); + nvif_object_fini(&drm->ttm.copy); continue; } @@ -1040,12 +1051,15 @@ static int nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { - u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; + struct ttm_place placement_memtype = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING + }; struct ttm_placement placement; struct ttm_mem_reg tmp_mem; int ret; - placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; placement.placement = placement.busy_placement = &placement_memtype; @@ -1073,12 +1087,15 @@ static int nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { - u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; + struct ttm_place placement_memtype = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING + }; struct ttm_placement placement; struct ttm_mem_reg tmp_mem; int ret; - placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; placement.placement = placement.busy_placement = &placement_memtype; @@ -1135,7 +1152,7 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, if (new_mem->mem_type != TTM_PL_VRAM) return 0; - if (nv_device(drm->device)->card_type >= NV_10) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) { *new_tile = nv10_bo_set_tiling(dev, offset, new_mem->size, nvbo->tile_mode, nvbo->tile_flags); @@ -1151,8 +1168,9 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct drm_device *dev = drm->dev; + struct fence *fence = reservation_object_get_excl(bo->resv); - nv10_bo_put_tile_region(dev, *old_tile, bo->sync_obj); + nv10_bo_put_tile_region(dev, *old_tile, fence); *old_tile = new_tile; } @@ -1166,7 +1184,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, struct nouveau_drm_tile *new_tile = NULL; int ret = 0; - if (nv_device(drm->device)->card_type < NV_50) { + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile); if (ret) return ret; @@ -1196,14 +1214,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, } /* Fallback to software copy. */ - spin_lock(&bo->bdev->fence_lock); ret = ttm_bo_wait(bo, true, intr, no_wait_gpu); - spin_unlock(&bo->bdev->fence_lock); if (ret == 0) ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); out: - if (nv_device(drm->device)->card_type < NV_50) { + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { if (ret) nouveau_bo_vm_cleanup(bo, NULL, &new_tile); else @@ -1227,7 +1243,6 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; struct nouveau_drm *drm = nouveau_bdev(bdev); struct nouveau_mem *node = mem->mm_node; - struct drm_device *dev = drm->dev; int ret; mem->bus.addr = NULL; @@ -1246,19 +1261,19 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) if (drm->agp.stat == ENABLED) { mem->bus.offset = mem->start << PAGE_SHIFT; mem->bus.base = drm->agp.base; - mem->bus.is_iomem = !dev->agp->cant_use_aperture; + mem->bus.is_iomem = !drm->dev->agp->cant_use_aperture; } #endif - if (nv_device(drm->device)->card_type < NV_50 || !node->memtype) + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !node->memtype) /* untiled */ break; /* fallthrough, tiled memory */ case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; - mem->bus.base = nv_device_resource_start(nouveau_dev(dev), 1); + mem->bus.base = nv_device_resource_start(nvkm_device(&drm->device), 1); mem->bus.is_iomem = true; - if (nv_device(drm->device)->card_type >= NV_50) { - struct nouveau_bar *bar = nouveau_bar(drm->device); + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + struct nouveau_bar *bar = nvkm_bar(&drm->device); ret = bar->umap(bar, node, NV_MEM_ACCESS_RW, &node->bar_vma); @@ -1278,7 +1293,7 @@ static void nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(bdev); - struct nouveau_bar *bar = nouveau_bar(drm->device); + struct nouveau_bar *bar = nvkm_bar(&drm->device); struct nouveau_mem *node = mem->mm_node; if (!node->bar_vma.node) @@ -1292,15 +1307,15 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_bo *nvbo = nouveau_bo(bo); - struct nouveau_device *device = nv_device(drm->device); - u32 mappable = nv_device_resource_len(device, 1) >> PAGE_SHIFT; - int ret; + struct nvif_device *device = &drm->device; + u32 mappable = nv_device_resource_len(nvkm_device(device), 1) >> PAGE_SHIFT; + int i, ret; /* as long as the bo isn't in vram, and isn't tiled, we've got * nothing to do here. */ if (bo->mem.mem_type != TTM_PL_VRAM) { - if (nv_device(drm->device)->card_type < NV_50 || + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !nouveau_bo_tile_layout(nvbo)) return 0; @@ -1315,13 +1330,20 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) } /* make sure bo is in mappable vram */ - if (nv_device(drm->device)->card_type >= NV_50 || + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA || bo->mem.start + bo->mem.num_pages < mappable) return 0; + for (i = 0; i < nvbo->placement.num_placement; ++i) { + nvbo->placements[i].fpfn = 0; + nvbo->placements[i].lpfn = mappable; + } + + for (i = 0; i < nvbo->placement.num_busy_placement; ++i) { + nvbo->busy_placements[i].fpfn = 0; + nvbo->busy_placements[i].lpfn = mappable; + } - nvbo->placement.fpfn = 0; - nvbo->placement.lpfn = mappable; nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0); return nouveau_bo_validate(nvbo, false, false); } @@ -1333,6 +1355,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) struct nouveau_drm *drm; struct nouveau_device *device; struct drm_device *dev; + struct device *pdev; unsigned i; int r; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); @@ -1349,8 +1372,9 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) } drm = nouveau_bdev(ttm->bdev); - device = nv_device(drm->device); + device = nvkm_device(&drm->device); dev = drm->dev; + pdev = nv_device_base(device); #if __OS_HAS_AGP if (drm->agp.stat == ENABLED) { @@ -1370,17 +1394,22 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) } for (i = 0; i < ttm->num_pages; i++) { - ttm_dma->dma_address[i] = nv_device_map_page(device, - ttm->pages[i]); - if (!ttm_dma->dma_address[i]) { + dma_addr_t addr; + + addr = dma_map_page(pdev, ttm->pages[i], 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + + if (dma_mapping_error(pdev, addr)) { while (--i) { - nv_device_unmap_page(device, - ttm_dma->dma_address[i]); + dma_unmap_page(pdev, ttm_dma->dma_address[i], + PAGE_SIZE, DMA_BIDIRECTIONAL); ttm_dma->dma_address[i] = 0; } ttm_pool_unpopulate(ttm); return -EFAULT; } + + ttm_dma->dma_address[i] = addr; } return 0; } @@ -1392,6 +1421,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) struct nouveau_drm *drm; struct nouveau_device *device; struct drm_device *dev; + struct device *pdev; unsigned i; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); @@ -1399,8 +1429,9 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) return; drm = nouveau_bdev(ttm->bdev); - device = nv_device(drm->device); + device = nvkm_device(&drm->device); dev = drm->dev; + pdev = nv_device_base(device); #if __OS_HAS_AGP if (drm->agp.stat == ENABLED) { @@ -1418,7 +1449,8 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) for (i = 0; i < ttm->num_pages; i++) { if (ttm_dma->dma_address[i]) { - nv_device_unmap_page(device, ttm_dma->dma_address[i]); + dma_unmap_page(pdev, ttm_dma->dma_address[i], PAGE_SIZE, + DMA_BIDIRECTIONAL); } } @@ -1426,47 +1458,14 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) } void -nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) -{ - struct nouveau_fence *new_fence = nouveau_fence_ref(fence); - struct nouveau_fence *old_fence = NULL; - - spin_lock(&nvbo->bo.bdev->fence_lock); - old_fence = nvbo->bo.sync_obj; - nvbo->bo.sync_obj = new_fence; - spin_unlock(&nvbo->bo.bdev->fence_lock); - - nouveau_fence_unref(&old_fence); -} - -static void -nouveau_bo_fence_unref(void **sync_obj) -{ - nouveau_fence_unref((struct nouveau_fence **)sync_obj); -} - -static void * -nouveau_bo_fence_ref(void *sync_obj) +nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive) { - return nouveau_fence_ref(sync_obj); -} - -static bool -nouveau_bo_fence_signalled(void *sync_obj) -{ - return nouveau_fence_done(sync_obj); -} + struct reservation_object *resv = nvbo->bo.resv; -static int -nouveau_bo_fence_wait(void *sync_obj, bool lazy, bool intr) -{ - return nouveau_fence_wait(sync_obj, lazy, intr); -} - -static int -nouveau_bo_fence_flush(void *sync_obj) -{ - return 0; + if (exclusive) + reservation_object_add_excl_fence(resv, &fence->base); + else if (fence) + reservation_object_add_shared_fence(resv, &fence->base); } struct ttm_bo_driver nouveau_bo_driver = { @@ -1479,11 +1478,6 @@ struct ttm_bo_driver nouveau_bo_driver = { .move_notify = nouveau_bo_move_ntfy, .move = nouveau_bo_move, .verify_access = nouveau_bo_verify_access, - .sync_obj_signaled = nouveau_bo_fence_signalled, - .sync_obj_wait = nouveau_bo_fence_wait, - .sync_obj_flush = nouveau_bo_fence_flush, - .sync_obj_unref = nouveau_bo_fence_unref, - .sync_obj_ref = nouveau_bo_fence_ref, .fault_reserve_notify = &nouveau_ttm_fault_reserve_notify, .io_mem_reserve = &nouveau_ttm_io_mem_reserve, .io_mem_free = &nouveau_ttm_io_mem_free, diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index ff17c1f432fc..22d2c764d80b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -1,6 +1,8 @@ #ifndef __NOUVEAU_BO_H__ #define __NOUVEAU_BO_H__ +#include <drm/drm_gem.h> + struct nouveau_channel; struct nouveau_fence; struct nouveau_vma; @@ -9,8 +11,8 @@ struct nouveau_bo { struct ttm_buffer_object bo; struct ttm_placement placement; u32 valid_domains; - u32 placements[3]; - u32 busy_placements[3]; + struct ttm_place placements[3]; + struct ttm_place busy_placements[3]; struct ttm_bo_kmap_obj kmap; struct list_head head; @@ -68,6 +70,7 @@ extern struct ttm_bo_driver nouveau_bo_driver; void nouveau_bo_move_init(struct nouveau_drm *); int nouveau_bo_new(struct drm_device *, int size, int align, u32 flags, u32 tile_mode, u32 tile_flags, struct sg_table *sg, + struct reservation_object *robj, struct nouveau_bo **); int nouveau_bo_pin(struct nouveau_bo *, u32 flags); int nouveau_bo_unpin(struct nouveau_bo *); @@ -78,7 +81,7 @@ u16 nouveau_bo_rd16(struct nouveau_bo *, unsigned index); void nouveau_bo_wr16(struct nouveau_bo *, unsigned index, u16 val); u32 nouveau_bo_rd32(struct nouveau_bo *, unsigned index); void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val); -void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *); +void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *, bool exclusive); int nouveau_bo_validate(struct nouveau_bo *, bool interruptible, bool no_wait_gpu); diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index ccb6b452d6d0..fd3dbd59d73e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -22,16 +22,11 @@ * Authors: Ben Skeggs */ -#include <core/object.h> -#include <core/client.h> -#include <core/device.h> -#include <core/class.h> - -#include <subdev/fb.h> -#include <subdev/vm.h> -#include <subdev/instmem.h> +#include <nvif/os.h> +#include <nvif/class.h> -#include <engine/software.h> +/*XXX*/ +#include <core/client.h> #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -41,13 +36,13 @@ #include "nouveau_abi16.h" MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM"); -static int nouveau_vram_pushbuf; +int nouveau_vram_pushbuf; module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); int nouveau_channel_idle(struct nouveau_channel *chan) { - struct nouveau_cli *cli = chan->cli; + struct nouveau_cli *cli = (void *)nvif_client(chan->object); struct nouveau_fence *fence = NULL; int ret; @@ -58,8 +53,8 @@ nouveau_channel_idle(struct nouveau_channel *chan) } if (ret) - NV_ERROR(cli, "failed to idle channel 0x%08x [%s]\n", - chan->handle, cli->base.name); + NV_PRINTK(error, cli, "failed to idle channel 0x%08x [%s]\n", + chan->object->handle, nvkm_client(&cli->base)->name); return ret; } @@ -68,36 +63,34 @@ nouveau_channel_del(struct nouveau_channel **pchan) { struct nouveau_channel *chan = *pchan; if (chan) { - struct nouveau_object *client = nv_object(chan->cli); if (chan->fence) { nouveau_channel_idle(chan); nouveau_fence(chan->drm)->context_del(chan); } - nouveau_object_del(client, NVDRM_DEVICE, chan->handle); - nouveau_object_del(client, NVDRM_DEVICE, chan->push.handle); + nvif_object_fini(&chan->nvsw); + nvif_object_fini(&chan->gart); + nvif_object_fini(&chan->vram); + nvif_object_ref(NULL, &chan->object); + nvif_object_fini(&chan->push.ctxdma); nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma); nouveau_bo_unmap(chan->push.buffer); if (chan->push.buffer && chan->push.buffer->pin_refcnt) nouveau_bo_unpin(chan->push.buffer); nouveau_bo_ref(NULL, &chan->push.buffer); + nvif_device_ref(NULL, &chan->device); kfree(chan); } *pchan = NULL; } static int -nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, u32 size, - struct nouveau_channel **pchan) +nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, u32 size, struct nouveau_channel **pchan) { - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_instmem *imem = nouveau_instmem(device); - struct nouveau_vmmgr *vmm = nouveau_vmmgr(device); - struct nouveau_fb *pfb = nouveau_fb(device); - struct nouveau_client *client = &cli->base; - struct nv_dma_class args = {}; + struct nouveau_cli *cli = (void *)nvif_client(&device->base); + struct nouveau_vmmgr *vmm = nvkm_vmmgr(device); + struct nv_dma_v0 args = {}; struct nouveau_channel *chan; - struct nouveau_object *push; u32 target; int ret; @@ -105,16 +98,15 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, if (!chan) return -ENOMEM; - chan->cli = cli; + nvif_device_ref(device, &chan->device); chan->drm = drm; - chan->handle = handle; /* allocate memory for dma push buffer */ target = TTM_PL_FLAG_TT; if (nouveau_vram_pushbuf) target = TTM_PL_FLAG_VRAM; - ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL, + ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL, NULL, &chan->push.buffer); if (ret == 0) { ret = nouveau_bo_pin(chan->push.buffer, target); @@ -132,51 +124,54 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, * we be able to call out to other (indirect) push buffers */ chan->push.vma.offset = chan->push.buffer->bo.offset; - chan->push.handle = NVDRM_PUSH | (handle & 0xffff); - if (device->card_type >= NV_50) { - ret = nouveau_bo_vma_add(chan->push.buffer, client->vm, + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_bo_vma_add(chan->push.buffer, cli->vm, &chan->push.vma); if (ret) { nouveau_channel_del(pchan); return ret; } - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_VM; args.start = 0; - args.limit = client->vm->vmm->limit - 1; + args.limit = cli->vm->vmm->limit - 1; } else if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) { - u64 limit = pfb->ram->size - imem->reserved - 1; - if (device->card_type == NV_04) { + if (device->info.family == NV_DEVICE_INFO_V0_TNT) { /* nv04 vram pushbuf hack, retarget to its location in * the framebuffer bar rather than direct vram access.. * nfi why this exists, it came from the -nv ddx. */ - args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR; - args.start = nv_device_resource_start(device, 1); - args.limit = args.start + limit; + args.target = NV_DMA_V0_TARGET_PCI; + args.access = NV_DMA_V0_ACCESS_RDWR; + args.start = nv_device_resource_start(nvkm_device(device), 1); + args.limit = args.start + device->info.ram_user - 1; } else { - args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VRAM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; - args.limit = limit; + args.limit = device->info.ram_user - 1; } } else { if (chan->drm->agp.stat == ENABLED) { - args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_AGP; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = chan->drm->agp.base; args.limit = chan->drm->agp.base + chan->drm->agp.size - 1; } else { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; args.limit = vmm->limit - 1; } } - ret = nouveau_object_new(nv_object(chan->cli), parent, - chan->push.handle, 0x0002, - &args, sizeof(args), &push); + ret = nvif_object_init(nvif_object(device), NULL, NVDRM_PUSH | + (handle & 0xffff), NV_DMA_FROM_MEMORY, + &args, sizeof(args), &chan->push.ctxdma); if (ret) { nouveau_channel_del(pchan); return ret; @@ -186,38 +181,56 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, } static int -nouveau_channel_ind(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, u32 engine, - struct nouveau_channel **pchan) +nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, u32 engine, struct nouveau_channel **pchan) { - static const u16 oclasses[] = { NVE0_CHANNEL_IND_CLASS, - NVC0_CHANNEL_IND_CLASS, - NV84_CHANNEL_IND_CLASS, - NV50_CHANNEL_IND_CLASS, + static const u16 oclasses[] = { KEPLER_CHANNEL_GPFIFO_A, + FERMI_CHANNEL_GPFIFO, + G82_CHANNEL_GPFIFO, + NV50_CHANNEL_GPFIFO, 0 }; const u16 *oclass = oclasses; - struct nve0_channel_ind_class args; + union { + struct nv50_channel_gpfifo_v0 nv50; + struct kepler_channel_gpfifo_a_v0 kepler; + } args, *retn; struct nouveau_channel *chan; + u32 size; int ret; /* allocate dma push buffer */ - ret = nouveau_channel_prep(drm, cli, parent, handle, 0x12000, &chan); + ret = nouveau_channel_prep(drm, device, handle, 0x12000, &chan); *pchan = chan; if (ret) return ret; /* create channel object */ - args.pushbuf = chan->push.handle; - args.ioffset = 0x10000 + chan->push.vma.offset; - args.ilength = 0x02000; - args.engine = engine; - do { - ret = nouveau_object_new(nv_object(cli), parent, handle, - *oclass++, &args, sizeof(args), - &chan->object); - if (ret == 0) + if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { + args.kepler.version = 0; + args.kepler.engine = engine; + args.kepler.pushbuf = chan->push.ctxdma.handle; + args.kepler.ilength = 0x02000; + args.kepler.ioffset = 0x10000 + chan->push.vma.offset; + size = sizeof(args.kepler); + } else { + args.nv50.version = 0; + args.nv50.pushbuf = chan->push.ctxdma.handle; + args.nv50.ilength = 0x02000; + args.nv50.ioffset = 0x10000 + chan->push.vma.offset; + size = sizeof(args.nv50); + } + + ret = nvif_object_new(nvif_object(device), handle, *oclass++, + &args, size, &chan->object); + if (ret == 0) { + retn = chan->object->data; + if (chan->object->oclass >= KEPLER_CHANNEL_GPFIFO_A) + chan->chid = retn->kepler.chid; + else + chan->chid = retn->nv50.chid; return ret; + } } while (*oclass); nouveau_channel_del(pchan); @@ -225,35 +238,38 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nouveau_cli *cli, } static int -nouveau_channel_dma(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, struct nouveau_channel **pchan) +nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, struct nouveau_channel **pchan) { - static const u16 oclasses[] = { NV40_CHANNEL_DMA_CLASS, - NV17_CHANNEL_DMA_CLASS, - NV10_CHANNEL_DMA_CLASS, - NV03_CHANNEL_DMA_CLASS, + static const u16 oclasses[] = { NV40_CHANNEL_DMA, + NV17_CHANNEL_DMA, + NV10_CHANNEL_DMA, + NV03_CHANNEL_DMA, 0 }; const u16 *oclass = oclasses; - struct nv03_channel_dma_class args; + struct nv03_channel_dma_v0 args, *retn; struct nouveau_channel *chan; int ret; /* allocate dma push buffer */ - ret = nouveau_channel_prep(drm, cli, parent, handle, 0x10000, &chan); + ret = nouveau_channel_prep(drm, device, handle, 0x10000, &chan); *pchan = chan; if (ret) return ret; /* create channel object */ - args.pushbuf = chan->push.handle; + args.version = 0; + args.pushbuf = chan->push.ctxdma.handle; args.offset = chan->push.vma.offset; do { - ret = nouveau_object_new(nv_object(cli), parent, handle, - *oclass++, &args, sizeof(args), - &chan->object); - if (ret == 0) + ret = nvif_object_new(nvif_object(device), handle, *oclass++, + &args, sizeof(args), &chan->object); + if (ret == 0) { + retn = chan->object->data; + chan->chid = retn->chid; return ret; + } } while (ret && *oclass); nouveau_channel_del(pchan); @@ -263,60 +279,64 @@ nouveau_channel_dma(struct nouveau_drm *drm, struct nouveau_cli *cli, static int nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) { - struct nouveau_client *client = nv_client(chan->cli); - struct nouveau_device *device = nv_device(chan->drm->device); - struct nouveau_instmem *imem = nouveau_instmem(device); - struct nouveau_vmmgr *vmm = nouveau_vmmgr(device); - struct nouveau_fb *pfb = nouveau_fb(device); + struct nvif_device *device = chan->device; + struct nouveau_cli *cli = (void *)nvif_client(&device->base); + struct nouveau_vmmgr *vmm = nvkm_vmmgr(device); struct nouveau_software_chan *swch; - struct nouveau_object *object; - struct nv_dma_class args = {}; + struct nv_dma_v0 args = {}; int ret, i; + bool save; + + nvif_object_map(chan->object); /* allocate dma objects to cover all allowed vram, and gart */ - if (device->card_type < NV_C0) { - if (device->card_type >= NV_50) { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_VM; args.start = 0; - args.limit = client->vm->vmm->limit - 1; + args.limit = cli->vm->vmm->limit - 1; } else { - args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VRAM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; - args.limit = pfb->ram->size - imem->reserved - 1; + args.limit = device->info.ram_user - 1; } - ret = nouveau_object_new(nv_object(client), chan->handle, vram, - 0x003d, &args, sizeof(args), &object); + ret = nvif_object_init(chan->object, NULL, vram, + NV_DMA_IN_MEMORY, &args, + sizeof(args), &chan->vram); if (ret) return ret; - if (device->card_type >= NV_50) { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM; + if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_VM; args.start = 0; - args.limit = client->vm->vmm->limit - 1; + args.limit = cli->vm->vmm->limit - 1; } else if (chan->drm->agp.stat == ENABLED) { - args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_AGP; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = chan->drm->agp.base; args.limit = chan->drm->agp.base + chan->drm->agp.size - 1; } else { - args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_RDWR; args.start = 0; args.limit = vmm->limit - 1; } - ret = nouveau_object_new(nv_object(client), chan->handle, gart, - 0x003d, &args, sizeof(args), &object); + ret = nvif_object_init(chan->object, NULL, gart, + NV_DMA_IN_MEMORY, &args, + sizeof(args), &chan->gart); if (ret) return ret; - - chan->vram = vram; - chan->gart = gart; } /* initialise dma tracking parameters */ - switch (nv_hclass(chan->object) & 0x00ff) { + switch (chan->object->oclass & 0x00ff) { case 0x006b: case 0x006e: chan->user_put = 0x40; @@ -347,13 +367,13 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) OUT_RING(chan, 0x00000000); /* allocate software object class (used for fences on <= nv05) */ - if (device->card_type < NV_10) { - ret = nouveau_object_new(nv_object(client), chan->handle, - NvSw, 0x006e, NULL, 0, &object); + if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { + ret = nvif_object_init(chan->object, NULL, 0x006e, 0x006e, + NULL, 0, &chan->nvsw); if (ret) return ret; - swch = (void *)object->parent; + swch = (void *)nvkm_object(&chan->nvsw)->parent; swch->flip = nouveau_flip_complete; swch->flip_data = chan; @@ -362,37 +382,48 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) return ret; BEGIN_NV04(chan, NvSubSw, 0x0000, 1); - OUT_RING (chan, NvSw); + OUT_RING (chan, chan->nvsw.handle); FIRE_RING (chan); } /* initialise synchronisation */ - return nouveau_fence(chan->drm)->context_new(chan); + save = cli->base.super; + cli->base.super = true; /* hack until fencenv50 fixed */ + ret = nouveau_fence(chan->drm)->context_new(chan); + cli->base.super = save; + return ret; } int -nouveau_channel_new(struct nouveau_drm *drm, struct nouveau_cli *cli, - u32 parent, u32 handle, u32 arg0, u32 arg1, +nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, + u32 handle, u32 arg0, u32 arg1, struct nouveau_channel **pchan) { + struct nouveau_cli *cli = (void *)nvif_client(&device->base); + bool super; int ret; - ret = nouveau_channel_ind(drm, cli, parent, handle, arg0, pchan); + /* hack until fencenv50 is fixed, and agp access relaxed */ + super = cli->base.super; + cli->base.super = true; + + ret = nouveau_channel_ind(drm, device, handle, arg0, pchan); if (ret) { - NV_DEBUG(cli, "ib channel create, %d\n", ret); - ret = nouveau_channel_dma(drm, cli, parent, handle, pchan); + NV_PRINTK(debug, cli, "ib channel create, %d\n", ret); + ret = nouveau_channel_dma(drm, device, handle, pchan); if (ret) { - NV_DEBUG(cli, "dma channel create, %d\n", ret); - return ret; + NV_PRINTK(debug, cli, "dma channel create, %d\n", ret); + goto done; } } ret = nouveau_channel_init(*pchan, arg0, arg1); if (ret) { - NV_ERROR(cli, "channel failed to initialise, %d\n", ret); + NV_PRINTK(error, cli, "channel failed to initialise, %d\n", ret); nouveau_channel_del(pchan); - return ret; } - return 0; +done: + cli->base.super = super; + return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h index 40f97e2c47b6..8309c24ee698 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.h +++ b/drivers/gpu/drm/nouveau/nouveau_chan.h @@ -1,20 +1,23 @@ #ifndef __NOUVEAU_CHAN_H__ #define __NOUVEAU_CHAN_H__ -struct nouveau_cli; +#include <nvif/object.h> +struct nvif_device; struct nouveau_channel { - struct nouveau_cli *cli; + struct nvif_device *device; struct nouveau_drm *drm; - u32 handle; - u32 vram; - u32 gart; + int chid; + + struct nvif_object vram; + struct nvif_object gart; + struct nvif_object nvsw; struct { struct nouveau_bo *buffer; struct nouveau_vma vma; - u32 handle; + struct nvif_object ctxdma; } push; /* TODO: this will be reworked in the near future */ @@ -34,14 +37,16 @@ struct nouveau_channel { u32 user_get; u32 user_put; - struct nouveau_object *object; + struct nvif_object *object; }; -int nouveau_channel_new(struct nouveau_drm *, struct nouveau_cli *, - u32 parent, u32 handle, u32 arg0, u32 arg1, +int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, + u32 handle, u32 arg0, u32 arg1, struct nouveau_channel **); void nouveau_channel_del(struct nouveau_channel **); int nouveau_channel_idle(struct nouveau_channel *); +extern int nouveau_vram_pushbuf; + #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 1fa222e8f007..c8ac9482cf2e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -42,20 +42,18 @@ #include "nouveau_encoder.h" #include "nouveau_crtc.h" -#include <subdev/i2c.h> -#include <subdev/gpio.h> -#include <engine/disp.h> +#include <nvif/event.h> MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); -static int nouveau_tv_disable = 0; +int nouveau_tv_disable = 0; module_param_named(tv_disable, nouveau_tv_disable, int, 0400); MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status"); -static int nouveau_ignorelid = 0; +int nouveau_ignorelid = 0; module_param_named(ignorelid, nouveau_ignorelid, int, 0400); MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)"); -static int nouveau_duallink = 1; +int nouveau_duallink = 1; module_param_named(duallink, nouveau_duallink, int, 0400); struct nouveau_encoder * @@ -63,7 +61,7 @@ find_encoder(struct drm_connector *connector, int type) { struct drm_device *dev = connector->dev; struct nouveau_encoder *nv_encoder; - struct drm_mode_object *obj; + struct drm_encoder *enc; int i, id; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { @@ -71,10 +69,10 @@ find_encoder(struct drm_connector *connector, int type) if (!id) break; - obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); - if (!obj) + enc = drm_encoder_find(dev, id); + if (!enc) continue; - nv_encoder = nouveau_encoder(obj_to_encoder(obj)); + nv_encoder = nouveau_encoder(enc); if (type == DCB_OUTPUT_ANY || (nv_encoder->dcb && nv_encoder->dcb->type == type)) @@ -102,9 +100,9 @@ static void nouveau_connector_destroy(struct drm_connector *connector) { struct nouveau_connector *nv_connector = nouveau_connector(connector); - nouveau_event_ref(NULL, &nv_connector->hpd); + nvif_notify_fini(&nv_connector->hpd); kfree(nv_connector->edid); - drm_sysfs_connector_remove(connector); + drm_connector_unregister(connector); drm_connector_cleanup(connector); if (nv_connector->aux.transfer) drm_dp_aux_unregister(&nv_connector->aux); @@ -117,9 +115,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); + struct nouveau_gpio *gpio = nvkm_gpio(&drm->device); struct nouveau_encoder *nv_encoder; - struct drm_mode_object *obj; + struct drm_encoder *encoder; int i, panel = -ENODEV; /* eDP panels need powering on by us (if the VBIOS doesn't default it @@ -139,10 +137,10 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) if (id == 0) break; - obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); - if (!obj) + encoder = drm_encoder_find(dev, id); + if (!encoder) continue; - nv_encoder = nouveau_encoder(obj_to_encoder(obj)); + nv_encoder = nouveau_encoder(encoder); if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { int ret = nouveau_dp_detect(nv_encoder); @@ -206,7 +204,7 @@ nouveau_connector_set_encoder(struct drm_connector *connector, return; nv_connector->detected_encoder = nv_encoder; - if (nv_device(drm->device)->card_type >= NV_50) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { connector->interlace_allowed = true; connector->doublescan_allowed = true; } else @@ -216,9 +214,8 @@ nouveau_connector_set_encoder(struct drm_connector *connector, connector->interlace_allowed = false; } else { connector->doublescan_allowed = true; - if (nv_device(drm->device)->card_type == NV_20 || - ((nv_device(drm->device)->card_type == NV_10 || - nv_device(drm->device)->card_type == NV_11) && + if (drm->device.info.family == NV_DEVICE_INFO_V0_KELVIN || + (drm->device.info.family == NV_DEVICE_INFO_V0_CELSIUS && (dev->pdev->device & 0x0ff0) != 0x0100 && (dev->pdev->device & 0x0ff0) != 0x0150)) /* HW is broken */ @@ -802,11 +799,11 @@ get_tmds_link_bandwidth(struct drm_connector *connector) struct dcb_output *dcb = nv_connector->detected_encoder->dcb; if (dcb->location != DCB_LOC_ON_CHIP || - nv_device(drm->device)->chipset >= 0x46) + drm->device.info.chipset >= 0x46) return 165000; - else if (nv_device(drm->device)->chipset >= 0x40) + else if (drm->device.info.chipset >= 0x40) return 155000; - else if (nv_device(drm->device)->chipset >= 0x18) + else if (drm->device.info.chipset >= 0x18) return 135000; else return 112000; @@ -939,18 +936,19 @@ nouveau_connector_funcs_dp = { .force = nouveau_connector_force }; -static void -nouveau_connector_hotplug_work(struct work_struct *work) +static int +nouveau_connector_hotplug(struct nvif_notify *notify) { struct nouveau_connector *nv_connector = - container_of(work, typeof(*nv_connector), work); + container_of(notify, typeof(*nv_connector), hpd); struct drm_connector *connector = &nv_connector->base; struct nouveau_drm *drm = nouveau_drm(connector->dev); + const struct nvif_notify_conn_rep_v0 *rep = notify->data; const char *name = connector->name; - if (nv_connector->status & NVKM_HPD_IRQ) { + if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) { } else { - bool plugged = (nv_connector->status != NVKM_HPD_UNPLUG); + bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG); NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name); @@ -961,16 +959,7 @@ nouveau_connector_hotplug_work(struct work_struct *work) drm_helper_hpd_irq_event(connector->dev); } - nouveau_event_get(nv_connector->hpd); -} - -static int -nouveau_connector_hotplug(void *data, u32 type, int index) -{ - struct nouveau_connector *nv_connector = data; - nv_connector->status = type; - schedule_work(&nv_connector->work); - return NVKM_EVENT_DROP; + return NVIF_NOTIFY_KEEP; } static ssize_t @@ -1040,7 +1029,6 @@ nouveau_connector_create(struct drm_device *dev, int index) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); struct nouveau_connector *nv_connector = NULL; - struct nouveau_disp *pdisp = nouveau_disp(drm->device); struct drm_connector *connector; int type, ret = 0; bool dummy; @@ -1194,7 +1182,7 @@ nouveau_connector_create(struct drm_device *dev, int index) switch (nv_connector->type) { case DCB_CONNECTOR_VGA: - if (nv_device(drm->device)->card_type >= NV_50) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { drm_object_attach_property(&connector->base, dev->mode_config.scaling_mode_property, nv_connector->scaling_mode); @@ -1226,16 +1214,20 @@ nouveau_connector_create(struct drm_device *dev, int index) break; } - ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index, - nouveau_connector_hotplug, - nv_connector, &nv_connector->hpd); + ret = nvif_notify_init(&disp->disp, NULL, nouveau_connector_hotplug, + true, NV04_DISP_NTFY_CONN, + &(struct nvif_notify_conn_req_v0) { + .mask = NVIF_NOTIFY_CONN_V0_ANY, + .conn = index, + }, + sizeof(struct nvif_notify_conn_req_v0), + sizeof(struct nvif_notify_conn_rep_v0), + &nv_connector->hpd); if (ret) connector->polled = DRM_CONNECTOR_POLL_CONNECT; else connector->polled = DRM_CONNECTOR_POLL_HPD; - INIT_WORK(&nv_connector->work, nouveau_connector_hotplug_work); - - drm_sysfs_connector_add(connector); + drm_connector_register(connector); return connector; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 8861b6c579ad..629a380c7085 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -27,14 +27,12 @@ #ifndef __NOUVEAU_CONNECTOR_H__ #define __NOUVEAU_CONNECTOR_H__ +#include <nvif/notify.h> + #include <drm/drm_edid.h> #include <drm/drm_dp_helper.h> #include "nouveau_crtc.h" -#include <core/event.h> - -#include <subdev/bios.h> - struct nouveau_i2c_port; enum nouveau_underscan_type { @@ -67,9 +65,7 @@ struct nouveau_connector { u8 index; u8 *dcb; - struct nouveau_eventh *hpd; - u32 status; - struct work_struct work; + struct nvif_notify hpd; struct drm_dp_aux aux; @@ -109,4 +105,8 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) struct drm_connector * nouveau_connector_create(struct drm_device *, int index); +extern int nouveau_tv_disable; +extern int nouveau_ignorelid; +extern int nouveau_duallink; + #endif /* __NOUVEAU_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index a0534489d23f..f19cb1c5fc5a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -27,10 +27,13 @@ #ifndef __NOUVEAU_CRTC_H__ #define __NOUVEAU_CRTC_H__ +#include <nvif/notify.h> + struct nouveau_crtc { struct drm_crtc base; int index; + struct nvif_notify vblank; uint32_t dpms_saved_fp_control; uint32_t fp_users; @@ -46,7 +49,7 @@ struct nouveau_crtc { int cpp; bool blanked; uint32_t offset; - uint32_t tile_flags; + uint32_t handle; } fb; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 47ad74255bf1..a88e6927f571 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -27,6 +27,8 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <nvif/class.h> + #include "nouveau_fbcon.h" #include "dispnv04/hw.h" #include "nouveau_crtc.h" @@ -37,35 +39,42 @@ #include "nouveau_fence.h" -#include <engine/disp.h> - -#include <core/class.h> +#include <nvif/event.h> static int -nouveau_display_vblank_handler(void *data, u32 type, int head) +nouveau_display_vblank_handler(struct nvif_notify *notify) { - struct nouveau_drm *drm = data; - drm_handle_vblank(drm->dev, head); - return NVKM_EVENT_KEEP; + struct nouveau_crtc *nv_crtc = + container_of(notify, typeof(*nv_crtc), vblank); + drm_handle_vblank(nv_crtc->base.dev, nv_crtc->index); + return NVIF_NOTIFY_KEEP; } int nouveau_display_vblank_enable(struct drm_device *dev, int head) { - struct nouveau_display *disp = nouveau_display(dev); - if (disp) { - nouveau_event_get(disp->vblank[head]); - return 0; + struct drm_crtc *crtc; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + if (nv_crtc->index == head) { + nvif_notify_get(&nv_crtc->vblank); + return 0; + } } - return -EIO; + return -EINVAL; } void nouveau_display_vblank_disable(struct drm_device *dev, int head) { - struct nouveau_display *disp = nouveau_display(dev); - if (disp) - nouveau_event_put(disp->vblank[head]); + struct drm_crtc *crtc; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + if (nv_crtc->index == head) { + nvif_notify_put(&nv_crtc->vblank); + return; + } + } } static inline int @@ -86,17 +95,22 @@ int nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) { - const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index; + struct { + struct nv04_disp_mthd_v0 base; + struct nv04_disp_scanoutpos_v0 scan; + } args = { + .base.method = NV04_DISP_SCANOUTPOS, + .base.head = nouveau_crtc(crtc)->index, + }; struct nouveau_display *disp = nouveau_display(crtc->dev); - struct nv04_display_scanoutpos args; int ret, retry = 1; do { - ret = nv_exec(disp->core, mthd, &args, sizeof(args)); + ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); if (ret != 0) return 0; - if (args.vline) { + if (args.scan.vline) { ret |= DRM_SCANOUTPOS_ACCURATE; ret |= DRM_SCANOUTPOS_VALID; break; @@ -105,13 +119,14 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, if (retry) ndelay(crtc->linedur_ns); } while (retry--); - *hpos = args.hline; - *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline); - if (stime) *stime = ns_to_ktime(args.time[0]); - if (etime) *etime = ns_to_ktime(args.time[1]); + *hpos = args.scan.hline; + *vpos = calc(args.scan.vblanks, args.scan.vblanke, + args.scan.vtotal, args.scan.vline); + if (stime) *stime = ns_to_ktime(args.scan.time[0]); + if (etime) *etime = ns_to_ktime(args.scan.time[1]); if (*vpos < 0) - ret |= DRM_SCANOUTPOS_INVBL; + ret |= DRM_SCANOUTPOS_IN_VBLANK; return ret; } @@ -151,16 +166,13 @@ nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error, static void nouveau_display_vblank_fini(struct drm_device *dev) { - struct nouveau_display *disp = nouveau_display(dev); - int i; + struct drm_crtc *crtc; drm_vblank_cleanup(dev); - if (disp->vblank) { - for (i = 0; i < dev->mode_config.num_crtc; i++) - nouveau_event_ref(NULL, &disp->vblank[i]); - kfree(disp->vblank); - disp->vblank = NULL; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + nvif_notify_fini(&nv_crtc->vblank); } } @@ -168,19 +180,20 @@ static int nouveau_display_vblank_init(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_disp *pdisp = nouveau_disp(drm->device); - int ret, i; - - disp->vblank = kzalloc(dev->mode_config.num_crtc * - sizeof(*disp->vblank), GFP_KERNEL); - if (!disp->vblank) - return -ENOMEM; + struct drm_crtc *crtc; + int ret; - for (i = 0; i < dev->mode_config.num_crtc; i++) { - ret = nouveau_event_new(pdisp->vblank, 1, i, - nouveau_display_vblank_handler, - drm, &disp->vblank[i]); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + ret = nvif_notify_init(&disp->disp, NULL, + nouveau_display_vblank_handler, false, + NV04_DISP_NTFY_VBLANK, + &(struct nvif_notify_head_req_v0) { + .head = nv_crtc->index, + }, + sizeof(struct nvif_notify_head_req_v0), + sizeof(struct nvif_notify_head_rep_v0), + &nv_crtc->vblank); if (ret) { nouveau_display_vblank_fini(dev); return ret; @@ -200,6 +213,10 @@ 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); @@ -229,63 +246,24 @@ nouveau_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct nouveau_bo *nvbo) { - struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_display *disp = nouveau_display(dev); struct drm_framebuffer *fb = &nv_fb->base; int ret; drm_helper_mode_fill_fb_struct(fb, mode_cmd); nv_fb->nvbo = nvbo; - if (nv_device(drm->device)->card_type >= NV_50) { - u32 tile_flags = nouveau_bo_tile_layout(nvbo); - if (tile_flags == 0x7a00 || - tile_flags == 0xfe00) - nv_fb->r_dma = NvEvoFB32; - else - if (tile_flags == 0x7000) - nv_fb->r_dma = NvEvoFB16; - else - nv_fb->r_dma = NvEvoVRAM_LP; - - 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 (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) { - NV_ERROR(drm, "framebuffer requires contiguous bo\n"); - return -EINVAL; - } - - if (nv_device(drm->device)->chipset == 0x50) - nv_fb->r_format |= (tile_flags << 8); - - if (!tile_flags) { - if (nv_device(drm->device)->card_type < NV_D0) - nv_fb->r_pitch = 0x00100000 | fb->pitches[0]; - else - nv_fb->r_pitch = 0x01000000 | fb->pitches[0]; - } else { - u32 mode = nvbo->tile_mode; - if (nv_device(drm->device)->card_type >= NV_C0) - mode >>= 4; - nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode; - } - } - ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); - if (ret) { + if (ret) return ret; + + if (disp->fb_ctor) { + ret = disp->fb_ctor(fb); + if (ret) + disp->fb_dtor(fb); } - return 0; + return ret; } static struct drm_framebuffer * @@ -393,7 +371,7 @@ nouveau_display_init(struct drm_device *dev) /* enable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - if (conn->hpd) nouveau_event_get(conn->hpd); + nvif_notify_get(&conn->hpd); } return ret; @@ -404,37 +382,32 @@ nouveau_display_fini(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); struct drm_connector *connector; + int head; + + /* 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); /* disable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - if (conn->hpd) nouveau_event_put(conn->hpd); + nvif_notify_put(&conn->hpd); } drm_kms_helper_poll_disable(dev); disp->fini(dev); } -int -nouveau_display_create(struct drm_device *dev) +static void +nouveau_display_create_properties(struct drm_device *dev) { - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_display *disp; - int ret, gen; - - disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL); - if (!disp) - return -ENOMEM; - - drm_mode_config_init(dev); - drm_mode_create_scaling_mode_property(dev); - drm_mode_create_dvi_i_properties(dev); + struct nouveau_display *disp = nouveau_display(dev); + int gen; - if (nv_device(drm->device)->card_type < NV_50) + if (disp->disp.oclass < NV50_DISP) gen = 0; else - if (nv_device(drm->device)->card_type < NV_D0) + if (disp->disp.oclass < GF110_DISP) gen = 1; else gen = 2; @@ -449,26 +422,43 @@ nouveau_display_create(struct drm_device *dev) disp->underscan_vborder_property = drm_property_create_range(dev, 0, "underscan vborder", 0, 128); - if (gen >= 1) { - /* -90..+90 */ - disp->vibrant_hue_property = - drm_property_create_range(dev, 0, "vibrant hue", 0, 180); + if (gen < 1) + return; - /* -100..+100 */ - disp->color_vibrance_property = - drm_property_create_range(dev, 0, "color vibrance", 0, 200); - } + /* -90..+90 */ + disp->vibrant_hue_property = + drm_property_create_range(dev, 0, "vibrant hue", 0, 180); + + /* -100..+100 */ + disp->color_vibrance_property = + drm_property_create_range(dev, 0, "color vibrance", 0, 200); +} + +int +nouveau_display_create(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_display *disp; + int ret; + + disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL); + if (!disp) + return -ENOMEM; + + drm_mode_config_init(dev); + drm_mode_create_scaling_mode_property(dev); + drm_mode_create_dvi_i_properties(dev); dev->mode_config.funcs = &nouveau_mode_config_funcs; - dev->mode_config.fb_base = nv_device_resource_start(device, 1); + dev->mode_config.fb_base = nv_device_resource_start(nvkm_device(&drm->device), 1); dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; - if (nv_device(drm->device)->card_type < NV_10) { + if (drm->device.info.family < NV_DEVICE_INFO_V0_CELSIUS) { dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; } else - if (nv_device(drm->device)->card_type < NV_50) { + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; } else { @@ -479,7 +469,7 @@ nouveau_display_create(struct drm_device *dev) dev->mode_config.preferred_depth = 24; dev->mode_config.prefer_shadow = 1; - if (nv_device(drm->device)->chipset < 0x11) + if (drm->device.info.chipset < 0x11) dev->mode_config.async_page_flip = false; else dev->mode_config.async_page_flip = true; @@ -487,29 +477,30 @@ nouveau_display_create(struct drm_device *dev) drm_kms_helper_poll_init(dev); drm_kms_helper_poll_disable(dev); - if (drm->vbios.dcb.entries) { + if (nouveau_modeset != 2 && drm->vbios.dcb.entries) { static const u16 oclass[] = { - GM107_DISP_CLASS, - NVF0_DISP_CLASS, - NVE0_DISP_CLASS, - NVD0_DISP_CLASS, - NVA3_DISP_CLASS, - NV94_DISP_CLASS, - NVA0_DISP_CLASS, - NV84_DISP_CLASS, - NV50_DISP_CLASS, - NV04_DISP_CLASS, + GM107_DISP, + GK110_DISP, + GK104_DISP, + GF110_DISP, + GT214_DISP, + GT206_DISP, + GT200_DISP, + G82_DISP, + NV50_DISP, + NV04_DISP, }; int i; for (i = 0, ret = -ENODEV; ret && i < ARRAY_SIZE(oclass); i++) { - ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, - NVDRM_DISPLAY, oclass[i], - NULL, 0, &disp->core); + ret = nvif_object_init(nvif_object(&drm->device), NULL, + NVDRM_DISPLAY, oclass[i], + NULL, 0, &disp->disp); } if (ret == 0) { - if (nv_mclass(disp->core) < NV50_DISP_CLASS) + nouveau_display_create_properties(dev); + if (disp->disp.oclass < NV50_DISP) ret = nv04_display_create(dev); else ret = nv50_display_create(dev); @@ -542,7 +533,6 @@ void nouveau_display_destroy(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); - struct nouveau_drm *drm = nouveau_drm(dev); nouveau_backlight_exit(dev); nouveau_display_vblank_fini(dev); @@ -553,21 +543,19 @@ nouveau_display_destroy(struct drm_device *dev) if (disp->dtor) disp->dtor(dev); - nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_DISPLAY); + nvif_object_fini(&disp->disp); nouveau_drm(dev)->display = NULL; kfree(disp); } int -nouveau_display_suspend(struct drm_device *dev) +nouveau_display_suspend(struct drm_device *dev, bool runtime) { - struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; nouveau_display_fini(dev); - NV_INFO(drm, "unpinning framebuffer(s)...\n"); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; @@ -589,12 +577,13 @@ nouveau_display_suspend(struct drm_device *dev) } void -nouveau_display_repin(struct drm_device *dev) +nouveau_display_resume(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; - int ret; + int ret, head; + /* re-pin fb/cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; @@ -602,7 +591,9 @@ nouveau_display_repin(struct drm_device *dev) if (!nouveau_fb || !nouveau_fb->nvbo) continue; - nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM); + if (ret) + NV_ERROR(drm, "Could not pin framebuffer\n"); } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -614,12 +605,7 @@ nouveau_display_repin(struct drm_device *dev) if (ret) NV_ERROR(drm, "Could not pin/map cursor.\n"); } -} -void -nouveau_display_resume(struct drm_device *dev) -{ - struct drm_crtc *crtc; nouveau_display_init(dev); /* Force CLUT to get re-loaded during modeset */ @@ -629,6 +615,17 @@ nouveau_display_resume(struct drm_device *dev) nv_crtc->lut.depth = 0; } + /* Make sure that drm and hw vblank irqs get resumed if needed. */ + for (head = 0; head < dev->mode_config.num_crtc; head++) + drm_vblank_on(dev, head); + + /* This should ensure we don't hit a locking problem when someone + * wakes us up via a connector. We should never go into suspend + * while the display is on anyways. + */ + if (runtime) + return; + drm_helper_resume_force_mode(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -660,7 +657,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, spin_unlock_irqrestore(&dev->event_lock, flags); /* Synchronize with the old framebuffer */ - ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan); + ret = nouveau_fence_sync(old_bo, chan, false, false); if (ret) goto fail; @@ -669,7 +666,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, if (ret) goto fail; - if (nv_device(drm->device)->card_type < NV_C0) + 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); @@ -698,12 +695,15 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; struct nouveau_page_flip_state *s; - struct nouveau_channel *chan = drm->channel; + struct nouveau_channel *chan; + struct nouveau_cli *cli; struct nouveau_fence *fence; int ret; - if (!drm->channel) + chan = drm->channel; + if (!chan) return -ENODEV; + cli = (void *)nvif_client(&chan->device->base); s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) @@ -715,20 +715,25 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, goto fail_free; } - mutex_lock(&chan->cli->mutex); - - /* synchronise rendering channel with the kernel's channel */ - spin_lock(&new_bo->bo.bdev->fence_lock); - fence = nouveau_fence_ref(new_bo->bo.sync_obj); - spin_unlock(&new_bo->bo.bdev->fence_lock); - ret = nouveau_fence_sync(fence, chan); - nouveau_fence_unref(&fence); + mutex_lock(&cli->mutex); + ret = ttm_bo_reserve(&new_bo->bo, true, false, false, NULL); if (ret) goto fail_unpin; - ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); - if (ret) + /* synchronise rendering channel with the kernel's channel */ + ret = nouveau_fence_sync(new_bo, chan, false, true); + if (ret) { + ttm_bo_unreserve(&new_bo->bo); goto fail_unpin; + } + + if (new_bo != old_bo) { + ttm_bo_unreserve(&new_bo->bo); + + ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); + if (ret) + goto fail_unpin; + } /* Initialize a page flip struct */ *s = (struct nouveau_page_flip_state) @@ -740,7 +745,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, drm_vblank_get(dev, nouveau_crtc(crtc)->index); /* Emit a page flip */ - if (nv_device(drm->device)->card_type >= NV_50) { + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ret = nv50_display_flip_next(crtc, fb, chan, swap_interval); if (ret) goto fail_unreserve; @@ -769,12 +774,12 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); if (ret) goto fail_unreserve; - mutex_unlock(&chan->cli->mutex); + mutex_unlock(&cli->mutex); /* Update the crtc struct and cleanup */ crtc->primary->fb = fb; - nouveau_bo_fence(old_bo, fence); + nouveau_bo_fence(old_bo, fence, false); ttm_bo_unreserve(&old_bo->bo); if (old_bo != new_bo) nouveau_bo_unpin(old_bo); @@ -785,7 +790,7 @@ fail_unreserve: drm_vblank_put(dev, nouveau_crtc(crtc)->index); ttm_bo_unreserve(&old_bo->bo); fail_unpin: - mutex_unlock(&chan->cli->mutex); + mutex_unlock(&cli->mutex); if (old_bo != new_bo) nouveau_bo_unpin(new_bo); fail_free: @@ -815,7 +820,7 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); if (s->event) { /* Vblank timestamps/counts are only correct on >= NV-50 */ - if (nv_device(drm->device)->card_type >= NV_50) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) crtcid = s->crtc; drm_send_vblank_event(dev, crtcid, s->event); @@ -841,7 +846,7 @@ nouveau_flip_complete(void *data) struct nouveau_page_flip_state state; if (!nouveau_finish_page_flip(chan, &state)) { - if (nv_device(drm->device)->card_type < NV_50) { + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { nv_set_crtc_base(drm->dev, state.crtc, state.offset + state.y * state.pitch + state.x * state.bpp / 8); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index a71cf77e55b2..be3d5947c6be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -9,9 +9,11 @@ struct nouveau_framebuffer { struct drm_framebuffer base; struct nouveau_bo *nvbo; struct nouveau_vma vma; - u32 r_dma; + u32 r_handle; u32 r_format; u32 r_pitch; + struct nvif_object h_base[4]; + struct nvif_object h_core; }; static inline struct nouveau_framebuffer * @@ -36,8 +38,10 @@ struct nouveau_display { int (*init)(struct drm_device *); void (*fini)(struct drm_device *); - struct nouveau_object *core; - struct nouveau_eventh **vblank; + int (*fb_ctor)(struct drm_framebuffer *); + void (*fb_dtor)(struct drm_framebuffer *); + + struct nvif_object disp; struct drm_property *dithering_mode; struct drm_property *dithering_depth; @@ -59,9 +63,8 @@ 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); -int nouveau_display_suspend(struct drm_device *dev); -void nouveau_display_repin(struct drm_device *dev); -void nouveau_display_resume(struct drm_device *dev); +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 *, int); void nouveau_display_vblank_disable(struct drm_device *, int); int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index c177272152e2..8508603cc8c3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -24,8 +24,6 @@ * */ -#include <core/client.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -54,9 +52,9 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout) { uint64_t val; - val = nv_ro32(chan->object, chan->user_get); + val = nvif_rd32(chan, chan->user_get); if (chan->user_get_hi) - val |= (uint64_t)nv_ro32(chan->object, chan->user_get_hi) << 32; + val |= (uint64_t)nvif_rd32(chan, chan->user_get_hi) << 32; /* reset counter as long as GET is still advancing, this is * to avoid misdetecting a GPU lockup if the GPU happens to @@ -84,12 +82,13 @@ void nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo, int delta, int length) { + struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base); struct nouveau_bo *pb = chan->push.buffer; struct nouveau_vma *vma; int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base; u64 offset; - vma = nouveau_bo_vma_find(bo, nv_client(chan->cli)->vm); + vma = nouveau_bo_vma_find(bo, cli->vm); BUG_ON(!vma); offset = vma->offset + delta; @@ -104,7 +103,7 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo, /* Flush writes. */ nouveau_bo_rd32(pb, 0); - nv_wo32(chan->object, 0x8c, chan->dma.ib_put); + nvif_wr32(chan, 0x8c, chan->dma.ib_put); chan->dma.ib_free--; } @@ -114,7 +113,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count) uint32_t cnt = 0, prev_get = 0; while (chan->dma.ib_free < count) { - uint32_t get = nv_ro32(chan->object, 0x88); + uint32_t get = nvif_rd32(chan, 0x88); if (get != prev_get) { prev_get = get; cnt = 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index dc0e0c5cadb4..8da0a272c45a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -58,31 +58,14 @@ enum { FermiSw = 5, /* DO NOT CHANGE (well.. 6/7 will work...) */ }; -/* Object handles. */ +/* Object handles - for stuff that's doesn't use handle == oclass. */ enum { - NvM2MF = 0x80000001, NvDmaFB = 0x80000002, NvDmaTT = 0x80000003, NvNotify0 = 0x80000006, - Nv2D = 0x80000007, - NvCtxSurf2D = 0x80000008, - NvRop = 0x80000009, - NvImagePatt = 0x8000000a, - NvClipRect = 0x8000000b, - NvGdiRect = 0x8000000c, - NvImageBlit = 0x8000000d, - NvSw = 0x8000000e, NvSema = 0x8000000f, NvEvoSema0 = 0x80000010, NvEvoSema1 = 0x80000011, - NvNotify1 = 0x80000012, - - /* G80+ display objects */ - NvEvoVRAM = 0x01000000, - NvEvoFB16 = 0x01000001, - NvEvoFB32 = 0x01000002, - NvEvoVRAM_LP = 0x01000003, - NvEvoSync = 0xcafe0000 }; #define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039 @@ -157,7 +140,7 @@ BEGIN_IMC0(struct nouveau_channel *chan, int subc, int mthd, u16 data) #define WRITE_PUT(val) do { \ mb(); \ nouveau_bo_rd32(chan->push.buffer, 0); \ - nv_wo32(chan->object, chan->user_put, ((val) << 2) + chan->push.vma.offset); \ + nvif_wr32(chan, chan->user_put, ((val) << 2) + chan->push.vma.offset); \ } while (0) static inline void diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 5675ffc175ae..c5137cccce7d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -30,11 +30,6 @@ #include "nouveau_encoder.h" #include "nouveau_crtc.h" -#include <core/class.h> - -#include <subdev/gpio.h> -#include <subdev/i2c.h> - static void nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch, u8 *dpcd) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index c9428c943afb..57238076049f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -27,21 +27,14 @@ #include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/vga_switcheroo.h> + #include "drmP.h" #include "drm_crtc_helper.h" + #include <core/device.h> -#include <core/client.h> #include <core/gpuobj.h> -#include <core/class.h> #include <core/option.h> -#include <engine/device.h> -#include <engine/disp.h> -#include <engine/fifo.h> -#include <engine/software.h> - -#include <subdev/vm.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_ttm.h" @@ -57,6 +50,8 @@ #include "nouveau_fbcon.h" #include "nouveau_fence.h" #include "nouveau_debugfs.h" +#include "nouveau_usif.h" +#include "nouveau_connector.h" MODULE_PARM_DESC(config, "option string to pass to driver core"); static char *nouveau_config; @@ -79,7 +74,9 @@ MODULE_PARM_DESC(runpm, "disable (0), force enable (1), optimus only default (-1 int nouveau_runtime_pm = -1; module_param_named(runpm, nouveau_runtime_pm, int, 0400); -static struct drm_driver driver; +static struct drm_driver driver_stub; +static struct drm_driver driver_pci; +static struct drm_driver driver_platform; static u64 nouveau_pci_name(struct pci_dev *pdev) @@ -109,40 +106,37 @@ static int nouveau_cli_create(u64 name, const char *sname, int size, void **pcli) { - struct nouveau_cli *cli; - int ret; - - *pcli = NULL; - ret = nouveau_client_create_(sname, name, nouveau_config, - nouveau_debug, size, pcli); - cli = *pcli; - if (ret) { - if (cli) - nouveau_client_destroy(&cli->base); - *pcli = NULL; + struct nouveau_cli *cli = *pcli = kzalloc(size, GFP_KERNEL); + if (cli) { + int ret = nvif_client_init(NULL, NULL, sname, name, + nouveau_config, nouveau_debug, + &cli->base); + if (ret == 0) { + mutex_init(&cli->mutex); + usif_client_init(cli); + } return ret; } - - mutex_init(&cli->mutex); - return 0; + return -ENOMEM; } static void nouveau_cli_destroy(struct nouveau_cli *cli) { - struct nouveau_object *client = nv_object(cli); - nouveau_vm_ref(NULL, &cli->base.vm, NULL); - nouveau_client_fini(&cli->base, false); - atomic_set(&client->refcount, 1); - nouveau_object_ref(NULL, &client); + nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL); + nvif_client_fini(&cli->base); + usif_client_fini(cli); } static void nouveau_accel_fini(struct nouveau_drm *drm) { - nouveau_gpuobj_ref(NULL, &drm->notify); nouveau_channel_del(&drm->channel); + nvif_object_fini(&drm->ntfy); + nouveau_gpuobj_ref(NULL, &drm->notify); + nvif_object_fini(&drm->nvsw); nouveau_channel_del(&drm->cechan); + nvif_object_fini(&drm->ttm.copy); if (drm->fence) nouveau_fence(drm)->dtor(drm); } @@ -150,46 +144,71 @@ nouveau_accel_fini(struct nouveau_drm *drm) static void nouveau_accel_init(struct nouveau_drm *drm) { - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_object *object; + struct nvif_device *device = &drm->device; u32 arg0, arg1; - int ret; + u32 sclass[16]; + int ret, i; - if (nouveau_noaccel || !nouveau_fifo(device) /*XXX*/) + if (nouveau_noaccel) return; /* initialise synchronisation routines */ - if (device->card_type < NV_10) ret = nv04_fence_create(drm); - else if (device->card_type < NV_11 || - device->chipset < 0x17) ret = nv10_fence_create(drm); - else if (device->card_type < NV_50) ret = nv17_fence_create(drm); - else if (device->chipset < 0x84) ret = nv50_fence_create(drm); - else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); - else ret = nvc0_fence_create(drm); + /*XXX: this is crap, but the fence/channel stuff is a little + * backwards in some places. this will be fixed. + */ + ret = nvif_object_sclass(&device->base, sclass, ARRAY_SIZE(sclass)); + if (ret < 0) + return; + + for (ret = -ENOSYS, i = 0; ret && i < ARRAY_SIZE(sclass); i++) { + switch (sclass[i]) { + case NV03_CHANNEL_DMA: + ret = nv04_fence_create(drm); + break; + case NV10_CHANNEL_DMA: + ret = nv10_fence_create(drm); + break; + case NV17_CHANNEL_DMA: + case NV40_CHANNEL_DMA: + ret = nv17_fence_create(drm); + break; + case NV50_CHANNEL_GPFIFO: + ret = nv50_fence_create(drm); + break; + case G82_CHANNEL_GPFIFO: + ret = nv84_fence_create(drm); + break; + case FERMI_CHANNEL_GPFIFO: + case KEPLER_CHANNEL_GPFIFO_A: + ret = nvc0_fence_create(drm); + break; + default: + break; + } + } + if (ret) { NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); nouveau_accel_fini(drm); return; } - if (device->card_type >= NV_E0) { - ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, - NVDRM_CHAN + 1, - NVE0_CHANNEL_IND_ENGINE_CE0 | - NVE0_CHANNEL_IND_ENGINE_CE1, 0, - &drm->cechan); + if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { + ret = nouveau_channel_new(drm, &drm->device, NVDRM_CHAN + 1, + KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0| + KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1, + 0, &drm->cechan); if (ret) NV_ERROR(drm, "failed to create ce channel, %d\n", ret); - arg0 = NVE0_CHANNEL_IND_ENGINE_GR; + arg0 = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR; arg1 = 1; } else - if (device->chipset >= 0xa3 && - device->chipset != 0xaa && - device->chipset != 0xac) { - ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, - NVDRM_CHAN + 1, NvDmaFB, NvDmaTT, - &drm->cechan); + if (device->info.chipset >= 0xa3 && + device->info.chipset != 0xaa && + device->info.chipset != 0xac) { + ret = nouveau_channel_new(drm, &drm->device, NVDRM_CHAN + 1, + NvDmaFB, NvDmaTT, &drm->cechan); if (ret) NV_ERROR(drm, "failed to create ce channel, %d\n", ret); @@ -200,30 +219,30 @@ nouveau_accel_init(struct nouveau_drm *drm) arg1 = NvDmaTT; } - ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN, - arg0, arg1, &drm->channel); + ret = nouveau_channel_new(drm, &drm->device, NVDRM_CHAN, arg0, arg1, + &drm->channel); if (ret) { NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); nouveau_accel_fini(drm); return; } - ret = nouveau_object_new(nv_object(drm), NVDRM_CHAN, NVDRM_NVSW, - nouveau_abi16_swclass(drm), NULL, 0, &object); + ret = nvif_object_init(drm->channel->object, NULL, NVDRM_NVSW, + nouveau_abi16_swclass(drm), NULL, 0, &drm->nvsw); if (ret == 0) { - struct nouveau_software_chan *swch = (void *)object->parent; + struct nouveau_software_chan *swch; ret = RING_SPACE(drm->channel, 2); if (ret == 0) { - if (device->card_type < NV_C0) { + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { BEGIN_NV04(drm->channel, NvSubSw, 0, 1); OUT_RING (drm->channel, NVDRM_NVSW); } else - if (device->card_type < NV_E0) { + if (device->info.family < NV_DEVICE_INFO_V0_KEPLER) { BEGIN_NVC0(drm->channel, FermiSw, 0, 1); OUT_RING (drm->channel, 0x001f0000); } } - swch = (void *)object->parent; + swch = (void *)nvkm_object(&drm->nvsw)->parent; swch->flip = nouveau_flip_complete; swch->flip_data = drm->channel; } @@ -234,24 +253,24 @@ nouveau_accel_init(struct nouveau_drm *drm) return; } - if (device->card_type < NV_C0) { - ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0, - &drm->notify); + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { + ret = nouveau_gpuobj_new(nvkm_object(&drm->device), NULL, 32, + 0, 0, &drm->notify); if (ret) { NV_ERROR(drm, "failed to allocate notifier, %d\n", ret); nouveau_accel_fini(drm); return; } - ret = nouveau_object_new(nv_object(drm), - drm->channel->handle, NvNotify0, - 0x003d, &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, + ret = nvif_object_init(drm->channel->object, NULL, NvNotify0, + NV_DMA_IN_MEMORY, + &(struct nv_dma_v0) { + .target = NV_DMA_V0_TARGET_VRAM, + .access = NV_DMA_V0_ACCESS_RDWR, .start = drm->notify->addr, .limit = drm->notify->addr + 31 - }, sizeof(struct nv_dma_class), - &object); + }, sizeof(struct nv_dma_v0), + &drm->ntfy); if (ret) { nouveau_accel_fini(drm); return; @@ -294,7 +313,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev, #ifdef CONFIG_X86 boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; #endif - remove_conflicting_framebuffers(aper, "nouveaufb", boot); + if (nouveau_modeset != 2) + remove_conflicting_framebuffers(aper, "nouveaufb", boot); kfree(aper); ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI, @@ -305,7 +325,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev, pci_set_master(pdev); - ret = drm_get_pci_dev(pdev, pent, &driver); + ret = drm_get_pci_dev(pdev, pent, &driver_pci); if (ret) { nouveau_object_ref(NULL, (struct nouveau_object **)&device); return ret; @@ -348,7 +368,6 @@ static int nouveau_drm_load(struct drm_device *dev, unsigned long flags) { struct pci_dev *pdev = dev->pdev; - struct nouveau_device *device; struct nouveau_drm *drm; int ret; @@ -359,7 +378,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) dev->dev_private = drm; drm->dev = dev; - nouveau_client(drm)->debug = nouveau_dbgopt(nouveau_debug, "DRM"); + nvkm_client(&drm->client.base)->debug = + nouveau_dbgopt(nouveau_debug, "DRM"); INIT_LIST_HEAD(&drm->clients); spin_lock_init(&drm->tile.lock); @@ -370,33 +390,34 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) * (possibly) execute vbios init tables (see nouveau_agp.h) */ if (pdev && drm_pci_device_is_agp(dev) && dev->agp) { + const u64 enables = NV_DEVICE_V0_DISABLE_IDENTIFY | + NV_DEVICE_V0_DISABLE_MMIO; /* dummy device object, doesn't init anything, but allows * agp code access to registers */ - ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, - NVDRM_DEVICE, 0x0080, - &(struct nv_device_class) { + ret = nvif_device_init(&drm->client.base.base, NULL, + NVDRM_DEVICE, NV_DEVICE, + &(struct nv_device_v0) { .device = ~0, - .disable = - ~(NV_DEVICE_DISABLE_MMIO | - NV_DEVICE_DISABLE_IDENTIFY), + .disable = ~enables, .debug0 = ~0, - }, sizeof(struct nv_device_class), - &drm->device); + }, sizeof(struct nv_device_v0), + &drm->device); if (ret) goto fail_device; nouveau_agp_reset(drm); - nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE); + nvif_device_fini(&drm->device); } - ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE, - 0x0080, &(struct nv_device_class) { + ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE, + NV_DEVICE, + &(struct nv_device_v0) { .device = ~0, .disable = 0, .debug0 = 0, - }, sizeof(struct nv_device_class), - &drm->device); + }, sizeof(struct nv_device_v0), + &drm->device); if (ret) goto fail_device; @@ -406,18 +427,19 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) * nosnoop capability. hopefully won't cause issues until a * better fix is found - assuming there is one... */ - device = nv_device(drm->device); - if (nv_device(drm->device)->chipset == 0xc1) - nv_mask(device, 0x00088080, 0x00000800, 0x00000000); + if (drm->device.info.chipset == 0xc1) + nvif_mask(&drm->device, 0x00088080, 0x00000800, 0x00000000); nouveau_vga_init(drm); nouveau_agp_init(drm); - if (device->card_type >= NV_50) { - ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), - 0x1000, &drm->client.base.vm); + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40), + 0x1000, &drm->client.vm); if (ret) goto fail_device; + + nvkm_client(&drm->client.base)->vm = drm->client.vm; } ret = nouveau_ttm_init(drm); @@ -463,6 +485,7 @@ fail_ttm: nouveau_agp_fini(drm); nouveau_vga_fini(drm); fail_device: + nvif_device_fini(&drm->device); nouveau_cli_destroy(&drm->client); return ret; } @@ -488,26 +511,37 @@ nouveau_drm_unload(struct drm_device *dev) nouveau_agp_fini(drm); nouveau_vga_fini(drm); + nvif_device_fini(&drm->device); if (drm->hdmi_device) pci_dev_put(drm->hdmi_device); nouveau_cli_destroy(&drm->client); return 0; } -static void -nouveau_drm_remove(struct pci_dev *pdev) +void +nouveau_drm_device_remove(struct drm_device *dev) { - struct drm_device *dev = pci_get_drvdata(pdev); struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_client *client; struct nouveau_object *device; dev->irq_enabled = false; - device = drm->client.base.device; + client = nvkm_client(&drm->client.base); + device = client->device; drm_put_dev(dev); nouveau_object_ref(NULL, &device); nouveau_object_debug(); } +EXPORT_SYMBOL(nouveau_drm_device_remove); + +static void +nouveau_drm_remove(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + + nouveau_drm_device_remove(dev); +} static int nouveau_do_suspend(struct drm_device *dev, bool runtime) @@ -516,9 +550,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) struct nouveau_cli *cli; int ret; - if (dev->mode_config.num_crtc && !runtime) { + if (dev->mode_config.num_crtc) { + NV_INFO(drm, "suspending console...\n"); + nouveau_fbcon_set_suspend(dev, 1); NV_INFO(drm, "suspending display...\n"); - ret = nouveau_display_suspend(dev); + ret = nouveau_display_suspend(dev, runtime); if (ret) return ret; } @@ -548,13 +584,13 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) } list_for_each_entry(cli, &drm->clients, head) { - ret = nouveau_client_fini(&cli->base, true); + ret = nvif_client_suspend(&cli->base); if (ret) goto fail_client; } NV_INFO(drm, "suspending kernel object tree...\n"); - ret = nouveau_client_fini(&drm->client.base, true); + ret = nvif_client_suspend(&drm->client.base); if (ret) goto fail_client; @@ -563,7 +599,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) fail_client: list_for_each_entry_continue_reverse(cli, &drm->clients, head) { - nouveau_client_init(&cli->base); + nvif_client_resume(&cli->base); } if (drm->fence && nouveau_fence(drm)->resume) @@ -572,7 +608,7 @@ fail_client: fail_display: if (dev->mode_config.num_crtc) { NV_INFO(drm, "resuming display...\n"); - nouveau_display_resume(dev); + nouveau_display_resume(dev, runtime); } return ret; } @@ -587,21 +623,19 @@ int nouveau_pmops_suspend(struct device *dev) drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) return 0; - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 1); - ret = nouveau_do_suspend(drm_dev, false); if (ret) return ret; pci_save_state(pdev); pci_disable_device(pdev); + pci_ignore_hotplug(pdev); pci_set_power_state(pdev, PCI_D3hot); return 0; } static int -nouveau_do_resume(struct drm_device *dev) +nouveau_do_resume(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; @@ -611,7 +645,7 @@ nouveau_do_resume(struct drm_device *dev) nouveau_agp_reset(drm); NV_INFO(drm, "resuming kernel object tree...\n"); - nouveau_client_init(&drm->client.base); + nvif_client_resume(&drm->client.base); nouveau_agp_init(drm); NV_INFO(drm, "resuming client object trees...\n"); @@ -619,14 +653,16 @@ nouveau_do_resume(struct drm_device *dev) nouveau_fence(drm)->resume(drm); list_for_each_entry(cli, &drm->clients, head) { - nouveau_client_init(&cli->base); + nvif_client_resume(&cli->base); } nouveau_run_vbios_init(dev); if (dev->mode_config.num_crtc) { NV_INFO(drm, "resuming display...\n"); - nouveau_display_repin(dev); + nouveau_display_resume(dev, runtime); + NV_INFO(drm, "resuming console...\n"); + nouveau_fbcon_set_suspend(dev, 0); } return 0; @@ -649,47 +685,21 @@ int nouveau_pmops_resume(struct device *dev) return ret; pci_set_master(pdev); - ret = nouveau_do_resume(drm_dev); - if (ret) - return ret; - - if (drm_dev->mode_config.num_crtc) { - nouveau_display_resume(drm_dev); - nouveau_fbcon_set_suspend(drm_dev, 0); - } - - return 0; + return nouveau_do_resume(drm_dev, false); } static int nouveau_pmops_freeze(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - int ret; - - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 1); - - ret = nouveau_do_suspend(drm_dev, false); - return ret; + return nouveau_do_suspend(drm_dev, false); } static int nouveau_pmops_thaw(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - int ret; - - ret = nouveau_do_resume(drm_dev); - if (ret) - return ret; - - if (drm_dev->mode_config.num_crtc) { - nouveau_display_resume(drm_dev); - nouveau_fbcon_set_suspend(drm_dev, 0); - } - - return 0; + return nouveau_do_resume(drm_dev, false); } @@ -715,13 +725,17 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) if (ret) goto out_suspend; - if (nv_device(drm->device)->card_type >= NV_50) { - ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), - 0x1000, &cli->base.vm); + cli->base.super = false; + + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40), + 0x1000, &cli->vm); if (ret) { nouveau_cli_destroy(cli); goto out_suspend; } + + nvkm_client(&cli->base)->vm = cli->vm; } fpriv->driver_priv = cli; @@ -779,24 +793,31 @@ nouveau_ioctls[] = { DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), }; -long nouveau_drm_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg) +long +nouveau_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct drm_file *file_priv = filp->private_data; - struct drm_device *dev; + struct drm_file *filp = file->private_data; + struct drm_device *dev = filp->minor->dev; long ret; - dev = file_priv->minor->dev; ret = pm_runtime_get_sync(dev->dev); if (ret < 0 && ret != -EACCES) return ret; - ret = drm_ioctl(filp, cmd, arg); + switch (_IOC_NR(cmd) - DRM_COMMAND_BASE) { + case DRM_NOUVEAU_NVIF: + ret = usif_ioctl(filp, (void __user *)arg, _IOC_SIZE(cmd)); + break; + default: + ret = drm_ioctl(file, cmd, arg); + break; + } pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return ret; } + static const struct file_operations nouveau_driver_fops = { .owner = THIS_MODULE, @@ -813,7 +834,7 @@ nouveau_driver_fops = { }; static struct drm_driver -driver = { +driver_stub = { .driver_features = DRIVER_USE_AGP | DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER, @@ -921,7 +942,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct nouveau_device *device = nouveau_dev(drm_dev); + struct nvif_device *device = &nouveau_drm(drm_dev)->device; int ret; if (nouveau_runtime_pm == 0) @@ -934,10 +955,10 @@ static int nouveau_pmops_runtime_resume(struct device *dev) return ret; pci_set_master(pdev); - ret = nouveau_do_resume(drm_dev); + ret = nouveau_do_resume(drm_dev, true); drm_kms_helper_poll_enable(drm_dev); /* do magic */ - nv_mask(device, 0x88488, (1 << 25), (1 << 25)); + nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; nv_debug_level(NORMAL); @@ -984,6 +1005,23 @@ static int nouveau_pmops_runtime_idle(struct device *dev) return 1; } +static void nouveau_display_options(void) +{ + DRM_DEBUG_DRIVER("Loading Nouveau with parameters:\n"); + + DRM_DEBUG_DRIVER("... tv_disable : %d\n", nouveau_tv_disable); + DRM_DEBUG_DRIVER("... ignorelid : %d\n", nouveau_ignorelid); + DRM_DEBUG_DRIVER("... duallink : %d\n", nouveau_duallink); + DRM_DEBUG_DRIVER("... nofbaccel : %d\n", nouveau_nofbaccel); + DRM_DEBUG_DRIVER("... config : %s\n", nouveau_config); + DRM_DEBUG_DRIVER("... debug : %s\n", nouveau_debug); + DRM_DEBUG_DRIVER("... noaccel : %d\n", nouveau_noaccel); + 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("... pstate : %d\n", nouveau_pstate); +} + static const struct dev_pm_ops nouveau_pm_ops = { .suspend = nouveau_pmops_suspend, .resume = nouveau_pmops_resume, @@ -1005,28 +1043,52 @@ nouveau_drm_pci_driver = { .driver.pm = &nouveau_pm_ops, }; -int nouveau_drm_platform_probe(struct platform_device *pdev) +struct drm_device * +nouveau_platform_device_create_(struct platform_device *pdev, int size, + void **pobject) { - struct nouveau_device *device; - int ret; + struct drm_device *drm; + int err; - ret = nouveau_device_create(pdev, NOUVEAU_BUS_PLATFORM, + err = nouveau_device_create_(pdev, NOUVEAU_BUS_PLATFORM, nouveau_platform_name(pdev), dev_name(&pdev->dev), nouveau_config, - nouveau_debug, &device); - - ret = drm_platform_init(&driver, pdev); - if (ret) { - nouveau_object_ref(NULL, (struct nouveau_object **)&device); - return ret; + nouveau_debug, size, pobject); + if (err) + return ERR_PTR(err); + + drm = drm_dev_alloc(&driver_platform, &pdev->dev); + if (!drm) { + err = -ENOMEM; + goto err_free; } - return ret; + err = drm_dev_set_unique(drm, "%s", dev_name(&pdev->dev)); + if (err < 0) + goto err_free; + + drm->platformdev = pdev; + platform_set_drvdata(pdev, drm); + + return drm; + +err_free: + nouveau_object_ref(NULL, (struct nouveau_object **)pobject); + + return ERR_PTR(err); } +EXPORT_SYMBOL(nouveau_platform_device_create_); static int __init nouveau_drm_init(void) { + driver_pci = driver_stub; + driver_pci.set_busid = drm_pci_set_busid; + driver_platform = driver_stub; + driver_platform.set_busid = drm_platform_set_busid; + + nouveau_display_options(); + if (nouveau_modeset == -1) { #ifdef CONFIG_VGA_CONSOLE if (vgacon_text_force()) @@ -1038,7 +1100,7 @@ nouveau_drm_init(void) return 0; nouveau_register_dsm_handler(); - return drm_pci_init(&driver, &nouveau_drm_pci_driver); + return drm_pci_init(&driver_pci, &nouveau_drm_pci_driver); } static void __exit @@ -1047,7 +1109,7 @@ nouveau_drm_exit(void) if (!nouveau_modeset) return; - drm_pci_exit(&driver, &nouveau_drm_pci_driver); + drm_pci_exit(&driver_pci, &nouveau_drm_pci_driver); nouveau_unregister_dsm_handler(); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 7efbafaf7c1d..8ae36f265fb8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -9,7 +9,7 @@ #define DRIVER_DATE "20120801" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 1 +#define DRIVER_MINOR 2 #define DRIVER_PATCHLEVEL 1 /* @@ -21,15 +21,19 @@ * to control registers on the MPs to enable performance counters, * and to control the warp error enable mask (OpenGL requires out of * bounds access to local memory to be silently ignored / return 0). + * 1.1.2: + * - fixes multiple bugs in flip completion events and timestamping + * 1.2.0: + * - object api exposed to userspace + * - fermi,kepler,maxwell zbc + * 1.2.1: + * - allow concurrent access to bo's mapped read/write. */ -#include <core/client.h> -#include <core/event.h> - -#include <subdev/vm.h> +#include <nvif/client.h> +#include <nvif/device.h> #include <drmP.h> -#include <drm/nouveau_drm.h> #include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_driver.h> @@ -38,7 +42,10 @@ #include <drm/ttm/ttm_module.h> #include <drm/ttm/ttm_page_alloc.h> +#include "uapi/drm/nouveau_drm.h" + struct nouveau_channel; +struct platform_device; #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) @@ -50,6 +57,17 @@ struct nouveau_drm_tile { bool used; }; +enum nouveau_drm_object_route { + NVDRM_OBJECT_NVIF = 0, + NVDRM_OBJECT_USIF, + NVDRM_OBJECT_ABI16, +}; + +enum nouveau_drm_notify_route { + NVDRM_NOTIFY_NVIF = 0, + NVDRM_NOTIFY_USIF +}; + enum nouveau_drm_handle { NVDRM_CLIENT = 0xffffffff, NVDRM_DEVICE = 0xdddddddd, @@ -61,10 +79,13 @@ enum nouveau_drm_handle { }; struct nouveau_cli { - struct nouveau_client base; + struct nvif_client base; + struct nouveau_vm *vm; /*XXX*/ struct list_head head; struct mutex mutex; void *abi16; + struct list_head objects; + struct list_head notifys; }; static inline struct nouveau_cli * @@ -73,13 +94,16 @@ nouveau_cli(struct drm_file *fpriv) return fpriv ? fpriv->driver_priv : NULL; } +#include <nvif/object.h> +#include <nvif/device.h> + extern int nouveau_runtime_pm; struct nouveau_drm { struct nouveau_cli client; struct drm_device *dev; - struct nouveau_object *device; + struct nvif_device device; struct list_head clients; struct { @@ -102,6 +126,7 @@ struct nouveau_drm { struct ttm_buffer_object *, struct ttm_mem_reg *, struct ttm_mem_reg *); struct nouveau_channel *chan; + struct nvif_object copy; int mtrr; } ttm; @@ -119,6 +144,8 @@ struct nouveau_drm { struct nouveau_channel *channel; struct nouveau_gpuobj *notify; struct nouveau_fbdev *fbcon; + struct nvif_object nvsw; + struct nvif_object ntfy; /* nv10-nv40 tiling regions */ struct { @@ -148,20 +175,25 @@ nouveau_drm(struct drm_device *dev) return dev->dev_private; } -static inline struct nouveau_device * -nouveau_dev(struct drm_device *dev) -{ - return nv_device(nouveau_drm(dev)->device); -} - int nouveau_pmops_suspend(struct device *); int nouveau_pmops_resume(struct device *); -#define NV_FATAL(cli, fmt, args...) nv_fatal((cli), fmt, ##args) -#define NV_ERROR(cli, fmt, args...) nv_error((cli), fmt, ##args) -#define NV_WARN(cli, fmt, args...) nv_warn((cli), fmt, ##args) -#define NV_INFO(cli, fmt, args...) nv_info((cli), fmt, ##args) -#define NV_DEBUG(cli, fmt, args...) nv_debug((cli), fmt, ##args) +#define nouveau_platform_device_create(p, u) \ + nouveau_platform_device_create_(p, sizeof(**u), (void **)u) +struct drm_device * +nouveau_platform_device_create_(struct platform_device *pdev, + int size, void **pobject); +void nouveau_drm_device_remove(struct drm_device *dev); + +#define NV_PRINTK(l,c,f,a...) do { \ + struct nouveau_cli *_cli = (c); \ + nv_##l(_cli->base.base.priv, f, ##a); \ +} while(0) +#define NV_FATAL(drm,f,a...) NV_PRINTK(fatal, &(drm)->client, f, ##a) +#define NV_ERROR(drm,f,a...) NV_PRINTK(error, &(drm)->client, f, ##a) +#define NV_WARN(drm,f,a...) NV_PRINTK(warn, &(drm)->client, f, ##a) +#define NV_INFO(drm,f,a...) NV_PRINTK(info, &(drm)->client, f, ##a) +#define NV_DEBUG(drm,f,a...) NV_PRINTK(debug, &(drm)->client, f, ##a) extern int nouveau_modeset; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 191665ee7f52..593ef8a2a069 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -51,13 +51,8 @@ #include "nouveau_crtc.h" -#include <core/client.h> -#include <core/device.h> - -#include <subdev/fb.h> - MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); -static int nouveau_nofbaccel = 0; +int nouveau_nofbaccel = 0; module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); static void @@ -65,7 +60,7 @@ 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_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int ret; if (info->state != FBINFO_STATE_RUNNING) @@ -74,10 +69,10 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && mutex_trylock(&drm->client.mutex)) { - if (device->card_type < NV_50) + if (device->info.family < NV_DEVICE_INFO_V0_TESLA) ret = nv04_fbcon_fillrect(info, rect); else - if (device->card_type < NV_C0) + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) ret = nv50_fbcon_fillrect(info, rect); else ret = nvc0_fbcon_fillrect(info, rect); @@ -97,7 +92,7 @@ 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_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int ret; if (info->state != FBINFO_STATE_RUNNING) @@ -106,10 +101,10 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && mutex_trylock(&drm->client.mutex)) { - if (device->card_type < NV_50) + if (device->info.family < NV_DEVICE_INFO_V0_TESLA) ret = nv04_fbcon_copyarea(info, image); else - if (device->card_type < NV_C0) + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) ret = nv50_fbcon_copyarea(info, image); else ret = nvc0_fbcon_copyarea(info, image); @@ -129,7 +124,7 @@ 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_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; int ret; if (info->state != FBINFO_STATE_RUNNING) @@ -138,10 +133,10 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && mutex_trylock(&drm->client.mutex)) { - if (device->card_type < NV_50) + if (device->info.family < NV_DEVICE_INFO_V0_TESLA) ret = nv04_fbcon_imageblit(info, image); else - if (device->card_type < NV_C0) + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) ret = nv50_fbcon_imageblit(info, image); else ret = nvc0_fbcon_imageblit(info, image); @@ -212,6 +207,65 @@ static struct fb_ops nouveau_fbcon_sw_ops = { .fb_debug_leave = drm_fb_helper_debug_leave, }; +void +nouveau_fbcon_accel_save_disable(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + if (drm->fbcon) { + drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; + drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; + } +} + +void +nouveau_fbcon_accel_restore(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + if (drm->fbcon) { + drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; + } +} + +static void +nouveau_fbcon_accel_fini(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_fbdev *fbcon = drm->fbcon; + if (fbcon && drm->channel) { + console_lock(); + fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; + console_unlock(); + nouveau_channel_idle(drm->channel); + nvif_object_fini(&fbcon->twod); + nvif_object_fini(&fbcon->blit); + nvif_object_fini(&fbcon->gdi); + nvif_object_fini(&fbcon->patt); + nvif_object_fini(&fbcon->rop); + nvif_object_fini(&fbcon->clip); + nvif_object_fini(&fbcon->surf2d); + } +} + +static void +nouveau_fbcon_accel_init(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_fbdev *fbcon = drm->fbcon; + struct fb_info *info = fbcon->helper.fbdev; + int ret; + + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) + ret = nv04_fbcon_accel_init(info); + else + if (drm->device.info.family < NV_DEVICE_INFO_V0_FERMI) + ret = nv50_fbcon_accel_init(info); + else + ret = nvc0_fbcon_accel_init(info); + + if (ret == 0) + info->fbops = &nouveau_fbcon_ops; +} + static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { @@ -254,10 +308,11 @@ static int nouveau_fbcon_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct nouveau_fbdev *fbcon = (struct nouveau_fbdev *)helper; + struct nouveau_fbdev *fbcon = + container_of(helper, struct nouveau_fbdev, helper); struct drm_device *dev = fbcon->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct fb_info *info; struct drm_framebuffer *fb; struct nouveau_framebuffer *nouveau_fb; @@ -299,8 +354,8 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, } chan = nouveau_nofbaccel ? NULL : drm->channel; - if (chan && device->card_type >= NV_50) { - ret = nouveau_bo_vma_add(nvbo, nv_client(chan->cli)->vm, + if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_bo_vma_add(nvbo, drm->client.vm, &fbcon->nouveau_fb.vma); if (ret) { NV_ERROR(drm, "failed to map fb into chan: %d\n", ret); @@ -357,20 +412,8 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, mutex_unlock(&dev->struct_mutex); - if (chan) { - ret = -ENODEV; - if (device->card_type < NV_50) - ret = nv04_fbcon_accel_init(info); - else - if (device->card_type < NV_C0) - ret = nv50_fbcon_accel_init(info); - else - ret = nvc0_fbcon_accel_init(info); - - if (ret == 0) - info->fbops = &nouveau_fbcon_ops; - } - + if (chan) + nouveau_fbcon_accel_init(dev); nouveau_fbcon_zfill(dev, fbcon); /* To allow resizeing without swapping buffers */ @@ -438,18 +481,27 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info) info->flags |= FBINFO_HWACCEL_DISABLED; } -static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { +static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { .gamma_set = nouveau_fbcon_gamma_set, .gamma_get = nouveau_fbcon_gamma_get, .fb_probe = nouveau_fbcon_create, }; +static void +nouveau_fbcon_set_suspend_work(struct work_struct *work) +{ + struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work); + console_lock(); + nouveau_fbcon_accel_restore(fbcon->dev); + nouveau_fbcon_zfill(fbcon->dev, fbcon); + fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING); + console_unlock(); +} int nouveau_fbcon_init(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_fb *pfb = nouveau_fb(drm->device); struct nouveau_fbdev *fbcon; int preferred_bpp; int ret; @@ -462,9 +514,11 @@ nouveau_fbcon_init(struct drm_device *dev) if (!fbcon) return -ENOMEM; + INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work); fbcon->dev = dev; drm->fbcon = fbcon; - fbcon->helper.funcs = &nouveau_fbcon_helper_funcs; + + drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); ret = drm_fb_helper_init(dev, &fbcon->helper, dev->mode_config.num_crtc, 4); @@ -475,10 +529,10 @@ nouveau_fbcon_init(struct drm_device *dev) drm_fb_helper_single_add_all_connectors(&fbcon->helper); - if (pfb->ram->size <= 32 * 1024 * 1024) + if (drm->device.info.ram_size <= 32 * 1024 * 1024) preferred_bpp = 8; else - if (pfb->ram->size <= 64 * 1024 * 1024) + if (drm->device.info.ram_size <= 64 * 1024 * 1024) preferred_bpp = 16; else preferred_bpp = 32; @@ -498,43 +552,25 @@ nouveau_fbcon_fini(struct drm_device *dev) if (!drm->fbcon) return; + nouveau_fbcon_accel_fini(dev); nouveau_fbcon_destroy(dev, drm->fbcon); kfree(drm->fbcon); drm->fbcon = NULL; } void -nouveau_fbcon_save_disable_accel(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon) { - drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; - drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; - } -} - -void -nouveau_fbcon_restore_accel(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon) { - drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; - } -} - -void nouveau_fbcon_set_suspend(struct drm_device *dev, int state) { struct nouveau_drm *drm = nouveau_drm(dev); if (drm->fbcon) { + if (state == FBINFO_STATE_RUNNING) { + schedule_work(&drm->fbcon->work); + return; + } + flush_work(&drm->fbcon->work); console_lock(); - if (state == 1) - nouveau_fbcon_save_disable_accel(dev); fb_set_suspend(drm->fbcon->helper.fbdev, state); - if (state == 0) { - nouveau_fbcon_restore_accel(dev); - nouveau_fbcon_zfill(dev, drm->fbcon); - } + nouveau_fbcon_accel_save_disable(dev); console_unlock(); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index fcff797d2084..6208e70e4a1c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -36,7 +36,15 @@ struct nouveau_fbdev { struct nouveau_framebuffer nouveau_fb; struct list_head fbdev_list; struct drm_device *dev; + struct work_struct work; unsigned int saved_flags; + struct nvif_object surf2d; + struct nvif_object clip; + struct nvif_object rop; + struct nvif_object patt; + struct nvif_object gdi; + struct nvif_object blit; + struct nvif_object twod; }; void nouveau_fbcon_restore(void); @@ -61,9 +69,12 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info); int nouveau_fbcon_init(struct drm_device *dev); void nouveau_fbcon_fini(struct drm_device *dev); void nouveau_fbcon_set_suspend(struct drm_device *dev, int state); -void nouveau_fbcon_save_disable_accel(struct drm_device *dev); -void nouveau_fbcon_restore_accel(struct drm_device *dev); +void nouveau_fbcon_accel_save_disable(struct drm_device *dev); +void nouveau_fbcon_accel_restore(struct drm_device *dev); void nouveau_fbcon_output_poll_changed(struct drm_device *dev); + +extern int nouveau_nofbaccel; + #endif /* __NV50_FBCON_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index ab5ea3b0d666..515cd9aebb99 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -28,130 +28,243 @@ #include <linux/ktime.h> #include <linux/hrtimer.h> +#include <trace/events/fence.h> + +#include <nvif/notify.h> +#include <nvif/event.h> #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_fence.h" -#include <engine/fifo.h> +static const struct fence_ops nouveau_fence_ops_uevent; +static const struct fence_ops nouveau_fence_ops_legacy; -struct fence_work { - struct work_struct base; - struct list_head head; - void (*func)(void *); - void *data; -}; +static inline struct nouveau_fence * +from_fence(struct fence *fence) +{ + return container_of(fence, struct nouveau_fence, base); +} + +static inline struct nouveau_fence_chan * +nouveau_fctx(struct nouveau_fence *fence) +{ + return container_of(fence->base.lock, struct nouveau_fence_chan, lock); +} static void nouveau_fence_signal(struct nouveau_fence *fence) { - struct fence_work *work, *temp; + fence_signal_locked(&fence->base); + list_del(&fence->head); + + if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) { + struct nouveau_fence_chan *fctx = nouveau_fctx(fence); - list_for_each_entry_safe(work, temp, &fence->work, head) { - schedule_work(&work->base); - list_del(&work->head); + if (!--fctx->notify_ref) + nvif_notify_put(&fctx->notify); } - fence->channel = NULL; - list_del(&fence->head); + fence_put(&fence->base); +} + +static struct nouveau_fence * +nouveau_local_fence(struct fence *fence, struct nouveau_drm *drm) { + struct nouveau_fence_priv *priv = (void*)drm->fence; + + if (fence->ops != &nouveau_fence_ops_legacy && + fence->ops != &nouveau_fence_ops_uevent) + return NULL; + + if (fence->context < priv->context_base || + fence->context >= priv->context_base + priv->contexts) + return NULL; + + return from_fence(fence); } void nouveau_fence_context_del(struct nouveau_fence_chan *fctx) { - struct nouveau_fence *fence, *fnext; - spin_lock(&fctx->lock); - list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { + struct nouveau_fence *fence; + + nvif_notify_fini(&fctx->notify); + + spin_lock_irq(&fctx->lock); + while (!list_empty(&fctx->pending)) { + fence = list_entry(fctx->pending.next, typeof(*fence), head); + + nouveau_fence_signal(fence); + fence->channel = NULL; + } + spin_unlock_irq(&fctx->lock); +} + +static void +nouveau_fence_context_put(struct kref *fence_ref) +{ + kfree(container_of(fence_ref, struct nouveau_fence_chan, fence_ref)); +} + +void +nouveau_fence_context_free(struct nouveau_fence_chan *fctx) +{ + kref_put(&fctx->fence_ref, nouveau_fence_context_put); +} + +static void +nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) +{ + struct nouveau_fence *fence; + + u32 seq = fctx->read(chan); + + while (!list_empty(&fctx->pending)) { + fence = list_entry(fctx->pending.next, typeof(*fence), head); + + if ((int)(seq - fence->base.seqno) < 0) + return; + nouveau_fence_signal(fence); } - spin_unlock(&fctx->lock); +} + +static int +nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) +{ + struct nouveau_fence_chan *fctx = + container_of(notify, typeof(*fctx), notify); + unsigned long flags; + + spin_lock_irqsave(&fctx->lock, flags); + if (!list_empty(&fctx->pending)) { + struct nouveau_fence *fence; + + fence = list_entry(fctx->pending.next, typeof(*fence), head); + nouveau_fence_update(fence->channel, fctx); + } + spin_unlock_irqrestore(&fctx->lock, flags); + + /* Always return keep here. NVIF refcount is handled with nouveau_fence_update */ + return NVIF_NOTIFY_KEEP; } void -nouveau_fence_context_new(struct nouveau_fence_chan *fctx) +nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) { + struct nouveau_fence_priv *priv = (void*)chan->drm->fence; + struct nouveau_cli *cli = (void *)nvif_client(chan->object); + int ret; + INIT_LIST_HEAD(&fctx->flip); INIT_LIST_HEAD(&fctx->pending); spin_lock_init(&fctx->lock); + fctx->context = priv->context_base + chan->chid; + + if (chan == chan->drm->cechan) + strcpy(fctx->name, "copy engine channel"); + else if (chan == chan->drm->channel) + strcpy(fctx->name, "generic kernel channel"); + else + strcpy(fctx->name, nvkm_client(&cli->base)->name); + + kref_init(&fctx->fence_ref); + if (!priv->uevent) + return; + + ret = nvif_notify_init(chan->object, NULL, + nouveau_fence_wait_uevent_handler, false, + G82_CHANNEL_DMA_V0_NTFY_UEVENT, + &(struct nvif_notify_uevent_req) { }, + sizeof(struct nvif_notify_uevent_req), + sizeof(struct nvif_notify_uevent_rep), + &fctx->notify); + + WARN_ON(ret); } +struct nouveau_fence_work { + struct work_struct work; + struct fence_cb cb; + void (*func)(void *); + void *data; +}; + static void nouveau_fence_work_handler(struct work_struct *kwork) { - struct fence_work *work = container_of(kwork, typeof(*work), base); + struct nouveau_fence_work *work = container_of(kwork, typeof(*work), work); work->func(work->data); kfree(work); } +static void nouveau_fence_work_cb(struct fence *fence, struct fence_cb *cb) +{ + struct nouveau_fence_work *work = container_of(cb, typeof(*work), cb); + + schedule_work(&work->work); +} + void -nouveau_fence_work(struct nouveau_fence *fence, +nouveau_fence_work(struct fence *fence, void (*func)(void *), void *data) { - struct nouveau_channel *chan = fence->channel; - struct nouveau_fence_chan *fctx; - struct fence_work *work = NULL; + struct nouveau_fence_work *work; - if (nouveau_fence_done(fence)) { - func(data); - return; - } + if (fence_is_signaled(fence)) + goto err; - fctx = chan->fence; work = kmalloc(sizeof(*work), GFP_KERNEL); if (!work) { - WARN_ON(nouveau_fence_wait(fence, false, false)); - func(data); - return; - } - - spin_lock(&fctx->lock); - if (!fence->channel) { - spin_unlock(&fctx->lock); - kfree(work); - func(data); - return; + /* + * this might not be a nouveau fence any more, + * so force a lazy wait here + */ + WARN_ON(nouveau_fence_wait((struct nouveau_fence *)fence, + true, false)); + goto err; } - INIT_WORK(&work->base, nouveau_fence_work_handler); + INIT_WORK(&work->work, nouveau_fence_work_handler); work->func = func; work->data = data; - list_add(&work->head, &fence->work); - spin_unlock(&fctx->lock); -} - -static void -nouveau_fence_update(struct nouveau_channel *chan) -{ - struct nouveau_fence_chan *fctx = chan->fence; - struct nouveau_fence *fence, *fnext; - spin_lock(&fctx->lock); - list_for_each_entry_safe(fence, fnext, &fctx->pending, head) { - if (fctx->read(chan) < fence->sequence) - break; + if (fence_add_callback(fence, &work->cb, nouveau_fence_work_cb) < 0) + goto err_free; + return; - nouveau_fence_signal(fence); - nouveau_fence_unref(&fence); - } - spin_unlock(&fctx->lock); +err_free: + kfree(work); +err: + func(data); } int nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) { struct nouveau_fence_chan *fctx = chan->fence; + struct nouveau_fence_priv *priv = (void*)chan->drm->fence; int ret; fence->channel = chan; fence->timeout = jiffies + (15 * HZ); - fence->sequence = ++fctx->sequence; + if (priv->uevent) + fence_init(&fence->base, &nouveau_fence_ops_uevent, + &fctx->lock, fctx->context, ++fctx->sequence); + else + fence_init(&fence->base, &nouveau_fence_ops_legacy, + &fctx->lock, fctx->context, ++fctx->sequence); + kref_get(&fctx->fence_ref); + + trace_fence_emit(&fence->base); ret = fctx->emit(fence); if (!ret) { - kref_get(&fence->kref); - spin_lock(&fctx->lock); + fence_get(&fence->base); + spin_lock_irq(&fctx->lock); + nouveau_fence_update(chan, fctx); list_add_tail(&fence->head, &fctx->pending); - spin_unlock(&fctx->lock); + spin_unlock_irq(&fctx->lock); } return ret; @@ -160,104 +273,70 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) bool nouveau_fence_done(struct nouveau_fence *fence) { - if (fence->channel) - nouveau_fence_update(fence->channel); - return !fence->channel; -} + if (fence->base.ops == &nouveau_fence_ops_legacy || + fence->base.ops == &nouveau_fence_ops_uevent) { + struct nouveau_fence_chan *fctx = nouveau_fctx(fence); + unsigned long flags; -static int -nouveau_fence_wait_uevent_handler(void *data, u32 type, int index) -{ - struct nouveau_fence_priv *priv = data; - wake_up_all(&priv->waiting); - return NVKM_EVENT_KEEP; -} + if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) + return true; -static int -nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) + spin_lock_irqsave(&fctx->lock, flags); + nouveau_fence_update(fence->channel, fctx); + spin_unlock_irqrestore(&fctx->lock, flags); + } + return fence_is_signaled(&fence->base); +} +static long +nouveau_fence_wait_legacy(struct fence *f, bool intr, long wait) { - struct nouveau_channel *chan = fence->channel; - struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device); - struct nouveau_fence_priv *priv = chan->drm->fence; - struct nouveau_eventh *handler; - int ret = 0; + struct nouveau_fence *fence = from_fence(f); + unsigned long sleep_time = NSEC_PER_MSEC / 1000; + unsigned long t = jiffies, timeout = t + wait; - ret = nouveau_event_new(pfifo->uevent, 1, 0, - nouveau_fence_wait_uevent_handler, - priv, &handler); - if (ret) - return ret; + while (!nouveau_fence_done(fence)) { + ktime_t kt; - nouveau_event_get(handler); - - if (fence->timeout) { - unsigned long timeout = fence->timeout - jiffies; - - if (time_before(jiffies, fence->timeout)) { - if (intr) { - ret = wait_event_interruptible_timeout( - priv->waiting, - nouveau_fence_done(fence), - timeout); - } else { - ret = wait_event_timeout(priv->waiting, - nouveau_fence_done(fence), - timeout); - } - } + t = jiffies; - if (ret >= 0) { - fence->timeout = jiffies + ret; - if (time_after_eq(jiffies, fence->timeout)) - ret = -EBUSY; - } - } else { - if (intr) { - ret = wait_event_interruptible(priv->waiting, - nouveau_fence_done(fence)); - } else { - wait_event(priv->waiting, nouveau_fence_done(fence)); + if (wait != MAX_SCHEDULE_TIMEOUT && time_after_eq(t, timeout)) { + __set_current_state(TASK_RUNNING); + return 0; } + + __set_current_state(intr ? TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + + kt = ktime_set(0, sleep_time); + schedule_hrtimeout(&kt, HRTIMER_MODE_REL); + sleep_time *= 2; + if (sleep_time > NSEC_PER_MSEC) + sleep_time = NSEC_PER_MSEC; + + if (intr && signal_pending(current)) + return -ERESTARTSYS; } - nouveau_event_ref(NULL, &handler); - if (unlikely(ret < 0)) - return ret; + __set_current_state(TASK_RUNNING); - return 0; + return timeout - t; } -int -nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) +static int +nouveau_fence_wait_busy(struct nouveau_fence *fence, bool intr) { - struct nouveau_channel *chan = fence->channel; - struct nouveau_fence_priv *priv = chan ? chan->drm->fence : NULL; - unsigned long sleep_time = NSEC_PER_MSEC / 1000; - ktime_t t; int ret = 0; - while (priv && priv->uevent && lazy && !nouveau_fence_done(fence)) { - ret = nouveau_fence_wait_uevent(fence, intr); - if (ret < 0) - return ret; - } - while (!nouveau_fence_done(fence)) { - if (fence->timeout && time_after_eq(jiffies, fence->timeout)) { + if (time_after_eq(jiffies, fence->timeout)) { ret = -EBUSY; break; } - __set_current_state(intr ? TASK_INTERRUPTIBLE : - TASK_UNINTERRUPTIBLE); - if (lazy) { - t = ktime_set(0, sleep_time); - schedule_hrtimeout(&t, HRTIMER_MODE_REL); - sleep_time *= 2; - if (sleep_time > NSEC_PER_MSEC) - sleep_time = NSEC_PER_MSEC; - } + __set_current_state(intr ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); if (intr && signal_pending(current)) { ret = -ERESTARTSYS; @@ -270,47 +349,86 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) } int -nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan) +nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) +{ + long ret; + + if (!lazy) + return nouveau_fence_wait_busy(fence, intr); + + ret = fence_wait_timeout(&fence->base, intr, 15 * HZ); + if (ret < 0) + return ret; + else if (!ret) + return -EBUSY; + else + return 0; +} + +int +nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool exclusive, bool intr) { struct nouveau_fence_chan *fctx = chan->fence; - struct nouveau_channel *prev; - int ret = 0; + struct fence *fence; + struct reservation_object *resv = nvbo->bo.resv; + struct reservation_object_list *fobj; + struct nouveau_fence *f; + int ret = 0, i; - prev = fence ? fence->channel : NULL; - if (prev) { - if (unlikely(prev != chan && !nouveau_fence_done(fence))) { - ret = fctx->sync(fence, prev, chan); - if (unlikely(ret)) - ret = nouveau_fence_wait(fence, true, false); - } + if (!exclusive) { + ret = reservation_object_reserve_shared(resv); + + if (ret) + return ret; } - return ret; -} + fobj = reservation_object_get_list(resv); + fence = reservation_object_get_excl(resv); -static void -nouveau_fence_del(struct kref *kref) -{ - struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref); - kfree(fence); + if (fence && (!exclusive || !fobj || !fobj->shared_count)) { + struct nouveau_channel *prev = NULL; + + f = nouveau_local_fence(fence, chan->drm); + if (f) + prev = f->channel; + + if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) + ret = fence_wait(fence, intr); + + return ret; + } + + if (!exclusive || !fobj) + return ret; + + for (i = 0; i < fobj->shared_count && !ret; ++i) { + struct nouveau_channel *prev = NULL; + + fence = rcu_dereference_protected(fobj->shared[i], + reservation_object_held(resv)); + + f = nouveau_local_fence(fence, chan->drm); + if (f) + prev = f->channel; + + if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) + ret = fence_wait(fence, intr); + + if (ret) + break; + } + + return ret; } void nouveau_fence_unref(struct nouveau_fence **pfence) { if (*pfence) - kref_put(&(*pfence)->kref, nouveau_fence_del); + fence_put(&(*pfence)->base); *pfence = NULL; } -struct nouveau_fence * -nouveau_fence_ref(struct nouveau_fence *fence) -{ - if (fence) - kref_get(&fence->kref); - return fence; -} - int nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, struct nouveau_fence **pfence) @@ -325,9 +443,7 @@ nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, if (!fence) return -ENOMEM; - INIT_LIST_HEAD(&fence->work); fence->sysmem = sysmem; - kref_init(&fence->kref); ret = nouveau_fence_emit(fence, chan); if (ret) @@ -336,3 +452,101 @@ nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, *pfence = fence; return ret; } + +static const char *nouveau_fence_get_get_driver_name(struct fence *fence) +{ + return "nouveau"; +} + +static const char *nouveau_fence_get_timeline_name(struct fence *f) +{ + struct nouveau_fence *fence = from_fence(f); + struct nouveau_fence_chan *fctx = nouveau_fctx(fence); + + return fence->channel ? fctx->name : "dead channel"; +} + +/* + * In an ideal world, read would not assume the channel context is still alive. + * This function may be called from another device, running into free memory as a + * result. The drm node should still be there, so we can derive the index from + * the fence context. + */ +static bool nouveau_fence_is_signaled(struct fence *f) +{ + struct nouveau_fence *fence = from_fence(f); + struct nouveau_fence_chan *fctx = nouveau_fctx(fence); + struct nouveau_channel *chan = fence->channel; + + return (int)(fctx->read(chan) - fence->base.seqno) >= 0; +} + +static bool nouveau_fence_no_signaling(struct fence *f) +{ + struct nouveau_fence *fence = from_fence(f); + + /* + * caller should have a reference on the fence, + * else fence could get freed here + */ + WARN_ON(atomic_read(&fence->base.refcount.refcount) <= 1); + + /* + * This needs uevents to work correctly, but fence_add_callback relies on + * being able to enable signaling. It will still get signaled eventually, + * just not right away. + */ + if (nouveau_fence_is_signaled(f)) { + list_del(&fence->head); + + fence_put(&fence->base); + return false; + } + + return true; +} + +static void nouveau_fence_release(struct fence *f) +{ + struct nouveau_fence *fence = from_fence(f); + struct nouveau_fence_chan *fctx = nouveau_fctx(fence); + + kref_put(&fctx->fence_ref, nouveau_fence_context_put); + fence_free(&fence->base); +} + +static const struct fence_ops nouveau_fence_ops_legacy = { + .get_driver_name = nouveau_fence_get_get_driver_name, + .get_timeline_name = nouveau_fence_get_timeline_name, + .enable_signaling = nouveau_fence_no_signaling, + .signaled = nouveau_fence_is_signaled, + .wait = nouveau_fence_wait_legacy, + .release = nouveau_fence_release +}; + +static bool nouveau_fence_enable_signaling(struct fence *f) +{ + struct nouveau_fence *fence = from_fence(f); + struct nouveau_fence_chan *fctx = nouveau_fctx(fence); + bool ret; + + if (!fctx->notify_ref++) + nvif_notify_get(&fctx->notify); + + ret = nouveau_fence_no_signaling(f); + if (ret) + set_bit(FENCE_FLAG_USER_BITS, &fence->base.flags); + else if (!--fctx->notify_ref) + nvif_notify_put(&fctx->notify); + + return ret; +} + +static const struct fence_ops nouveau_fence_ops_uevent = { + .get_driver_name = nouveau_fence_get_get_driver_name, + .get_timeline_name = nouveau_fence_get_timeline_name, + .enable_signaling = nouveau_fence_enable_signaling, + .signaled = nouveau_fence_is_signaled, + .wait = fence_default_wait, + .release = NULL +}; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index c57bb61da58c..943b0b17b1fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -1,33 +1,37 @@ #ifndef __NOUVEAU_FENCE_H__ #define __NOUVEAU_FENCE_H__ +#include <linux/fence.h> +#include <nvif/notify.h> + struct nouveau_drm; +struct nouveau_bo; struct nouveau_fence { + struct fence base; + struct list_head head; - struct list_head work; - struct kref kref; bool sysmem; struct nouveau_channel *channel; unsigned long timeout; - u32 sequence; }; int nouveau_fence_new(struct nouveau_channel *, bool sysmem, struct nouveau_fence **); -struct nouveau_fence * -nouveau_fence_ref(struct nouveau_fence *); void nouveau_fence_unref(struct nouveau_fence **); int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *); bool nouveau_fence_done(struct nouveau_fence *); -void nouveau_fence_work(struct nouveau_fence *, void (*)(void *), void *); +void nouveau_fence_work(struct fence *, void (*)(void *), void *); int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); -int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *); +int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr); struct nouveau_fence_chan { + spinlock_t lock; + struct kref fence_ref; + struct list_head pending; struct list_head flip; @@ -38,8 +42,12 @@ struct nouveau_fence_chan { int (*emit32)(struct nouveau_channel *, u64, u32); int (*sync32)(struct nouveau_channel *, u64, u32); - spinlock_t lock; u32 sequence; + u32 context; + char name[32]; + + struct nvif_notify notify; + int notify_ref; }; struct nouveau_fence_priv { @@ -49,14 +57,15 @@ struct nouveau_fence_priv { int (*context_new)(struct nouveau_channel *); void (*context_del)(struct nouveau_channel *); - wait_queue_head_t waiting; + u32 contexts, context_base; bool uevent; }; #define nouveau_fence(drm) ((struct nouveau_fence_priv *)(drm)->fence) -void nouveau_fence_context_new(struct nouveau_fence_chan *); +void nouveau_fence_context_new(struct nouveau_channel *, struct nouveau_fence_chan *); void nouveau_fence_context_del(struct nouveau_fence_chan *); +void nouveau_fence_context_free(struct nouveau_fence_chan *); int nv04_fence_create(struct nouveau_drm *); int nv04_fence_mthd(struct nouveau_channel *, u32, u32, u32); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index c90c0dc0afe8..36951ee4b157 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -24,8 +24,6 @@ * */ -#include <subdev/fb.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_fence.h" @@ -58,14 +56,14 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) struct nouveau_vma *vma; int ret; - if (!cli->base.vm) + if (!cli->vm) return 0; - ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0); + ret = ttm_bo_reserve(&nvbo->bo, false, false, false, NULL); if (ret) return ret; - vma = nouveau_bo_vma_find(nvbo, cli->base.vm); + vma = nouveau_bo_vma_find(nvbo, cli->vm); if (!vma) { vma = kzalloc(sizeof(*vma), GFP_KERNEL); if (!vma) { @@ -73,7 +71,7 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) goto out; } - ret = nouveau_bo_vma_add(nvbo, cli->base.vm, vma); + ret = nouveau_bo_vma_add(nvbo, cli->vm, vma); if (ret) { kfree(vma); goto out; @@ -100,17 +98,23 @@ static void nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma) { const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM; - struct nouveau_fence *fence = NULL; + struct reservation_object *resv = nvbo->bo.resv; + struct reservation_object_list *fobj; + struct fence *fence = NULL; + + fobj = reservation_object_get_list(resv); list_del(&vma->head); - if (mapped) { - spin_lock(&nvbo->bo.bdev->fence_lock); - fence = nouveau_fence_ref(nvbo->bo.sync_obj); - spin_unlock(&nvbo->bo.bdev->fence_lock); - } + if (fobj && fobj->shared_count > 1) + ttm_bo_wait(&nvbo->bo, true, false, false); + else if (fobj && fobj->shared_count == 1) + fence = rcu_dereference_protected(fobj->shared[0], + reservation_object_held(resv)); + else + fence = reservation_object_get_excl(nvbo->bo.resv); - if (fence) { + if (fence && mapped) { nouveau_fence_work(fence, nouveau_gem_object_delete, vma); } else { if (mapped) @@ -118,7 +122,6 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma) nouveau_vm_put(vma); kfree(vma); } - nouveau_fence_unref(&fence); } void @@ -129,14 +132,14 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) struct nouveau_vma *vma; int ret; - if (!cli->base.vm) + if (!cli->vm) return; - ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0); + ret = ttm_bo_reserve(&nvbo->bo, false, false, false, NULL); if (ret) return; - vma = nouveau_bo_vma_find(nvbo, cli->base.vm); + vma = nouveau_bo_vma_find(nvbo, cli->vm); if (vma) { if (--vma->refcount == 0) nouveau_gem_object_unmap(nvbo, vma); @@ -162,7 +165,7 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain, flags |= TTM_PL_FLAG_SYSTEM; ret = nouveau_bo_new(dev, size, align, flags, tile_mode, - tile_flags, NULL, pnvbo); + tile_flags, NULL, NULL, pnvbo); if (ret) return ret; nvbo = *pnvbo; @@ -173,7 +176,7 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain, */ nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART; - if (nv_device(drm->device)->card_type >= NV_50) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) nvbo->valid_domains &= domain; /* Initialize the embedded gem-object. We return a single gem-reference @@ -202,8 +205,8 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, rep->domain = NOUVEAU_GEM_DOMAIN_VRAM; rep->offset = nvbo->bo.offset; - if (cli->base.vm) { - vma = nouveau_bo_vma_find(nvbo, cli->base.vm); + if (cli->vm) { + vma = nouveau_bo_vma_find(nvbo, cli->vm); if (!vma) return -EINVAL; @@ -223,13 +226,13 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli = nouveau_cli(file_priv); - struct nouveau_fb *pfb = nouveau_fb(drm->device); + struct nouveau_fb *pfb = nvkm_fb(&drm->device); struct drm_nouveau_gem_new *req = data; struct nouveau_bo *nvbo = NULL; int ret = 0; if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { - NV_ERROR(cli, "bad page flags: 0x%08x\n", req->info.tile_flags); + NV_PRINTK(error, cli, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; } @@ -290,24 +293,23 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, } struct validate_op { - struct list_head vram_list; - struct list_head gart_list; - struct list_head both_list; + struct list_head list; struct ww_acquire_ctx ticket; }; static void -validate_fini_list(struct list_head *list, struct nouveau_fence *fence, - struct ww_acquire_ctx *ticket) +validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence, + struct drm_nouveau_gem_pushbuf_bo *pbbo) { - struct list_head *entry, *tmp; struct nouveau_bo *nvbo; + struct drm_nouveau_gem_pushbuf_bo *b; - list_for_each_safe(entry, tmp, list) { - nvbo = list_entry(entry, struct nouveau_bo, entry); + while (!list_empty(&op->list)) { + nvbo = list_entry(op->list.next, struct nouveau_bo, entry); + b = &pbbo[nvbo->pbbo_index]; if (likely(fence)) - nouveau_bo_fence(nvbo, fence); + nouveau_bo_fence(nvbo, fence, !!b->write_domains); if (unlikely(nvbo->validate_mapped)) { ttm_bo_kunmap(&nvbo->kmap); @@ -316,23 +318,16 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence, list_del(&nvbo->entry); nvbo->reserved_by = NULL; - ttm_bo_unreserve_ticket(&nvbo->bo, ticket); + ttm_bo_unreserve_ticket(&nvbo->bo, &op->ticket); drm_gem_object_unreference_unlocked(&nvbo->gem); } } static void -validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence) +validate_fini(struct validate_op *op, struct nouveau_fence *fence, + struct drm_nouveau_gem_pushbuf_bo *pbbo) { - validate_fini_list(&op->vram_list, fence, &op->ticket); - validate_fini_list(&op->gart_list, fence, &op->ticket); - validate_fini_list(&op->both_list, fence, &op->ticket); -} - -static void -validate_fini(struct validate_op *op, struct nouveau_fence *fence) -{ - validate_fini_no_ticket(op, fence); + validate_fini_no_ticket(op, fence, pbbo); ww_acquire_fini(&op->ticket); } @@ -346,11 +341,14 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, int trycnt = 0; int ret, i; struct nouveau_bo *res_bo = NULL; + LIST_HEAD(gart_list); + LIST_HEAD(vram_list); + LIST_HEAD(both_list); ww_acquire_init(&op->ticket, &reservation_ww_class); retry: if (++trycnt > 100000) { - NV_ERROR(cli, "%s failed and gave up.\n", __func__); + NV_PRINTK(error, cli, "%s failed and gave up.\n", __func__); return -EINVAL; } @@ -361,10 +359,9 @@ retry: gem = drm_gem_object_lookup(dev, file_priv, b->handle); if (!gem) { - NV_ERROR(cli, "Unknown handle 0x%08x\n", b->handle); - ww_acquire_done(&op->ticket); - validate_fini(op, NULL); - return -ENOENT; + NV_PRINTK(error, cli, "Unknown handle 0x%08x\n", b->handle); + ret = -ENOENT; + break; } nvbo = nouveau_gem_object(gem); if (nvbo == res_bo) { @@ -374,17 +371,19 @@ retry: } if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { - NV_ERROR(cli, "multiple instances of buffer %d on " + NV_PRINTK(error, cli, "multiple instances of buffer %d on " "validation list\n", b->handle); drm_gem_object_unreference_unlocked(gem); - ww_acquire_done(&op->ticket); - validate_fini(op, NULL); - return -EINVAL; + ret = -EINVAL; + break; } ret = ttm_bo_reserve(&nvbo->bo, true, false, true, &op->ticket); if (ret) { - validate_fini_no_ticket(op, NULL); + list_splice_tail_init(&vram_list, &op->list); + list_splice_tail_init(&gart_list, &op->list); + list_splice_tail_init(&both_list, &op->list); + validate_fini_no_ticket(op, NULL, NULL); if (unlikely(ret == -EDEADLK)) { ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, &op->ticket); @@ -392,12 +391,9 @@ retry: res_bo = nvbo; } if (unlikely(ret)) { - ww_acquire_done(&op->ticket); - ww_acquire_fini(&op->ticket); - drm_gem_object_unreference_unlocked(gem); if (ret != -ERESTARTSYS) - NV_ERROR(cli, "fail reserve\n"); - return ret; + NV_PRINTK(error, cli, "fail reserve\n"); + break; } } @@ -406,45 +402,32 @@ retry: nvbo->pbbo_index = i; if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) && (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART)) - list_add_tail(&nvbo->entry, &op->both_list); + list_add_tail(&nvbo->entry, &both_list); else if (b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) - list_add_tail(&nvbo->entry, &op->vram_list); + list_add_tail(&nvbo->entry, &vram_list); else if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART) - list_add_tail(&nvbo->entry, &op->gart_list); + list_add_tail(&nvbo->entry, &gart_list); else { - NV_ERROR(cli, "invalid valid domains: 0x%08x\n", + NV_PRINTK(error, cli, "invalid valid domains: 0x%08x\n", b->valid_domains); - list_add_tail(&nvbo->entry, &op->both_list); - ww_acquire_done(&op->ticket); - validate_fini(op, NULL); - return -EINVAL; + list_add_tail(&nvbo->entry, &both_list); + ret = -EINVAL; + break; } if (nvbo == res_bo) goto retry; } ww_acquire_done(&op->ticket); - return 0; -} - -static int -validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo) -{ - struct nouveau_fence *fence = NULL; - int ret = 0; - - spin_lock(&nvbo->bo.bdev->fence_lock); - fence = nouveau_fence_ref(nvbo->bo.sync_obj); - spin_unlock(&nvbo->bo.bdev->fence_lock); - - if (fence) { - ret = nouveau_fence_sync(fence, chan); - nouveau_fence_unref(&fence); - } - + list_splice_tail(&vram_list, &op->list); + list_splice_tail(&gart_list, &op->list); + list_splice_tail(&both_list, &op->list); + if (ret) + validate_fini(op, NULL, NULL); return ret; + } static int @@ -465,24 +448,25 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, b->write_domains, b->valid_domains); if (unlikely(ret)) { - NV_ERROR(cli, "fail set_domain\n"); + NV_PRINTK(error, cli, "fail set_domain\n"); return ret; } ret = nouveau_bo_validate(nvbo, true, false); if (unlikely(ret)) { if (ret != -ERESTARTSYS) - NV_ERROR(cli, "fail ttm_validate\n"); + NV_PRINTK(error, cli, "fail ttm_validate\n"); return ret; } - ret = validate_sync(chan, nvbo); + ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains, true); if (unlikely(ret)) { - NV_ERROR(cli, "fail post-validate sync\n"); + if (ret != -ERESTARTSYS) + NV_PRINTK(error, cli, "fail post-validate sync\n"); return ret; } - if (nv_device(drm->device)->card_type < NV_50) { + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { if (nvbo->bo.offset == b->presumed.offset && ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || @@ -515,11 +499,9 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, struct validate_op *op, int *apply_relocs) { struct nouveau_cli *cli = nouveau_cli(file_priv); - int ret, relocs = 0; + int ret; - INIT_LIST_HEAD(&op->vram_list); - INIT_LIST_HEAD(&op->gart_list); - INIT_LIST_HEAD(&op->both_list); + INIT_LIST_HEAD(&op->list); if (nr_buffers == 0) return 0; @@ -527,38 +509,18 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); if (unlikely(ret)) { if (ret != -ERESTARTSYS) - NV_ERROR(cli, "validate_init\n"); + NV_PRINTK(error, cli, "validate_init\n"); return ret; } - ret = validate_list(chan, cli, &op->vram_list, pbbo, user_buffers); + ret = validate_list(chan, cli, &op->list, pbbo, user_buffers); if (unlikely(ret < 0)) { if (ret != -ERESTARTSYS) - NV_ERROR(cli, "validate vram_list\n"); - validate_fini(op, NULL); + NV_PRINTK(error, cli, "validating bo list\n"); + validate_fini(op, NULL, NULL); return ret; } - relocs += ret; - - ret = validate_list(chan, cli, &op->gart_list, pbbo, user_buffers); - if (unlikely(ret < 0)) { - if (ret != -ERESTARTSYS) - NV_ERROR(cli, "validate gart_list\n"); - validate_fini(op, NULL); - return ret; - } - relocs += ret; - - ret = validate_list(chan, cli, &op->both_list, pbbo, user_buffers); - if (unlikely(ret < 0)) { - if (ret != -ERESTARTSYS) - NV_ERROR(cli, "validate both_list\n"); - validate_fini(op, NULL); - return ret; - } - relocs += ret; - - *apply_relocs = relocs; + *apply_relocs = ret; return 0; } @@ -613,7 +575,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, uint32_t data; if (unlikely(r->bo_index > req->nr_buffers)) { - NV_ERROR(cli, "reloc bo index invalid\n"); + NV_PRINTK(error, cli, "reloc bo index invalid\n"); ret = -EINVAL; break; } @@ -623,7 +585,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, continue; if (unlikely(r->reloc_bo_index > req->nr_buffers)) { - NV_ERROR(cli, "reloc container bo index invalid\n"); + NV_PRINTK(error, cli, "reloc container bo index invalid\n"); ret = -EINVAL; break; } @@ -631,7 +593,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, if (unlikely(r->reloc_bo_offset + 4 > nvbo->bo.mem.num_pages << PAGE_SHIFT)) { - NV_ERROR(cli, "reloc outside of bo\n"); + NV_PRINTK(error, cli, "reloc outside of bo\n"); ret = -EINVAL; break; } @@ -640,7 +602,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap); if (ret) { - NV_ERROR(cli, "failed kmap for reloc\n"); + NV_PRINTK(error, cli, "failed kmap for reloc\n"); break; } nvbo->validate_mapped = true; @@ -661,11 +623,9 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, data |= r->vor; } - spin_lock(&nvbo->bo.bdev->fence_lock); - ret = ttm_bo_wait(&nvbo->bo, false, false, false); - spin_unlock(&nvbo->bo.bdev->fence_lock); + ret = ttm_bo_wait(&nvbo->bo, true, false, false); if (ret) { - NV_ERROR(cli, "reloc wait_idle failed: %d\n", ret); + NV_PRINTK(error, cli, "reloc wait_idle failed: %d\n", ret); break; } @@ -696,7 +656,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, return -ENOMEM; list_for_each_entry(temp, &abi16->channels, head) { - if (temp->chan->handle == (NVDRM_CHAN | req->channel)) { + if (temp->chan->object->handle == (NVDRM_CHAN | req->channel)) { chan = temp->chan; break; } @@ -711,19 +671,19 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, goto out_next; if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { - NV_ERROR(cli, "pushbuf push count exceeds limit: %d max %d\n", + NV_PRINTK(error, cli, "pushbuf push count exceeds limit: %d max %d\n", req->nr_push, NOUVEAU_GEM_MAX_PUSH); return nouveau_abi16_put(abi16, -EINVAL); } if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { - NV_ERROR(cli, "pushbuf bo count exceeds limit: %d max %d\n", + NV_PRINTK(error, cli, "pushbuf bo count exceeds limit: %d max %d\n", req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); return nouveau_abi16_put(abi16, -EINVAL); } if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { - NV_ERROR(cli, "pushbuf reloc count exceeds limit: %d max %d\n", + NV_PRINTK(error, cli, "pushbuf reloc count exceeds limit: %d max %d\n", req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); return nouveau_abi16_put(abi16, -EINVAL); } @@ -741,7 +701,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, /* Ensure all push buffers are on validate list */ for (i = 0; i < req->nr_push; i++) { if (push[i].bo_index >= req->nr_buffers) { - NV_ERROR(cli, "push %d buffer not in list\n", i); + NV_PRINTK(error, cli, "push %d buffer not in list\n", i); ret = -EINVAL; goto out_prevalid; } @@ -752,7 +712,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, req->nr_buffers, &op, &do_reloc); if (ret) { if (ret != -ERESTARTSYS) - NV_ERROR(cli, "validate: %d\n", ret); + NV_PRINTK(error, cli, "validate: %d\n", ret); goto out_prevalid; } @@ -760,7 +720,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (do_reloc) { ret = nouveau_gem_pushbuf_reloc_apply(cli, req, bo); if (ret) { - NV_ERROR(cli, "reloc apply: %d\n", ret); + NV_PRINTK(error, cli, "reloc apply: %d\n", ret); goto out; } } @@ -768,7 +728,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (chan->dma.ib_max) { ret = nouveau_dma_wait(chan, req->nr_push + 1, 16); if (ret) { - NV_ERROR(cli, "nv50cal_space: %d\n", ret); + NV_PRINTK(error, cli, "nv50cal_space: %d\n", ret); goto out; } @@ -780,10 +740,10 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, push[i].length); } } else - if (nv_device(drm->device)->chipset >= 0x25) { + if (drm->device.info.chipset >= 0x25) { ret = RING_SPACE(chan, req->nr_push * 2); if (ret) { - NV_ERROR(cli, "cal_space: %d\n", ret); + NV_PRINTK(error, cli, "cal_space: %d\n", ret); goto out; } @@ -797,7 +757,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } else { ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS)); if (ret) { - NV_ERROR(cli, "jmp_space: %d\n", ret); + NV_PRINTK(error, cli, "jmp_space: %d\n", ret); goto out; } @@ -835,13 +795,13 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ret = nouveau_fence_new(chan, false, &fence); if (ret) { - NV_ERROR(cli, "error fencing pushbuf: %d\n", ret); + NV_PRINTK(error, cli, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); goto out; } out: - validate_fini(&op, fence); + validate_fini(&op, fence, bo); nouveau_fence_unref(&fence); out_prevalid: @@ -853,7 +813,7 @@ out_next: req->suffix0 = 0x00000000; req->suffix1 = 0x00000000; } else - if (nv_device(drm->device)->chipset >= 0x25) { + if (drm->device.info.chipset >= 0x25) { req->suffix0 = 0x00020000; req->suffix1 = 0x00000000; } else { @@ -886,17 +846,29 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, struct drm_gem_object *gem; struct nouveau_bo *nvbo; bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); - int ret = -EINVAL; + bool write = !!(req->flags & NOUVEAU_GEM_CPU_PREP_WRITE); + int ret; gem = drm_gem_object_lookup(dev, file_priv, req->handle); if (!gem) return -ENOENT; nvbo = nouveau_gem_object(gem); - spin_lock(&nvbo->bo.bdev->fence_lock); - ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait); - spin_unlock(&nvbo->bo.bdev->fence_lock); + if (no_wait) + ret = reservation_object_test_signaled_rcu(nvbo->bo.resv, write) ? 0 : -EBUSY; + else { + long lret; + + lret = reservation_object_wait_timeout_rcu(nvbo->bo.resv, write, true, 30 * HZ); + if (!lret) + ret = -EBUSY; + else if (lret > 0) + ret = 0; + else + ret = lret; + } drm_gem_object_unreference_unlocked(gem); + return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.h b/drivers/gpu/drm/nouveau/nouveau_gem.h index ddab762d81fe..e4049faca780 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.h +++ b/drivers/gpu/drm/nouveau/nouveau_gem.h @@ -39,7 +39,7 @@ struct reservation_object *nouveau_gem_prime_res_obj(struct drm_gem_object *); extern void nouveau_gem_prime_unpin(struct drm_gem_object *); extern struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *); extern struct drm_gem_object *nouveau_gem_prime_import_sg_table( - struct drm_device *, size_t size, struct sg_table *); + struct drm_device *, struct dma_buf_attachment *, struct sg_table *); extern void *nouveau_gem_prime_vmap(struct drm_gem_object *); extern void nouveau_gem_prime_vunmap(struct drm_gem_object *, void *); diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 19fd767bab10..afb36d66e78d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -34,17 +34,13 @@ #include "nouveau_drm.h" #include "nouveau_hwmon.h" -#include <subdev/gpio.h> -#include <subdev/timer.h> -#include <subdev/therm.h> - #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); int temp = therm->temp_get(therm); if (temp < 0) @@ -70,7 +66,7 @@ nouveau_hwmon_temp1_auto_point1_temp(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST) * 1000); @@ -82,7 +78,7 @@ nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -103,7 +99,7 @@ nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000); @@ -115,7 +111,7 @@ nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -135,7 +131,7 @@ nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000); @@ -146,7 +142,7 @@ nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -166,7 +162,7 @@ nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000); @@ -177,7 +173,7 @@ nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -198,7 +194,7 @@ nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000); @@ -210,7 +206,7 @@ nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -231,7 +227,7 @@ nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000); @@ -244,7 +240,7 @@ nouveau_hwmon_set_critical_temp_hyst(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -264,7 +260,7 @@ nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000); @@ -276,7 +272,7 @@ nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -297,7 +293,7 @@ nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000); @@ -310,7 +306,7 @@ nouveau_hwmon_set_emergency_temp_hyst(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; if (kstrtol(buf, 10, &value) == -EINVAL) @@ -350,7 +346,7 @@ nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm)); } @@ -363,7 +359,7 @@ nouveau_hwmon_get_pwm1_enable(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); int ret; ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE); @@ -379,7 +375,7 @@ nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; int ret; @@ -402,7 +398,7 @@ nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); int ret; ret = therm->fan_get(therm); @@ -418,7 +414,7 @@ nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); int ret = -ENODEV; long value; @@ -442,7 +438,7 @@ nouveau_hwmon_get_pwm1_min(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); int ret; ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY); @@ -458,7 +454,7 @@ nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; int ret; @@ -482,7 +478,7 @@ nouveau_hwmon_get_pwm1_max(struct device *d, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); int ret; ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY); @@ -498,7 +494,7 @@ nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, { struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); long value; int ret; @@ -565,7 +561,7 @@ nouveau_hwmon_init(struct drm_device *dev) { #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); + struct nouveau_therm *therm = nvkm_therm(&drm->device); struct nouveau_hwmon *hwmon; struct device *hwmon_dev; int ret = 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c new file mode 100644 index 000000000000..6544b84f0303 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c @@ -0,0 +1,136 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +/******************************************************************************* + * NVIF client driver - NVKM directly linked + ******************************************************************************/ + +#include <core/client.h> +#include <core/notify.h> +#include <core/ioctl.h> + +#include <nvif/client.h> +#include <nvif/driver.h> +#include <nvif/notify.h> +#include <nvif/event.h> +#include <nvif/ioctl.h> + +#include "nouveau_drm.h" +#include "nouveau_usif.h" + +static void +nvkm_client_unmap(void *priv, void __iomem *ptr, u32 size) +{ + iounmap(ptr); +} + +static void __iomem * +nvkm_client_map(void *priv, u64 handle, u32 size) +{ + return ioremap(handle, size); +} + +static int +nvkm_client_ioctl(void *priv, bool super, void *data, u32 size, void **hack) +{ + return nvkm_ioctl(priv, super, data, size, hack); +} + +static int +nvkm_client_resume(void *priv) +{ + return nouveau_client_init(priv); +} + +static int +nvkm_client_suspend(void *priv) +{ + return nouveau_client_fini(priv, true); +} + +static void +nvkm_client_fini(void *priv) +{ + struct nouveau_object *client = priv; + nouveau_client_fini(nv_client(client), false); + atomic_set(&client->refcount, 1); + nouveau_object_ref(NULL, &client); +} + +static int +nvkm_client_ntfy(const void *header, u32 length, const void *data, u32 size) +{ + const union { + struct nvif_notify_req_v0 v0; + } *args = header; + u8 route; + + if (length == sizeof(args->v0) && args->v0.version == 0) { + route = args->v0.route; + } else { + WARN_ON(1); + return NVKM_NOTIFY_DROP; + } + + switch (route) { + case NVDRM_NOTIFY_NVIF: + return nvif_notify(header, length, data, size); + case NVDRM_NOTIFY_USIF: + return usif_notify(header, length, data, size); + default: + WARN_ON(1); + break; + } + + return NVKM_NOTIFY_DROP; +} + +static int +nvkm_client_init(const char *name, u64 device, const char *cfg, + const char *dbg, void **ppriv) +{ + struct nouveau_client *client; + int ret; + + ret = nouveau_client_create(name, device, cfg, dbg, &client); + *ppriv = client; + if (ret) + return ret; + + client->ntfy = nvkm_client_ntfy; + return 0; +} + +const struct nvif_driver +nvif_driver_nvkm = { + .name = "nvkm", + .init = nvkm_client_init, + .fini = nvkm_client_fini, + .suspend = nvkm_client_suspend, + .resume = nvkm_client_resume, + .ioctl = nvkm_client_ioctl, + .map = nvkm_client_map, + .unmap = nvkm_client_unmap, + .keep = false, +}; diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c new file mode 100644 index 000000000000..246a824c16ca --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2014, 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 <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/reset.h> +#include <linux/regulator/consumer.h> +#include <soc/tegra/pmc.h> + +#include "nouveau_drm.h" +#include "nouveau_platform.h" + +static int nouveau_platform_power_up(struct nouveau_platform_gpu *gpu) +{ + int err; + + err = regulator_enable(gpu->vdd); + if (err) + goto err_power; + + err = clk_prepare_enable(gpu->clk); + if (err) + goto err_clk; + err = clk_prepare_enable(gpu->clk_pwr); + if (err) + goto err_clk_pwr; + clk_set_rate(gpu->clk_pwr, 204000000); + udelay(10); + + reset_control_assert(gpu->rst); + udelay(10); + + err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); + if (err) + goto err_clamp; + udelay(10); + + reset_control_deassert(gpu->rst); + udelay(10); + + return 0; + +err_clamp: + clk_disable_unprepare(gpu->clk_pwr); +err_clk_pwr: + clk_disable_unprepare(gpu->clk); +err_clk: + regulator_disable(gpu->vdd); +err_power: + return err; +} + +static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu) +{ + int err; + + reset_control_assert(gpu->rst); + udelay(10); + + clk_disable_unprepare(gpu->clk_pwr); + clk_disable_unprepare(gpu->clk); + udelay(10); + + err = regulator_disable(gpu->vdd); + if (err) + return err; + + return 0; +} + +static int nouveau_platform_probe(struct platform_device *pdev) +{ + struct nouveau_platform_gpu *gpu; + struct nouveau_platform_device *device; + struct drm_device *drm; + int err; + + gpu = devm_kzalloc(&pdev->dev, sizeof(*gpu), GFP_KERNEL); + if (!gpu) + return -ENOMEM; + + gpu->vdd = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(gpu->vdd)) + return PTR_ERR(gpu->vdd); + + gpu->rst = devm_reset_control_get(&pdev->dev, "gpu"); + if (IS_ERR(gpu->rst)) + return PTR_ERR(gpu->rst); + + gpu->clk = devm_clk_get(&pdev->dev, "gpu"); + if (IS_ERR(gpu->clk)) + return PTR_ERR(gpu->clk); + + gpu->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); + if (IS_ERR(gpu->clk_pwr)) + return PTR_ERR(gpu->clk_pwr); + + err = nouveau_platform_power_up(gpu); + if (err) + return err; + + drm = nouveau_platform_device_create(pdev, &device); + if (IS_ERR(drm)) { + err = PTR_ERR(drm); + goto power_down; + } + + device->gpu = gpu; + + err = drm_dev_register(drm, 0); + if (err < 0) + goto err_unref; + + return 0; + +err_unref: + drm_dev_unref(drm); + + return 0; + +power_down: + nouveau_platform_power_down(gpu); + + return err; +} + +static int nouveau_platform_remove(struct platform_device *pdev) +{ + struct drm_device *drm_dev = platform_get_drvdata(pdev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nouveau_device *device = nvkm_device(&drm->device); + struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu; + + nouveau_drm_device_remove(drm_dev); + + return nouveau_platform_power_down(gpu); +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id nouveau_platform_match[] = { + { .compatible = "nvidia,gk20a" }, + { } +}; + +MODULE_DEVICE_TABLE(of, nouveau_platform_match); +#endif + +struct platform_driver nouveau_platform_driver = { + .driver = { + .name = "nouveau", + .of_match_table = of_match_ptr(nouveau_platform_match), + }, + .probe = nouveau_platform_probe, + .remove = nouveau_platform_remove, +}; + +module_platform_driver(nouveau_platform_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.h b/drivers/gpu/drm/nouveau/nouveau_platform.h new file mode 100644 index 000000000000..91f66504900e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_platform.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, 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. + */ + +#ifndef __NOUVEAU_PLATFORM_H__ +#define __NOUVEAU_PLATFORM_H__ + +#include "core/device.h" + +struct reset_control; +struct clk; +struct regulator; + +struct nouveau_platform_gpu { + struct reset_control *rst; + struct clk *clk; + struct clk *clk_pwr; + + struct regulator *vdd; +}; + +struct nouveau_platform_device { + struct nouveau_device device; + + struct nouveau_platform_gpu *gpu; +}; + +#define nv_device_to_platform(d) \ + container_of(d, struct nouveau_platform_device, device) + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index 1f51008e4d26..228226ab27fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -23,6 +23,7 @@ */ #include <drm/drmP.h> +#include <linux/dma-buf.h> #include "nouveau_drm.h" #include "nouveau_gem.h" @@ -56,17 +57,20 @@ void nouveau_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) } struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, - size_t size, + struct dma_buf_attachment *attach, struct sg_table *sg) { struct nouveau_bo *nvbo; + struct reservation_object *robj = attach->dmabuf->resv; u32 flags = 0; int ret; flags = TTM_PL_FLAG_TT; - ret = nouveau_bo_new(dev, size, 0, flags, 0, 0, - sg, &nvbo); + ww_mutex_lock(&robj->lock, NULL); + ret = nouveau_bo_new(dev, attach->dmabuf->size, 0, flags, 0, 0, + sg, robj, &nvbo); + ww_mutex_unlock(&robj->lock); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index a4d22e5eb176..01707e7deaf5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -1,8 +1,6 @@ #include <linux/pagemap.h> #include <linux/slab.h> -#include <subdev/fb.h> - #include "nouveau_drm.h" #include "nouveau_ttm.h" @@ -104,7 +102,7 @@ nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev, return NULL; nvbe->dev = drm->dev; - if (nv_device(drm->device)->card_type < NV_50) + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) nvbe->ttm.ttm.func = &nv04_sgdma_backend; else nvbe->ttm.ttm.func = &nv50_sgdma_backend; diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c index 75dda2b07176..8fbbf3093d86 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c @@ -22,10 +22,15 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ +#include <nvif/os.h> +#include <nvif/class.h> +#include <nvif/ioctl.h> + #include "nouveau_sysfs.h" -#include <core/object.h> -#include <core/class.h> +MODULE_PARM_DESC(pstate, "enable sysfs pstate file, which will be moved in the future"); +int nouveau_pstate; +module_param_named(pstate, nouveau_pstate, int, 0400); static inline struct drm_device * drm_device(struct device *d) @@ -43,38 +48,42 @@ static ssize_t nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b) { struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d)); - struct nv_control_pstate_info info; + struct nvif_control_pstate_info_v0 info = {}; size_t cnt = PAGE_SIZE; char *buf = b; int ret, i; - ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_INFO, &info, sizeof(info)); + ret = nvif_mthd(&sysfs->ctrl, NVIF_CONTROL_PSTATE_INFO, + &info, sizeof(info)); if (ret) return ret; for (i = 0; i < info.count + 1; i++) { const s32 state = i < info.count ? i : - NV_CONTROL_PSTATE_ATTR_STATE_CURRENT; - struct nv_control_pstate_attr attr = { + NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT; + struct nvif_control_pstate_attr_v0 attr = { .state = state, .index = 0, }; - ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR, - &attr, sizeof(attr)); + ret = nvif_mthd(&sysfs->ctrl, NVIF_CONTROL_PSTATE_ATTR, + &attr, sizeof(attr)); if (ret) return ret; if (i < info.count) snappendf(buf, cnt, "%02x:", attr.state); else - snappendf(buf, cnt, "--:"); + snappendf(buf, cnt, "%s:", info.pwrsrc == 0 ? "DC" : + info.pwrsrc == 1 ? "AC" : + "--"); attr.index = 0; do { attr.state = state; - ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR, - &attr, sizeof(attr)); + ret = nvif_mthd(&sysfs->ctrl, + NVIF_CONTROL_PSTATE_ATTR, + &attr, sizeof(attr)); if (ret) return ret; @@ -84,9 +93,20 @@ nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b) snappendf(buf, cnt, " %s", attr.unit); } while (attr.index); - if ((state >= 0 && info.pstate == state) || - (state < 0 && info.ustate < 0)) - snappendf(buf, cnt, " *"); + if (state >= 0) { + if (info.ustate_ac == state) + snappendf(buf, cnt, " AC"); + if (info.ustate_dc == state) + snappendf(buf, cnt, " DC"); + if (info.pstate == state) + snappendf(buf, cnt, " *"); + } else { + if (info.ustate_ac < -1) + snappendf(buf, cnt, " AC"); + if (info.ustate_dc < -1) + snappendf(buf, cnt, " DC"); + } + snappendf(buf, cnt, "\n"); } @@ -98,26 +118,36 @@ nouveau_sysfs_pstate_set(struct device *d, struct device_attribute *a, const char *buf, size_t count) { struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d)); - struct nv_control_pstate_user args; + struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL }; long value, ret; char *tmp; if ((tmp = strchr(buf, '\n'))) *tmp = '\0'; + if (!strncasecmp(buf, "dc:", 3)) { + args.pwrsrc = 0; + buf += 3; + } else + if (!strncasecmp(buf, "ac:", 3)) { + args.pwrsrc = 1; + buf += 3; + } + if (!strcasecmp(buf, "none")) - args.state = NV_CONTROL_PSTATE_USER_STATE_UNKNOWN; + args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN; else if (!strcasecmp(buf, "auto")) - args.state = NV_CONTROL_PSTATE_USER_STATE_PERFMON; + args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON; else { ret = kstrtol(buf, 16, &value); if (ret) return ret; - args.state = value; + args.ustate = value; } - ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_USER, &args, sizeof(args)); + ret = nvif_mthd(&sysfs->ctrl, NVIF_CONTROL_PSTATE_USER, + &args, sizeof(args)); if (ret < 0) return ret; @@ -132,11 +162,11 @@ nouveau_sysfs_fini(struct drm_device *dev) { struct nouveau_sysfs *sysfs = nouveau_sysfs(dev); struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; - if (sysfs->ctrl) { - device_remove_file(nv_device_base(device), &dev_attr_pstate); - nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL); + if (sysfs && sysfs->ctrl.priv) { + device_remove_file(nv_device_base(nvkm_device(device)), &dev_attr_pstate); + nvif_object_fini(&sysfs->ctrl); } drm->sysfs = NULL; @@ -147,18 +177,22 @@ int nouveau_sysfs_init(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct nouveau_sysfs *sysfs; int ret; + if (!nouveau_pstate) + return 0; + sysfs = drm->sysfs = kzalloc(sizeof(*sysfs), GFP_KERNEL); if (!sysfs) return -ENOMEM; - ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL, - NV_CONTROL_CLASS, NULL, 0, &sysfs->ctrl); + ret = nvif_object_init(nvif_object(device), NULL, NVDRM_CONTROL, + NVIF_IOCTL_NEW_V0_CONTROL, NULL, 0, + &sysfs->ctrl); if (ret == 0) - device_create_file(nv_device_base(device), &dev_attr_pstate); + device_create_file(nv_device_base(nvkm_device(device)), &dev_attr_pstate); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.h b/drivers/gpu/drm/nouveau/nouveau_sysfs.h index 74b47f1e01ed..4e5ea9241b28 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sysfs.h +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.h @@ -4,7 +4,7 @@ #include "nouveau_drm.h" struct nouveau_sysfs { - struct nouveau_object *ctrl; + struct nvif_object ctrl; }; static inline struct nouveau_sysfs * @@ -16,4 +16,6 @@ nouveau_sysfs(struct drm_device *dev) int nouveau_sysfs_init(struct drm_device *); void nouveau_sysfs_fini(struct drm_device *); +extern int nouveau_pstate; + #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index ab0228f640a5..753a6def61e7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -24,10 +24,6 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include <subdev/fb.h> -#include <subdev/vm.h> -#include <subdev/instmem.h> - #include "nouveau_drm.h" #include "nouveau_ttm.h" #include "nouveau_gem.h" @@ -36,7 +32,7 @@ static int nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nouveau_fb *pfb = nouveau_fb(drm->device); + struct nouveau_fb *pfb = nvkm_fb(&drm->device); man->priv = pfb; return 0; } @@ -67,7 +63,7 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nouveau_fb *pfb = nouveau_fb(drm->device); + struct nouveau_fb *pfb = nvkm_fb(&drm->device); nouveau_mem_node_cleanup(mem->mm_node); pfb->ram->put(pfb, (struct nouveau_mem **)&mem->mm_node); } @@ -75,11 +71,11 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man, static int nouveau_vram_manager_new(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nouveau_fb *pfb = nouveau_fb(drm->device); + struct nouveau_fb *pfb = nvkm_fb(&drm->device); struct nouveau_bo *nvbo = nouveau_bo(bo); struct nouveau_mem *node; u32 size_nc = 0; @@ -161,7 +157,7 @@ nouveau_gart_manager_del(struct ttm_mem_type_manager *man, static int nouveau_gart_manager_new(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); @@ -174,14 +170,13 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man, node->page_shift = 12; - switch (nv_device(drm->device)->card_type) { - case NV_50: - if (nv_device(drm->device)->chipset != 0x50) + switch (drm->device.info.family) { + case NV_DEVICE_INFO_V0_TESLA: + if (drm->device.info.chipset != 0x50) node->memtype = (nvbo->tile_flags & 0x7f00) >> 8; break; - case NV_C0: - case NV_D0: - case NV_E0: + case NV_DEVICE_INFO_V0_FERMI: + case NV_DEVICE_INFO_V0_KEPLER: node->memtype = (nvbo->tile_flags & 0xff00) >> 8; break; default: @@ -206,12 +201,13 @@ const struct ttm_mem_type_manager_func nouveau_gart_manager = { nouveau_gart_manager_debug }; +/*XXX*/ #include <core/subdev/vm/nv04.h> static int nv04_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nouveau_vmmgr *vmm = nouveau_vmmgr(drm->device); + struct nouveau_vmmgr *vmm = nvkm_vmmgr(&drm->device); struct nv04_vmmgr_priv *priv = (void *)vmm; struct nouveau_vm *vm = NULL; nouveau_vm_ref(priv->vm, &vm, NULL); @@ -241,7 +237,7 @@ nv04_gart_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) static int nv04_gart_manager_new(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct nouveau_mem *node; @@ -285,7 +281,7 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev); if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) - return drm_mmap(filp, vma); + return -EINVAL; return ttm_bo_mmap(filp, vma, &drm->ttm.bdev); } @@ -354,12 +350,11 @@ int nouveau_ttm_init(struct nouveau_drm *drm) { struct drm_device *dev = drm->dev; - struct nouveau_device *device = nv_device(drm->device); u32 bits; int ret; - bits = nouveau_vmmgr(drm->device)->dma_bits; - if (nv_device_is_pci(device)) { + bits = nvkm_vmmgr(&drm->device)->dma_bits; + if (nv_device_is_pci(nvkm_device(&drm->device))) { if (drm->agp.stat == ENABLED || !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) bits = 32; @@ -391,8 +386,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) } /* VRAM init */ - drm->gem.vram_available = nouveau_fb(drm->device)->ram->size; - drm->gem.vram_available -= nouveau_instmem(drm->device)->reserved; + drm->gem.vram_available = drm->device.info.ram_user; ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM, drm->gem.vram_available >> PAGE_SHIFT); @@ -401,12 +395,12 @@ nouveau_ttm_init(struct nouveau_drm *drm) return ret; } - drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(device, 1), - nv_device_resource_len(device, 1)); + drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(nvkm_device(&drm->device), 1), + nv_device_resource_len(nvkm_device(&drm->device), 1)); /* GART init */ if (drm->agp.stat != ENABLED) { - drm->gem.gart_available = nouveau_vmmgr(drm->device)->limit; + drm->gem.gart_available = nvkm_vmmgr(&drm->device)->limit; } else { drm->gem.gart_available = drm->agp.size; } diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c new file mode 100644 index 000000000000..cb1182d7e80e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_usif.c @@ -0,0 +1,384 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +#include "nouveau_drm.h" +#include "nouveau_usif.h" + +#include <nvif/notify.h> +#include <nvif/unpack.h> +#include <nvif/client.h> +#include <nvif/event.h> +#include <nvif/ioctl.h> + +struct usif_notify_p { + struct drm_pending_event base; + struct { + struct drm_event base; + u8 data[]; + } e; +}; + +struct usif_notify { + struct list_head head; + atomic_t enabled; + u32 handle; + u16 reply; + u8 route; + u64 token; + struct usif_notify_p *p; +}; + +static inline struct usif_notify * +usif_notify_find(struct drm_file *filp, u32 handle) +{ + struct nouveau_cli *cli = nouveau_cli(filp); + struct usif_notify *ntfy; + list_for_each_entry(ntfy, &cli->notifys, head) { + if (ntfy->handle == handle) + return ntfy; + } + return NULL; +} + +static inline void +usif_notify_dtor(struct usif_notify *ntfy) +{ + list_del(&ntfy->head); + kfree(ntfy); +} + +int +usif_notify(const void *header, u32 length, const void *data, u32 size) +{ + struct usif_notify *ntfy = NULL; + const union { + struct nvif_notify_rep_v0 v0; + } *rep = header; + struct drm_device *dev; + struct drm_file *filp; + unsigned long flags; + + if (length == sizeof(rep->v0) && rep->v0.version == 0) { + if (WARN_ON(!(ntfy = (void *)(unsigned long)rep->v0.token))) + return NVIF_NOTIFY_DROP; + BUG_ON(rep->v0.route != NVDRM_NOTIFY_USIF); + } else + if (WARN_ON(1)) + return NVIF_NOTIFY_DROP; + + if (WARN_ON(!ntfy->p || ntfy->reply != (length + size))) + return NVIF_NOTIFY_DROP; + filp = ntfy->p->base.file_priv; + dev = filp->minor->dev; + + memcpy(&ntfy->p->e.data[0], header, length); + memcpy(&ntfy->p->e.data[length], data, size); + switch (rep->v0.version) { + case 0: { + struct nvif_notify_rep_v0 *rep = (void *)ntfy->p->e.data; + rep->route = ntfy->route; + rep->token = ntfy->token; + } + break; + default: + BUG_ON(1); + break; + } + + spin_lock_irqsave(&dev->event_lock, flags); + if (!WARN_ON(filp->event_space < ntfy->p->e.base.length)) { + list_add_tail(&ntfy->p->base.link, &filp->event_list); + filp->event_space -= ntfy->p->e.base.length; + } + wake_up_interruptible(&filp->event_wait); + spin_unlock_irqrestore(&dev->event_lock, flags); + atomic_set(&ntfy->enabled, 0); + return NVIF_NOTIFY_DROP; +} + +static int +usif_notify_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) +{ + struct nouveau_cli *cli = nouveau_cli(f); + struct nvif_client *client = &cli->base; + union { + struct nvif_ioctl_ntfy_new_v0 v0; + } *args = data; + union { + struct nvif_notify_req_v0 v0; + } *req; + struct usif_notify *ntfy; + int ret; + + if (nvif_unpack(args->v0, 0, 0, true)) { + if (usif_notify_find(f, args->v0.index)) + return -EEXIST; + } else + return ret; + req = data; + + if (!(ntfy = kmalloc(sizeof(*ntfy), GFP_KERNEL))) + return -ENOMEM; + atomic_set(&ntfy->enabled, 0); + + if (nvif_unpack(req->v0, 0, 0, true)) { + ntfy->reply = sizeof(struct nvif_notify_rep_v0) + req->v0.reply; + ntfy->route = req->v0.route; + ntfy->token = req->v0.token; + req->v0.route = NVDRM_NOTIFY_USIF; + req->v0.token = (unsigned long)(void *)ntfy; + ret = nvif_client_ioctl(client, argv, argc); + req->v0.token = ntfy->token; + req->v0.route = ntfy->route; + ntfy->handle = args->v0.index; + } + + if (ret == 0) + list_add(&ntfy->head, &cli->notifys); + if (ret) + kfree(ntfy); + return ret; +} + +static int +usif_notify_del(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) +{ + struct nouveau_cli *cli = nouveau_cli(f); + struct nvif_client *client = &cli->base; + union { + struct nvif_ioctl_ntfy_del_v0 v0; + } *args = data; + struct usif_notify *ntfy; + int ret; + + if (nvif_unpack(args->v0, 0, 0, true)) { + if (!(ntfy = usif_notify_find(f, args->v0.index))) + return -ENOENT; + } else + return ret; + + ret = nvif_client_ioctl(client, argv, argc); + if (ret == 0) + usif_notify_dtor(ntfy); + return ret; +} + +static int +usif_notify_get(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) +{ + struct nouveau_cli *cli = nouveau_cli(f); + struct nvif_client *client = &cli->base; + union { + struct nvif_ioctl_ntfy_del_v0 v0; + } *args = data; + struct usif_notify *ntfy; + int ret; + + if (nvif_unpack(args->v0, 0, 0, true)) { + if (!(ntfy = usif_notify_find(f, args->v0.index))) + return -ENOENT; + } else + return ret; + + if (atomic_xchg(&ntfy->enabled, 1)) + return 0; + + ntfy->p = kmalloc(sizeof(*ntfy->p) + ntfy->reply, GFP_KERNEL); + if (ret = -ENOMEM, !ntfy->p) + goto done; + ntfy->p->base.event = &ntfy->p->e.base; + ntfy->p->base.file_priv = f; + ntfy->p->base.pid = current->pid; + ntfy->p->base.destroy =(void(*)(struct drm_pending_event *))kfree; + ntfy->p->e.base.type = DRM_NOUVEAU_EVENT_NVIF; + ntfy->p->e.base.length = sizeof(ntfy->p->e.base) + ntfy->reply; + + ret = nvif_client_ioctl(client, argv, argc); +done: + if (ret) { + atomic_set(&ntfy->enabled, 0); + kfree(ntfy->p); + } + return ret; +} + +static int +usif_notify_put(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) +{ + struct nouveau_cli *cli = nouveau_cli(f); + struct nvif_client *client = &cli->base; + union { + struct nvif_ioctl_ntfy_put_v0 v0; + } *args = data; + struct usif_notify *ntfy; + int ret; + + if (nvif_unpack(args->v0, 0, 0, true)) { + if (!(ntfy = usif_notify_find(f, args->v0.index))) + return -ENOENT; + } else + return ret; + + ret = nvif_client_ioctl(client, argv, argc); + if (ret == 0 && atomic_xchg(&ntfy->enabled, 0)) + kfree(ntfy->p); + return ret; +} + +struct usif_object { + struct list_head head; + struct list_head ntfy; + u8 route; + u64 token; +}; + +static void +usif_object_dtor(struct usif_object *object) +{ + list_del(&object->head); + kfree(object); +} + +static int +usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) +{ + struct nouveau_cli *cli = nouveau_cli(f); + struct nvif_client *client = &cli->base; + union { + struct nvif_ioctl_new_v0 v0; + } *args = data; + struct usif_object *object; + int ret; + + if (!(object = kmalloc(sizeof(*object), GFP_KERNEL))) + return -ENOMEM; + list_add(&object->head, &cli->objects); + + if (nvif_unpack(args->v0, 0, 0, true)) { + object->route = args->v0.route; + object->token = args->v0.token; + args->v0.route = NVDRM_OBJECT_USIF; + args->v0.token = (unsigned long)(void *)object; + ret = nvif_client_ioctl(client, argv, argc); + args->v0.token = object->token; + args->v0.route = object->route; + } + + if (ret) + usif_object_dtor(object); + return ret; +} + +int +usif_ioctl(struct drm_file *filp, void __user *user, u32 argc) +{ + struct nouveau_cli *cli = nouveau_cli(filp); + struct nvif_client *client = &cli->base; + void *data = kmalloc(argc, GFP_KERNEL); + u32 size = argc; + union { + struct nvif_ioctl_v0 v0; + } *argv = data; + struct usif_object *object; + u8 owner; + int ret; + + if (ret = -ENOMEM, !argv) + goto done; + if (ret = -EFAULT, copy_from_user(argv, user, size)) + goto done; + + if (nvif_unpack(argv->v0, 0, 0, true)) { + /* block access to objects not created via this interface */ + owner = argv->v0.owner; + argv->v0.owner = NVDRM_OBJECT_USIF; + } else + goto done; + + mutex_lock(&cli->mutex); + switch (argv->v0.type) { + case NVIF_IOCTL_V0_NEW: + /* ... except if we're creating children */ + argv->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; + ret = usif_object_new(filp, data, size, argv, argc); + break; + case NVIF_IOCTL_V0_NTFY_NEW: + ret = usif_notify_new(filp, data, size, argv, argc); + break; + case NVIF_IOCTL_V0_NTFY_DEL: + ret = usif_notify_del(filp, data, size, argv, argc); + break; + case NVIF_IOCTL_V0_NTFY_GET: + ret = usif_notify_get(filp, data, size, argv, argc); + break; + case NVIF_IOCTL_V0_NTFY_PUT: + ret = usif_notify_put(filp, data, size, argv, argc); + break; + default: + ret = nvif_client_ioctl(client, argv, argc); + break; + } + if (argv->v0.route == NVDRM_OBJECT_USIF) { + object = (void *)(unsigned long)argv->v0.token; + argv->v0.route = object->route; + argv->v0.token = object->token; + if (ret == 0 && argv->v0.type == NVIF_IOCTL_V0_DEL) { + list_del(&object->head); + kfree(object); + } + } else { + argv->v0.route = NVIF_IOCTL_V0_ROUTE_HIDDEN; + argv->v0.token = 0; + } + argv->v0.owner = owner; + mutex_unlock(&cli->mutex); + + if (copy_to_user(user, argv, argc)) + ret = -EFAULT; +done: + kfree(argv); + return ret; +} + +void +usif_client_fini(struct nouveau_cli *cli) +{ + struct usif_object *object, *otemp; + struct usif_notify *notify, *ntemp; + + list_for_each_entry_safe(notify, ntemp, &cli->notifys, head) { + usif_notify_dtor(notify); + } + + list_for_each_entry_safe(object, otemp, &cli->objects, head) { + usif_object_dtor(object); + } +} + +void +usif_client_init(struct nouveau_cli *cli) +{ + INIT_LIST_HEAD(&cli->objects); + INIT_LIST_HEAD(&cli->notifys); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.h b/drivers/gpu/drm/nouveau/nouveau_usif.h new file mode 100644 index 000000000000..c037e3ae8c70 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_usif.h @@ -0,0 +1,9 @@ +#ifndef __NOUVEAU_USIF_H__ +#define __NOUVEAU_USIF_H__ + +void usif_client_init(struct nouveau_cli *); +void usif_client_fini(struct nouveau_cli *); +int usif_ioctl(struct drm_file *, void __user *, u32); +int usif_notify(const void *, u32, const void *, u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 4f4c3fec6916..c7592ec8ecb8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -12,14 +12,16 @@ static unsigned int nouveau_vga_set_decode(void *priv, bool state) { - struct nouveau_device *device = nouveau_dev(priv); + struct nvif_device *device = &nouveau_drm(priv)->device; - if (device->card_type == NV_40 && device->chipset >= 0x4c) - nv_wr32(device, 0x088060, state); - else if (device->chipset >= 0x40) - nv_wr32(device, 0x088054, state); + if (device->info.family == NV_DEVICE_INFO_V0_CURIE && + device->info.chipset >= 0x4c) + nvif_wr32(device, 0x088060, state); else - nv_wr32(device, 0x001854, state); + if (device->info.chipset >= 0x40) + nvif_wr32(device, 0x088054, state); + else + nvif_wr32(device, 0x001854, state); if (state) return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | @@ -106,7 +108,16 @@ void nouveau_vga_fini(struct nouveau_drm *drm) { struct drm_device *dev = drm->dev; + bool runtime = false; + + if (nouveau_runtime_pm == 1) + runtime = true; + if ((nouveau_runtime_pm == -1) && (nouveau_is_optimus() || nouveau_is_v1_dsm())) + runtime = true; + vga_switcheroo_unregister_client(dev->pdev); + if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus()) + vga_switcheroo_fini_domain_pm_ops(drm->dev->dev); vga_client_register(dev->pdev, NULL, NULL, NULL); } diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 8fe32bbed99a..4ef602c5469d 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -22,8 +22,6 @@ * DEALINGS IN THE SOFTWARE. */ -#include <core/object.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_fbcon.h" @@ -141,8 +139,7 @@ nv04_fbcon_accel_init(struct fb_info *info) struct drm_device *dev = nfbdev->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; - struct nouveau_device *device = nv_device(drm->device); - struct nouveau_object *object; + struct nvif_device *device = &drm->device; int surface_fmt, pattern_fmt, rect_fmt; int ret; @@ -174,35 +171,35 @@ nv04_fbcon_accel_init(struct fb_info *info) return -EINVAL; } - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvCtxSurf2D, - device->card_type >= NV_10 ? 0x0062 : 0x0042, - NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x0062, + device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ? + 0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d); if (ret) return ret; - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvClipRect, - 0x0019, NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x0019, 0x0019, NULL, 0, + &nfbdev->clip); if (ret) return ret; - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvRop, - 0x0043, NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x0043, 0x0043, NULL, 0, + &nfbdev->rop); if (ret) return ret; - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvImagePatt, - 0x0044, NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x0044, 0x0044, NULL, 0, + &nfbdev->patt); if (ret) return ret; - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvGdiRect, - 0x004a, NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x004a, 0x004a, NULL, 0, + &nfbdev->gdi); if (ret) return ret; - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvImageBlit, - device->chipset >= 0x11 ? 0x009f : 0x005f, - NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x005f, + device->info.chipset >= 0x11 ? 0x009f : 0x005f, + NULL, 0, &nfbdev->blit); if (ret) return ret; @@ -212,10 +209,10 @@ nv04_fbcon_accel_init(struct fb_info *info) } BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1); - OUT_RING(chan, NvCtxSurf2D); + OUT_RING(chan, nfbdev->surf2d.handle); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0184, 2); - OUT_RING(chan, NvDmaFB); - OUT_RING(chan, NvDmaFB); + OUT_RING(chan, chan->vram.handle); + OUT_RING(chan, chan->vram.handle); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 4); OUT_RING(chan, surface_fmt); OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16)); @@ -223,12 +220,12 @@ nv04_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1); - OUT_RING(chan, NvRop); + OUT_RING(chan, nfbdev->rop.handle); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 1); OUT_RING(chan, 0x55); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1); - OUT_RING(chan, NvImagePatt); + OUT_RING(chan, nfbdev->patt.handle); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 8); OUT_RING(chan, pattern_fmt); #ifdef __BIG_ENDIAN @@ -244,18 +241,18 @@ nv04_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, ~0); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1); - OUT_RING(chan, NvClipRect); + OUT_RING(chan, nfbdev->clip.handle); BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 2); OUT_RING(chan, 0); OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual); BEGIN_NV04(chan, NvSubImageBlit, 0x0000, 1); - OUT_RING(chan, NvImageBlit); + OUT_RING(chan, nfbdev->blit.handle); BEGIN_NV04(chan, NvSubImageBlit, 0x019c, 1); - OUT_RING(chan, NvCtxSurf2D); + OUT_RING(chan, nfbdev->surf2d.handle); BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1); OUT_RING(chan, 3); - if (device->chipset >= 0x11 /*XXX: oclass == 0x009f*/) { + if (device->info.chipset >= 0x11 /*XXX: oclass == 0x009f*/) { BEGIN_NV04(chan, NvSubImageBlit, 0x0120, 3); OUT_RING(chan, 0); OUT_RING(chan, 1); @@ -263,12 +260,12 @@ nv04_fbcon_accel_init(struct fb_info *info) } BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1); - OUT_RING(chan, NvGdiRect); + OUT_RING(chan, nfbdev->gdi.handle); BEGIN_NV04(chan, NvSubGdiRect, 0x0198, 1); - OUT_RING(chan, NvCtxSurf2D); + OUT_RING(chan, nfbdev->surf2d.handle); BEGIN_NV04(chan, NvSubGdiRect, 0x0188, 2); - OUT_RING(chan, NvImagePatt); - OUT_RING(chan, NvRop); + OUT_RING(chan, nfbdev->patt.handle); + OUT_RING(chan, nfbdev->rop.handle); BEGIN_NV04(chan, NvSubGdiRect, 0x0304, 1); OUT_RING(chan, 1); BEGIN_NV04(chan, NvSubGdiRect, 0x0300, 1); diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c index 94eadd1dd10a..f9859deb108a 100644 --- a/drivers/gpu/drm/nouveau/nv04_fence.c +++ b/drivers/gpu/drm/nouveau/nv04_fence.c @@ -22,8 +22,6 @@ * Authors: Ben Skeggs */ -#include <engine/fifo.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_fence.h" @@ -43,7 +41,7 @@ nv04_fence_emit(struct nouveau_fence *fence) int ret = RING_SPACE(chan, 2); if (ret == 0) { BEGIN_NV04(chan, NvSubSw, 0x0150, 1); - OUT_RING (chan, fence->sequence); + OUT_RING (chan, fence->base.seqno); FIRE_RING (chan); } return ret; @@ -59,7 +57,7 @@ nv04_fence_sync(struct nouveau_fence *fence, static u32 nv04_fence_read(struct nouveau_channel *chan) { - struct nouveau_fifo_chan *fifo = (void *)chan->object; + struct nouveau_fifo_chan *fifo = nvkm_fifo_chan(chan);; return atomic_read(&fifo->refcnt); } @@ -69,7 +67,7 @@ nv04_fence_context_del(struct nouveau_channel *chan) struct nv04_fence_chan *fctx = chan->fence; nouveau_fence_context_del(&fctx->base); chan->fence = NULL; - kfree(fctx); + nouveau_fence_context_free(&fctx->base); } static int @@ -77,7 +75,7 @@ nv04_fence_context_new(struct nouveau_channel *chan) { struct nv04_fence_chan *fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); if (fctx) { - nouveau_fence_context_new(&fctx->base); + nouveau_fence_context_new(chan, &fctx->base); fctx->base.emit = nv04_fence_emit; fctx->base.sync = nv04_fence_sync; fctx->base.read = nv04_fence_read; @@ -107,5 +105,7 @@ nv04_fence_create(struct nouveau_drm *drm) priv->base.dtor = nv04_fence_destroy; priv->base.context_new = nv04_fence_context_new; priv->base.context_del = nv04_fence_context_del; + priv->base.contexts = 15; + priv->base.context_base = fence_context_alloc(priv->base.contexts); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index 06f434f03fba..5e1ea1cdce75 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c @@ -22,9 +22,6 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include <core/object.h> -#include <core/class.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nv10_fence.h" @@ -36,7 +33,7 @@ nv10_fence_emit(struct nouveau_fence *fence) int ret = RING_SPACE(chan, 2); if (ret == 0) { BEGIN_NV04(chan, 0, NV10_SUBCHAN_REF_CNT, 1); - OUT_RING (chan, fence->sequence); + OUT_RING (chan, fence->base.seqno); FIRE_RING (chan); } return ret; @@ -53,16 +50,20 @@ nv10_fence_sync(struct nouveau_fence *fence, u32 nv10_fence_read(struct nouveau_channel *chan) { - return nv_ro32(chan->object, 0x0048); + return nvif_rd32(chan, 0x0048); } 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; - kfree(fctx); + nouveau_fence_context_free(&fctx->base); } int @@ -74,7 +75,7 @@ nv10_fence_context_new(struct nouveau_channel *chan) if (!fctx) return -ENOMEM; - nouveau_fence_context_new(&fctx->base); + nouveau_fence_context_new(chan, &fctx->base); fctx->base.emit = nv10_fence_emit; fctx->base.read = nv10_fence_read; fctx->base.sync = nv10_fence_sync; @@ -105,6 +106,8 @@ nv10_fence_create(struct nouveau_drm *drm) priv->base.dtor = nv10_fence_destroy; priv->base.context_new = nv10_fence_context_new; priv->base.context_del = nv10_fence_context_del; + priv->base.contexts = 31; + priv->base.context_base = fence_context_alloc(priv->base.contexts); spin_lock_init(&priv->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv10_fence.h b/drivers/gpu/drm/nouveau/nv10_fence.h index e5d9204826c2..a87259f3983a 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.h +++ b/drivers/gpu/drm/nouveau/nv10_fence.h @@ -1,12 +1,13 @@ #ifndef __NV10_FENCE_H_ #define __NV10_FENCE_H_ -#include <core/os.h> #include "nouveau_fence.h" #include "nouveau_bo.h" 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/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c index 22aa9963ea6f..40b461c7d5c5 100644 --- a/drivers/gpu/drm/nouveau/nv17_fence.c +++ b/drivers/gpu/drm/nouveau/nv17_fence.c @@ -22,8 +22,8 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include <core/object.h> -#include <core/class.h> +#include <nvif/os.h> +#include <nvif/class.h> #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -33,11 +33,13 @@ int nv17_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *prev, struct nouveau_channel *chan) { + struct nouveau_cli *cli = (void *)nvif_client(&prev->device->base); struct nv10_fence_priv *priv = chan->drm->fence; + struct nv10_fence_chan *fctx = chan->fence; u32 value; int ret; - if (!mutex_trylock(&prev->cli->mutex)) + if (!mutex_trylock(&cli->mutex)) return -EBUSY; spin_lock(&priv->lock); @@ -48,7 +50,7 @@ nv17_fence_sync(struct nouveau_fence *fence, ret = RING_SPACE(prev, 5); if (!ret) { BEGIN_NV04(prev, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4); - OUT_RING (prev, NvSema); + OUT_RING (prev, fctx->sema.handle); OUT_RING (prev, 0); OUT_RING (prev, value + 0); OUT_RING (prev, value + 1); @@ -57,14 +59,14 @@ nv17_fence_sync(struct nouveau_fence *fence, if (!ret && !(ret = RING_SPACE(chan, 5))) { BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4); - OUT_RING (chan, NvSema); + OUT_RING (chan, fctx->sema.handle); OUT_RING (chan, 0); OUT_RING (chan, value + 1); OUT_RING (chan, value + 2); FIRE_RING (chan); } - mutex_unlock(&prev->cli->mutex); + mutex_unlock(&cli->mutex); return 0; } @@ -74,7 +76,6 @@ nv17_fence_context_new(struct nouveau_channel *chan) struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx; struct ttm_mem_reg *mem = &priv->bo->bo.mem; - struct nouveau_object *object; u32 start = mem->start * PAGE_SIZE; u32 limit = start + mem->size - 1; int ret = 0; @@ -83,20 +84,19 @@ nv17_fence_context_new(struct nouveau_channel *chan) if (!fctx) return -ENOMEM; - nouveau_fence_context_new(&fctx->base); + nouveau_fence_context_new(chan, &fctx->base); fctx->base.emit = nv10_fence_emit; fctx->base.read = nv10_fence_read; fctx->base.sync = nv17_fence_sync; - ret = nouveau_object_new(nv_object(chan->cli), chan->handle, - NvSema, 0x0002, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, + ret = nvif_object_init(chan->object, NULL, NvSema, NV_DMA_FROM_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_class), - &object); + }, sizeof(struct nv_dma_v0), + &fctx->sema); if (ret) nv10_fence_context_del(chan); return ret; @@ -124,10 +124,12 @@ nv17_fence_create(struct nouveau_drm *drm) priv->base.resume = nv17_fence_resume; priv->base.context_new = nv17_fence_context_new; priv->base.context_del = nv10_fence_context_del; + priv->base.contexts = 31; + priv->base.context_base = fence_context_alloc(priv->base.contexts); spin_lock_init(&priv->lock); ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, - 0, 0x0000, NULL, &priv->bo); + 0, 0x0000, NULL, NULL, &priv->bo); if (!ret) { ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); if (!ret) { diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 4c534b7b04da..eb8b36714fa1 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -28,6 +28,8 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_dp_helper.h> +#include <nvif/class.h> + #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_gem.h" @@ -37,15 +39,6 @@ #include "nouveau_fence.h" #include "nv50_display.h" -#include <core/client.h> -#include <core/gpuobj.h> -#include <core/class.h> - -#include <subdev/timer.h> -#include <subdev/bar.h> -#include <subdev/fb.h> -#include <subdev/i2c.h> - #define EVO_DMA_NR 9 #define EVO_MASTER (0x00) @@ -60,45 +53,34 @@ #define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00) #define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10) -#define EVO_CORE_HANDLE (0xd1500000) -#define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i)) -#define EVO_CHAN_OCLASS(t,c) ((nv_hclass(c) & 0xff00) | ((t) & 0x00ff)) -#define EVO_PUSH_HANDLE(t,i) (0xd15b0000 | (i) | \ - (((NV50_DISP_##t##_CLASS) & 0x00ff) << 8)) - /****************************************************************************** * EVO channel *****************************************************************************/ struct nv50_chan { - struct nouveau_object *user; - u32 handle; + struct nvif_object user; }; static int -nv50_chan_create(struct nouveau_object *core, u32 bclass, u8 head, +nv50_chan_create(struct nvif_object *disp, const u32 *oclass, u8 head, void *data, u32 size, struct nv50_chan *chan) { - struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS); - const u32 oclass = EVO_CHAN_OCLASS(bclass, core); - const u32 handle = EVO_CHAN_HANDLE(bclass, head); - int ret; - - ret = nouveau_object_new(client, EVO_CORE_HANDLE, handle, - oclass, data, size, &chan->user); - if (ret) - return ret; - - chan->handle = handle; - return 0; + while (oclass[0]) { + int ret = nvif_object_init(disp, NULL, (oclass[0] << 16) | head, + oclass[0], data, size, + &chan->user); + if (oclass++, ret == 0) { + nvif_object_map(&chan->user); + return ret; + } + } + return -ENOSYS; } static void -nv50_chan_destroy(struct nouveau_object *core, struct nv50_chan *chan) +nv50_chan_destroy(struct nv50_chan *chan) { - struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS); - if (chan->handle) - nouveau_object_del(client, EVO_CORE_HANDLE, chan->handle); + nvif_object_fini(&chan->user); } /****************************************************************************** @@ -110,16 +92,70 @@ struct nv50_pioc { }; static void -nv50_pioc_destroy(struct nouveau_object *core, struct nv50_pioc *pioc) +nv50_pioc_destroy(struct nv50_pioc *pioc) { - nv50_chan_destroy(core, &pioc->base); + nv50_chan_destroy(&pioc->base); } static int -nv50_pioc_create(struct nouveau_object *core, u32 bclass, u8 head, +nv50_pioc_create(struct nvif_object *disp, const u32 *oclass, u8 head, void *data, u32 size, struct nv50_pioc *pioc) { - return nv50_chan_create(core, bclass, head, data, size, &pioc->base); + return nv50_chan_create(disp, oclass, head, data, size, &pioc->base); +} + +/****************************************************************************** + * Cursor Immediate + *****************************************************************************/ + +struct nv50_curs { + struct nv50_pioc base; +}; + +static int +nv50_curs_create(struct nvif_object *disp, int head, struct nv50_curs *curs) +{ + struct nv50_disp_cursor_v0 args = { + .head = head, + }; + static const u32 oclass[] = { + GK104_DISP_CURSOR, + GF110_DISP_CURSOR, + GT214_DISP_CURSOR, + G82_DISP_CURSOR, + NV50_DISP_CURSOR, + 0 + }; + + return nv50_pioc_create(disp, oclass, head, &args, sizeof(args), + &curs->base); +} + +/****************************************************************************** + * Overlay Immediate + *****************************************************************************/ + +struct nv50_oimm { + struct nv50_pioc base; +}; + +static int +nv50_oimm_create(struct nvif_object *disp, int head, struct nv50_oimm *oimm) +{ + struct nv50_disp_cursor_v0 args = { + .head = head, + }; + static const u32 oclass[] = { + GK104_DISP_OVERLAY, + GF110_DISP_OVERLAY, + GT214_DISP_OVERLAY, + G82_DISP_OVERLAY, + NV50_DISP_OVERLAY, + 0 + }; + + return nv50_pioc_create(disp, oclass, head, &args, sizeof(args), + &oimm->base); } /****************************************************************************** @@ -131,6 +167,9 @@ struct nv50_dmac { dma_addr_t handle; u32 *ptr; + struct nvif_object sync; + struct nvif_object vram; + /* Protects against concurrent pushbuf access to this channel, lock is * grabbed by evo_wait (if the pushbuf reservation is successful) and * dropped again by evo_kick. */ @@ -138,207 +177,113 @@ struct nv50_dmac { }; static void -nv50_dmac_destroy(struct nouveau_object *core, struct nv50_dmac *dmac) +nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp) { + nvif_object_fini(&dmac->vram); + nvif_object_fini(&dmac->sync); + + nv50_chan_destroy(&dmac->base); + if (dmac->ptr) { - struct pci_dev *pdev = nv_device(core)->pdev; + struct pci_dev *pdev = nvkm_device(nvif_device(disp))->pdev; pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle); } - - nv50_chan_destroy(core, &dmac->base); -} - -static int -nv50_dmac_create_fbdma(struct nouveau_object *core, u32 parent) -{ - struct nouveau_fb *pfb = nouveau_fb(core); - struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS); - struct nouveau_object *object; - int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NV50_DMA_CONF0_ENABLE | - NV50_DMA_CONF0_PART_256, - }, sizeof(struct nv_dma_class), &object); - if (ret) - return ret; - - ret = nouveau_object_new(client, parent, NvEvoFB16, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NV50_DMA_CONF0_ENABLE | 0x70 | - NV50_DMA_CONF0_PART_256, - }, sizeof(struct nv_dma_class), &object); - if (ret) - return ret; - - ret = nouveau_object_new(client, parent, NvEvoFB32, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NV50_DMA_CONF0_ENABLE | 0x7a | - NV50_DMA_CONF0_PART_256, - }, sizeof(struct nv_dma_class), &object); - return ret; -} - -static int -nvc0_dmac_create_fbdma(struct nouveau_object *core, u32 parent) -{ - struct nouveau_fb *pfb = nouveau_fb(core); - struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS); - struct nouveau_object *object; - int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NVC0_DMA_CONF0_ENABLE, - }, sizeof(struct nv_dma_class), &object); - if (ret) - return ret; - - ret = nouveau_object_new(client, parent, NvEvoFB16, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe, - }, sizeof(struct nv_dma_class), &object); - if (ret) - return ret; - - ret = nouveau_object_new(client, parent, NvEvoFB32, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe, - }, sizeof(struct nv_dma_class), &object); - return ret; -} - -static int -nvd0_dmac_create_fbdma(struct nouveau_object *core, u32 parent) -{ - struct nouveau_fb *pfb = nouveau_fb(core); - struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS); - struct nouveau_object *object; - int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NVD0_DMA_CONF0_ENABLE | - NVD0_DMA_CONF0_PAGE_LP, - }, sizeof(struct nv_dma_class), &object); - if (ret) - return ret; - - ret = nouveau_object_new(client, parent, NvEvoFB32, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, - .start = 0, - .limit = pfb->ram->size - 1, - .conf0 = NVD0_DMA_CONF0_ENABLE | 0xfe | - NVD0_DMA_CONF0_PAGE_LP, - }, sizeof(struct nv_dma_class), &object); - return ret; } static int -nv50_dmac_create(struct nouveau_object *core, u32 bclass, u8 head, +nv50_dmac_create(struct nvif_object *disp, const u32 *oclass, u8 head, void *data, u32 size, u64 syncbuf, struct nv50_dmac *dmac) { - struct nouveau_fb *pfb = nouveau_fb(core); - struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS); - struct nouveau_object *object; - u32 pushbuf = *(u32 *)data; + struct nvif_device *device = nvif_device(disp); + struct nv50_disp_core_channel_dma_v0 *args = data; + struct nvif_object pushbuf; int ret; mutex_init(&dmac->lock); - dmac->ptr = pci_alloc_consistent(nv_device(core)->pdev, PAGE_SIZE, - &dmac->handle); + dmac->ptr = pci_alloc_consistent(nvkm_device(device)->pdev, + PAGE_SIZE, &dmac->handle); if (!dmac->ptr) return -ENOMEM; - ret = nouveau_object_new(client, NVDRM_DEVICE, pushbuf, - NV_DMA_FROM_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_PCI_US | - NV_DMA_ACCESS_RD, + ret = nvif_object_init(nvif_object(device), NULL, + args->pushbuf, NV_DMA_FROM_MEMORY, + &(struct nv_dma_v0) { + .target = NV_DMA_V0_TARGET_PCI_US, + .access = NV_DMA_V0_ACCESS_RD, .start = dmac->handle + 0x0000, .limit = dmac->handle + 0x0fff, - }, sizeof(struct nv_dma_class), &object); + }, sizeof(struct nv_dma_v0), &pushbuf); if (ret) return ret; - ret = nv50_chan_create(core, bclass, head, data, size, &dmac->base); + ret = nv50_chan_create(disp, oclass, head, data, size, &dmac->base); + nvif_object_fini(&pushbuf); if (ret) return ret; - ret = nouveau_object_new(client, dmac->base.handle, NvEvoSync, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, + ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000000, + NV_DMA_IN_MEMORY, + &(struct nv_dma_v0) { + .target = NV_DMA_V0_TARGET_VRAM, + .access = NV_DMA_V0_ACCESS_RDWR, .start = syncbuf + 0x0000, .limit = syncbuf + 0x0fff, - }, sizeof(struct nv_dma_class), &object); + }, sizeof(struct nv_dma_v0), + &dmac->sync); if (ret) return ret; - ret = nouveau_object_new(client, dmac->base.handle, NvEvoVRAM, - NV_DMA_IN_MEMORY_CLASS, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, + ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000001, + NV_DMA_IN_MEMORY, + &(struct nv_dma_v0) { + .target = NV_DMA_V0_TARGET_VRAM, + .access = NV_DMA_V0_ACCESS_RDWR, .start = 0, - .limit = pfb->ram->size - 1, - }, sizeof(struct nv_dma_class), &object); + .limit = device->info.ram_user - 1, + }, sizeof(struct nv_dma_v0), + &dmac->vram); if (ret) return ret; - if (nv_device(core)->card_type < NV_C0) - ret = nv50_dmac_create_fbdma(core, dmac->base.handle); - else - if (nv_device(core)->card_type < NV_D0) - ret = nvc0_dmac_create_fbdma(core, dmac->base.handle); - else - ret = nvd0_dmac_create_fbdma(core, dmac->base.handle); return ret; } +/****************************************************************************** + * Core + *****************************************************************************/ + struct nv50_mast { struct nv50_dmac base; }; -struct nv50_curs { - struct nv50_pioc base; -}; +static int +nv50_core_create(struct nvif_object *disp, u64 syncbuf, struct nv50_mast *core) +{ + struct nv50_disp_core_channel_dma_v0 args = { + .pushbuf = 0xb0007d00, + }; + static const u32 oclass[] = { + GM107_DISP_CORE_CHANNEL_DMA, + GK110_DISP_CORE_CHANNEL_DMA, + GK104_DISP_CORE_CHANNEL_DMA, + GF110_DISP_CORE_CHANNEL_DMA, + GT214_DISP_CORE_CHANNEL_DMA, + GT206_DISP_CORE_CHANNEL_DMA, + GT200_DISP_CORE_CHANNEL_DMA, + G82_DISP_CORE_CHANNEL_DMA, + NV50_DISP_CORE_CHANNEL_DMA, + 0 + }; + + return nv50_dmac_create(disp, oclass, 0, &args, sizeof(args), syncbuf, + &core->base); +} + +/****************************************************************************** + * Base + *****************************************************************************/ struct nv50_sync { struct nv50_dmac base; @@ -346,13 +291,58 @@ struct nv50_sync { u32 data; }; +static int +nv50_base_create(struct nvif_object *disp, int head, u64 syncbuf, + struct nv50_sync *base) +{ + struct nv50_disp_base_channel_dma_v0 args = { + .pushbuf = 0xb0007c00 | head, + .head = head, + }; + static const u32 oclass[] = { + GK110_DISP_BASE_CHANNEL_DMA, + GK104_DISP_BASE_CHANNEL_DMA, + GF110_DISP_BASE_CHANNEL_DMA, + GT214_DISP_BASE_CHANNEL_DMA, + GT200_DISP_BASE_CHANNEL_DMA, + G82_DISP_BASE_CHANNEL_DMA, + NV50_DISP_BASE_CHANNEL_DMA, + 0 + }; + + return nv50_dmac_create(disp, oclass, head, &args, sizeof(args), + syncbuf, &base->base); +} + +/****************************************************************************** + * Overlay + *****************************************************************************/ + struct nv50_ovly { struct nv50_dmac base; }; -struct nv50_oimm { - struct nv50_pioc base; -}; +static int +nv50_ovly_create(struct nvif_object *disp, int head, u64 syncbuf, + struct nv50_ovly *ovly) +{ + struct nv50_disp_overlay_channel_dma_v0 args = { + .pushbuf = 0xb0007e00 | head, + .head = head, + }; + static const u32 oclass[] = { + GK104_DISP_OVERLAY_CONTROL_DMA, + GF110_DISP_OVERLAY_CONTROL_DMA, + GT214_DISP_OVERLAY_CHANNEL_DMA, + GT200_DISP_OVERLAY_CHANNEL_DMA, + G82_DISP_OVERLAY_CHANNEL_DMA, + NV50_DISP_OVERLAY_CHANNEL_DMA, + 0 + }; + + return nv50_dmac_create(disp, oclass, head, &args, sizeof(args), + syncbuf, &ovly->base); +} struct nv50_head { struct nouveau_crtc base; @@ -369,13 +359,19 @@ struct nv50_head { #define nv50_ovly(c) (&nv50_head(c)->ovly) #define nv50_oimm(c) (&nv50_head(c)->oimm) #define nv50_chan(c) (&(c)->base.base) -#define nv50_vers(c) nv_mclass(nv50_chan(c)->user) +#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 nouveau_object *core; + struct nvif_object *disp; struct nv50_mast mast; - u32 modeset; + struct list_head fbdma; struct nouveau_bo *sync; }; @@ -401,16 +397,16 @@ static u32 * evo_wait(void *evoc, int nr) { struct nv50_dmac *dmac = evoc; - u32 put = nv_ro32(dmac->base.user, 0x0000) / 4; + u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4; mutex_lock(&dmac->lock); if (put + nr >= (PAGE_SIZE / 4) - 8) { dmac->ptr[put] = 0x20000000; - nv_wo32(dmac->base.user, 0x0000, 0x00000000); - if (!nv_wait(dmac->base.user, 0x0004, ~0, 0x00000000)) { + nvif_wr32(&dmac->base.user, 0x0000, 0x00000000); + if (!nvkm_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) { mutex_unlock(&dmac->lock); - NV_ERROR(dmac->base.user, "channel stalled\n"); + nv_error(nvkm_object(&dmac->base.user), "channel stalled\n"); return NULL; } @@ -424,7 +420,7 @@ static void evo_kick(u32 *push, void *evoc) { struct nv50_dmac *dmac = evoc; - nv_wo32(dmac->base.user, 0x0000, (push - dmac->ptr) << 2); + nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2); mutex_unlock(&dmac->lock); } @@ -443,7 +439,7 @@ evo_sync_wait(void *data) static int evo_sync(struct drm_device *dev) { - struct nouveau_device *device = nouveau_dev(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); @@ -455,7 +451,7 @@ evo_sync(struct drm_device *dev) evo_data(push, 0x00000000); evo_data(push, 0x00000000); evo_kick(push, mast); - if (nv_wait_cb(device, evo_sync_wait, disp->sync)) + if (nv_wait_cb(nvkm_device(device), evo_sync_wait, disp->sync)) return 0; } @@ -490,7 +486,7 @@ nv50_display_flip_wait(void *data) void nv50_display_flip_stop(struct drm_crtc *crtc) { - struct nouveau_device *device = nouveau_dev(crtc->dev); + struct nvif_device *device = &nouveau_drm(crtc->dev)->device; struct nv50_display_flip flip = { .disp = nv50_disp(crtc->dev), .chan = nv50_sync(crtc), @@ -510,7 +506,7 @@ nv50_display_flip_stop(struct drm_crtc *crtc) evo_kick(push, flip.chan); } - nv_wait_cb(device, nv50_display_flip_wait, &flip); + nv_wait_cb(nvkm_device(device), nv50_display_flip_wait, &flip); } int @@ -534,7 +530,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (unlikely(push == NULL)) return -EBUSY; - if (chan && nv_mclass(chan->object) < NV84_CHANNEL_IND_CLASS) { + if (chan && chan->object->oclass < G82_CHANNEL_GPFIFO) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -548,14 +544,14 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, OUT_RING (chan, sync->addr); OUT_RING (chan, sync->data); } else - if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { + if (chan && chan->object->oclass < FERMI_CHANNEL_GPFIFO) { u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; ret = RING_SPACE(chan, 12); if (ret) return ret; BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); - OUT_RING (chan, chan->vram); + 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)); @@ -606,16 +602,16 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, evo_data(push, sync->addr); evo_data(push, sync->data++); evo_data(push, sync->data); - evo_data(push, NvEvoSync); + 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_dma); + evo_data(push, nv_fb->r_handle); evo_mthd(push, 0x0110, 2); evo_data(push, 0x00000000); evo_data(push, 0x00000000); - if (nv50_vers(sync) < NVD0_DISP_SYNC_CLASS) { + 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); @@ -667,11 +663,11 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) push = evo_wait(mast, 4); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + 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) < NVE0_DISP_MAST_CLASS) { + if (nv50_vers(mast) < GK104_DISP_CORE_CHANNEL_DMA) { evo_mthd(push, 0x0490 + (nv_crtc->index * 0x0300), 1); evo_data(push, mode); } else { @@ -762,7 +758,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) push = evo_wait(mast, 8); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + 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); @@ -795,6 +791,22 @@ 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); @@ -807,7 +819,7 @@ nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update) push = evo_wait(mast, 16); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + 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 { @@ -835,7 +847,7 @@ nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, push = evo_wait(mast, 16); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + 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); @@ -844,9 +856,9 @@ nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, 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_MAST_CLASS) { + if (nv50_vers(mast) > NV50_DISP_CORE_CHANNEL_DMA) { evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, nvfb->r_dma); + evo_data(push, nvfb->r_handle); } } else { evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1); @@ -855,7 +867,7 @@ nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, 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_dma); + evo_data(push, nvfb->r_handle); evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1); evo_data(push, (y << 16) | x); } @@ -867,7 +879,7 @@ nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, evo_kick(push, mast); } - nv_crtc->fb.tile_flags = nvfb->r_dma; + nv_crtc->fb.handle = nvfb->r_handle; return 0; } @@ -877,23 +889,23 @@ 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) < NV84_DISP_MAST_CLASS) { + 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) < NVD0_DISP_MAST_CLASS) { + 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, NvEvoVRAM); + 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, NvEvoVRAM); + evo_data(push, mast->base.vram.handle); } evo_kick(push, mast); } @@ -905,11 +917,11 @@ 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) < NV84_DISP_MAST_CLASS) { + 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) < NVD0_DISP_MAST_CLASS) { + 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); @@ -960,13 +972,13 @@ nv50_crtc_prepare(struct drm_crtc *crtc) push = evo_wait(mast, 6); if (push) { - if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) { + 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) < NVD0_DISP_MAST_CLASS) { + 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); @@ -997,31 +1009,31 @@ nv50_crtc_commit(struct drm_crtc *crtc) push = evo_wait(mast, 32); if (push) { - if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) { + if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, NvEvoVRAM_LP); + 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) < NVD0_DISP_MAST_CLASS) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, nv_crtc->fb.tile_flags); + 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, NvEvoVRAM); + evo_data(push, mast->base.vram.handle); } else { evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); - evo_data(push, nv_crtc->fb.tile_flags); + 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); evo_data(push, 0x00000000); evo_data(push, 0x00000000); evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); - evo_data(push, NvEvoVRAM); + evo_data(push, mast->base.vram.handle); evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1); evo_data(push, 0xffffff00); } @@ -1070,7 +1082,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, 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; + u32 vblan2e = 0, vblan2s = 1, vblankus = 0; u32 *push; int ret; @@ -1087,6 +1099,11 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, 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); @@ -1099,7 +1116,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, push = evo_wait(mast, 64); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + 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); @@ -1140,6 +1157,11 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, nv_connector = nouveau_crtc_connector_get(nv_crtc); 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, vblankus); + nv50_crtc_set_color_vibrance(nv_crtc, false); nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false); return 0; @@ -1192,7 +1214,7 @@ nv50_crtc_lut_load(struct drm_crtc *crtc) u16 g = nv_crtc->lut.g[i] >> 2; u16 b = nv_crtc->lut.b[i] >> 2; - if (nv_mclass(disp->core) < NVD0_DISP_CLASS) { + if (disp->disp->oclass < GF110_DISP) { writew(r + 0x0000, lut + (i * 0x08) + 0); writew(g + 0x0000, lut + (i * 0x08) + 2); writew(b + 0x0000, lut + (i * 0x08) + 4); @@ -1259,8 +1281,8 @@ nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) { struct nv50_curs *curs = nv50_curs(crtc); struct nv50_chan *chan = nv50_chan(curs); - nv_wo32(chan->user, 0x0084, (y << 16) | (x & 0xffff)); - nv_wo32(chan->user, 0x0080, 0x00000000); + nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff)); + nvif_wr32(&chan->user, 0x0080, 0x00000000); return 0; } @@ -1287,11 +1309,16 @@ 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; - nv50_dmac_destroy(disp->core, &head->ovly.base); - nv50_pioc_destroy(disp->core, &head->oimm.base); - nv50_dmac_destroy(disp->core, &head->sync.base); - nv50_pioc_destroy(disp->core, &head->curs.base); + 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); + 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 * disconnect() during the cleanup paths @@ -1346,7 +1373,7 @@ nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset) } static int -nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index) +nv50_crtc_create(struct drm_device *dev, int index) { struct nv50_disp *disp = nv50_disp(dev); struct nv50_head *head; @@ -1377,7 +1404,7 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index) drm_mode_crtc_set_gamma_size(crtc, 256); ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, NULL, &head->base.lut.nvbo); + 0, 0x0000, NULL, NULL, &head->base.lut.nvbo); if (!ret) { ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM); if (!ret) { @@ -1395,16 +1422,12 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index) nv50_crtc_lut_load(crtc); /* allocate cursor resources */ - ret = nv50_pioc_create(disp->core, NV50_DISP_CURS_CLASS, index, - &(struct nv50_display_curs_class) { - .head = index, - }, sizeof(struct nv50_display_curs_class), - &head->curs.base); + ret = nv50_curs_create(disp->disp, index, &head->curs); if (ret) goto out; ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, NULL, &head->base.cursor.nvbo); + 0, 0x0000, NULL, NULL, &head->base.cursor.nvbo); if (!ret) { ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) { @@ -1420,12 +1443,8 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index) goto out; /* allocate page flip / sync resources */ - ret = nv50_dmac_create(disp->core, NV50_DISP_SYNC_CLASS, index, - &(struct nv50_display_sync_class) { - .pushbuf = EVO_PUSH_HANDLE(SYNC, index), - .head = index, - }, sizeof(struct nv50_display_sync_class), - disp->sync->bo.offset, &head->sync.base); + ret = nv50_base_create(disp->disp, index, disp->sync->bo.offset, + &head->sync); if (ret) goto out; @@ -1433,20 +1452,12 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index) head->sync.data = 0x00000000; /* allocate overlay resources */ - ret = nv50_pioc_create(disp->core, NV50_DISP_OIMM_CLASS, index, - &(struct nv50_display_oimm_class) { - .head = index, - }, sizeof(struct nv50_display_oimm_class), - &head->oimm.base); + ret = nv50_oimm_create(disp->disp, index, &head->oimm); if (ret) goto out; - ret = nv50_dmac_create(disp->core, NV50_DISP_OVLY_CLASS, index, - &(struct nv50_display_ovly_class) { - .pushbuf = EVO_PUSH_HANDLE(OVLY, index), - .head = index, - }, sizeof(struct nv50_display_ovly_class), - disp->sync->bo.offset, &head->ovly.base); + ret = nv50_ovly_create(disp->disp, index, disp->sync->bo.offset, + &head->ovly); if (ret) goto out; @@ -1464,16 +1475,23 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv50_disp *disp = nv50_disp(encoder->dev); - int or = nv_encoder->or; - u32 dpms_ctrl; - - dpms_ctrl = 0x00000000; - if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF) - dpms_ctrl |= 0x00000001; - if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF) - dpms_ctrl |= 0x00000004; + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_dac_pwr_v0 pwr; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_DAC_PWR, + .base.hasht = nv_encoder->dcb->hasht, + .base.hashm = nv_encoder->dcb->hashm, + .pwr.state = 1, + .pwr.data = 1, + .pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND && + mode != DRM_MODE_DPMS_OFF), + .pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY && + mode != DRM_MODE_DPMS_OFF), + }; - nv_call(disp->core, NV50_DISP_DAC_PWR + or, dpms_ctrl); + nvif_mthd(disp->disp, 0, &args, sizeof(args)); } static bool @@ -1514,7 +1532,7 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, push = evo_wait(mast, 8); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { u32 syncs = 0x00000000; if (mode->flags & DRM_MODE_FLAG_NHSYNC) @@ -1563,7 +1581,7 @@ nv50_dac_disconnect(struct drm_encoder *encoder) push = evo_wait(mast, 4); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { evo_mthd(push, 0x0400 + (or * 0x080), 1); evo_data(push, 0x00000000); } else { @@ -1580,14 +1598,25 @@ nv50_dac_disconnect(struct drm_encoder *encoder) static enum drm_connector_status nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv50_disp *disp = nv50_disp(encoder->dev); - int ret, or = nouveau_encoder(encoder)->or; - u32 load = nouveau_drm(encoder->dev)->vbios.dactestval; - if (load == 0) - load = 340; + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_dac_load_v0 load; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_DAC_LOAD, + .base.hasht = nv_encoder->dcb->hasht, + .base.hashm = nv_encoder->dcb->hashm, + }; + int ret; - ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load)); - if (ret || !load) + args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval; + if (args.load.data == 0) + args.load.data = 340; + + ret = nvif_mthd(disp->disp, 0, &args, sizeof(args)); + if (ret || !args.load.load) return connector_status_disconnected; return connector_status_connected; @@ -1619,7 +1648,7 @@ static int nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) { struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nouveau_i2c *i2c = nouveau_i2c(drm->device); + struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; int type = DRM_MODE_ENCODER_DAC; @@ -1648,27 +1677,50 @@ static void nv50_audio_mode_set(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); struct nouveau_connector *nv_connector; struct nv50_disp *disp = nv50_disp(encoder->dev); + struct __packed { + struct { + struct nv50_disp_mthd_v1 mthd; + struct nv50_disp_sor_hda_eld_v0 eld; + } base; + u8 data[sizeof(nv_connector->base.eld)]; + } args = { + .base.mthd.version = 1, + .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD, + .base.mthd.hasht = nv_encoder->dcb->hasht, + .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) | + (0x0100 << nv_crtc->index), + }; nv_connector = nouveau_encoder_connector_get(nv_encoder); if (!drm_detect_monitor_audio(nv_connector->edid)) return; drm_edid_to_eld(&nv_connector->base, nv_connector->edid); + memcpy(args.data, nv_connector->base.eld, sizeof(args.data)); - nv_exec(disp->core, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or, - nv_connector->base.eld, - nv_connector->base.eld[2] * 4); + nvif_mthd(disp->disp, 0, &args, sizeof(args.base) + args.data[2] * 4); } static void -nv50_audio_disconnect(struct drm_encoder *encoder) +nv50_audio_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_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), + }; - nv_exec(disp->core, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or, NULL, 0); + nvif_mthd(disp->disp, 0, &args, sizeof(args)); } /****************************************************************************** @@ -1679,10 +1731,20 @@ nv50_hdmi_mode_set(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); - struct nouveau_connector *nv_connector; struct nv50_disp *disp = nv50_disp(encoder->dev); - const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; - u32 rekey = 56; /* binary driver, and tegra constant */ + 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), + .pwr.state = 1, + .pwr.rekey = 56, /* binary driver, and tegra, constant */ + }; + struct nouveau_connector *nv_connector; u32 max_ac_packet; nv_connector = nouveau_encoder_connector_get(nv_encoder); @@ -1690,14 +1752,11 @@ nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) return; max_ac_packet = mode->htotal - mode->hdisplay; - max_ac_packet -= rekey; + max_ac_packet -= args.pwr.rekey; max_ac_packet -= 18; /* constant from tegra */ - max_ac_packet /= 32; - - nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff, - NV84_DISP_SOR_HDMI_PWR_STATE_ON | - (max_ac_packet << 16) | rekey); + args.pwr.max_ac_packet = max_ac_packet / 32; + nvif_mthd(disp->disp, 0, &args, sizeof(args)); nv50_audio_mode_set(encoder, mode); } @@ -1706,11 +1765,18 @@ 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); - const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; - - nv50_audio_disconnect(encoder); + 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), + }; - nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff, 0x00000000); + nvif_mthd(disp->disp, 0, &args, sizeof(args)); } /****************************************************************************** @@ -1720,10 +1786,29 @@ static void nv50_sor_dpms(struct drm_encoder *encoder, int mode) { 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_pwr_v0 pwr; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_SOR_PWR, + .base.hasht = nv_encoder->dcb->hasht, + .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 nv50_disp *disp = nv50_disp(dev); struct drm_encoder *partner; - u32 mthd; nv_encoder->last_dpms = mode; @@ -1741,18 +1826,13 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) } } - mthd = (ffs(nv_encoder->dcb->heads) - 1) << 3; - mthd |= (ffs(nv_encoder->dcb->sorconf.link) - 1) << 2; - mthd |= nv_encoder->or; - if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { - nv_call(disp->core, NV50_DISP_SOR_PWR | mthd, 1); - mthd |= NV94_DISP_SOR_DP_PWR; + args.pwr.state = 1; + nvif_mthd(disp->disp, 0, &args, sizeof(args)); + nvif_mthd(disp->disp, 0, &link, sizeof(link)); } else { - mthd |= NV50_DISP_SOR_PWR; + nvif_mthd(disp->disp, 0, &args, sizeof(args)); } - - nv_call(disp->core, mthd, (mode == DRM_MODE_DPMS_ON)); } static bool @@ -1781,7 +1861,7 @@ nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data) 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) < NVD0_DISP_MAST_CLASS) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1); evo_data(push, (nv_encoder->ctrl = temp)); } else { @@ -1804,6 +1884,7 @@ 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); } } @@ -1817,15 +1898,24 @@ static void nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, struct drm_display_mode *mode) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_sor_lvds_script_v0 lvds; + } lvds = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT, + .base.hasht = nv_encoder->dcb->hasht, + .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_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct nouveau_connector *nv_connector; struct nvbios *bios = &drm->vbios; - u32 lvds = 0, mask, ctrl; + u32 mask, ctrl; u8 owner = 1 << nv_crtc->index; u8 proto = 0xf; u8 depth = 0x0; @@ -1851,31 +1941,31 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, if (bios->fp_no_ddc) { if (bios->fp.dual_link) - lvds |= 0x0100; + lvds.lvds.script |= 0x0100; if (bios->fp.if_is_24bit) - lvds |= 0x0200; + lvds.lvds.script |= 0x0200; } else { if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) { if (((u8 *)nv_connector->edid)[121] == 2) - lvds |= 0x0100; + lvds.lvds.script |= 0x0100; } else if (mode->clock >= bios->fp.duallink_transition_clk) { - lvds |= 0x0100; + lvds.lvds.script |= 0x0100; } - if (lvds & 0x0100) { + if (lvds.lvds.script & 0x0100) { if (bios->fp.strapless_is_24bit & 2) - lvds |= 0x0200; + lvds.lvds.script |= 0x0200; } else { if (bios->fp.strapless_is_24bit & 1) - lvds |= 0x0200; + lvds.lvds.script |= 0x0200; } if (nv_connector->base.display_info.bpc == 8) - lvds |= 0x0200; + lvds.lvds.script |= 0x0200; } - nv_call(disp->core, NV50_DISP_SOR_LVDS_SCRIPT + nv_encoder->or, lvds); + nvif_mthd(disp->disp, 0, &lvds, sizeof(lvds)); break; case DCB_OUTPUT_DP: if (nv_connector->base.display_info.bpc == 6) { @@ -1894,6 +1984,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, proto = 0x8; else proto = 0x9; + nv50_audio_mode_set(encoder, mode); break; default: BUG_ON(1); @@ -1902,7 +1993,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON); - if (nv50_vers(mast) >= NVD0_DISP_CLASS) { + if (nv50_vers(mast) >= GF110_DISP) { u32 *push = evo_wait(mast, 3); if (push) { u32 magic = 0x31ec6000 | (nv_crtc->index << 25); @@ -1961,7 +2052,7 @@ static int nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) { struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nouveau_i2c *i2c = nouveau_i2c(drm->device); + struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; int type; @@ -2002,9 +2093,19 @@ nv50_pior_dpms(struct drm_encoder *encoder, int mode) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv50_disp *disp = nv50_disp(encoder->dev); - u32 mthd = (nv_encoder->dcb->type << 12) | nv_encoder->or; - u32 ctrl = (mode == DRM_MODE_DPMS_ON); - nv_call(disp->core, NV50_DISP_PIOR_PWR + mthd, ctrl); + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_pior_pwr_v0 pwr; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_PIOR_PWR, + .base.hasht = nv_encoder->dcb->hasht, + .base.hashm = nv_encoder->dcb->hashm, + .pwr.state = mode == DRM_MODE_DPMS_ON, + .pwr.type = nv_encoder->dcb->type, + }; + + nvif_mthd(disp->disp, 0, &args, sizeof(args)); } static bool @@ -2067,7 +2168,7 @@ nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, push = evo_wait(mast, 8); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { u32 ctrl = (depth << 16) | (proto << 8) | owner; if (mode->flags & DRM_MODE_FLAG_NHSYNC) ctrl |= 0x00001000; @@ -2096,7 +2197,7 @@ nv50_pior_disconnect(struct drm_encoder *encoder) push = evo_wait(mast, 4); if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { evo_mthd(push, 0x0700 + (or * 0x040), 1); evo_data(push, 0x00000000); } @@ -2132,7 +2233,7 @@ static int nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) { struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nouveau_i2c *i2c = nouveau_i2c(drm->device); + struct nouveau_i2c *i2c = nvkm_i2c(&drm->device); struct nouveau_i2c_port *ddc = NULL; struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; @@ -2169,8 +2270,151 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) } /****************************************************************************** + * Framebuffer + *****************************************************************************/ + +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 gf110_dma_v0 gf110; + }; + } 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.gf110.page = GF110_DMA_V0_PAGE_LP; + args.gf110.kind = kind; + size += sizeof(args.gf110); + } + + 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, NULL, + 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, NULL, 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) +{ +} + +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; + + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) { + NV_ERROR(drm, "framebuffer requires contiguous bo\n"); + return -EINVAL; + } + + 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; + + return nv50_fbdma_init(fb->dev, nv_fb->r_handle, 0, + drm->device.info.ram_user, kind); +} + +/****************************************************************************** * Init *****************************************************************************/ + void nv50_display_fini(struct drm_device *dev) { @@ -2193,7 +2437,7 @@ nv50_display_init(struct drm_device *dev) } evo_mthd(push, 0x0088, 1); - evo_data(push, NvEvoSync); + evo_data(push, nv50_mast(dev)->base.sync.handle); evo_kick(push, nv50_mast(dev)); return 0; } @@ -2202,8 +2446,13 @@ 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->core, &disp->mast.base); + nv50_dmac_destroy(&disp->mast.base, disp->disp); nouveau_bo_unmap(disp->sync); if (disp->sync) @@ -2217,7 +2466,7 @@ nv50_display_destroy(struct drm_device *dev) int nv50_display_create(struct drm_device *dev) { - struct nouveau_device *device = nouveau_dev(dev); + struct nvif_device *device = &nouveau_drm(dev)->device; struct nouveau_drm *drm = nouveau_drm(dev); struct dcb_table *dcb = &drm->vbios.dcb; struct drm_connector *connector, *tmp; @@ -2228,16 +2477,19 @@ 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; nouveau_display(dev)->init = nv50_display_init; nouveau_display(dev)->fini = nv50_display_fini; - disp->core = nouveau_display(dev)->core; + nouveau_display(dev)->fb_ctor = nv50_fb_ctor; + nouveau_display(dev)->fb_dtor = nv50_fb_dtor; + disp->disp = &nouveau_display(dev)->disp; /* small shared memory area we use for notifiers and semaphores */ ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, - 0, 0x0000, NULL, &disp->sync); + 0, 0x0000, NULL, NULL, &disp->sync); if (!ret) { ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM); if (!ret) { @@ -2253,22 +2505,19 @@ nv50_display_create(struct drm_device *dev) goto out; /* allocate master evo channel */ - ret = nv50_dmac_create(disp->core, NV50_DISP_MAST_CLASS, 0, - &(struct nv50_display_mast_class) { - .pushbuf = EVO_PUSH_HANDLE(MAST, 0), - }, sizeof(struct nv50_display_mast_class), - disp->sync->bo.offset, &disp->mast.base); + ret = nv50_core_create(disp->disp, disp->sync->bo.offset, + &disp->mast); if (ret) goto out; /* create crtc objects to represent the hw heads */ - if (nv_mclass(disp->core) >= NVD0_DISP_CLASS) - crtcs = nv_rd32(device, 0x022448); + if (disp->disp->oclass >= GF110_DISP) + crtcs = nvif_rd32(device, 0x022448); else crtcs = 2; for (i = 0; i < crtcs; i++) { - ret = nv50_crtc_create(dev, disp->core, i); + ret = nv50_crtc_create(dev, i); if (ret) goto out; } diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 52068a0910dc..394c89abcc97 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -154,7 +154,6 @@ nv50_fbcon_accel_init(struct fb_info *info) struct drm_device *dev = nfbdev->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; - struct nouveau_object *object; int ret, format; switch (info->var.bits_per_pixel) { @@ -184,8 +183,8 @@ nv50_fbcon_accel_init(struct fb_info *info) return -EINVAL; } - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, Nv2D, - 0x502d, NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x502d, 0x502d, NULL, 0, + &nfbdev->twod); if (ret) return ret; @@ -196,11 +195,11 @@ nv50_fbcon_accel_init(struct fb_info *info) } BEGIN_NV04(chan, NvSub2D, 0x0000, 1); - OUT_RING(chan, Nv2D); + OUT_RING(chan, nfbdev->twod.handle); BEGIN_NV04(chan, NvSub2D, 0x0184, 3); - OUT_RING(chan, NvDmaFB); - OUT_RING(chan, NvDmaFB); - OUT_RING(chan, NvDmaFB); + OUT_RING(chan, chan->vram.handle); + OUT_RING(chan, chan->vram.handle); + OUT_RING(chan, chan->vram.handle); BEGIN_NV04(chan, NvSub2D, 0x0290, 1); OUT_RING(chan, 0); BEGIN_NV04(chan, NvSub2D, 0x0888, 1); diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index 0ee363840035..22d242b37962 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c @@ -22,8 +22,8 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include <core/object.h> -#include <core/class.h> +#include <nvif/os.h> +#include <nvif/class.h> #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -38,7 +38,6 @@ nv50_fence_context_new(struct nouveau_channel *chan) struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx; struct ttm_mem_reg *mem = &priv->bo->bo.mem; - struct nouveau_object *object; u32 start = mem->start * PAGE_SIZE; u32 limit = start + mem->size - 1; int ret, i; @@ -47,20 +46,19 @@ nv50_fence_context_new(struct nouveau_channel *chan) if (!fctx) return -ENOMEM; - nouveau_fence_context_new(&fctx->base); + nouveau_fence_context_new(chan, &fctx->base); fctx->base.emit = nv10_fence_emit; fctx->base.read = nv10_fence_read; fctx->base.sync = nv17_fence_sync; - ret = nouveau_object_new(nv_object(chan->cli), chan->handle, - NvSema, 0x003d, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, + ret = nvif_object_init(chan->object, NULL, NvSema, 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_class), - &object); + }, 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++) { @@ -68,15 +66,14 @@ nv50_fence_context_new(struct nouveau_channel *chan) u32 start = bo->bo.mem.start * PAGE_SIZE; u32 limit = start + bo->bo.mem.size - 1; - ret = nouveau_object_new(nv_object(chan->cli), chan->handle, - NvEvoSema0 + i, 0x003d, - &(struct nv_dma_class) { - .flags = NV_DMA_TARGET_VRAM | - NV_DMA_ACCESS_RDWR, + ret = nvif_object_init(chan->object, NULL, 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_class), - &object); + }, sizeof(struct nv_dma_v0), + &fctx->head[i]); } if (ret) @@ -98,10 +95,12 @@ nv50_fence_create(struct nouveau_drm *drm) priv->base.resume = nv17_fence_resume; priv->base.context_new = nv50_fence_context_new; priv->base.context_del = nv10_fence_context_del; + priv->base.contexts = 127; + priv->base.context_base = fence_context_alloc(priv->base.contexts); spin_lock_init(&priv->lock); ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, - 0, 0x0000, NULL, &priv->bo); + 0, 0x0000, NULL, NULL, &priv->bo); if (!ret) { ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); if (!ret) { diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 9fd475c89820..d6c6c87c3f07 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -22,12 +22,6 @@ * Authors: Ben Skeggs */ -#include <core/object.h> -#include <core/client.h> -#include <core/class.h> - -#include <engine/fifo.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_fence.h" @@ -47,7 +41,7 @@ nv84_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence) int ret = RING_SPACE(chan, 8); if (ret == 0) { BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); - OUT_RING (chan, chan->vram); + OUT_RING (chan, chan->vram.handle); BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5); OUT_RING (chan, upper_32_bits(virtual)); OUT_RING (chan, lower_32_bits(virtual)); @@ -65,7 +59,7 @@ nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence) int ret = RING_SPACE(chan, 7); if (ret == 0) { BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); - OUT_RING (chan, chan->vram); + OUT_RING (chan, chan->vram.handle); BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(virtual)); OUT_RING (chan, lower_32_bits(virtual)); @@ -81,15 +75,14 @@ nv84_fence_emit(struct nouveau_fence *fence) { struct nouveau_channel *chan = fence->channel; struct nv84_fence_chan *fctx = chan->fence; - struct nouveau_fifo_chan *fifo = (void *)chan->object; - u64 addr = fifo->chid * 16; + u64 addr = chan->chid * 16; if (fence->sysmem) addr += fctx->vma_gart.offset; else addr += fctx->vma.offset; - return fctx->base.emit32(chan, addr, fence->sequence); + return fctx->base.emit32(chan, addr, fence->base.seqno); } static int @@ -97,23 +90,21 @@ nv84_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *prev, struct nouveau_channel *chan) { struct nv84_fence_chan *fctx = chan->fence; - struct nouveau_fifo_chan *fifo = (void *)prev->object; - u64 addr = fifo->chid * 16; + u64 addr = prev->chid * 16; if (fence->sysmem) addr += fctx->vma_gart.offset; else addr += fctx->vma.offset; - return fctx->base.sync32(chan, addr, fence->sequence); + return fctx->base.sync32(chan, addr, fence->base.seqno); } static u32 nv84_fence_read(struct nouveau_channel *chan) { - struct nouveau_fifo_chan *fifo = (void *)chan->object; struct nv84_fence_priv *priv = chan->drm->fence; - return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4); + return nouveau_bo_rd32(priv->bo, chan->chid * 16/4); } static void @@ -129,18 +120,18 @@ nv84_fence_context_del(struct nouveau_channel *chan) 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); nouveau_bo_vma_del(priv->bo, &fctx->vma); nouveau_fence_context_del(&fctx->base); chan->fence = NULL; - kfree(fctx); + nouveau_fence_context_free(&fctx->base); } int nv84_fence_context_new(struct nouveau_channel *chan) { - struct nouveau_fifo_chan *fifo = (void *)chan->object; - struct nouveau_client *client = nouveau_client(fifo); + struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base); struct nv84_fence_priv *priv = chan->drm->fence; struct nv84_fence_chan *fctx; int ret, i; @@ -149,27 +140,26 @@ nv84_fence_context_new(struct nouveau_channel *chan) if (!fctx) return -ENOMEM; - nouveau_fence_context_new(&fctx->base); + nouveau_fence_context_new(chan, &fctx->base); fctx->base.emit = nv84_fence_emit; fctx->base.sync = nv84_fence_sync; fctx->base.read = nv84_fence_read; fctx->base.emit32 = nv84_fence_emit32; fctx->base.sync32 = nv84_fence_sync32; + fctx->base.sequence = nv84_fence_read(chan); - ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma); + ret = nouveau_bo_vma_add(priv->bo, cli->vm, &fctx->vma); if (ret == 0) { - ret = nouveau_bo_vma_add(priv->bo_gart, client->vm, + ret = nouveau_bo_vma_add(priv->bo_gart, cli->vm, &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, client->vm, &fctx->dispc_vma[i]); + ret = nouveau_bo_vma_add(bo, cli->vm, &fctx->dispc_vma[i]); } - nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000); - if (ret) nv84_fence_context_del(chan); return ret; @@ -178,13 +168,12 @@ nv84_fence_context_new(struct nouveau_channel *chan) static bool nv84_fence_suspend(struct nouveau_drm *drm) { - struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); struct nv84_fence_priv *priv = drm->fence; int i; - priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32)); + priv->suspend = vmalloc(priv->base.contexts * sizeof(u32)); if (priv->suspend) { - for (i = 0; i <= pfifo->max; i++) + for (i = 0; i < priv->base.contexts; i++) priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4); } @@ -194,12 +183,11 @@ nv84_fence_suspend(struct nouveau_drm *drm) static void nv84_fence_resume(struct nouveau_drm *drm) { - struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); struct nv84_fence_priv *priv = drm->fence; int i; if (priv->suspend) { - for (i = 0; i <= pfifo->max; i++) + for (i = 0; i < priv->base.contexts; i++) nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]); vfree(priv->suspend); priv->suspend = NULL; @@ -225,7 +213,7 @@ nv84_fence_destroy(struct nouveau_drm *drm) int nv84_fence_create(struct nouveau_drm *drm) { - struct nouveau_fifo *pfifo = nouveau_fifo(drm->device); + struct nouveau_fifo *pfifo = nvkm_fifo(&drm->device); struct nv84_fence_priv *priv; int ret; @@ -239,11 +227,12 @@ nv84_fence_create(struct nouveau_drm *drm) priv->base.context_new = nv84_fence_context_new; priv->base.context_del = nv84_fence_context_del; - init_waitqueue_head(&priv->base.waiting); + priv->base.contexts = pfifo->max + 1; + priv->base.context_base = fence_context_alloc(priv->base.contexts); priv->base.uevent = true; - ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0, - TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo); + ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0, + TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL, &priv->bo); if (ret == 0) { ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM); if (ret == 0) { @@ -256,8 +245,8 @@ nv84_fence_create(struct nouveau_drm *drm) } if (ret == 0) - ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0, - TTM_PL_FLAG_TT, 0, 0, NULL, + ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0, + TTM_PL_FLAG_TT, 0, 0, NULL, NULL, &priv->bo_gart); if (ret == 0) { ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT); diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c index 9dcd30f3e1e0..61246677e8dc 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c +++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c @@ -154,11 +154,10 @@ nvc0_fbcon_accel_init(struct fb_info *info) struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; - struct nouveau_object *object; int ret, format; - ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, Nv2D, - 0x902d, NULL, 0, &object); + ret = nvif_object_init(chan->object, NULL, 0x902d, 0x902d, NULL, 0, + &nfbdev->twod); if (ret) return ret; @@ -197,7 +196,7 @@ nvc0_fbcon_accel_init(struct fb_info *info) } BEGIN_NVC0(chan, NvSub2D, 0x0000, 1); - OUT_RING (chan, 0x0000902d); + OUT_RING (chan, nfbdev->twod.handle); BEGIN_NVC0(chan, NvSub2D, 0x0290, 1); OUT_RING (chan, 0); BEGIN_NVC0(chan, NvSub2D, 0x0888, 1); diff --git a/drivers/gpu/drm/nouveau/nvc0_fence.c b/drivers/gpu/drm/nouveau/nvc0_fence.c index 9566267fbc42..becf19abda2d 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fence.c +++ b/drivers/gpu/drm/nouveau/nvc0_fence.c @@ -22,12 +22,6 @@ * Authors: Ben Skeggs */ -#include <core/object.h> -#include <core/client.h> -#include <core/class.h> - -#include <engine/fifo.h> - #include "nouveau_drm.h" #include "nouveau_dma.h" #include "nouveau_fence.h" diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h new file mode 100644 index 000000000000..e5a27df0672b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/class.h @@ -0,0 +1,567 @@ +#ifndef __NVIF_CLASS_H__ +#define __NVIF_CLASS_H__ + +/******************************************************************************* + * class identifiers + ******************************************************************************/ + +/* the below match nvidia-assigned (either in hw, or sw) class numbers */ +#define NV_DEVICE 0x00000080 + +#define NV_DMA_FROM_MEMORY 0x00000002 +#define NV_DMA_TO_MEMORY 0x00000003 +#define NV_DMA_IN_MEMORY 0x0000003d + +#define NV04_DISP 0x00000046 + +#define NV03_CHANNEL_DMA 0x0000006b +#define NV10_CHANNEL_DMA 0x0000006e +#define NV17_CHANNEL_DMA 0x0000176e +#define NV40_CHANNEL_DMA 0x0000406e +#define NV50_CHANNEL_DMA 0x0000506e +#define G82_CHANNEL_DMA 0x0000826e + +#define NV50_CHANNEL_GPFIFO 0x0000506f +#define G82_CHANNEL_GPFIFO 0x0000826f +#define FERMI_CHANNEL_GPFIFO 0x0000906f +#define KEPLER_CHANNEL_GPFIFO_A 0x0000a06f + +#define NV50_DISP 0x00005070 +#define G82_DISP 0x00008270 +#define GT200_DISP 0x00008370 +#define GT214_DISP 0x00008570 +#define GT206_DISP 0x00008870 +#define GF110_DISP 0x00009070 +#define GK104_DISP 0x00009170 +#define GK110_DISP 0x00009270 +#define GM107_DISP 0x00009470 + +#define NV50_DISP_CURSOR 0x0000507a +#define G82_DISP_CURSOR 0x0000827a +#define GT214_DISP_CURSOR 0x0000857a +#define GF110_DISP_CURSOR 0x0000907a +#define GK104_DISP_CURSOR 0x0000917a + +#define NV50_DISP_OVERLAY 0x0000507b +#define G82_DISP_OVERLAY 0x0000827b +#define GT214_DISP_OVERLAY 0x0000857b +#define GF110_DISP_OVERLAY 0x0000907b +#define GK104_DISP_OVERLAY 0x0000917b + +#define NV50_DISP_BASE_CHANNEL_DMA 0x0000507c +#define G82_DISP_BASE_CHANNEL_DMA 0x0000827c +#define GT200_DISP_BASE_CHANNEL_DMA 0x0000837c +#define GT214_DISP_BASE_CHANNEL_DMA 0x0000857c +#define GF110_DISP_BASE_CHANNEL_DMA 0x0000907c +#define GK104_DISP_BASE_CHANNEL_DMA 0x0000917c +#define GK110_DISP_BASE_CHANNEL_DMA 0x0000927c + +#define NV50_DISP_CORE_CHANNEL_DMA 0x0000507d +#define G82_DISP_CORE_CHANNEL_DMA 0x0000827d +#define GT200_DISP_CORE_CHANNEL_DMA 0x0000837d +#define GT214_DISP_CORE_CHANNEL_DMA 0x0000857d +#define GT206_DISP_CORE_CHANNEL_DMA 0x0000887d +#define GF110_DISP_CORE_CHANNEL_DMA 0x0000907d +#define GK104_DISP_CORE_CHANNEL_DMA 0x0000917d +#define GK110_DISP_CORE_CHANNEL_DMA 0x0000927d +#define GM107_DISP_CORE_CHANNEL_DMA 0x0000947d + +#define NV50_DISP_OVERLAY_CHANNEL_DMA 0x0000507e +#define G82_DISP_OVERLAY_CHANNEL_DMA 0x0000827e +#define GT200_DISP_OVERLAY_CHANNEL_DMA 0x0000837e +#define GT214_DISP_OVERLAY_CHANNEL_DMA 0x0000857e +#define GF110_DISP_OVERLAY_CONTROL_DMA 0x0000907e +#define GK104_DISP_OVERLAY_CONTROL_DMA 0x0000917e + +#define FERMI_A 0x00009097 +#define FERMI_B 0x00009197 +#define FERMI_C 0x00009297 + +#define KEPLER_A 0x0000a097 +#define KEPLER_B 0x0000a197 +#define KEPLER_C 0x0000a297 + +#define MAXWELL_A 0x0000b097 + +#define FERMI_COMPUTE_A 0x000090c0 +#define FERMI_COMPUTE_B 0x000091c0 + +#define KEPLER_COMPUTE_A 0x0000a0c0 +#define KEPLER_COMPUTE_B 0x0000a1c0 + +#define MAXWELL_COMPUTE_A 0x0000b0c0 + + +/******************************************************************************* + * client + ******************************************************************************/ + +#define NV_CLIENT_DEVLIST 0x00 + +struct nv_client_devlist_v0 { + __u8 version; + __u8 count; + __u8 pad02[6]; + __u64 device[]; +}; + + +/******************************************************************************* + * device + ******************************************************************************/ + +struct nv_device_v0 { + __u8 version; + __u8 pad01[7]; + __u64 device; /* device identifier, ~0 for client default */ +#define NV_DEVICE_V0_DISABLE_IDENTIFY 0x0000000000000001ULL +#define NV_DEVICE_V0_DISABLE_MMIO 0x0000000000000002ULL +#define NV_DEVICE_V0_DISABLE_VBIOS 0x0000000000000004ULL +#define NV_DEVICE_V0_DISABLE_CORE 0x0000000000000008ULL +#define NV_DEVICE_V0_DISABLE_DISP 0x0000000000010000ULL +#define NV_DEVICE_V0_DISABLE_FIFO 0x0000000000020000ULL +#define NV_DEVICE_V0_DISABLE_GRAPH 0x0000000100000000ULL +#define NV_DEVICE_V0_DISABLE_MPEG 0x0000000200000000ULL +#define NV_DEVICE_V0_DISABLE_ME 0x0000000400000000ULL +#define NV_DEVICE_V0_DISABLE_VP 0x0000000800000000ULL +#define NV_DEVICE_V0_DISABLE_CRYPT 0x0000001000000000ULL +#define NV_DEVICE_V0_DISABLE_BSP 0x0000002000000000ULL +#define NV_DEVICE_V0_DISABLE_PPP 0x0000004000000000ULL +#define NV_DEVICE_V0_DISABLE_COPY0 0x0000008000000000ULL +#define NV_DEVICE_V0_DISABLE_COPY1 0x0000010000000000ULL +#define NV_DEVICE_V0_DISABLE_VIC 0x0000020000000000ULL +#define NV_DEVICE_V0_DISABLE_VENC 0x0000040000000000ULL + __u64 disable; /* disable particular subsystems */ + __u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */ +}; + +#define NV_DEVICE_V0_INFO 0x00 + +struct nv_device_info_v0 { + __u8 version; +#define NV_DEVICE_INFO_V0_IGP 0x00 +#define NV_DEVICE_INFO_V0_PCI 0x01 +#define NV_DEVICE_INFO_V0_AGP 0x02 +#define NV_DEVICE_INFO_V0_PCIE 0x03 +#define NV_DEVICE_INFO_V0_SOC 0x04 + __u8 platform; + __u16 chipset; /* from NV_PMC_BOOT_0 */ + __u8 revision; /* from NV_PMC_BOOT_0 */ +#define NV_DEVICE_INFO_V0_TNT 0x01 +#define NV_DEVICE_INFO_V0_CELSIUS 0x02 +#define NV_DEVICE_INFO_V0_KELVIN 0x03 +#define NV_DEVICE_INFO_V0_RANKINE 0x04 +#define NV_DEVICE_INFO_V0_CURIE 0x05 +#define NV_DEVICE_INFO_V0_TESLA 0x06 +#define NV_DEVICE_INFO_V0_FERMI 0x07 +#define NV_DEVICE_INFO_V0_KEPLER 0x08 +#define NV_DEVICE_INFO_V0_MAXWELL 0x09 + __u8 family; + __u8 pad06[2]; + __u64 ram_size; + __u64 ram_user; +}; + + +/******************************************************************************* + * context dma + ******************************************************************************/ + +struct nv_dma_v0 { + __u8 version; +#define NV_DMA_V0_TARGET_VM 0x00 +#define NV_DMA_V0_TARGET_VRAM 0x01 +#define NV_DMA_V0_TARGET_PCI 0x02 +#define NV_DMA_V0_TARGET_PCI_US 0x03 +#define NV_DMA_V0_TARGET_AGP 0x04 + __u8 target; +#define NV_DMA_V0_ACCESS_VM 0x00 +#define NV_DMA_V0_ACCESS_RD 0x01 +#define NV_DMA_V0_ACCESS_WR 0x02 +#define NV_DMA_V0_ACCESS_RDWR (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR) + __u8 access; + __u8 pad03[5]; + __u64 start; + __u64 limit; + /* ... chipset-specific class data */ +}; + +struct nv50_dma_v0 { + __u8 version; +#define NV50_DMA_V0_PRIV_VM 0x00 +#define NV50_DMA_V0_PRIV_US 0x01 +#define NV50_DMA_V0_PRIV__S 0x02 + __u8 priv; +#define NV50_DMA_V0_PART_VM 0x00 +#define NV50_DMA_V0_PART_256 0x01 +#define NV50_DMA_V0_PART_1KB 0x02 + __u8 part; +#define NV50_DMA_V0_COMP_NONE 0x00 +#define NV50_DMA_V0_COMP_1 0x01 +#define NV50_DMA_V0_COMP_2 0x02 +#define NV50_DMA_V0_COMP_VM 0x03 + __u8 comp; +#define NV50_DMA_V0_KIND_PITCH 0x00 +#define NV50_DMA_V0_KIND_VM 0x7f + __u8 kind; + __u8 pad05[3]; +}; + +struct gf100_dma_v0 { + __u8 version; +#define GF100_DMA_V0_PRIV_VM 0x00 +#define GF100_DMA_V0_PRIV_US 0x01 +#define GF100_DMA_V0_PRIV__S 0x02 + __u8 priv; +#define GF100_DMA_V0_KIND_PITCH 0x00 +#define GF100_DMA_V0_KIND_VM 0xff + __u8 kind; + __u8 pad03[5]; +}; + +struct gf110_dma_v0 { + __u8 version; +#define GF110_DMA_V0_PAGE_LP 0x00 +#define GF110_DMA_V0_PAGE_SP 0x01 + __u8 page; +#define GF110_DMA_V0_KIND_PITCH 0x00 +#define GF110_DMA_V0_KIND_VM 0xff + __u8 kind; + __u8 pad03[5]; +}; + + +/******************************************************************************* + * perfmon + ******************************************************************************/ + +struct nvif_perfctr_v0 { + __u8 version; + __u8 pad01[1]; + __u16 logic_op; + __u8 pad04[4]; + char name[4][64]; +}; + +#define NVIF_PERFCTR_V0_QUERY 0x00 +#define NVIF_PERFCTR_V0_SAMPLE 0x01 +#define NVIF_PERFCTR_V0_READ 0x02 + +struct nvif_perfctr_query_v0 { + __u8 version; + __u8 pad01[3]; + __u32 iter; + char name[64]; +}; + +struct nvif_perfctr_sample { +}; + +struct nvif_perfctr_read_v0 { + __u8 version; + __u8 pad01[7]; + __u32 ctr; + __u32 clk; +}; + + +/******************************************************************************* + * device control + ******************************************************************************/ + +#define NVIF_CONTROL_PSTATE_INFO 0x00 +#define NVIF_CONTROL_PSTATE_ATTR 0x01 +#define NVIF_CONTROL_PSTATE_USER 0x02 + +struct nvif_control_pstate_info_v0 { + __u8 version; + __u8 count; /* out: number of power states */ +#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE (-1) +#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON (-2) + __s8 ustate_ac; /* out: target pstate index */ + __s8 ustate_dc; /* out: target pstate index */ + __s8 pwrsrc; /* out: current power source */ +#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN (-1) +#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON (-2) + __s8 pstate; /* out: current pstate index */ + __u8 pad06[2]; +}; + +struct nvif_control_pstate_attr_v0 { + __u8 version; +#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT (-1) + __s8 state; /* in: index of pstate to query + * out: pstate identifier + */ + __u8 index; /* in: index of attribute to query + * out: index of next attribute, or 0 if no more + */ + __u8 pad03[5]; + __u32 min; + __u32 max; + char name[32]; + char unit[16]; +}; + +struct nvif_control_pstate_user_v0 { + __u8 version; +#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN (-1) +#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON (-2) + __s8 ustate; /* in: pstate identifier */ + __s8 pwrsrc; /* in: target power source */ + __u8 pad03[5]; +}; + + +/******************************************************************************* + * DMA FIFO channels + ******************************************************************************/ + +struct nv03_channel_dma_v0 { + __u8 version; + __u8 chid; + __u8 pad02[2]; + __u32 pushbuf; + __u64 offset; +}; + +#define G82_CHANNEL_DMA_V0_NTFY_UEVENT 0x00 + +/******************************************************************************* + * GPFIFO channels + ******************************************************************************/ + +struct nv50_channel_gpfifo_v0 { + __u8 version; + __u8 chid; + __u8 pad01[6]; + __u32 pushbuf; + __u32 ilength; + __u64 ioffset; +}; + +struct kepler_channel_gpfifo_a_v0 { + __u8 version; +#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR 0x01 +#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_VP 0x02 +#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_PPP 0x04 +#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_BSP 0x08 +#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0 0x10 +#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1 0x20 +#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC 0x40 + __u8 engine; + __u16 chid; + __u8 pad04[4]; + __u32 pushbuf; + __u32 ilength; + __u64 ioffset; +}; + +/******************************************************************************* + * legacy display + ******************************************************************************/ + +#define NV04_DISP_NTFY_VBLANK 0x00 +#define NV04_DISP_NTFY_CONN 0x01 + +struct nv04_disp_mthd_v0 { + __u8 version; +#define NV04_DISP_SCANOUTPOS 0x00 + __u8 method; + __u8 head; + __u8 pad03[5]; +}; + +struct nv04_disp_scanoutpos_v0 { + __u8 version; + __u8 pad01[7]; + __s64 time[2]; + __u16 vblanks; + __u16 vblanke; + __u16 vtotal; + __u16 vline; + __u16 hblanks; + __u16 hblanke; + __u16 htotal; + __u16 hline; +}; + +/******************************************************************************* + * display + ******************************************************************************/ + +#define NV50_DISP_MTHD 0x00 + +struct nv50_disp_mthd_v0 { + __u8 version; +#define NV50_DISP_SCANOUTPOS 0x00 + __u8 method; + __u8 head; + __u8 pad03[5]; +}; + +struct nv50_disp_mthd_v1 { + __u8 version; +#define NV50_DISP_MTHD_V1_DAC_PWR 0x10 +#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11 +#define NV50_DISP_MTHD_V1_SOR_PWR 0x20 +#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21 +#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_PIOR_PWR 0x30 + __u8 method; + __u16 hasht; + __u16 hashm; + __u8 pad06[2]; +}; + +struct nv50_disp_dac_pwr_v0 { + __u8 version; + __u8 state; + __u8 data; + __u8 vsync; + __u8 hsync; + __u8 pad05[3]; +}; + +struct nv50_disp_dac_load_v0 { + __u8 version; + __u8 load; + __u8 pad02[2]; + __u32 data; +}; + +struct nv50_disp_sor_pwr_v0 { + __u8 version; + __u8 state; + __u8 pad02[6]; +}; + +struct nv50_disp_sor_hda_eld_v0 { + __u8 version; + __u8 pad01[7]; + __u8 data[]; +}; + +struct nv50_disp_sor_hdmi_pwr_v0 { + __u8 version; + __u8 state; + __u8 max_ac_packet; + __u8 rekey; + __u8 pad04[4]; +}; + +struct nv50_disp_sor_lvds_script_v0 { + __u8 version; + __u8 pad01[1]; + __u16 script; + __u8 pad04[4]; +}; + +struct nv50_disp_sor_dp_pwr_v0 { + __u8 version; + __u8 state; + __u8 pad02[6]; +}; + +struct nv50_disp_pior_pwr_v0 { + __u8 version; + __u8 state; + __u8 type; + __u8 pad03[5]; +}; + +/* core */ +struct nv50_disp_core_channel_dma_v0 { + __u8 version; + __u8 pad01[3]; + __u32 pushbuf; +}; + +#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00 + +/* cursor immediate */ +struct nv50_disp_cursor_v0 { + __u8 version; + __u8 head; + __u8 pad02[6]; +}; + +#define NV50_DISP_CURSOR_V0_NTFY_UEVENT 0x00 + +/* base */ +struct nv50_disp_base_channel_dma_v0 { + __u8 version; + __u8 pad01[2]; + __u8 head; + __u32 pushbuf; +}; + +#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00 + +/* overlay */ +struct nv50_disp_overlay_channel_dma_v0 { + __u8 version; + __u8 pad01[2]; + __u8 head; + __u32 pushbuf; +}; + +#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00 + +/* overlay immediate */ +struct nv50_disp_overlay_v0 { + __u8 version; + __u8 head; + __u8 pad02[6]; +}; + +#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT 0x00 + +/******************************************************************************* + * fermi + ******************************************************************************/ + +#define FERMI_A_ZBC_COLOR 0x00 +#define FERMI_A_ZBC_DEPTH 0x01 + +struct fermi_a_zbc_color_v0 { + __u8 version; +#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO 0x01 +#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE 0x02 +#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32 0x04 +#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16 0x08 +#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16 0x0c +#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16 0x10 +#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16 0x14 +#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16 0x16 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8 0x18 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8 0x1c +#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10 0x20 +#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10 0x24 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8 0x28 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8 0x2c +#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8 0x30 +#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8 0x34 +#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8 0x38 +#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10 0x3c +#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11 0x40 + __u8 format; + __u8 index; + __u8 pad03[5]; + __u32 ds[4]; + __u32 l2[4]; +}; + +struct fermi_a_zbc_depth_v0 { + __u8 version; +#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32 0x01 + __u8 format; + __u8 index; + __u8 pad03[5]; + __u32 ds; + __u32 l2; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c new file mode 100644 index 000000000000..3c4df1fc26dc --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -0,0 +1,129 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#include "client.h" +#include "driver.h" +#include "ioctl.h" + +int +nvif_client_ioctl(struct nvif_client *client, void *data, u32 size) +{ + return client->driver->ioctl(client->base.priv, client->super, data, size, NULL); +} + +int +nvif_client_suspend(struct nvif_client *client) +{ + return client->driver->suspend(client->base.priv); +} + +int +nvif_client_resume(struct nvif_client *client) +{ + return client->driver->resume(client->base.priv); +} + +void +nvif_client_fini(struct nvif_client *client) +{ + if (client->driver) { + client->driver->fini(client->base.priv); + client->driver = NULL; + client->base.parent = NULL; + nvif_object_fini(&client->base); + } +} + +const struct nvif_driver * +nvif_drivers[] = { +#ifdef __KERNEL__ + &nvif_driver_nvkm, +#else + &nvif_driver_drm, + &nvif_driver_lib, +#endif + NULL +}; + +int +nvif_client_init(void (*dtor)(struct nvif_client *), const char *driver, + const char *name, u64 device, const char *cfg, const char *dbg, + struct nvif_client *client) +{ + int ret, i; + + ret = nvif_object_init(NULL, (void*)dtor, 0, 0, NULL, 0, &client->base); + if (ret) + return ret; + + client->base.parent = &client->base; + client->base.handle = ~0; + client->object = &client->base; + client->super = true; + + for (i = 0, ret = -EINVAL; (client->driver = nvif_drivers[i]); i++) { + if (!driver || !strcmp(client->driver->name, driver)) { + ret = client->driver->init(name, device, cfg, dbg, + &client->base.priv); + if (!ret || driver) + break; + } + } + + if (ret) + nvif_client_fini(client); + return ret; +} + +static void +nvif_client_del(struct nvif_client *client) +{ + nvif_client_fini(client); + kfree(client); +} + +int +nvif_client_new(const char *driver, const char *name, u64 device, + const char *cfg, const char *dbg, + struct nvif_client **pclient) +{ + struct nvif_client *client = kzalloc(sizeof(*client), GFP_KERNEL); + if (client) { + int ret = nvif_client_init(nvif_client_del, driver, name, + device, cfg, dbg, client); + if (ret) { + kfree(client); + client = NULL; + } + *pclient = client; + return ret; + } + return -ENOMEM; +} + +void +nvif_client_ref(struct nvif_client *client, struct nvif_client **pclient) +{ + nvif_object_ref(&client->base, (struct nvif_object **)pclient); +} diff --git a/drivers/gpu/drm/nouveau/nvif/client.h b/drivers/gpu/drm/nouveau/nvif/client.h new file mode 100644 index 000000000000..28352f0882ec --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/client.h @@ -0,0 +1,39 @@ +#ifndef __NVIF_CLIENT_H__ +#define __NVIF_CLIENT_H__ + +#include "object.h" + +struct nvif_client { + struct nvif_object base; + struct nvif_object *object; /*XXX: hack for nvif_object() */ + const struct nvif_driver *driver; + bool super; +}; + +static inline struct nvif_client * +nvif_client(struct nvif_object *object) +{ + while (object && object->parent != object) + object = object->parent; + return (void *)object; +} + +int nvif_client_init(void (*dtor)(struct nvif_client *), const char *, + const char *, u64, const char *, const char *, + struct nvif_client *); +void nvif_client_fini(struct nvif_client *); +int nvif_client_new(const char *, const char *, u64, const char *, + const char *, struct nvif_client **); +void nvif_client_ref(struct nvif_client *, struct nvif_client **); +int nvif_client_ioctl(struct nvif_client *, void *, u32); +int nvif_client_suspend(struct nvif_client *); +int nvif_client_resume(struct nvif_client *); + +/*XXX*/ +#include <core/client.h> +#define nvkm_client(a) ({ \ + struct nvif_client *_client = nvif_client(nvif_object(a)); \ + nouveau_client(_client->base.priv); \ +}) + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c new file mode 100644 index 000000000000..f477579725e3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/device.c @@ -0,0 +1,78 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +#include "device.h" + +void +nvif_device_fini(struct nvif_device *device) +{ + nvif_object_fini(&device->base); +} + +int +nvif_device_init(struct nvif_object *parent, void (*dtor)(struct nvif_device *), + u32 handle, u32 oclass, void *data, u32 size, + struct nvif_device *device) +{ + int ret = nvif_object_init(parent, (void *)dtor, handle, oclass, + data, size, &device->base); + if (ret == 0) { + device->object = &device->base; + device->info.version = 0; + ret = nvif_object_mthd(&device->base, NV_DEVICE_V0_INFO, + &device->info, sizeof(device->info)); + } + return ret; +} + +static void +nvif_device_del(struct nvif_device *device) +{ + nvif_device_fini(device); + kfree(device); +} + +int +nvif_device_new(struct nvif_object *parent, u32 handle, u32 oclass, + void *data, u32 size, struct nvif_device **pdevice) +{ + struct nvif_device *device = kzalloc(sizeof(*device), GFP_KERNEL); + if (device) { + int ret = nvif_device_init(parent, nvif_device_del, handle, + oclass, data, size, device); + if (ret) { + kfree(device); + device = NULL; + } + *pdevice = device; + return ret; + } + return -ENOMEM; +} + +void +nvif_device_ref(struct nvif_device *device, struct nvif_device **pdevice) +{ + nvif_object_ref(&device->base, (struct nvif_object **)pdevice); +} diff --git a/drivers/gpu/drm/nouveau/nvif/device.h b/drivers/gpu/drm/nouveau/nvif/device.h new file mode 100644 index 000000000000..43180f9fe630 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/device.h @@ -0,0 +1,62 @@ +#ifndef __NVIF_DEVICE_H__ +#define __NVIF_DEVICE_H__ + +#include "object.h" +#include "class.h" + +struct nvif_device { + struct nvif_object base; + struct nvif_object *object; /*XXX: hack for nvif_object() */ + struct nv_device_info_v0 info; +}; + +static inline struct nvif_device * +nvif_device(struct nvif_object *object) +{ + while (object && object->oclass != 0x0080 /*XXX: NV_DEVICE_CLASS*/ ) + object = object->parent; + return (void *)object; +} + +int nvif_device_init(struct nvif_object *, void (*dtor)(struct nvif_device *), + u32 handle, u32 oclass, void *, u32, + struct nvif_device *); +void nvif_device_fini(struct nvif_device *); +int nvif_device_new(struct nvif_object *, u32 handle, u32 oclass, + void *, u32, struct nvif_device **); +void nvif_device_ref(struct nvif_device *, struct nvif_device **); + +/*XXX*/ +#include <subdev/bios.h> +#include <subdev/fb.h> +#include <subdev/vm.h> +#include <subdev/bar.h> +#include <subdev/gpio.h> +#include <subdev/clock.h> +#include <subdev/i2c.h> +#include <subdev/timer.h> +#include <subdev/therm.h> + +#define nvkm_device(a) nv_device(nvkm_object((a))) +#define nvkm_bios(a) nouveau_bios(nvkm_device(a)) +#define nvkm_fb(a) nouveau_fb(nvkm_device(a)) +#define nvkm_vmmgr(a) nouveau_vmmgr(nvkm_device(a)) +#define nvkm_bar(a) nouveau_bar(nvkm_device(a)) +#define nvkm_gpio(a) nouveau_gpio(nvkm_device(a)) +#define nvkm_clock(a) nouveau_clock(nvkm_device(a)) +#define nvkm_i2c(a) nouveau_i2c(nvkm_device(a)) +#define nvkm_timer(a) nouveau_timer(nvkm_device(a)) +#define nvkm_wait(a,b,c,d) nv_wait(nvkm_timer(a), (b), (c), (d)) +#define nvkm_wait_cb(a,b,c) nv_wait_cb(nvkm_timer(a), (b), (c)) +#define nvkm_therm(a) nouveau_therm(nvkm_device(a)) + +#include <engine/device.h> +#include <engine/fifo.h> +#include <engine/graph.h> +#include <engine/software.h> + +#define nvkm_fifo(a) nouveau_fifo(nvkm_device(a)) +#define nvkm_fifo_chan(a) ((struct nouveau_fifo_chan *)nvkm_object(a)) +#define nvkm_gr(a) ((struct nouveau_graph *)nouveau_engine(nvkm_object(a), NVDEV_ENGINE_GR)) + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/driver.h b/drivers/gpu/drm/nouveau/nvif/driver.h new file mode 100644 index 000000000000..ac4bdb3ea506 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/driver.h @@ -0,0 +1,21 @@ +#ifndef __NVIF_DRIVER_H__ +#define __NVIF_DRIVER_H__ + +struct nvif_driver { + const char *name; + int (*init)(const char *name, u64 device, const char *cfg, + const char *dbg, void **priv); + void (*fini)(void *priv); + int (*suspend)(void *priv); + int (*resume)(void *priv); + int (*ioctl)(void *priv, bool super, void *data, u32 size, void **hack); + void __iomem *(*map)(void *priv, u64 handle, u32 size); + void (*unmap)(void *priv, void __iomem *ptr, u32 size); + bool keep; +}; + +extern const struct nvif_driver nvif_driver_nvkm; +extern const struct nvif_driver nvif_driver_drm; +extern const struct nvif_driver nvif_driver_lib; + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/event.h b/drivers/gpu/drm/nouveau/nvif/event.h new file mode 100644 index 000000000000..21764499b4be --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/event.h @@ -0,0 +1,62 @@ +#ifndef __NVIF_EVENT_H__ +#define __NVIF_EVENT_H__ + +struct nvif_notify_req_v0 { + __u8 version; + __u8 reply; + __u8 pad02[5]; +#define NVIF_NOTIFY_V0_ROUTE_NVIF 0x00 + __u8 route; + __u64 token; /* must be unique */ + __u8 data[]; /* request data (below) */ +}; + +struct nvif_notify_rep_v0 { + __u8 version; + __u8 pad01[6]; + __u8 route; + __u64 token; + __u8 data[]; /* reply data (below) */ +}; + +struct nvif_notify_head_req_v0 { + /* nvif_notify_req ... */ + __u8 version; + __u8 head; + __u8 pad02[6]; +}; + +struct nvif_notify_head_rep_v0 { + /* nvif_notify_rep ... */ + __u8 version; + __u8 pad01[7]; +}; + +struct nvif_notify_conn_req_v0 { + /* nvif_notify_req ... */ + __u8 version; +#define NVIF_NOTIFY_CONN_V0_PLUG 0x01 +#define NVIF_NOTIFY_CONN_V0_UNPLUG 0x02 +#define NVIF_NOTIFY_CONN_V0_IRQ 0x04 +#define NVIF_NOTIFY_CONN_V0_ANY 0x07 + __u8 mask; + __u8 conn; + __u8 pad03[5]; +}; + +struct nvif_notify_conn_rep_v0 { + /* nvif_notify_rep ... */ + __u8 version; + __u8 mask; + __u8 pad02[6]; +}; + +struct nvif_notify_uevent_req { + /* nvif_notify_req ... */ +}; + +struct nvif_notify_uevent_rep { + /* nvif_notify_rep ... */ +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/ioctl.h b/drivers/gpu/drm/nouveau/nvif/ioctl.h new file mode 100644 index 000000000000..4cd8e323b23d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/ioctl.h @@ -0,0 +1,128 @@ +#ifndef __NVIF_IOCTL_H__ +#define __NVIF_IOCTL_H__ + +struct nvif_ioctl_v0 { + __u8 version; +#define NVIF_IOCTL_V0_OWNER_NVIF 0x00 +#define NVIF_IOCTL_V0_OWNER_ANY 0xff + __u8 owner; +#define NVIF_IOCTL_V0_NOP 0x00 +#define NVIF_IOCTL_V0_SCLASS 0x01 +#define NVIF_IOCTL_V0_NEW 0x02 +#define NVIF_IOCTL_V0_DEL 0x03 +#define NVIF_IOCTL_V0_MTHD 0x04 +#define NVIF_IOCTL_V0_RD 0x05 +#define NVIF_IOCTL_V0_WR 0x06 +#define NVIF_IOCTL_V0_MAP 0x07 +#define NVIF_IOCTL_V0_UNMAP 0x08 +#define NVIF_IOCTL_V0_NTFY_NEW 0x09 +#define NVIF_IOCTL_V0_NTFY_DEL 0x0a +#define NVIF_IOCTL_V0_NTFY_GET 0x0b +#define NVIF_IOCTL_V0_NTFY_PUT 0x0c + __u8 type; + __u8 path_nr; +#define NVIF_IOCTL_V0_ROUTE_NVIF 0x00 +#define NVIF_IOCTL_V0_ROUTE_HIDDEN 0xff + __u8 pad04[3]; + __u8 route; + __u64 token; + __u32 path[8]; /* in reverse */ + __u8 data[]; /* ioctl data (below) */ +}; + +struct nvif_ioctl_nop { +}; + +struct nvif_ioctl_sclass_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 count; + __u8 pad02[6]; + __u32 oclass[]; +}; + +struct nvif_ioctl_new_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 pad01[6]; + __u8 route; + __u64 token; + __u32 handle; +/* these class numbers are made up by us, and not nvidia-assigned */ +#define NVIF_IOCTL_NEW_V0_PERFCTR 0x0000ffff +#define NVIF_IOCTL_NEW_V0_CONTROL 0x0000fffe + __u32 oclass; + __u8 data[]; /* class data (class.h) */ +}; + +struct nvif_ioctl_del { +}; + +struct nvif_ioctl_rd_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 size; + __u8 pad02[2]; + __u32 data; + __u64 addr; +}; + +struct nvif_ioctl_wr_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 size; + __u8 pad02[2]; + __u32 data; + __u64 addr; +}; + +struct nvif_ioctl_map_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 pad01[3]; + __u32 length; + __u64 handle; +}; + +struct nvif_ioctl_unmap { +}; + +struct nvif_ioctl_ntfy_new_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 event; + __u8 index; + __u8 pad03[5]; + __u8 data[]; /* event request data (event.h) */ +}; + +struct nvif_ioctl_ntfy_del_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 index; + __u8 pad02[6]; +}; + +struct nvif_ioctl_ntfy_get_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 index; + __u8 pad02[6]; +}; + +struct nvif_ioctl_ntfy_put_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 index; + __u8 pad02[6]; +}; + +struct nvif_ioctl_mthd_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 method; + __u8 pad02[6]; + __u8 data[]; /* method data (class.h) */ +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/list.h b/drivers/gpu/drm/nouveau/nvif/list.h new file mode 100644 index 000000000000..8af5d144ecb0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/list.h @@ -0,0 +1,353 @@ +/* + * Copyright © 2010 Intel Corporation + * Copyright © 2010 Francisco Jerez <currojerez@riseup.net> + * + * 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 (including the next + * paragraph) 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. + * + */ + +/* Modified by Ben Skeggs <bskeggs@redhat.com> to match kernel list APIs */ + +#ifndef _XORG_LIST_H_ +#define _XORG_LIST_H_ + +/** + * @file Classic doubly-link circular list implementation. + * For real usage examples of the linked list, see the file test/list.c + * + * Example: + * We need to keep a list of struct foo in the parent struct bar, i.e. what + * we want is something like this. + * + * struct bar { + * ... + * struct foo *list_of_foos; -----> struct foo {}, struct foo {}, struct foo{} + * ... + * } + * + * We need one list head in bar and a list element in all list_of_foos (both are of + * data type 'struct list_head'). + * + * struct bar { + * ... + * struct list_head list_of_foos; + * ... + * } + * + * struct foo { + * ... + * struct list_head entry; + * ... + * } + * + * Now we initialize the list head: + * + * struct bar bar; + * ... + * INIT_LIST_HEAD(&bar.list_of_foos); + * + * Then we create the first element and add it to this list: + * + * struct foo *foo = malloc(...); + * .... + * list_add(&foo->entry, &bar.list_of_foos); + * + * Repeat the above for each element you want to add to the list. Deleting + * works with the element itself. + * list_del(&foo->entry); + * free(foo); + * + * Note: calling list_del(&bar.list_of_foos) will set bar.list_of_foos to an empty + * list again. + * + * Looping through the list requires a 'struct foo' as iterator and the + * name of the field the subnodes use. + * + * struct foo *iterator; + * list_for_each_entry(iterator, &bar.list_of_foos, entry) { + * if (iterator->something == ...) + * ... + * } + * + * Note: You must not call list_del() on the iterator if you continue the + * loop. You need to run the safe for-each loop instead: + * + * struct foo *iterator, *next; + * list_for_each_entry_safe(iterator, next, &bar.list_of_foos, entry) { + * if (...) + * list_del(&iterator->entry); + * } + * + */ + +/** + * The linkage struct for list nodes. This struct must be part of your + * to-be-linked struct. struct list_head is required for both the head of the + * list and for each list node. + * + * Position and name of the struct list_head field is irrelevant. + * There are no requirements that elements of a list are of the same type. + * There are no requirements for a list head, any struct list_head can be a list + * head. + */ +struct list_head { + struct list_head *next, *prev; +}; + +/** + * Initialize the list as an empty list. + * + * Example: + * INIT_LIST_HEAD(&bar->list_of_foos); + * + * @param The list to initialized. + */ +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void +INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list->prev = list; +} + +static inline void +__list_add(struct list_head *entry, + struct list_head *prev, struct list_head *next) +{ + next->prev = entry; + entry->next = next; + entry->prev = prev; + prev->next = entry; +} + +/** + * Insert a new element after the given list head. The new element does not + * need to be initialised as empty list. + * The list changes from: + * head → some element → ... + * to + * head → new element → older element → ... + * + * Example: + * struct foo *newfoo = malloc(...); + * list_add(&newfoo->entry, &bar->list_of_foos); + * + * @param entry The new element to prepend to the list. + * @param head The existing list. + */ +static inline void +list_add(struct list_head *entry, struct list_head *head) +{ + __list_add(entry, head, head->next); +} + +/** + * Append a new element to the end of the list given with this list head. + * + * The list changes from: + * head → some element → ... → lastelement + * to + * head → some element → ... → lastelement → new element + * + * Example: + * struct foo *newfoo = malloc(...); + * list_add_tail(&newfoo->entry, &bar->list_of_foos); + * + * @param entry The new element to prepend to the list. + * @param head The existing list. + */ +static inline void +list_add_tail(struct list_head *entry, struct list_head *head) +{ + __list_add(entry, head->prev, head); +} + +static inline void +__list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * Remove the element from the list it is in. Using this function will reset + * the pointers to/from this element so it is removed from the list. It does + * NOT free the element itself or manipulate it otherwise. + * + * Using list_del on a pure list head (like in the example at the top of + * this file) will NOT remove the first element from + * the list but rather reset the list as empty list. + * + * Example: + * list_del(&foo->entry); + * + * @param entry The element to remove. + */ +static inline void +list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void +list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * Check if the list is empty. + * + * Example: + * list_empty(&bar->list_of_foos); + * + * @return True if the list contains one or more elements or False otherwise. + */ +static inline bool +list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * Returns a pointer to the container of this list element. + * + * Example: + * struct foo* f; + * f = container_of(&foo->entry, struct foo, entry); + * assert(f == foo); + * + * @param ptr Pointer to the struct list_head. + * @param type Data type of the list element. + * @param member Member name of the struct list_head field in the list element. + * @return A pointer to the data struct containing the list head. + */ +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char *)(ptr) - (char *) &((type *)0)->member) +#endif + +/** + * Alias of container_of + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * Retrieve the first list entry for the given list pointer. + * + * Example: + * struct foo *first; + * first = list_first_entry(&bar->list_of_foos, struct foo, list_of_foos); + * + * @param ptr The list head + * @param type Data type of the list element to retrieve + * @param member Member name of the struct list_head field in the list element. + * @return A pointer to the first list element. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * Retrieve the last list entry for the given listpointer. + * + * Example: + * struct foo *first; + * first = list_last_entry(&bar->list_of_foos, struct foo, list_of_foos); + * + * @param ptr The list head + * @param type Data type of the list element to retrieve + * @param member Member name of the struct list_head field in the list element. + * @return A pointer to the last list element. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +#define __container_of(ptr, sample, member) \ + (void *)container_of((ptr), typeof(*(sample)), member) + +/** + * Loop through the list given by head and set pos to struct in the list. + * + * Example: + * struct foo *iterator; + * list_for_each_entry(iterator, &bar->list_of_foos, entry) { + * [modify iterator] + * } + * + * This macro is not safe for node deletion. Use list_for_each_entry_safe + * instead. + * + * @param pos Iterator variable of the type of the list elements. + * @param head List head + * @param member Member name of the struct list_head in the list elements. + * + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = __container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = __container_of(pos->member.next, pos, member)) + +/** + * Loop through the list, keeping a backup pointer to the element. This + * macro allows for the deletion of a list element while looping through the + * list. + * + * See list_for_each_entry for more details. + */ +#define list_for_each_entry_safe(pos, tmp, head, member) \ + for (pos = __container_of((head)->next, pos, member), \ + tmp = __container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = tmp, tmp = __container_of(pos->member.next, tmp, member)) + + +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = __container_of((head)->prev, pos, member); \ + &pos->member != (head); \ + pos = __container_of(pos->member.prev, pos, member)) + +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = __container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = __container_of(pos->member.next, pos, member)) + +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = __container_of(pos->member.prev, pos, member); \ + &pos->member != (head); \ + pos = __container_of(pos->member.prev, pos, member)) + +#define list_for_each_entry_from(pos, head, member) \ + for (; \ + &pos->member != (head); \ + pos = __container_of(pos->member.next, pos, member)) + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c new file mode 100644 index 000000000000..0898c3155292 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/notify.c @@ -0,0 +1,248 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +#include <nvif/client.h> +#include <nvif/driver.h> +#include <nvif/notify.h> +#include <nvif/object.h> +#include <nvif/ioctl.h> +#include <nvif/event.h> + +static inline int +nvif_notify_put_(struct nvif_notify *notify) +{ + struct nvif_object *object = notify->object; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_put_v0 ntfy; + } args = { + .ioctl.type = NVIF_IOCTL_V0_NTFY_PUT, + .ntfy.index = notify->index, + }; + + if (atomic_inc_return(¬ify->putcnt) != 1) + return 0; + + return nvif_object_ioctl(object, &args, sizeof(args), NULL); +} + +int +nvif_notify_put(struct nvif_notify *notify) +{ + if (likely(notify->object) && + test_and_clear_bit(NVIF_NOTIFY_USER, ¬ify->flags)) { + int ret = nvif_notify_put_(notify); + if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) + flush_work(¬ify->work); + return ret; + } + return 0; +} + +static inline int +nvif_notify_get_(struct nvif_notify *notify) +{ + struct nvif_object *object = notify->object; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_get_v0 ntfy; + } args = { + .ioctl.type = NVIF_IOCTL_V0_NTFY_GET, + .ntfy.index = notify->index, + }; + + if (atomic_dec_return(¬ify->putcnt) != 0) + return 0; + + return nvif_object_ioctl(object, &args, sizeof(args), NULL); +} + +int +nvif_notify_get(struct nvif_notify *notify) +{ + if (likely(notify->object) && + !test_and_set_bit(NVIF_NOTIFY_USER, ¬ify->flags)) + return nvif_notify_get_(notify); + return 0; +} + +static inline int +nvif_notify_func(struct nvif_notify *notify, bool keep) +{ + int ret = notify->func(notify); + if (ret == NVIF_NOTIFY_KEEP || + !test_and_clear_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { + if (!keep) + atomic_dec(¬ify->putcnt); + else + nvif_notify_get_(notify); + } + return ret; +} + +static void +nvif_notify_work(struct work_struct *work) +{ + struct nvif_notify *notify = container_of(work, typeof(*notify), work); + nvif_notify_func(notify, true); +} + +int +nvif_notify(const void *header, u32 length, const void *data, u32 size) +{ + struct nvif_notify *notify = NULL; + const union { + struct nvif_notify_rep_v0 v0; + } *args = header; + int ret = NVIF_NOTIFY_DROP; + + if (length == sizeof(args->v0) && args->v0.version == 0) { + if (WARN_ON(args->v0.route)) + return NVIF_NOTIFY_DROP; + notify = (void *)(unsigned long)args->v0.token; + } + + if (!WARN_ON(notify == NULL)) { + struct nvif_client *client = nvif_client(notify->object); + if (!WARN_ON(notify->size != size)) { + atomic_inc(¬ify->putcnt); + if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) { + memcpy((void *)notify->data, data, size); + schedule_work(¬ify->work); + return NVIF_NOTIFY_DROP; + } + notify->data = data; + ret = nvif_notify_func(notify, client->driver->keep); + notify->data = NULL; + } + } + + return ret; +} + +int +nvif_notify_fini(struct nvif_notify *notify) +{ + struct nvif_object *object = notify->object; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_del_v0 ntfy; + } args = { + .ioctl.type = NVIF_IOCTL_V0_NTFY_DEL, + .ntfy.index = notify->index, + }; + int ret = nvif_notify_put(notify); + if (ret >= 0 && object) { + ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); + if (ret == 0) { + nvif_object_ref(NULL, ¬ify->object); + kfree((void *)notify->data); + } + } + return ret; +} + +int +nvif_notify_init(struct nvif_object *object, void (*dtor)(struct nvif_notify *), + int (*func)(struct nvif_notify *), bool work, u8 event, + void *data, u32 size, u32 reply, struct nvif_notify *notify) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_ntfy_new_v0 ntfy; + struct nvif_notify_req_v0 req; + } *args; + int ret = -ENOMEM; + + notify->object = NULL; + nvif_object_ref(object, ¬ify->object); + notify->flags = 0; + atomic_set(¬ify->putcnt, 1); + notify->dtor = dtor; + notify->func = func; + notify->data = NULL; + notify->size = reply; + if (work) { + INIT_WORK(¬ify->work, nvif_notify_work); + set_bit(NVIF_NOTIFY_WORK, ¬ify->flags); + notify->data = kmalloc(notify->size, GFP_KERNEL); + if (!notify->data) + goto done; + } + + if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) + goto done; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_NTFY_NEW; + args->ntfy.version = 0; + args->ntfy.event = event; + args->req.version = 0; + args->req.reply = notify->size; + args->req.route = 0; + args->req.token = (unsigned long)(void *)notify; + + memcpy(args->req.data, data, size); + ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); + notify->index = args->ntfy.index; + kfree(args); +done: + if (ret) + nvif_notify_fini(notify); + return ret; +} + +static void +nvif_notify_del(struct nvif_notify *notify) +{ + nvif_notify_fini(notify); + kfree(notify); +} + +void +nvif_notify_ref(struct nvif_notify *notify, struct nvif_notify **pnotify) +{ + BUG_ON(notify != NULL); + if (*pnotify) + (*pnotify)->dtor(*pnotify); + *pnotify = notify; +} + +int +nvif_notify_new(struct nvif_object *object, int (*func)(struct nvif_notify *), + bool work, u8 type, void *data, u32 size, u32 reply, + struct nvif_notify **pnotify) +{ + struct nvif_notify *notify = kzalloc(sizeof(*notify), GFP_KERNEL); + if (notify) { + int ret = nvif_notify_init(object, nvif_notify_del, func, work, + type, data, size, reply, notify); + if (ret) { + kfree(notify); + notify = NULL; + } + *pnotify = notify; + return ret; + } + return -ENOMEM; +} diff --git a/drivers/gpu/drm/nouveau/nvif/notify.h b/drivers/gpu/drm/nouveau/nvif/notify.h new file mode 100644 index 000000000000..9ebfa3b45e76 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/notify.h @@ -0,0 +1,39 @@ +#ifndef __NVIF_NOTIFY_H__ +#define __NVIF_NOTIFY_H__ + +struct nvif_notify { + struct nvif_object *object; + int index; + +#define NVIF_NOTIFY_USER 0 +#define NVIF_NOTIFY_WORK 1 + unsigned long flags; + atomic_t putcnt; + void (*dtor)(struct nvif_notify *); +#define NVIF_NOTIFY_DROP 0 +#define NVIF_NOTIFY_KEEP 1 + int (*func)(struct nvif_notify *); + + /* this is const for a *very* good reason - the data might be on the + * stack from an irq handler. if you're not nvif/notify.c then you + * should probably think twice before casting it away... + */ + const void *data; + u32 size; + struct work_struct work; +}; + +int nvif_notify_init(struct nvif_object *, void (*dtor)(struct nvif_notify *), + int (*func)(struct nvif_notify *), bool work, u8 type, + void *data, u32 size, u32 reply, struct nvif_notify *); +int nvif_notify_fini(struct nvif_notify *); +int nvif_notify_get(struct nvif_notify *); +int nvif_notify_put(struct nvif_notify *); +int nvif_notify(const void *, u32, const void *, u32); + +int nvif_notify_new(struct nvif_object *, int (*func)(struct nvif_notify *), + bool work, u8 type, void *data, u32 size, u32 reply, + struct nvif_notify **); +void nvif_notify_ref(struct nvif_notify *, struct nvif_notify **); + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c new file mode 100644 index 000000000000..dd85b56f6aa5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -0,0 +1,304 @@ +/* + * Copyright 2014 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 <bskeggs@redhat.com> + */ + +#include "object.h" +#include "client.h" +#include "driver.h" +#include "ioctl.h" + +int +nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) +{ + struct nvif_client *client = nvif_client(object); + union { + struct nvif_ioctl_v0 v0; + } *args = data; + + if (size >= sizeof(*args) && args->v0.version == 0) { + args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; + args->v0.path_nr = 0; + while (args->v0.path_nr < ARRAY_SIZE(args->v0.path)) { + args->v0.path[args->v0.path_nr++] = object->handle; + if (object->parent == object) + break; + object = object->parent; + } + } else + return -ENOSYS; + + return client->driver->ioctl(client->base.priv, client->super, data, size, hack); +} + +int +nvif_object_sclass(struct nvif_object *object, u32 *oclass, int count) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_sclass_v0 sclass; + } *args; + u32 size = count * sizeof(args->sclass.oclass[0]); + int ret; + + if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) + return -ENOMEM; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_SCLASS; + args->sclass.version = 0; + args->sclass.count = count; + + memcpy(args->sclass.oclass, oclass, size); + ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); + ret = ret ? ret : args->sclass.count; + memcpy(oclass, args->sclass.oclass, size); + kfree(args); + return ret; +} + +u32 +nvif_object_rd(struct nvif_object *object, int size, u64 addr) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_rd_v0 rd; + } args = { + .ioctl.type = NVIF_IOCTL_V0_RD, + .rd.size = size, + .rd.addr = addr, + }; + int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); + if (ret) { + /*XXX: warn? */ + return 0; + } + return args.rd.data; +} + +void +nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_wr_v0 wr; + } args = { + .ioctl.type = NVIF_IOCTL_V0_WR, + .wr.size = size, + .wr.addr = addr, + .wr.data = data, + }; + int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); + if (ret) { + /*XXX: warn? */ + } +} + +int +nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_mthd_v0 mthd; + } *args; + u8 stack[128]; + int ret; + + if (sizeof(*args) + size > sizeof(stack)) { + if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) + return -ENOMEM; + } else { + args = (void *)stack; + } + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_MTHD; + args->mthd.version = 0; + args->mthd.method = mthd; + + memcpy(args->mthd.data, data, size); + ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); + memcpy(data, args->mthd.data, size); + if (args != (void *)stack) + kfree(args); + return ret; +} + +void +nvif_object_unmap(struct nvif_object *object) +{ + if (object->map.size) { + struct nvif_client *client = nvif_client(object); + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_unmap unmap; + } args = { + .ioctl.type = NVIF_IOCTL_V0_UNMAP, + }; + + if (object->map.ptr) { + client->driver->unmap(client, object->map.ptr, + object->map.size); + object->map.ptr = NULL; + } + + nvif_object_ioctl(object, &args, sizeof(args), NULL); + object->map.size = 0; + } +} + +int +nvif_object_map(struct nvif_object *object) +{ + struct nvif_client *client = nvif_client(object); + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_map_v0 map; + } args = { + .ioctl.type = NVIF_IOCTL_V0_MAP, + }; + int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); + if (ret == 0) { + object->map.size = args.map.length; + object->map.ptr = client->driver->map(client, args.map.handle, + object->map.size); + if (ret = -ENOMEM, object->map.ptr) + return 0; + nvif_object_unmap(object); + } + return ret; +} + +struct ctor { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_new_v0 new; +}; + +void +nvif_object_fini(struct nvif_object *object) +{ + struct ctor *ctor = container_of(object->data, typeof(*ctor), new.data); + if (object->parent) { + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_del del; + } args = { + .ioctl.type = NVIF_IOCTL_V0_DEL, + }; + + nvif_object_unmap(object); + nvif_object_ioctl(object, &args, sizeof(args), NULL); + if (object->data) { + object->size = 0; + object->data = NULL; + kfree(ctor); + } + nvif_object_ref(NULL, &object->parent); + } +} + +int +nvif_object_init(struct nvif_object *parent, void (*dtor)(struct nvif_object *), + u32 handle, u32 oclass, void *data, u32 size, + struct nvif_object *object) +{ + struct ctor *ctor; + int ret = 0; + + object->parent = NULL; + object->object = object; + nvif_object_ref(parent, &object->parent); + kref_init(&object->refcount); + object->handle = handle; + object->oclass = oclass; + object->data = NULL; + object->size = 0; + object->dtor = dtor; + object->map.ptr = NULL; + object->map.size = 0; + + if (object->parent) { + if (!(ctor = kmalloc(sizeof(*ctor) + size, GFP_KERNEL))) { + nvif_object_fini(object); + return -ENOMEM; + } + object->data = ctor->new.data; + object->size = size; + memcpy(object->data, data, size); + + ctor->ioctl.version = 0; + ctor->ioctl.type = NVIF_IOCTL_V0_NEW; + ctor->new.version = 0; + ctor->new.route = NVIF_IOCTL_V0_ROUTE_NVIF; + ctor->new.token = (unsigned long)(void *)object; + ctor->new.handle = handle; + ctor->new.oclass = oclass; + + ret = nvif_object_ioctl(parent, ctor, sizeof(*ctor) + + object->size, &object->priv); + } + + if (ret) + nvif_object_fini(object); + return ret; +} + +static void +nvif_object_del(struct nvif_object *object) +{ + nvif_object_fini(object); + kfree(object); +} + +int +nvif_object_new(struct nvif_object *parent, u32 handle, u32 oclass, + void *data, u32 size, struct nvif_object **pobject) +{ + struct nvif_object *object = kzalloc(sizeof(*object), GFP_KERNEL); + if (object) { + int ret = nvif_object_init(parent, nvif_object_del, handle, + oclass, data, size, object); + if (ret) { + kfree(object); + object = NULL; + } + *pobject = object; + return ret; + } + return -ENOMEM; +} + +static void +nvif_object_put(struct kref *kref) +{ + struct nvif_object *object = + container_of(kref, typeof(*object), refcount); + object->dtor(object); +} + +void +nvif_object_ref(struct nvif_object *object, struct nvif_object **pobject) +{ + if (object) + kref_get(&object->refcount); + if (*pobject) + kref_put(&(*pobject)->refcount, nvif_object_put); + *pobject = object; +} diff --git a/drivers/gpu/drm/nouveau/nvif/object.h b/drivers/gpu/drm/nouveau/nvif/object.h new file mode 100644 index 000000000000..fe519179b76c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/object.h @@ -0,0 +1,75 @@ +#ifndef __NVIF_OBJECT_H__ +#define __NVIF_OBJECT_H__ + +#include <nvif/os.h> + +struct nvif_object { + struct nvif_object *parent; + struct nvif_object *object; /*XXX: hack for nvif_object() */ + struct kref refcount; + u32 handle; + u32 oclass; + void *data; + u32 size; + void *priv; /*XXX: hack */ + void (*dtor)(struct nvif_object *); + struct { + void __iomem *ptr; + u32 size; + } map; +}; + +int nvif_object_init(struct nvif_object *, void (*dtor)(struct nvif_object *), + u32 handle, u32 oclass, void *, u32, + struct nvif_object *); +void nvif_object_fini(struct nvif_object *); +int nvif_object_new(struct nvif_object *, u32 handle, u32 oclass, + void *, u32, struct nvif_object **); +void nvif_object_ref(struct nvif_object *, struct nvif_object **); +int nvif_object_ioctl(struct nvif_object *, void *, u32, void **); +int nvif_object_sclass(struct nvif_object *, u32 *, int); +u32 nvif_object_rd(struct nvif_object *, int, u64); +void nvif_object_wr(struct nvif_object *, int, u64, u32); +int nvif_object_mthd(struct nvif_object *, u32, void *, u32); +int nvif_object_map(struct nvif_object *); +void nvif_object_unmap(struct nvif_object *); + +#define nvif_object(a) (a)->object + +#define ioread8_native ioread8 +#define iowrite8_native iowrite8 +#define nvif_rd(a,b,c) ({ \ + struct nvif_object *_object = nvif_object(a); \ + u32 _data; \ + if (likely(_object->map.ptr)) \ + _data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c)); \ + else \ + _data = nvif_object_rd(_object, (b) / 8, (c)); \ + _data; \ +}) +#define nvif_wr(a,b,c,d) ({ \ + struct nvif_object *_object = nvif_object(a); \ + if (likely(_object->map.ptr)) \ + iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c)); \ + else \ + nvif_object_wr(_object, (b) / 8, (c), (d)); \ +}) +#define nvif_rd08(a,b) ({ u8 _v = nvif_rd((a), 8, (b)); _v; }) +#define nvif_rd16(a,b) ({ u16 _v = nvif_rd((a), 16, (b)); _v; }) +#define nvif_rd32(a,b) ({ u32 _v = nvif_rd((a), 32, (b)); _v; }) +#define nvif_wr08(a,b,c) nvif_wr((a), 8, (b), (u8)(c)) +#define nvif_wr16(a,b,c) nvif_wr((a), 16, (b), (u16)(c)) +#define nvif_wr32(a,b,c) nvif_wr((a), 32, (b), (u32)(c)) +#define nvif_mask(a,b,c,d) ({ \ + u32 _v = nvif_rd32(nvif_object(a), (b)); \ + nvif_wr32(nvif_object(a), (b), (_v & ~(c)) | (d)); \ + _v; \ +}) + +#define nvif_mthd(a,b,c,d) nvif_object_mthd(nvif_object(a), (b), (c), (d)) + +/*XXX*/ +#include <core/object.h> +#define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv) + +#endif diff --git a/drivers/gpu/drm/nouveau/nvif/os.h b/drivers/gpu/drm/nouveau/nvif/os.h new file mode 120000 index 000000000000..bd744b2cf5cf --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/os.h @@ -0,0 +1 @@ +../core/os.h
\ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/nvif/unpack.h b/drivers/gpu/drm/nouveau/nvif/unpack.h new file mode 100644 index 000000000000..5933188b4a77 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/unpack.h @@ -0,0 +1,24 @@ +#ifndef __NVIF_UNPACK_H__ +#define __NVIF_UNPACK_H__ + +#define nvif_unvers(d) ({ \ + ret = (size == sizeof(d)) ? 0 : -ENOSYS; \ + (ret == 0); \ +}) + +#define nvif_unpack(d,vl,vh,m) ({ \ + if ((vl) == 0 || ret == -ENOSYS) { \ + int _size = sizeof(d); \ + if (_size <= size && (d).version >= (vl) && \ + (d).version <= (vh)) { \ + data = (u8 *)data + _size; \ + size = size - _size; \ + ret = ((m) || !size) ? 0 : -E2BIG; \ + } else { \ + ret = -ENOSYS; \ + } \ + } \ + (ret == 0); \ +}) + +#endif |