diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau')
430 files changed, 44089 insertions, 15768 deletions
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index ff80f12480e..637c29a3312 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -3,6 +3,7 @@ config DRM_NOUVEAU depends on DRM && PCI select FW_LOADER select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER select DRM_TTM select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -10,7 +11,7 @@ config DRM_NOUVEAU select FB select FRAMEBUFFER_CONSOLE if !EXPERT select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT - select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT + select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && INPUT select X86_PLATFORM_DEVICES if ACPI && X86 select ACPI_WMI if ACPI && X86 select MXM_WMI if ACPI && X86 @@ -18,7 +19,6 @@ config DRM_NOUVEAU # Similar to i915, we need to select ACPI_VIDEO and it's dependencies select BACKLIGHT_LCD_SUPPORT if ACPI && X86 select BACKLIGHT_CLASS_DEVICE if ACPI && X86 - select VIDEO_OUTPUT_CONTROL if ACPI && X86 select INPUT if ACPI && X86 select THERMAL if ACPI && X86 select ACPI_VIDEO if ACPI && X86 diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index d939a1da320..8b307e14363 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -28,7 +28,9 @@ nouveau-y += core/subdev/bar/nv50.o nouveau-y += core/subdev/bar/nvc0.o nouveau-y += core/subdev/bios/base.o nouveau-y += core/subdev/bios/bit.o +nouveau-y += core/subdev/bios/boost.o nouveau-y += core/subdev/bios/conn.o +nouveau-y += core/subdev/bios/cstep.o nouveau-y += core/subdev/bios/dcb.o nouveau-y += core/subdev/bios/disp.o nouveau-y += core/subdev/bios/dp.o @@ -39,17 +41,29 @@ nouveau-y += core/subdev/bios/init.o nouveau-y += core/subdev/bios/mxm.o nouveau-y += core/subdev/bios/perf.o nouveau-y += core/subdev/bios/pll.o +nouveau-y += core/subdev/bios/ramcfg.o +nouveau-y += core/subdev/bios/rammap.o +nouveau-y += core/subdev/bios/timing.o 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/P0260.o +nouveau-y += core/subdev/bus/hwsq.o nouveau-y += core/subdev/bus/nv04.o nouveau-y += core/subdev/bus/nv31.o nouveau-y += core/subdev/bus/nv50.o +nouveau-y += core/subdev/bus/nv94.o nouveau-y += core/subdev/bus/nvc0.o +nouveau-y += core/subdev/clock/base.o nouveau-y += core/subdev/clock/nv04.o nouveau-y += core/subdev/clock/nv40.o nouveau-y += core/subdev/clock/nv50.o +nouveau-y += core/subdev/clock/nv84.o 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/pllnv04.o nouveau-y += core/subdev/clock/pllnva3.o nouveau-y += core/subdev/devinit/base.o @@ -59,8 +73,12 @@ nouveau-y += core/subdev/devinit/nv10.o nouveau-y += core/subdev/devinit/nv1a.o nouveau-y += core/subdev/devinit/nv20.o nouveau-y += core/subdev/devinit/nv50.o +nouveau-y += core/subdev/devinit/nv84.o +nouveau-y += core/subdev/devinit/nv98.o nouveau-y += core/subdev/devinit/nva3.o +nouveau-y += core/subdev/devinit/nvaf.o nouveau-y += core/subdev/devinit/nvc0.o +nouveau-y += core/subdev/devinit/gm107.o nouveau-y += core/subdev/fb/base.o nouveau-y += core/subdev/fb/nv04.o nouveau-y += core/subdev/fb/nv10.o @@ -78,7 +96,14 @@ nouveau-y += core/subdev/fb/nv47.o nouveau-y += core/subdev/fb/nv49.o nouveau-y += core/subdev/fb/nv4e.o nouveau-y += core/subdev/fb/nv50.o +nouveau-y += core/subdev/fb/nv84.o +nouveau-y += core/subdev/fb/nva3.o +nouveau-y += core/subdev/fb/nvaa.o +nouveau-y += core/subdev/fb/nvaf.o nouveau-y += core/subdev/fb/nvc0.o +nouveau-y += core/subdev/fb/nve0.o +nouveau-y += core/subdev/fb/gk20a.o +nouveau-y += core/subdev/fb/gm107.o nouveau-y += core/subdev/fb/ramnv04.o nouveau-y += core/subdev/fb/ramnv10.o nouveau-y += core/subdev/fb/ramnv1a.o @@ -89,37 +114,62 @@ nouveau-y += core/subdev/fb/ramnv44.o nouveau-y += core/subdev/fb/ramnv49.o nouveau-y += core/subdev/fb/ramnv4e.o nouveau-y += core/subdev/fb/ramnv50.o +nouveau-y += core/subdev/fb/ramnva3.o +nouveau-y += core/subdev/fb/ramnvaa.o 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/sddr3.o +nouveau-y += core/subdev/fb/gddr5.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/nvd0.o nouveau-y += core/subdev/gpio/nve0.o nouveau-y += core/subdev/i2c/base.o nouveau-y += core/subdev/i2c/anx9805.o nouveau-y += core/subdev/i2c/aux.o nouveau-y += core/subdev/i2c/bit.o +nouveau-y += core/subdev/i2c/pad.o +nouveau-y += core/subdev/i2c/padnv04.o +nouveau-y += core/subdev/i2c/padnv94.o nouveau-y += core/subdev/i2c/nv04.o nouveau-y += core/subdev/i2c/nv4e.o nouveau-y += core/subdev/i2c/nv50.o nouveau-y += core/subdev/i2c/nv94.o nouveau-y += core/subdev/i2c/nvd0.o +nouveau-y += core/subdev/i2c/gf117.o +nouveau-y += core/subdev/i2c/nve0.o nouveau-y += core/subdev/ibus/nvc0.o nouveau-y += core/subdev/ibus/nve0.o +nouveau-y += core/subdev/ibus/gk20a.o 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/nvc0.o +nouveau-y += core/subdev/ltcg/gf100.o +nouveau-y += core/subdev/ltcg/gm107.o nouveau-y += core/subdev/mc/base.o nouveau-y += core/subdev/mc/nv04.o +nouveau-y += core/subdev/mc/nv40.o nouveau-y += core/subdev/mc/nv44.o +nouveau-y += core/subdev/mc/nv4c.o nouveau-y += core/subdev/mc/nv50.o +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/mxm/base.o nouveau-y += core/subdev/mxm/mxms.o nouveau-y += core/subdev/mxm/nv50.o +nouveau-y += core/subdev/pwr/base.o +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/nv108.o nouveau-y += core/subdev/therm/base.o nouveau-y += core/subdev/therm/fan.o nouveau-y += core/subdev/therm/fannil.o @@ -134,12 +184,16 @@ nouveau-y += core/subdev/therm/nva3.o nouveau-y += core/subdev/therm/nvd0.o nouveau-y += core/subdev/timer/base.o nouveau-y += core/subdev/timer/nv04.o +nouveau-y += core/subdev/timer/gk20a.o nouveau-y += core/subdev/vm/base.o nouveau-y += core/subdev/vm/nv04.o nouveau-y += core/subdev/vm/nv41.o nouveau-y += core/subdev/vm/nv44.o nouveau-y += core/subdev/vm/nv50.o nouveau-y += core/subdev/vm/nvc0.o +nouveau-y += core/subdev/volt/base.o +nouveau-y += core/subdev/volt/gpio.o +nouveau-y += core/subdev/volt/nv40.o nouveau-y += core/engine/falcon.o nouveau-y += core/engine/xtensa.o @@ -158,6 +212,7 @@ 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/base.o +nouveau-y += core/engine/device/ctrl.o nouveau-y += core/engine/device/nv04.o nouveau-y += core/engine/device/nv10.o nouveau-y += core/engine/device/nv20.o @@ -166,7 +221,11 @@ nouveau-y += core/engine/device/nv40.o nouveau-y += core/engine/device/nv50.o nouveau-y += core/engine/device/nvc0.o nouveau-y += core/engine/device/nve0.o +nouveau-y += core/engine/device/gm100.o nouveau-y += core/engine/disp/base.o +nouveau-y += core/engine/disp/conn.o +nouveau-y += core/engine/disp/outp.o +nouveau-y += core/engine/disp/outpdp.o nouveau-y += core/engine/disp/nv04.o nouveau-y += core/engine/disp/nv50.o nouveau-y += core/engine/disp/nv84.o @@ -176,6 +235,7 @@ nouveau-y += core/engine/disp/nva3.o nouveau-y += core/engine/disp/nvd0.o nouveau-y += core/engine/disp/nve0.o nouveau-y += core/engine/disp/nvf0.o +nouveau-y += core/engine/disp/gm107.o nouveau-y += core/engine/disp/dacnv50.o nouveau-y += core/engine/disp/dport.o nouveau-y += core/engine/disp/hdanva3.o @@ -197,16 +257,21 @@ nouveau-y += core/engine/fifo/nv50.o nouveau-y += core/engine/fifo/nv84.o nouveau-y += core/engine/fifo/nvc0.o nouveau-y += core/engine/fifo/nve0.o +nouveau-y += core/engine/fifo/gk20a.o +nouveau-y += core/engine/fifo/nv108.o nouveau-y += core/engine/graph/ctxnv40.o nouveau-y += core/engine/graph/ctxnv50.o nouveau-y += core/engine/graph/ctxnvc0.o nouveau-y += core/engine/graph/ctxnvc1.o -nouveau-y += core/engine/graph/ctxnvc3.o +nouveau-y += core/engine/graph/ctxnvc4.o nouveau-y += core/engine/graph/ctxnvc8.o nouveau-y += core/engine/graph/ctxnvd7.o 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/ctxnv108.o +nouveau-y += core/engine/graph/ctxgm107.o nouveau-y += core/engine/graph/nv04.o nouveau-y += core/engine/graph/nv10.o nouveau-y += core/engine/graph/nv20.o @@ -219,16 +284,29 @@ nouveau-y += core/engine/graph/nv40.o nouveau-y += core/engine/graph/nv50.o nouveau-y += core/engine/graph/nvc0.o nouveau-y += core/engine/graph/nvc1.o -nouveau-y += core/engine/graph/nvc3.o +nouveau-y += core/engine/graph/nvc4.o nouveau-y += core/engine/graph/nvc8.o nouveau-y += core/engine/graph/nvd7.o 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/nv108.o +nouveau-y += core/engine/graph/gm107.o nouveau-y += core/engine/mpeg/nv31.o nouveau-y += core/engine/mpeg/nv40.o +nouveau-y += core/engine/mpeg/nv44.o nouveau-y += core/engine/mpeg/nv50.o nouveau-y += core/engine/mpeg/nv84.o +nouveau-y += core/engine/perfmon/base.o +nouveau-y += core/engine/perfmon/daemon.o +nouveau-y += core/engine/perfmon/nv40.o +nouveau-y += core/engine/perfmon/nv50.o +nouveau-y += core/engine/perfmon/nv84.o +nouveau-y += core/engine/perfmon/nva3.o +nouveau-y += core/engine/perfmon/nvc0.o +nouveau-y += core/engine/perfmon/nve0.o +nouveau-y += core/engine/perfmon/nvf0.o nouveau-y += core/engine/ppp/nv98.o nouveau-y += core/engine/ppp/nvc0.o nouveau-y += core/engine/software/nv04.o @@ -260,9 +338,7 @@ include $(src)/dispnv04/Makefile nouveau-y += nv50_display.o # drm/pm -nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o -nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o -nouveau-y += nouveau_mem.o +nouveau-y += nouveau_hwmon.o nouveau_sysfs.o # other random bits nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/core/core/engine.c b/drivers/gpu/drm/nouveau/core/core/engine.c index c8bed4a2683..1f6954ae9dd 100644 --- a/drivers/gpu/drm/nouveau/core/core/engine.c +++ b/drivers/gpu/drm/nouveau/core/core/engine.c @@ -42,11 +42,24 @@ nouveau_engine_create_(struct nouveau_object *parent, if (ret) return ret; - if ( parent && - !nouveau_boolopt(nv_device(parent)->cfgopt, iname, enable)) { - if (!enable) - nv_warn(engine, "disabled, %s=1 to enable\n", iname); - return -ENODEV; + if (parent) { + struct nouveau_device *device = nv_device(parent); + int engidx = nv_engidx(nv_object(engine)); + + if (device->disable_mask & (1ULL << engidx)) { + if (!nouveau_boolopt(device->cfgopt, iname, false)) { + nv_debug(engine, "engine disabled by hw/fw\n"); + return -ENODEV; + } + + nv_warn(engine, "ignoring hw/fw engine disable\n"); + } + + if (!nouveau_boolopt(device->cfgopt, iname, enable)) { + if (!enable) + nv_warn(engine, "disabled, %s=1 to enable\n", iname); + return -ENODEV; + } } INIT_LIST_HEAD(&engine->contexts); diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c index 7eb81c1b6fa..ae81d3b5d8b 100644 --- a/drivers/gpu/drm/nouveau/core/core/event.c +++ b/drivers/gpu/drm/nouveau/core/core/event.c @@ -23,62 +23,140 @@ #include <core/os.h> #include <core/event.h> -static void -nouveau_event_put_locked(struct nouveau_event *event, int index, - struct nouveau_eventh *handler) +void +nouveau_event_put(struct nouveau_eventh *handler) { - if (!--event->index[index].refs) { - if (event->disable) - event->disable(event, 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); + } + } - list_del(&handler->head); + spin_unlock_irqrestore(&event->refs_lock, flags); } void -nouveau_event_put(struct nouveau_event *event, int index, - struct nouveau_eventh *handler) +nouveau_event_get(struct nouveau_eventh *handler) { + 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); + } - spin_lock_irqsave(&event->lock, flags); - if (index < event->index_nr) - nouveau_event_put_locked(event, index, handler); - spin_unlock_irqrestore(&event->lock, flags); + } + spin_unlock_irqrestore(&event->refs_lock, flags); } -void -nouveau_event_get(struct nouveau_event *event, int index, - struct nouveau_eventh *handler) +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; - spin_lock_irqsave(&event->lock, flags); - if (index < event->index_nr) { - list_add(&handler->head, &event->index[index].list); - if (!event->index[index].refs++) { - if (event->enable) - event->enable(event, index); - } + 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; } - spin_unlock_irqrestore(&event->lock, flags); + + 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_trigger(struct nouveau_event *event, int index) +nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref) { - struct nouveau_eventh *handler, *temp; + 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) +{ + struct nouveau_eventh *handler; unsigned long flags; - if (index >= event->index_nr) + if (WARN_ON(index >= event->index_nr)) return; - spin_lock_irqsave(&event->lock, flags); - list_for_each_entry_safe(handler, temp, &event->index[index].list, head) { - if (handler->func(handler, index) == NVKM_EVENT_DROP) { - nouveau_event_put_locked(event, index, handler); - } + 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); } - spin_unlock_irqrestore(&event->lock, flags); + spin_unlock_irqrestore(&event->list_lock, flags); } void @@ -92,19 +170,27 @@ nouveau_event_destroy(struct nouveau_event **pevent) } int -nouveau_event_create(int index_nr, struct nouveau_event **pevent) +nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **pevent) { struct nouveau_event *event; int i; - event = *pevent = kzalloc(sizeof(*event) + index_nr * - sizeof(event->index[0]), GFP_KERNEL); + event = *pevent = kzalloc(sizeof(*event) + (index_nr * types_nr) * + sizeof(event->refs[0]), GFP_KERNEL); if (!event) return -ENOMEM; - spin_lock_init(&event->lock); + event->list = kmalloc(sizeof(*event->list) * index_nr, GFP_KERNEL); + if (!event->list) { + kfree(event); + 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->index[i].list); + INIT_LIST_HEAD(&event->list[i]); + event->types_nr = types_nr; event->index_nr = index_nr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/core/namedb.c b/drivers/gpu/drm/nouveau/core/core/namedb.c index 1ce95a8709d..0594a599f6f 100644 --- a/drivers/gpu/drm/nouveau/core/core/namedb.c +++ b/drivers/gpu/drm/nouveau/core/core/namedb.c @@ -167,7 +167,7 @@ int nouveau_namedb_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, u32 pclass, - struct nouveau_oclass *sclass, u32 engcls, + struct nouveau_oclass *sclass, u64 engcls, int length, void **pobject) { struct nouveau_namedb *namedb; diff --git a/drivers/gpu/drm/nouveau/core/core/object.c b/drivers/gpu/drm/nouveau/core/core/object.c index 7f48e288215..12453855590 100644 --- a/drivers/gpu/drm/nouveau/core/core/object.c +++ b/drivers/gpu/drm/nouveau/core/core/object.c @@ -156,7 +156,7 @@ nouveau_object_ctor(struct nouveau_object *parent, } if (ret == 0) { - nv_debug(object, "created\n"); + nv_trace(object, "created\n"); atomic_set(&object->refcount, 1); } @@ -166,7 +166,7 @@ nouveau_object_ctor(struct nouveau_object *parent, static void nouveau_object_dtor(struct nouveau_object *object) { - nv_debug(object, "destroying\n"); + nv_trace(object, "destroying\n"); nv_ofuncs(object)->dtor(object); } @@ -337,7 +337,7 @@ nouveau_object_inc(struct nouveau_object *object) goto fail_self; } - nv_debug(object, "initialised\n"); + nv_trace(object, "initialised\n"); return 0; fail_self: @@ -375,7 +375,7 @@ nouveau_object_decf(struct nouveau_object *object) if (object->parent) nouveau_object_dec(object->parent, false); - nv_debug(object, "stopped\n"); + nv_trace(object, "stopped\n"); return 0; } @@ -411,7 +411,7 @@ nouveau_object_decs(struct nouveau_object *object) } } - nv_debug(object, "suspended\n"); + nv_trace(object, "suspended\n"); return 0; fail_parent: diff --git a/drivers/gpu/drm/nouveau/core/core/option.c b/drivers/gpu/drm/nouveau/core/core/option.c index 62a432ea39e..9f6fcc5f66c 100644 --- a/drivers/gpu/drm/nouveau/core/core/option.c +++ b/drivers/gpu/drm/nouveau/core/core/option.c @@ -25,15 +25,6 @@ #include <core/option.h> #include <core/debug.h> -/* compares unterminated string 'str' with zero-terminated string 'cmp' */ -static inline int -strncasecmpz(const char *str, const char *cmp, size_t len) -{ - if (strlen(cmp) != len) - return len; - return strncasecmp(str, cmp, len); -} - const char * nouveau_stropt(const char *optstr, const char *opt, int *arglen) { @@ -105,7 +96,7 @@ nouveau_dbgopt(const char *optstr, const char *sub) else if (!strncasecmpz(optstr, "warn", len)) level = NV_DBG_WARN; else if (!strncasecmpz(optstr, "info", len)) - level = NV_DBG_INFO; + level = NV_DBG_INFO_NORMAL; else if (!strncasecmpz(optstr, "debug", len)) level = NV_DBG_DEBUG; else if (!strncasecmpz(optstr, "trace", len)) diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c index 313380ce632..dee5d1235e9 100644 --- a/drivers/gpu/drm/nouveau/core/core/parent.c +++ b/drivers/gpu/drm/nouveau/core/core/parent.c @@ -49,7 +49,7 @@ nouveau_parent_sclass(struct nouveau_object *parent, u16 handle, mask = nv_parent(parent)->engine; while (mask) { - int i = ffsll(mask) - 1; + int i = __ffs64(mask); if (nv_iclass(parent, NV_CLIENT_CLASS)) engine = nv_engine(nv_client(parent)->device); diff --git a/drivers/gpu/drm/nouveau/core/core/printk.c b/drivers/gpu/drm/nouveau/core/core/printk.c index 52fb2aa129e..03e0060b13d 100644 --- a/drivers/gpu/drm/nouveau/core/core/printk.c +++ b/drivers/gpu/drm/nouveau/core/core/printk.c @@ -27,16 +27,38 @@ #include <core/subdev.h> #include <core/printk.h> -int nv_printk_suspend_level = NV_DBG_DEBUG; +int nv_info_debug_level = NV_DBG_INFO_NORMAL; void -nv_printk_(struct nouveau_object *object, const char *pfx, int level, - const char *fmt, ...) +nv_printk_(struct nouveau_object *object, int level, const char *fmt, ...) { static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' }; + const char *pfx; char mfmt[256]; va_list args; + switch (level) { + case NV_DBG_FATAL: + pfx = KERN_CRIT; + break; + case NV_DBG_ERROR: + pfx = KERN_ERR; + break; + case NV_DBG_WARN: + pfx = KERN_WARNING; + break; + case NV_DBG_INFO_NORMAL: + pfx = KERN_INFO; + break; + case NV_DBG_DEBUG: + case NV_DBG_PARANOIA: + case NV_DBG_TRACE: + case NV_DBG_SPAM: + default: + pfx = KERN_DEBUG; + break; + } + if (object && !nv_iclass(object, NV_CLIENT_CLASS)) { struct nouveau_object *device = object; struct nouveau_object *subdev = object; @@ -74,20 +96,3 @@ nv_printk_(struct nouveau_object *object, const char *pfx, int level, vprintk(mfmt, args); va_end(args); } - -#define CONV_LEVEL(x) case NV_DBG_##x: return NV_PRINTK_##x - -const char *nv_printk_level_to_pfx(int level) -{ - switch (level) { - CONV_LEVEL(FATAL); - CONV_LEVEL(ERROR); - CONV_LEVEL(WARN); - CONV_LEVEL(INFO); - CONV_LEVEL(DEBUG); - CONV_LEVEL(PARANOIA); - CONV_LEVEL(TRACE); - CONV_LEVEL(SPAM); - } - return NV_PRINTK_DEBUG; -} diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c index 48f06378d3f..2ea5568b6cf 100644 --- a/drivers/gpu/drm/nouveau/core/core/subdev.c +++ b/drivers/gpu/drm/nouveau/core/core/subdev.c @@ -104,11 +104,8 @@ nouveau_subdev_create_(struct nouveau_object *parent, if (parent) { struct nouveau_device *device = nv_device(parent); - int subidx = nv_hclass(subdev) & 0xff; - subdev->debug = nouveau_dbgopt(device->dbgopt, subname); subdev->mmio = nv_subdev(device)->mmio; - device->subdev[subidx] = *pobject; } return 0; diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c index 993df09ad64..ac3291f781f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c @@ -105,9 +105,6 @@ nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_copy_priv *priv; int ret; - if (nv_rd32(parent, 0x022500) & 0x00000100) - return -ENODEV; - ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, true, "PCE0", "copy0", &priv); *pobject = nv_object(priv); @@ -133,9 +130,6 @@ nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_copy_priv *priv; int ret; - if (nv_rd32(parent, 0x022500) & 0x00000200) - return -ENODEV; - ret = nouveau_falcon_create(parent, engine, oclass, 0x105000, true, "PCE1", "copy1", &priv); *pobject = nv_object(priv); diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c index 30f1ef1edcc..748a61eb3c6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c @@ -88,9 +88,6 @@ nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nve0_copy_priv *priv; int ret; - if (nv_rd32(parent, 0x022500) & 0x00000100) - return -ENODEV; - ret = nouveau_engine_create(parent, engine, oclass, true, "PCE0", "copy0", &priv); *pobject = nv_object(priv); @@ -112,9 +109,6 @@ nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nve0_copy_priv *priv; int ret; - if (nv_rd32(parent, 0x022500) & 0x00000200) - return -ENODEV; - ret = nouveau_engine_create(parent, engine, oclass, true, "PCE1", "copy1", &priv); *pobject = nv_object(priv); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c index 4c72571655a..18c8c7245b7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c @@ -29,7 +29,7 @@ #include <core/class.h> -#include <engine/device.h> +#include "priv.h" static DEFINE_MUTEX(nv_devices_mutex); static LIST_HEAD(nv_devices); @@ -75,7 +75,9 @@ static const u64 disable_map[] = { [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, @@ -87,7 +89,7 @@ static const u64 disable_map[] = { [NVDEV_ENGINE_PPP] = NV_DEVICE_DISABLE_PPP, [NVDEV_ENGINE_COPY0] = NV_DEVICE_DISABLE_COPY0, [NVDEV_ENGINE_COPY1] = NV_DEVICE_DISABLE_COPY1, - [NVDEV_ENGINE_UNK1C1] = NV_DEVICE_DISABLE_UNK1C1, + [NVDEV_ENGINE_VIC] = NV_DEVICE_DISABLE_VIC, [NVDEV_ENGINE_VENC] = NV_DEVICE_DISABLE_VENC, [NVDEV_ENGINE_DISP] = NV_DEVICE_DISABLE_DISP, [NVDEV_SUBDEV_NR] = 0, @@ -119,16 +121,18 @@ nouveau_devobj_ctor(struct nouveau_object *parent, return -ENODEV; } - ret = nouveau_parent_create(parent, nv_object(device), oclass, 0, NULL, + ret = nouveau_parent_create(parent, nv_object(device), oclass, 0, + nouveau_control_oclass, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_FIFO) | - (1ULL << NVDEV_ENGINE_DISP), &devobj); + (1ULL << NVDEV_ENGINE_DISP) | + (1ULL << NVDEV_ENGINE_PERFMON), &devobj); *pobject = nv_object(devobj); if (ret) return ret; - mmio_base = pci_resource_start(device->pdev, 0); - mmio_size = pci_resource_len(device->pdev, 0); + mmio_base = nv_device_resource_start(device, 0); + mmio_size = nv_device_resource_len(device, 0); /* translate api disable mask into internal mapping */ disable = args->debug0; @@ -158,22 +162,30 @@ nouveau_devobj_ctor(struct nouveau_object *parent, iounmap(map); /* determine chipset and derive architecture from it */ - if ((boot0 & 0x0f000000) > 0) { - device->chipset = (boot0 & 0xff00000) >> 20; - switch (device->chipset & 0xf0) { - case 0x10: device->card_type = NV_10; break; - case 0x20: device->card_type = NV_20; break; - case 0x30: device->card_type = NV_30; break; - case 0x40: - case 0x60: device->card_type = NV_40; break; - case 0x50: - case 0x80: - case 0x90: - case 0xa0: device->card_type = NV_50; break; - case 0xc0: device->card_type = NV_C0; break; - case 0xd0: device->card_type = NV_D0; break; - case 0xe0: - case 0xf0: device->card_type = NV_E0; break; + if ((boot0 & 0x1f000000) > 0) { + device->chipset = (boot0 & 0x1ff00000) >> 20; + switch (device->chipset & 0x1f0) { + case 0x010: { + if (0x461 & (1 << (device->chipset & 0xf))) + device->card_type = NV_10; + else + device->card_type = NV_11; + break; + } + case 0x020: device->card_type = NV_20; break; + case 0x030: device->card_type = NV_30; break; + case 0x040: + case 0x060: device->card_type = NV_40; break; + case 0x050: + 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 0x0e0: + case 0x0f0: + case 0x100: device->card_type = NV_E0; break; + case 0x110: device->card_type = GM100; break; default: break; } @@ -188,7 +200,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent, switch (device->card_type) { case NV_04: ret = nv04_identify(device); break; - case NV_10: ret = nv10_identify(device); break; + case NV_10: + case NV_11: ret = nv10_identify(device); break; case NV_20: ret = nv20_identify(device); break; case NV_30: ret = nv30_identify(device); break; case NV_40: ret = nv40_identify(device); break; @@ -196,6 +209,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent, case NV_C0: case NV_D0: ret = nvc0_identify(device); break; case NV_E0: ret = nve0_identify(device); break; + case GM100: ret = gm100_identify(device); break; default: ret = -EINVAL; break; @@ -212,7 +226,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent, nv_info(device, "Family : NV%02X\n", device->card_type); /* determine frequency of timing crystal */ - if ( device->chipset < 0x17 || + if ( device->card_type <= NV_10 || device->chipset < 0x17 || (device->chipset >= 0x20 && device->chipset < 0x25)) strap &= 0x00000040; else @@ -256,6 +270,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent, if (ret) return ret; + device->subdev[i] = devobj->subdev[i]; + /* note: can't init *any* subdevs until devinit has been run * due to not knowing exactly what the vbios init tables will * mess with. devinit also can't be run until all of its @@ -432,6 +448,72 @@ nouveau_device_dtor(struct nouveau_object *object) nouveau_engine_destroy(&device->base); } +resource_size_t +nv_device_resource_start(struct nouveau_device *device, unsigned int bar) +{ + if (nv_device_is_pci(device)) { + return pci_resource_start(device->pdev, bar); + } else { + struct resource *res; + res = platform_get_resource(device->platformdev, + IORESOURCE_MEM, bar); + if (!res) + return 0; + return res->start; + } +} + +resource_size_t +nv_device_resource_len(struct nouveau_device *device, unsigned int bar) +{ + if (nv_device_is_pci(device)) { + return pci_resource_len(device->pdev, bar); + } else { + struct resource *res; + res = platform_get_resource(device->platformdev, + IORESOURCE_MEM, bar); + if (!res) + return 0; + return resource_size(res); + } +} + +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) +{ + if (nv_device_is_pci(device)) { + return device->pdev->irq; + } else { + return platform_get_irq_byname(device->platformdev, + stall ? "stall" : "nonstall"); + } +} + static struct nouveau_oclass nouveau_device_oclass = { .handle = NV_ENGINE(DEVICE, 0x00), @@ -443,8 +525,8 @@ nouveau_device_oclass = { }; int -nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname, - const char *cfg, const char *dbg, +nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name, + const char *sname, const char *cfg, const char *dbg, int length, void **pobject) { struct nouveau_device *device; @@ -462,7 +544,14 @@ nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname, if (ret) goto done; - device->pdev = pdev; + switch (type) { + case NOUVEAU_BUS_PCI: + device->pdev = dev; + break; + case NOUVEAU_BUS_PLATFORM: + device->platformdev = dev; + break; + } device->handle = name; device->cfgopt = cfg; device->dbgopt = dbg; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c new file mode 100644 index 00000000000..4b69bf56ed0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c @@ -0,0 +1,144 @@ +/* + * 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 <core/object.h> +#include <core/class.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) +{ + struct nouveau_clock *clk = nouveau_clock(object); + struct nv_control_pstate_info *args = data; + + if (size < sizeof(*args)) + return -EINVAL; + + if (clk) { + args->count = clk->state_nr; + args->ustate = clk->ustate; + args->pstate = clk->pstate; + } else { + args->count = 0; + args->ustate = NV_CONTROL_PSTATE_INFO_USTATE_DISABLE; + args->pstate = NV_CONTROL_PSTATE_INFO_PSTATE_UNKNOWN; + } + + return 0; +} + +static int +nouveau_control_mthd_pstate_attr(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + 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; + domain = clk->domains; + + while (domain->name != nv_clk_src_max) { + if (domain->mname && ++j == args->index) + break; + domain++; + } + + if (domain->name == nv_clk_src_max) + return -EINVAL; + + if (args->state != NV_CONTROL_PSTATE_ATTR_STATE_CURRENT) { + list_for_each_entry(pstate, &clk->states, head) { + if (i++ == args->state) + break; + } + + lo = pstate->base.domain[domain->name]; + hi = lo; + list_for_each_entry(cstate, &pstate->list, head) { + lo = min(lo, cstate->domain[domain->name]); + hi = max(hi, cstate->domain[domain->name]); + } + + args->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; + + args->index = 0; + while ((++domain)->name != nv_clk_src_max) { + if (domain->mname) { + args->index = ++j; + break; + } + } + + return 0; +} + +static int +nouveau_control_mthd_pstate_user(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + struct nouveau_clock *clk = nouveau_clock(object); + struct nv_control_pstate_user *args = data; + + if (size < sizeof(*args) || !clk) + return -EINVAL; + + return nouveau_clock_ustate(clk, args->state); +} + +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 }, + {}, + }, + }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c new file mode 100644 index 00000000000..a520029e25d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c @@ -0,0 +1,106 @@ +/* + * 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 <subdev/bios.h> +#include <subdev/bus.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/mxm.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/ltcg.h> +#include <subdev/ibus.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> +#include <subdev/bar.h> +#include <subdev/pwr.h> +#include <subdev/volt.h> + +#include <engine/device.h> +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/disp.h> +#include <engine/copy.h> +#include <engine/bsp.h> +#include <engine/vp.h> +#include <engine/ppp.h> +#include <engine/perfmon.h> + +int +gm100_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x117: + device->cname = "GM107"; + 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_CLOCK ] = &nve0_clock_oclass; +#if 0 + device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; +#endif + 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_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_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; +#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_FIFO ] = nv108_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; +#if 0 + device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; +#endif + device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; +#if 0 + device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; +#endif + break; + default: + nv_fatal(device, "unknown Maxwell chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c index a0284cf09c0..40b29d0214c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c @@ -47,38 +47,38 @@ nv04_identify(struct nouveau_device *device) case 0x04: device->cname = "NV04"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv04_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv04_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: device->cname = "NV05"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv04_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv04_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown RIVA chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c index 1b7809a095c..5f7c25ff523 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c @@ -48,152 +48,152 @@ nv10_identify(struct nouveau_device *device) case 0x10: device->cname = "NV10"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: device->cname = "NV15"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: device->cname = "NV16"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: device->cname = "nForce"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: device->cname = "NV11"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: device->cname = "NV17"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: device->cname = "nForce2"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv1a_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: device->cname = "NV18"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown Celsius chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c index 12a4005fa61..75fed11bba0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c @@ -49,78 +49,78 @@ nv20_identify(struct nouveau_device *device) case 0x20: device->cname = "NV20"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: device->cname = "NV25"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: device->cname = "NV28"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: device->cname = "NV2A"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv25_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown Kelvin chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c index cef0f1ea4c2..36919d7db7c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c @@ -49,100 +49,100 @@ nv30_identify(struct nouveau_device *device) case 0x30: device->cname = "NV30"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: device->cname = "NV35"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv04_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv35_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: device->cname = "NV31"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: device->cname = "NV36"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv36_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: device->cname = "NV34"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass; + 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_FIFO ] = &nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown Rankine chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c index 1719cb0ee59..1130a62be2c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c @@ -35,6 +35,7 @@ #include <subdev/fb.h> #include <subdev/instmem.h> #include <subdev/vm.h> +#include <subdev/volt.h> #include <engine/device.h> #include <engine/dmaobj.h> @@ -43,6 +44,7 @@ #include <engine/graph.h> #include <engine/mpeg.h> #include <engine/disp.h> +#include <engine/perfmon.h> int nv40_identify(struct nouveau_device *device) @@ -51,338 +53,370 @@ nv40_identify(struct nouveau_device *device) case 0x40: device->cname = "NV40"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x41: device->cname = "NV41"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x42: device->cname = "NV42"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x43: device->cname = "NV43"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv41_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x45: device->cname = "NV45"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x47: device->cname = "G70"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv47_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv47_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x49: device->cname = "G71"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4b: device->cname = "G73"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv49_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x44: device->cname = "NV44"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x46: device->cname = "G72"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4a: device->cname = "NV44A"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv44_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4c: device->cname = "C61"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4e: device->cname = "C51"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv4e_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv4e_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x63: device->cname = "C73"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x67: device->cname = "C67"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x68: device->cname = "C68"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv31_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; + 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_FIFO ] = &nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_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; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; default: nv_fatal(device, "unknown Curie chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c index ffc18b80c5d..ef0b0bde1a9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c @@ -36,6 +36,8 @@ #include <subdev/instmem.h> #include <subdev/vm.h> #include <subdev/bar.h> +#include <subdev/pwr.h> +#include <subdev/volt.h> #include <engine/device.h> #include <engine/dmaobj.h> @@ -49,6 +51,7 @@ #include <engine/ppp.h> #include <engine/copy.h> #include <engine/disp.h> +#include <engine/perfmon.h> int nv50_identify(struct nouveau_device *device) @@ -57,364 +60,396 @@ nv50_identify(struct nouveau_device *device) case 0x50: device->cname = "G80"; 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_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv50_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv50_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv50_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv50_perfmon_oclass; break; case 0x84: device->cname = "G84"; 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_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x86: device->cname = "G86"; 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_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x92: device->cname = "G92"; 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_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x94: device->cname = "G94"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv94_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x96: device->cname = "G96"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv94_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x98: device->cname = "G98"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xa0: device->cname = "G200"; 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_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva0_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xaa: device->cname = "MCP77/MCP78"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvaa_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xac: device->cname = "MCP79/MCP7A"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvaa_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xa3: device->cname = "GT215"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nva3_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; case 0xa5: device->cname = "GT216"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nva3_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; case 0xa8: device->cname = "GT218"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nva3_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; case 0xaf: device->cname = "MCP89"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvaf_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = &nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvaf_fb_oclass; + 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_VOLT ] = &nv40_volt_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_FIFO ] = nv84_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; default: nv_fatal(device, "unknown Tesla chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index 418f51f50d7..8d55ed633b1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -38,6 +38,8 @@ #include <subdev/instmem.h> #include <subdev/vm.h> #include <subdev/bar.h> +#include <subdev/pwr.h> +#include <subdev/volt.h> #include <engine/device.h> #include <engine/dmaobj.h> @@ -49,6 +51,7 @@ #include <engine/ppp.h> #include <engine/copy.h> #include <engine/disp.h> +#include <engine/perfmon.h> int nvc0_identify(struct nouveau_device *device) @@ -57,259 +60,284 @@ nvc0_identify(struct nouveau_device *device) case 0xc0: device->cname = "GF100"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc0_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc4: device->cname = "GF104"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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 ] = nvc3_graph_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; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc3: device->cname = "GF106"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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 ] = nvc3_graph_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; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xce: device->cname = "GF114"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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 ] = nvc3_graph_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; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xcf: device->cname = "GF116"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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 ] = nvc3_graph_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; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc1: device->cname = "GF108"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc1_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc8: device->cname = "GF110"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvc8_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xd9: device->cname = "GF119"; 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_GPIO ] = nvd0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nvc0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvd9_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xd7: device->cname = "GF117"; 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_GPIO ] = nvd0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_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; - device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_FIFO ] = &nvc0_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_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; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; default: nv_fatal(device, "unknown Fermi chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c index 7aca1877add..2d1e97d4264 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c @@ -38,6 +38,8 @@ #include <subdev/instmem.h> #include <subdev/vm.h> #include <subdev/bar.h> +#include <subdev/pwr.h> +#include <subdev/volt.h> #include <engine/device.h> #include <engine/dmaobj.h> @@ -49,6 +51,7 @@ #include <engine/bsp.h> #include <engine/vp.h> #include <engine/ppp.h> +#include <engine/perfmon.h> int nve0_identify(struct nouveau_device *device) @@ -57,124 +60,216 @@ nve0_identify(struct nouveau_device *device) case 0xe4: device->cname = "GK104"; 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_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_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 ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nve0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass; break; case 0xe7: device->cname = "GK107"; 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_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_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 ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nve0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass; break; case 0xe6: device->cname = "GK106"; 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_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_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 ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nve0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass; + break; + case 0xea: + device->cname = "GK20A"; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_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_ENGINE_FIFO ] = gk20a_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass; + device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass; break; case 0xf0: device->cname = "GK110"; 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_CLOCK ] = &nvc0_clock_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_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_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_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_VOLT ] = &nv40_volt_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_DISP ] = nvf0_disp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; + device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; + device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass; + break; + case 0xf1: + device->cname = "GK110B"; + 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_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 ] = &nvc0_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + 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 ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_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_VOLT ] = &nv40_volt_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_FIFO ] = nve0_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvf0_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nvf0_disp_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; + device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; + device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass; + break; + case 0x108: + device->cname = "GK208"; + 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_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_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_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_VOLT ] = &nv40_volt_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; + device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; -#if 0 device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; -#endif break; default: nv_fatal(device, "unknown Kepler chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/priv.h b/drivers/gpu/drm/nouveau/core/engine/device/priv.h new file mode 100644 index 00000000000..035fd5b9cfc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/device/priv.h @@ -0,0 +1,8 @@ +#ifndef __NVKM_DEVICE_PRIV_H__ +#define __NVKM_DEVICE_PRIV_H__ + +#include <engine/device.h> + +extern struct nouveau_oclass nouveau_control_oclass[]; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c index 7a5cae42834..9c38c5e4050 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/base.c @@ -22,13 +22,89 @@ * Authors: Ben Skeggs */ -#include <engine/disp.h> +#include "priv.h" +#include "outp.h" +#include "conn.h" + +static int +nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index) +{ + struct nouveau_disp *disp = event->priv; + 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; + } + } + return -ENOSYS; +} + +int +_nouveau_disp_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_disp *disp = (void *)object; + struct nvkm_output *outp; + int ret; + + list_for_each_entry(outp, &disp->outp, head) { + ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend); + if (ret && suspend) + goto fail_outp; + } + + return nouveau_engine_fini(&disp->base, suspend); + +fail_outp: + list_for_each_entry_continue_reverse(outp, &disp->outp, head) { + nv_ofuncs(outp)->init(nv_object(outp)); + } + + return ret; +} + +int +_nouveau_disp_init(struct nouveau_object *object) +{ + struct nouveau_disp *disp = (void *)object; + struct nvkm_output *outp; + int ret; + + ret = nouveau_engine_init(&disp->base); + if (ret) + return ret; + + list_for_each_entry(outp, &disp->outp, head) { + ret = nv_ofuncs(outp)->init(nv_object(outp)); + if (ret) + goto fail_outp; + } + + return ret; + +fail_outp: + list_for_each_entry_continue_reverse(outp, &disp->outp, head) { + nv_ofuncs(outp)->fini(nv_object(outp), false); + } + + return ret; +} void _nouveau_disp_dtor(struct nouveau_object *object) { struct nouveau_disp *disp = (void *)object; + struct nvkm_output *outp, *outt; + nouveau_event_destroy(&disp->vblank); + + if (disp->outp.next) { + list_for_each_entry_safe(outp, outt, &disp->outp, head) { + nouveau_object_ref(NULL, (struct nouveau_object **)&outp); + } + } + nouveau_engine_destroy(&disp->base); } @@ -39,8 +115,15 @@ nouveau_disp_create_(struct nouveau_object *parent, const char *intname, const char *extname, int length, void **pobject) { + struct nouveau_disp_impl *impl = (void *)oclass; + struct nouveau_bios *bios = nouveau_bios(parent); struct nouveau_disp *disp; - int ret; + struct nouveau_oclass **sclass; + struct nouveau_object *object; + struct dcb_output dcbE; + u8 hpd = 0, ver, hdr; + u32 data; + int ret, i; ret = nouveau_engine_create_(parent, engine, oclass, true, intname, extname, length, pobject); @@ -48,5 +131,42 @@ nouveau_disp_create_(struct nouveau_object *parent, if (ret) return ret; - return nouveau_event_create(heads, &disp->vblank); + INIT_LIST_HEAD(&disp->outp); + + /* create output objects for each display path in the vbios */ + i = -1; + while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { + if (dcbE.type == DCB_OUTPUT_UNUSED) + continue; + if (dcbE.type == DCB_OUTPUT_EOL) + break; + data = dcbE.location << 4 | dcbE.type; + + oclass = nvkm_output_oclass; + sclass = impl->outp; + while (sclass && sclass[0]) { + if (sclass[0]->handle == data) { + oclass = sclass[0]; + break; + } + sclass++; + } + + nouveau_object_ctor(*pobject, *pobject, oclass, + &dcbE, i, &object); + hpd = max(hpd, (u8)(dcbE.connector + 1)); + } + + ret = nouveau_event_create(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); + if (ret) + return ret; + + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c new file mode 100644 index 00000000000..4ffbc70ecf5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c @@ -0,0 +1,172 @@ +/* + * 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 <subdev/gpio.h> + +#include "conn.h" +#include "outp.h" + +static void +nvkm_connector_hpd_work(struct work_struct *w) +{ + struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work); + 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); +} + +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; +} + +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); + return nouveau_object_fini(&conn->base, suspend); +} + +int +_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); + } + return ret; +} + +void +_nvkm_connector_dtor(struct nouveau_object *object) +{ + struct nvkm_connector *conn = (void *)object; + nouveau_event_ref(NULL, &conn->hpd.event); + nouveau_object_destroy(&conn->base); +} + +int +nvkm_connector_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + struct nvbios_connE *info, int index, + int length, void **pobject) +{ + static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 }; + struct nouveau_gpio *gpio = nouveau_gpio(parent); + struct nouveau_disp *disp = (void *)engine; + struct nvkm_connector *conn; + struct nvkm_output *outp; + struct dcb_gpio_func func; + int ret; + + list_for_each_entry(outp, &disp->outp, head) { + if (outp->conn && outp->conn->index == index) { + atomic_inc(&nv_object(outp->conn)->refcount); + *pobject = outp->conn; + return 1; + } + } + + ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject); + conn = *pobject; + if (ret) + return ret; + + conn->info = *info; + conn->index = index; + + DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n", + info->type, info->location, info->hpd, info->dp, + info->di, info->sr, info->lcdid); + + if ((info->hpd = ffs(info->hpd))) { + if (--info->hpd >= ARRAY_SIZE(hpd)) { + ERR("hpd %02x unknown\n", info->hpd); + goto done; + } + 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; + } + + ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED, + func.line, nvkm_connector_hpd, + conn, &conn->hpd.event); + if (ret) { + ERR("func %02x failed, %d\n", info->hpd, ret); + } else { + DBG("func %02x (HPD)\n", info->hpd); + } + } + +done: + INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work); + return 0; +} + +int +_nvkm_connector_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *info, u32 index, + struct nouveau_object **pobject) +{ + struct nvkm_connector *conn; + int ret; + + ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn); + *pobject = nv_object(conn); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass * +nvkm_connector_oclass = &(struct nvkm_connector_impl) { + .base = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_connector_ctor, + .dtor = _nvkm_connector_dtor, + .init = _nvkm_connector_init, + .fini = _nvkm_connector_fini, + }, + }, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h new file mode 100644 index 00000000000..035ebeacbb1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h @@ -0,0 +1,59 @@ +#ifndef __NVKM_DISP_CONN_H__ +#define __NVKM_DISP_CONN_H__ + +#include "priv.h" + +struct nvkm_connector { + struct nouveau_object base; + struct list_head head; + + struct nvbios_connE info; + int index; + + struct { + struct nouveau_eventh *event; + struct work_struct work; + } hpd; +}; + +#define nvkm_connector_create(p,e,c,b,i,d) \ + nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) +#define nvkm_connector_destroy(d) ({ \ + struct nvkm_connector *disp = (d); \ + _nvkm_connector_dtor(nv_object(disp)); \ +}) +#define nvkm_connector_init(d) ({ \ + struct nvkm_connector *disp = (d); \ + _nvkm_connector_init(nv_object(disp)); \ +}) +#define nvkm_connector_fini(d,s) ({ \ + struct nvkm_connector *disp = (d); \ + _nvkm_connector_fini(nv_object(disp), (s)); \ +}) + +int nvkm_connector_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, struct nvbios_connE *, + int, int, void **); + +int _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nvkm_connector_dtor(struct nouveau_object *); +int _nvkm_connector_init(struct nouveau_object *); +int _nvkm_connector_fini(struct nouveau_object *, bool); + +struct nvkm_connector_impl { + struct nouveau_oclass base; +}; + +#ifndef MSG +#define MSG(l,f,a...) do { \ + struct nvkm_connector *_conn = (void *)conn; \ + nv_##l(nv_object(conn)->engine, "%02x:%02x%02x: "f, _conn->index, \ + _conn->info.location, _conn->info.type, ##a); \ +} while(0) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c index 054d9cff4f5..5a5b59b2113 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c @@ -30,60 +30,49 @@ #include <engine/disp.h> -#include "dport.h" +#include <core/class.h> -#define DBG(fmt, args...) nv_debug(dp->disp, "DP:%04x:%04x: " fmt, \ - dp->outp->hasht, dp->outp->hashm, ##args) -#define ERR(fmt, args...) nv_error(dp->disp, "DP:%04x:%04x: " fmt, \ - dp->outp->hasht, dp->outp->hashm, ##args) +#include "dport.h" +#include "outpdp.h" /****************************************************************************** * link training *****************************************************************************/ struct dp_state { - const struct nouveau_dp_func *func; - struct nouveau_disp *disp; - struct dcb_output *outp; - struct nvbios_dpout info; - u8 version; - struct nouveau_i2c_port *aux; - int head; - u8 dpcd[4]; + struct nvkm_output_dp *outp; int link_nr; u32 link_bw; u8 stat[6]; u8 conf[4]; + bool pc2; + u8 pc2stat; + u8 pc2conf[2]; }; static int dp_set_link_config(struct dp_state *dp) { - struct nouveau_disp *disp = dp->disp; + struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); + struct nvkm_output_dp *outp = dp->outp; + struct nouveau_disp *disp = nouveau_disp(outp); struct nouveau_bios *bios = nouveau_bios(disp); struct nvbios_init init = { - .subdev = nv_subdev(dp->disp), + .subdev = nv_subdev(disp), .bios = bios, .offset = 0x0000, - .outp = dp->outp, - .crtc = dp->head, + .outp = &outp->base.info, + .crtc = -1, .execute = 1, }; u32 lnkcmp; u8 sink[2]; + int ret; DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); - /* set desired link configuration on the sink */ - sink[0] = dp->link_bw / 27000; - sink[1] = dp->link_nr; - if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) - sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; - - nv_wraux(dp->aux, DPCD_LC00, sink, 2); - /* set desired link configuration on the source */ - if ((lnkcmp = dp->info.lnkcmp)) { - if (dp->version < 0x30) { + if ((lnkcmp = dp->outp->info.lnkcmp)) { + if (outp->version < 0x30) { while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) lnkcmp += 4; init.offset = nv_ro16(bios, lnkcmp + 2); @@ -96,61 +85,112 @@ dp_set_link_config(struct dp_state *dp) nvbios_exec(&init); } - return dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, - dp->link_nr, dp->link_bw / 27000, - dp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); + ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, + outp->dpcd[DPCD_RC02] & + DPCD_RC02_ENHANCED_FRAME_CAP); + if (ret) { + if (ret < 0) + ERR("lnk_ctl failed with %d\n", ret); + return ret; + } + + impl->lnk_pwr(outp, dp->link_nr); + + /* set desired link configuration on the sink */ + sink[0] = dp->link_bw / 27000; + sink[1] = dp->link_nr; + if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) + sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; + + return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2); } static void dp_set_training_pattern(struct dp_state *dp, u8 pattern) { + struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); + struct nvkm_output_dp *outp = dp->outp; u8 sink_tp; DBG("training pattern %d\n", pattern); - dp->func->pattern(dp->disp, dp->outp, dp->head, pattern); + impl->pattern(outp, pattern); - nv_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); + nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp |= pattern; - nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); + nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1); } static int -dp_link_train_commit(struct dp_state *dp) +dp_link_train_commit(struct dp_state *dp, bool pc) { - int i; + struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); + struct nvkm_output_dp *outp = dp->outp; + int ret, i; for (i = 0; i < dp->link_nr; i++) { u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; + u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3; u8 lpre = (lane & 0x0c) >> 2; u8 lvsw = (lane & 0x03) >> 0; + u8 hivs = 3 - lpre; + u8 hipe = 3; + u8 hipc = 3; + + if (lpc2 >= hipc) + lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED; + if (lpre >= hipe) { + lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */ + lvsw = hivs = 3 - (lpre & 3); + } else + if (lvsw >= hivs) { + lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED; + } dp->conf[i] = (lpre << 3) | lvsw; - if (lvsw == 3) - dp->conf[i] |= DPCD_LC03_MAX_SWING_REACHED; - if (lpre == 3) - dp->conf[i] |= DPCD_LC03_MAX_PRE_EMPHASIS_REACHED; + dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4); + + DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2); + impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); + } + + ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4); + if (ret) + return ret; - DBG("config lane %d %02x\n", i, dp->conf[i]); - dp->func->drv_ctl(dp->disp, dp->outp, dp->head, i, lvsw, lpre); + if (pc) { + ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2); + if (ret) + return ret; } - return nv_wraux(dp->aux, DPCD_LC03(0), dp->conf, 4); + return 0; } static int -dp_link_train_update(struct dp_state *dp, u32 delay) +dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) { + struct nvkm_output_dp *outp = dp->outp; int ret; - udelay(delay); + if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) + mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); + else + udelay(delay); - ret = nv_rdaux(dp->aux, DPCD_LS02, dp->stat, 6); + ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6); if (ret) return ret; - DBG("status %6ph\n", dp->stat); + if (pc) { + ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1); + if (ret) + dp->pc2stat = 0x00; + DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat); + } else { + DBG("status %6ph\n", dp->stat); + } + return 0; } @@ -164,8 +204,8 @@ dp_link_train_cr(struct dp_state *dp) dp_set_training_pattern(dp, 1); do { - if (dp_link_train_commit(dp) || - dp_link_train_update(dp, 100)) + if (dp_link_train_commit(dp, false) || + dp_link_train_update(dp, false, 100)) break; cr_done = true; @@ -191,13 +231,19 @@ dp_link_train_cr(struct dp_state *dp) static int dp_link_train_eq(struct dp_state *dp) { + struct nvkm_output_dp *outp = dp->outp; bool eq_done = false, cr_done = true; int tries = 0, i; - dp_set_training_pattern(dp, 2); + if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) + dp_set_training_pattern(dp, 3); + else + dp_set_training_pattern(dp, 2); do { - if (dp_link_train_update(dp, 400)) + if ((tries && + dp_link_train_commit(dp, dp->pc2)) || + dp_link_train_update(dp, dp->pc2, 400)) break; eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); @@ -209,9 +255,6 @@ dp_link_train_eq(struct dp_state *dp) !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) eq_done = false; } - - if (dp_link_train_commit(dp)) - break; } while (!eq_done && cr_done && ++tries <= 5); return eq_done ? 0 : -1; @@ -220,104 +263,109 @@ dp_link_train_eq(struct dp_state *dp) static void dp_link_train_init(struct dp_state *dp, bool spread) { + struct nvkm_output_dp *outp = dp->outp; + struct nouveau_disp *disp = nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(disp); struct nvbios_init init = { - .subdev = nv_subdev(dp->disp), - .bios = nouveau_bios(dp->disp), - .outp = dp->outp, - .crtc = dp->head, + .subdev = nv_subdev(disp), + .bios = bios, + .outp = &outp->base.info, + .crtc = -1, .execute = 1, }; /* set desired spread */ if (spread) - init.offset = dp->info.script[2]; + init.offset = outp->info.script[2]; else - init.offset = dp->info.script[3]; + init.offset = outp->info.script[3]; nvbios_exec(&init); /* pre-train script */ - init.offset = dp->info.script[0]; + init.offset = outp->info.script[0]; nvbios_exec(&init); } static void dp_link_train_fini(struct dp_state *dp) { + struct nvkm_output_dp *outp = dp->outp; + struct nouveau_disp *disp = nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(disp); struct nvbios_init init = { - .subdev = nv_subdev(dp->disp), - .bios = nouveau_bios(dp->disp), - .outp = dp->outp, - .crtc = dp->head, + .subdev = nv_subdev(disp), + .bios = bios, + .outp = &outp->base.info, + .crtc = -1, .execute = 1, }; /* post-train script */ - init.offset = dp->info.script[1], + init.offset = outp->info.script[1], nvbios_exec(&init); } -int -nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, - struct dcb_output *outp, int head, u32 datarate) +static const struct dp_rates { + u32 rate; + u8 bw; + u8 nr; +} nouveau_dp_rates[] = { + { 2160000, 0x14, 4 }, + { 1080000, 0x0a, 4 }, + { 1080000, 0x14, 2 }, + { 648000, 0x06, 4 }, + { 540000, 0x0a, 2 }, + { 540000, 0x14, 1 }, + { 324000, 0x06, 2 }, + { 270000, 0x0a, 1 }, + { 162000, 0x06, 1 }, + {} +}; + +void +nouveau_dp_train(struct work_struct *w) { - struct nouveau_bios *bios = nouveau_bios(disp); - struct nouveau_i2c *i2c = nouveau_i2c(disp); + struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); + struct nouveau_disp *disp = nouveau_disp(outp); + const struct dp_rates *cfg = nouveau_dp_rates; struct dp_state _dp = { - .disp = disp, - .func = func, .outp = outp, - .head = head, }, *dp = &_dp; - const u32 bw_list[] = { 270000, 162000, 0 }; - const u32 *link_bw = bw_list; - u8 hdr, cnt, len; - u32 data; + u32 datarate = 0; int ret; - /* find the bios displayport data relevant to this output */ - data = nvbios_dpout_match(bios, outp->hasht, outp->hashm, &dp->version, - &hdr, &cnt, &len, &dp->info); - if (!data) { - ERR("bios data not found\n"); - return -EINVAL; - } - - /* acquire the aux channel and fetch some info about the display */ - if (outp->location) - dp->aux = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); - else - dp->aux = i2c->find(i2c, NV_I2C_TYPE_DCBI2C(outp->i2c_index)); - if (!dp->aux) { - ERR("no aux channel?!\n"); - return -ENODEV; + /* bring capabilities within encoder limits */ + if (nv_mclass(disp) < NVD0_DISP_CLASS) + 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; + outp->dpcd[2] |= outp->base.info.dpconf.link_nr; } - - ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd)); - if (ret) { - ERR("failed to read DPCD\n"); - return ret; + if (outp->dpcd[1] > outp->base.info.dpconf.link_bw) + outp->dpcd[1] = outp->base.info.dpconf.link_bw; + dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; + + /* restrict link config to the lowest required rate, if requested */ + if (datarate) { + datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */ + while (cfg[1].rate >= datarate) + cfg++; } + cfg--; - /* adjust required bandwidth for 8B/10B coding overhead */ - datarate = (datarate / 8) * 10; + /* disable link interrupt handling during link training */ + nouveau_event_put(outp->irq); /* enable down-spreading and execute pre-train script from vbios */ - dp_link_train_init(dp, dp->dpcd[3] & 0x01); - - /* start off at highest link rate supported by encoder and display */ - while (*link_bw > (dp->dpcd[1] * 27000)) - link_bw++; + dp_link_train_init(dp, outp->dpcd[3] & 0x01); - while (link_bw[0]) { - /* find minimum required lane count at this link rate */ - dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT; - while ((dp->link_nr >> 1) * link_bw[0] > datarate) - dp->link_nr >>= 1; - - /* drop link rate to minimum with this lane count */ - while ((link_bw[1] * dp->link_nr) > datarate) - link_bw++; - dp->link_bw = link_bw[0]; + while (ret = -EIO, (++cfg)->rate) { + /* select next configuration supported by encoder and sink */ + while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || + cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE])) + cfg++; + dp->link_bw = cfg->bw * 27000; + dp->link_nr = cfg->nr; /* program selected link configuration */ ret = dp_set_link_config(dp); @@ -328,19 +376,24 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, !dp_link_train_eq(dp)) break; } else - if (ret >= 1) { - /* dp_set_link_config() handled training */ + if (ret) { + /* dp_set_link_config() handled training, or + * we failed to communicate with the sink. + */ break; } - - /* retry at lower rate */ - link_bw++; } - /* finish link training */ + /* finish link training and execute post-train script from vbios */ dp_set_training_pattern(dp, 0); + if (ret < 0) + ERR("link training failed\n"); - /* execute post-train script from vbios */ dp_link_train_fini(dp); - return true; + + /* signal completion and enable link interrupt handling */ + DBG("training complete\n"); + atomic_set(&outp->lt.done, 1); + wake_up(&outp->lt.wait); + nouveau_event_get(outp->irq); } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h index 0e1bbd18ff6..5628d2d5ec7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h @@ -2,19 +2,18 @@ #define __NVKM_DISP_DPORT_H__ /* DPCD Receiver Capabilities */ -#define DPCD_RC00 0x00000 -#define DPCD_RC00_DPCD_REV 0xff -#define DPCD_RC01 0x00001 -#define DPCD_RC01_MAX_LINK_RATE 0xff +#define DPCD_RC00_DPCD_REV 0x00000 +#define DPCD_RC01_MAX_LINK_RATE 0x00001 #define DPCD_RC02 0x00002 #define DPCD_RC02_ENHANCED_FRAME_CAP 0x80 +#define DPCD_RC02_TPS3_SUPPORTED 0x40 #define DPCD_RC02_MAX_LANE_COUNT 0x1f #define DPCD_RC03 0x00003 #define DPCD_RC03_MAX_DOWNSPREAD 0x01 +#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e /* DPCD Link Configuration */ -#define DPCD_LC00 0x00100 -#define DPCD_LC00_LINK_BW_SET 0xff +#define DPCD_LC00_LINK_BW_SET 0x00100 #define DPCD_LC01 0x00101 #define DPCD_LC01_ENHANCED_FRAME_EN 0x80 #define DPCD_LC01_LANE_COUNT_SET 0x1f @@ -25,6 +24,16 @@ #define DPCD_LC03_PRE_EMPHASIS_SET 0x18 #define DPCD_LC03_MAX_SWING_REACHED 0x04 #define DPCD_LC03_VOLTAGE_SWING_SET 0x03 +#define DPCD_LC0F 0x0010f +#define DPCD_LC0F_LANE1_MAX_POST_CURSOR2_REACHED 0x40 +#define DPCD_LC0F_LANE1_POST_CURSOR2_SET 0x30 +#define DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED 0x04 +#define DPCD_LC0F_LANE0_POST_CURSOR2_SET 0x03 +#define DPCD_LC10 0x00110 +#define DPCD_LC10_LANE3_MAX_POST_CURSOR2_REACHED 0x40 +#define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30 +#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04 +#define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03 /* DPCD Link/Sink Status */ #define DPCD_LS02 0x00202 @@ -55,24 +64,12 @@ #define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30 #define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c #define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03 +#define DPCD_LS0C 0x0020c +#define DPCD_LS0C_LANE3_POST_CURSOR2 0xc0 +#define DPCD_LS0C_LANE2_POST_CURSOR2 0x30 +#define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c +#define DPCD_LS0C_LANE0_POST_CURSOR2 0x03 -struct nouveau_disp; -struct dcb_output; - -struct nouveau_dp_func { - int (*pattern)(struct nouveau_disp *, struct dcb_output *, - int head, int pattern); - int (*lnk_ctl)(struct nouveau_disp *, struct dcb_output *, int head, - int link_nr, int link_bw, bool enh_frame); - int (*drv_ctl)(struct nouveau_disp *, struct dcb_output *, int head, - int lane, int swing, int preem); -}; - -extern const struct nouveau_dp_func nv94_sor_dp_func; -extern const struct nouveau_dp_func nvd0_sor_dp_func; -extern const struct nouveau_dp_func nv50_pior_dp_func; - -int nouveau_dp_train(struct nouveau_disp *, const struct nouveau_dp_func *, - struct dcb_output *, int, u32); +void nouveau_dp_train(struct work_struct *); #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c new file mode 100644 index 00000000000..9fc7447fec9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c @@ -0,0 +1,101 @@ +/* + * 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 <engine/software.h> +#include <engine/disp.h> + +#include <core/class.h> + +#include "nv50.h" + +/******************************************************************************* + * Base display object + ******************************************************************************/ + +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 }, + {} +}; + +static struct nouveau_oclass +gm107_disp_base_oclass[] = { + { GM107_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, + {} +}; + +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + +static int +gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_disp_priv *priv; + int heads = nv_rd32(parent, 0x022448); + int ret; + + ret = nouveau_disp_create(parent, engine, oclass, heads, + "PDISP", "display", &priv); + *pobject = nv_object(priv); + 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; + INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); + priv->sclass = gm107_disp_sclass; + priv->head.nr = heads; + priv->dac.nr = 3; + priv->sor.nr = 4; + priv->dac.power = nv50_dac_power; + 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; + return 0; +} + +struct nouveau_oclass * +gm107_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x07), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_disp_ctor, + .dtor = _nouveau_disp_dtor, + .init = _nouveau_disp_init, + .fini = _nouveau_disp_fini, + }, + .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, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c index 05e903f08a3..a32666ed0c4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs */ -#include <engine/disp.h> +#include "priv.h" #include <core/event.h> #include <core/class.h> @@ -31,9 +31,53 @@ struct nv04_disp_priv { struct nouveau_disp base; }; +static int +nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + struct nv04_disp_priv *priv = (void *)object->engine; + struct nv04_display_scanoutpos *args = data; + const int head = (mthd & NV04_DISP_MTHD_HEAD); + u32 line; + + 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 struct nouveau_omthds +nv04_disp_omthds[] = { + { HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos }, + {} +}; + static struct nouveau_oclass nv04_disp_sclass[] = { - { NV04_DISP_CLASS, &nouveau_object_ofuncs }, + { NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds }, {}, }; @@ -42,13 +86,13 @@ nv04_disp_sclass[] = { ******************************************************************************/ static void -nv04_disp_vblank_enable(struct nouveau_event *event, int head) +nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head) { nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001); } static void -nv04_disp_vblank_disable(struct nouveau_event *event, int head) +nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head) { nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000); } @@ -59,16 +103,25 @@ nv04_disp_intr(struct nouveau_subdev *subdev) struct nv04_disp_priv *priv = (void *)subdev; u32 crtc0 = nv_rd32(priv, 0x600100); u32 crtc1 = nv_rd32(priv, 0x602100); + u32 pvideo; if (crtc0 & 0x00000001) { - nouveau_event_trigger(priv->base.vblank, 0); + nouveau_event_trigger(priv->base.vblank, 1, 0); nv_wr32(priv, 0x600100, 0x00000001); } if (crtc1 & 0x00000001) { - nouveau_event_trigger(priv->base.vblank, 1); + nouveau_event_trigger(priv->base.vblank, 1, 1); nv_wr32(priv, 0x602100, 0x00000001); } + + if (nv_device(priv)->chipset >= 0x10 && + nv_device(priv)->chipset <= 0x40) { + pvideo = nv_rd32(priv, 0x8100); + if (pvideo & ~0x11) + nv_info(priv, "PVIDEO intr: %08x\n", pvideo); + nv_wr32(priv, 0x8100, pvideo); + } } static int @@ -93,13 +146,13 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv04_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv04_disp_oclass = &(struct nouveau_disp_impl) { + .base.handle = NV_ENGINE(DISP, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index c168ae3eaa9..2283c442a10 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -26,8 +26,7 @@ #include <core/parent.h> #include <core/handle.h> #include <core/class.h> - -#include <engine/disp.h> +#include <core/enum.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -227,6 +226,177 @@ nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend) * EVO master channel object ******************************************************************************/ +static void +nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c, + const struct nv50_disp_mthd_list *list, int inst) +{ + struct nouveau_object *disp = nv_object(priv); + int i; + + for (i = 0; list->data[i].mthd; i++) { + if (list->data[i].addr) { + u32 next = nv_rd32(priv, list->data[i].addr + base + 0); + u32 prev = nv_rd32(priv, list->data[i].addr + base + c); + u32 mthd = list->data[i].mthd + (list->mthd * inst); + const char *name = list->data[i].name; + char mods[16]; + + if (prev != next) + snprintf(mods, sizeof(mods), "-> 0x%08x", next); + else + snprintf(mods, sizeof(mods), "%13c", ' '); + + nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n", + mthd, prev, mods, name ? " // " : "", + name ? name : ""); + } + } +} + +void +nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head, + const struct nv50_disp_mthd_chan *chan) +{ + struct nouveau_object *disp = nv_object(priv); + const struct nv50_disp_impl *impl = (void *)disp->oclass; + const struct nv50_disp_mthd_list *list; + int i, j; + + if (debug > nv_subdev(priv)->debug) + return; + + for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { + u32 base = head * chan->addr; + for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { + const char *cname = chan->name; + const char *sname = ""; + char cname_[16], sname_[16]; + + if (chan->addr) { + snprintf(cname_, sizeof(cname_), "%s %d", + chan->name, head); + cname = cname_; + } + + if (chan->data[i].nr > 1) { + snprintf(sname_, sizeof(sname_), " - %s %d", + chan->data[i].name, j); + sname = sname_; + } + + nv_printk_(disp, debug, "%s%s:\n", cname, sname); + nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev, + list, j); + } + } +} + +const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x610bb8 }, + { 0x0088, 0x610b9c }, + { 0x008c, 0x000000 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610828 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610b70 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_pior = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0700, 0x610b80 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nv50_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_mast_mthd_base }, + { "DAC", 3, &nv50_disp_mast_mthd_dac }, + { "SOR", 2, &nv50_disp_mast_mthd_sor }, + { "PIOR", 3, &nv50_disp_mast_mthd_pior }, + { "HEAD", 2, &nv50_disp_mast_mthd_head }, + {} + } +}; + static int nv50_disp_mast_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -323,6 +493,56 @@ nv50_disp_mast_ofuncs = { * EVO sync channel objects ******************************************************************************/ +static const struct nv50_disp_mthd_list +nv50_disp_sync_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x0100, 0x610894 }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_sync_mthd_image = { + .mthd = 0x0400, + .addr = 0x000000, + .data = { + { 0x0800, 0x6108f0 }, + { 0x0804, 0x6108fc }, + { 0x0808, 0x61090c }, + { 0x080c, 0x610914 }, + { 0x0810, 0x610904 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nv50_disp_sync_mthd_chan = { + .name = "Base", + .addr = 0x000540, + .data = { + { "Global", 1, &nv50_disp_sync_mthd_base }, + { "Image", 2, &nv50_disp_sync_mthd_image }, + {} + } +}; + static int nv50_disp_sync_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -362,6 +582,44 @@ nv50_disp_sync_ofuncs = { * EVO overlay channel objects ******************************************************************************/ +const struct nv50_disp_mthd_list +nv50_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0009a0 }, + { 0x0088, 0x0009c0 }, + { 0x008c, 0x0009c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nv50_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &nv50_disp_ovly_mthd_base }, + {} + } +}; + static int nv50_disp_ovly_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -541,14 +799,43 @@ nv50_disp_curs_ofuncs = { * Base display object ******************************************************************************/ +int +nv50_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; + 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 head) +nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head) { nv_mask(event->priv, 0x61002c, (4 << head), (4 << head)); } static void -nv50_disp_base_vblank_disable(struct nouveau_event *event, int head) +nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head) { nv_mask(event->priv, 0x61002c, (4 << head), 0); } @@ -675,6 +962,7 @@ nv50_disp_base_ofuncs = { 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 }, @@ -752,40 +1040,94 @@ nv50_disp_cclass = { * Display engine implementation ******************************************************************************/ -static void -nv50_disp_intr_error(struct nv50_disp_priv *priv) -{ - u32 channels = (nv_rd32(priv, 0x610020) & 0x001f0000) >> 16; - u32 addr, data; - int chid; - - for (chid = 0; chid < 5; chid++) { - if (!(channels & (1 << chid))) - continue; +static const struct nouveau_enum +nv50_disp_intr_error_type[] = { + { 3, "ILLEGAL_MTHD" }, + { 4, "INVALID_VALUE" }, + { 5, "INVALID_STATE" }, + { 7, "INVALID_HANDLE" }, + {} +}; - nv_wr32(priv, 0x610020, 0x00010000 << chid); - addr = nv_rd32(priv, 0x610080 + (chid * 0x08)); - data = nv_rd32(priv, 0x610084 + (chid * 0x08)); - nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); +static const struct nouveau_enum +nv50_disp_intr_error_code[] = { + { 0x00, "" }, + {} +}; - nv_error(priv, "chid %d mthd 0x%04x data 0x%08x 0x%08x\n", - chid, addr & 0xffc, data, addr); +static void +nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) +{ + struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; + u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08)); + u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08)); + u32 code = (addr & 0x00ff0000) >> 16; + u32 type = (addr & 0x00007000) >> 12; + u32 mthd = (addr & 0x00000ffc); + const struct nouveau_enum *ec, *et; + char ecunk[6], etunk[6]; + + et = nouveau_enum_find(nv50_disp_intr_error_type, type); + if (!et) + snprintf(etunk, sizeof(etunk), "UNK%02X", type); + + ec = nouveau_enum_find(nv50_disp_intr_error_code, code); + if (!ec) + snprintf(ecunk, sizeof(ecunk), "UNK%02X", code); + + nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n", + et ? et->name : etunk, ec ? ec->name : ecunk, + chid, mthd, data); + + if (chid == 0) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, + impl->mthd.core); + break; + default: + break; + } + } else + if (chid <= 2) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, + impl->mthd.base); + break; + default: + break; + } + } else + if (chid <= 4) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3, + impl->mthd.ovly); + break; + default: + break; + } } + + nv_wr32(priv, 0x610020, 0x00010000 << chid); + nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); } -static u16 -exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, - struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, +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, struct nvbios_outp *info) { struct nouveau_bios *bios = nouveau_bios(priv); - u16 mask, type, data; + struct nvkm_output *outp; + u16 mask, type; - if (outp < 4) { + if (or < 4) { type = DCB_OUTPUT_ANALOG; mask = 0; } else - if (outp < 8) { + if (or < 8) { switch (ctrl & 0x00000f00) { case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; @@ -795,45 +1137,48 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; default: nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); - return 0x0000; + return NULL; } - outp -= 4; + or -= 4; } else { - outp = outp - 8; + or = or - 8; type = 0x0010; mask = 0; switch (ctrl & 0x00000f00) { - case 0x00000000: type |= priv->pior.type[outp]; break; + case 0x00000000: type |= priv->pior.type[or]; break; default: nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl); - return 0x0000; + return NULL; } } mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << outp; + mask |= 0x0001 << or; mask |= 0x0100 << head; - data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); - if (!data) - return 0x0000; - - /* off-chip encoders require matching the exact encoder type */ - if (dcb->location != 0) - type |= dcb->extdev << 8; + list_for_each_entry(outp, &priv->base.outp, head) { + if ((outp->info.hasht & 0xff) == type && + (outp->info.hashm & mask) == mask) { + *data = nvbios_outp_match(bios, outp->info.hasht, + outp->info.hashm, + ver, hdr, cnt, len, info); + if (!*data) + return NULL; + return outp; + } + } - return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); + return NULL; } -static bool +static struct nvkm_output * exec_script(struct nv50_disp_priv *priv, int head, int id) { struct nouveau_bios *bios = nouveau_bios(priv); + struct nvkm_output *outp; struct nvbios_outp info; - struct dcb_output dcb; u8 ver, hdr, cnt, len; - u16 data; - u32 ctrl = 0x00000000; + u32 data, ctrl = 0; u32 reg; int i; @@ -863,36 +1208,35 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) } if (!(ctrl & (1 << head))) - return false; + return NULL; i--; - data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); - if (data) { + outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); + if (outp) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[id], - .outp = &dcb, + .outp = &outp->info, .crtc = head, .execute = 1, }; - return nvbios_exec(&init) == 0; + nvbios_exec(&init); } - return false; + return outp; } -static u32 -exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, - struct dcb_output *outp) +static struct nvkm_output * +exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) { struct nouveau_bios *bios = nouveau_bios(priv); + struct nvkm_output *outp; struct nvbios_outp info1; struct nvbios_ocfg info2; u8 ver, hdr, cnt, len; - u32 ctrl = 0x00000000; - u32 data, conf = ~0; + u32 data, ctrl = 0; u32 reg; int i; @@ -922,37 +1266,37 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, } if (!(ctrl & (1 << head))) - return conf; + return NULL; i--; - data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); - if (!data) - return conf; + outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); + if (!outp) + return NULL; - if (outp->location == 0) { - switch (outp->type) { + if (outp->info.location == 0) { + switch (outp->info.type) { case DCB_OUTPUT_TMDS: - conf = (ctrl & 0x00000f00) >> 8; + *conf = (ctrl & 0x00000f00) >> 8; if (pclk >= 165000) - conf |= 0x0100; + *conf |= 0x0100; break; case DCB_OUTPUT_LVDS: - conf = priv->sor.lvdsconf; + *conf = priv->sor.lvdsconf; break; case DCB_OUTPUT_DP: - conf = (ctrl & 0x00000f00) >> 8; + *conf = (ctrl & 0x00000f00) >> 8; break; case DCB_OUTPUT_ANALOG: default: - conf = 0x00ff; + *conf = 0x00ff; break; } } else { - conf = (ctrl & 0x00000f00) >> 8; + *conf = (ctrl & 0x00000f00) >> 8; pclk = pclk / 2; } - data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); + data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); if (data && id < 0xff) { data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { @@ -960,7 +1304,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, .subdev = nv_subdev(priv), .bios = bios, .offset = data, - .outp = outp, + .outp = &outp->info, .crtc = head, .execute = 1, }; @@ -969,7 +1313,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, } } - return conf; + return outp; } static void @@ -981,7 +1325,35 @@ nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head) static void nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) { - exec_script(priv, head, 2); + struct nvkm_output *outp = exec_script(priv, head, 2); + + /* the binary driver does this outside of the supervisor handling + * (after the third supervisor from a detach). we (currently?) + * allow both detach/attach to happen in the same set of + * supervisor interrupts, so it would make sense to execute this + * (full power down?) script after all the detach phases of the + * supervisor handling. like with training if needed from the + * second supervisor, nvidia doesn't do this, so who knows if it's + * entirely safe, but it does appear to work.. + * + * without this script being run, on some configurations i've + * seen, switching from DP to TMDS on a DP connector may result + * in a blank screen (SOR_PWR off/on can restore it) + */ + if (outp && outp->info.type == DCB_OUTPUT_DP) { + struct nvkm_output_dp *outpdp = (void *)outp; + struct nvbios_init init = { + .subdev = nv_subdev(priv), + .bios = nouveau_bios(priv), + .outp = &outp->info, + .crtc = head, + .offset = outpdp->info.script[4], + .execute = 1, + }; + + nvbios_exec(&init); + atomic_set(&outpdp->lt.done, 0); + } } static void @@ -1103,56 +1475,83 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, static void nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) { - struct dcb_output outp; + struct nvkm_output *outp; u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 hval, hreg = 0x614200 + (head * 0x800); u32 oval, oreg; - u32 mask; - u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); - if (conf != ~0) { - if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) { - u32 soff = (ffs(outp.or) - 1) * 0x08; - u32 ctrl = nv_rd32(priv, 0x610798 + soff); - u32 datarate; - - switch ((ctrl & 0x000f0000) >> 16) { - case 6: datarate = pclk * 30 / 8; break; - case 5: datarate = pclk * 24 / 8; break; - case 2: - default: - datarate = pclk * 18 / 8; - break; - } + u32 mask, conf; - nouveau_dp_train(&priv->base, priv->sor.dp, - &outp, head, datarate); - } + outp = exec_clkcmp(priv, head, 0xff, pclk, &conf); + if (!outp) + return; - exec_clkcmp(priv, head, 0, pclk, &outp); - - if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) { - oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800; - oval = 0x00000000; - hval = 0x00000000; - mask = 0xffffffff; - } else - if (!outp.location) { - if (outp.type == DCB_OUTPUT_DP) - nv50_disp_intr_unk20_2_dp(priv, &outp, pclk); - oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800; - oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; - hval = 0x00000000; - mask = 0x00000707; + /* we allow both encoder attach and detach operations to occur + * within a single supervisor (ie. modeset) sequence. the + * encoder detach scripts quite often switch off power to the + * lanes, which requires the link to be re-trained. + * + * this is not generally an issue as the sink "must" (heh) + * signal an irq when it's lost sync so the driver can + * re-train. + * + * however, on some boards, if one does not configure at least + * the gpu side of the link *before* attaching, then various + * things can go horribly wrong (PDISP disappearing from mmio, + * third supervisor never happens, etc). + * + * the solution is simply to retrain here, if necessary. last + * i checked, the binary driver userspace does not appear to + * trigger this situation (it forces an UPDATE between steps). + */ + if (outp->info.type == DCB_OUTPUT_DP) { + u32 soff = (ffs(outp->info.or) - 1) * 0x08; + u32 ctrl, datarate; + + if (outp->info.location == 0) { + ctrl = nv_rd32(priv, 0x610794 + soff); + soff = 1; } else { - oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800; - oval = 0x00000001; - hval = 0x00000001; - mask = 0x00000707; + ctrl = nv_rd32(priv, 0x610b80 + soff); + soff = 2; + } + + switch ((ctrl & 0x000f0000) >> 16) { + case 6: datarate = pclk * 30; break; + case 5: datarate = pclk * 24; break; + case 2: + default: + datarate = pclk * 18; + break; } - nv_mask(priv, hreg, 0x0000000f, hval); - nv_mask(priv, oreg, mask, oval); + if (nvkm_output_dp_train(outp, datarate / soff, true)) + ERR("link not trained before attach\n"); } + + exec_clkcmp(priv, head, 0, pclk, &conf); + + if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) { + oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800; + oval = 0x00000000; + hval = 0x00000000; + mask = 0xffffffff; + } else + if (!outp->info.location) { + if (outp->info.type == DCB_OUTPUT_DP) + nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk); + oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800; + oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; + hval = 0x00000000; + mask = 0x00000707; + } else { + oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800; + oval = 0x00000001; + hval = 0x00000001; + mask = 0x00000707; + } + + nv_mask(priv, hreg, 0x0000000f, hval); + nv_mask(priv, oreg, mask, oval); } /* If programming a TMDS output on a SOR that can also be configured for @@ -1180,30 +1579,16 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp static void nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) { - struct dcb_output outp; + struct nvkm_output *outp; u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; - if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) { - if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS) - nv50_disp_intr_unk40_0_tmds(priv, &outp); - else - if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) { - u32 soff = (ffs(outp.or) - 1) * 0x08; - u32 ctrl = nv_rd32(priv, 0x610b84 + soff); - u32 datarate; - - switch ((ctrl & 0x000f0000) >> 16) { - case 6: datarate = pclk * 30 / 8; break; - case 5: datarate = pclk * 24 / 8; break; - case 2: - default: - datarate = pclk * 18 / 8; - break; - } + u32 conf; - nouveau_dp_train(&priv->base, priv->pior.dp, - &outp, head, datarate); - } - } + outp = exec_clkcmp(priv, head, 1, pclk, &conf); + if (!outp) + return; + + if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) + nv50_disp_intr_unk40_0_tmds(priv, &outp->info); } void @@ -1211,12 +1596,14 @@ nv50_disp_intr_supervisor(struct work_struct *work) { struct nv50_disp_priv *priv = container_of(work, struct nv50_disp_priv, supervisor); + struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; u32 super = nv_rd32(priv, 0x610030); int head; nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super); if (priv->super & 0x00000010) { + nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); for (head = 0; head < priv->head.nr; head++) { if (!(super & (0x00000020 << head))) continue; @@ -1260,19 +1647,20 @@ nv50_disp_intr(struct nouveau_subdev *subdev) u32 intr0 = nv_rd32(priv, 0x610020); u32 intr1 = nv_rd32(priv, 0x610024); - if (intr0 & 0x001f0000) { - nv50_disp_intr_error(priv); - intr0 &= ~0x001f0000; + while (intr0 & 0x001f0000) { + u32 chid = __ffs(intr0 & 0x001f0000) - 16; + nv50_disp_intr_error(priv, chid); + intr0 &= ~(0x00010000 << chid); } if (intr1 & 0x00000004) { - nouveau_event_trigger(priv->base.vblank, 0); + nouveau_event_trigger(priv->base.vblank, 1, 0); nv_wr32(priv, 0x610024, 0x00000004); intr1 &= ~0x00000004; } if (intr1 & 0x00000008) { - nouveau_event_trigger(priv->base.vblank, 1); + nouveau_event_trigger(priv->base.vblank, 1, 1); nv_wr32(priv, 0x610024, 0x00000008); intr1 &= ~0x00000008; } @@ -1312,17 +1700,27 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->pior.power = nv50_pior_power; - priv->pior.dp = &nv50_pior_dp_func; return 0; } -struct nouveau_oclass -nv50_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv50_disp_outp_sclass[] = { + &nv50_pior_dp_impl.base.base, + NULL +}; + +struct nouveau_oclass * +nv50_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x50), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.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 1ae6ceb5670..1a886472b6f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -8,9 +8,21 @@ #include <core/event.h> #include <engine/dmaobj.h> -#include <engine/disp.h> #include "dport.h" +#include "priv.h" +#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; +}; struct nv50_disp_priv { struct nouveau_disp base; @@ -33,16 +45,18 @@ struct nv50_disp_priv { int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); u32 lvdsconf; - const struct nouveau_dp_func *dp; } sor; struct { int nr; int (*power)(struct nv50_disp_priv *, int ext, u32 data); u8 type[3]; - const struct nouveau_dp_func *dp; } pior; }; +#define HEAD_MTHD(n) (n), (n) + 0x03 + +int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32); + #define DAC_MTHD(n) (n), (n) + 0x03 int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32); @@ -120,28 +134,79 @@ struct nv50_disp_pioc { struct nv50_disp_chan base; }; +struct nv50_disp_mthd_list { + u32 mthd; + u32 addr; + struct { + u32 mthd; + u32 addr; + const char *name; + } data[]; +}; + +struct nv50_disp_mthd_chan { + const char *name; + u32 addr; + struct { + const char *name; + int nr; + const struct nv50_disp_mthd_list *mthd; + } data[]; +}; + extern struct nouveau_ofuncs nv50_disp_mast_ofuncs; +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 const struct nv50_disp_mthd_list nv50_disp_sync_mthd_image; extern struct nouveau_ofuncs nv50_disp_ovly_ofuncs; +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 nouveau_ofuncs nv50_disp_base_ofuncs; 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 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 struct nouveau_omthds nva3_disp_base_omthds[]; +extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan; extern struct nouveau_ofuncs 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 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 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 nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; +extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; + +extern struct nvkm_output_dp_impl nv50_pior_dp_impl; +extern struct nouveau_oclass *nv50_disp_outp_sclass[]; + +extern struct nvkm_output_dp_impl nv94_sor_dp_impl; +int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); +extern struct nouveau_oclass *nv94_disp_outp_sclass[]; + +extern struct nvkm_output_dp_impl nvd0_sor_dp_impl; +extern struct nouveau_oclass *nvd0_disp_outp_sclass[]; + #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index d8c74c0883a..1cc62e43468 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c @@ -29,6 +29,179 @@ #include "nv50.h" +/******************************************************************************* + * EVO master channel object + ******************************************************************************/ + +const struct nv50_disp_mthd_list +nv84_disp_mast_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610bc4 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv84_disp_mast_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x085c, 0x610c5c }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0878, 0x610c50 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x089c, 0x610c68 }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + { 0x0910, 0x610c70 }, + { 0x0914, 0x610c78 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv84_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_mast_mthd_base }, + { "DAC", 3, &nv84_disp_mast_mthd_dac }, + { "SOR", 2, &nv50_disp_mast_mthd_sor }, + { "PIOR", 3, &nv50_disp_mast_mthd_pior }, + { "HEAD", 2, &nv84_disp_mast_mthd_head }, + {} + } +}; + +/******************************************************************************* + * EVO sync channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nv84_disp_sync_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00c4, 0x610800 }, + { 0x00c8, 0x61080c }, + { 0x00cc, 0x610818 }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x00fc, 0x610824 }, + { 0x0100, 0x610894 }, + { 0x0104, 0x61082c }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv84_disp_sync_mthd_chan = { + .name = "Base", + .addr = 0x000540, + .data = { + { "Global", 1, &nv84_disp_sync_mthd_base }, + { "Image", 2, &nv50_disp_sync_mthd_image }, + {} + } +}; + +/******************************************************************************* + * EVO overlay channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nv84_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv84_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &nv84_disp_ovly_mthd_base }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nv84_disp_sclass[] = { { NV84_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -41,6 +214,7 @@ nv84_disp_sclass[] = { 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 }, @@ -58,6 +232,10 @@ nv84_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -86,17 +264,21 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hdmi = nv84_hdmi_ctrl; priv->pior.power = nv50_pior_power; - priv->pior.dp = &nv50_pior_dp_func; return 0; } -struct nouveau_oclass -nv84_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x82), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv84_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x82), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv84_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.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 a66f949c1f8..4f718a9f5ae 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c @@ -29,6 +29,38 @@ #include "nv50.h" +/******************************************************************************* + * EVO master channel object + ******************************************************************************/ + +const struct nv50_disp_mthd_list +nv94_disp_mast_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610794 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv94_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_mast_mthd_base }, + { "DAC", 3, &nv84_disp_mast_mthd_dac }, + { "SOR", 4, &nv94_disp_mast_mthd_sor }, + { "PIOR", 3, &nv50_disp_mast_mthd_pior }, + { "HEAD", 2, &nv84_disp_mast_mthd_head }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nv94_disp_sclass[] = { { NV94_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -41,9 +73,11 @@ nv94_disp_sclass[] = { 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 }, @@ -58,6 +92,10 @@ nv94_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -85,19 +123,29 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hdmi = nv84_hdmi_ctrl; - priv->sor.dp = &nv94_sor_dp_func; priv->pior.power = nv50_pior_power; - priv->pior.dp = &nv50_pior_dp_func; return 0; } -struct nouveau_oclass -nv94_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x88), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv94_disp_outp_sclass[] = { + &nv50_pior_dp_impl.base.base, + &nv94_sor_dp_impl.base.base, + NULL +}; + +struct nouveau_oclass * +nv94_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x88), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv94_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.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 6cf8eefac36..6237a9a36f7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c @@ -29,6 +29,55 @@ #include "nv50.h" +/******************************************************************************* + * EVO overlay channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nva0_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00b0, 0x610c98 }, + { 0x00b4, 0x610ca4 }, + { 0x00b8, 0x610cac }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nva0_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &nva0_disp_ovly_mthd_base }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nva0_disp_sclass[] = { { NVA0_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -45,6 +94,10 @@ nva0_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -73,17 +126,21 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hdmi = nv84_hdmi_ctrl; priv->pior.power = nv50_pior_power; - priv->pior.dp = &nv50_pior_dp_func; return 0; } -struct nouveau_oclass -nva0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x83), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nva0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x83), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nva0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.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 b75413169ea..019124d4782 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c @@ -29,6 +29,10 @@ #include "nv50.h" +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nva3_disp_sclass[] = { { NVA3_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -39,12 +43,14 @@ nva3_disp_sclass[] = { {} }; -struct nouveau_omthds +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 }, @@ -59,6 +65,10 @@ nva3_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -87,19 +97,22 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nva3_hda_eld; priv->sor.hdmi = nva3_hdmi_ctrl; - priv->sor.dp = &nv94_sor_dp_func; priv->pior.power = nv50_pior_power; - priv->pior.dp = &nv50_pior_dp_func; return 0; } -struct nouveau_oclass -nva3_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x85), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nva3_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x85), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nva3_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.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 52dd7a1db72..fa30d8196f3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -124,6 +124,146 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend) * EVO master channel object ******************************************************************************/ +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x660080 }, + { 0x0084, 0x660084 }, + { 0x0088, 0x660088 }, + { 0x008c, 0x000000 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_dac = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0180, 0x660180 }, + { 0x0184, 0x660184 }, + { 0x0188, 0x660188 }, + { 0x0190, 0x660190 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_sor = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0200, 0x660200 }, + { 0x0204, 0x660204 }, + { 0x0208, 0x660208 }, + { 0x0210, 0x660210 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_pior = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0300, 0x660300 }, + { 0x0304, 0x660304 }, + { 0x0308, 0x660308 }, + { 0x0310, 0x660310 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nvd0_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nvd0_disp_mast_mthd_base }, + { "DAC", 3, &nvd0_disp_mast_mthd_dac }, + { "SOR", 8, &nvd0_disp_mast_mthd_sor }, + { "PIOR", 4, &nvd0_disp_mast_mthd_pior }, + { "HEAD", 4, &nvd0_disp_mast_mthd_head }, + {} + } +}; + static int nvd0_disp_mast_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -216,6 +356,81 @@ nvd0_disp_mast_ofuncs = { * EVO sync channel objects ******************************************************************************/ +static const struct nv50_disp_mthd_list +nvd0_disp_sync_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x661080 }, + { 0x0084, 0x661084 }, + { 0x0088, 0x661088 }, + { 0x008c, 0x66108c }, + { 0x0090, 0x661090 }, + { 0x0094, 0x661094 }, + { 0x00a0, 0x6610a0 }, + { 0x00a4, 0x6610a4 }, + { 0x00c0, 0x6610c0 }, + { 0x00c4, 0x6610c4 }, + { 0x00c8, 0x6610c8 }, + { 0x00cc, 0x6610cc }, + { 0x00e0, 0x6610e0 }, + { 0x00e4, 0x6610e4 }, + { 0x00e8, 0x6610e8 }, + { 0x00ec, 0x6610ec }, + { 0x00fc, 0x6610fc }, + { 0x0100, 0x661100 }, + { 0x0104, 0x661104 }, + { 0x0108, 0x661108 }, + { 0x010c, 0x66110c }, + { 0x0110, 0x661110 }, + { 0x0114, 0x661114 }, + { 0x0118, 0x661118 }, + { 0x011c, 0x66111c }, + { 0x0130, 0x661130 }, + { 0x0134, 0x661134 }, + { 0x0138, 0x661138 }, + { 0x013c, 0x66113c }, + { 0x0140, 0x661140 }, + { 0x0144, 0x661144 }, + { 0x0148, 0x661148 }, + { 0x014c, 0x66114c }, + { 0x0150, 0x661150 }, + { 0x0154, 0x661154 }, + { 0x0158, 0x661158 }, + { 0x015c, 0x66115c }, + { 0x0160, 0x661160 }, + { 0x0164, 0x661164 }, + { 0x0168, 0x661168 }, + { 0x016c, 0x66116c }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nvd0_disp_sync_mthd_image = { + .mthd = 0x0400, + .addr = 0x000400, + .data = { + { 0x0400, 0x661400 }, + { 0x0404, 0x661404 }, + { 0x0408, 0x661408 }, + { 0x040c, 0x66140c }, + { 0x0410, 0x661410 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nvd0_disp_sync_mthd_chan = { + .name = "Base", + .addr = 0x001000, + .data = { + { "Global", 1, &nvd0_disp_sync_mthd_base }, + { "Image", 2, &nvd0_disp_sync_mthd_image }, + {} + } +}; + static int nvd0_disp_sync_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -256,6 +471,68 @@ nvd0_disp_sync_ofuncs = { * EVO overlay channel objects ******************************************************************************/ +static const struct nv50_disp_mthd_list +nvd0_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nvd0_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x001000, + .data = { + { "Global", 1, &nvd0_disp_ovly_mthd_base }, + {} + } +}; + static int nvd0_disp_ovly_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -440,14 +717,44 @@ nvd0_disp_curs_ofuncs = { * 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 head) +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 head) +nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head) { nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); } @@ -541,6 +848,15 @@ nvd0_disp_base_init(struct nouveau_object *object) nv_wr32(priv, 0x6100a0, 0x00000000); nv_wr32(priv, 0x6100b0, 0x00000307); + /* disable underflow reporting, preventing an intermittent issue + * on some nve4 boards where the production vbios left this + * setting enabled by default. + * + * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt + */ + for (i = 0; i < priv->head.nr; i++) + nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); + return 0; } @@ -564,9 +880,25 @@ nvd0_disp_base_ofuncs = { .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 }, + {}, +}; + static struct nouveau_oclass nvd0_disp_base_oclass[] = { - { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds }, + { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, {} }; @@ -584,19 +916,20 @@ nvd0_disp_sclass[] = { * Display engine implementation ******************************************************************************/ -static u16 -exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, - struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, +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, struct nvbios_outp *info) { struct nouveau_bios *bios = nouveau_bios(priv); - u16 mask, type, data; + struct nvkm_output *outp; + u16 mask, type; - if (outp < 4) { + if (or < 4) { type = DCB_OUTPUT_ANALOG; mask = 0; } else { - outp -= 4; + or -= 4; switch (ctrl & 0x00000f00) { case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; @@ -608,101 +941,106 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); return 0x0000; } - dcb->sorconf.link = mask; } mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << outp; + mask |= 0x0001 << or; mask |= 0x0100 << head; - data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); - if (!data) - return 0x0000; + list_for_each_entry(outp, &priv->base.outp, head) { + if ((outp->info.hasht & 0xff) == type && + (outp->info.hashm & mask) == mask) { + *data = nvbios_outp_match(bios, outp->info.hasht, + outp->info.hashm, + ver, hdr, cnt, len, info); + if (!*data) + return NULL; + return outp; + } + } - return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); + return NULL; } -static bool +static struct nvkm_output * exec_script(struct nv50_disp_priv *priv, int head, int id) { struct nouveau_bios *bios = nouveau_bios(priv); + struct nvkm_output *outp; struct nvbios_outp info; - struct dcb_output dcb; u8 ver, hdr, cnt, len; - u32 ctrl = 0x00000000; - u16 data; - int outp; + u32 data, ctrl = 0; + int or; - for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { - ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20)); + for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { + ctrl = nv_rd32(priv, 0x640180 + (or * 0x20)); if (ctrl & (1 << head)) break; } - if (outp == 8) - return false; + if (or == 8) + return NULL; - data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); - if (data) { + outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); + if (outp) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[id], - .outp = &dcb, + .outp = &outp->info, .crtc = head, .execute = 1, }; - return nvbios_exec(&init) == 0; + nvbios_exec(&init); } - return false; + return outp; } -static u32 -exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, - u32 pclk, struct dcb_output *dcb) +static struct nvkm_output * +exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) { struct nouveau_bios *bios = nouveau_bios(priv); + struct nvkm_output *outp; struct nvbios_outp info1; struct nvbios_ocfg info2; u8 ver, hdr, cnt, len; - u32 ctrl = 0x00000000; - u32 data, conf = ~0; - int outp; + u32 data, ctrl = 0; + int or; - for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { - ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20)); + for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { + ctrl = nv_rd32(priv, 0x660180 + (or * 0x20)); if (ctrl & (1 << head)) break; } - if (outp == 8) - return false; + if (or == 8) + return NULL; - data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); - if (data == 0x0000) - return conf; + outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); + if (!outp) + return NULL; - switch (dcb->type) { + switch (outp->info.type) { case DCB_OUTPUT_TMDS: - conf = (ctrl & 0x00000f00) >> 8; + *conf = (ctrl & 0x00000f00) >> 8; if (pclk >= 165000) - conf |= 0x0100; + *conf |= 0x0100; break; case DCB_OUTPUT_LVDS: - conf = priv->sor.lvdsconf; + *conf = priv->sor.lvdsconf; break; case DCB_OUTPUT_DP: - conf = (ctrl & 0x00000f00) >> 8; + *conf = (ctrl & 0x00000f00) >> 8; break; case DCB_OUTPUT_ANALOG: default: - conf = 0x00ff; + *conf = 0x00ff; break; } - data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); + data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); if (data && id < 0xff) { data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { @@ -710,7 +1048,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, .subdev = nv_subdev(priv), .bios = bios, .offset = data, - .outp = dcb, + .outp = &outp->info, .crtc = head, .execute = 1, }; @@ -719,7 +1057,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, } } - return conf; + return outp; } static void @@ -731,7 +1069,23 @@ nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head) static void nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head) { - exec_script(priv, head, 2); + struct nvkm_output *outp = exec_script(priv, head, 2); + + /* see note in nv50_disp_intr_unk20_0() */ + if (outp && outp->info.type == DCB_OUTPUT_DP) { + struct nvkm_output_dp *outpdp = (void *)outp; + struct nvbios_init init = { + .subdev = nv_subdev(priv), + .bios = nouveau_bios(priv), + .outp = &outp->info, + .crtc = head, + .offset = outpdp->info.script[4], + .execute = 1, + }; + + nvbios_exec(&init); + atomic_set(&outpdp->lt.done, 0); + } } static void @@ -793,49 +1147,52 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, static void nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) { - struct dcb_output outp; + struct nvkm_output *outp; u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; - u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); - if (conf != ~0) { - u32 addr, data; - - if (outp.type == DCB_OUTPUT_DP) { - u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300)); - switch ((sync & 0x000003c0) >> 6) { - case 6: pclk = pclk * 30 / 8; break; - case 5: pclk = pclk * 24 / 8; break; - case 2: - default: - pclk = pclk * 18 / 8; - break; - } - - nouveau_dp_train(&priv->base, priv->sor.dp, - &outp, head, pclk); + u32 conf, addr, data; + + outp = exec_clkcmp(priv, head, 0xff, pclk, &conf); + if (!outp) + return; + + /* see note in nv50_disp_intr_unk20_2() */ + if (outp->info.type == DCB_OUTPUT_DP) { + u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300)); + switch ((sync & 0x000003c0) >> 6) { + case 6: pclk = pclk * 30; break; + case 5: pclk = pclk * 24; break; + case 2: + default: + pclk = pclk * 18; + break; } - exec_clkcmp(priv, head, 0, pclk, &outp); + if (nvkm_output_dp_train(outp, pclk, true)) + ERR("link not trained before attach\n"); + } - if (outp.type == DCB_OUTPUT_ANALOG) { - addr = 0x612280 + (ffs(outp.or) - 1) * 0x800; - data = 0x00000000; - } else { - if (outp.type == DCB_OUTPUT_DP) - nvd0_disp_intr_unk2_2_tu(priv, head, &outp); - addr = 0x612300 + (ffs(outp.or) - 1) * 0x800; - data = (conf & 0x0100) ? 0x00000101 : 0x00000000; - } + exec_clkcmp(priv, head, 0, pclk, &conf); - nv_mask(priv, addr, 0x00000707, data); + if (outp->info.type == DCB_OUTPUT_ANALOG) { + addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; + data = 0x00000000; + } else { + if (outp->info.type == DCB_OUTPUT_DP) + nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info); + addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; + data = (conf & 0x0100) ? 0x00000101 : 0x00000000; } + + nv_mask(priv, addr, 0x00000707, data); } static void nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) { - struct dcb_output outp; u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; - exec_clkcmp(priv, head, 1, pclk, &outp); + u32 conf; + + exec_clkcmp(priv, head, 1, pclk, &conf); } void @@ -843,19 +1200,22 @@ nvd0_disp_intr_supervisor(struct work_struct *work) { struct nv50_disp_priv *priv = container_of(work, struct nv50_disp_priv, supervisor); + struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; u32 mask[4]; int head; - nv_debug(priv, "supervisor %08x\n", priv->super); + nv_debug(priv, "supervisor %d\n", ffs(priv->super)); for (head = 0; head < priv->head.nr; head++) { mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800)); nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]); } if (priv->super & 0x00000001) { + nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 1.0 - head %d\n", head); nvd0_disp_intr_unk1_0(priv, head); } } else @@ -863,16 +1223,19 @@ nvd0_disp_intr_supervisor(struct work_struct *work) for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 2.0 - head %d\n", head); nvd0_disp_intr_unk2_0(priv, head); } for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00010000)) continue; + nv_debug(priv, "supervisor 2.1 - head %d\n", head); nvd0_disp_intr_unk2_1(priv, head); } for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 2.2 - head %d\n", head); nvd0_disp_intr_unk2_2(priv, head); } } else @@ -880,6 +1243,7 @@ nvd0_disp_intr_supervisor(struct work_struct *work) for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 3.0 - head %d\n", head); nvd0_disp_intr_unk4_0(priv, head); } } @@ -889,6 +1253,53 @@ nvd0_disp_intr_supervisor(struct work_struct *work) nv_wr32(priv, 0x6101d0, 0x80000000); } +static void +nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid) +{ + const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; + u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12)); + u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12)); + u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12)); + + nv_error(priv, "chid %d mthd 0x%04x data 0x%08x " + "0x%08x 0x%08x\n", + chid, (mthd & 0x0000ffc), data, mthd, unkn); + + if (chid == 0) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, + impl->mthd.core); + break; + default: + break; + } + } else + if (chid <= 4) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, + impl->mthd.base); + break; + default: + break; + } + } else + if (chid <= 8) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5, + impl->mthd.ovly); + break; + default: + break; + } + } + + nv_wr32(priv, 0x61009c, (1 << chid)); + nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000); +} + void nvd0_disp_intr(struct nouveau_subdev *subdev) { @@ -905,18 +1316,8 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) if (intr & 0x00000002) { u32 stat = nv_rd32(priv, 0x61009c); int chid = ffs(stat) - 1; - if (chid >= 0) { - u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12)); - u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12)); - u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12)); - - nv_error(priv, "chid %d mthd 0x%04x data 0x%08x " - "0x%08x 0x%08x\n", - chid, (mthd & 0x0000ffc), data, mthd, unkn); - nv_wr32(priv, 0x61009c, (1 << chid)); - nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000); - } - + if (chid >= 0) + nvd0_disp_intr_error(priv, chid); intr &= ~0x00000002; } @@ -942,7 +1343,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, i); + nouveau_event_trigger(priv->base.vblank, 1, i); nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); nv_rd32(priv, 0x6100c0 + (i * 0x800)); } @@ -958,9 +1359,6 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, int heads = nv_rd32(parent, 0x022448); int ret; - if (nv_rd32(parent, 0x022500) & 0x00000001) - return -ENODEV; - ret = nouveau_disp_create(parent, engine, oclass, heads, "PDISP", "display", &priv); *pobject = nv_object(priv); @@ -980,17 +1378,27 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hdmi = nvd0_hdmi_ctrl; - priv->sor.dp = &nvd0_sor_dp_func; return 0; } -struct nouveau_oclass -nvd0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x90), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nvd0_disp_outp_sclass[] = { + &nvd0_sor_dp_impl.base.base, + NULL +}; + +struct nouveau_oclass * +nvd0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x90), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvd0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.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 fb1fe6ae5e7..11328e3f5df 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c @@ -29,6 +29,175 @@ #include "nv50.h" +/******************************************************************************* + * EVO master channel object + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nve0_disp_mast_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x047c, 0x66047c }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x0488, 0x660488 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04a0, 0x6604a0 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x0520, 0x660520 }, + { 0x0524, 0x660524 }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nve0_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nvd0_disp_mast_mthd_base }, + { "DAC", 3, &nvd0_disp_mast_mthd_dac }, + { "SOR", 8, &nvd0_disp_mast_mthd_sor }, + { "PIOR", 4, &nvd0_disp_mast_mthd_pior }, + { "HEAD", 4, &nve0_disp_mast_mthd_head }, + {} + } +}; + +/******************************************************************************* + * EVO overlay channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nve0_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00c4, 0x6650c4 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0404, 0x665404 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nve0_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x001000, + .data = { + { "Global", 1, &nve0_disp_ovly_mthd_base }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nve0_disp_sclass[] = { { NVE0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, @@ -41,10 +210,14 @@ nve0_disp_sclass[] = { static struct nouveau_oclass nve0_disp_base_oclass[] = { - { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds }, + { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -54,9 +227,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, int heads = nv_rd32(parent, 0x022448); int ret; - if (nv_rd32(parent, 0x022500) & 0x00000001) - return -ENODEV; - ret = nouveau_disp_create(parent, engine, oclass, heads, "PDISP", "display", &priv); *pobject = nv_object(priv); @@ -76,17 +246,21 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hdmi = nvd0_hdmi_ctrl; - priv->sor.dp = &nvd0_sor_dp_func; return 0; } -struct nouveau_oclass -nve0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x91), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nve0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x91), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nve0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.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 42aa6b97dbe..104388081d7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c @@ -29,6 +29,10 @@ #include "nv50.h" +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nvf0_disp_sclass[] = { { NVF0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, @@ -41,10 +45,14 @@ nvf0_disp_sclass[] = { static struct nouveau_oclass nvf0_disp_base_oclass[] = { - { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds }, + { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -54,9 +62,6 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, int heads = nv_rd32(parent, 0x022448); int ret; - if (nv_rd32(parent, 0x022500) & 0x00000001) - return -ENODEV; - ret = nouveau_disp_create(parent, engine, oclass, heads, "PDISP", "display", &priv); *pobject = nv_object(priv); @@ -76,17 +81,21 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hdmi = nvd0_hdmi_ctrl; - priv->sor.dp = &nvd0_sor_dp_func; return 0; } -struct nouveau_oclass -nvf0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x92), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nvf0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x92), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvf0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .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, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c new file mode 100644 index 00000000000..ad9ba7ccec7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c @@ -0,0 +1,137 @@ +/* + * 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 <subdev/i2c.h> +#include <subdev/bios.h> +#include <subdev/bios/conn.h> + +#include "outp.h" + +int +_nvkm_output_fini(struct nouveau_object *object, bool suspend) +{ + struct nvkm_output *outp = (void *)object; + nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend); + return nouveau_object_fini(&outp->base, suspend); +} + +int +_nvkm_output_init(struct nouveau_object *object) +{ + struct nvkm_output *outp = (void *)object; + int ret = nouveau_object_init(&outp->base); + if (ret == 0) + nv_ofuncs(outp->conn)->init(nv_object(outp->conn)); + return 0; +} + +void +_nvkm_output_dtor(struct nouveau_object *object) +{ + struct nvkm_output *outp = (void *)object; + list_del(&outp->head); + nouveau_object_ref(NULL, (void *)&outp->conn); + nouveau_object_destroy(&outp->base); +} + +int +nvkm_output_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + struct dcb_output *dcbE, int index, + int length, void **pobject) +{ + struct nouveau_bios *bios = nouveau_bios(engine); + struct nouveau_i2c *i2c = nouveau_i2c(parent); + struct nouveau_disp *disp = (void *)engine; + struct nvbios_connE connE; + struct nvkm_output *outp; + u8 ver, hdr; + u32 data; + int ret; + + ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject); + outp = *pobject; + if (ret) + return ret; + + outp->info = *dcbE; + outp->index = index; + + 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 ? + dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index, + dcbE->bus, dcbE->heads); + + outp->port = i2c->find(i2c, outp->info.i2c_index); + outp->edid = outp->port; + + data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); + if (!data) { + DBG("vbios connector data not found\n"); + memset(&connE, 0x00, sizeof(connE)); + connE.type = DCB_CONNECTOR_NONE; + } + + ret = nouveau_object_ctor(parent, engine, nvkm_connector_oclass, + &connE, outp->info.connector, + (struct nouveau_object **)&outp->conn); + if (ret < 0) { + ERR("error %d creating connector, disabling\n", ret); + return ret; + } + + list_add_tail(&outp->head, &disp->outp); + return 0; +} + +int +_nvkm_output_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *dcbE, u32 index, + struct nouveau_object **pobject) +{ + struct nvkm_output *outp; + int ret; + + ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp); + *pobject = nv_object(outp); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass * +nvkm_output_oclass = &(struct nvkm_output_impl) { + .base = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_output_ctor, + .dtor = _nvkm_output_dtor, + .init = _nvkm_output_init, + .fini = _nvkm_output_fini, + }, + }, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h new file mode 100644 index 00000000000..bc76fbf8571 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h @@ -0,0 +1,59 @@ +#ifndef __NVKM_DISP_OUTP_H__ +#define __NVKM_DISP_OUTP_H__ + +#include "priv.h" + +struct nvkm_output { + struct nouveau_object base; + struct list_head head; + + struct dcb_output info; + int index; + + struct nouveau_i2c_port *port; + struct nouveau_i2c_port *edid; + + struct nvkm_connector *conn; +}; + +#define nvkm_output_create(p,e,c,b,i,d) \ + nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) +#define nvkm_output_destroy(d) ({ \ + struct nvkm_output *_outp = (d); \ + _nvkm_output_dtor(nv_object(_outp)); \ +}) +#define nvkm_output_init(d) ({ \ + struct nvkm_output *_outp = (d); \ + _nvkm_output_init(nv_object(_outp)); \ +}) +#define nvkm_output_fini(d,s) ({ \ + struct nvkm_output *_outp = (d); \ + _nvkm_output_fini(nv_object(_outp), (s)); \ +}) + +int nvkm_output_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, struct dcb_output *, + int, int, void **); + +int _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nvkm_output_dtor(struct nouveau_object *); +int _nvkm_output_init(struct nouveau_object *); +int _nvkm_output_fini(struct nouveau_object *, bool); + +struct nvkm_output_impl { + struct nouveau_oclass base; +}; + +#ifndef MSG +#define MSG(l,f,a...) do { \ + struct nvkm_output *_outp = (void *)outp; \ + nv_##l(nv_object(outp)->engine, "%02x:%04x:%04x: "f, _outp->index, \ + _outp->info.hasht, _outp->info.hashm, ##a); \ +} while(0) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c new file mode 100644 index 00000000000..eb2d7789555 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c @@ -0,0 +1,278 @@ +/* + * 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 <subdev/i2c.h> + +#include "outpdp.h" +#include "conn.h" +#include "dport.h" + +int +nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) +{ + struct nvkm_output_dp *outp = (void *)base; + bool retrain = true; + u8 link[2], stat[3]; + u32 linkrate; + int ret, i; + + /* check that the link is trained at a high enough rate */ + ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2); + if (ret) { + DBG("failed to read link config, assuming no sink\n"); + goto done; + } + + linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET); + linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ + datarate = (datarate + 9) / 10; /* -> decakilobits */ + if (linkrate < datarate) { + DBG("link not trained at sufficient rate\n"); + goto done; + } + + /* check that link is still trained */ + ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3); + if (ret) { + DBG("failed to read link status, assuming no sink\n"); + goto done; + } + + if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) { + for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) { + u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f; + if (!(lane & DPCD_LS02_LANE0_CR_DONE) || + !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || + !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { + DBG("lane %d not equalised\n", lane); + goto done; + } + } + retrain = false; + } else { + DBG("no inter-lane alignment\n"); + } + +done: + if (retrain || !atomic_read(&outp->lt.done)) { + /* no sink, but still need to configure source */ + if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) { + outp->dpcd[DPCD_RC01_MAX_LINK_RATE] = + outp->base.info.dpconf.link_bw; + outp->dpcd[DPCD_RC02] = + outp->base.info.dpconf.link_nr; + } + atomic_set(&outp->lt.done, 0); + schedule_work(&outp->lt.work); + } else { + nouveau_event_get(outp->irq); + } + + if (wait) { + if (!wait_event_timeout(outp->lt.wait, + atomic_read(&outp->lt.done), + msecs_to_jiffies(2000))) + ret = -ETIMEDOUT; + } + + return ret; +} + +static void +nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present) +{ + struct nouveau_i2c_port *port = outp->base.edid; + if (present) { + if (!outp->present) { + nouveau_i2c(port)->acquire_pad(port, 0); + DBG("aux power -> always\n"); + outp->present = true; + } + nvkm_output_dp_train(&outp->base, 0, true); + } else { + if (outp->present) { + nouveau_i2c(port)->release_pad(port); + DBG("aux power -> demand\n"); + outp->present = false; + } + atomic_set(&outp->lt.done, 0); + } +} + +static void +nvkm_output_dp_detect(struct nvkm_output_dp *outp) +{ + struct nouveau_i2c_port *port = outp->base.edid; + int ret = nouveau_i2c(port)->acquire_pad(port, 0); + if (ret == 0) { + ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV, + outp->dpcd, sizeof(outp->dpcd)); + nvkm_output_dp_enable(outp, ret == 0); + nouveau_i2c(port)->release_pad(port); + } +} + +static void +nvkm_output_dp_service_work(struct work_struct *work) +{ + 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; + } + + nouveau_event_trigger(disp->hpd, send, outp->base.info.connector); +} + +static int +nvkm_output_dp_service(void *data, u32 type, int index) +{ + struct nvkm_output_dp *outp = data; + DBG("HPD: %d\n", type); + atomic_or(type, &outp->pending); + schedule_work(&outp->work); + return NVKM_EVENT_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_output_dp_enable(outp, false); + return nvkm_output_fini(&outp->base, suspend); +} + +int +_nvkm_output_dp_init(struct nouveau_object *object) +{ + struct nvkm_output_dp *outp = (void *)object; + nvkm_output_dp_detect(outp); + return nvkm_output_init(&outp->base); +} + +void +_nvkm_output_dp_dtor(struct nouveau_object *object) +{ + struct nvkm_output_dp *outp = (void *)object; + nouveau_event_ref(NULL, &outp->irq); + nvkm_output_destroy(&outp->base); +} + +int +nvkm_output_dp_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + struct dcb_output *info, int index, + int length, void **pobject) +{ + struct nouveau_bios *bios = nouveau_bios(parent); + struct nouveau_i2c *i2c = nouveau_i2c(parent); + struct nvkm_output_dp *outp; + u8 hdr, cnt, len; + u32 data; + int ret; + + ret = nvkm_output_create_(parent, engine, oclass, info, index, + length, pobject); + outp = *pobject; + if (ret) + return ret; + + nouveau_event_ref(NULL, &outp->base.conn->hpd.event); + + /* access to the aux channel is not optional... */ + if (!outp->base.edid) { + ERR("aux channel not found\n"); + return -ENODEV; + } + + /* nor is the bios data for this output... */ + data = nvbios_dpout_match(bios, outp->base.info.hasht, + outp->base.info.hashm, &outp->version, + &hdr, &cnt, &len, &outp->info); + if (!data) { + ERR("no bios dp data\n"); + return -ENODEV; + } + + DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len); + + /* link training */ + INIT_WORK(&outp->lt.work, nouveau_dp_train); + init_waitqueue_head(&outp->lt.wait); + 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); + 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); + if (ret) { + ERR("error monitoring aux hpd events: %d\n", ret); + return ret; + } + + return 0; +} + +int +_nvkm_output_dp_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *info, u32 index, + struct nouveau_object **pobject) +{ + struct nvkm_output_dp *outp; + int ret; + + ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); + *pobject = nv_object(outp); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h new file mode 100644 index 00000000000..ff33ba12cb6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h @@ -0,0 +1,65 @@ +#ifndef __NVKM_DISP_OUTP_DP_H__ +#define __NVKM_DISP_OUTP_DP_H__ + +#include <subdev/bios.h> +#include <subdev/bios/dp.h> + +#include "outp.h" + +struct nvkm_output_dp { + struct nvkm_output base; + + struct nvbios_dpout info; + u8 version; + + struct nouveau_eventh *irq; + struct nouveau_eventh *hpd; + struct work_struct work; + atomic_t pending; + bool present; + u8 dpcd[16]; + + struct { + struct work_struct work; + wait_queue_head_t wait; + atomic_t done; + } lt; +}; + +#define nvkm_output_dp_create(p,e,c,b,i,d) \ + nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) +#define nvkm_output_dp_destroy(d) ({ \ + struct nvkm_output_dp *_outp = (d); \ + _nvkm_output_dp_dtor(nv_object(_outp)); \ +}) +#define nvkm_output_dp_init(d) ({ \ + struct nvkm_output_dp *_outp = (d); \ + _nvkm_output_dp_init(nv_object(_outp)); \ +}) +#define nvkm_output_dp_fini(d,s) ({ \ + struct nvkm_output_dp *_outp = (d); \ + _nvkm_output_dp_fini(nv_object(_outp), (s)); \ +}) + +int nvkm_output_dp_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, struct dcb_output *, + int, int, void **); + +int _nvkm_output_dp_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nvkm_output_dp_dtor(struct nouveau_object *); +int _nvkm_output_dp_init(struct nouveau_object *); +int _nvkm_output_dp_fini(struct nouveau_object *, bool); + +struct nvkm_output_dp_impl { + struct nvkm_output_impl base; + int (*pattern)(struct nvkm_output_dp *, int); + int (*lnk_pwr)(struct nvkm_output_dp *, int nr); + int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); + int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); +}; + +int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c index 2c8ce351b52..fe0f256f11b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c @@ -33,68 +33,107 @@ #include "nv50.h" /****************************************************************************** - * DisplayPort + * TMDS *****************************************************************************/ -static struct nouveau_i2c_port * -nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp) + +static int +nv50_pior_tmds_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *info, u32 index, + struct nouveau_object **pobject) { - struct nouveau_i2c *i2c = nouveau_i2c(disp); - return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); + struct nouveau_i2c *i2c = nouveau_i2c(parent); + struct nvkm_output *outp; + int ret; + + ret = nvkm_output_create(parent, engine, oclass, info, index, &outp); + *pobject = nv_object(outp); + if (ret) + return ret; + + outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev)); + return 0; } +struct nvkm_output_impl +nv50_pior_tmds_impl = { + .base.handle = DCB_OUTPUT_TMDS | 0x0100, + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_pior_tmds_ctor, + .dtor = _nvkm_output_dtor, + .init = _nvkm_output_init, + .fini = _nvkm_output_fini, + }, +}; + +/****************************************************************************** + * DisplayPort + *****************************************************************************/ + static int -nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int pattern) +nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nouveau_i2c_port *port; - int ret = -EINVAL; - - port = nv50_pior_dp_find(disp, outp); - if (port) { - if (port->func->pattern) - ret = port->func->pattern(port, pattern); - else - ret = 0; - } - - return ret; + struct nouveau_i2c_port *port = outp->base.edid; + if (port && port->func->pattern) + return port->func->pattern(port, pattern); + return port ? 0 : -ENODEV; } static int -nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane_nr, int link_bw, bool enh) +nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nouveau_i2c_port *port; - int ret = -EINVAL; + return 0; +} - port = nv50_pior_dp_find(disp, outp); +static int +nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) +{ + struct nouveau_i2c_port *port = outp->base.edid; if (port && port->func->lnk_ctl) - ret = port->func->lnk_ctl(port, lane_nr, link_bw, enh); + return port->func->lnk_ctl(port, nr, bw, ef); + return port ? 0 : -ENODEV; +} - return ret; +static int +nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) +{ + struct nouveau_i2c_port *port = outp->base.edid; + if (port && port->func->drv_ctl) + return port->func->drv_ctl(port, ln, vs, pe); + return port ? 0 : -ENODEV; } static int -nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane, int vsw, int pre) +nv50_pior_dp_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *info, u32 index, + struct nouveau_object **pobject) { - struct nouveau_i2c_port *port; - int ret = -EINVAL; - - port = nv50_pior_dp_find(disp, outp); - if (port) { - if (port->func->drv_ctl) - ret = port->func->drv_ctl(port, lane, vsw, pre); - else - ret = 0; - } + struct nouveau_i2c *i2c = nouveau_i2c(parent); + struct nvkm_output_dp *outp; + int ret; - return ret; + ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); + *pobject = nv_object(outp); + if (ret) + return ret; + + outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX( + outp->base.info.extdev)); + return 0; } -const struct nouveau_dp_func -nv50_pior_dp_func = { +struct nvkm_output_dp_impl +nv50_pior_dp_impl = { + .base.base.handle = DCB_OUTPUT_DP | 0x0010, + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_pior_dp_ctor, + .dtor = _nvkm_output_dp_dtor, + .init = _nvkm_output_dp_init, + .fini = _nvkm_output_dp_fini, + }, .pattern = nv50_pior_dp_pattern, + .lnk_pwr = nv50_pior_dp_lnk_pwr, .lnk_ctl = nv50_pior_dp_lnk_ctl, .drv_ctl = nv50_pior_dp_drv_ctl, }; @@ -102,6 +141,7 @@ nv50_pior_dp_func = { /****************************************************************************** * General PIOR handling *****************************************************************************/ + int nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data) { diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h new file mode 100644 index 00000000000..26e9a42569c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h @@ -0,0 +1,42 @@ +#ifndef __NVKM_DISP_PRIV_H__ +#define __NVKM_DISP_PRIV_H__ + +#include <subdev/bios.h> +#include <subdev/bios/dcb.h> +#include <subdev/bios/conn.h> + +#include <engine/disp.h> + +struct nouveau_disp_impl { + struct nouveau_oclass base; + struct nouveau_oclass **outp; + struct nouveau_oclass **conn; +}; + +#define nouveau_disp_create(p,e,c,h,i,x,d) \ + nouveau_disp_create_((p), (e), (c), (h), (i), (x), \ + sizeof(**d), (void **)d) +#define nouveau_disp_destroy(d) ({ \ + struct nouveau_disp *disp = (d); \ + _nouveau_disp_dtor(nv_object(disp)); \ +}) +#define nouveau_disp_init(d) ({ \ + struct nouveau_disp *disp = (d); \ + _nouveau_disp_init(nv_object(disp)); \ +}) +#define nouveau_disp_fini(d,s) ({ \ + struct nouveau_disp *disp = (d); \ + _nouveau_disp_fini(nv_object(disp), (s)); \ +}) + +int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int heads, + const char *, const char *, int, void **); +void _nouveau_disp_dtor(struct nouveau_object *); +int _nouveau_disp_init(struct nouveau_object *); +int _nouveau_disp_fini(struct nouveau_object *, bool); + +extern struct nouveau_oclass *nvkm_output_oclass; +extern struct nouveau_oclass *nvkm_connector_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c index 526b7524289..7a1ebdfa9e1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c @@ -47,8 +47,12 @@ 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; @@ -56,6 +60,13 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) 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: @@ -71,6 +82,24 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) 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); } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c index 7ec4ee83fb6..05487cda84a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c @@ -29,19 +29,21 @@ #include <subdev/bios/dcb.h> #include <subdev/bios/dp.h> #include <subdev/bios/init.h> +#include <subdev/timer.h> #include "nv50.h" +#include "outpdp.h" static inline u32 -nv94_sor_soff(struct dcb_output *outp) +nv94_sor_soff(struct nvkm_output_dp *outp) { - return (ffs(outp->or) - 1) * 0x800; + return (ffs(outp->base.info.or) - 1) * 0x800; } static inline u32 -nv94_sor_loff(struct dcb_output *outp) +nv94_sor_loff(struct nvkm_output_dp *outp) { - return nv94_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; + return nv94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } static inline u32 @@ -55,73 +57,96 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) } static int -nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int pattern) +nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 loff = nv94_sor_loff(outp); nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); return 0; } +int +nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) +{ + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); + const u32 soff = nv94_sor_soff(outp); + const u32 loff = nv94_sor_loff(outp); + u32 mask = 0, i; + + for (i = 0; i < nr; i++) + mask |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3); + + nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask); + nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000); + nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000); + return 0; +} + static int -nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int link_nr, int link_bw, bool enh_frame) +nv94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 soff = nv94_sor_soff(outp); const u32 loff = nv94_sor_loff(outp); u32 dpctrl = 0x00000000; u32 clksor = 0x00000000; - u32 lane = 0; - int i; - dpctrl |= ((1 << link_nr) - 1) << 16; - if (enh_frame) + dpctrl |= ((1 << nr) - 1) << 16; + if (ef) dpctrl |= 0x00004000; - if (link_bw > 0x06) + if (bw > 0x06) clksor |= 0x00040000; - for (i = 0; i < link_nr; i++) - lane |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3); - nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor); nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); - nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane); return 0; } static int -nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane, int swing, int preem) +nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nouveau_bios *bios = nouveau_bios(disp); - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(priv); + const u32 shift = nv94_sor_dp_lane_map(priv, ln); const u32 loff = nv94_sor_loff(outp); - u32 addr, shift = nv94_sor_dp_lane_map(priv, lane); + u32 addr, data[3]; u8 ver, hdr, cnt, len; struct nvbios_dpout info; struct nvbios_dpcfg ocfg; - addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, + addr = nvbios_dpout_match(bios, outp->base.info.hasht, + outp->base.info.hashm, &ver, &hdr, &cnt, &len, &info); if (!addr) return -ENODEV; - addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, + addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; - nv_mask(priv, 0x61c118 + loff, 0x000000ff << shift, ocfg.drv << shift); - nv_mask(priv, 0x61c120 + loff, 0x000000ff << shift, ocfg.pre << shift); - nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8); + data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nv_rd32(priv, 0x61c130 + loff); + if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) + data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); + nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); return 0; } -const struct nouveau_dp_func -nv94_sor_dp_func = { +struct nvkm_output_dp_impl +nv94_sor_dp_impl = { + .base.base.handle = DCB_OUTPUT_DP, + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_output_dp_ctor, + .dtor = _nvkm_output_dp_dtor, + .init = _nvkm_output_dp_init, + .fini = _nvkm_output_dp_fini, + }, .pattern = nv94_sor_dp_pattern, + .lnk_pwr = nv94_sor_dp_lnk_pwr, .lnk_ctl = nv94_sor_dp_lnk_ctl, .drv_ctl = nv94_sor_dp_drv_ctl, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c index 9e1d435d728..97f0e9cd3d4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c @@ -29,19 +29,20 @@ #include <subdev/bios/dcb.h> #include <subdev/bios/dp.h> #include <subdev/bios/init.h> +#include <subdev/timer.h> #include "nv50.h" static inline u32 -nvd0_sor_soff(struct dcb_output *outp) +nvd0_sor_soff(struct nvkm_output_dp *outp) { - return (ffs(outp->or) - 1) * 0x800; + return (ffs(outp->base.info.or) - 1) * 0x800; } static inline u32 -nvd0_sor_loff(struct dcb_output *outp) +nvd0_sor_loff(struct nvkm_output_dp *outp) { - return nvd0_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; + return nvd0_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } static inline u32 @@ -52,73 +53,80 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) } static int -nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int pattern) +nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 loff = nvd0_sor_loff(outp); nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; } static int -nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int link_nr, int link_bw, bool enh_frame) +nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); const u32 soff = nvd0_sor_soff(outp); const u32 loff = nvd0_sor_loff(outp); u32 dpctrl = 0x00000000; u32 clksor = 0x00000000; - u32 lane = 0; - int i; - clksor |= link_bw << 18; - dpctrl |= ((1 << link_nr) - 1) << 16; - if (enh_frame) + clksor |= bw << 18; + dpctrl |= ((1 << nr) - 1) << 16; + if (ef) dpctrl |= 0x00004000; - for (i = 0; i < link_nr; i++) - lane |= 1 << (nvd0_sor_dp_lane_map(priv, i) >> 3); - nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor); nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); - nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane); return 0; } static int -nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, - int head, int lane, int swing, int preem) +nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nouveau_bios *bios = nouveau_bios(disp); - struct nv50_disp_priv *priv = (void *)disp; + struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); + struct nouveau_bios *bios = nouveau_bios(priv); + const u32 shift = nvd0_sor_dp_lane_map(priv, ln); const u32 loff = nvd0_sor_loff(outp); - u32 addr, shift = nvd0_sor_dp_lane_map(priv, lane); + u32 addr, data[4]; u8 ver, hdr, cnt, len; struct nvbios_dpout info; struct nvbios_dpcfg ocfg; - addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, + addr = nvbios_dpout_match(bios, outp->base.info.hasht, + outp->base.info.hashm, &ver, &hdr, &cnt, &len, &info); if (!addr) return -ENODEV; - addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, + addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe, &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; - nv_mask(priv, 0x61c118 + loff, 0x000000ff << shift, ocfg.drv << shift); - nv_mask(priv, 0x61c120 + loff, 0x000000ff << shift, ocfg.pre << shift); - nv_mask(priv, 0x61c130 + loff, 0x0000ff00, ocfg.unk << 8); - nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000); + data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nv_rd32(priv, 0x61c130 + loff); + if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) + data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); + nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); + data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift); + nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; } -const struct nouveau_dp_func -nvd0_sor_dp_func = { +struct nvkm_output_dp_impl +nvd0_sor_dp_impl = { + .base.base.handle = DCB_OUTPUT_DP, + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_output_dp_ctor, + .dtor = _nvkm_output_dp_dtor, + .init = _nvkm_output_dp_init, + .fini = _nvkm_output_dp_fini, + }, .pattern = nvd0_sor_dp_pattern, + .lnk_pwr = nv94_sor_dp_lnk_pwr, .lnk_ctl = nvd0_sor_dp_lnk_ctl, .drv_ctl = nvd0_sor_dp_drv_ctl, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c index 5a1c6847459..8836c3cb99c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c @@ -138,10 +138,15 @@ nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) bool nv_lockvgac(void *obj, bool lock) { + struct nouveau_device *dev = nv_device(obj); + bool locked = !nv_rdvgac(obj, 0, 0x1f); u8 data = lock ? 0x99 : 0x57; - nv_wrvgac(obj, 0, 0x1f, data); - if (nv_device(obj)->chipset == 0x11) { + if (dev->card_type < NV_50) + nv_wrvgac(obj, 0, 0x1f, data); + else + nv_wrvgac(obj, 0, 0x3f, data); + if (dev->chipset == 0x11) { if (!(nv_rd32(obj, 0x001084) & 0x10000000)) nv_wrvgac(obj, 1, 0x1f, data); } diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c index 944e73ac485..1cfb3bb9013 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c @@ -53,6 +53,9 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, 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: break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/core/engine/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c index e03fc8e4dc1..2914646c870 100644 --- a/drivers/gpu/drm/nouveau/core/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/core/engine/falcon.c @@ -56,6 +56,16 @@ _nouveau_falcon_wr32(struct nouveau_object *object, u64 addr, u32 data) nv_wr32(falcon, falcon->addr + addr, data); } +static void * +vmemdup(const void *src, size_t len) +{ + void *p = vmalloc(len); + + if (p) + memcpy(p, src, len); + return p; +} + int _nouveau_falcon_init(struct nouveau_object *object) { @@ -109,9 +119,9 @@ _nouveau_falcon_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret == 0) { - falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL); + falcon->code.data = vmemdup(fw->data, fw->size); falcon->code.size = fw->size; falcon->data.data = NULL; falcon->data.size = 0; @@ -128,13 +138,13 @@ _nouveau_falcon_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nv_error(falcon, "unable to load firmware data\n"); return ret; } - falcon->data.data = kmemdup(fw->data, fw->size, GFP_KERNEL); + falcon->data.data = vmemdup(fw->data, fw->size); falcon->data.size = fw->size; release_firmware(fw); if (!falcon->data.data) @@ -143,13 +153,13 @@ _nouveau_falcon_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nv_error(falcon, "unable to load firmware code\n"); return ret; } - falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL); + falcon->code.data = vmemdup(fw->data, fw->size); falcon->code.size = fw->size; release_firmware(fw); if (!falcon->code.data) @@ -235,8 +245,8 @@ _nouveau_falcon_fini(struct nouveau_object *object, bool suspend) if (!suspend) { nouveau_gpuobj_ref(NULL, &falcon->core); if (falcon->external) { - kfree(falcon->data.data); - kfree(falcon->code.data); + vfree(falcon->data.data); + vfree(falcon->code.data); falcon->code.data = NULL; } } diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c index d3ec436d9cb..56ed3d73bf8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c @@ -86,12 +86,12 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent, } /* map fifo control registers */ - chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr + + chan->user = ioremap(nv_device_resource_start(device, bar) + addr + (chan->chid * size), size); if (!chan->user) return -EFAULT; - nouveau_event_trigger(priv->cevent, 0); + nouveau_event_trigger(priv->cevent, 1, 0); chan->size = size; return 0; @@ -194,11 +194,11 @@ nouveau_fifo_create_(struct nouveau_object *parent, if (!priv->channel) return -ENOMEM; - ret = nouveau_event_create(1, &priv->cevent); + ret = nouveau_event_create(1, 1, &priv->cevent); if (ret) return ret; - ret = nouveau_event_create(1, &priv->uevent); + ret = nouveau_event_create(1, 1, &priv->uevent); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c new file mode 100644 index 00000000000..327456eae96 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c @@ -0,0 +1,35 @@ +/* + * 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 "nve0.h" + +struct nouveau_oclass * +gk20a_fifo_oclass = &(struct nve0_fifo_impl) { + .base.handle = NV_ENGINE(FIFO, 0xea), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_fifo_ctor, + .dtor = nve0_fifo_dtor, + .init = nve0_fifo_init, + .fini = nve0_fifo_fini, + }, + .channels = 128, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c index f877bd524a9..c61b16a6388 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c @@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) } if (status & 0x40000000) { - nouveau_event_trigger(priv->base.uevent, 0); + nouveau_event_trigger(priv->base.uevent, 1, 0); nv_wr32(priv, 0x002100, 0x40000000); status &= ~0x40000000; } @@ -632,8 +632,8 @@ nv04_fifo_init(struct nouveau_object *object) return 0; } -struct nouveau_oclass -nv04_fifo_oclass = { +struct nouveau_oclass * +nv04_fifo_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(FIFO, 0x04), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_fifo_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c index 2c927c1d173..571a22aa1ae 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c @@ -159,8 +159,8 @@ nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv10_fifo_oclass = { +struct nouveau_oclass * +nv10_fifo_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(FIFO, 0x10), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv10_fifo_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c new file mode 100644 index 00000000000..09362a51ba5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c @@ -0,0 +1,37 @@ +/* + * 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 "nve0.h" + +struct nouveau_oclass * +nv108_fifo_oclass = &(struct nve0_fifo_impl) { + .base.handle = NV_ENGINE(FIFO, 0x08), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_fifo_ctor, + .dtor = nve0_fifo_dtor, + .init = nve0_fifo_init, + .fini = _nouveau_fifo_fini, + }, + .channels = 1024, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c index a9cb51d38c5..f2576020931 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c @@ -196,8 +196,8 @@ nv17_fifo_init(struct nouveau_object *object) return 0; } -struct nouveau_oclass -nv17_fifo_oclass = { +struct nouveau_oclass * +nv17_fifo_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(FIFO, 0x17), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv17_fifo_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c index 5c7433d5069..343487ed223 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c @@ -337,8 +337,8 @@ nv40_fifo_init(struct nouveau_object *object) return 0; } -struct nouveau_oclass -nv40_fifo_oclass = { +struct nouveau_oclass * +nv40_fifo_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(FIFO, 0x40), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv40_fifo_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c index 7e5dff51d3c..e6352bd5b4f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c @@ -33,6 +33,7 @@ #include <engine/dmaobj.h> #include <engine/fifo.h> +#include "nv04.h" #include "nv50.h" /******************************************************************************* @@ -460,6 +461,8 @@ nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_subdev(priv)->intr = nv04_fifo_intr; nv_engine(priv)->cclass = &nv50_fifo_cclass; nv_engine(priv)->sclass = nv50_fifo_sclass; + priv->base.pause = nv04_fifo_pause; + priv->base.start = nv04_fifo_start; return 0; } @@ -502,8 +505,8 @@ nv50_fifo_init(struct nouveau_object *object) return 0; } -struct nouveau_oclass -nv50_fifo_oclass = { +struct nouveau_oclass * +nv50_fifo_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(FIFO, 0x50), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_fifo_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c index 91a87cd7195..6e5ac16e546 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c @@ -35,6 +35,7 @@ #include <engine/dmaobj.h> #include <engine/fifo.h> +#include "nv04.h" #include "nv50.h" /******************************************************************************* @@ -144,7 +145,7 @@ nv84_fifo_object_attach(struct nouveau_object *parent, case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break; case NVDEV_ENGINE_VP : context |= 0x00400000; break; case NVDEV_ENGINE_CRYPT : - case NVDEV_ENGINE_UNK1C1: context |= 0x00500000; break; + case NVDEV_ENGINE_VIC : context |= 0x00500000; break; case NVDEV_ENGINE_BSP : context |= 0x00600000; break; default: return -EINVAL; @@ -180,7 +181,7 @@ nv84_fifo_chan_ctor_dma(struct nouveau_object *parent, (1ULL << NVDEV_ENGINE_BSP) | (1ULL << NVDEV_ENGINE_PPP) | (1ULL << NVDEV_ENGINE_COPY0) | - (1ULL << NVDEV_ENGINE_UNK1C1), &chan); + (1ULL << NVDEV_ENGINE_VIC), &chan); *pobject = nv_object(chan); if (ret) return ret; @@ -243,7 +244,7 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent, (1ULL << NVDEV_ENGINE_BSP) | (1ULL << NVDEV_ENGINE_PPP) | (1ULL << NVDEV_ENGINE_COPY0) | - (1ULL << NVDEV_ENGINE_UNK1C1), &chan); + (1ULL << NVDEV_ENGINE_VIC), &chan); *pobject = nv_object(chan); if (ret) return ret; @@ -388,14 +389,14 @@ nv84_fifo_cclass = { ******************************************************************************/ static void -nv84_fifo_uevent_enable(struct nouveau_event *event, int index) +nv84_fifo_uevent_enable(struct nouveau_event *event, int type, int index) { struct nv84_fifo_priv *priv = event->priv; nv_mask(priv, 0x002140, 0x40000000, 0x40000000); } static void -nv84_fifo_uevent_disable(struct nouveau_event *event, int index) +nv84_fifo_uevent_disable(struct nouveau_event *event, int type, int index) { struct nv84_fifo_priv *priv = event->priv; nv_mask(priv, 0x002140, 0x40000000, 0x00000000); @@ -432,11 +433,13 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_subdev(priv)->intr = nv04_fifo_intr; nv_engine(priv)->cclass = &nv84_fifo_cclass; nv_engine(priv)->sclass = nv84_fifo_sclass; + priv->base.pause = nv04_fifo_pause; + priv->base.start = nv04_fifo_start; return 0; } -struct nouveau_oclass -nv84_fifo_oclass = { +struct nouveau_oclass * +nv84_fifo_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(FIFO, 0x84), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv84_fifo_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index ce92f289e75..ae4a4dc5642 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -33,6 +33,7 @@ #include <subdev/timer.h> #include <subdev/bar.h> +#include <subdev/fb.h> #include <subdev/vm.h> #include <engine/dmaobj.h> @@ -40,8 +41,16 @@ struct nvc0_fifo_priv { struct nouveau_fifo base; - struct nouveau_gpuobj *playlist[2]; - int cur_playlist; + + struct work_struct fault; + u64 mask; + + struct { + struct nouveau_gpuobj *mem[2]; + int active; + wait_queue_head_t wait; + } runlist; + struct { struct nouveau_gpuobj *mem; struct nouveau_vma bar; @@ -57,6 +66,11 @@ struct nvc0_fifo_base { struct nvc0_fifo_chan { struct nouveau_fifo_chan base; + enum { + STOPPED, + RUNNING, + KILLED + } state; }; /******************************************************************************* @@ -64,29 +78,33 @@ struct nvc0_fifo_chan { ******************************************************************************/ static void -nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) +nvc0_fifo_runlist_update(struct nvc0_fifo_priv *priv) { struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_gpuobj *cur; int i, p; mutex_lock(&nv_subdev(priv)->mutex); - cur = priv->playlist[priv->cur_playlist]; - priv->cur_playlist = !priv->cur_playlist; + cur = priv->runlist.mem[priv->runlist.active]; + priv->runlist.active = !priv->runlist.active; for (i = 0, p = 0; i < 128; i++) { - if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1)) - continue; - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000004); - p += 8; + struct nvc0_fifo_chan *chan = (void *)priv->base.channel[i]; + if (chan && chan->state == RUNNING) { + nv_wo32(cur, p + 0, i); + nv_wo32(cur, p + 4, 0x00000004); + p += 8; + } } bar->flush(bar); nv_wr32(priv, 0x002270, cur->addr >> 12); nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); - if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000)) - nv_error(priv, "playlist update failed\n"); + + if (wait_event_timeout(priv->runlist.wait, + !(nv_rd32(priv, 0x00227c) & 0x00100000), + msecs_to_jiffies(2000)) == 0) + nv_error(priv, "runlist update timeout\n"); mutex_unlock(&nv_subdev(priv)->mutex); } @@ -238,30 +256,32 @@ nvc0_fifo_chan_init(struct nouveau_object *object) return ret; nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); - nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); - nvc0_fifo_playlist_update(priv); + + if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { + nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); + nvc0_fifo_runlist_update(priv); + } + return 0; } +static void nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv); + static int nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend) { struct nvc0_fifo_priv *priv = (void *)object->engine; struct nvc0_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; - u32 mask, engine; - nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); - nvc0_fifo_playlist_update(priv); - mask = nv_rd32(priv, 0x0025a4); - for (engine = 0; mask && engine < 16; engine++) { - if (!(mask & (1 << engine))) - continue; - nv_mask(priv, 0x0025a8 + (engine * 4), 0x00000000, 0x00000000); - mask &= ~(1 << engine); + if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { + nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + nvc0_fifo_runlist_update(priv); } - nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); + nvc0_fifo_intr_engine(priv); + + nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); return nouveau_fifo_channel_fini(&chan->base, suspend); } @@ -344,11 +364,177 @@ nvc0_fifo_cclass = { * PFIFO engine ******************************************************************************/ -static const struct nouveau_enum nvc0_fifo_fault_unit[] = { +static inline int +nvc0_fifo_engidx(struct nvc0_fifo_priv *priv, u32 engn) +{ + switch (engn) { + case NVDEV_ENGINE_GR : engn = 0; break; + case NVDEV_ENGINE_BSP : engn = 1; break; + case NVDEV_ENGINE_PPP : engn = 2; break; + case NVDEV_ENGINE_VP : engn = 3; break; + case NVDEV_ENGINE_COPY0: engn = 4; break; + case NVDEV_ENGINE_COPY1: engn = 5; break; + default: + return -1; + } + + return engn; +} + +static inline struct nouveau_engine * +nvc0_fifo_engine(struct nvc0_fifo_priv *priv, u32 engn) +{ + switch (engn) { + case 0: engn = NVDEV_ENGINE_GR; break; + case 1: engn = NVDEV_ENGINE_BSP; break; + case 2: engn = NVDEV_ENGINE_PPP; break; + case 3: engn = NVDEV_ENGINE_VP; break; + case 4: engn = NVDEV_ENGINE_COPY0; break; + case 5: engn = NVDEV_ENGINE_COPY1; break; + default: + return NULL; + } + + return nouveau_engine(priv, engn); +} + +static void +nvc0_fifo_recover_work(struct work_struct *work) +{ + struct nvc0_fifo_priv *priv = container_of(work, typeof(*priv), fault); + struct nouveau_object *engine; + unsigned long flags; + u32 engn, engm = 0; + u64 mask, todo; + + spin_lock_irqsave(&priv->base.lock, flags); + mask = priv->mask; + priv->mask = 0ULL; + spin_unlock_irqrestore(&priv->base.lock, flags); + + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) + engm |= 1 << nvc0_fifo_engidx(priv, engn); + nv_mask(priv, 0x002630, engm, engm); + + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { + if ((engine = (void *)nouveau_engine(priv, engn))) { + nv_ofuncs(engine)->fini(engine, false); + WARN_ON(nv_ofuncs(engine)->init(engine)); + } + } + + nvc0_fifo_runlist_update(priv); + nv_wr32(priv, 0x00262c, engm); + nv_mask(priv, 0x002630, engm, 0x00000000); +} + +static void +nvc0_fifo_recover(struct nvc0_fifo_priv *priv, struct nouveau_engine *engine, + struct nvc0_fifo_chan *chan) +{ + struct nouveau_object *engobj = nv_object(engine); + u32 chid = chan->base.chid; + unsigned long flags; + + nv_error(priv, "%s engine fault on channel %d, recovering...\n", + nv_subdev(engine)->name, chid); + + nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); + chan->state = KILLED; + + spin_lock_irqsave(&priv->base.lock, flags); + priv->mask |= 1ULL << nv_engidx(engobj); + spin_unlock_irqrestore(&priv->base.lock, flags); + schedule_work(&priv->fault); +} + +static int +nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) +{ + struct nvc0_fifo_chan *chan = NULL; + struct nouveau_handle *bind; + unsigned long flags; + int ret = -EINVAL; + + spin_lock_irqsave(&priv->base.lock, flags); + if (likely(chid >= priv->base.min && chid <= priv->base.max)) + chan = (void *)priv->base.channel[chid]; + if (unlikely(!chan)) + goto out; + + bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); + if (likely(bind)) { + if (!mthd || !nv_call(bind->object, mthd, data)) + ret = 0; + nouveau_namedb_put(bind); + } + +out: + spin_unlock_irqrestore(&priv->base.lock, flags); + return ret; +} + +static const struct nouveau_enum +nvc0_fifo_sched_reason[] = { + { 0x0a, "CTXSW_TIMEOUT" }, + {} +}; + +static void +nvc0_fifo_intr_sched_ctxsw(struct nvc0_fifo_priv *priv) +{ + struct nouveau_engine *engine; + struct nvc0_fifo_chan *chan; + u32 engn; + + for (engn = 0; engn < 6; engn++) { + u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 busy = (stat & 0x80000000); + u32 save = (stat & 0x00100000); /* maybe? */ + u32 unk0 = (stat & 0x00040000); + u32 unk1 = (stat & 0x00001000); + u32 chid = (stat & 0x0000007f); + (void)save; + + if (busy && unk0 && unk1) { + if (!(chan = (void *)priv->base.channel[chid])) + continue; + if (!(engine = nvc0_fifo_engine(priv, engn))) + continue; + nvc0_fifo_recover(priv, engine, chan); + } + } +} + +static void +nvc0_fifo_intr_sched(struct nvc0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x00254c); + u32 code = intr & 0x000000ff; + const struct nouveau_enum *en; + char enunk[6] = ""; + + en = nouveau_enum_find(nvc0_fifo_sched_reason, code); + if (!en) + snprintf(enunk, sizeof(enunk), "UNK%02x", code); + + nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + + switch (code) { + case 0x0a: + nvc0_fifo_intr_sched_ctxsw(priv); + break; + default: + break; + } +} + +static const struct nouveau_enum +nvc0_fifo_fault_engine[] = { { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR }, - { 0x03, "PEEPHOLE" }, - { 0x04, "BAR1" }, - { 0x05, "BAR3" }, + { 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO }, { 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP }, { 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP }, @@ -360,7 +546,8 @@ static const struct nouveau_enum nvc0_fifo_fault_unit[] = { {} }; -static const struct nouveau_enum nvc0_fifo_fault_reason[] = { +static const struct nouveau_enum +nvc0_fifo_fault_reason[] = { { 0x00, "PT_NOT_PRESENT" }, { 0x01, "PT_TOO_SHORT" }, { 0x02, "PAGE_NOT_PRESENT" }, @@ -373,7 +560,8 @@ static const struct nouveau_enum nvc0_fifo_fault_reason[] = { {} }; -static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = { +static const struct nouveau_enum +nvc0_fifo_fault_hubclient[] = { { 0x01, "PCOPY0" }, { 0x02, "PCOPY1" }, { 0x04, "DISPATCH" }, @@ -391,7 +579,8 @@ static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = { {} }; -static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = { +static const struct nouveau_enum +nvc0_fifo_fault_gpcclient[] = { { 0x01, "TEX" }, { 0x0c, "ESETUP" }, { 0x0e, "CTXCTL" }, @@ -399,92 +588,92 @@ static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = { {} }; -static const struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = { -/* { 0x00008000, "" } seen with null ib push */ - { 0x00200000, "ILLEGAL_MTHD" }, - { 0x00800000, "EMPTY_SUBC" }, - {} -}; - static void -nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit) +nvc0_fifo_intr_fault(struct nvc0_fifo_priv *priv, int unit) { u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; - const struct nouveau_enum *en; - struct nouveau_engine *engine; - struct nouveau_object *engctx = NULL; - - switch (unit) { - case 3: /* PEEPHOLE */ - nv_mask(priv, 0x001718, 0x00000000, 0x00000000); - break; - case 4: /* BAR1 */ - nv_mask(priv, 0x001704, 0x00000000, 0x00000000); - break; - case 5: /* BAR3 */ - nv_mask(priv, 0x001714, 0x00000000, 0x00000000); - break; - default: - break; + u32 write = (stat & 0x00000080); + u32 hub = (stat & 0x00000040); + u32 reason = (stat & 0x0000000f); + struct nouveau_object *engctx = NULL, *object; + struct nouveau_engine *engine = NULL; + const struct nouveau_enum *er, *eu, *ec; + char erunk[6] = ""; + char euunk[6] = ""; + char ecunk[6] = ""; + char gpcid[3] = ""; + + er = nouveau_enum_find(nvc0_fifo_fault_reason, reason); + if (!er) + snprintf(erunk, sizeof(erunk), "UNK%02X", reason); + + eu = nouveau_enum_find(nvc0_fifo_fault_engine, unit); + if (eu) { + switch (eu->data2) { + case NVDEV_SUBDEV_BAR: + nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + break; + case NVDEV_SUBDEV_INSTMEM: + nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + break; + case NVDEV_ENGINE_IFB: + nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + break; + default: + engine = nouveau_engine(priv, eu->data2); + if (engine) + engctx = nouveau_engctx_get(engine, inst); + break; + } + } else { + snprintf(euunk, sizeof(euunk), "UNK%02x", unit); } - nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ? - "write" : "read", (u64)vahi << 32 | valo); - nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); - pr_cont("] from "); - en = nouveau_enum_print(nvc0_fifo_fault_unit, unit); - if (stat & 0x00000040) { - pr_cont("/"); - nouveau_enum_print(nvc0_fifo_fault_hubclient, client); + if (hub) { + ec = nouveau_enum_find(nvc0_fifo_fault_hubclient, client); } else { - pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24); - nouveau_enum_print(nvc0_fifo_fault_gpcclient, client); + ec = nouveau_enum_find(nvc0_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "%d", gpc); } - if (en && en->data2) { - engine = nouveau_engine(priv, en->data2); - if (engine) - engctx = nouveau_engctx_get(engine, inst); - + if (!ec) + snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); + + nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " + "channel 0x%010llx [%s]\n", write ? "write" : "read", + (u64)vahi << 32 | valo, er ? er->name : erunk, + eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", + ec ? ec->name : ecunk, (u64)inst << 12, + nouveau_client_name(engctx)); + + object = engctx; + while (object) { + switch (nv_mclass(object)) { + case NVC0_CHANNEL_IND_CLASS: + nvc0_fifo_recover(priv, engine, (void *)object); + break; + } + object = object->parent; } - pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, - nouveau_client_name(engctx)); nouveau_engctx_put(engctx); } -static int -nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) -{ - struct nvc0_fifo_chan *chan = NULL; - struct nouveau_handle *bind; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; - if (unlikely(!chan)) - goto out; - - bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); - if (likely(bind)) { - if (!mthd || !nv_call(bind->object, mthd, data)) - ret = 0; - nouveau_namedb_put(bind); - } - -out: - spin_unlock_irqrestore(&priv->base.lock, flags); - return ret; -} +static const struct nouveau_bitfield +nvc0_fifo_pbdma_intr[] = { +/* { 0x00008000, "" } seen with null ib push */ + { 0x00200000, "ILLEGAL_MTHD" }, + { 0x00800000, "EMPTY_SUBC" }, + {} +}; static void -nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) +nvc0_fifo_intr_pbdma(struct nvc0_fifo_priv *priv, int unit) { u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); @@ -494,24 +683,17 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) u32 mthd = (addr & 0x00003ffc); u32 show = stat; - if (stat & 0x00200000) { - if (mthd == 0x0054) { - if (!nvc0_fifo_swmthd(priv, chid, 0x0500, 0x00000000)) - show &= ~0x00200000; - } - } - if (stat & 0x00800000) { if (!nvc0_fifo_swmthd(priv, chid, mthd, data)) show &= ~0x00800000; } if (show) { - nv_error(priv, "SUBFIFO%d:", unit); - nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); + nv_error(priv, "PBDMA%d:", unit); + nouveau_bitfield_print(nvc0_fifo_pbdma_intr, show); pr_cont("\n"); nv_error(priv, - "SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", + "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", unit, chid, nouveau_client_name_for_fifo_chid(&priv->base, chid), subc, mthd, data); @@ -522,6 +704,56 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) } static void +nvc0_fifo_intr_runlist(struct nvc0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x002a00); + + if (intr & 0x10000000) { + wake_up(&priv->runlist.wait); + nv_wr32(priv, 0x002a00, 0x10000000); + intr &= ~0x10000000; + } + + if (intr) { + nv_error(priv, "RUNLIST 0x%08x\n", intr); + nv_wr32(priv, 0x002a00, intr); + } +} + +static void +nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) +{ + u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04)); + u32 inte = nv_rd32(priv, 0x002628); + u32 unkn; + + for (unkn = 0; unkn < 8; unkn++) { + u32 ints = (intr >> (unkn * 0x04)) & inte; + if (ints & 0x1) { + nouveau_event_trigger(priv->base.uevent, 1, 0); + ints &= ~1; + } + if (ints) { + nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints); + nv_mask(priv, 0x002628, ints, 0); + } + } + + nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); +} + +static void +nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv) +{ + u32 mask = nv_rd32(priv, 0x0025a4); + while (mask) { + u32 unit = __ffs(mask); + nvc0_fifo_intr_engine_unit(priv, unit); + mask &= ~(1 << unit); + } +} + +static void nvc0_fifo_intr(struct nouveau_subdev *subdev) { struct nvc0_fifo_priv *priv = (void *)subdev; @@ -536,8 +768,7 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) } if (stat & 0x00000100) { - u32 intr = nv_rd32(priv, 0x00254c); - nv_warn(priv, "INTR 0x00000100: 0x%08x\n", intr); + nvc0_fifo_intr_sched(priv); nv_wr32(priv, 0x002100, 0x00000100); stat &= ~0x00000100; } @@ -557,64 +788,53 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) } if (stat & 0x10000000) { - u32 units = nv_rd32(priv, 0x00259c); - u32 u = units; - - while (u) { - int i = ffs(u) - 1; - nvc0_fifo_isr_vm_fault(priv, i); - u &= ~(1 << i); + u32 mask = nv_rd32(priv, 0x00259c); + while (mask) { + u32 unit = __ffs(mask); + nvc0_fifo_intr_fault(priv, unit); + nv_wr32(priv, 0x00259c, (1 << unit)); + mask &= ~(1 << unit); } - - nv_wr32(priv, 0x00259c, units); stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 units = nv_rd32(priv, 0x0025a0); - u32 u = units; - - while (u) { - int i = ffs(u) - 1; - nvc0_fifo_isr_subfifo_intr(priv, i); - u &= ~(1 << i); + u32 mask = nv_rd32(priv, 0x0025a0); + while (mask) { + u32 unit = __ffs(mask); + nvc0_fifo_intr_pbdma(priv, unit); + nv_wr32(priv, 0x0025a0, (1 << unit)); + mask &= ~(1 << unit); } - - nv_wr32(priv, 0x0025a0, units); stat &= ~0x20000000; } if (stat & 0x40000000) { - u32 intr0 = nv_rd32(priv, 0x0025a4); - u32 intr1 = nv_mask(priv, 0x002a00, 0x00000000, 0x00000); - nv_debug(priv, "INTR 0x40000000: 0x%08x 0x%08x\n", - intr0, intr1); + nvc0_fifo_intr_runlist(priv); stat &= ~0x40000000; } if (stat & 0x80000000) { - u32 intr = nv_mask(priv, 0x0025a8, 0x00000000, 0x00000000); - nouveau_event_trigger(priv->base.uevent, 0); - nv_debug(priv, "INTR 0x80000000: 0x%08x\n", intr); + nvc0_fifo_intr_engine(priv); stat &= ~0x80000000; } if (stat) { - nv_fatal(priv, "unhandled status 0x%08x\n", stat); + nv_error(priv, "INTR 0x%08x\n", stat); + nv_mask(priv, 0x002140, stat, 0x00000000); nv_wr32(priv, 0x002100, stat); - nv_wr32(priv, 0x002140, 0); } } static void -nvc0_fifo_uevent_enable(struct nouveau_event *event, int index) +nvc0_fifo_uevent_enable(struct nouveau_event *event, int type, int index) { struct nvc0_fifo_priv *priv = event->priv; nv_mask(priv, 0x002140, 0x80000000, 0x80000000); } static void -nvc0_fifo_uevent_disable(struct nouveau_event *event, int index) +nvc0_fifo_uevent_disable(struct nouveau_event *event, int type, int index) { struct nvc0_fifo_priv *priv = event->priv; nv_mask(priv, 0x002140, 0x80000000, 0x00000000); @@ -633,16 +853,20 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + INIT_WORK(&priv->fault, nvc0_fifo_recover_work); + ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->playlist[0]); + &priv->runlist.mem[0]); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->playlist[1]); + &priv->runlist.mem[1]); if (ret) return ret; + init_waitqueue_head(&priv->runlist.wait); + ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0, &priv->user.mem); if (ret) @@ -671,8 +895,8 @@ nvc0_fifo_dtor(struct nouveau_object *object) nouveau_gpuobj_unmap(&priv->user.bar); nouveau_gpuobj_ref(NULL, &priv->user.mem); - nouveau_gpuobj_ref(NULL, &priv->playlist[1]); - nouveau_gpuobj_ref(NULL, &priv->playlist[0]); + nouveau_gpuobj_ref(NULL, &priv->runlist.mem[0]); + nouveau_gpuobj_ref(NULL, &priv->runlist.mem[1]); nouveau_fifo_destroy(&priv->base); } @@ -691,9 +915,9 @@ nvc0_fifo_init(struct nouveau_object *object) nv_wr32(priv, 0x002204, 0xffffffff); priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204)); - nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr); + nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr); - /* assign engines to subfifos */ + /* assign engines to PBDMAs */ if (priv->spoon_nr >= 3) { nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */ nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */ @@ -703,7 +927,7 @@ nvc0_fifo_init(struct nouveau_object *object) nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */ } - /* PSUBFIFO[n] */ + /* PBDMA[n] */ for (i = 0; i < priv->spoon_nr; i++) { nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ @@ -713,15 +937,14 @@ nvc0_fifo_init(struct nouveau_object *object) nv_mask(priv, 0x002200, 0x00000001, 0x00000001); nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); - nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x3fffffff); - nv_wr32(priv, 0x002628, 0x00000001); /* makes mthd 0x20 work */ + nv_wr32(priv, 0x002140, 0x7fffffff); + nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ return 0; } -struct nouveau_oclass -nvc0_fifo_oclass = { +struct nouveau_oclass * +nvc0_fifo_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(FIFO, 0xc0), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_fifo_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 8e8121abe31..298063edb92 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -33,10 +33,12 @@ #include <subdev/timer.h> #include <subdev/bar.h> +#include <subdev/fb.h> #include <subdev/vm.h> #include <engine/dmaobj.h> -#include <engine/fifo.h> + +#include "nve0.h" #define _(a,b) { (a), ((1ULL << (a)) | (b)) } static const struct { @@ -56,12 +58,17 @@ static const struct { #define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) struct nve0_fifo_engn { - struct nouveau_gpuobj *playlist[2]; - int cur_playlist; + struct nouveau_gpuobj *runlist[2]; + int cur_runlist; + wait_queue_head_t wait; }; struct nve0_fifo_priv { struct nouveau_fifo base; + + struct work_struct fault; + u64 mask; + struct nve0_fifo_engn engine[FIFO_ENGINE_NR]; struct { struct nouveau_gpuobj *mem; @@ -79,6 +86,11 @@ struct nve0_fifo_base { struct nve0_fifo_chan { struct nouveau_fifo_chan base; u32 engine; + enum { + STOPPED, + RUNNING, + KILLED + } state; }; /******************************************************************************* @@ -86,32 +98,34 @@ struct nve0_fifo_chan { ******************************************************************************/ static void -nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine) +nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine) { struct nouveau_bar *bar = nouveau_bar(priv); struct nve0_fifo_engn *engn = &priv->engine[engine]; struct nouveau_gpuobj *cur; - u32 match = (engine << 16) | 0x00000001; int i, p; mutex_lock(&nv_subdev(priv)->mutex); - cur = engn->playlist[engn->cur_playlist]; - engn->cur_playlist = !engn->cur_playlist; + cur = engn->runlist[engn->cur_runlist]; + engn->cur_runlist = !engn->cur_runlist; for (i = 0, p = 0; i < priv->base.max; i++) { - u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001; - if (ctrl != match) - continue; - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000000); - p += 8; + struct nve0_fifo_chan *chan = (void *)priv->base.channel[i]; + if (chan && chan->state == RUNNING && chan->engine == engine) { + nv_wo32(cur, p + 0, i); + nv_wo32(cur, p + 4, 0x00000000); + p += 8; + } } bar->flush(bar); nv_wr32(priv, 0x002270, cur->addr >> 12); nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); - if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) - nv_error(priv, "playlist %d update timeout\n", engine); + + if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 + + (engine * 0x08)) & 0x00100000), + msecs_to_jiffies(2000)) == 0) + nv_error(priv, "runlist %d update timeout\n", engine); mutex_unlock(&nv_subdev(priv)->mutex); } @@ -127,9 +141,11 @@ nve0_fifo_context_attach(struct nouveau_object *parent, switch (nv_engidx(object->engine)) { case NVDEV_ENGINE_SW : + return 0; case NVDEV_ENGINE_COPY0: case NVDEV_ENGINE_COPY1: case NVDEV_ENGINE_COPY2: + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; return 0; case NVDEV_ENGINE_GR : addr = 0x0210; break; case NVDEV_ENGINE_BSP : addr = 0x0270; break; @@ -277,9 +293,13 @@ nve0_fifo_chan_init(struct nouveau_object *object) nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); - nve0_fifo_playlist_update(priv, chan->engine); - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + + if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { + nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + nve0_fifo_runlist_update(priv, chan->engine); + nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + } + return 0; } @@ -290,10 +310,12 @@ nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend) struct nve0_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; - nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); - nve0_fifo_playlist_update(priv, chan->engine); - nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); + if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { + nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + nve0_fifo_runlist_update(priv, chan->engine); + } + nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); return nouveau_fifo_channel_fini(&chan->base, suspend); } @@ -375,73 +397,81 @@ nve0_fifo_cclass = { * PFIFO engine ******************************************************************************/ -static const struct nouveau_enum nve0_fifo_fault_unit[] = { - {} -}; - -static const struct nouveau_enum nve0_fifo_fault_reason[] = { - { 0x00, "PT_NOT_PRESENT" }, - { 0x01, "PT_TOO_SHORT" }, - { 0x02, "PAGE_NOT_PRESENT" }, - { 0x03, "VM_LIMIT_EXCEEDED" }, - { 0x04, "NO_CHANNEL" }, - { 0x05, "PAGE_SYSTEM_ONLY" }, - { 0x06, "PAGE_READ_ONLY" }, - { 0x0a, "COMPRESSED_SYSRAM" }, - { 0x0c, "INVALID_STORAGE_TYPE" }, - {} -}; - -static const struct nouveau_enum nve0_fifo_fault_hubclient[] = { - {} -}; +static inline int +nve0_fifo_engidx(struct nve0_fifo_priv *priv, u32 engn) +{ + switch (engn) { + case NVDEV_ENGINE_GR : + case NVDEV_ENGINE_COPY2: engn = 0; break; + case NVDEV_ENGINE_BSP : engn = 1; break; + case NVDEV_ENGINE_PPP : engn = 2; break; + case NVDEV_ENGINE_VP : engn = 3; break; + case NVDEV_ENGINE_COPY0: engn = 4; break; + case NVDEV_ENGINE_COPY1: engn = 5; break; + case NVDEV_ENGINE_VENC : engn = 6; break; + default: + return -1; + } -static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = { - {} -}; + return engn; +} -static const struct nouveau_bitfield nve0_fifo_subfifo_intr[] = { - { 0x00200000, "ILLEGAL_MTHD" }, - { 0x00800000, "EMPTY_SUBC" }, - {} -}; +static inline struct nouveau_engine * +nve0_fifo_engine(struct nve0_fifo_priv *priv, u32 engn) +{ + if (engn >= ARRAY_SIZE(fifo_engine)) + return NULL; + return nouveau_engine(priv, fifo_engine[engn].subdev); +} static void -nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit) +nve0_fifo_recover_work(struct work_struct *work) { - u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10)); - u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10)); - u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10)); - u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10)); - u32 client = (stat & 0x00001f00) >> 8; - const struct nouveau_enum *en; - struct nouveau_engine *engine; - struct nouveau_object *engctx = NULL; - - nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ? - "write" : "read", (u64)vahi << 32 | valo); - nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f); - pr_cont("] from "); - en = nouveau_enum_print(nve0_fifo_fault_unit, unit); - if (stat & 0x00000040) { - pr_cont("/"); - nouveau_enum_print(nve0_fifo_fault_hubclient, client); - } else { - pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24); - nouveau_enum_print(nve0_fifo_fault_gpcclient, client); - } + struct nve0_fifo_priv *priv = container_of(work, typeof(*priv), fault); + struct nouveau_object *engine; + unsigned long flags; + u32 engn, engm = 0; + u64 mask, todo; - if (en && en->data2) { - engine = nouveau_engine(priv, en->data2); - if (engine) - engctx = nouveau_engctx_get(engine, inst); + spin_lock_irqsave(&priv->base.lock, flags); + mask = priv->mask; + priv->mask = 0ULL; + spin_unlock_irqrestore(&priv->base.lock, flags); + + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) + engm |= 1 << nve0_fifo_engidx(priv, engn); + nv_mask(priv, 0x002630, engm, engm); + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { + if ((engine = (void *)nouveau_engine(priv, engn))) { + nv_ofuncs(engine)->fini(engine, false); + WARN_ON(nv_ofuncs(engine)->init(engine)); + } + nve0_fifo_runlist_update(priv, nve0_fifo_engidx(priv, engn)); } - pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, - nouveau_client_name(engctx)); + nv_wr32(priv, 0x00262c, engm); + nv_mask(priv, 0x002630, engm, 0x00000000); +} - nouveau_engctx_put(engctx); +static void +nve0_fifo_recover(struct nve0_fifo_priv *priv, struct nouveau_engine *engine, + struct nve0_fifo_chan *chan) +{ + struct nouveau_object *engobj = nv_object(engine); + u32 chid = chan->base.chid; + unsigned long flags; + + nv_error(priv, "%s engine fault on channel %d, recovering...\n", + nv_subdev(engine)->name, chid); + + nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); + chan->state = KILLED; + + spin_lock_irqsave(&priv->base.lock, flags); + priv->mask |= 1ULL << nv_engidx(engobj); + spin_unlock_irqrestore(&priv->base.lock, flags); + schedule_work(&priv->fault); } static int @@ -470,8 +500,321 @@ out: return ret; } +static const struct nouveau_enum +nve0_fifo_bind_reason[] = { + { 0x01, "BIND_NOT_UNBOUND" }, + { 0x02, "SNOOP_WITHOUT_BAR1" }, + { 0x03, "UNBIND_WHILE_RUNNING" }, + { 0x05, "INVALID_RUNLIST" }, + { 0x06, "INVALID_CTX_TGT" }, + { 0x0b, "UNBIND_WHILE_PARKED" }, + {} +}; + static void -nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit) +nve0_fifo_intr_bind(struct nve0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x00252c); + u32 code = intr & 0x000000ff; + const struct nouveau_enum *en; + char enunk[6] = ""; + + en = nouveau_enum_find(nve0_fifo_bind_reason, code); + if (!en) + snprintf(enunk, sizeof(enunk), "UNK%02x", code); + + nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk); +} + +static const struct nouveau_enum +nve0_fifo_sched_reason[] = { + { 0x0a, "CTXSW_TIMEOUT" }, + {} +}; + +static void +nve0_fifo_intr_sched_ctxsw(struct nve0_fifo_priv *priv) +{ + struct nouveau_engine *engine; + struct nve0_fifo_chan *chan; + u32 engn; + + for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { + u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 busy = (stat & 0x80000000); + u32 next = (stat & 0x07ff0000) >> 16; + u32 chsw = (stat & 0x00008000); + u32 save = (stat & 0x00004000); + u32 load = (stat & 0x00002000); + u32 prev = (stat & 0x000007ff); + u32 chid = load ? next : prev; + (void)save; + + if (busy && chsw) { + if (!(chan = (void *)priv->base.channel[chid])) + continue; + if (!(engine = nve0_fifo_engine(priv, engn))) + continue; + nve0_fifo_recover(priv, engine, chan); + } + } +} + +static void +nve0_fifo_intr_sched(struct nve0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x00254c); + u32 code = intr & 0x000000ff; + const struct nouveau_enum *en; + char enunk[6] = ""; + + en = nouveau_enum_find(nve0_fifo_sched_reason, code); + if (!en) + snprintf(enunk, sizeof(enunk), "UNK%02x", code); + + nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + + switch (code) { + case 0x0a: + nve0_fifo_intr_sched_ctxsw(priv); + break; + default: + break; + } +} + +static void +nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv) +{ + u32 stat = nv_rd32(priv, 0x00256c); + nv_error(priv, "CHSW_ERROR 0x%08x\n", stat); + nv_wr32(priv, 0x00256c, stat); +} + +static void +nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv) +{ + u32 stat = nv_rd32(priv, 0x00259c); + nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat); +} + +static const struct nouveau_enum +nve0_fifo_fault_engine[] = { + { 0x00, "GR", NULL, NVDEV_ENGINE_GR }, + { 0x03, "IFB", NULL, NVDEV_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, + { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO }, + { 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO }, + { 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO }, + { 0x10, "MSVLD", NULL, NVDEV_ENGINE_BSP }, + { 0x11, "MSPPP", NULL, NVDEV_ENGINE_PPP }, + { 0x13, "PERF" }, + { 0x14, "MSPDEC", NULL, NVDEV_ENGINE_VP }, + { 0x15, "CE0", NULL, NVDEV_ENGINE_COPY0 }, + { 0x16, "CE1", NULL, NVDEV_ENGINE_COPY1 }, + { 0x17, "PMU" }, + { 0x19, "MSENC", NULL, NVDEV_ENGINE_VENC }, + { 0x1b, "CE2", NULL, NVDEV_ENGINE_COPY2 }, + {} +}; + +static const struct nouveau_enum +nve0_fifo_fault_reason[] = { + { 0x00, "PDE" }, + { 0x01, "PDE_SIZE" }, + { 0x02, "PTE" }, + { 0x03, "VA_LIMIT_VIOLATION" }, + { 0x04, "UNBOUND_INST_BLOCK" }, + { 0x05, "PRIV_VIOLATION" }, + { 0x06, "RO_VIOLATION" }, + { 0x07, "WO_VIOLATION" }, + { 0x08, "PITCH_MASK_VIOLATION" }, + { 0x09, "WORK_CREATION" }, + { 0x0a, "UNSUPPORTED_APERTURE" }, + { 0x0b, "COMPRESSION_FAILURE" }, + { 0x0c, "UNSUPPORTED_KIND" }, + { 0x0d, "REGION_VIOLATION" }, + { 0x0e, "BOTH_PTES_VALID" }, + { 0x0f, "INFO_TYPE_POISONED" }, + {} +}; + +static const struct nouveau_enum +nve0_fifo_fault_hubclient[] = { + { 0x00, "VIP" }, + { 0x01, "CE0" }, + { 0x02, "CE1" }, + { 0x03, "DNISO" }, + { 0x04, "FE" }, + { 0x05, "FECS" }, + { 0x06, "HOST" }, + { 0x07, "HOST_CPU" }, + { 0x08, "HOST_CPU_NB" }, + { 0x09, "ISO" }, + { 0x0a, "MMU" }, + { 0x0b, "MSPDEC" }, + { 0x0c, "MSPPP" }, + { 0x0d, "MSVLD" }, + { 0x0e, "NISO" }, + { 0x0f, "P2P" }, + { 0x10, "PD" }, + { 0x11, "PERF" }, + { 0x12, "PMU" }, + { 0x13, "RASTERTWOD" }, + { 0x14, "SCC" }, + { 0x15, "SCC_NB" }, + { 0x16, "SEC" }, + { 0x17, "SSYNC" }, + { 0x18, "GR_COPY" }, + { 0x19, "CE2" }, + { 0x1a, "XV" }, + { 0x1b, "MMU_NB" }, + { 0x1c, "MSENC" }, + { 0x1d, "DFALCON" }, + { 0x1e, "SKED" }, + { 0x1f, "AFALCON" }, + {} +}; + +static const struct nouveau_enum +nve0_fifo_fault_gpcclient[] = { + { 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" }, + { 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" }, + { 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" }, + { 0x09, "L1_3" }, { 0x0a, "T1_3" }, { 0x0b, "PE_3" }, + { 0x0c, "RAST" }, + { 0x0d, "GCC" }, + { 0x0e, "GPCCS" }, + { 0x0f, "PROP_0" }, + { 0x10, "PROP_1" }, + { 0x11, "PROP_2" }, + { 0x12, "PROP_3" }, + { 0x13, "L1_4" }, { 0x14, "T1_4" }, { 0x15, "PE_4" }, + { 0x16, "L1_5" }, { 0x17, "T1_5" }, { 0x18, "PE_5" }, + { 0x19, "L1_6" }, { 0x1a, "T1_6" }, { 0x1b, "PE_6" }, + { 0x1c, "L1_7" }, { 0x1d, "T1_7" }, { 0x1e, "PE_7" }, + { 0x1f, "GPM" }, + { 0x20, "LTP_UTLB_0" }, + { 0x21, "LTP_UTLB_1" }, + { 0x22, "LTP_UTLB_2" }, + { 0x23, "LTP_UTLB_3" }, + { 0x24, "GPC_RGG_UTLB" }, + {} +}; + +static void +nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit) +{ + u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); + u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); + u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); + u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + u32 gpc = (stat & 0x1f000000) >> 24; + u32 client = (stat & 0x00001f00) >> 8; + u32 write = (stat & 0x00000080); + u32 hub = (stat & 0x00000040); + u32 reason = (stat & 0x0000000f); + struct nouveau_object *engctx = NULL, *object; + struct nouveau_engine *engine = NULL; + const struct nouveau_enum *er, *eu, *ec; + char erunk[6] = ""; + char euunk[6] = ""; + char ecunk[6] = ""; + char gpcid[3] = ""; + + er = nouveau_enum_find(nve0_fifo_fault_reason, reason); + if (!er) + snprintf(erunk, sizeof(erunk), "UNK%02X", reason); + + eu = nouveau_enum_find(nve0_fifo_fault_engine, unit); + if (eu) { + switch (eu->data2) { + case NVDEV_SUBDEV_BAR: + nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + break; + case NVDEV_SUBDEV_INSTMEM: + nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + break; + case NVDEV_ENGINE_IFB: + nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + break; + default: + engine = nouveau_engine(priv, eu->data2); + if (engine) + engctx = nouveau_engctx_get(engine, inst); + break; + } + } else { + snprintf(euunk, sizeof(euunk), "UNK%02x", unit); + } + + if (hub) { + ec = nouveau_enum_find(nve0_fifo_fault_hubclient, client); + } else { + ec = nouveau_enum_find(nve0_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "%d", gpc); + } + + if (!ec) + snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); + + nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " + "channel 0x%010llx [%s]\n", write ? "write" : "read", + (u64)vahi << 32 | valo, er ? er->name : erunk, + eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", + ec ? ec->name : ecunk, (u64)inst << 12, + nouveau_client_name(engctx)); + + object = engctx; + while (object) { + switch (nv_mclass(object)) { + case NVE0_CHANNEL_IND_CLASS: + nve0_fifo_recover(priv, engine, (void *)object); + break; + } + object = object->parent; + } + + nouveau_engctx_put(engctx); +} + +static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = { + { 0x00000001, "MEMREQ" }, + { 0x00000002, "MEMACK_TIMEOUT" }, + { 0x00000004, "MEMACK_EXTRA" }, + { 0x00000008, "MEMDAT_TIMEOUT" }, + { 0x00000010, "MEMDAT_EXTRA" }, + { 0x00000020, "MEMFLUSH" }, + { 0x00000040, "MEMOP" }, + { 0x00000080, "LBCONNECT" }, + { 0x00000100, "LBREQ" }, + { 0x00000200, "LBACK_TIMEOUT" }, + { 0x00000400, "LBACK_EXTRA" }, + { 0x00000800, "LBDAT_TIMEOUT" }, + { 0x00001000, "LBDAT_EXTRA" }, + { 0x00002000, "GPFIFO" }, + { 0x00004000, "GPPTR" }, + { 0x00008000, "GPENTRY" }, + { 0x00010000, "GPCRC" }, + { 0x00020000, "PBPTR" }, + { 0x00040000, "PBENTRY" }, + { 0x00080000, "PBCRC" }, + { 0x00100000, "XBARCONNECT" }, + { 0x00200000, "METHOD" }, + { 0x00400000, "METHODCRC" }, + { 0x00800000, "DEVICE" }, + { 0x02000000, "SEMAPHORE" }, + { 0x04000000, "ACQUIRE" }, + { 0x08000000, "PRI" }, + { 0x20000000, "NO_CTXSW_SEG" }, + { 0x40000000, "PBSEG" }, + { 0x80000000, "SIGNATURE" }, + {} +}; + +static void +nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit) { u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); @@ -481,24 +824,17 @@ nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit) u32 mthd = (addr & 0x00003ffc); u32 show = stat; - if (stat & 0x00200000) { - if (mthd == 0x0054) { - if (!nve0_fifo_swmthd(priv, chid, 0x0500, 0x00000000)) - show &= ~0x00200000; - } - } - if (stat & 0x00800000) { if (!nve0_fifo_swmthd(priv, chid, mthd, data)) show &= ~0x00800000; } if (show) { - nv_error(priv, "SUBFIFO%d:", unit); - nouveau_bitfield_print(nve0_fifo_subfifo_intr, show); + nv_error(priv, "PBDMA%d:", unit); + nouveau_bitfield_print(nve0_fifo_pbdma_intr, show); pr_cont("\n"); nv_error(priv, - "SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", + "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", unit, chid, nouveau_client_name_for_fifo_chid(&priv->base, chid), subc, mthd, data); @@ -509,126 +845,171 @@ nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit) } static void +nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv) +{ + u32 mask = nv_rd32(priv, 0x002a00); + while (mask) { + u32 engn = __ffs(mask); + wake_up(&priv->engine[engn].wait); + nv_wr32(priv, 0x002a00, 1 << engn); + mask &= ~(1 << engn); + } +} + +static void +nve0_fifo_intr_engine(struct nve0_fifo_priv *priv) +{ + nouveau_event_trigger(priv->base.uevent, 1, 0); +} + +static void nve0_fifo_intr(struct nouveau_subdev *subdev) { struct nve0_fifo_priv *priv = (void *)subdev; u32 mask = nv_rd32(priv, 0x002140); u32 stat = nv_rd32(priv, 0x002100) & mask; + if (stat & 0x00000001) { + nve0_fifo_intr_bind(priv); + nv_wr32(priv, 0x002100, 0x00000001); + stat &= ~0x00000001; + } + + if (stat & 0x00000010) { + nv_error(priv, "PIO_ERROR\n"); + nv_wr32(priv, 0x002100, 0x00000010); + stat &= ~0x00000010; + } + if (stat & 0x00000100) { - nv_warn(priv, "unknown status 0x00000100\n"); + nve0_fifo_intr_sched(priv); nv_wr32(priv, 0x002100, 0x00000100); stat &= ~0x00000100; } - if (stat & 0x10000000) { - u32 units = nv_rd32(priv, 0x00259c); - u32 u = units; + if (stat & 0x00010000) { + nve0_fifo_intr_chsw(priv); + nv_wr32(priv, 0x002100, 0x00010000); + stat &= ~0x00010000; + } - while (u) { - int i = ffs(u) - 1; - nve0_fifo_isr_vm_fault(priv, i); - u &= ~(1 << i); - } + if (stat & 0x00800000) { + nv_error(priv, "FB_FLUSH_TIMEOUT\n"); + nv_wr32(priv, 0x002100, 0x00800000); + stat &= ~0x00800000; + } - nv_wr32(priv, 0x00259c, units); - stat &= ~0x10000000; + if (stat & 0x01000000) { + nv_error(priv, "LB_ERROR\n"); + nv_wr32(priv, 0x002100, 0x01000000); + stat &= ~0x01000000; } - if (stat & 0x20000000) { - u32 units = nv_rd32(priv, 0x0025a0); - u32 u = units; + if (stat & 0x08000000) { + nve0_fifo_intr_dropped_fault(priv); + nv_wr32(priv, 0x002100, 0x08000000); + stat &= ~0x08000000; + } - while (u) { - int i = ffs(u) - 1; - nve0_fifo_isr_subfifo_intr(priv, i); - u &= ~(1 << i); + if (stat & 0x10000000) { + u32 mask = nv_rd32(priv, 0x00259c); + while (mask) { + u32 unit = __ffs(mask); + nve0_fifo_intr_fault(priv, unit); + nv_wr32(priv, 0x00259c, (1 << unit)); + mask &= ~(1 << unit); } + stat &= ~0x10000000; + } - nv_wr32(priv, 0x0025a0, units); + if (stat & 0x20000000) { + u32 mask = nv_rd32(priv, 0x0025a0); + while (mask) { + u32 unit = __ffs(mask); + nve0_fifo_intr_pbdma(priv, unit); + nv_wr32(priv, 0x0025a0, (1 << unit)); + mask &= ~(1 << unit); + } stat &= ~0x20000000; } if (stat & 0x40000000) { - nv_warn(priv, "unknown status 0x40000000\n"); - nv_mask(priv, 0x002a00, 0x00000000, 0x00000000); + nve0_fifo_intr_runlist(priv); stat &= ~0x40000000; } if (stat & 0x80000000) { - nouveau_event_trigger(priv->base.uevent, 0); + nve0_fifo_intr_engine(priv); nv_wr32(priv, 0x002100, 0x80000000); stat &= ~0x80000000; } if (stat) { - nv_fatal(priv, "unhandled status 0x%08x\n", stat); + nv_error(priv, "INTR 0x%08x\n", stat); + nv_mask(priv, 0x002140, stat, 0x00000000); nv_wr32(priv, 0x002100, stat); - nv_wr32(priv, 0x002140, 0); } } static void -nve0_fifo_uevent_enable(struct nouveau_event *event, int index) +nve0_fifo_uevent_enable(struct nouveau_event *event, int type, int index) { struct nve0_fifo_priv *priv = event->priv; nv_mask(priv, 0x002140, 0x80000000, 0x80000000); } static void -nve0_fifo_uevent_disable(struct nouveau_event *event, int index) +nve0_fifo_uevent_disable(struct nouveau_event *event, int type, int index) { struct nve0_fifo_priv *priv = event->priv; nv_mask(priv, 0x002140, 0x80000000, 0x00000000); } -static int -nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +int +nve0_fifo_fini(struct nouveau_object *object, bool suspend) { - struct nve0_fifo_priv *priv; - int ret, i; + struct nve0_fifo_priv *priv = (void *)object; + int ret; - ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv); - *pobject = nv_object(priv); + ret = nouveau_fifo_fini(&priv->base, suspend); if (ret) return ret; - for (i = 0; i < FIFO_ENGINE_NR; i++) { - ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, - 0, &priv->engine[i].playlist[0]); - if (ret) - return ret; + /* allow mmu fault interrupts, even when we're not using fifo */ + nv_mask(priv, 0x002140, 0x10000000, 0x10000000); + return 0; +} - ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, - 0, &priv->engine[i].playlist[1]); - if (ret) - return ret; - } +int +nve0_fifo_init(struct nouveau_object *object) +{ + struct nve0_fifo_priv *priv = (void *)object; + int ret, i; - ret = nouveau_gpuobj_new(nv_object(priv), NULL, 4096 * 0x200, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); + ret = nouveau_fifo_init(&priv->base); if (ret) return ret; - ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, - &priv->user.bar); - if (ret) - return ret; + /* enable all available PBDMA units */ + nv_wr32(priv, 0x000204, 0xffffffff); + priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204)); + nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr); - priv->base.uevent->enable = nve0_fifo_uevent_enable; - priv->base.uevent->disable = nve0_fifo_uevent_disable; - priv->base.uevent->priv = priv; + /* PBDMA[n] */ + for (i = 0; i < priv->spoon_nr; i++) { + nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + } - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nve0_fifo_intr; - nv_engine(priv)->cclass = &nve0_fifo_cclass; - nv_engine(priv)->sclass = nve0_fifo_sclass; + nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + + nv_wr32(priv, 0x002100, 0xffffffff); + nv_wr32(priv, 0x002140, 0x7fffffff); return 0; } -static void +void nve0_fifo_dtor(struct nouveau_object *object) { struct nve0_fifo_priv *priv = (void *)object; @@ -638,50 +1019,73 @@ nve0_fifo_dtor(struct nouveau_object *object) nouveau_gpuobj_ref(NULL, &priv->user.mem); for (i = 0; i < FIFO_ENGINE_NR; i++) { - nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]); - nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]); + nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[1]); + nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[0]); } nouveau_fifo_destroy(&priv->base); } -static int -nve0_fifo_init(struct nouveau_object *object) +int +nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nve0_fifo_priv *priv = (void *)object; + struct nve0_fifo_impl *impl = (void *)oclass; + struct nve0_fifo_priv *priv; int ret, i; - ret = nouveau_fifo_init(&priv->base); + ret = nouveau_fifo_create(parent, engine, oclass, 0, + impl->channels - 1, &priv); + *pobject = nv_object(priv); if (ret) return ret; - /* enable all available PSUBFIFOs */ - nv_wr32(priv, 0x000204, 0xffffffff); - priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204)); - nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr); + INIT_WORK(&priv->fault, nve0_fifo_recover_work); - /* PSUBFIFO[n] */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + for (i = 0; i < FIFO_ENGINE_NR; i++) { + ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, + 0, &priv->engine[i].runlist[0]); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, + 0, &priv->engine[i].runlist[1]); + if (ret) + return ret; + + init_waitqueue_head(&priv->engine[i].wait); } - nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + ret = nouveau_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); + if (ret) + return ret; - nv_wr32(priv, 0x002a00, 0xffffffff); - nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x3fffffff); + ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, + &priv->user.bar); + 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; + + nv_subdev(priv)->unit = 0x00000100; + nv_subdev(priv)->intr = nve0_fifo_intr; + nv_engine(priv)->cclass = &nve0_fifo_cclass; + nv_engine(priv)->sclass = nve0_fifo_sclass; return 0; } -struct nouveau_oclass -nve0_fifo_oclass = { - .handle = NV_ENGINE(FIFO, 0xe0), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nve0_fifo_oclass = &(struct nve0_fifo_impl) { + .base.handle = NV_ENGINE(FIFO, 0xe0), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nve0_fifo_ctor, .dtor = nve0_fifo_dtor, .init = nve0_fifo_init, - .fini = _nouveau_fifo_fini, + .fini = nve0_fifo_fini, }, -}; + .channels = 4096, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h new file mode 100644 index 00000000000..e96b32bb1bb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_FIFO_NVE0_H__ +#define __NVKM_FIFO_NVE0_H__ + +#include <engine/fifo.h> + +int nve0_fifo_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nve0_fifo_dtor(struct nouveau_object *); +int nve0_fifo_init(struct nouveau_object *); +int nve0_fifo_fini(struct nouveau_object *, bool); + +struct nve0_fifo_impl { + struct nouveau_oclass base; + u32 channels; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c new file mode 100644 index 00000000000..224ee0287ab --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c @@ -0,0 +1,53 @@ +/* + * 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 "ctxnvc0.h" + +static const struct nvc0_graph_pack +gk20a_grctx_pack_mthd[] = { + { nve4_grctx_init_a097_0, 0xa297 }, + { nvc0_grctx_init_902d_0, 0x902d }, + {} +}; + +struct nouveau_oclass * +gk20a_grctx_oclass = &(struct nvc0_grctx_oclass) { + .base.handle = NV_ENGCTX(GR, 0xea), + .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, + .mods = nve4_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = nve4_grctx_pack_hub, + .gpc = nve4_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nve4_grctx_pack_tpc, + .ppc = nve4_grctx_pack_ppc, + .icmd = nve4_grctx_pack_icmd, + .mthd = gk20a_grctx_pack_mthd, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c new file mode 100644 index 00000000000..b0d0fb2f4d0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c @@ -0,0 +1,991 @@ +/* + * 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 +gm107_grctx_init_icmd_0[] = { + { 0x001000, 1, 0x01, 0x00000004 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x0000a9, 1, 0x01, 0x0000ffff }, + { 0x000038, 1, 0x01, 0x0fac6881 }, + { 0x00003d, 1, 0x01, 0x00000001 }, + { 0x0000e8, 8, 0x01, 0x00000400 }, + { 0x000078, 8, 0x01, 0x00000300 }, + { 0x000050, 1, 0x01, 0x00000011 }, + { 0x000058, 8, 0x01, 0x00000008 }, + { 0x000208, 8, 0x01, 0x00000001 }, + { 0x000081, 1, 0x01, 0x00000001 }, + { 0x000085, 1, 0x01, 0x00000004 }, + { 0x000088, 1, 0x01, 0x00000400 }, + { 0x000090, 1, 0x01, 0x00000300 }, + { 0x000098, 1, 0x01, 0x00001001 }, + { 0x0000e3, 1, 0x01, 0x00000001 }, + { 0x0000da, 1, 0x01, 0x00000001 }, + { 0x0000f8, 1, 0x01, 0x00000003 }, + { 0x0000fa, 1, 0x01, 0x00000001 }, + { 0x0000b1, 2, 0x01, 0x00000001 }, + { 0x00009f, 4, 0x01, 0x0000ffff }, + { 0x0000a8, 1, 0x01, 0x0000ffff }, + { 0x0000ad, 1, 0x01, 0x0000013e }, + { 0x0000e1, 1, 0x01, 0x00000010 }, + { 0x000290, 16, 0x01, 0x00000000 }, + { 0x0003b0, 16, 0x01, 0x00000000 }, + { 0x0002a0, 16, 0x01, 0x00000000 }, + { 0x000420, 16, 0x01, 0x00000000 }, + { 0x0002b0, 16, 0x01, 0x00000000 }, + { 0x000430, 16, 0x01, 0x00000000 }, + { 0x0002c0, 16, 0x01, 0x00000000 }, + { 0x0004d0, 16, 0x01, 0x00000000 }, + { 0x000720, 16, 0x01, 0x00000000 }, + { 0x0008c0, 16, 0x01, 0x00000000 }, + { 0x000890, 16, 0x01, 0x00000000 }, + { 0x0008e0, 16, 0x01, 0x00000000 }, + { 0x0008a0, 16, 0x01, 0x00000000 }, + { 0x0008f0, 16, 0x01, 0x00000000 }, + { 0x00094c, 1, 0x01, 0x000000ff }, + { 0x00094d, 1, 0x01, 0xffffffff }, + { 0x00094e, 1, 0x01, 0x00000002 }, + { 0x0002f2, 2, 0x01, 0x00000001 }, + { 0x0002f5, 1, 0x01, 0x00000001 }, + { 0x0002f7, 1, 0x01, 0x00000001 }, + { 0x000303, 1, 0x01, 0x00000001 }, + { 0x0002e6, 1, 0x01, 0x00000001 }, + { 0x000466, 1, 0x01, 0x00000052 }, + { 0x000301, 1, 0x01, 0x3f800000 }, + { 0x000304, 1, 0x01, 0x30201000 }, + { 0x000305, 1, 0x01, 0x70605040 }, + { 0x000306, 1, 0x01, 0xb8a89888 }, + { 0x000307, 1, 0x01, 0xf8e8d8c8 }, + { 0x00030a, 1, 0x01, 0x00ffff00 }, + { 0x0000de, 1, 0x01, 0x00000001 }, + { 0x00030b, 1, 0x01, 0x0000001a }, + { 0x00030c, 1, 0x01, 0x00000001 }, + { 0x000318, 1, 0x01, 0x00000001 }, + { 0x000340, 1, 0x01, 0x00000000 }, + { 0x00037d, 1, 0x01, 0x00000006 }, + { 0x0003a0, 1, 0x01, 0x00000002 }, + { 0x0003aa, 1, 0x01, 0x00000001 }, + { 0x0003a9, 1, 0x01, 0x00000001 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000383, 1, 0x01, 0x00000011 }, + { 0x000360, 1, 0x01, 0x00000040 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x00037a, 1, 0x01, 0x00000012 }, + { 0x000619, 1, 0x01, 0x00000003 }, + { 0x000811, 1, 0x01, 0x00000003 }, + { 0x000812, 1, 0x01, 0x00000004 }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000815, 1, 0x01, 0x0000000b }, + { 0x000800, 6, 0x01, 0x00000001 }, + { 0x000632, 1, 0x01, 0x00000001 }, + { 0x000633, 1, 0x01, 0x00000002 }, + { 0x000634, 1, 0x01, 0x00000003 }, + { 0x000635, 1, 0x01, 0x00000004 }, + { 0x000654, 1, 0x01, 0x3f800000 }, + { 0x000657, 1, 0x01, 0x3f800000 }, + { 0x000655, 2, 0x01, 0x3f800000 }, + { 0x0006cd, 1, 0x01, 0x3f800000 }, + { 0x0007f5, 1, 0x01, 0x3f800000 }, + { 0x0007dc, 1, 0x01, 0x39291909 }, + { 0x0007dd, 1, 0x01, 0x79695949 }, + { 0x0007de, 1, 0x01, 0xb9a99989 }, + { 0x0007df, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007e8, 1, 0x01, 0x00003210 }, + { 0x0007e9, 1, 0x01, 0x00007654 }, + { 0x0007ea, 1, 0x01, 0x00000098 }, + { 0x0007ec, 1, 0x01, 0x39291909 }, + { 0x0007ed, 1, 0x01, 0x79695949 }, + { 0x0007ee, 1, 0x01, 0xb9a99989 }, + { 0x0007ef, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007f0, 1, 0x01, 0x00003210 }, + { 0x0007f1, 1, 0x01, 0x00007654 }, + { 0x0007f2, 1, 0x01, 0x00000098 }, + { 0x0005a5, 1, 0x01, 0x00000001 }, + { 0x0005d0, 1, 0x01, 0x20181008 }, + { 0x0005d1, 1, 0x01, 0x40383028 }, + { 0x0005d2, 1, 0x01, 0x60585048 }, + { 0x0005d3, 1, 0x01, 0x80787068 }, + { 0x000980, 128, 0x01, 0x00000000 }, + { 0x000468, 1, 0x01, 0x00000004 }, + { 0x00046c, 1, 0x01, 0x00000001 }, + { 0x000470, 96, 0x01, 0x00000000 }, + { 0x000510, 16, 0x01, 0x3f800000 }, + { 0x000520, 1, 0x01, 0x000002b6 }, + { 0x000529, 1, 0x01, 0x00000001 }, + { 0x000530, 16, 0x01, 0xffff0000 }, + { 0x000550, 32, 0x01, 0xffff0000 }, + { 0x000585, 1, 0x01, 0x0000003f }, + { 0x000576, 1, 0x01, 0x00000003 }, + { 0x00057b, 1, 0x01, 0x00000059 }, + { 0x000586, 1, 0x01, 0x00000040 }, + { 0x000582, 2, 0x01, 0x00000080 }, + { 0x000595, 1, 0x01, 0x00400040 }, + { 0x000596, 1, 0x01, 0x00000492 }, + { 0x000597, 1, 0x01, 0x08080203 }, + { 0x0005ad, 1, 0x01, 0x00000008 }, + { 0x000598, 1, 0x01, 0x00020001 }, + { 0x0005c2, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, + { 0x00063a, 1, 0x01, 0x00000002 }, + { 0x00063b, 2, 0x01, 0x00000001 }, + { 0x00063d, 1, 0x01, 0x00000002 }, + { 0x00063e, 1, 0x01, 0x00000001 }, + { 0x0008b8, 8, 0x01, 0x00000001 }, + { 0x000900, 8, 0x01, 0x00000001 }, + { 0x000908, 8, 0x01, 0x00000002 }, + { 0x000910, 16, 0x01, 0x00000001 }, + { 0x000920, 8, 0x01, 0x00000002 }, + { 0x000928, 8, 0x01, 0x00000001 }, + { 0x000662, 1, 0x01, 0x00000001 }, + { 0x000648, 9, 0x01, 0x00000001 }, + { 0x000658, 1, 0x01, 0x0000000f }, + { 0x0007ff, 1, 0x01, 0x0000000a }, + { 0x00066a, 1, 0x01, 0x40000000 }, + { 0x00066b, 1, 0x01, 0x10000000 }, + { 0x00066c, 2, 0x01, 0xffff0000 }, + { 0x0007af, 2, 0x01, 0x00000008 }, + { 0x0007f6, 1, 0x01, 0x00000001 }, + { 0x0006b2, 1, 0x01, 0x00000055 }, + { 0x0007ad, 1, 0x01, 0x00000003 }, + { 0x000971, 1, 0x01, 0x00000008 }, + { 0x000972, 1, 0x01, 0x00000040 }, + { 0x000973, 1, 0x01, 0x0000012c }, + { 0x00097c, 1, 0x01, 0x00000040 }, + { 0x000975, 1, 0x01, 0x00000020 }, + { 0x000976, 1, 0x01, 0x00000001 }, + { 0x000977, 1, 0x01, 0x00000020 }, + { 0x000978, 1, 0x01, 0x00000001 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x00095e, 1, 0x01, 0x20164010 }, + { 0x00095f, 1, 0x01, 0x00000020 }, + { 0x000a0d, 1, 0x01, 0x00000006 }, + { 0x00097d, 1, 0x01, 0x0000000c }, + { 0x000683, 1, 0x01, 0x00000006 }, + { 0x000687, 1, 0x01, 0x003fffff }, + { 0x0006a0, 1, 0x01, 0x00000005 }, + { 0x000840, 1, 0x01, 0x00400008 }, + { 0x000841, 1, 0x01, 0x08000080 }, + { 0x000842, 1, 0x01, 0x00400008 }, + { 0x000843, 1, 0x01, 0x08000080 }, + { 0x000818, 8, 0x01, 0x00000000 }, + { 0x000848, 16, 0x01, 0x00000000 }, + { 0x000738, 1, 0x01, 0x00000000 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ab, 1, 0x01, 0x00000002 }, + { 0x0006ac, 1, 0x01, 0x00000080 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x0006bb, 1, 0x01, 0x000000cf }, + { 0x0006ce, 1, 0x01, 0x2a712488 }, + { 0x000739, 1, 0x01, 0x4085c000 }, + { 0x00073a, 1, 0x01, 0x00000080 }, + { 0x000786, 1, 0x01, 0x80000100 }, + { 0x00073c, 1, 0x01, 0x00010100 }, + { 0x00073d, 1, 0x01, 0x02800000 }, + { 0x000787, 1, 0x01, 0x000000cf }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x000836, 1, 0x01, 0x00000001 }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x000833, 1, 0x01, 0x04444480 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c1b0, 8, 0x01, 0x0000000f }, + { 0x00c1b8, 1, 0x01, 0x0fac6881 }, + { 0x00c1b9, 1, 0x01, 0x00fac688 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000002 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000008 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000818, 8, 0x01, 0x00000000 }, + { 0x000848, 16, 0x01, 0x00000000 }, + { 0x000738, 1, 0x01, 0x00000000 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000001 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_icmd[] = { + { gm107_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_b097_0[] = { + { 0x000800, 8, 0x40, 0x00000000 }, + { 0x000804, 8, 0x40, 0x00000000 }, + { 0x000808, 8, 0x40, 0x00000400 }, + { 0x00080c, 8, 0x40, 0x00000300 }, + { 0x000810, 1, 0x04, 0x000000cf }, + { 0x000850, 7, 0x40, 0x00000000 }, + { 0x000814, 8, 0x40, 0x00000040 }, + { 0x000818, 8, 0x40, 0x00000001 }, + { 0x00081c, 8, 0x40, 0x00000000 }, + { 0x000820, 8, 0x40, 0x00000000 }, + { 0x001c00, 16, 0x10, 0x00000000 }, + { 0x001c04, 16, 0x10, 0x00000000 }, + { 0x001c08, 16, 0x10, 0x00000000 }, + { 0x001c0c, 16, 0x10, 0x00000000 }, + { 0x001d00, 16, 0x10, 0x00000000 }, + { 0x001d04, 16, 0x10, 0x00000000 }, + { 0x001d08, 16, 0x10, 0x00000000 }, + { 0x001d0c, 16, 0x10, 0x00000000 }, + { 0x001f00, 16, 0x08, 0x00000000 }, + { 0x001f04, 16, 0x08, 0x00000000 }, + { 0x001f80, 16, 0x08, 0x00000000 }, + { 0x001f84, 16, 0x08, 0x00000000 }, + { 0x002000, 1, 0x04, 0x00000000 }, + { 0x002040, 1, 0x04, 0x00000011 }, + { 0x002080, 1, 0x04, 0x00000020 }, + { 0x0020c0, 1, 0x04, 0x00000030 }, + { 0x002100, 1, 0x04, 0x00000040 }, + { 0x002140, 1, 0x04, 0x00000051 }, + { 0x00200c, 6, 0x40, 0x00000001 }, + { 0x002010, 1, 0x04, 0x00000000 }, + { 0x002050, 1, 0x04, 0x00000000 }, + { 0x002090, 1, 0x04, 0x00000001 }, + { 0x0020d0, 1, 0x04, 0x00000002 }, + { 0x002110, 1, 0x04, 0x00000003 }, + { 0x002150, 1, 0x04, 0x00000004 }, + { 0x000380, 4, 0x20, 0x00000000 }, + { 0x000384, 4, 0x20, 0x00000000 }, + { 0x000388, 4, 0x20, 0x00000000 }, + { 0x00038c, 4, 0x20, 0x00000000 }, + { 0x000700, 4, 0x10, 0x00000000 }, + { 0x000704, 4, 0x10, 0x00000000 }, + { 0x000708, 4, 0x10, 0x00000000 }, + { 0x002800, 128, 0x04, 0x00000000 }, + { 0x000a00, 16, 0x20, 0x00000000 }, + { 0x000a04, 16, 0x20, 0x00000000 }, + { 0x000a08, 16, 0x20, 0x00000000 }, + { 0x000a0c, 16, 0x20, 0x00000000 }, + { 0x000a10, 16, 0x20, 0x00000000 }, + { 0x000a14, 16, 0x20, 0x00000000 }, + { 0x000c00, 16, 0x10, 0x00000000 }, + { 0x000c04, 16, 0x10, 0x00000000 }, + { 0x000c08, 16, 0x10, 0x00000000 }, + { 0x000c0c, 16, 0x10, 0x3f800000 }, + { 0x000d00, 8, 0x08, 0xffff0000 }, + { 0x000d04, 8, 0x08, 0xffff0000 }, + { 0x000e00, 16, 0x10, 0x00000000 }, + { 0x000e04, 16, 0x10, 0xffff0000 }, + { 0x000e08, 16, 0x10, 0xffff0000 }, + { 0x000d40, 4, 0x08, 0x00000000 }, + { 0x000d44, 4, 0x08, 0x00000000 }, + { 0x001e00, 8, 0x20, 0x00000001 }, + { 0x001e04, 8, 0x20, 0x00000001 }, + { 0x001e08, 8, 0x20, 0x00000002 }, + { 0x001e0c, 8, 0x20, 0x00000001 }, + { 0x001e10, 8, 0x20, 0x00000001 }, + { 0x001e14, 8, 0x20, 0x00000002 }, + { 0x001e18, 8, 0x20, 0x00000001 }, + { 0x001480, 8, 0x10, 0x00000000 }, + { 0x001484, 8, 0x10, 0x00000000 }, + { 0x001488, 8, 0x10, 0x00000000 }, + { 0x003400, 128, 0x04, 0x00000000 }, + { 0x00030c, 1, 0x04, 0x00000001 }, + { 0x001944, 1, 0x04, 0x00000000 }, + { 0x001514, 1, 0x04, 0x00000000 }, + { 0x000d68, 1, 0x04, 0x0000ffff }, + { 0x00121c, 1, 0x04, 0x0fac6881 }, + { 0x000fac, 1, 0x04, 0x00000001 }, + { 0x001538, 1, 0x04, 0x00000001 }, + { 0x000fe0, 2, 0x04, 0x00000000 }, + { 0x000fe8, 1, 0x04, 0x00000014 }, + { 0x000fec, 1, 0x04, 0x00000040 }, + { 0x000ff0, 1, 0x04, 0x00000000 }, + { 0x00179c, 1, 0x04, 0x00000000 }, + { 0x001228, 1, 0x04, 0x00000400 }, + { 0x00122c, 1, 0x04, 0x00000300 }, + { 0x001230, 1, 0x04, 0x00010001 }, + { 0x0007f8, 1, 0x04, 0x00000000 }, + { 0x0015b4, 1, 0x04, 0x00000001 }, + { 0x0015cc, 1, 0x04, 0x00000000 }, + { 0x001534, 1, 0x04, 0x00000000 }, + { 0x000754, 1, 0x04, 0x00000001 }, + { 0x000fb0, 1, 0x04, 0x00000000 }, + { 0x0015d0, 1, 0x04, 0x00000000 }, + { 0x00153c, 1, 0x04, 0x00000000 }, + { 0x0016b4, 1, 0x04, 0x00000003 }, + { 0x000fbc, 4, 0x04, 0x0000ffff }, + { 0x000df8, 2, 0x04, 0x00000000 }, + { 0x001948, 1, 0x04, 0x00000000 }, + { 0x001970, 1, 0x04, 0x00000001 }, + { 0x00161c, 1, 0x04, 0x000009f0 }, + { 0x000dcc, 1, 0x04, 0x00000010 }, + { 0x0015e4, 1, 0x04, 0x00000000 }, + { 0x001160, 32, 0x04, 0x25e00040 }, + { 0x001880, 32, 0x04, 0x00000000 }, + { 0x000f84, 2, 0x04, 0x00000000 }, + { 0x0017c8, 2, 0x04, 0x00000000 }, + { 0x0017d0, 1, 0x04, 0x000000ff }, + { 0x0017d4, 1, 0x04, 0xffffffff }, + { 0x0017d8, 1, 0x04, 0x00000002 }, + { 0x0017dc, 1, 0x04, 0x00000000 }, + { 0x0015f4, 2, 0x04, 0x00000000 }, + { 0x001434, 2, 0x04, 0x00000000 }, + { 0x000d74, 1, 0x04, 0x00000000 }, + { 0x0013a4, 1, 0x04, 0x00000000 }, + { 0x001318, 1, 0x04, 0x00000001 }, + { 0x001080, 2, 0x04, 0x00000000 }, + { 0x001088, 2, 0x04, 0x00000001 }, + { 0x001090, 1, 0x04, 0x00000000 }, + { 0x001094, 1, 0x04, 0x00000001 }, + { 0x001098, 1, 0x04, 0x00000000 }, + { 0x00109c, 1, 0x04, 0x00000001 }, + { 0x0010a0, 2, 0x04, 0x00000000 }, + { 0x001644, 1, 0x04, 0x00000000 }, + { 0x000748, 1, 0x04, 0x00000000 }, + { 0x000de8, 1, 0x04, 0x00000000 }, + { 0x001648, 1, 0x04, 0x00000000 }, + { 0x0012a4, 1, 0x04, 0x00000000 }, + { 0x001120, 4, 0x04, 0x00000000 }, + { 0x001118, 1, 0x04, 0x00000000 }, + { 0x00164c, 1, 0x04, 0x00000000 }, + { 0x001658, 1, 0x04, 0x00000000 }, + { 0x001910, 1, 0x04, 0x00000290 }, + { 0x001518, 1, 0x04, 0x00000000 }, + { 0x00165c, 1, 0x04, 0x00000001 }, + { 0x001520, 1, 0x04, 0x00000000 }, + { 0x001604, 1, 0x04, 0x00000000 }, + { 0x001570, 1, 0x04, 0x00000000 }, + { 0x0013b0, 2, 0x04, 0x3f800000 }, + { 0x00020c, 1, 0x04, 0x00000000 }, + { 0x001670, 1, 0x04, 0x30201000 }, + { 0x001674, 1, 0x04, 0x70605040 }, + { 0x001678, 1, 0x04, 0xb8a89888 }, + { 0x00167c, 1, 0x04, 0xf8e8d8c8 }, + { 0x00166c, 1, 0x04, 0x00000000 }, + { 0x001680, 1, 0x04, 0x00ffff00 }, + { 0x0012d0, 1, 0x04, 0x00000003 }, + { 0x0012d4, 1, 0x04, 0x00000002 }, + { 0x001684, 2, 0x04, 0x00000000 }, + { 0x000dac, 2, 0x04, 0x00001b02 }, + { 0x000db4, 1, 0x04, 0x00000000 }, + { 0x00168c, 1, 0x04, 0x00000000 }, + { 0x0015bc, 1, 0x04, 0x00000000 }, + { 0x00156c, 1, 0x04, 0x00000000 }, + { 0x00187c, 1, 0x04, 0x00000000 }, + { 0x001110, 1, 0x04, 0x00000001 }, + { 0x000dc0, 3, 0x04, 0x00000000 }, + { 0x000f40, 5, 0x04, 0x00000000 }, + { 0x001234, 1, 0x04, 0x00000000 }, + { 0x001690, 1, 0x04, 0x00000000 }, + { 0x000790, 5, 0x04, 0x00000000 }, + { 0x00077c, 1, 0x04, 0x00000000 }, + { 0x001000, 1, 0x04, 0x00000010 }, + { 0x0010fc, 1, 0x04, 0x00000000 }, + { 0x001290, 1, 0x04, 0x00000000 }, + { 0x000218, 1, 0x04, 0x00000010 }, + { 0x0012d8, 1, 0x04, 0x00000000 }, + { 0x0012dc, 1, 0x04, 0x00000010 }, + { 0x000d94, 1, 0x04, 0x00000001 }, + { 0x00155c, 2, 0x04, 0x00000000 }, + { 0x001564, 1, 0x04, 0x00000fff }, + { 0x001574, 2, 0x04, 0x00000000 }, + { 0x00157c, 1, 0x04, 0x000fffff }, + { 0x001354, 1, 0x04, 0x00000000 }, + { 0x001610, 1, 0x04, 0x00000012 }, + { 0x001608, 2, 0x04, 0x00000000 }, + { 0x00260c, 1, 0x04, 0x00000000 }, + { 0x0007ac, 1, 0x04, 0x00000000 }, + { 0x00162c, 1, 0x04, 0x00000003 }, + { 0x000210, 1, 0x04, 0x00000000 }, + { 0x000320, 1, 0x04, 0x00000000 }, + { 0x000324, 6, 0x04, 0x3f800000 }, + { 0x000750, 1, 0x04, 0x00000000 }, + { 0x000760, 1, 0x04, 0x39291909 }, + { 0x000764, 1, 0x04, 0x79695949 }, + { 0x000768, 1, 0x04, 0xb9a99989 }, + { 0x00076c, 1, 0x04, 0xf9e9d9c9 }, + { 0x000770, 1, 0x04, 0x30201000 }, + { 0x000774, 1, 0x04, 0x70605040 }, + { 0x000778, 1, 0x04, 0x00009080 }, + { 0x000780, 1, 0x04, 0x39291909 }, + { 0x000784, 1, 0x04, 0x79695949 }, + { 0x000788, 1, 0x04, 0xb9a99989 }, + { 0x00078c, 1, 0x04, 0xf9e9d9c9 }, + { 0x0007d0, 1, 0x04, 0x30201000 }, + { 0x0007d4, 1, 0x04, 0x70605040 }, + { 0x0007d8, 1, 0x04, 0x00009080 }, + { 0x00037c, 1, 0x04, 0x00000001 }, + { 0x000740, 2, 0x04, 0x00000000 }, + { 0x002600, 1, 0x04, 0x00000000 }, + { 0x001918, 1, 0x04, 0x00000000 }, + { 0x00191c, 1, 0x04, 0x00000900 }, + { 0x001920, 1, 0x04, 0x00000405 }, + { 0x001308, 1, 0x04, 0x00000001 }, + { 0x001924, 1, 0x04, 0x00000000 }, + { 0x0013ac, 1, 0x04, 0x00000000 }, + { 0x00192c, 1, 0x04, 0x00000001 }, + { 0x00193c, 1, 0x04, 0x00002c1c }, + { 0x000d7c, 1, 0x04, 0x00000000 }, + { 0x000f8c, 1, 0x04, 0x00000000 }, + { 0x0002c0, 1, 0x04, 0x00000001 }, + { 0x001510, 1, 0x04, 0x00000000 }, + { 0x001940, 1, 0x04, 0x00000000 }, + { 0x000ff4, 2, 0x04, 0x00000000 }, + { 0x00194c, 2, 0x04, 0x00000000 }, + { 0x001968, 1, 0x04, 0x00000000 }, + { 0x001590, 1, 0x04, 0x0000003f }, + { 0x0007e8, 4, 0x04, 0x00000000 }, + { 0x00196c, 1, 0x04, 0x00000011 }, + { 0x0002e4, 1, 0x04, 0x0000b001 }, + { 0x00036c, 2, 0x04, 0x00000000 }, + { 0x00197c, 1, 0x04, 0x00000000 }, + { 0x000fcc, 2, 0x04, 0x00000000 }, + { 0x0002d8, 1, 0x04, 0x00000040 }, + { 0x001980, 1, 0x04, 0x00000080 }, + { 0x001504, 1, 0x04, 0x00000080 }, + { 0x001984, 1, 0x04, 0x00000000 }, + { 0x000f60, 1, 0x04, 0x00000000 }, + { 0x000f64, 1, 0x04, 0x00400040 }, + { 0x000f68, 1, 0x04, 0x00002212 }, + { 0x000f6c, 1, 0x04, 0x08080203 }, + { 0x001108, 1, 0x04, 0x00000008 }, + { 0x000f70, 1, 0x04, 0x00080001 }, + { 0x000ffc, 1, 0x04, 0x00000000 }, + { 0x000300, 1, 0x04, 0x00000001 }, + { 0x0013a8, 1, 0x04, 0x00000000 }, + { 0x0012ec, 1, 0x04, 0x00000000 }, + { 0x001310, 1, 0x04, 0x00000000 }, + { 0x001314, 1, 0x04, 0x00000001 }, + { 0x001380, 1, 0x04, 0x00000000 }, + { 0x001384, 4, 0x04, 0x00000001 }, + { 0x001394, 1, 0x04, 0x00000000 }, + { 0x00139c, 1, 0x04, 0x00000000 }, + { 0x001398, 1, 0x04, 0x00000000 }, + { 0x001594, 1, 0x04, 0x00000000 }, + { 0x001598, 4, 0x04, 0x00000001 }, + { 0x000f54, 3, 0x04, 0x00000000 }, + { 0x0019bc, 1, 0x04, 0x00000000 }, + { 0x000f9c, 2, 0x04, 0x00000000 }, + { 0x0012cc, 1, 0x04, 0x00000000 }, + { 0x0012e8, 1, 0x04, 0x00000000 }, + { 0x00130c, 1, 0x04, 0x00000001 }, + { 0x001360, 8, 0x04, 0x00000000 }, + { 0x00133c, 2, 0x04, 0x00000001 }, + { 0x001344, 1, 0x04, 0x00000002 }, + { 0x001348, 2, 0x04, 0x00000001 }, + { 0x001350, 1, 0x04, 0x00000002 }, + { 0x001358, 1, 0x04, 0x00000001 }, + { 0x0012e4, 1, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, + { 0x0019c0, 1, 0x04, 0x00000000 }, + { 0x001140, 1, 0x04, 0x00000000 }, + { 0x000dd0, 1, 0x04, 0x00000000 }, + { 0x000dd4, 1, 0x04, 0x00000001 }, + { 0x0002f4, 1, 0x04, 0x00000000 }, + { 0x0019c4, 1, 0x04, 0x00000000 }, + { 0x0019c8, 1, 0x04, 0x00001500 }, + { 0x00135c, 1, 0x04, 0x00000000 }, + { 0x000f90, 1, 0x04, 0x00000000 }, + { 0x0019e0, 8, 0x04, 0x00000001 }, + { 0x0019cc, 1, 0x04, 0x00000001 }, + { 0x0015b8, 1, 0x04, 0x00000000 }, + { 0x001a00, 1, 0x04, 0x00001111 }, + { 0x001a04, 7, 0x04, 0x00000000 }, + { 0x000d6c, 2, 0x04, 0xffff0000 }, + { 0x0010f8, 1, 0x04, 0x00001010 }, + { 0x000d80, 5, 0x04, 0x00000000 }, + { 0x000da0, 1, 0x04, 0x00000000 }, + { 0x0007a4, 2, 0x04, 0x00000000 }, + { 0x001508, 1, 0x04, 0x80000000 }, + { 0x00150c, 1, 0x04, 0x40000000 }, + { 0x001668, 1, 0x04, 0x00000000 }, + { 0x000318, 2, 0x04, 0x00000008 }, + { 0x000d9c, 1, 0x04, 0x00000001 }, + { 0x000f14, 1, 0x04, 0x00000000 }, + { 0x000374, 1, 0x04, 0x00000000 }, + { 0x000378, 1, 0x04, 0x0000000c }, + { 0x0007dc, 1, 0x04, 0x00000000 }, + { 0x00074c, 1, 0x04, 0x00000055 }, + { 0x001420, 1, 0x04, 0x00000003 }, + { 0x001008, 1, 0x04, 0x00000008 }, + { 0x00100c, 1, 0x04, 0x00000040 }, + { 0x001010, 1, 0x04, 0x0000012c }, + { 0x000d60, 1, 0x04, 0x00000040 }, + { 0x001018, 1, 0x04, 0x00000020 }, + { 0x00101c, 1, 0x04, 0x00000001 }, + { 0x001020, 1, 0x04, 0x00000020 }, + { 0x001024, 1, 0x04, 0x00000001 }, + { 0x001444, 3, 0x04, 0x00000000 }, + { 0x000360, 1, 0x04, 0x20164010 }, + { 0x000364, 1, 0x04, 0x00000020 }, + { 0x000368, 1, 0x04, 0x00000000 }, + { 0x000da8, 1, 0x04, 0x00000030 }, + { 0x000de4, 1, 0x04, 0x00000000 }, + { 0x000204, 1, 0x04, 0x00000006 }, + { 0x0002d0, 1, 0x04, 0x003fffff }, + { 0x001220, 1, 0x04, 0x00000005 }, + { 0x000fdc, 1, 0x04, 0x00000000 }, + { 0x000f98, 1, 0x04, 0x00400008 }, + { 0x001284, 1, 0x04, 0x08000080 }, + { 0x001450, 1, 0x04, 0x00400008 }, + { 0x001454, 1, 0x04, 0x08000080 }, + { 0x000214, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_mthd[] = { + { gm107_grctx_init_b097_0, 0xb097 }, + { nvc0_grctx_init_902d_0, 0x902d }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_fe_0[] = { + { 0x404004, 8, 0x04, 0x00000000 }, + { 0x404024, 1, 0x04, 0x0000e000 }, + { 0x404028, 8, 0x04, 0x00000000 }, + { 0x4040a8, 8, 0x04, 0x00000000 }, + { 0x4040c8, 1, 0x04, 0xf800008f }, + { 0x4040d0, 6, 0x04, 0x00000000 }, + { 0x4040f8, 1, 0x04, 0x00000000 }, + { 0x404100, 10, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, + { 0x404150, 1, 0x04, 0x0000002e }, + { 0x404154, 1, 0x04, 0x00000400 }, + { 0x404158, 1, 0x04, 0x00000200 }, + { 0x404164, 1, 0x04, 0x00000045 }, + { 0x40417c, 2, 0x04, 0x00000000 }, + { 0x404194, 1, 0x04, 0x01000700 }, + { 0x4041a0, 4, 0x04, 0x00000000 }, + { 0x404200, 4, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_ds_0[] = { + { 0x405800, 1, 0x04, 0x0f8001bf }, + { 0x405830, 1, 0x04, 0x0aa01000 }, + { 0x405834, 1, 0x04, 0x08000000 }, + { 0x405838, 1, 0x04, 0x00000000 }, + { 0x405854, 1, 0x04, 0x00000000 }, + { 0x405870, 4, 0x04, 0x00000001 }, + { 0x405a00, 2, 0x04, 0x00000000 }, + { 0x405a18, 1, 0x04, 0x00000000 }, + { 0x405a1c, 1, 0x04, 0x000000ff }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x07410001 }, + { 0x406028, 4, 0x04, 0x00000001 }, + { 0x4064a8, 1, 0x04, 0x00000000 }, + { 0x4064ac, 1, 0x04, 0x00003fff }, + { 0x4064b0, 3, 0x04, 0x00000000 }, + { 0x4064c0, 1, 0x04, 0x80400280 }, + { 0x4064c4, 1, 0x04, 0x0400ffff }, + { 0x4064c8, 1, 0x04, 0x018001ff }, + { 0x4064cc, 9, 0x04, 0x00000000 }, + { 0x4064fc, 1, 0x04, 0x0000022a }, + { 0x406500, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_be_0[] = { + { 0x408800, 1, 0x04, 0x32802a3c }, + { 0x408804, 1, 0x04, 0x00000040 }, + { 0x408808, 1, 0x04, 0x1003e005 }, + { 0x408840, 1, 0x04, 0x0000000b }, + { 0x408900, 1, 0x04, 0xb080b801 }, + { 0x408904, 1, 0x04, 0x63038001 }, + { 0x408908, 1, 0x04, 0x02c8102f }, + { 0x408980, 1, 0x04, 0x0000011d }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { gm107_grctx_init_fe_0 }, + { nvf0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { gm107_grctx_init_ds_0 }, + { nvf0_grctx_init_cwd_0 }, + { gm107_grctx_init_pd_0 }, + { nv108_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { gm107_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_gpc_unk_0[] = { + { 0x418380, 1, 0x04, 0x00000056 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_gpc_unk_1[] = { + { 0x418600, 1, 0x04, 0x0000007f }, + { 0x418684, 1, 0x04, 0x0000001f }, + { 0x418700, 1, 0x04, 0x00000002 }, + { 0x418704, 1, 0x04, 0x00000080 }, + { 0x418708, 1, 0x04, 0x40000000 }, + { 0x41870c, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_setup_0[] = { + { 0x418800, 1, 0x04, 0x7006863a }, + { 0x418810, 1, 0x04, 0x00000000 }, + { 0x418828, 1, 0x04, 0x00000044 }, + { 0x418830, 1, 0x04, 0x10000001 }, + { 0x4188d8, 1, 0x04, 0x00000008 }, + { 0x4188e0, 1, 0x04, 0x01000000 }, + { 0x4188e8, 5, 0x04, 0x00000000 }, + { 0x4188fc, 1, 0x04, 0x20100058 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_gpc_unk_2[] = { + { 0x418d24, 1, 0x04, 0x00000000 }, + { 0x418e00, 1, 0x04, 0x90000000 }, + { 0x418e24, 1, 0x04, 0x00000000 }, + { 0x418e28, 1, 0x04, 0x00000030 }, + { 0x418e30, 1, 0x04, 0x00000000 }, + { 0x418e34, 1, 0x04, 0x00010000 }, + { 0x418e38, 1, 0x04, 0x00000000 }, + { 0x418e40, 22, 0x04, 0x00000000 }, + { 0x418ea0, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_gpc[] = { + { gm107_grctx_init_gpc_unk_0 }, + { nv108_grctx_init_prop_0 }, + { gm107_grctx_init_gpc_unk_1 }, + { gm107_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nv108_grctx_init_crstr_0 }, + { nve4_grctx_init_gpm_0 }, + { gm107_grctx_init_gpc_unk_2 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_tex_0[] = { + { 0x419a00, 1, 0x04, 0x000300f0 }, + { 0x419a04, 1, 0x04, 0x00000005 }, + { 0x419a08, 1, 0x04, 0x00000421 }, + { 0x419a0c, 1, 0x04, 0x00120000 }, + { 0x419a10, 1, 0x04, 0x00000000 }, + { 0x419a14, 1, 0x04, 0x00002200 }, + { 0x419a1c, 1, 0x04, 0x0000c000 }, + { 0x419a20, 1, 0x04, 0x20008a00 }, + { 0x419a30, 1, 0x04, 0x00000001 }, + { 0x419a3c, 1, 0x04, 0x00000002 }, + { 0x419ac4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_mpc_0[] = { + { 0x419c00, 1, 0x04, 0x0000001a }, + { 0x419c04, 1, 0x04, 0x80000006 }, + { 0x419c08, 1, 0x04, 0x00000002 }, + { 0x419c20, 1, 0x04, 0x00000000 }, + { 0x419c24, 1, 0x04, 0x00084210 }, + { 0x419c28, 1, 0x04, 0x3efbefbe }, + { 0x419c2c, 1, 0x04, 0x00000000 }, + { 0x419c34, 1, 0x04, 0x01ff1ff3 }, + { 0x419c3c, 1, 0x04, 0x00001919 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_l1c_0[] = { + { 0x419c84, 1, 0x04, 0x00000020 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_sm_0[] = { + { 0x419e04, 3, 0x04, 0x00000000 }, + { 0x419e10, 1, 0x04, 0x00001c02 }, + { 0x419e44, 1, 0x04, 0x00d3eff2 }, + { 0x419e48, 1, 0x04, 0x00000000 }, + { 0x419e4c, 1, 0x04, 0x0000007f }, + { 0x419e50, 1, 0x04, 0x00000000 }, + { 0x419e60, 4, 0x04, 0x00000000 }, + { 0x419e74, 10, 0x04, 0x00000000 }, + { 0x419eac, 1, 0x04, 0x0001cf8b }, + { 0x419eb0, 1, 0x04, 0x00030300 }, + { 0x419eb8, 1, 0x04, 0x00000000 }, + { 0x419ef0, 24, 0x04, 0x00000000 }, + { 0x419f68, 2, 0x04, 0x00000000 }, + { 0x419f70, 1, 0x04, 0x00000020 }, + { 0x419f78, 1, 0x04, 0x000003eb }, + { 0x419f7c, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { gm107_grctx_init_tex_0 }, + { gm107_grctx_init_mpc_0 }, + { gm107_grctx_init_l1c_0 }, + { gm107_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_cbm_0[] = { + { 0x41bec0, 1, 0x04, 0x00000000 }, + { 0x41bec4, 1, 0x04, 0x01050000 }, + { 0x41bee4, 1, 0x04, 0x00000000 }, + { 0x41bef0, 1, 0x04, 0x000003ff }, + { 0x41bef4, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_wwdx_0[] = { + { 0x41bf00, 1, 0x04, 0x0a418820 }, + { 0x41bf04, 1, 0x04, 0x062080e6 }, + { 0x41bf08, 1, 0x04, 0x020398a4 }, + { 0x41bf0c, 1, 0x04, 0x0e629062 }, + { 0x41bf10, 1, 0x04, 0x0a418820 }, + { 0x41bf14, 1, 0x04, 0x000000e6 }, + { 0x41bfd0, 1, 0x04, 0x00900103 }, + { 0x41bfe0, 1, 0x04, 0x80000000 }, + { 0x41bfe4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { gm107_grctx_init_cbm_0 }, + { gm107_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + +static void +gm107_grctx_generate_mods(struct nvc0_graph_priv *priv, 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); +} + +static void +gm107_grctx_generate_tpcid(struct nvc0_graph_priv *priv) +{ + int gpc, tpc, id; + + for (tpc = 0, id = 0; tpc < 4; tpc++) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + if (tpc < priv->tpc_nr[gpc]) { + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + id++; + } + + nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); + } + } +} + +static void +gm107_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +{ + struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + int i; + + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); + + nv_wr32(priv, 0x404154, 0x00000000); + + oclass->mods(priv, info); + oclass->unkn(priv); + + gm107_grctx_generate_tpcid(priv); + nvc0_grctx_generate_r406028(priv); + nve4_grctx_generate_r418bb8(priv); + nvc0_grctx_generate_r406800(priv); + + nv_wr32(priv, 0x4064d0, 0x00000001); + for (i = 1; i < 8; i++) + nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(priv, 0x406500, 0x00000001); + + nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + + if (priv->gpc_nr == 1) { + nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]); + nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]); + } else { + nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr); + nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr); + } + + nvc0_graph_icmd(priv, oclass->icmd); + nv_wr32(priv, 0x404154, 0x00000400); + nvc0_graph_mthd(priv, oclass->mthd); + + nv_mask(priv, 0x419e00, 0x00808080, 0x00808080); + nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000); + nv_mask(priv, 0x419f80, 0x80000000, 0x80000000); + nv_mask(priv, 0x419f88, 0x80000000, 0x80000000); +} + +struct nouveau_oclass * +gm107_grctx_oclass = &(struct nvc0_grctx_oclass) { + .base.handle = NV_ENGCTX(GR, 0x08), + .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 = gm107_grctx_generate_main, + .mods = gm107_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = gm107_grctx_pack_hub, + .gpc = gm107_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = gm107_grctx_pack_tpc, + .ppc = gm107_grctx_pack_ppc, + .icmd = gm107_grctx_pack_icmd, + .mthd = gm107_grctx_pack_mthd, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c new file mode 100644 index 00000000000..8de4a429154 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c @@ -0,0 +1,599 @@ +/* + * 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 +nv108_grctx_init_icmd_0[] = { + { 0x001000, 1, 0x01, 0x00000004 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x0000a9, 1, 0x01, 0x0000ffff }, + { 0x000038, 1, 0x01, 0x0fac6881 }, + { 0x00003d, 1, 0x01, 0x00000001 }, + { 0x0000e8, 8, 0x01, 0x00000400 }, + { 0x000078, 8, 0x01, 0x00000300 }, + { 0x000050, 1, 0x01, 0x00000011 }, + { 0x000058, 8, 0x01, 0x00000008 }, + { 0x000208, 8, 0x01, 0x00000001 }, + { 0x000081, 1, 0x01, 0x00000001 }, + { 0x000085, 1, 0x01, 0x00000004 }, + { 0x000088, 1, 0x01, 0x00000400 }, + { 0x000090, 1, 0x01, 0x00000300 }, + { 0x000098, 1, 0x01, 0x00001001 }, + { 0x0000e3, 1, 0x01, 0x00000001 }, + { 0x0000da, 1, 0x01, 0x00000001 }, + { 0x0000f8, 1, 0x01, 0x00000003 }, + { 0x0000fa, 1, 0x01, 0x00000001 }, + { 0x00009f, 4, 0x01, 0x0000ffff }, + { 0x0000b1, 1, 0x01, 0x00000001 }, + { 0x0000ad, 1, 0x01, 0x0000013e }, + { 0x0000e1, 1, 0x01, 0x00000010 }, + { 0x000290, 16, 0x01, 0x00000000 }, + { 0x0003b0, 16, 0x01, 0x00000000 }, + { 0x0002a0, 16, 0x01, 0x00000000 }, + { 0x000420, 16, 0x01, 0x00000000 }, + { 0x0002b0, 16, 0x01, 0x00000000 }, + { 0x000430, 16, 0x01, 0x00000000 }, + { 0x0002c0, 16, 0x01, 0x00000000 }, + { 0x0004d0, 16, 0x01, 0x00000000 }, + { 0x000720, 16, 0x01, 0x00000000 }, + { 0x0008c0, 16, 0x01, 0x00000000 }, + { 0x000890, 16, 0x01, 0x00000000 }, + { 0x0008e0, 16, 0x01, 0x00000000 }, + { 0x0008a0, 16, 0x01, 0x00000000 }, + { 0x0008f0, 16, 0x01, 0x00000000 }, + { 0x00094c, 1, 0x01, 0x000000ff }, + { 0x00094d, 1, 0x01, 0xffffffff }, + { 0x00094e, 1, 0x01, 0x00000002 }, + { 0x0002ec, 1, 0x01, 0x00000001 }, + { 0x0002f2, 2, 0x01, 0x00000001 }, + { 0x0002f5, 1, 0x01, 0x00000001 }, + { 0x0002f7, 1, 0x01, 0x00000001 }, + { 0x000303, 1, 0x01, 0x00000001 }, + { 0x0002e6, 1, 0x01, 0x00000001 }, + { 0x000466, 1, 0x01, 0x00000052 }, + { 0x000301, 1, 0x01, 0x3f800000 }, + { 0x000304, 1, 0x01, 0x30201000 }, + { 0x000305, 1, 0x01, 0x70605040 }, + { 0x000306, 1, 0x01, 0xb8a89888 }, + { 0x000307, 1, 0x01, 0xf8e8d8c8 }, + { 0x00030a, 1, 0x01, 0x00ffff00 }, + { 0x00030b, 1, 0x01, 0x0000001a }, + { 0x00030c, 1, 0x01, 0x00000001 }, + { 0x000318, 1, 0x01, 0x00000001 }, + { 0x000340, 1, 0x01, 0x00000000 }, + { 0x000375, 1, 0x01, 0x00000001 }, + { 0x00037d, 1, 0x01, 0x00000006 }, + { 0x0003a0, 1, 0x01, 0x00000002 }, + { 0x0003aa, 1, 0x01, 0x00000001 }, + { 0x0003a9, 1, 0x01, 0x00000001 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000383, 1, 0x01, 0x00000011 }, + { 0x000360, 1, 0x01, 0x00000040 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x00037a, 1, 0x01, 0x00000012 }, + { 0x000619, 1, 0x01, 0x00000003 }, + { 0x000811, 1, 0x01, 0x00000003 }, + { 0x000812, 1, 0x01, 0x00000004 }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000815, 1, 0x01, 0x0000000b }, + { 0x000800, 6, 0x01, 0x00000001 }, + { 0x000632, 1, 0x01, 0x00000001 }, + { 0x000633, 1, 0x01, 0x00000002 }, + { 0x000634, 1, 0x01, 0x00000003 }, + { 0x000635, 1, 0x01, 0x00000004 }, + { 0x000654, 1, 0x01, 0x3f800000 }, + { 0x000657, 1, 0x01, 0x3f800000 }, + { 0x000655, 2, 0x01, 0x3f800000 }, + { 0x0006cd, 1, 0x01, 0x3f800000 }, + { 0x0007f5, 1, 0x01, 0x3f800000 }, + { 0x0007dc, 1, 0x01, 0x39291909 }, + { 0x0007dd, 1, 0x01, 0x79695949 }, + { 0x0007de, 1, 0x01, 0xb9a99989 }, + { 0x0007df, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007e8, 1, 0x01, 0x00003210 }, + { 0x0007e9, 1, 0x01, 0x00007654 }, + { 0x0007ea, 1, 0x01, 0x00000098 }, + { 0x0007ec, 1, 0x01, 0x39291909 }, + { 0x0007ed, 1, 0x01, 0x79695949 }, + { 0x0007ee, 1, 0x01, 0xb9a99989 }, + { 0x0007ef, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007f0, 1, 0x01, 0x00003210 }, + { 0x0007f1, 1, 0x01, 0x00007654 }, + { 0x0007f2, 1, 0x01, 0x00000098 }, + { 0x0005a5, 1, 0x01, 0x00000001 }, + { 0x000980, 128, 0x01, 0x00000000 }, + { 0x000468, 1, 0x01, 0x00000004 }, + { 0x00046c, 1, 0x01, 0x00000001 }, + { 0x000470, 96, 0x01, 0x00000000 }, + { 0x000510, 16, 0x01, 0x3f800000 }, + { 0x000520, 1, 0x01, 0x000002b6 }, + { 0x000529, 1, 0x01, 0x00000001 }, + { 0x000530, 16, 0x01, 0xffff0000 }, + { 0x000585, 1, 0x01, 0x0000003f }, + { 0x000576, 1, 0x01, 0x00000003 }, + { 0x00057b, 1, 0x01, 0x00000059 }, + { 0x000586, 1, 0x01, 0x00000040 }, + { 0x000582, 2, 0x01, 0x00000080 }, + { 0x0005c2, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, + { 0x00063a, 1, 0x01, 0x00000002 }, + { 0x00063b, 2, 0x01, 0x00000001 }, + { 0x00063d, 1, 0x01, 0x00000002 }, + { 0x00063e, 1, 0x01, 0x00000001 }, + { 0x0008b8, 8, 0x01, 0x00000001 }, + { 0x000900, 8, 0x01, 0x00000001 }, + { 0x000908, 8, 0x01, 0x00000002 }, + { 0x000910, 16, 0x01, 0x00000001 }, + { 0x000920, 8, 0x01, 0x00000002 }, + { 0x000928, 8, 0x01, 0x00000001 }, + { 0x000662, 1, 0x01, 0x00000001 }, + { 0x000648, 9, 0x01, 0x00000001 }, + { 0x000658, 1, 0x01, 0x0000000f }, + { 0x0007ff, 1, 0x01, 0x0000000a }, + { 0x00066a, 1, 0x01, 0x40000000 }, + { 0x00066b, 1, 0x01, 0x10000000 }, + { 0x00066c, 2, 0x01, 0xffff0000 }, + { 0x0007af, 2, 0x01, 0x00000008 }, + { 0x0007f6, 1, 0x01, 0x00000001 }, + { 0x00080b, 1, 0x01, 0x00000002 }, + { 0x0006b2, 1, 0x01, 0x00000055 }, + { 0x0007ad, 1, 0x01, 0x00000003 }, + { 0x000937, 1, 0x01, 0x00000001 }, + { 0x000971, 1, 0x01, 0x00000008 }, + { 0x000972, 1, 0x01, 0x00000040 }, + { 0x000973, 1, 0x01, 0x0000012c }, + { 0x00097c, 1, 0x01, 0x00000040 }, + { 0x000979, 1, 0x01, 0x00000003 }, + { 0x000975, 1, 0x01, 0x00000020 }, + { 0x000976, 1, 0x01, 0x00000001 }, + { 0x000977, 1, 0x01, 0x00000020 }, + { 0x000978, 1, 0x01, 0x00000001 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x00095e, 1, 0x01, 0x20164010 }, + { 0x00095f, 1, 0x01, 0x00000020 }, + { 0x000a0d, 1, 0x01, 0x00000006 }, + { 0x00097d, 1, 0x01, 0x00000020 }, + { 0x000683, 1, 0x01, 0x00000006 }, + { 0x000685, 1, 0x01, 0x003fffff }, + { 0x000687, 1, 0x01, 0x003fffff }, + { 0x0006a0, 1, 0x01, 0x00000005 }, + { 0x000840, 1, 0x01, 0x00400008 }, + { 0x000841, 1, 0x01, 0x08000080 }, + { 0x000842, 1, 0x01, 0x00400008 }, + { 0x000843, 1, 0x01, 0x08000080 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ab, 1, 0x01, 0x00000002 }, + { 0x0006ac, 1, 0x01, 0x00000080 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x0006bb, 1, 0x01, 0x000000cf }, + { 0x0006ce, 1, 0x01, 0x2a712488 }, + { 0x000739, 1, 0x01, 0x4085c000 }, + { 0x00073a, 1, 0x01, 0x00000080 }, + { 0x000786, 1, 0x01, 0x80000100 }, + { 0x00073c, 1, 0x01, 0x00010100 }, + { 0x00073d, 1, 0x01, 0x02800000 }, + { 0x000787, 1, 0x01, 0x000000cf }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x000836, 1, 0x01, 0x00000001 }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x000833, 1, 0x01, 0x04444480 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c1b0, 8, 0x01, 0x0000000f }, + { 0x00c1b8, 1, 0x01, 0x0fac6881 }, + { 0x00c1b9, 1, 0x01, 0x00fac688 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x00c500, 1, 0x01, 0x00000003 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000002 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000008 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x00c500, 1, 0x01, 0x00000003 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000001 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + {} +}; + +static const struct nvc0_graph_pack +nv108_grctx_pack_icmd[] = { + { nv108_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_fe_0[] = { + { 0x404004, 8, 0x04, 0x00000000 }, + { 0x404024, 1, 0x04, 0x0000e000 }, + { 0x404028, 8, 0x04, 0x00000000 }, + { 0x4040a8, 8, 0x04, 0x00000000 }, + { 0x4040c8, 1, 0x04, 0xf800008f }, + { 0x4040d0, 6, 0x04, 0x00000000 }, + { 0x4040e8, 1, 0x04, 0x00001000 }, + { 0x4040f8, 1, 0x04, 0x00000000 }, + { 0x404100, 10, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, + { 0x404138, 1, 0x04, 0x20000040 }, + { 0x404150, 1, 0x04, 0x0000002e }, + { 0x404154, 1, 0x04, 0x00000400 }, + { 0x404158, 1, 0x04, 0x00000200 }, + { 0x404164, 1, 0x04, 0x00000055 }, + { 0x40417c, 2, 0x04, 0x00000000 }, + { 0x404194, 1, 0x04, 0x01000700 }, + { 0x4041a0, 4, 0x04, 0x00000000 }, + { 0x404200, 1, 0x04, 0x0000a197 }, + { 0x404204, 1, 0x04, 0x0000a1c0 }, + { 0x404208, 1, 0x04, 0x0000a140 }, + { 0x40420c, 1, 0x04, 0x0000902d }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_ds_0[] = { + { 0x405800, 1, 0x04, 0x0f8000bf }, + { 0x405830, 1, 0x04, 0x02180648 }, + { 0x405834, 1, 0x04, 0x08000000 }, + { 0x405838, 1, 0x04, 0x00000000 }, + { 0x405854, 1, 0x04, 0x00000000 }, + { 0x405870, 4, 0x04, 0x00000001 }, + { 0x405a00, 2, 0x04, 0x00000000 }, + { 0x405a18, 1, 0x04, 0x00000000 }, + { 0x405a1c, 1, 0x04, 0x000000ff }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x034103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, + { 0x4064a8, 1, 0x04, 0x00000000 }, + { 0x4064ac, 1, 0x04, 0x00003fff }, + { 0x4064b0, 3, 0x04, 0x00000000 }, + { 0x4064c0, 1, 0x04, 0x802000f0 }, + { 0x4064c4, 1, 0x04, 0x0192ffff }, + { 0x4064c8, 1, 0x04, 0x00c20200 }, + { 0x4064cc, 9, 0x04, 0x00000000 }, + { 0x4064fc, 1, 0x04, 0x0000022a }, + {} +}; + +const struct nvc0_graph_init +nv108_grctx_init_rstr2d_0[] = { + { 0x407804, 1, 0x04, 0x00000063 }, + { 0x40780c, 1, 0x04, 0x0a418820 }, + { 0x407810, 1, 0x04, 0x062080e6 }, + { 0x407814, 1, 0x04, 0x020398a4 }, + { 0x407818, 1, 0x04, 0x0e629062 }, + { 0x40781c, 1, 0x04, 0x0a418820 }, + { 0x407820, 1, 0x04, 0x000000e6 }, + { 0x4078bc, 1, 0x04, 0x00000103 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_be_0[] = { + { 0x408800, 1, 0x04, 0x32802a3c }, + { 0x408804, 1, 0x04, 0x00000040 }, + { 0x408808, 1, 0x04, 0x1003e005 }, + { 0x408840, 1, 0x04, 0x0000000b }, + { 0x408900, 1, 0x04, 0xb080b801 }, + { 0x408904, 1, 0x04, 0x62000001 }, + { 0x408908, 1, 0x04, 0x02c8102f }, + { 0x408980, 1, 0x04, 0x0000011d }, + {} +}; + +static const struct nvc0_graph_pack +nv108_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nv108_grctx_init_fe_0 }, + { nvf0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { nv108_grctx_init_ds_0 }, + { nvf0_grctx_init_cwd_0 }, + { nv108_grctx_init_pd_0 }, + { nv108_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { nv108_grctx_init_be_0 }, + {} +}; + +const struct nvc0_graph_init +nv108_grctx_init_prop_0[] = { + { 0x418400, 1, 0x04, 0x38005e00 }, + { 0x418404, 1, 0x04, 0x71e0ffff }, + { 0x41840c, 1, 0x04, 0x00001008 }, + { 0x418410, 1, 0x04, 0x0fff0fff }, + { 0x418414, 1, 0x04, 0x02200fff }, + { 0x418450, 6, 0x04, 0x00000000 }, + { 0x418468, 1, 0x04, 0x00000001 }, + { 0x41846c, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_gpc_unk_1[] = { + { 0x418600, 1, 0x04, 0x0000007f }, + { 0x418684, 1, 0x04, 0x0000001f }, + { 0x418700, 1, 0x04, 0x00000002 }, + { 0x418704, 2, 0x04, 0x00000080 }, + { 0x41870c, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_setup_0[] = { + { 0x418800, 1, 0x04, 0x7006863a }, + { 0x418808, 1, 0x04, 0x00000000 }, + { 0x41880c, 1, 0x04, 0x00000030 }, + { 0x418810, 1, 0x04, 0x00000000 }, + { 0x418828, 1, 0x04, 0x00000044 }, + { 0x418830, 1, 0x04, 0x10000001 }, + { 0x4188d8, 1, 0x04, 0x00000008 }, + { 0x4188e0, 1, 0x04, 0x01000000 }, + { 0x4188e8, 5, 0x04, 0x00000000 }, + { 0x4188fc, 1, 0x04, 0x20100058 }, + {} +}; + +const struct nvc0_graph_init +nv108_grctx_init_crstr_0[] = { + { 0x418b00, 1, 0x04, 0x0000001e }, + { 0x418b08, 1, 0x04, 0x0a418820 }, + { 0x418b0c, 1, 0x04, 0x062080e6 }, + { 0x418b10, 1, 0x04, 0x020398a4 }, + { 0x418b14, 1, 0x04, 0x0e629062 }, + { 0x418b18, 1, 0x04, 0x0a418820 }, + { 0x418b1c, 1, 0x04, 0x000000e6 }, + { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_gpm_0[] = { + { 0x418c08, 1, 0x04, 0x00000001 }, + { 0x418c10, 8, 0x04, 0x00000000 }, + { 0x418c40, 1, 0x04, 0xffffffff }, + { 0x418c6c, 1, 0x04, 0x00000001 }, + { 0x418c80, 1, 0x04, 0x2020000c }, + { 0x418c8c, 1, 0x04, 0x00000001 }, + {} +}; + +static const struct nvc0_graph_pack +nv108_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nv108_grctx_init_prop_0 }, + { nv108_grctx_init_gpc_unk_1 }, + { nv108_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nv108_grctx_init_crstr_0 }, + { nv108_grctx_init_gpm_0 }, + { nvf0_grctx_init_gpc_unk_2 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_tex_0[] = { + { 0x419a00, 1, 0x04, 0x000100f0 }, + { 0x419a04, 1, 0x04, 0x00000001 }, + { 0x419a08, 1, 0x04, 0x00000421 }, + { 0x419a0c, 1, 0x04, 0x00120000 }, + { 0x419a10, 1, 0x04, 0x00000000 }, + { 0x419a14, 1, 0x04, 0x00000200 }, + { 0x419a1c, 1, 0x04, 0x0000c000 }, + { 0x419a20, 1, 0x04, 0x00000800 }, + { 0x419a30, 1, 0x04, 0x00000001 }, + { 0x419ac4, 1, 0x04, 0x0037f440 }, + {} +}; + +static const struct nvc0_graph_init +nv108_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, 0x00000020 }, + { 0x419f70, 1, 0x04, 0x00000000 }, + { 0x419f78, 1, 0x04, 0x000001eb }, + { 0x419f7c, 1, 0x04, 0x00000404 }, + {} +}; + +static const struct nvc0_graph_pack +nv108_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nv108_grctx_init_tex_0 }, + { nvf0_grctx_init_mpc_0 }, + { nvf0_grctx_init_l1c_0 }, + { nv108_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_cbm_0[] = { + { 0x41bec0, 1, 0x04, 0x10000000 }, + { 0x41bec4, 1, 0x04, 0x00037f7f }, + { 0x41bee4, 1, 0x04, 0x00000000 }, + { 0x41bef0, 1, 0x04, 0x000003ff }, + {} +}; + +static const struct nvc0_graph_pack +nv108_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { nv108_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * 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), + .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, + .mods = nv108_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = nv108_grctx_pack_hub, + .gpc = nv108_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nv108_grctx_pack_tpc, + .ppc = nv108_grctx_pack_ppc, + .icmd = nv108_grctx_pack_icmd, + .mthd = nvf0_grctx_pack_mthd, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c index 64dca260912..833a96508c4 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nvc0_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvc0_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -140,8 +144,7 @@ nvc0_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -201,15 +204,13 @@ nvc0_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -235,14 +236,12 @@ nvc0_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -267,8 +266,14 @@ nvc0_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_9097[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_icmd[] = { + { nvc0_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_9097_0[] = { { 0x000800, 8, 0x40, 0x00000000 }, { 0x000804, 8, 0x40, 0x00000000 }, { 0x000808, 8, 0x40, 0x00000400 }, @@ -516,8 +521,7 @@ nvc0_grctx_init_9097[] = { { 0x001350, 1, 0x04, 0x00000002 }, { 0x001358, 1, 0x04, 0x00000001 }, { 0x0012e4, 1, 0x04, 0x00000000 }, - { 0x00131c, 1, 0x04, 0x00000000 }, - { 0x001320, 3, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, { 0x0019c0, 1, 0x04, 0x00000000 }, { 0x001140, 1, 0x04, 0x00000000 }, { 0x0019c4, 1, 0x04, 0x00000000 }, @@ -571,8 +575,8 @@ nvc0_grctx_init_9097[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_902d[] = { +const struct nvc0_graph_init +nvc0_grctx_init_902d_0[] = { { 0x000200, 1, 0x04, 0x000000cf }, { 0x000204, 1, 0x04, 0x00000001 }, { 0x000208, 1, 0x04, 0x00000020 }, @@ -590,8 +594,8 @@ nvc0_grctx_init_902d[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_9039[] = { +const struct nvc0_graph_init +nvc0_grctx_init_9039_0[] = { { 0x00030c, 3, 0x04, 0x00000000 }, { 0x000320, 1, 0x04, 0x00000000 }, { 0x000238, 2, 0x04, 0x00000000 }, @@ -599,8 +603,8 @@ nvc0_grctx_init_9039[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_90c0[] = { +const struct nvc0_graph_init +nvc0_grctx_init_90c0_0[] = { { 0x00270c, 8, 0x20, 0x00000000 }, { 0x00030c, 1, 0x04, 0x00000001 }, { 0x001944, 1, 0x04, 0x00000000 }, @@ -617,38 +621,44 @@ nvc0_grctx_init_90c0[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_base[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_mthd[] = { + { nvc0_grctx_init_9097_0, 0x9097 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvc0_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_main_0[] = { { 0x400204, 2, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk40xx[] = { - { 0x404004, 10, 0x04, 0x00000000 }, +const struct nvc0_graph_init +nvc0_grctx_init_fe_0[] = { + { 0x404004, 11, 0x04, 0x00000000 }, { 0x404044, 1, 0x04, 0x00000000 }, - { 0x404094, 1, 0x04, 0x00000000 }, - { 0x404098, 12, 0x04, 0x00000000 }, + { 0x404094, 13, 0x04, 0x00000000 }, { 0x4040c8, 1, 0x04, 0xf0000087 }, { 0x4040d0, 6, 0x04, 0x00000000 }, { 0x4040e8, 1, 0x04, 0x00001000 }, { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, { 0x404138, 1, 0x04, 0x20000040 }, { 0x404150, 1, 0x04, 0x0000002e }, { 0x404154, 1, 0x04, 0x00000400 }, { 0x404158, 1, 0x04, 0x00000200 }, { 0x404164, 1, 0x04, 0x00000055 }, { 0x404168, 1, 0x04, 0x00000000 }, - { 0x404174, 1, 0x04, 0x00000000 }, - { 0x404178, 2, 0x04, 0x00000000 }, + { 0x404174, 3, 0x04, 0x00000000 }, { 0x404200, 8, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk44xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_pri_0[] = { { 0x404404, 14, 0x04, 0x00000000 }, { 0x404460, 2, 0x04, 0x00000000 }, { 0x404468, 1, 0x04, 0x00ffffff }, @@ -658,8 +668,8 @@ nvc0_grctx_init_unk44xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk46xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_memfmt_0[] = { { 0x404604, 1, 0x04, 0x00000015 }, { 0x404608, 1, 0x04, 0x00000000 }, { 0x40460c, 1, 0x04, 0x00002e00 }, @@ -674,19 +684,14 @@ nvc0_grctx_init_unk46xx[] = { { 0x4046a0, 1, 0x04, 0x007f0080 }, { 0x4046a4, 18, 0x04, 0x00000000 }, { 0x4046f0, 2, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_init -nvc0_grctx_init_unk47xx[] = { { 0x404700, 13, 0x04, 0x00000000 }, { 0x404734, 1, 0x04, 0x00000100 }, { 0x404738, 8, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk58xx[] = { +static const struct nvc0_graph_init +nvc0_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x078000bf }, { 0x405830, 1, 0x04, 0x02180000 }, { 0x405834, 2, 0x04, 0x00000000 }, @@ -697,23 +702,18 @@ nvc0_grctx_init_unk58xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk60xx[] = { +static const struct nvc0_graph_init +nvc0_grctx_init_pd_0[] = { { 0x406020, 1, 0x04, 0x000103c1 }, { 0x406028, 4, 0x04, 0x00000001 }, - {} -}; - -struct nvc0_graph_init -nvc0_grctx_init_unk64xx[] = { { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 2, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk78xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_rstr2d_0[] = { { 0x407804, 1, 0x04, 0x00000023 }, { 0x40780c, 1, 0x04, 0x0a418820 }, { 0x407810, 1, 0x04, 0x062080e6 }, @@ -725,8 +725,8 @@ nvc0_grctx_init_unk78xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk80xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_scc_0[] = { { 0x408000, 2, 0x04, 0x00000000 }, { 0x408008, 1, 0x04, 0x00000018 }, { 0x40800c, 2, 0x04, 0x00000000 }, @@ -736,8 +736,8 @@ nvc0_grctx_init_unk80xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_rop[] = { +static const struct nvc0_graph_init +nvc0_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x0003e00d }, @@ -748,9 +748,28 @@ nvc0_grctx_init_rop[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_gpc_0[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvc0_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvc0_grctx_init_ds_0 }, + { nvc0_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvc0_grctx_init_be_0 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gpc_unk_0[] = { { 0x418380, 1, 0x04, 0x00000016 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_prop_0[] = { { 0x418400, 1, 0x04, 0x38004e00 }, { 0x418404, 1, 0x04, 0x71e0ffff }, { 0x418408, 1, 0x04, 0x00000000 }, @@ -760,6 +779,11 @@ nvc0_grctx_init_gpc_0[] = { { 0x418450, 6, 0x04, 0x00000000 }, { 0x418468, 1, 0x04, 0x00000001 }, { 0x41846c, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gpc_unk_1[] = { { 0x418600, 1, 0x04, 0x0000001f }, { 0x418684, 1, 0x04, 0x0000000f }, { 0x418700, 1, 0x04, 0x00000002 }, @@ -767,6 +791,11 @@ nvc0_grctx_init_gpc_0[] = { { 0x418708, 1, 0x04, 0x00000000 }, { 0x41870c, 1, 0x04, 0x07c80000 }, { 0x418710, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x0006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -775,10 +804,20 @@ nvc0_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x00100000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_zcull_0[] = { { 0x41891c, 1, 0x04, 0x00ff00ff }, { 0x418924, 1, 0x04, 0x00000000 }, { 0x418928, 1, 0x04, 0x00ffff00 }, { 0x41892c, 1, 0x04, 0x0000ff00 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_crstr_0[] = { { 0x418b00, 1, 0x04, 0x00000000 }, { 0x418b08, 1, 0x04, 0x0a418820 }, { 0x418b0c, 1, 0x04, 0x062080e6 }, @@ -787,18 +826,41 @@ nvc0_grctx_init_gpc_0[] = { { 0x418b18, 1, 0x04, 0x0a418820 }, { 0x418b1c, 1, 0x04, 0x000000e6 }, { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gpm_0[] = { { 0x418c08, 1, 0x04, 0x00000001 }, { 0x418c10, 8, 0x04, 0x00000000 }, { 0x418c80, 1, 0x04, 0x20200004 }, { 0x418c8c, 1, 0x04, 0x00000001 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gcc_0[] = { { 0x419000, 1, 0x04, 0x00000780 }, { 0x419004, 2, 0x04, 0x00000000 }, { 0x419014, 1, 0x04, 0x00000004 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_gpc_1[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvc0_grctx_init_prop_0 }, + { nvc0_grctx_init_gpc_unk_1 }, + { nvc0_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvc0_grctx_init_crstr_0 }, + { nvc0_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_zcullr_0[] = { { 0x418a00, 3, 0x04, 0x00000000 }, { 0x418a0c, 1, 0x04, 0x00010000 }, { 0x418a10, 3, 0x04, 0x00000000 }, @@ -826,19 +888,35 @@ nvc0_grctx_init_gpc_1[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_tpc[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_zcull[] = { + { nvc0_grctx_init_zcullr_0 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_pe_0[] = { { 0x419818, 1, 0x04, 0x00000000 }, { 0x41983c, 1, 0x04, 0x00038bc7 }, { 0x419848, 1, 0x04, 0x00000000 }, { 0x419864, 1, 0x04, 0x0000012a }, { 0x419888, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, { 0x419a0c, 1, 0x04, 0x00020000 }, { 0x419a10, 1, 0x04, 0x00000000 }, { 0x419a14, 1, 0x04, 0x00000200 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_wwdx_0[] = { { 0x419b00, 1, 0x04, 0x0a418820 }, { 0x419b04, 1, 0x04, 0x062080e6 }, { 0x419b08, 1, 0x04, 0x020398a4 }, @@ -848,15 +926,35 @@ nvc0_grctx_init_tpc[] = { { 0x419bd0, 1, 0x04, 0x00900103 }, { 0x419be0, 1, 0x04, 0x00000001 }, { 0x419be4, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x00000002 }, { 0x419c04, 1, 0x04, 0x00000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_l1c_0[] = { { 0x419cb0, 1, 0x04, 0x00060048 }, { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00000183 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_tpccs_0[] = { { 0x419d20, 1, 0x04, 0x02180000 }, { 0x419d24, 1, 0x04, 0x00001fff }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000002 }, { 0x419e44, 1, 0x04, 0x001beff2 }, @@ -868,6 +966,22 @@ nvc0_grctx_init_tpc[] = { {} }; +const struct nvc0_graph_pack +nvc0_grctx_pack_tpc[] = { + { nvc0_grctx_init_pe_0 }, + { nvc0_grctx_init_tex_0 }, + { nvc0_grctx_init_wwdx_0 }, + { nvc0_grctx_init_mpc_0 }, + { nvc0_grctx_init_l1c_0 }, + { nvc0_grctx_init_tpccs_0 }, + { nvc0_grctx_init_sm_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + void nvc0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -1039,7 +1153,7 @@ nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv) } while (!tpcnr[gpc]); tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; - tpc_set |= 1 << ((gpc * 8) + tpc); + tpc_set |= 1ULL << ((gpc * 8) + tpc); } nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); @@ -1055,14 +1169,14 @@ void nvc0_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); - for (i = 0; oclass->hub[i]; i++) - nvc0_graph_mmio(priv, oclass->hub[i]); - for (i = 0; oclass->gpc[i]; i++) - nvc0_graph_mmio(priv, oclass->gpc[i]); + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); nv_wr32(priv, 0x404154, 0x00000000); @@ -1182,46 +1296,6 @@ done: return ret; } -struct nvc0_graph_init * -nvc0_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvc0_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvc0_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvc0_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvc0_grctx_init_rop, - NULL -}; - -static struct nvc0_graph_init * -nvc0_grctx_init_gpc[] = { - nvc0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc0_grctx_init_tpc, - NULL -}; - -struct nvc0_graph_init -nvc0_grctx_init_mthd_magic[] = { - { 0x3410, 1, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_mthd -nvc0_grctx_init_mthd[] = { - { 0x9097, nvc0_grctx_init_9097, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvc0_grctx_init_90c0, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc0), @@ -1233,11 +1307,13 @@ nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, - .unkn = nvc0_grctx_generate_unkn, - .hub = nvc0_grctx_init_hub, - .gpc = nvc0_grctx_init_gpc, - .icmd = nvc0_grctx_init_icmd, - .mthd = nvc0_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc0_grctx_pack_tpc, + .icmd = nvc0_grctx_pack_icmd, + .mthd = nvc0_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h new file mode 100644 index 00000000000..8da8b627b9d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h @@ -0,0 +1,179 @@ +#ifndef __NVKM_GRCTX_NVC0_H__ +#define __NVKM_GRCTX_NVC0_H__ + +#include "nvc0.h" + +struct nvc0_grctx { + struct nvc0_graph_priv *priv; + struct nvc0_graph_data *data; + struct nvc0_graph_mmio *mmio; + int buffer_nr; + u64 buffer[4]; + u64 addr; +}; + +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; + const struct nvc0_graph_pack *gpc; + const struct nvc0_graph_pack *zcull; + const struct nvc0_graph_pack *tpc; + const struct nvc0_graph_pack *ppc; + /* indirect context data, generated with icmds/mthds */ + const struct nvc0_graph_pack *icmd; + const struct nvc0_graph_pack *mthd; +}; + +#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) + +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_unkn(struct nvc0_graph_priv *); +void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *); +void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *); +void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *); +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_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; +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_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 *nv108_grctx_oclass; +extern struct nouveau_oclass *gm107_grctx_oclass; + +/* context init value lists */ + +extern const struct nvc0_graph_pack nvc0_grctx_pack_icmd[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_mthd[]; +extern const struct nvc0_graph_init nvc0_grctx_init_902d_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_9039_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_90c0_0[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_hub[]; +extern const struct nvc0_graph_init nvc0_grctx_init_main_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_fe_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_pri_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_memfmt_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_rstr2d_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_scc_0[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_gpc[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_prop_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvc0_grctx_init_zcull_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_crstr_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gpm_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gcc_0[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_zcull[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_tpc[]; +extern const struct nvc0_graph_init nvc0_grctx_init_pe_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_wwdx_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_mpc_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_tpccs_0[]; + +extern const struct nvc0_graph_init nvc4_grctx_init_tex_0[]; +extern const struct nvc0_graph_init nvc4_grctx_init_l1c_0[]; +extern const struct nvc0_graph_init nvc4_grctx_init_sm_0[]; + +extern const struct nvc0_graph_init nvc1_grctx_init_9097_0[]; + +extern const struct nvc0_graph_init nvc1_grctx_init_gpm_0[]; + +extern const struct nvc0_graph_init nvc1_grctx_init_pe_0[]; +extern const struct nvc0_graph_init nvc1_grctx_init_wwdx_0[]; +extern const struct nvc0_graph_init nvc1_grctx_init_tpccs_0[]; + +extern const struct nvc0_graph_init nvc8_grctx_init_9197_0[]; +extern const struct nvc0_graph_init nvc8_grctx_init_9297_0[]; + +extern const struct nvc0_graph_pack nvd9_grctx_pack_icmd[]; + +extern const struct nvc0_graph_pack nvd9_grctx_pack_mthd[]; + +extern const struct nvc0_graph_init nvd9_grctx_init_fe_0[]; +extern const struct nvc0_graph_init nvd9_grctx_init_be_0[]; + +extern const struct nvc0_graph_init nvd9_grctx_init_prop_0[]; +extern const struct nvc0_graph_init nvd9_grctx_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvd9_grctx_init_crstr_0[]; + +extern const struct nvc0_graph_init nvd9_grctx_init_sm_0[]; + +extern const struct nvc0_graph_init nvd7_grctx_init_pe_0[]; + +extern const struct nvc0_graph_init nvd7_grctx_init_wwdx_0[]; + +extern const struct nvc0_graph_init nve4_grctx_init_memfmt_0[]; +extern const struct nvc0_graph_init nve4_grctx_init_ds_0[]; +extern const struct nvc0_graph_init nve4_grctx_init_scc_0[]; + +extern const struct nvc0_graph_init nve4_grctx_init_gpm_0[]; + +extern const struct nvc0_graph_init nve4_grctx_init_pes_0[]; + +extern const struct nvc0_graph_pack nve4_grctx_pack_hub[]; +extern const struct nvc0_graph_pack nve4_grctx_pack_gpc[]; +extern const struct nvc0_graph_pack nve4_grctx_pack_tpc[]; +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_mthd[]; + +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_init nvf0_grctx_init_gpc_unk_2[]; + +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_init nv108_grctx_init_rstr2d_0[]; + +extern const struct nvc0_graph_init nv108_grctx_init_prop_0[]; +extern const struct nvc0_graph_init nv108_grctx_init_crstr_0[]; + + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c index e5be3ee7f17..24a92c569c0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvc1_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvc1_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -141,8 +145,7 @@ nvc1_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -202,15 +205,13 @@ nvc1_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -236,14 +237,12 @@ nvc1_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -268,8 +267,14 @@ nvc1_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nvc1_grctx_init_9097[] = { +static const struct nvc0_graph_pack +nvc1_grctx_pack_icmd[] = { + { nvc1_grctx_init_icmd_0 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_9097_0[] = { { 0x000800, 8, 0x40, 0x00000000 }, { 0x000804, 8, 0x40, 0x00000000 }, { 0x000808, 8, 0x40, 0x00000400 }, @@ -516,8 +521,7 @@ nvc1_grctx_init_9097[] = { { 0x001350, 1, 0x04, 0x00000002 }, { 0x001358, 1, 0x04, 0x00000001 }, { 0x0012e4, 1, 0x04, 0x00000000 }, - { 0x00131c, 1, 0x04, 0x00000000 }, - { 0x001320, 3, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, { 0x0019c0, 1, 0x04, 0x00000000 }, { 0x001140, 1, 0x04, 0x00000000 }, { 0x0019c4, 1, 0x04, 0x00000000 }, @@ -571,15 +575,25 @@ nvc1_grctx_init_9097[] = { {} }; -static struct nvc0_graph_init -nvc1_grctx_init_9197[] = { +static const struct nvc0_graph_init +nvc1_grctx_init_9197_0[] = { { 0x003400, 128, 0x04, 0x00000000 }, { 0x0002e4, 1, 0x04, 0x0000b001 }, {} }; -static struct nvc0_graph_init -nvc1_grctx_init_unk58xx[] = { +static const struct nvc0_graph_pack +nvc1_grctx_pack_mthd[] = { + { nvc1_grctx_init_9097_0, 0x9097 }, + { nvc1_grctx_init_9197_0, 0x9197 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvc0_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +static const struct nvc0_graph_init +nvc1_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180218 }, { 0x405834, 2, 0x04, 0x00000000 }, @@ -587,10 +601,23 @@ nvc1_grctx_init_unk58xx[] = { { 0x405870, 4, 0x04, 0x00000001 }, { 0x405a00, 2, 0x04, 0x00000000 }, { 0x405a18, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc1_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x000103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, + { 0x4064a8, 1, 0x04, 0x00000000 }, + { 0x4064ac, 1, 0x04, 0x00003fff }, + { 0x4064b4, 2, 0x04, 0x00000000 }, + { 0x4064c0, 1, 0x04, 0x80140078 }, + { 0x4064c4, 1, 0x04, 0x0086ffff }, + {} }; -static struct nvc0_graph_init -nvc1_grctx_init_rop[] = { +static const struct nvc0_graph_init +nvc1_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1003e005 }, @@ -598,27 +625,25 @@ nvc1_grctx_init_rop[] = { { 0x408904, 1, 0x04, 0x62000001 }, { 0x408908, 1, 0x04, 0x00c80929 }, { 0x408980, 1, 0x04, 0x0000011d }, + {} +}; + +static const struct nvc0_graph_pack +nvc1_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvc0_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvc1_grctx_init_ds_0 }, + { nvc1_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvc1_grctx_init_be_0 }, + {} }; -static struct nvc0_graph_init -nvc1_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x00200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 1, 0x04, 0x00000000 }, - { 0x41870c, 1, 0x04, 0x07c80000 }, - { 0x418710, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_init +nvc1_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x0006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -627,68 +652,44 @@ nvc1_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x00100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418a00, 3, 0x04, 0x00000000 }, - { 0x418a0c, 1, 0x04, 0x00010000 }, - { 0x418a10, 3, 0x04, 0x00000000 }, - { 0x418a20, 3, 0x04, 0x00000000 }, - { 0x418a2c, 1, 0x04, 0x00010000 }, - { 0x418a30, 3, 0x04, 0x00000000 }, - { 0x418a40, 3, 0x04, 0x00000000 }, - { 0x418a4c, 1, 0x04, 0x00010000 }, - { 0x418a50, 3, 0x04, 0x00000000 }, - { 0x418a60, 3, 0x04, 0x00000000 }, - { 0x418a6c, 1, 0x04, 0x00010000 }, - { 0x418a70, 3, 0x04, 0x00000000 }, - { 0x418a80, 3, 0x04, 0x00000000 }, - { 0x418a8c, 1, 0x04, 0x00010000 }, - { 0x418a90, 3, 0x04, 0x00000000 }, - { 0x418aa0, 3, 0x04, 0x00000000 }, - { 0x418aac, 1, 0x04, 0x00010000 }, - { 0x418ab0, 3, 0x04, 0x00000000 }, - { 0x418ac0, 3, 0x04, 0x00000000 }, - { 0x418acc, 1, 0x04, 0x00010000 }, - { 0x418ad0, 3, 0x04, 0x00000000 }, - { 0x418ae0, 3, 0x04, 0x00000000 }, - { 0x418aec, 1, 0x04, 0x00010000 }, - { 0x418af0, 3, 0x04, 0x00000000 }, - { 0x418b00, 1, 0x04, 0x00000000 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_gpm_0[] = { { 0x418c08, 1, 0x04, 0x00000001 }, { 0x418c10, 8, 0x04, 0x00000000 }, { 0x418c6c, 1, 0x04, 0x00000001 }, { 0x418c80, 1, 0x04, 0x20200004 }, { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, + {} +}; + +static const struct nvc0_graph_pack +nvc1_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvc0_grctx_init_prop_0 }, + { nvc0_grctx_init_gpc_unk_1 }, + { nvc1_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvc0_grctx_init_crstr_0 }, + { nvc1_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} }; -static struct nvc0_graph_init -nvc1_grctx_init_tpc[] = { +const struct nvc0_graph_init +nvc1_grctx_init_pe_0[] = { { 0x419818, 1, 0x04, 0x00000000 }, { 0x41983c, 1, 0x04, 0x00038bc7 }, { 0x419848, 1, 0x04, 0x00000000 }, { 0x419864, 1, 0x04, 0x00000129 }, { 0x419888, 1, 0x04, 0x00000000 }, - { 0x419a00, 1, 0x04, 0x000001f0 }, - { 0x419a04, 1, 0x04, 0x00000001 }, - { 0x419a08, 1, 0x04, 0x00000023 }, - { 0x419a0c, 1, 0x04, 0x00020000 }, - { 0x419a10, 1, 0x04, 0x00000000 }, - { 0x419a14, 1, 0x04, 0x00000200 }, - { 0x419a1c, 1, 0x04, 0x00000000 }, - { 0x419a20, 1, 0x04, 0x00000800 }, - { 0x419ac4, 1, 0x04, 0x0007f440 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_wwdx_0[] = { { 0x419b00, 1, 0x04, 0x0a418820 }, { 0x419b04, 1, 0x04, 0x062080e6 }, { 0x419b08, 1, 0x04, 0x020398a4 }, @@ -698,27 +699,33 @@ nvc1_grctx_init_tpc[] = { { 0x419bd0, 1, 0x04, 0x00900103 }, { 0x419be0, 1, 0x04, 0x00400001 }, { 0x419be4, 1, 0x04, 0x00000000 }, - { 0x419c00, 1, 0x04, 0x00000002 }, - { 0x419c04, 1, 0x04, 0x00000006 }, - { 0x419c08, 1, 0x04, 0x00000002 }, - { 0x419c20, 1, 0x04, 0x00000000 }, - { 0x419cb0, 1, 0x04, 0x00020048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_tpccs_0[] = { { 0x419d20, 1, 0x04, 0x12180000 }, { 0x419d24, 1, 0x04, 0x00001fff }, { 0x419d44, 1, 0x04, 0x02180218 }, - { 0x419e04, 3, 0x04, 0x00000000 }, - { 0x419e10, 1, 0x04, 0x00000002 }, - { 0x419e44, 1, 0x04, 0x001beff2 }, - { 0x419e48, 1, 0x04, 0x00000000 }, - { 0x419e4c, 1, 0x04, 0x0000000f }, - { 0x419e50, 17, 0x04, 0x00000000 }, - { 0x419e98, 1, 0x04, 0x00000000 }, - { 0x419ee0, 1, 0x04, 0x00011110 }, - { 0x419f30, 11, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +nvc1_grctx_pack_tpc[] = { + { nvc1_grctx_init_pe_0 }, + { nvc4_grctx_init_tex_0 }, + { nvc1_grctx_init_wwdx_0 }, + { nvc0_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvc1_grctx_init_tpccs_0 }, + { nvc4_grctx_init_sm_0 }, + {} }; +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + void nvc1_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -767,41 +774,6 @@ nvc1_grctx_generate_unkn(struct nvc0_graph_priv *priv) nv_mask(priv, 0x419c00, 0x00000008, 0x00000008); } -static struct nvc0_graph_init * -nvc1_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvc0_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvc1_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvc0_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvc1_grctx_init_rop, - NULL -}; - -struct nvc0_graph_init * -nvc1_grctx_init_gpc[] = { - nvc1_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc1_grctx_init_tpc, - NULL -}; - -static struct nvc0_graph_mthd -nvc1_grctx_init_mthd[] = { - { 0x9097, nvc1_grctx_init_9097, }, - { 0x9197, nvc1_grctx_init_9197, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvc0_grctx_init_90c0, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc1), @@ -813,11 +785,13 @@ nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc1_grctx_generate_mods, - .unkn = nvc1_grctx_generate_unkn, - .hub = nvc1_grctx_init_hub, - .gpc = nvc1_grctx_init_gpc, - .icmd = nvc1_grctx_init_icmd, - .mthd = nvc1_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc1_grctx_pack_tpc, + .icmd = nvc1_grctx_pack_icmd, + .mthd = nvc1_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c index 8f237b3bd8c..e11ed553819 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c @@ -22,15 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvc3_grctx_init_tpc[] = { - { 0x419818, 1, 0x04, 0x00000000 }, - { 0x41983c, 1, 0x04, 0x00038bc7 }, - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x0000012a }, - { 0x419888, 1, 0x04, 0x00000000 }, +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +const struct nvc0_graph_init +nvc4_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, @@ -40,24 +39,19 @@ nvc3_grctx_init_tpc[] = { { 0x419a1c, 1, 0x04, 0x00000000 }, { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419ac4, 1, 0x04, 0x0007f440 }, - { 0x419b00, 1, 0x04, 0x0a418820 }, - { 0x419b04, 1, 0x04, 0x062080e6 }, - { 0x419b08, 1, 0x04, 0x020398a4 }, - { 0x419b0c, 1, 0x04, 0x0e629062 }, - { 0x419b10, 1, 0x04, 0x0a418820 }, - { 0x419b14, 1, 0x04, 0x000000e6 }, - { 0x419bd0, 1, 0x04, 0x00900103 }, - { 0x419be0, 1, 0x04, 0x00000001 }, - { 0x419be4, 1, 0x04, 0x00000000 }, - { 0x419c00, 1, 0x04, 0x00000002 }, - { 0x419c04, 1, 0x04, 0x00000006 }, - { 0x419c08, 1, 0x04, 0x00000002 }, - { 0x419c20, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc4_grctx_init_l1c_0[] = { { 0x419cb0, 1, 0x04, 0x00020048 }, { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419d20, 1, 0x04, 0x02180000 }, - { 0x419d24, 1, 0x04, 0x00001fff }, + {} +}; + +const struct nvc0_graph_init +nvc4_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000002 }, { 0x419e44, 1, 0x04, 0x001beff2 }, @@ -70,16 +64,24 @@ nvc3_grctx_init_tpc[] = { {} }; -struct nvc0_graph_init * -nvc3_grctx_init_gpc[] = { - nvc0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc3_grctx_init_tpc, - NULL +static const struct nvc0_graph_pack +nvc4_grctx_pack_tpc[] = { + { nvc0_grctx_init_pe_0 }, + { nvc4_grctx_init_tex_0 }, + { nvc0_grctx_init_wwdx_0 }, + { nvc0_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvc0_grctx_init_tpccs_0 }, + { nvc4_grctx_init_sm_0 }, + {} }; +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + struct nouveau_oclass * -nvc3_grctx_oclass = &(struct nvc0_grctx_oclass) { +nvc4_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc3), .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_graph_context_ctor, @@ -89,11 +91,13 @@ nvc3_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, - .unkn = nvc0_grctx_generate_unkn, - .hub = nvc0_grctx_init_hub, - .gpc = nvc3_grctx_init_gpc, - .icmd = nvc0_grctx_init_icmd, - .mthd = nvc0_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc4_grctx_pack_tpc, + .icmd = nvc0_grctx_pack_icmd, + .mthd = nvc0_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c index d0d4ce3c489..feebd58dfe8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvc8_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvc8_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -141,8 +145,7 @@ nvc8_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -203,15 +206,13 @@ nvc8_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -237,14 +238,12 @@ nvc8_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -269,58 +268,20 @@ nvc8_grctx_init_icmd[] = { {} }; -static struct nvc0_graph_init -nvc8_grctx_init_tpc[] = { - { 0x419818, 1, 0x04, 0x00000000 }, - { 0x41983c, 1, 0x04, 0x00038bc7 }, - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x0000012a }, - { 0x419888, 1, 0x04, 0x00000000 }, - { 0x419a00, 1, 0x04, 0x000001f0 }, - { 0x419a04, 1, 0x04, 0x00000001 }, - { 0x419a08, 1, 0x04, 0x00000023 }, - { 0x419a0c, 1, 0x04, 0x00020000 }, - { 0x419a10, 1, 0x04, 0x00000000 }, - { 0x419a14, 1, 0x04, 0x00000200 }, - { 0x419a1c, 1, 0x04, 0x00000000 }, - { 0x419a20, 1, 0x04, 0x00000800 }, - { 0x419b00, 1, 0x04, 0x0a418820 }, - { 0x419b04, 1, 0x04, 0x062080e6 }, - { 0x419b08, 1, 0x04, 0x020398a4 }, - { 0x419b0c, 1, 0x04, 0x0e629062 }, - { 0x419b10, 1, 0x04, 0x0a418820 }, - { 0x419b14, 1, 0x04, 0x000000e6 }, - { 0x419bd0, 1, 0x04, 0x00900103 }, - { 0x419be0, 1, 0x04, 0x00000001 }, - { 0x419be4, 1, 0x04, 0x00000000 }, - { 0x419c00, 1, 0x04, 0x00000002 }, - { 0x419c04, 1, 0x04, 0x00000006 }, - { 0x419c08, 1, 0x04, 0x00000002 }, - { 0x419c20, 1, 0x04, 0x00000000 }, - { 0x419cb0, 1, 0x04, 0x00060048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419d20, 1, 0x04, 0x02180000 }, - { 0x419d24, 1, 0x04, 0x00001fff }, - { 0x419e04, 3, 0x04, 0x00000000 }, - { 0x419e10, 1, 0x04, 0x00000002 }, - { 0x419e44, 1, 0x04, 0x001beff2 }, - { 0x419e48, 1, 0x04, 0x00000000 }, - { 0x419e4c, 1, 0x04, 0x0000000f }, - { 0x419e50, 17, 0x04, 0x00000000 }, - { 0x419e98, 1, 0x04, 0x00000000 }, - { 0x419f50, 2, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvc8_grctx_pack_icmd[] = { + { nvc8_grctx_init_icmd_0 }, {} }; -struct nvc0_graph_init -nvc8_grctx_init_9197[] = { +const struct nvc0_graph_init +nvc8_grctx_init_9197_0[] = { { 0x0002e4, 1, 0x04, 0x0000b001 }, {} }; -struct nvc0_graph_init -nvc8_grctx_init_9297[] = { +const struct nvc0_graph_init +nvc8_grctx_init_9297_0[] = { { 0x003400, 128, 0x04, 0x00000000 }, { 0x00036c, 2, 0x04, 0x00000000 }, { 0x0007a4, 2, 0x04, 0x00000000 }, @@ -329,26 +290,47 @@ nvc8_grctx_init_9297[] = { {} }; -static struct nvc0_graph_mthd -nvc8_grctx_init_mthd[] = { - { 0x9097, nvc1_grctx_init_9097, }, - { 0x9197, nvc8_grctx_init_9197, }, - { 0x9297, nvc8_grctx_init_9297, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvc0_grctx_init_90c0, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, +static const struct nvc0_graph_pack +nvc8_grctx_pack_mthd[] = { + { nvc1_grctx_init_9097_0, 0x9097 }, + { nvc8_grctx_init_9197_0, 0x9197 }, + { nvc8_grctx_init_9297_0, 0x9297 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvc0_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +static const struct nvc0_graph_init +nvc8_grctx_init_setup_0[] = { + { 0x418800, 1, 0x04, 0x0006860a }, + { 0x418808, 3, 0x04, 0x00000000 }, + { 0x418828, 1, 0x04, 0x00008442 }, + { 0x418830, 1, 0x04, 0x00000001 }, + { 0x4188d8, 1, 0x04, 0x00000008 }, + { 0x4188e0, 1, 0x04, 0x01000000 }, + { 0x4188e8, 5, 0x04, 0x00000000 }, + { 0x4188fc, 1, 0x04, 0x20100000 }, {} }; -static struct nvc0_graph_init * -nvc8_grctx_init_gpc[] = { - nvc0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc8_grctx_init_tpc, - NULL +static const struct nvc0_graph_pack +nvc8_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvc0_grctx_init_prop_0 }, + { nvc0_grctx_init_gpc_unk_1 }, + { nvc8_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvc0_grctx_init_crstr_0 }, + { nvc0_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} }; +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + struct nouveau_oclass * nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc8), @@ -360,11 +342,13 @@ nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, - .unkn = nvc0_grctx_generate_unkn, - .hub = nvc0_grctx_init_hub, - .gpc = nvc8_grctx_init_gpc, - .icmd = nvc8_grctx_init_icmd, - .mthd = nvc8_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc0_grctx_pack_tpc, + .icmd = nvc8_grctx_pack_icmd, + .mthd = nvc8_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c index 438e7841080..1dbc8d7f2e8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c @@ -22,33 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nvd7_grctx_init_unk40xx[] = { - { 0x404004, 10, 0x04, 0x00000000 }, - { 0x404044, 1, 0x04, 0x00000000 }, - { 0x404094, 1, 0x04, 0x00000000 }, - { 0x404098, 12, 0x04, 0x00000000 }, - { 0x4040c8, 1, 0x04, 0xf0000087 }, - { 0x4040d0, 6, 0x04, 0x00000000 }, - { 0x4040e8, 1, 0x04, 0x00001000 }, - { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, - { 0x404138, 1, 0x04, 0x20000040 }, - { 0x404150, 1, 0x04, 0x0000002e }, - { 0x404154, 1, 0x04, 0x00000400 }, - { 0x404158, 1, 0x04, 0x00000200 }, - { 0x404164, 1, 0x04, 0x00000055 }, - { 0x404168, 1, 0x04, 0x00000000 }, - { 0x404178, 2, 0x04, 0x00000000 }, - { 0x404200, 8, 0x04, 0x00000000 }, - {} -}; +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ -static struct nvc0_graph_init -nvd7_grctx_init_unk58xx[] = { +static const struct nvc0_graph_init +nvd7_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180324 }, { 0x405834, 1, 0x04, 0x08000000 }, @@ -60,8 +41,10 @@ nvd7_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nvd7_grctx_init_unk64xx[] = { +static const struct nvc0_graph_init +nvd7_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x000103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 3, 0x04, 0x00000000 }, @@ -71,22 +54,22 @@ nvd7_grctx_init_unk64xx[] = { {} }; -static struct nvc0_graph_init -nvd7_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x02200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 3, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvd7_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvd9_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvd7_grctx_init_ds_0 }, + { nvd7_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvd9_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -95,34 +78,32 @@ nvd7_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418b00, 1, 0x04, 0x00000006 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, - { 0x418c08, 1, 0x04, 0x00000001 }, - { 0x418c10, 8, 0x04, 0x00000000 }, - { 0x418c6c, 1, 0x04, 0x00000001 }, - { 0x418c80, 1, 0x04, 0x20200004 }, - { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nvd7_grctx_init_tpc[] = { +static const struct nvc0_graph_pack +nvd7_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nvd7_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nvc1_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +const struct nvc0_graph_init +nvd7_grctx_init_pe_0[] = { { 0x419848, 1, 0x04, 0x00000000 }, { 0x419864, 1, 0x04, 0x00000129 }, { 0x419888, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, @@ -132,33 +113,46 @@ nvd7_grctx_init_tpc[] = { { 0x419a1c, 1, 0x04, 0x00008000 }, { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419ac4, 1, 0x04, 0x0017f440 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000000a }, { 0x419c04, 1, 0x04, 0x00000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3efbefbe }, - { 0x419cb0, 1, 0x04, 0x00020048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419e04, 3, 0x04, 0x00000000 }, - { 0x419e10, 1, 0x04, 0x00000002 }, - { 0x419e44, 1, 0x04, 0x001beff2 }, - { 0x419e48, 1, 0x04, 0x00000000 }, - { 0x419e4c, 1, 0x04, 0x0000000f }, - { 0x419e50, 17, 0x04, 0x00000000 }, - { 0x419e98, 1, 0x04, 0x00000000 }, - { 0x419ee0, 1, 0x04, 0x00010110 }, - { 0x419f30, 11, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvd7_grctx_init_unk[] = { +static const struct nvc0_graph_pack +nvd7_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nvd7_grctx_init_tex_0 }, + { nvd7_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvd9_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_pes_0[] = { { 0x41be24, 1, 0x04, 0x00000002 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_cbm_0[] = { { 0x41bec0, 1, 0x04, 0x12180000 }, { 0x41bec4, 1, 0x04, 0x00003fff }, { 0x41bee4, 1, 0x04, 0x03240218 }, + {} +}; + +const struct nvc0_graph_init +nvd7_grctx_init_wwdx_0[] = { { 0x41bf00, 1, 0x04, 0x0a418820 }, { 0x41bf04, 1, 0x04, 0x062080e6 }, { 0x41bf08, 1, 0x04, 0x020398a4 }, @@ -171,6 +165,18 @@ nvd7_grctx_init_unk[] = { {} }; +static const struct nvc0_graph_pack +nvd7_grctx_pack_ppc[] = { + { nvd7_grctx_init_pes_0 }, + { nvd7_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + static void nvd7_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -219,10 +225,11 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x000260, 0x00000001, 0x00000000); - for (i = 0; oclass->hub[i]; i++) - nvc0_graph_mmio(priv, oclass->hub[i]); - for (i = 0; oclass->gpc[i]; i++) - nvc0_graph_mmio(priv, oclass->gpc[i]); + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); nv_wr32(priv, 0x404154, 0x00000000); @@ -244,31 +251,6 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x000260, 0x00000001, 0x00000001); } - -static struct nvc0_graph_init * -nvd7_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvd7_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvd7_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvd7_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvd9_grctx_init_rop, -}; - -struct nvc0_graph_init * -nvd7_grctx_init_gpc[] = { - nvd7_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvd7_grctx_init_tpc, - nvd7_grctx_init_unk, - NULL -}; - struct nouveau_oclass * nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xd7), @@ -280,11 +262,14 @@ nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvd7_grctx_generate_main, - .mods = nvd7_grctx_generate_mods, - .unkn = nve4_grctx_generate_unkn, - .hub = nvd7_grctx_init_hub, - .gpc = nvd7_grctx_init_gpc, - .icmd = nvd9_grctx_init_icmd, - .mthd = nvd9_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvd7_grctx_pack_tpc, + .ppc = nvd7_grctx_pack_ppc, + .icmd = nvd9_grctx_pack_icmd, + .mthd = nvd9_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c index 818a4751df4..c665fb7e466 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c @@ -22,38 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nvd9_grctx_init_90c0[] = { - { 0x002700, 4, 0x40, 0x00000000 }, - { 0x002720, 4, 0x40, 0x00000000 }, - { 0x002704, 4, 0x40, 0x00000000 }, - { 0x002724, 4, 0x40, 0x00000000 }, - { 0x002708, 4, 0x40, 0x00000000 }, - { 0x002728, 4, 0x40, 0x00000000 }, - { 0x00270c, 8, 0x20, 0x00000000 }, - { 0x002710, 4, 0x40, 0x00014000 }, - { 0x002730, 4, 0x40, 0x00014000 }, - { 0x002714, 4, 0x40, 0x00000040 }, - { 0x002734, 4, 0x40, 0x00000040 }, - { 0x00030c, 1, 0x04, 0x00000001 }, - { 0x001944, 1, 0x04, 0x00000000 }, - { 0x000758, 1, 0x04, 0x00000100 }, - { 0x0002c4, 1, 0x04, 0x00000000 }, - { 0x000790, 5, 0x04, 0x00000000 }, - { 0x00077c, 1, 0x04, 0x00000000 }, - { 0x000204, 3, 0x04, 0x00000000 }, - { 0x000214, 1, 0x04, 0x00000000 }, - { 0x00024c, 1, 0x04, 0x00000000 }, - { 0x000d94, 1, 0x04, 0x00000001 }, - { 0x001608, 2, 0x04, 0x00000000 }, - { 0x001664, 1, 0x04, 0x00000000 }, - {} -}; +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ -struct nvc0_graph_init -nvd9_grctx_init_icmd[] = { +static const struct nvc0_graph_init +nvd9_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -171,8 +147,7 @@ nvd9_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -233,15 +208,13 @@ nvd9_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -267,14 +240,12 @@ nvd9_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -299,18 +270,56 @@ nvd9_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nvd9_grctx_init_unk40xx[] = { - { 0x404004, 11, 0x04, 0x00000000 }, +const struct nvc0_graph_pack +nvd9_grctx_pack_icmd[] = { + { nvd9_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_90c0_0[] = { + { 0x002700, 8, 0x20, 0x00000000 }, + { 0x002704, 8, 0x20, 0x00000000 }, + { 0x002708, 8, 0x20, 0x00000000 }, + { 0x00270c, 8, 0x20, 0x00000000 }, + { 0x002710, 8, 0x20, 0x00014000 }, + { 0x002714, 8, 0x20, 0x00000040 }, + { 0x00030c, 1, 0x04, 0x00000001 }, + { 0x001944, 1, 0x04, 0x00000000 }, + { 0x000758, 1, 0x04, 0x00000100 }, + { 0x0002c4, 1, 0x04, 0x00000000 }, + { 0x000790, 5, 0x04, 0x00000000 }, + { 0x00077c, 1, 0x04, 0x00000000 }, + { 0x000204, 3, 0x04, 0x00000000 }, + { 0x000214, 1, 0x04, 0x00000000 }, + { 0x00024c, 1, 0x04, 0x00000000 }, + { 0x000d94, 1, 0x04, 0x00000001 }, + { 0x001608, 2, 0x04, 0x00000000 }, + { 0x001664, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_pack +nvd9_grctx_pack_mthd[] = { + { nvc1_grctx_init_9097_0, 0x9097 }, + { nvc8_grctx_init_9197_0, 0x9197 }, + { nvc8_grctx_init_9297_0, 0x9297 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvd9_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_fe_0[] = { + { 0x404004, 10, 0x04, 0x00000000 }, { 0x404044, 1, 0x04, 0x00000000 }, - { 0x404094, 1, 0x04, 0x00000000 }, - { 0x404098, 12, 0x04, 0x00000000 }, + { 0x404094, 13, 0x04, 0x00000000 }, { 0x4040c8, 1, 0x04, 0xf0000087 }, { 0x4040d0, 6, 0x04, 0x00000000 }, { 0x4040e8, 1, 0x04, 0x00001000 }, { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, { 0x404138, 1, 0x04, 0x20000040 }, { 0x404150, 1, 0x04, 0x0000002e }, { 0x404154, 1, 0x04, 0x00000400 }, @@ -322,8 +331,8 @@ nvd9_grctx_init_unk40xx[] = { {} }; -static struct nvc0_graph_init -nvd9_grctx_init_unk58xx[] = { +static const struct nvc0_graph_init +nvd9_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180218 }, { 0x405834, 1, 0x04, 0x08000000 }, @@ -335,8 +344,10 @@ nvd9_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nvd9_grctx_init_unk64xx[] = { +static const struct nvc0_graph_init +nvd9_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x000103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 3, 0x04, 0x00000000 }, @@ -345,21 +356,34 @@ nvd9_grctx_init_unk64xx[] = { {} }; -struct nvc0_graph_init -nvd9_grctx_init_rop[] = { +const struct nvc0_graph_init +nvd9_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1043e005 }, { 0x408900, 1, 0x04, 0x3080b801 }, - { 0x408904, 1, 0x04, 0x1043e005 }, + { 0x408904, 1, 0x04, 0x62000001 }, { 0x408908, 1, 0x04, 0x00c8102f }, { 0x408980, 1, 0x04, 0x0000011d }, {} }; -static struct nvc0_graph_init -nvd9_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, +static const struct nvc0_graph_pack +nvd9_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvd9_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvd9_grctx_init_ds_0 }, + { nvd9_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvd9_grctx_init_be_0 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_prop_0[] = { { 0x418400, 1, 0x04, 0x38004e00 }, { 0x418404, 1, 0x04, 0x71e0ffff }, { 0x41840c, 1, 0x04, 0x00001008 }, @@ -368,11 +392,21 @@ nvd9_grctx_init_gpc_0[] = { { 0x418450, 6, 0x04, 0x00000000 }, { 0x418468, 1, 0x04, 0x00000001 }, { 0x41846c, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_gpc_unk_1[] = { { 0x418600, 1, 0x04, 0x0000001f }, { 0x418684, 1, 0x04, 0x0000000f }, { 0x418700, 1, 0x04, 0x00000002 }, { 0x418704, 1, 0x04, 0x00000080 }, { 0x418708, 3, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -381,10 +415,11 @@ nvd9_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100008 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_crstr_0[] = { { 0x418b00, 1, 0x04, 0x00000006 }, { 0x418b08, 1, 0x04, 0x0a418820 }, { 0x418b0c, 1, 0x04, 0x062080e6 }, @@ -393,24 +428,24 @@ nvd9_grctx_init_gpc_0[] = { { 0x418b18, 1, 0x04, 0x0a418820 }, { 0x418b1c, 1, 0x04, 0x000000e6 }, { 0x418bb8, 1, 0x04, 0x00000103 }, - { 0x418c08, 1, 0x04, 0x00000001 }, - { 0x418c10, 8, 0x04, 0x00000000 }, - { 0x418c6c, 1, 0x04, 0x00000001 }, - { 0x418c80, 1, 0x04, 0x20200004 }, - { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nvd9_grctx_init_tpc[] = { - { 0x419818, 1, 0x04, 0x00000000 }, - { 0x41983c, 1, 0x04, 0x00038bc7 }, - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x00000129 }, - { 0x419888, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvd9_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nvd9_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nvc1_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, @@ -420,27 +455,22 @@ nvd9_grctx_init_tpc[] = { { 0x419a1c, 1, 0x04, 0x00000000 }, { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419ac4, 1, 0x04, 0x0017f440 }, - { 0x419b00, 1, 0x04, 0x0a418820 }, - { 0x419b04, 1, 0x04, 0x062080e6 }, - { 0x419b08, 1, 0x04, 0x020398a4 }, - { 0x419b0c, 1, 0x04, 0x0e629062 }, - { 0x419b10, 1, 0x04, 0x0a418820 }, - { 0x419b14, 1, 0x04, 0x000000e6 }, - { 0x419bd0, 1, 0x04, 0x00900103 }, - { 0x419be0, 1, 0x04, 0x00400001 }, - { 0x419be4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000000a }, { 0x419c04, 1, 0x04, 0x00000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3cf3cf3c }, - { 0x419cb0, 1, 0x04, 0x00020048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419d20, 1, 0x04, 0x12180000 }, - { 0x419d24, 1, 0x04, 0x00001fff }, - { 0x419d44, 1, 0x04, 0x02180218 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000002 }, { 0x419e44, 1, 0x04, 0x001beff2 }, @@ -453,46 +483,21 @@ nvd9_grctx_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvd9_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvd9_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvd9_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvd9_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvd9_grctx_init_rop, -}; - -struct nvc0_graph_init * -nvd9_grctx_init_gpc[] = { - nvd9_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvd9_grctx_init_tpc, - NULL -}; - -struct nvc0_graph_init -nvd9_grctx_init_mthd_magic[] = { - { 0x3410, 1, 0x04, 0x80002006 }, +static const struct nvc0_graph_pack +nvd9_grctx_pack_tpc[] = { + { nvc1_grctx_init_pe_0 }, + { nvd9_grctx_init_tex_0 }, + { nvc1_grctx_init_wwdx_0 }, + { nvd9_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvc1_grctx_init_tpccs_0 }, + { nvd9_grctx_init_sm_0 }, {} }; -struct nvc0_graph_mthd -nvd9_grctx_init_mthd[] = { - { 0x9097, nvc1_grctx_init_9097, }, - { 0x9197, nvc8_grctx_init_9197, }, - { 0x9297, nvc8_grctx_init_9297, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvd9_grctx_init_90c0, }, - { 0x902d, nvd9_grctx_init_mthd_magic, }, - {} -}; +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ struct nouveau_oclass * nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) { @@ -505,11 +510,13 @@ nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc1_grctx_generate_mods, - .unkn = nvc1_grctx_generate_unkn, - .hub = nvd9_grctx_init_hub, - .gpc = nvd9_grctx_init_gpc, - .icmd = nvd9_grctx_init_icmd, - .mthd = nvd9_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvd9_grctx_pack_tpc, + .icmd = nvd9_grctx_pack_icmd, + .mthd = nvd9_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c index e2de73ee5ee..c5b24923858 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nve4_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nve4_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x000039, 3, 0x01, 0x00000000 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, @@ -138,8 +142,7 @@ nve4_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -197,15 +200,13 @@ nve4_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x000b07, 1, 0x01, 0x00000002 }, { 0x000b08, 2, 0x01, 0x00000100 }, @@ -231,14 +232,12 @@ nve4_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000008 }, @@ -273,8 +272,14 @@ nve4_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nve4_grctx_init_a097[] = { +const struct nvc0_graph_pack +nve4_grctx_pack_icmd[] = { + { nve4_grctx_init_icmd_0 }, + {} +}; + +const struct nvc0_graph_init +nve4_grctx_init_a097_0[] = { { 0x000800, 8, 0x40, 0x00000000 }, { 0x000804, 8, 0x40, 0x00000000 }, { 0x000808, 8, 0x40, 0x00000400 }, @@ -517,8 +522,7 @@ nve4_grctx_init_a097[] = { { 0x001350, 1, 0x04, 0x00000002 }, { 0x001358, 1, 0x04, 0x00000001 }, { 0x0012e4, 1, 0x04, 0x00000000 }, - { 0x00131c, 1, 0x04, 0x00000000 }, - { 0x001320, 3, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, { 0x0019c0, 1, 0x04, 0x00000000 }, { 0x001140, 1, 0x04, 0x00000000 }, { 0x0019c4, 1, 0x04, 0x00000000 }, @@ -574,19 +578,24 @@ nve4_grctx_init_a097[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk40xx[] = { +static const struct nvc0_graph_pack +nve4_grctx_pack_mthd[] = { + { nve4_grctx_init_a097_0, 0xa097 }, + { nvc0_grctx_init_902d_0, 0x902d }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_fe_0[] = { { 0x404010, 5, 0x04, 0x00000000 }, { 0x404024, 1, 0x04, 0x0000e000 }, { 0x404028, 1, 0x04, 0x00000000 }, - { 0x4040a8, 1, 0x04, 0x00000000 }, - { 0x4040ac, 7, 0x04, 0x00000000 }, + { 0x4040a8, 8, 0x04, 0x00000000 }, { 0x4040c8, 1, 0x04, 0xf800008f }, { 0x4040d0, 6, 0x04, 0x00000000 }, { 0x4040e8, 1, 0x04, 0x00001000 }, { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, { 0x404138, 1, 0x04, 0x20000040 }, { 0x404150, 1, 0x04, 0x0000002e }, { 0x404154, 1, 0x04, 0x00000400 }, @@ -597,8 +606,8 @@ nve4_grctx_init_unk40xx[] = { {} }; -struct nvc0_graph_init -nve4_grctx_init_unk46xx[] = { +const struct nvc0_graph_init +nve4_grctx_init_memfmt_0[] = { { 0x404604, 1, 0x04, 0x00000014 }, { 0x404608, 1, 0x04, 0x00000000 }, { 0x40460c, 1, 0x04, 0x00003fff }, @@ -614,11 +623,6 @@ nve4_grctx_init_unk46xx[] = { { 0x4046a0, 1, 0x04, 0x007f0080 }, { 0x4046a4, 8, 0x04, 0x00000000 }, { 0x4046c8, 3, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_init -nve4_grctx_init_unk47xx[] = { { 0x404700, 3, 0x04, 0x00000000 }, { 0x404718, 7, 0x04, 0x00000000 }, { 0x404734, 1, 0x04, 0x00000100 }, @@ -628,8 +632,8 @@ nve4_grctx_init_unk47xx[] = { {} }; -struct nvc0_graph_init -nve4_grctx_init_unk58xx[] = { +const struct nvc0_graph_init +nve4_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180648 }, { 0x405834, 1, 0x04, 0x08000000 }, @@ -641,22 +645,17 @@ nve4_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk5bxx[] = { +static const struct nvc0_graph_init +nve4_grctx_init_cwd_0[] = { { 0x405b00, 1, 0x04, 0x00000000 }, { 0x405b10, 1, 0x04, 0x00001000 }, {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk60xx[] = { +static const struct nvc0_graph_init +nve4_grctx_init_pd_0[] = { { 0x406020, 1, 0x04, 0x004103c1 }, { 0x406028, 4, 0x04, 0x00000001 }, - {} -}; - -static struct nvc0_graph_init -nve4_grctx_init_unk64xx[] = { { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 2, 0x04, 0x00000000 }, @@ -668,14 +667,14 @@ nve4_grctx_init_unk64xx[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk70xx[] = { +static const struct nvc0_graph_init +nve4_grctx_init_sked_0[] = { { 0x407040, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nve4_grctx_init_unk80xx[] = { +const struct nvc0_graph_init +nve4_grctx_init_scc_0[] = { { 0x408000, 2, 0x04, 0x00000000 }, { 0x408008, 1, 0x04, 0x00000030 }, { 0x40800c, 2, 0x04, 0x00000000 }, @@ -685,8 +684,8 @@ nve4_grctx_init_unk80xx[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_rop[] = { +static const struct nvc0_graph_init +nve4_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1043e005 }, @@ -698,22 +697,24 @@ nve4_grctx_init_rop[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x02200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 3, 0x04, 0x00000000 }, +const struct nvc0_graph_pack +nve4_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nve4_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { nve4_grctx_init_ds_0 }, + { nve4_grctx_init_cwd_0 }, + { nve4_grctx_init_pd_0 }, + { nve4_grctx_init_sked_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { nve4_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00000044 }, @@ -722,35 +723,35 @@ nve4_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418b00, 1, 0x04, 0x00000006 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +const struct nvc0_graph_init +nve4_grctx_init_gpm_0[] = { { 0x418c08, 1, 0x04, 0x00000001 }, { 0x418c10, 8, 0x04, 0x00000000 }, { 0x418c40, 1, 0x04, 0xffffffff }, { 0x418c6c, 1, 0x04, 0x00000001 }, { 0x418c80, 1, 0x04, 0x20200004 }, { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nve4_grctx_init_tpc[] = { - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x00000129 }, - { 0x419888, 1, 0x04, 0x00000000 }, +const struct nvc0_graph_pack +nve4_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nve4_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nve4_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000000f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000021 }, @@ -761,14 +762,29 @@ nve4_grctx_init_tpc[] = { { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419a30, 1, 0x04, 0x00000001 }, { 0x419ac4, 1, 0x04, 0x0037f440 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000000a }, { 0x419c04, 1, 0x04, 0x80000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3efbefbe }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_l1c_0[] = { { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00003203 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000402 }, { 0x419e44, 1, 0x04, 0x0013eff2 }, @@ -782,29 +798,47 @@ nve4_grctx_init_tpc[] = { { 0x419f58, 1, 0x04, 0x00000000 }, { 0x419f70, 1, 0x04, 0x00000000 }, { 0x419f78, 1, 0x04, 0x0000000b }, - { 0x419f7c, 1, 0x04, 0x0000027a }, + { 0x419f7c, 1, 0x04, 0x0000027c }, {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk[] = { +const struct nvc0_graph_pack +nve4_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nve4_grctx_init_tex_0 }, + { nve4_grctx_init_mpc_0 }, + { nve4_grctx_init_l1c_0 }, + { nve4_grctx_init_sm_0 }, + {} +}; + +const struct nvc0_graph_init +nve4_grctx_init_pes_0[] = { { 0x41be24, 1, 0x04, 0x00000006 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_cbm_0[] = { { 0x41bec0, 1, 0x04, 0x12180000 }, { 0x41bec4, 1, 0x04, 0x00037f7f }, { 0x41bee4, 1, 0x04, 0x06480430 }, - { 0x41bf00, 1, 0x04, 0x0a418820 }, - { 0x41bf04, 1, 0x04, 0x062080e6 }, - { 0x41bf08, 1, 0x04, 0x020398a4 }, - { 0x41bf0c, 1, 0x04, 0x0e629062 }, - { 0x41bf10, 1, 0x04, 0x0a418820 }, - { 0x41bf14, 1, 0x04, 0x000000e6 }, - { 0x41bfd0, 1, 0x04, 0x00900103 }, - { 0x41bfe0, 1, 0x04, 0x00400001 }, - { 0x41bfe4, 1, 0x04, 0x00000000 }, {} }; -static void +const struct nvc0_graph_pack +nve4_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { nve4_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + +void nve4_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { u32 magic[GPC_MAX][2]; @@ -925,10 +959,11 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x000260, 0x00000001, 0x00000000); - for (i = 0; oclass->hub[i]; i++) - nvc0_graph_mmio(priv, oclass->hub[i]); - for (i = 0; oclass->gpc[i]; i++) - nvc0_graph_mmio(priv, oclass->gpc[i]); + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); nv_wr32(priv, 0x404154, 0x00000000); @@ -962,41 +997,6 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x41be10, 0x00800000, 0x00800000); } -static struct nvc0_graph_init * -nve4_grctx_init_hub[] = { - nvc0_grctx_init_base, - nve4_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nve4_grctx_init_unk46xx, - nve4_grctx_init_unk47xx, - nve4_grctx_init_unk58xx, - nve4_grctx_init_unk5bxx, - nve4_grctx_init_unk60xx, - nve4_grctx_init_unk64xx, - nve4_grctx_init_unk70xx, - nvc0_grctx_init_unk78xx, - nve4_grctx_init_unk80xx, - nve4_grctx_init_rop, - NULL -}; - -struct nvc0_graph_init * -nve4_grctx_init_gpc[] = { - nve4_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nve4_grctx_init_tpc, - nve4_grctx_init_unk, - NULL -}; - -static struct nvc0_graph_mthd -nve4_grctx_init_mthd[] = { - { 0xa097, nve4_grctx_init_a097, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nve4_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xe4), @@ -1008,11 +1008,14 @@ nve4_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nve4_grctx_generate_main, - .mods = nve4_grctx_generate_mods, - .unkn = nve4_grctx_generate_unkn, - .hub = nve4_grctx_init_hub, - .gpc = nve4_grctx_init_gpc, - .icmd = nve4_grctx_init_icmd, - .mthd = nve4_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nve4_grctx_pack_tpc, + .ppc = nve4_grctx_pack_ppc, + .icmd = nve4_grctx_pack_icmd, + .mthd = nve4_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c index dcb2ebb8c29..dec03f04114 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c @@ -22,10 +22,580 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvf0_grctx_init_unk40xx[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvf0_grctx_init_icmd_0[] = { + { 0x001000, 1, 0x01, 0x00000004 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x0000a9, 1, 0x01, 0x0000ffff }, + { 0x000038, 1, 0x01, 0x0fac6881 }, + { 0x00003d, 1, 0x01, 0x00000001 }, + { 0x0000e8, 8, 0x01, 0x00000400 }, + { 0x000078, 8, 0x01, 0x00000300 }, + { 0x000050, 1, 0x01, 0x00000011 }, + { 0x000058, 8, 0x01, 0x00000008 }, + { 0x000208, 8, 0x01, 0x00000001 }, + { 0x000081, 1, 0x01, 0x00000001 }, + { 0x000085, 1, 0x01, 0x00000004 }, + { 0x000088, 1, 0x01, 0x00000400 }, + { 0x000090, 1, 0x01, 0x00000300 }, + { 0x000098, 1, 0x01, 0x00001001 }, + { 0x0000e3, 1, 0x01, 0x00000001 }, + { 0x0000da, 1, 0x01, 0x00000001 }, + { 0x0000f8, 1, 0x01, 0x00000003 }, + { 0x0000fa, 1, 0x01, 0x00000001 }, + { 0x00009f, 4, 0x01, 0x0000ffff }, + { 0x0000b1, 1, 0x01, 0x00000001 }, + { 0x0000ad, 1, 0x01, 0x0000013e }, + { 0x0000e1, 1, 0x01, 0x00000010 }, + { 0x000290, 16, 0x01, 0x00000000 }, + { 0x0003b0, 16, 0x01, 0x00000000 }, + { 0x0002a0, 16, 0x01, 0x00000000 }, + { 0x000420, 16, 0x01, 0x00000000 }, + { 0x0002b0, 16, 0x01, 0x00000000 }, + { 0x000430, 16, 0x01, 0x00000000 }, + { 0x0002c0, 16, 0x01, 0x00000000 }, + { 0x0004d0, 16, 0x01, 0x00000000 }, + { 0x000720, 16, 0x01, 0x00000000 }, + { 0x0008c0, 16, 0x01, 0x00000000 }, + { 0x000890, 16, 0x01, 0x00000000 }, + { 0x0008e0, 16, 0x01, 0x00000000 }, + { 0x0008a0, 16, 0x01, 0x00000000 }, + { 0x0008f0, 16, 0x01, 0x00000000 }, + { 0x00094c, 1, 0x01, 0x000000ff }, + { 0x00094d, 1, 0x01, 0xffffffff }, + { 0x00094e, 1, 0x01, 0x00000002 }, + { 0x0002ec, 1, 0x01, 0x00000001 }, + { 0x0002f2, 2, 0x01, 0x00000001 }, + { 0x0002f5, 1, 0x01, 0x00000001 }, + { 0x0002f7, 1, 0x01, 0x00000001 }, + { 0x000303, 1, 0x01, 0x00000001 }, + { 0x0002e6, 1, 0x01, 0x00000001 }, + { 0x000466, 1, 0x01, 0x00000052 }, + { 0x000301, 1, 0x01, 0x3f800000 }, + { 0x000304, 1, 0x01, 0x30201000 }, + { 0x000305, 1, 0x01, 0x70605040 }, + { 0x000306, 1, 0x01, 0xb8a89888 }, + { 0x000307, 1, 0x01, 0xf8e8d8c8 }, + { 0x00030a, 1, 0x01, 0x00ffff00 }, + { 0x00030b, 1, 0x01, 0x0000001a }, + { 0x00030c, 1, 0x01, 0x00000001 }, + { 0x000318, 1, 0x01, 0x00000001 }, + { 0x000340, 1, 0x01, 0x00000000 }, + { 0x000375, 1, 0x01, 0x00000001 }, + { 0x00037d, 1, 0x01, 0x00000006 }, + { 0x0003a0, 1, 0x01, 0x00000002 }, + { 0x0003aa, 1, 0x01, 0x00000001 }, + { 0x0003a9, 1, 0x01, 0x00000001 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000383, 1, 0x01, 0x00000011 }, + { 0x000360, 1, 0x01, 0x00000040 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x00037a, 1, 0x01, 0x00000012 }, + { 0x000619, 1, 0x01, 0x00000003 }, + { 0x000811, 1, 0x01, 0x00000003 }, + { 0x000812, 1, 0x01, 0x00000004 }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000815, 1, 0x01, 0x0000000b }, + { 0x000800, 6, 0x01, 0x00000001 }, + { 0x000632, 1, 0x01, 0x00000001 }, + { 0x000633, 1, 0x01, 0x00000002 }, + { 0x000634, 1, 0x01, 0x00000003 }, + { 0x000635, 1, 0x01, 0x00000004 }, + { 0x000654, 1, 0x01, 0x3f800000 }, + { 0x000657, 1, 0x01, 0x3f800000 }, + { 0x000655, 2, 0x01, 0x3f800000 }, + { 0x0006cd, 1, 0x01, 0x3f800000 }, + { 0x0007f5, 1, 0x01, 0x3f800000 }, + { 0x0007dc, 1, 0x01, 0x39291909 }, + { 0x0007dd, 1, 0x01, 0x79695949 }, + { 0x0007de, 1, 0x01, 0xb9a99989 }, + { 0x0007df, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007e8, 1, 0x01, 0x00003210 }, + { 0x0007e9, 1, 0x01, 0x00007654 }, + { 0x0007ea, 1, 0x01, 0x00000098 }, + { 0x0007ec, 1, 0x01, 0x39291909 }, + { 0x0007ed, 1, 0x01, 0x79695949 }, + { 0x0007ee, 1, 0x01, 0xb9a99989 }, + { 0x0007ef, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007f0, 1, 0x01, 0x00003210 }, + { 0x0007f1, 1, 0x01, 0x00007654 }, + { 0x0007f2, 1, 0x01, 0x00000098 }, + { 0x0005a5, 1, 0x01, 0x00000001 }, + { 0x000980, 128, 0x01, 0x00000000 }, + { 0x000468, 1, 0x01, 0x00000004 }, + { 0x00046c, 1, 0x01, 0x00000001 }, + { 0x000470, 96, 0x01, 0x00000000 }, + { 0x000510, 16, 0x01, 0x3f800000 }, + { 0x000520, 1, 0x01, 0x000002b6 }, + { 0x000529, 1, 0x01, 0x00000001 }, + { 0x000530, 16, 0x01, 0xffff0000 }, + { 0x000585, 1, 0x01, 0x0000003f }, + { 0x000576, 1, 0x01, 0x00000003 }, + { 0x00057b, 1, 0x01, 0x00000059 }, + { 0x000586, 1, 0x01, 0x00000040 }, + { 0x000582, 2, 0x01, 0x00000080 }, + { 0x0005c2, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, + { 0x00063a, 1, 0x01, 0x00000002 }, + { 0x00063b, 2, 0x01, 0x00000001 }, + { 0x00063d, 1, 0x01, 0x00000002 }, + { 0x00063e, 1, 0x01, 0x00000001 }, + { 0x0008b8, 8, 0x01, 0x00000001 }, + { 0x000900, 8, 0x01, 0x00000001 }, + { 0x000908, 8, 0x01, 0x00000002 }, + { 0x000910, 16, 0x01, 0x00000001 }, + { 0x000920, 8, 0x01, 0x00000002 }, + { 0x000928, 8, 0x01, 0x00000001 }, + { 0x000662, 1, 0x01, 0x00000001 }, + { 0x000648, 9, 0x01, 0x00000001 }, + { 0x000658, 1, 0x01, 0x0000000f }, + { 0x0007ff, 1, 0x01, 0x0000000a }, + { 0x00066a, 1, 0x01, 0x40000000 }, + { 0x00066b, 1, 0x01, 0x10000000 }, + { 0x00066c, 2, 0x01, 0xffff0000 }, + { 0x0007af, 2, 0x01, 0x00000008 }, + { 0x0007f6, 1, 0x01, 0x00000001 }, + { 0x00080b, 1, 0x01, 0x00000002 }, + { 0x0006b2, 1, 0x01, 0x00000055 }, + { 0x0007ad, 1, 0x01, 0x00000003 }, + { 0x000937, 1, 0x01, 0x00000001 }, + { 0x000971, 1, 0x01, 0x00000008 }, + { 0x000972, 1, 0x01, 0x00000040 }, + { 0x000973, 1, 0x01, 0x0000012c }, + { 0x00097c, 1, 0x01, 0x00000040 }, + { 0x000979, 1, 0x01, 0x00000003 }, + { 0x000975, 1, 0x01, 0x00000020 }, + { 0x000976, 1, 0x01, 0x00000001 }, + { 0x000977, 1, 0x01, 0x00000020 }, + { 0x000978, 1, 0x01, 0x00000001 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x00095e, 1, 0x01, 0x20164010 }, + { 0x00095f, 1, 0x01, 0x00000020 }, + { 0x000a0d, 1, 0x01, 0x00000006 }, + { 0x00097d, 1, 0x01, 0x00000020 }, + { 0x000683, 1, 0x01, 0x00000006 }, + { 0x000685, 1, 0x01, 0x003fffff }, + { 0x000687, 1, 0x01, 0x003fffff }, + { 0x0006a0, 1, 0x01, 0x00000005 }, + { 0x000840, 1, 0x01, 0x00400008 }, + { 0x000841, 1, 0x01, 0x08000080 }, + { 0x000842, 1, 0x01, 0x00400008 }, + { 0x000843, 1, 0x01, 0x08000080 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ab, 1, 0x01, 0x00000002 }, + { 0x0006ac, 1, 0x01, 0x00000080 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x0006bb, 1, 0x01, 0x000000cf }, + { 0x0006ce, 1, 0x01, 0x2a712488 }, + { 0x000739, 1, 0x01, 0x4085c000 }, + { 0x00073a, 1, 0x01, 0x00000080 }, + { 0x000786, 1, 0x01, 0x80000100 }, + { 0x00073c, 1, 0x01, 0x00010100 }, + { 0x00073d, 1, 0x01, 0x02800000 }, + { 0x000787, 1, 0x01, 0x000000cf }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x000836, 1, 0x01, 0x00000001 }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x000833, 1, 0x01, 0x04444480 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c1b0, 8, 0x01, 0x0000000f }, + { 0x00c1b8, 1, 0x01, 0x0fac6881 }, + { 0x00c1b9, 1, 0x01, 0x00fac688 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x00c500, 1, 0x01, 0x00000003 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000002 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x000833, 1, 0x01, 0x04444480 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000008 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x00c500, 1, 0x01, 0x00000003 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000001 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + {} +}; + +static const struct nvc0_graph_pack +nvf0_grctx_pack_icmd[] = { + { nvf0_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_a197_0[] = { + { 0x000800, 8, 0x40, 0x00000000 }, + { 0x000804, 8, 0x40, 0x00000000 }, + { 0x000808, 8, 0x40, 0x00000400 }, + { 0x00080c, 8, 0x40, 0x00000300 }, + { 0x000810, 1, 0x04, 0x000000cf }, + { 0x000850, 7, 0x40, 0x00000000 }, + { 0x000814, 8, 0x40, 0x00000040 }, + { 0x000818, 8, 0x40, 0x00000001 }, + { 0x00081c, 8, 0x40, 0x00000000 }, + { 0x000820, 8, 0x40, 0x00000000 }, + { 0x001c00, 16, 0x10, 0x00000000 }, + { 0x001c04, 16, 0x10, 0x00000000 }, + { 0x001c08, 16, 0x10, 0x00000000 }, + { 0x001c0c, 16, 0x10, 0x00000000 }, + { 0x001d00, 16, 0x10, 0x00000000 }, + { 0x001d04, 16, 0x10, 0x00000000 }, + { 0x001d08, 16, 0x10, 0x00000000 }, + { 0x001d0c, 16, 0x10, 0x00000000 }, + { 0x001f00, 16, 0x08, 0x00000000 }, + { 0x001f04, 16, 0x08, 0x00000000 }, + { 0x001f80, 16, 0x08, 0x00000000 }, + { 0x001f84, 16, 0x08, 0x00000000 }, + { 0x002000, 1, 0x04, 0x00000000 }, + { 0x002040, 1, 0x04, 0x00000011 }, + { 0x002080, 1, 0x04, 0x00000020 }, + { 0x0020c0, 1, 0x04, 0x00000030 }, + { 0x002100, 1, 0x04, 0x00000040 }, + { 0x002140, 1, 0x04, 0x00000051 }, + { 0x00200c, 6, 0x40, 0x00000001 }, + { 0x002010, 1, 0x04, 0x00000000 }, + { 0x002050, 1, 0x04, 0x00000000 }, + { 0x002090, 1, 0x04, 0x00000001 }, + { 0x0020d0, 1, 0x04, 0x00000002 }, + { 0x002110, 1, 0x04, 0x00000003 }, + { 0x002150, 1, 0x04, 0x00000004 }, + { 0x000380, 4, 0x20, 0x00000000 }, + { 0x000384, 4, 0x20, 0x00000000 }, + { 0x000388, 4, 0x20, 0x00000000 }, + { 0x00038c, 4, 0x20, 0x00000000 }, + { 0x000700, 4, 0x10, 0x00000000 }, + { 0x000704, 4, 0x10, 0x00000000 }, + { 0x000708, 4, 0x10, 0x00000000 }, + { 0x002800, 128, 0x04, 0x00000000 }, + { 0x000a00, 16, 0x20, 0x00000000 }, + { 0x000a04, 16, 0x20, 0x00000000 }, + { 0x000a08, 16, 0x20, 0x00000000 }, + { 0x000a0c, 16, 0x20, 0x00000000 }, + { 0x000a10, 16, 0x20, 0x00000000 }, + { 0x000a14, 16, 0x20, 0x00000000 }, + { 0x000c00, 16, 0x10, 0x00000000 }, + { 0x000c04, 16, 0x10, 0x00000000 }, + { 0x000c08, 16, 0x10, 0x00000000 }, + { 0x000c0c, 16, 0x10, 0x3f800000 }, + { 0x000d00, 8, 0x08, 0xffff0000 }, + { 0x000d04, 8, 0x08, 0xffff0000 }, + { 0x000e00, 16, 0x10, 0x00000000 }, + { 0x000e04, 16, 0x10, 0xffff0000 }, + { 0x000e08, 16, 0x10, 0xffff0000 }, + { 0x000d40, 4, 0x08, 0x00000000 }, + { 0x000d44, 4, 0x08, 0x00000000 }, + { 0x001e00, 8, 0x20, 0x00000001 }, + { 0x001e04, 8, 0x20, 0x00000001 }, + { 0x001e08, 8, 0x20, 0x00000002 }, + { 0x001e0c, 8, 0x20, 0x00000001 }, + { 0x001e10, 8, 0x20, 0x00000001 }, + { 0x001e14, 8, 0x20, 0x00000002 }, + { 0x001e18, 8, 0x20, 0x00000001 }, + { 0x003400, 128, 0x04, 0x00000000 }, + { 0x00030c, 1, 0x04, 0x00000001 }, + { 0x001944, 1, 0x04, 0x00000000 }, + { 0x001514, 1, 0x04, 0x00000000 }, + { 0x000d68, 1, 0x04, 0x0000ffff }, + { 0x00121c, 1, 0x04, 0x0fac6881 }, + { 0x000fac, 1, 0x04, 0x00000001 }, + { 0x001538, 1, 0x04, 0x00000001 }, + { 0x000fe0, 2, 0x04, 0x00000000 }, + { 0x000fe8, 1, 0x04, 0x00000014 }, + { 0x000fec, 1, 0x04, 0x00000040 }, + { 0x000ff0, 1, 0x04, 0x00000000 }, + { 0x00179c, 1, 0x04, 0x00000000 }, + { 0x001228, 1, 0x04, 0x00000400 }, + { 0x00122c, 1, 0x04, 0x00000300 }, + { 0x001230, 1, 0x04, 0x00010001 }, + { 0x0007f8, 1, 0x04, 0x00000000 }, + { 0x0015b4, 1, 0x04, 0x00000001 }, + { 0x0015cc, 1, 0x04, 0x00000000 }, + { 0x001534, 1, 0x04, 0x00000000 }, + { 0x000fb0, 1, 0x04, 0x00000000 }, + { 0x0015d0, 1, 0x04, 0x00000000 }, + { 0x00153c, 1, 0x04, 0x00000000 }, + { 0x0016b4, 1, 0x04, 0x00000003 }, + { 0x000fbc, 4, 0x04, 0x0000ffff }, + { 0x000df8, 2, 0x04, 0x00000000 }, + { 0x001948, 1, 0x04, 0x00000000 }, + { 0x001970, 1, 0x04, 0x00000001 }, + { 0x00161c, 1, 0x04, 0x000009f0 }, + { 0x000dcc, 1, 0x04, 0x00000010 }, + { 0x00163c, 1, 0x04, 0x00000000 }, + { 0x0015e4, 1, 0x04, 0x00000000 }, + { 0x001160, 32, 0x04, 0x25e00040 }, + { 0x001880, 32, 0x04, 0x00000000 }, + { 0x000f84, 2, 0x04, 0x00000000 }, + { 0x0017c8, 2, 0x04, 0x00000000 }, + { 0x0017d0, 1, 0x04, 0x000000ff }, + { 0x0017d4, 1, 0x04, 0xffffffff }, + { 0x0017d8, 1, 0x04, 0x00000002 }, + { 0x0017dc, 1, 0x04, 0x00000000 }, + { 0x0015f4, 2, 0x04, 0x00000000 }, + { 0x001434, 2, 0x04, 0x00000000 }, + { 0x000d74, 1, 0x04, 0x00000000 }, + { 0x000dec, 1, 0x04, 0x00000001 }, + { 0x0013a4, 1, 0x04, 0x00000000 }, + { 0x001318, 1, 0x04, 0x00000001 }, + { 0x001644, 1, 0x04, 0x00000000 }, + { 0x000748, 1, 0x04, 0x00000000 }, + { 0x000de8, 1, 0x04, 0x00000000 }, + { 0x001648, 1, 0x04, 0x00000000 }, + { 0x0012a4, 1, 0x04, 0x00000000 }, + { 0x001120, 4, 0x04, 0x00000000 }, + { 0x001118, 1, 0x04, 0x00000000 }, + { 0x00164c, 1, 0x04, 0x00000000 }, + { 0x001658, 1, 0x04, 0x00000000 }, + { 0x001910, 1, 0x04, 0x00000290 }, + { 0x001518, 1, 0x04, 0x00000000 }, + { 0x00165c, 1, 0x04, 0x00000001 }, + { 0x001520, 1, 0x04, 0x00000000 }, + { 0x001604, 1, 0x04, 0x00000000 }, + { 0x001570, 1, 0x04, 0x00000000 }, + { 0x0013b0, 2, 0x04, 0x3f800000 }, + { 0x00020c, 1, 0x04, 0x00000000 }, + { 0x001670, 1, 0x04, 0x30201000 }, + { 0x001674, 1, 0x04, 0x70605040 }, + { 0x001678, 1, 0x04, 0xb8a89888 }, + { 0x00167c, 1, 0x04, 0xf8e8d8c8 }, + { 0x00166c, 1, 0x04, 0x00000000 }, + { 0x001680, 1, 0x04, 0x00ffff00 }, + { 0x0012d0, 1, 0x04, 0x00000003 }, + { 0x0012d4, 1, 0x04, 0x00000002 }, + { 0x001684, 2, 0x04, 0x00000000 }, + { 0x000dac, 2, 0x04, 0x00001b02 }, + { 0x000db4, 1, 0x04, 0x00000000 }, + { 0x00168c, 1, 0x04, 0x00000000 }, + { 0x0015bc, 1, 0x04, 0x00000000 }, + { 0x00156c, 1, 0x04, 0x00000000 }, + { 0x00187c, 1, 0x04, 0x00000000 }, + { 0x001110, 1, 0x04, 0x00000001 }, + { 0x000dc0, 3, 0x04, 0x00000000 }, + { 0x001234, 1, 0x04, 0x00000000 }, + { 0x001690, 1, 0x04, 0x00000000 }, + { 0x0012ac, 1, 0x04, 0x00000001 }, + { 0x0002c4, 1, 0x04, 0x00000000 }, + { 0x000790, 5, 0x04, 0x00000000 }, + { 0x00077c, 1, 0x04, 0x00000000 }, + { 0x001000, 1, 0x04, 0x00000010 }, + { 0x0010fc, 1, 0x04, 0x00000000 }, + { 0x001290, 1, 0x04, 0x00000000 }, + { 0x000218, 1, 0x04, 0x00000010 }, + { 0x0012d8, 1, 0x04, 0x00000000 }, + { 0x0012dc, 1, 0x04, 0x00000010 }, + { 0x000d94, 1, 0x04, 0x00000001 }, + { 0x00155c, 2, 0x04, 0x00000000 }, + { 0x001564, 1, 0x04, 0x00000fff }, + { 0x001574, 2, 0x04, 0x00000000 }, + { 0x00157c, 1, 0x04, 0x000fffff }, + { 0x001354, 1, 0x04, 0x00000000 }, + { 0x001610, 1, 0x04, 0x00000012 }, + { 0x001608, 2, 0x04, 0x00000000 }, + { 0x00260c, 1, 0x04, 0x00000000 }, + { 0x0007ac, 1, 0x04, 0x00000000 }, + { 0x00162c, 1, 0x04, 0x00000003 }, + { 0x000210, 1, 0x04, 0x00000000 }, + { 0x000320, 1, 0x04, 0x00000000 }, + { 0x000324, 6, 0x04, 0x3f800000 }, + { 0x000750, 1, 0x04, 0x00000000 }, + { 0x000760, 1, 0x04, 0x39291909 }, + { 0x000764, 1, 0x04, 0x79695949 }, + { 0x000768, 1, 0x04, 0xb9a99989 }, + { 0x00076c, 1, 0x04, 0xf9e9d9c9 }, + { 0x000770, 1, 0x04, 0x30201000 }, + { 0x000774, 1, 0x04, 0x70605040 }, + { 0x000778, 1, 0x04, 0x00009080 }, + { 0x000780, 1, 0x04, 0x39291909 }, + { 0x000784, 1, 0x04, 0x79695949 }, + { 0x000788, 1, 0x04, 0xb9a99989 }, + { 0x00078c, 1, 0x04, 0xf9e9d9c9 }, + { 0x0007d0, 1, 0x04, 0x30201000 }, + { 0x0007d4, 1, 0x04, 0x70605040 }, + { 0x0007d8, 1, 0x04, 0x00009080 }, + { 0x00037c, 1, 0x04, 0x00000001 }, + { 0x000740, 2, 0x04, 0x00000000 }, + { 0x002600, 1, 0x04, 0x00000000 }, + { 0x001918, 1, 0x04, 0x00000000 }, + { 0x00191c, 1, 0x04, 0x00000900 }, + { 0x001920, 1, 0x04, 0x00000405 }, + { 0x001308, 1, 0x04, 0x00000001 }, + { 0x001924, 1, 0x04, 0x00000000 }, + { 0x0013ac, 1, 0x04, 0x00000000 }, + { 0x00192c, 1, 0x04, 0x00000001 }, + { 0x00193c, 1, 0x04, 0x00002c1c }, + { 0x000d7c, 1, 0x04, 0x00000000 }, + { 0x000f8c, 1, 0x04, 0x00000000 }, + { 0x0002c0, 1, 0x04, 0x00000001 }, + { 0x001510, 1, 0x04, 0x00000000 }, + { 0x001940, 1, 0x04, 0x00000000 }, + { 0x000ff4, 2, 0x04, 0x00000000 }, + { 0x00194c, 2, 0x04, 0x00000000 }, + { 0x001968, 1, 0x04, 0x00000000 }, + { 0x001590, 1, 0x04, 0x0000003f }, + { 0x0007e8, 4, 0x04, 0x00000000 }, + { 0x00196c, 1, 0x04, 0x00000011 }, + { 0x0002e4, 1, 0x04, 0x0000b001 }, + { 0x00036c, 2, 0x04, 0x00000000 }, + { 0x00197c, 1, 0x04, 0x00000000 }, + { 0x000fcc, 2, 0x04, 0x00000000 }, + { 0x0002d8, 1, 0x04, 0x00000040 }, + { 0x001980, 1, 0x04, 0x00000080 }, + { 0x001504, 1, 0x04, 0x00000080 }, + { 0x001984, 1, 0x04, 0x00000000 }, + { 0x000300, 1, 0x04, 0x00000001 }, + { 0x0013a8, 1, 0x04, 0x00000000 }, + { 0x0012ec, 1, 0x04, 0x00000000 }, + { 0x001310, 1, 0x04, 0x00000000 }, + { 0x001314, 1, 0x04, 0x00000001 }, + { 0x001380, 1, 0x04, 0x00000000 }, + { 0x001384, 4, 0x04, 0x00000001 }, + { 0x001394, 1, 0x04, 0x00000000 }, + { 0x00139c, 1, 0x04, 0x00000000 }, + { 0x001398, 1, 0x04, 0x00000000 }, + { 0x001594, 1, 0x04, 0x00000000 }, + { 0x001598, 4, 0x04, 0x00000001 }, + { 0x000f54, 3, 0x04, 0x00000000 }, + { 0x0019bc, 1, 0x04, 0x00000000 }, + { 0x000f9c, 2, 0x04, 0x00000000 }, + { 0x0012cc, 1, 0x04, 0x00000000 }, + { 0x0012e8, 1, 0x04, 0x00000000 }, + { 0x00130c, 1, 0x04, 0x00000001 }, + { 0x001360, 8, 0x04, 0x00000000 }, + { 0x00133c, 2, 0x04, 0x00000001 }, + { 0x001344, 1, 0x04, 0x00000002 }, + { 0x001348, 2, 0x04, 0x00000001 }, + { 0x001350, 1, 0x04, 0x00000002 }, + { 0x001358, 1, 0x04, 0x00000001 }, + { 0x0012e4, 1, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, + { 0x0019c0, 1, 0x04, 0x00000000 }, + { 0x001140, 1, 0x04, 0x00000000 }, + { 0x0019c4, 1, 0x04, 0x00000000 }, + { 0x0019c8, 1, 0x04, 0x00001500 }, + { 0x00135c, 1, 0x04, 0x00000000 }, + { 0x000f90, 1, 0x04, 0x00000000 }, + { 0x0019e0, 8, 0x04, 0x00000001 }, + { 0x0019cc, 1, 0x04, 0x00000001 }, + { 0x0015b8, 1, 0x04, 0x00000000 }, + { 0x001a00, 1, 0x04, 0x00001111 }, + { 0x001a04, 7, 0x04, 0x00000000 }, + { 0x000d6c, 2, 0x04, 0xffff0000 }, + { 0x0010f8, 1, 0x04, 0x00001010 }, + { 0x000d80, 5, 0x04, 0x00000000 }, + { 0x000da0, 1, 0x04, 0x00000000 }, + { 0x0007a4, 2, 0x04, 0x00000000 }, + { 0x001508, 1, 0x04, 0x80000000 }, + { 0x00150c, 1, 0x04, 0x40000000 }, + { 0x001668, 1, 0x04, 0x00000000 }, + { 0x000318, 2, 0x04, 0x00000008 }, + { 0x000d9c, 1, 0x04, 0x00000001 }, + { 0x000ddc, 1, 0x04, 0x00000002 }, + { 0x000374, 1, 0x04, 0x00000000 }, + { 0x000378, 1, 0x04, 0x00000020 }, + { 0x0007dc, 1, 0x04, 0x00000000 }, + { 0x00074c, 1, 0x04, 0x00000055 }, + { 0x001420, 1, 0x04, 0x00000003 }, + { 0x0017bc, 2, 0x04, 0x00000000 }, + { 0x0017c4, 1, 0x04, 0x00000001 }, + { 0x001008, 1, 0x04, 0x00000008 }, + { 0x00100c, 1, 0x04, 0x00000040 }, + { 0x001010, 1, 0x04, 0x0000012c }, + { 0x000d60, 1, 0x04, 0x00000040 }, + { 0x00075c, 1, 0x04, 0x00000003 }, + { 0x001018, 1, 0x04, 0x00000020 }, + { 0x00101c, 1, 0x04, 0x00000001 }, + { 0x001020, 1, 0x04, 0x00000020 }, + { 0x001024, 1, 0x04, 0x00000001 }, + { 0x001444, 3, 0x04, 0x00000000 }, + { 0x000360, 1, 0x04, 0x20164010 }, + { 0x000364, 1, 0x04, 0x00000020 }, + { 0x000368, 1, 0x04, 0x00000000 }, + { 0x000de4, 1, 0x04, 0x00000000 }, + { 0x000204, 1, 0x04, 0x00000006 }, + { 0x000208, 1, 0x04, 0x00000000 }, + { 0x0002cc, 2, 0x04, 0x003fffff }, + { 0x001220, 1, 0x04, 0x00000005 }, + { 0x000fdc, 1, 0x04, 0x00000000 }, + { 0x000f98, 1, 0x04, 0x00400008 }, + { 0x001284, 1, 0x04, 0x08000080 }, + { 0x001450, 1, 0x04, 0x00400008 }, + { 0x001454, 1, 0x04, 0x08000080 }, + { 0x000214, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_pack +nvf0_grctx_pack_mthd[] = { + { nvf0_grctx_init_a197_0, 0xa197 }, + { nvc0_grctx_init_902d_0, 0x902d }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_fe_0[] = { { 0x404004, 8, 0x04, 0x00000000 }, { 0x404024, 1, 0x04, 0x0000e000 }, { 0x404028, 8, 0x04, 0x00000000 }, @@ -50,8 +620,8 @@ nvf0_grctx_init_unk40xx[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_unk44xx[] = { +const struct nvc0_graph_init +nvf0_grctx_init_pri_0[] = { { 0x404404, 12, 0x04, 0x00000000 }, { 0x404438, 1, 0x04, 0x00000000 }, { 0x404460, 2, 0x04, 0x00000000 }, @@ -62,23 +632,18 @@ nvf0_grctx_init_unk44xx[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_unk5bxx[] = { +const struct nvc0_graph_init +nvf0_grctx_init_cwd_0[] = { { 0x405b00, 1, 0x04, 0x00000000 }, { 0x405b10, 1, 0x04, 0x00001000 }, { 0x405b20, 1, 0x04, 0x04000000 }, {} }; -static struct nvc0_graph_init -nvf0_grctx_init_unk60xx[] = { +static const struct nvc0_graph_init +nvf0_grctx_init_pd_0[] = { { 0x406020, 1, 0x04, 0x034103c1 }, { 0x406028, 4, 0x04, 0x00000001 }, - {} -}; - -static struct nvc0_graph_init -nvf0_grctx_init_unk64xx[] = { { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b0, 3, 0x04, 0x00000000 }, @@ -90,8 +655,8 @@ nvf0_grctx_init_unk64xx[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_unk88xx[] = { +static const struct nvc0_graph_init +nvf0_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x12802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1003e005 }, @@ -103,22 +668,23 @@ nvf0_grctx_init_unk88xx[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x02200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 3, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvf0_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvf0_grctx_init_fe_0 }, + { nvf0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { nve4_grctx_init_ds_0 }, + { nvf0_grctx_init_cwd_0 }, + { nvf0_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { nvf0_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 1, 0x04, 0x00000000 }, { 0x41880c, 1, 0x04, 0x00000030 }, @@ -129,36 +695,31 @@ nvf0_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418b00, 1, 0x04, 0x00000006 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, - { 0x418c08, 1, 0x04, 0x00000001 }, - { 0x418c10, 8, 0x04, 0x00000000 }, - { 0x418c40, 1, 0x04, 0xffffffff }, - { 0x418c6c, 1, 0x04, 0x00000001 }, - { 0x418c80, 1, 0x04, 0x20200004 }, - { 0x418c8c, 1, 0x04, 0x00000001 }, + {} +}; + +const struct nvc0_graph_init +nvf0_grctx_init_gpc_unk_2[] = { { 0x418d24, 1, 0x04, 0x00000000 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nvf0_grctx_init_tpc[] = { - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x00000129 }, - { 0x419888, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvf0_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nvf0_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nve4_grctx_init_gpm_0 }, + { nvf0_grctx_init_gpc_unk_2 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000000f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000021 }, @@ -169,14 +730,29 @@ nvf0_grctx_init_tpc[] = { { 0x419a20, 1, 0x04, 0x00020800 }, { 0x419a30, 1, 0x04, 0x00000001 }, { 0x419ac4, 1, 0x04, 0x0037f440 }, + {} +}; + +const struct nvc0_graph_init +nvf0_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000001a }, { 0x419c04, 1, 0x04, 0x80000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3efbefbe }, + {} +}; + +const struct nvc0_graph_init +nvf0_grctx_init_l1c_0[] = { { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00000203 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_sm_0[] = { { 0x419e04, 1, 0x04, 0x00000000 }, { 0x419e08, 1, 0x04, 0x0000001d }, { 0x419e0c, 1, 0x04, 0x00000000 }, @@ -189,8 +765,8 @@ nvf0_grctx_init_tpc[] = { { 0x419e5c, 3, 0x04, 0x00000000 }, { 0x419e68, 1, 0x04, 0x00000002 }, { 0x419e6c, 12, 0x04, 0x00000000 }, - { 0x419eac, 1, 0x04, 0x00001fcf }, - { 0x419eb0, 1, 0x04, 0x0db00da0 }, + { 0x419eac, 1, 0x04, 0x00001f8f }, + { 0x419eb0, 1, 0x04, 0x0db00d2f }, { 0x419eb8, 1, 0x04, 0x00000000 }, { 0x419ec8, 1, 0x04, 0x0001304f }, { 0x419f30, 4, 0x04, 0x00000000 }, @@ -203,24 +779,36 @@ nvf0_grctx_init_tpc[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_unk[] = { - { 0x41be24, 1, 0x04, 0x00000006 }, +static const struct nvc0_graph_pack +nvf0_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nvf0_grctx_init_tex_0 }, + { nvf0_grctx_init_mpc_0 }, + { nvf0_grctx_init_l1c_0 }, + { nvf0_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_cbm_0[] = { { 0x41bec0, 1, 0x04, 0x10000000 }, { 0x41bec4, 1, 0x04, 0x00037f7f }, { 0x41bee4, 1, 0x04, 0x00000000 }, - { 0x41bf00, 1, 0x04, 0x0a418820 }, - { 0x41bf04, 1, 0x04, 0x062080e6 }, - { 0x41bf08, 1, 0x04, 0x020398a4 }, - { 0x41bf0c, 1, 0x04, 0x0e629062 }, - { 0x41bf10, 1, 0x04, 0x0a418820 }, - { 0x41bf14, 1, 0x04, 0x000000e6 }, - { 0x41bfd0, 1, 0x04, 0x00900103 }, - { 0x41bfe0, 1, 0x04, 0x00400001 }, - { 0x41bfe4, 1, 0x04, 0x00000000 }, {} }; +static const struct nvc0_graph_pack +nvf0_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { nvf0_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + static void nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -254,7 +842,7 @@ nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) u16 magic3 = 0x0648; magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset; magic[gpc][1] = 0x00000000 | (magic1 << 16); - offset += 0x0324 * (priv->tpc_nr[gpc] - 1);; + offset += 0x0324 * (priv->tpc_nr[gpc] - 1); magic[gpc][2] = 0x10000000 | (magic2 << 16) | offset; magic[gpc][3] = 0x00000000 | (magic3 << 16); offset += 0x0324; @@ -273,40 +861,6 @@ nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) mmio_list(0x17e920, 0x00090a05, 0, 0); } -static struct nvc0_graph_init * -nvf0_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvf0_grctx_init_unk40xx, - nvf0_grctx_init_unk44xx, - nve4_grctx_init_unk46xx, - nve4_grctx_init_unk47xx, - nve4_grctx_init_unk58xx, - nvf0_grctx_init_unk5bxx, - nvf0_grctx_init_unk60xx, - nvf0_grctx_init_unk64xx, - nve4_grctx_init_unk80xx, - nvf0_grctx_init_unk88xx, - nvd9_grctx_init_rop, - NULL -}; - -struct nvc0_graph_init * -nvf0_grctx_init_gpc[] = { - nvf0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvf0_grctx_init_tpc, - nvf0_grctx_init_unk, - NULL -}; - -static struct nvc0_graph_mthd -nvf0_grctx_init_mthd[] = { - { 0xa197, nvc1_grctx_init_9097, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xf0), @@ -318,11 +872,14 @@ nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nve4_grctx_generate_main, - .mods = nvf0_grctx_generate_mods, - .unkn = nve4_grctx_generate_unkn, - .hub = nvf0_grctx_init_hub, - .gpc = nvf0_grctx_init_gpc, - .icmd = nvc0_grctx_init_icmd, - .mthd = nvf0_grctx_init_mthd, + .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, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvf0_grctx_pack_tpc, + .ppc = nvf0_grctx_pack_ppc, + .icmd = nvf0_grctx_pack_icmd, + .mthd = nvf0_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc index 5d24b6de16c..e37d8106ae1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc @@ -38,7 +38,7 @@ queue_put: cmpu b32 $r8 $r9 bra ne #queue_put_next mov $r15 E_CMD_OVERFLOW - call #error + call(error) ret // store cmd/data on queue @@ -92,18 +92,16 @@ queue_get_done: // Out: $r15 value // nv_rd32: - mov $r11 0x728 - shl b32 $r11 6 mov b32 $r12 $r14 bset $r12 31 // MMIO_CTRL_PENDING - iowr I[$r11 + 0x000] $r12 // MMIO_CTRL + nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12) nv_rd32_wait: - iord $r12 I[$r11 + 0x000] + nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0) xbit $r12 $r12 31 bra ne #nv_rd32_wait mov $r10 6 // DONE_MMIO_RD - call #wait_doneo - iord $r15 I[$r11 + 0x100] // MMIO_RDVAL + call(wait_doneo) + nv_iord($r15, NV_PGRAPH_FECS_MMIO_RDVAL, 0) ret // nv_wr32 - write 32-bit value to nv register @@ -112,37 +110,17 @@ nv_rd32: // $r15 value // nv_wr32: - mov $r11 0x728 - shl b32 $r11 6 - iowr I[$r11 + 0x200] $r15 // MMIO_WRVAL + nv_iowr(NV_PGRAPH_FECS_MMIO_WRVAL, 0, $r15) mov b32 $r12 $r14 bset $r12 31 // MMIO_CTRL_PENDING bset $r12 30 // MMIO_CTRL_WRITE - iowr I[$r11 + 0x000] $r12 // MMIO_CTRL + nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12) nv_wr32_wait: - iord $r12 I[$r11 + 0x000] + nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0) xbit $r12 $r12 31 bra ne #nv_wr32_wait ret -// (re)set watchdog timer -// -// In : $r15 timeout -// -watchdog_reset: - mov $r8 0x430 - shl b32 $r8 6 - bset $r15 31 - iowr I[$r8 + 0x000] $r15 - ret - -// clear watchdog timer -watchdog_clear: - mov $r8 0x430 - shl b32 $r8 6 - iowr I[$r8 + 0x000] $r0 - ret - // wait_donez - wait on FUC_DONE bit to become clear // // In : $r10 bit to wait on @@ -163,13 +141,9 @@ wait_donez: // wait_doneo: trace_set(T_WAIT); - mov $r8 0x818 - shl b32 $r8 6 - iowr I[$r8 + 0x000] $r10 + nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10) wait_doneo_e: - mov $r8 0x400 - shl b32 $r8 6 - iord $r8 I[$r8 + 0x000] + nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0) xbit $r8 $r8 $r10 bra e #wait_doneo_e trace_clr(T_WAIT) @@ -209,21 +183,18 @@ mmctx_size: // mmctx_xfer: trace_set(T_MMCTX) - mov $r8 0x710 - shl b32 $r8 6 clear b32 $r9 or $r11 $r11 bra e #mmctx_base_disabled - iowr I[$r8 + 0x000] $r11 // MMCTX_BASE + nv_iowr(NV_PGRAPH_FECS_MMCTX_BASE, 0, $r11) bset $r9 0 // BASE_EN mmctx_base_disabled: or $r14 $r14 bra e #mmctx_multi_disabled - iowr I[$r8 + 0x200] $r14 // MMCTX_MULTI_STRIDE - iowr I[$r8 + 0x300] $r15 // MMCTX_MULTI_MASK + nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE, 0, $r14) + nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_MASK, 0, $r15) bset $r9 1 // MULTI_EN mmctx_multi_disabled: - add b32 $r8 0x100 xbit $r11 $r10 0 shl b32 $r11 16 // DIR @@ -231,20 +202,20 @@ mmctx_xfer: xbit $r14 $r10 1 shl b32 $r14 17 or $r11 $r14 // START_TRIGGER - iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL + nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11) // loop over the mmio list, and send requests to the hw mmctx_exec_loop: // wait for space in mmctx queue mmctx_wait_free: - iord $r14 I[$r8 + 0x000] // MMCTX_CTRL + nv_iord($r14, NV_PGRAPH_FECS_MMCTX_CTRL, 0) and $r14 0x1f bra e #mmctx_wait_free // queue up an entry ld b32 $r14 D[$r12] or $r14 $r9 - iowr I[$r8 + 0x300] $r14 + nv_iowr(NV_PGRAPH_FECS_MMCTX_QUEUE, 0, $r14) add b32 $r12 4 cmpu b32 $r12 $r13 bra ne #mmctx_exec_loop @@ -253,22 +224,22 @@ mmctx_xfer: bra ne #mmctx_stop // wait for queue to empty mmctx_fini_wait: - iord $r11 I[$r8 + 0x000] // MMCTX_CTRL + nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0) and $r11 0x1f cmpu b32 $r11 0x10 bra ne #mmctx_fini_wait - mov $r10 2 // DONE_MMCTX - call #wait_donez + mov $r10 5 // DONE_MMCTX + call(wait_donez) bra #mmctx_done mmctx_stop: xbit $r11 $r10 0 shl b32 $r11 16 // DIR bset $r11 12 // QLIMIT = 0x10 bset $r11 18 // STOP_TRIGGER - iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL + nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11) mmctx_stop_wait: // wait for STOP_TRIGGER to clear - iord $r11 I[$r8 + 0x000] // MMCTX_CTRL + nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0) xbit $r11 $r11 18 bra ne #mmctx_stop_wait mmctx_done: @@ -280,28 +251,24 @@ mmctx_xfer: strand_wait: push $r10 mov $r10 2 - call #wait_donez + call(wait_donez) pop $r10 ret // unknown - call before issuing strand commands // strand_pre: - mov $r8 0x4afc - sethi $r8 0x20000 - mov $r9 0xc - iowr I[$r8] $r9 - call #strand_wait + mov $r9 NV_PGRAPH_FECS_STRAND_CMD_ENABLE + nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9) + call(strand_wait) ret // unknown - call after issuing strand commands // strand_post: - mov $r8 0x4afc - sethi $r8 0x20000 - mov $r9 0xd - iowr I[$r8] $r9 - call #strand_wait + mov $r9 NV_PGRAPH_FECS_STRAND_CMD_DISABLE + nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9) + call(strand_wait) ret // Selects strand set?! @@ -309,18 +276,14 @@ strand_post: // In: $r14 id // strand_set: - mov $r10 0x4ffc - sethi $r10 0x20000 - sub b32 $r11 $r10 0x500 mov $r12 0xf - iowr I[$r10 + 0x000] $r12 // 0x93c = 0xf - mov $r12 0xb - iowr I[$r11 + 0x000] $r12 // 0x928 = 0xb - call #strand_wait - iowr I[$r10 + 0x000] $r14 // 0x93c = <id> - mov $r12 0xa - iowr I[$r11 + 0x000] $r12 // 0x928 = 0xa - call #strand_wait + nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r12) + mov $r12 NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER + nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12) + nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r14) + mov $r12 NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER + nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12) + call(strand_wait) ret // Initialise strand context data @@ -332,30 +295,27 @@ strand_set: // strand_ctx_init: trace_set(T_STRINIT) - call #strand_pre + call(strand_pre) mov $r14 3 - call #strand_set - mov $r10 0x46fc - sethi $r10 0x20000 - add b32 $r11 $r10 0x400 - iowr I[$r10 + 0x100] $r0 // STRAND_FIRST_GENE = 0 - mov $r12 1 - iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_FIRST_GENE - call #strand_wait + call(strand_set) + + clear b32 $r12 + nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r12) + mov $r12 NV_PGRAPH_FECS_STRAND_CMD_SEEK + nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12) + call(strand_wait) sub b32 $r12 $r0 1 - iowr I[$r10 + 0x000] $r12 // STRAND_GENE_CNT = 0xffffffff - mov $r12 2 - iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_GENE_CNT - call #strand_wait - call #strand_post + nv_iowr(NV_PGRAPH_FECS_STRAND_DATA, 0x3f, $r12) + mov $r12 NV_PGRAPH_FECS_STRAND_CMD_GET_INFO + nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12) + call(strand_wait) + call(strand_post) // read the size of each strand, poke the context offset of // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry // about it later then. - mov $r8 0x880 - shl b32 $r8 6 - iord $r9 I[$r8 + 0x000] // STRANDS - add b32 $r8 0x2200 + nv_mkio($r8, NV_PGRAPH_FECS_STRAND_SAVE_SWBASE, 0x00) + nv_iord($r9, NV_PGRAPH_FECS_STRANDS_CNT, 0x00) shr b32 $r14 $r15 8 ctx_init_strand_loop: iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc index 5547c1b3f4f..7445f12b1d9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc @@ -54,16 +54,13 @@ mmio_list_base: #ifdef INCLUDE_CODE // reports an exception to the host // -// In: $r15 error code (see nvc0.fuc) +// In: $r15 error code (see os.h) // error: push $r14 - mov $r14 -0x67ec // 0x9814 - sethi $r14 0x400000 - call #nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code - add b32 $r14 0x41c + nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15) mov $r15 1 - call #nv_wr32 // HUB_CTXCTL_INTR_UP_SET + nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15) pop $r14 ret @@ -81,49 +78,48 @@ error: // init: clear b32 $r0 - mov $sp $r0 + + // setup stack + nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0) + extr $r1 $r1 9:17 + shl b32 $r1 8 + mov $sp $r1 // enable fifo access - mov $r1 0x1200 - mov $r2 2 - iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE + mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO + nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2) // setup i0 handler, and route all interrupts to it mov $r1 #ih mov $iv0 $r1 - mov $r1 0x400 - iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH + nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0) // enable fifo interrupt - mov $r2 4 - iowr I[$r1 + 0x000] $r2 // INTR_EN_SET + mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO + nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2) // enable interrupts bset $flags ie0 // figure out which GPC we are, and how many TPCs we have - mov $r1 0x608 - shl b32 $r1 6 - iord $r2 I[$r1 + 0x000] // UNITS + nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0) mov $r3 1 and $r2 0x1f shl b32 $r3 $r2 sub b32 $r3 1 st b32 D[$r0 + #tpc_count] $r2 st b32 D[$r0 + #tpc_mask] $r3 - add b32 $r1 0x400 - iord $r2 I[$r1 + 0x000] // MYINDEX + nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0) st b32 D[$r0 + #gpc_id] $r2 #if NV_PGRAPH_GPCX_UNK__SIZE > 0 // figure out which, and how many, UNKs are actually present - mov $r14 0x0c30 - sethi $r14 0x500000 + imm32($r14, 0x500c30) clear b32 $r2 clear b32 $r3 clear b32 $r4 init_unk_loop: - call #nv_rd32 + call(nv_rd32) cmp b32 $r15 0 bra z #init_unk_next mov $r15 1 @@ -146,23 +142,21 @@ init: // set mmctx base addresses now so we don't have to do it later, // they don't currently ever change - mov $r4 0x700 - shl b32 $r4 6 shr b32 $r5 $r2 8 - iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE - iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE + nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5) + nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5) // calculate GPC mmio context size ld b32 $r14 D[$r0 + #gpc_mmio_list_head] ld b32 $r15 D[$r0 + #gpc_mmio_list_tail] - call #mmctx_size + call(mmctx_size) add b32 $r2 $r15 add b32 $r3 $r15 // calculate per-TPC mmio context size ld b32 $r14 D[$r0 + #tpc_mmio_list_head] ld b32 $r15 D[$r0 + #tpc_mmio_list_tail] - call #mmctx_size + call(mmctx_size) ld b32 $r14 D[$r0 + #tpc_count] mulu $r14 $r15 add b32 $r2 $r14 @@ -172,7 +166,7 @@ init: // calculate per-UNK mmio context size ld b32 $r14 D[$r0 + #unk_mmio_list_head] ld b32 $r15 D[$r0 + #unk_mmio_list_tail] - call #mmctx_size + call(mmctx_size) ld b32 $r14 D[$r0 + #unk_count] mulu $r14 $r15 add b32 $r2 $r14 @@ -180,9 +174,8 @@ init: #endif // round up base/size to 256 byte boundary (for strand SWBASE) - add b32 $r4 0x1300 shr b32 $r3 2 - iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!? + nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?! shr b32 $r2 8 shr b32 $r3 6 add b32 $r2 1 @@ -192,7 +185,7 @@ init: // calculate size of strand context data mov b32 $r15 $r2 - call #strand_ctx_init + call(strand_ctx_init) add b32 $r3 $r15 // save context size, and tell HUB we're done @@ -208,7 +201,7 @@ main: bset $flags $p0 sleep $p0 mov $r13 #cmd_queue - call #queue_get + call(queue_get) bra $p1 #main // 0x0000-0x0003 are all context transfers @@ -224,13 +217,13 @@ main: or $r1 $r14 mov $flags $r1 // transfer context data - call #ctx_xfer + call(ctx_xfer) bra #main main_not_ctx_xfer: shl b32 $r15 $r14 16 or $r15 E_BAD_COMMAND - call #error + call(error) bra #main // interrupt handler @@ -247,22 +240,20 @@ ih: clear b32 $r0 // incoming fifo command? - iord $r10 I[$r0 + 0x200] // INTR - and $r11 $r10 0x00000004 + nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0) + and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO bra e #ih_no_fifo // queue incoming fifo command for later processing - mov $r11 0x1900 mov $r13 #cmd_queue - iord $r14 I[$r11 + 0x100] // FIFO_CMD - iord $r15 I[$r11 + 0x000] // FIFO_DATA - call #queue_put - add b32 $r11 0x400 + nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0) + nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0) + call(queue_put) mov $r14 1 - iowr I[$r11 + 0x000] $r14 // FIFO_ACK + nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14) // ack, and wake up main() ih_no_fifo: - iowr I[$r0 + 0x100] $r10 // INTR_ACK + nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10) pop $r15 pop $r14 @@ -283,9 +274,7 @@ hub_barrier_done: mov $r15 1 ld b32 $r14 D[$r0 + #gpc_id] shl b32 $r15 $r14 - mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET - sethi $r14 0x400000 - call #nv_wr32 + nv_wr32(0x409418, $r15) // 0x409418 - HUB_BAR_SET ret // Disables various things, waits a bit, and re-enables them.. @@ -295,16 +284,15 @@ hub_barrier_done: // funny things happen. // ctx_redswitch: - mov $r14 0x614 - shl b32 $r14 6 - mov $r15 0x020 - iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER - mov $r15 8 + mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER + nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15) + mov $r14 8 ctx_redswitch_delay: - sub b32 $r15 1 + sub b32 $r14 1 bra ne #ctx_redswitch_delay - mov $r15 0xa20 - iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER + or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11 + or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE + nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15) ret // Transfer GPC context data between GPU and storage area @@ -317,46 +305,37 @@ ctx_redswitch: // ctx_xfer: // set context base address - mov $r1 0xa04 - shl b32 $r1 6 - iowr I[$r1 + 0x000] $r15// MEM_BASE + nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15) bra not $p1 #ctx_xfer_not_load - call #ctx_redswitch + call(ctx_redswitch) ctx_xfer_not_load: // strands - mov $r1 0x4afc - sethi $r1 0x20000 - mov $r2 0xc - iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c - call #strand_wait - mov $r2 0x47fc - sethi $r2 0x20000 - iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 - xbit $r2 $flags $p1 - add b32 $r2 3 - iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) + call(strand_pre) + clear b32 $r2 + nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2) + xbit $r2 $flags $p1 // SAVE/LOAD + add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE + nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2) // mmio context xbit $r10 $flags $p1 // direction or $r10 2 // first - mov $r11 0x0000 - sethi $r11 0x500000 + imm32($r11,0x500000) ld b32 $r12 D[$r0 + #gpc_id] shl b32 $r12 15 add b32 $r11 $r12 // base = NV_PGRAPH_GPCn ld b32 $r12 D[$r0 + #gpc_mmio_list_head] ld b32 $r13 D[$r0 + #gpc_mmio_list_tail] mov $r14 0 // not multi - call #mmctx_xfer + call(mmctx_xfer) // per-TPC mmio context xbit $r10 $flags $p1 // direction #if !NV_PGRAPH_GPCX_UNK__SIZE or $r10 4 // last #endif - mov $r11 0x4000 - sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0 + imm32($r11, 0x504000) ld b32 $r12 D[$r0 + #gpc_id] shl b32 $r12 15 add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0 @@ -364,14 +343,13 @@ ctx_xfer: ld b32 $r13 D[$r0 + #tpc_mmio_list_tail] ld b32 $r15 D[$r0 + #tpc_mask] mov $r14 0x800 // stride = 0x800 - call #mmctx_xfer + call(mmctx_xfer) #if NV_PGRAPH_GPCX_UNK__SIZE > 0 // per-UNK mmio context xbit $r10 $flags $p1 // direction or $r10 4 // last - mov $r11 0x3000 - sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_UNK0 + imm32($r11, 0x503000) ld b32 $r12 D[$r0 + #gpc_id] shl b32 $r12 15 add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_UNK0 @@ -379,11 +357,11 @@ ctx_xfer: ld b32 $r13 D[$r0 + #unk_mmio_list_tail] ld b32 $r15 D[$r0 + #unk_mask] mov $r14 0x200 // stride = 0x200 - call #mmctx_xfer + call(mmctx_xfer) #endif // wait for strands to finish - call #strand_wait + call(strand_wait) // if load, or a save without a load following, do some // unknown stuff that's done after finishing a block of @@ -391,14 +369,10 @@ ctx_xfer: bra $p1 #ctx_xfer_post bra not $p2 #ctx_xfer_done ctx_xfer_post: - mov $r1 0x4afc - sethi $r1 0x20000 - mov $r2 0xd - iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d - call #strand_wait + call(strand_post) // mark completion in HUB's barrier ctx_xfer_done: - call #hub_barrier_done + call(hub_barrier_done) ret #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 new file mode 100644 index 00000000000..e730603891d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 @@ -0,0 +1,42 @@ +/* + * 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> + */ + +#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000002 + +#define CHIPSET GK208 +#include "macros.fuc" + +.section #gm107_grgpc_data +#define INCLUDE_DATA +#include "com.fuc" +#include "gpc.fuc" +#undef INCLUDE_DATA + +.section #gm107_grgpc_code +#define INCLUDE_CODE +bra #init +#include "com.fuc" +#include "gpc.fuc" +.align 256 +#undef INCLUDE_CODE diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h new file mode 100644 index 00000000000..6d53b67dd3c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h @@ -0,0 +1,473 @@ +uint32_t gm107_grgpc_data[] = { +/* 0x0000: gpc_mmio_list_head */ + 0x0000006c, +/* 0x0004: gpc_mmio_list_tail */ +/* 0x0004: tpc_mmio_list_head */ + 0x0000006c, +/* 0x0008: tpc_mmio_list_tail */ +/* 0x0008: unk_mmio_list_head */ + 0x0000006c, +/* 0x000c: unk_mmio_list_tail */ + 0x0000006c, +/* 0x0010: gpc_id */ + 0x00000000, +/* 0x0014: tpc_count */ + 0x00000000, +/* 0x0018: tpc_mask */ + 0x00000000, +/* 0x001c: unk_count */ + 0x00000000, +/* 0x0020: unk_mask */ + 0x00000000, +/* 0x0024: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +uint32_t gm107_grgpc_code[] = { + 0x03140ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0xf489a408, + 0x020f0b1b, + 0x0002f87e, +/* 0x001a: queue_put_next */ + 0x98c400f8, + 0x0384b607, + 0xb6008dbb, + 0x8eb50880, + 0x018fb500, + 0xf00190b6, + 0xd9b50f94, +/* 0x0037: queue_get */ + 0xf400f801, + 0xd8980131, + 0x01d99800, + 0x0bf489a4, + 0x0789c421, + 0xbb0394b6, + 0x90b6009d, + 0x009e9808, + 0xb6019f98, + 0x84f00180, + 0x00d8b50f, +/* 0x0063: queue_get_done */ + 0xf80132f4, +/* 0x0065: nv_rd32 */ + 0xf0ecb200, + 0x00801fc9, + 0x0cf601ca, +/* 0x0073: nv_rd32_wait */ + 0x8c04bd00, + 0xcf01ca00, + 0xccc800cc, + 0xf61bf41f, + 0xec7e060a, + 0x008f0000, + 0xffcf01cb, +/* 0x008f: nv_wr32 */ + 0x8000f800, + 0xf601cc00, + 0x04bd000f, + 0xc9f0ecb2, + 0x1ec9f01f, + 0x01ca0080, + 0xbd000cf6, +/* 0x00a9: nv_wr32_wait */ + 0xca008c04, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f61b, +/* 0x00b8: wait_donez */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x00cf: wait_donez_ne */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf61bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x00ec: wait_doneo */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x0103: wait_doneo_e */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf60bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x0120: mmctx_size */ +/* 0x0122: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0x1bf4efa4, + 0xf89fb2ec, +/* 0x013d: mmctx_xfer */ + 0xf094bd00, + 0x00800199, + 0x09f60237, + 0xbd04bd00, + 0x05bbfd94, + 0x800f0bf4, + 0xf601c400, + 0x04bd000b, +/* 0x015f: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0xc6008018, + 0x000ef601, + 0x008004bd, + 0x0ff601c7, + 0xf004bd00, +/* 0x017a: mmctx_multi_disabled */ + 0xabc80199, + 0x10b4b600, + 0xc80cb9f0, + 0xe4b601ae, + 0x05befd11, + 0x01c50080, + 0xbd000bf6, +/* 0x0195: mmctx_exec_loop */ +/* 0x0195: mmctx_wait_free */ + 0xc5008e04, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f60b, + 0x05e9fd00, + 0x01c80080, + 0xbd000ef6, + 0x04c0b604, + 0x1bf4cda4, + 0x02abc8df, +/* 0x01bf: mmctx_fini_wait */ + 0x8b1c1bf4, + 0xcf01c500, + 0xb4f000bb, + 0x10b4b01f, + 0x0af31bf4, + 0x00b87e05, + 0x250ef400, +/* 0x01d8: mmctx_stop */ + 0xb600abc8, + 0xb9f010b4, + 0x12b9f00c, + 0x01c50080, + 0xbd000bf6, +/* 0x01ed: mmctx_stop_wait */ + 0xc5008b04, + 0x00bbcf01, + 0xf412bbc8, +/* 0x01fa: mmctx_done */ + 0x94bdf61b, + 0x800199f0, + 0xf6021700, + 0x04bd0009, +/* 0x020a: strand_wait */ + 0xa0f900f8, + 0xb87e020a, + 0xa0fc0000, +/* 0x0216: strand_pre */ + 0x0c0900f8, + 0x024afc80, + 0xbd0009f6, + 0x020a7e04, +/* 0x0227: strand_post */ + 0x0900f800, + 0x4afc800d, + 0x0009f602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0238: strand_set */ + 0xfc800f0c, + 0x0cf6024f, + 0x0c04bd00, + 0x4afc800b, + 0x000cf602, + 0xfc8004bd, + 0x0ef6024f, + 0x0c04bd00, + 0x4afc800a, + 0x000cf602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0268: strand_ctx_init */ + 0x99f094bd, + 0x37008003, + 0x0009f602, + 0x167e04bd, + 0x030e0002, + 0x0002387e, + 0xfc80c4bd, + 0x0cf60247, + 0x0c04bd00, + 0x4afc8001, + 0x000cf602, + 0x0a7e04bd, + 0x0c920002, + 0x46fc8001, + 0x000cf602, + 0x020c04bd, + 0x024afc80, + 0xbd000cf6, + 0x020a7e04, + 0x02277e00, + 0x42008800, + 0x20008902, + 0x0099cf02, +/* 0x02c7: ctx_init_strand_loop */ + 0xf608fe95, + 0x8ef6008e, + 0x808acf40, + 0xb606a5b6, + 0xeabb01a0, + 0x0480b600, + 0xf40192b6, + 0xe4b6e81b, + 0xf2efbc08, + 0x99f094bd, + 0x17008003, + 0x0009f602, + 0x00f804bd, +/* 0x02f8: error */ + 0xffb2e0f9, + 0x4098148e, + 0x00008f7e, + 0xffb2010f, + 0x409c1c8e, + 0x00008f7e, + 0x00f8e0fc, +/* 0x0314: init */ + 0x004104bd, + 0x0011cf42, + 0x010911e7, + 0xfe0814b6, + 0x02020014, + 0xf6120040, + 0x04bd0002, + 0xfe047241, + 0x00400010, + 0x0000f607, + 0x040204bd, + 0xf6040040, + 0x04bd0002, + 0x821031f4, + 0xcf018200, + 0x01030022, + 0xbb1f24f0, + 0x32b60432, + 0x0502b501, + 0x820603b5, + 0xcf018600, + 0x02b50022, + 0x0c308e04, + 0xbd24bd50, +/* 0x0377: init_unk_loop */ + 0x7e44bd34, + 0xb0000065, + 0x0bf400f6, + 0xbb010f0e, + 0x4ffd04f2, + 0x0130b605, +/* 0x038c: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf402, +/* 0x0398: init_unk_done */ + 0xb50703b5, + 0x00820804, + 0x22cf0201, + 0x9534bd00, + 0x00800825, + 0x05f601c0, + 0x8004bd00, + 0xf601c100, + 0x04bd0005, + 0x98000e98, + 0x207e010f, + 0x2fbb0001, + 0x003fbb00, + 0x98010e98, + 0x207e020f, + 0x0e980001, + 0x00effd05, + 0xbb002ebb, + 0x0e98003e, + 0x030f9802, + 0x0001207e, + 0xfd070e98, + 0x2ebb00ef, + 0x003ebb00, + 0x800235b6, + 0xf601d300, + 0x04bd0003, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb20834, + 0x0002687e, + 0x80003fbb, + 0xf6020100, + 0x04bd0003, + 0x29f024bd, + 0x3000801f, + 0x0002f602, +/* 0x0436: main */ + 0x31f404bd, + 0x0028f400, + 0x377e240d, + 0x01f40000, + 0x04e4b0f4, + 0xfe1d18f4, + 0x06020181, + 0x12fd20bd, + 0x01e4b604, + 0xfe051efd, + 0x097e0018, + 0x0ef40005, +/* 0x0465: main_not_ctx_xfer */ + 0x10ef94d4, + 0x7e01f5f0, + 0xf40002f8, +/* 0x0472: ih */ + 0x80f9c70e, + 0xf90188fe, + 0xf990f980, + 0xf9b0f9a0, + 0xf9e0f9d0, + 0x4a04bdf0, + 0xaacf0200, + 0x04abc400, + 0x0d1f0bf4, + 0x1a004e24, + 0x4f00eecf, + 0xffcf1900, + 0x00047e00, + 0x40010e00, + 0x0ef61d00, +/* 0x04af: ih_no_fifo */ + 0x4004bd00, + 0x0af60100, + 0xfc04bd00, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x04cf: hub_barrier_done */ + 0x0f01f800, + 0x040e9801, + 0xb204febb, + 0x94188eff, + 0x008f7e40, +/* 0x04e3: ctx_redswitch */ + 0x0f00f800, + 0x85008020, + 0x000ff601, + 0x080e04bd, +/* 0x04f0: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x00800200, + 0x0ff60185, + 0xf804bd00, +/* 0x0509: ctx_xfer */ + 0x81008000, + 0x000ff602, + 0x11f404bd, + 0x04e37e07, +/* 0x0519: ctx_xfer_not_load */ + 0x02167e00, + 0x8024bd00, + 0xf60247fc, + 0x04bd0002, + 0xb6012cf0, + 0xfc800320, + 0x02f6024a, + 0xf004bd00, + 0xa5f001ac, + 0x00008b02, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x010d9800, + 0x3d7e000e, + 0xacf00001, + 0x40008b01, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0x4e060f98, + 0x3d7e0800, + 0xacf00001, + 0x04a5f001, + 0x5030008b, + 0xb6040c98, + 0xbcbb0fc4, + 0x020c9800, + 0x98030d98, + 0x004e080f, + 0x013d7e02, + 0x020a7e00, + 0x0601f400, +/* 0x05a3: ctx_xfer_post */ + 0x7e0712f4, +/* 0x05a7: ctx_xfer_done */ + 0x7e000227, + 0xf80004cf, + 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/engine/graph/fuc/gpcnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5 new file mode 100644 index 00000000000..bd30262d635 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5 @@ -0,0 +1,42 @@ +/* + * 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> + */ + +#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001 + +#define CHIPSET GK208 +#include "macros.fuc" + +.section #nv108_grgpc_data +#define INCLUDE_DATA +#include "com.fuc" +#include "gpc.fuc" +#undef INCLUDE_DATA + +.section #nv108_grgpc_code +#define INCLUDE_CODE +bra #init +#include "com.fuc" +#include "gpc.fuc" +.align 256 +#undef INCLUDE_CODE diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h new file mode 100644 index 00000000000..31922707794 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h @@ -0,0 +1,473 @@ +uint32_t nv108_grgpc_data[] = { +/* 0x0000: gpc_mmio_list_head */ + 0x0000006c, +/* 0x0004: gpc_mmio_list_tail */ +/* 0x0004: tpc_mmio_list_head */ + 0x0000006c, +/* 0x0008: tpc_mmio_list_tail */ +/* 0x0008: unk_mmio_list_head */ + 0x0000006c, +/* 0x000c: unk_mmio_list_tail */ + 0x0000006c, +/* 0x0010: gpc_id */ + 0x00000000, +/* 0x0014: tpc_count */ + 0x00000000, +/* 0x0018: tpc_mask */ + 0x00000000, +/* 0x001c: unk_count */ + 0x00000000, +/* 0x0020: unk_mask */ + 0x00000000, +/* 0x0024: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +uint32_t nv108_grgpc_code[] = { + 0x03140ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0xf489a408, + 0x020f0b1b, + 0x0002f87e, +/* 0x001a: queue_put_next */ + 0x98c400f8, + 0x0384b607, + 0xb6008dbb, + 0x8eb50880, + 0x018fb500, + 0xf00190b6, + 0xd9b50f94, +/* 0x0037: queue_get */ + 0xf400f801, + 0xd8980131, + 0x01d99800, + 0x0bf489a4, + 0x0789c421, + 0xbb0394b6, + 0x90b6009d, + 0x009e9808, + 0xb6019f98, + 0x84f00180, + 0x00d8b50f, +/* 0x0063: queue_get_done */ + 0xf80132f4, +/* 0x0065: nv_rd32 */ + 0xf0ecb200, + 0x00801fc9, + 0x0cf601ca, +/* 0x0073: nv_rd32_wait */ + 0x8c04bd00, + 0xcf01ca00, + 0xccc800cc, + 0xf61bf41f, + 0xec7e060a, + 0x008f0000, + 0xffcf01cb, +/* 0x008f: nv_wr32 */ + 0x8000f800, + 0xf601cc00, + 0x04bd000f, + 0xc9f0ecb2, + 0x1ec9f01f, + 0x01ca0080, + 0xbd000cf6, +/* 0x00a9: nv_wr32_wait */ + 0xca008c04, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f61b, +/* 0x00b8: wait_donez */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x00cf: wait_donez_ne */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf61bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x00ec: wait_doneo */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x0103: wait_doneo_e */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf60bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x0120: mmctx_size */ +/* 0x0122: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0x1bf4efa4, + 0xf89fb2ec, +/* 0x013d: mmctx_xfer */ + 0xf094bd00, + 0x00800199, + 0x09f60237, + 0xbd04bd00, + 0x05bbfd94, + 0x800f0bf4, + 0xf601c400, + 0x04bd000b, +/* 0x015f: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0xc6008018, + 0x000ef601, + 0x008004bd, + 0x0ff601c7, + 0xf004bd00, +/* 0x017a: mmctx_multi_disabled */ + 0xabc80199, + 0x10b4b600, + 0xc80cb9f0, + 0xe4b601ae, + 0x05befd11, + 0x01c50080, + 0xbd000bf6, +/* 0x0195: mmctx_exec_loop */ +/* 0x0195: mmctx_wait_free */ + 0xc5008e04, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f60b, + 0x05e9fd00, + 0x01c80080, + 0xbd000ef6, + 0x04c0b604, + 0x1bf4cda4, + 0x02abc8df, +/* 0x01bf: mmctx_fini_wait */ + 0x8b1c1bf4, + 0xcf01c500, + 0xb4f000bb, + 0x10b4b01f, + 0x0af31bf4, + 0x00b87e05, + 0x250ef400, +/* 0x01d8: mmctx_stop */ + 0xb600abc8, + 0xb9f010b4, + 0x12b9f00c, + 0x01c50080, + 0xbd000bf6, +/* 0x01ed: mmctx_stop_wait */ + 0xc5008b04, + 0x00bbcf01, + 0xf412bbc8, +/* 0x01fa: mmctx_done */ + 0x94bdf61b, + 0x800199f0, + 0xf6021700, + 0x04bd0009, +/* 0x020a: strand_wait */ + 0xa0f900f8, + 0xb87e020a, + 0xa0fc0000, +/* 0x0216: strand_pre */ + 0x0c0900f8, + 0x024afc80, + 0xbd0009f6, + 0x020a7e04, +/* 0x0227: strand_post */ + 0x0900f800, + 0x4afc800d, + 0x0009f602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0238: strand_set */ + 0xfc800f0c, + 0x0cf6024f, + 0x0c04bd00, + 0x4afc800b, + 0x000cf602, + 0xfc8004bd, + 0x0ef6024f, + 0x0c04bd00, + 0x4afc800a, + 0x000cf602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0268: strand_ctx_init */ + 0x99f094bd, + 0x37008003, + 0x0009f602, + 0x167e04bd, + 0x030e0002, + 0x0002387e, + 0xfc80c4bd, + 0x0cf60247, + 0x0c04bd00, + 0x4afc8001, + 0x000cf602, + 0x0a7e04bd, + 0x0c920002, + 0x46fc8001, + 0x000cf602, + 0x020c04bd, + 0x024afc80, + 0xbd000cf6, + 0x020a7e04, + 0x02277e00, + 0x42008800, + 0x20008902, + 0x0099cf02, +/* 0x02c7: ctx_init_strand_loop */ + 0xf608fe95, + 0x8ef6008e, + 0x808acf40, + 0xb606a5b6, + 0xeabb01a0, + 0x0480b600, + 0xf40192b6, + 0xe4b6e81b, + 0xf2efbc08, + 0x99f094bd, + 0x17008003, + 0x0009f602, + 0x00f804bd, +/* 0x02f8: error */ + 0xffb2e0f9, + 0x4098148e, + 0x00008f7e, + 0xffb2010f, + 0x409c1c8e, + 0x00008f7e, + 0x00f8e0fc, +/* 0x0314: init */ + 0x004104bd, + 0x0011cf42, + 0x010911e7, + 0xfe0814b6, + 0x02020014, + 0xf6120040, + 0x04bd0002, + 0xfe047241, + 0x00400010, + 0x0000f607, + 0x040204bd, + 0xf6040040, + 0x04bd0002, + 0x821031f4, + 0xcf018200, + 0x01030022, + 0xbb1f24f0, + 0x32b60432, + 0x0502b501, + 0x820603b5, + 0xcf018600, + 0x02b50022, + 0x0c308e04, + 0xbd24bd50, +/* 0x0377: init_unk_loop */ + 0x7e44bd34, + 0xb0000065, + 0x0bf400f6, + 0xbb010f0e, + 0x4ffd04f2, + 0x0130b605, +/* 0x038c: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf401, +/* 0x0398: init_unk_done */ + 0xb50703b5, + 0x00820804, + 0x22cf0201, + 0x9534bd00, + 0x00800825, + 0x05f601c0, + 0x8004bd00, + 0xf601c100, + 0x04bd0005, + 0x98000e98, + 0x207e010f, + 0x2fbb0001, + 0x003fbb00, + 0x98010e98, + 0x207e020f, + 0x0e980001, + 0x00effd05, + 0xbb002ebb, + 0x0e98003e, + 0x030f9802, + 0x0001207e, + 0xfd070e98, + 0x2ebb00ef, + 0x003ebb00, + 0x800235b6, + 0xf601d300, + 0x04bd0003, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb20834, + 0x0002687e, + 0x80003fbb, + 0xf6020100, + 0x04bd0003, + 0x29f024bd, + 0x3000801f, + 0x0002f602, +/* 0x0436: main */ + 0x31f404bd, + 0x0028f400, + 0x377e240d, + 0x01f40000, + 0x04e4b0f4, + 0xfe1d18f4, + 0x06020181, + 0x12fd20bd, + 0x01e4b604, + 0xfe051efd, + 0x097e0018, + 0x0ef40005, +/* 0x0465: main_not_ctx_xfer */ + 0x10ef94d4, + 0x7e01f5f0, + 0xf40002f8, +/* 0x0472: ih */ + 0x80f9c70e, + 0xf90188fe, + 0xf990f980, + 0xf9b0f9a0, + 0xf9e0f9d0, + 0x4a04bdf0, + 0xaacf0200, + 0x04abc400, + 0x0d1f0bf4, + 0x1a004e24, + 0x4f00eecf, + 0xffcf1900, + 0x00047e00, + 0x40010e00, + 0x0ef61d00, +/* 0x04af: ih_no_fifo */ + 0x4004bd00, + 0x0af60100, + 0xfc04bd00, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x04cf: hub_barrier_done */ + 0x0f01f800, + 0x040e9801, + 0xb204febb, + 0x94188eff, + 0x008f7e40, +/* 0x04e3: ctx_redswitch */ + 0x0f00f800, + 0x85008020, + 0x000ff601, + 0x080e04bd, +/* 0x04f0: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x00800200, + 0x0ff60185, + 0xf804bd00, +/* 0x0509: ctx_xfer */ + 0x81008000, + 0x000ff602, + 0x11f404bd, + 0x04e37e07, +/* 0x0519: ctx_xfer_not_load */ + 0x02167e00, + 0x8024bd00, + 0xf60247fc, + 0x04bd0002, + 0xb6012cf0, + 0xfc800320, + 0x02f6024a, + 0xf004bd00, + 0xa5f001ac, + 0x00008b02, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x010d9800, + 0x3d7e000e, + 0xacf00001, + 0x40008b01, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0x4e060f98, + 0x3d7e0800, + 0xacf00001, + 0x04a5f001, + 0x5030008b, + 0xb6040c98, + 0xbcbb0fc4, + 0x020c9800, + 0x98030d98, + 0x004e080f, + 0x013d7e02, + 0x020a7e00, + 0x0601f400, +/* 0x05a3: ctx_xfer_post */ + 0x7e0712f4, +/* 0x05a7: ctx_xfer_done */ + 0x7e000227, + 0xf80004cf, + 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/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h index f2b0dea8011..325cc7b7b2f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h @@ -37,14 +37,14 @@ uint32_t nvc0_grgpc_data[] = { }; uint32_t nvc0_grgpc_code[] = { - 0x03180ef5, + 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -68,184 +68,214 @@ uint32_t nvc0_grgpc_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f00f00, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f00f, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f00f, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf00f0007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f00f00, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -259,59 +289,75 @@ uint32_t nvc0_grgpc_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0xe0f900f8, - 0x9814e7f1, - 0xf440e3f0, - 0xe0b78d21, - 0xf7f0041c, - 0x8d21f401, - 0x00f8e0fc, -/* 0x0318: init */ - 0x04fe04bd, - 0x0017f100, - 0x0227f012, - 0xf10012d0, - 0xfe042617, - 0x17f10010, - 0x10d00400, - 0x0427f0c0, - 0xf40012d0, - 0x17f11031, - 0x14b60608, - 0x0012cf06, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x10b70603, - 0x12cf0400, + 0xf102ffb9, + 0xf09814e7, + 0x21f440e3, + 0x01f7f09d, + 0xf102ffb9, + 0xf09c1ce7, + 0x21f440e3, + 0xf8e0fc9d, +/* 0x03a1: init */ + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe04e6, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, + 0xd00003f0, + 0x04bd0002, + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, 0x04028000, 0x010027f1, 0xcf0223f0, 0x34bd0022, - 0x070047f1, - 0x950644b6, - 0x45d00825, - 0x4045d000, - 0x98000e98, - 0x21f5010f, - 0x2fbb0147, - 0x003fbb00, - 0x98010e98, - 0x21f5020f, - 0x0e980147, - 0x00effd05, - 0xbb002ebb, - 0x40b7003e, - 0x35b61300, - 0x0043d002, + 0xf1082595, + 0xf0c00007, + 0x05d00103, + 0xf104bd00, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x0235b600, + 0xd30007f1, + 0xd00103f0, + 0x04bd0003, 0xb60825b6, 0x20b60635, 0x0130b601, 0xb60824b6, 0x2fb90834, - 0x7121f502, + 0xd321f502, 0x003fbb02, 0x010007f1, 0xd00203f0, @@ -320,7 +366,7 @@ uint32_t nvc0_grgpc_code[] = { 0x0007f11f, 0x0203f008, 0xbd0002d0, -/* 0x03e9: main */ +/* 0x04a9: main */ 0x0031f404, 0xf00028f4, 0x21f41cd7, @@ -332,74 +378,87 @@ uint32_t nvc0_grgpc_code[] = { 0x01e4b604, 0xfe051efd, 0x21f50018, - 0x0ef404ad, -/* 0x0419: main_not_ctx_xfer */ + 0x0ef4059e, +/* 0x04d9: main_not_ctx_xfer */ 0x10ef94d3, 0xf501f5f0, - 0xf402fe21, -/* 0x0426: ih */ + 0xf4037e21, +/* 0x04e6: ih */ 0x80f9c60e, 0xf90188fe, 0xf990f980, 0xf9b0f9a0, 0xf9e0f9d0, - 0xcf04bdf0, - 0xabc4800a, - 0x1d0bf404, - 0x1900b7f1, - 0xcf1cd7f0, - 0xbfcf40be, - 0x0421f400, - 0x0400b0b7, - 0xd001e7f0, -/* 0x045e: ih_no_fifo */ - 0x0ad000be, - 0xfcf0fc40, - 0xfcd0fce0, - 0xfca0fcb0, - 0xfe80fc90, - 0x80fc0088, - 0xf80032f4, -/* 0x0479: hub_barrier_done */ - 0x01f7f001, - 0xbb040e98, - 0xe7f104fe, - 0xe3f09418, - 0x8d21f440, -/* 0x048e: ctx_redswitch */ - 0xe7f100f8, - 0xe4b60614, - 0x20f7f006, - 0xf000efd0, -/* 0x049e: ctx_redswitch_delay */ - 0xf2b608f7, + 0xf104bdf0, + 0xf00200a7, + 0xaacf00a3, + 0x04abc400, + 0xf02c0bf4, + 0xe7f11cd7, + 0xe3f01a00, + 0x00eecf00, + 0x1900f7f1, + 0xcf00f3f0, + 0x21f400ff, + 0x01e7f004, + 0x1d0007f1, + 0xd00003f0, + 0x04bd000e, +/* 0x0534: ih_no_fifo */ + 0x010007f1, + 0xd00003f0, + 0x04bd000a, + 0xe0fcf0fc, + 0xb0fcd0fc, + 0x90fca0fc, + 0x88fe80fc, + 0xf480fc00, + 0x01f80032, +/* 0x0558: hub_barrier_done */ + 0x9801f7f0, + 0xfebb040e, + 0x02ffb904, + 0x9418e7f1, + 0xf440e3f0, + 0x00f89d21, +/* 0x0570: ctx_redswitch */ + 0xf120f7f0, + 0xf0850007, + 0x0fd00103, + 0xf004bd00, +/* 0x0582: ctx_redswitch_delay */ + 0xe2b608e7, 0xfd1bf401, - 0x0a20f7f1, - 0xf800efd0, -/* 0x04ad: ctx_xfer */ - 0x0417f100, - 0x0614b60a, - 0xf4001fd0, - 0x21f50711, -/* 0x04be: ctx_xfer_not_load */ - 0x17f1048e, - 0x13f04afc, - 0x0c27f002, - 0xf50012d0, - 0xf1021521, - 0xf047fc27, - 0x20d00223, - 0x012cf000, - 0xd00320b6, - 0xacf00012, - 0x02a5f001, - 0xf000b7f0, + 0x0800f5f1, + 0x0200f5f1, + 0x850007f1, + 0xd00103f0, + 0x04bd000f, +/* 0x059e: ctx_xfer */ + 0x07f100f8, + 0x03f08100, + 0x000fd002, + 0x11f404bd, + 0x7021f507, +/* 0x05b1: ctx_xfer_not_load */ + 0x6a21f505, + 0xf124bd02, + 0xf047fc07, + 0x02d00203, + 0xf004bd00, + 0x20b6012c, + 0xfc07f103, + 0x0203f04a, + 0xbd0002d0, + 0x01acf004, + 0xf102a5f0, + 0xf00000b7, 0x0c9850b3, 0x0fc4b604, 0x9800bcbb, 0x0d98000c, 0x00e7f001, - 0x016621f5, + 0x016f21f5, 0xf001acf0, 0xb7f104a5, 0xb3f04000, @@ -409,17 +468,20 @@ uint32_t nvc0_grgpc_code[] = { 0x020d9801, 0xf1060f98, 0xf50800e7, - 0xf5016621, - 0xf4021521, + 0xf5016f21, + 0xf4025e21, 0x12f40601, -/* 0x0535: ctx_xfer_post */ - 0xfc17f114, - 0x0213f04a, - 0xd00d27f0, - 0x21f50012, -/* 0x0546: ctx_xfer_done */ - 0x21f50215, - 0x00f80479, +/* 0x0629: ctx_xfer_post */ + 0x7f21f507, +/* 0x062d: ctx_xfer_done */ + 0x5821f502, + 0x0000f805, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h index dd346c2a162..d1504a4059c 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h @@ -41,14 +41,14 @@ uint32_t nvd7_grgpc_data[] = { }; uint32_t nvd7_grgpc_code[] = { - 0x03180ef5, + 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -72,184 +72,214 @@ uint32_t nvd7_grgpc_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f00f00, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f00f, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f00f, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf00f0007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f00f00, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -263,81 +293,97 @@ uint32_t nvd7_grgpc_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0xe0f900f8, - 0x9814e7f1, - 0xf440e3f0, - 0xe0b78d21, - 0xf7f0041c, - 0x8d21f401, - 0x00f8e0fc, -/* 0x0318: init */ - 0x04fe04bd, - 0x0017f100, - 0x0227f012, - 0xf10012d0, - 0xfe047017, - 0x17f10010, - 0x10d00400, - 0x0427f0c0, - 0xf40012d0, - 0x17f11031, - 0x14b60608, - 0x0012cf06, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x10b70603, - 0x12cf0400, + 0xf102ffb9, + 0xf09814e7, + 0x21f440e3, + 0x01f7f09d, + 0xf102ffb9, + 0xf09c1ce7, + 0x21f440e3, + 0xf8e0fc9d, +/* 0x03a1: init */ + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe0530, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, + 0xd00003f0, + 0x04bd0002, + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, 0x04028000, 0x0c30e7f1, 0xbd50e3f0, 0xbd34bd24, -/* 0x0371: init_unk_loop */ +/* 0x0421: init_unk_loop */ 0x6821f444, 0xf400f6b0, 0xf7f00f0b, 0x04f2bb01, 0xb6054ffd, -/* 0x0386: init_unk_next */ +/* 0x0436: init_unk_next */ 0x20b60130, 0x04e0b601, 0xf40126b0, -/* 0x0392: init_unk_done */ +/* 0x0442: init_unk_done */ 0x0380e21b, 0x08048007, 0x010027f1, 0xcf0223f0, 0x34bd0022, - 0x070047f1, - 0x950644b6, - 0x45d00825, - 0x4045d000, - 0x98000e98, - 0x21f5010f, - 0x2fbb0147, - 0x003fbb00, - 0x98010e98, - 0x21f5020f, - 0x0e980147, - 0x00effd05, - 0xbb002ebb, - 0x0e98003e, - 0x030f9802, - 0x014721f5, - 0xfd070e98, - 0x2ebb00ef, - 0x003ebb00, - 0x130040b7, - 0xd00235b6, - 0x25b60043, + 0xf1082595, + 0xf0c00007, + 0x05d00103, + 0xf104bd00, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x020e9800, + 0xf5030f98, + 0x98015021, + 0xeffd070e, + 0x002ebb00, + 0xb6003ebb, + 0x07f10235, + 0x03f0d300, + 0x0003d001, + 0x25b604bd, 0x0635b608, 0xb60120b6, 0x24b60130, 0x0834b608, 0xf5022fb9, - 0xbb027121, + 0xbb02d321, 0x07f1003f, 0x03f00100, 0x0003d002, @@ -345,7 +391,7 @@ uint32_t nvd7_grgpc_code[] = { 0xf11f29f0, 0xf0080007, 0x02d00203, -/* 0x0433: main */ +/* 0x04f3: main */ 0xf404bd00, 0x28f40031, 0x24d7f000, @@ -357,75 +403,88 @@ uint32_t nvd7_grgpc_code[] = { 0xb60412fd, 0x1efd01e4, 0x0018fe05, - 0x04f721f5, -/* 0x0463: main_not_ctx_xfer */ + 0x05e821f5, +/* 0x0523: main_not_ctx_xfer */ 0x94d30ef4, 0xf5f010ef, - 0xfe21f501, - 0xc60ef402, -/* 0x0470: ih */ + 0x7e21f501, + 0xc60ef403, +/* 0x0530: ih */ 0x88fe80f9, 0xf980f901, 0xf9a0f990, 0xf9d0f9b0, 0xbdf0f9e0, - 0x800acf04, - 0xf404abc4, - 0xb7f11d0b, - 0xd7f01900, - 0x40becf24, - 0xf400bfcf, - 0xb0b70421, - 0xe7f00400, - 0x00bed001, -/* 0x04a8: ih_no_fifo */ - 0xfc400ad0, - 0xfce0fcf0, - 0xfcb0fcd0, - 0xfc90fca0, - 0x0088fe80, - 0x32f480fc, -/* 0x04c3: hub_barrier_done */ - 0xf001f800, - 0x0e9801f7, - 0x04febb04, - 0x9418e7f1, - 0xf440e3f0, - 0x00f88d21, -/* 0x04d8: ctx_redswitch */ - 0x0614e7f1, - 0xf006e4b6, - 0xefd020f7, - 0x08f7f000, -/* 0x04e8: ctx_redswitch_delay */ - 0xf401f2b6, - 0xf7f1fd1b, - 0xefd00a20, -/* 0x04f7: ctx_xfer */ - 0xf100f800, - 0xb60a0417, - 0x1fd00614, - 0x0711f400, - 0x04d821f5, -/* 0x0508: ctx_xfer_not_load */ - 0x4afc17f1, - 0xf00213f0, - 0x12d00c27, - 0x1521f500, - 0xfc27f102, - 0x0223f047, - 0xf00020d0, - 0x20b6012c, - 0x0012d003, - 0xf001acf0, - 0xb7f002a5, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x24d7f02c, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, + 0xf00421f4, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x057e: ih_no_fifo */ + 0x07f104bd, + 0x03f00100, + 0x000ad000, + 0xf0fc04bd, + 0xd0fce0fc, + 0xa0fcb0fc, + 0x80fc90fc, + 0xfc0088fe, + 0x0032f480, +/* 0x05a2: hub_barrier_done */ + 0xf7f001f8, + 0x040e9801, + 0xb904febb, + 0xe7f102ff, + 0xe3f09418, + 0x9d21f440, +/* 0x05ba: ctx_redswitch */ + 0xf7f000f8, + 0x0007f120, + 0x0103f085, + 0xbd000fd0, + 0x08e7f004, +/* 0x05cc: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x07f10200, + 0x03f08500, + 0x000fd001, + 0x00f804bd, +/* 0x05e8: ctx_xfer */ + 0x810007f1, + 0xd00203f0, + 0x04bd000f, + 0xf50711f4, +/* 0x05fb: ctx_xfer_not_load */ + 0xf505ba21, + 0xbd026a21, + 0xfc07f124, + 0x0203f047, + 0xbd0002d0, + 0x012cf004, + 0xf10320b6, + 0xf04afc07, + 0x02d00203, + 0xf004bd00, + 0xa5f001ac, + 0x00b7f102, 0x50b3f000, 0xb6040c98, 0xbcbb0fc4, 0x000c9800, 0xf0010d98, 0x21f500e7, - 0xacf00166, + 0xacf0016f, 0x00b7f101, 0x50b3f040, 0xb6040c98, @@ -434,7 +493,7 @@ uint32_t nvd7_grgpc_code[] = { 0x98020d98, 0xe7f1060f, 0x21f50800, - 0xacf00166, + 0xacf0016f, 0x04a5f001, 0x3000b7f1, 0x9850b3f0, @@ -443,18 +502,21 @@ uint32_t nvd7_grgpc_code[] = { 0x98020c98, 0x0f98030d, 0x00e7f108, - 0x6621f502, - 0x1521f501, + 0x6f21f502, + 0x5e21f501, 0x0601f402, -/* 0x05a3: ctx_xfer_post */ - 0xf11412f4, - 0xf04afc17, - 0x27f00213, - 0x0012d00d, - 0x021521f5, -/* 0x05b4: ctx_xfer_done */ - 0x04c321f5, - 0x000000f8, +/* 0x0697: ctx_xfer_post */ + 0xf50712f4, +/* 0x069b: ctx_xfer_done */ + 0xf5027f21, + 0xf805a221, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h index 7ff5ef6b080..855b220378f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h @@ -41,14 +41,14 @@ uint32_t nve0_grgpc_data[] = { }; uint32_t nve0_grgpc_code[] = { - 0x03180ef5, + 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -72,184 +72,214 @@ uint32_t nve0_grgpc_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f00f00, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f00f, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f00f, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf00f0007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f00f00, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -263,81 +293,97 @@ uint32_t nve0_grgpc_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0xe0f900f8, - 0x9814e7f1, - 0xf440e3f0, - 0xe0b78d21, - 0xf7f0041c, - 0x8d21f401, - 0x00f8e0fc, -/* 0x0318: init */ - 0x04fe04bd, - 0x0017f100, - 0x0227f012, - 0xf10012d0, - 0xfe047017, - 0x17f10010, - 0x10d00400, - 0x0427f0c0, - 0xf40012d0, - 0x17f11031, - 0x14b60608, - 0x0012cf06, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x10b70603, - 0x12cf0400, + 0xf102ffb9, + 0xf09814e7, + 0x21f440e3, + 0x01f7f09d, + 0xf102ffb9, + 0xf09c1ce7, + 0x21f440e3, + 0xf8e0fc9d, +/* 0x03a1: init */ + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe0530, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, + 0xd00003f0, + 0x04bd0002, + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, 0x04028000, 0x0c30e7f1, 0xbd50e3f0, 0xbd34bd24, -/* 0x0371: init_unk_loop */ +/* 0x0421: init_unk_loop */ 0x6821f444, 0xf400f6b0, 0xf7f00f0b, 0x04f2bb01, 0xb6054ffd, -/* 0x0386: init_unk_next */ +/* 0x0436: init_unk_next */ 0x20b60130, 0x04e0b601, 0xf40126b0, -/* 0x0392: init_unk_done */ +/* 0x0442: init_unk_done */ 0x0380e21b, 0x08048007, 0x010027f1, 0xcf0223f0, 0x34bd0022, - 0x070047f1, - 0x950644b6, - 0x45d00825, - 0x4045d000, - 0x98000e98, - 0x21f5010f, - 0x2fbb0147, - 0x003fbb00, - 0x98010e98, - 0x21f5020f, - 0x0e980147, - 0x00effd05, - 0xbb002ebb, - 0x0e98003e, - 0x030f9802, - 0x014721f5, - 0xfd070e98, - 0x2ebb00ef, - 0x003ebb00, - 0x130040b7, - 0xd00235b6, - 0x25b60043, + 0xf1082595, + 0xf0c00007, + 0x05d00103, + 0xf104bd00, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x020e9800, + 0xf5030f98, + 0x98015021, + 0xeffd070e, + 0x002ebb00, + 0xb6003ebb, + 0x07f10235, + 0x03f0d300, + 0x0003d001, + 0x25b604bd, 0x0635b608, 0xb60120b6, 0x24b60130, 0x0834b608, 0xf5022fb9, - 0xbb027121, + 0xbb02d321, 0x07f1003f, 0x03f00100, 0x0003d002, @@ -345,7 +391,7 @@ uint32_t nve0_grgpc_code[] = { 0xf11f29f0, 0xf0080007, 0x02d00203, -/* 0x0433: main */ +/* 0x04f3: main */ 0xf404bd00, 0x28f40031, 0x24d7f000, @@ -357,75 +403,88 @@ uint32_t nve0_grgpc_code[] = { 0xb60412fd, 0x1efd01e4, 0x0018fe05, - 0x04f721f5, -/* 0x0463: main_not_ctx_xfer */ + 0x05e821f5, +/* 0x0523: main_not_ctx_xfer */ 0x94d30ef4, 0xf5f010ef, - 0xfe21f501, - 0xc60ef402, -/* 0x0470: ih */ + 0x7e21f501, + 0xc60ef403, +/* 0x0530: ih */ 0x88fe80f9, 0xf980f901, 0xf9a0f990, 0xf9d0f9b0, 0xbdf0f9e0, - 0x800acf04, - 0xf404abc4, - 0xb7f11d0b, - 0xd7f01900, - 0x40becf24, - 0xf400bfcf, - 0xb0b70421, - 0xe7f00400, - 0x00bed001, -/* 0x04a8: ih_no_fifo */ - 0xfc400ad0, - 0xfce0fcf0, - 0xfcb0fcd0, - 0xfc90fca0, - 0x0088fe80, - 0x32f480fc, -/* 0x04c3: hub_barrier_done */ - 0xf001f800, - 0x0e9801f7, - 0x04febb04, - 0x9418e7f1, - 0xf440e3f0, - 0x00f88d21, -/* 0x04d8: ctx_redswitch */ - 0x0614e7f1, - 0xf006e4b6, - 0xefd020f7, - 0x08f7f000, -/* 0x04e8: ctx_redswitch_delay */ - 0xf401f2b6, - 0xf7f1fd1b, - 0xefd00a20, -/* 0x04f7: ctx_xfer */ - 0xf100f800, - 0xb60a0417, - 0x1fd00614, - 0x0711f400, - 0x04d821f5, -/* 0x0508: ctx_xfer_not_load */ - 0x4afc17f1, - 0xf00213f0, - 0x12d00c27, - 0x1521f500, - 0xfc27f102, - 0x0223f047, - 0xf00020d0, - 0x20b6012c, - 0x0012d003, - 0xf001acf0, - 0xb7f002a5, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x24d7f02c, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, + 0xf00421f4, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x057e: ih_no_fifo */ + 0x07f104bd, + 0x03f00100, + 0x000ad000, + 0xf0fc04bd, + 0xd0fce0fc, + 0xa0fcb0fc, + 0x80fc90fc, + 0xfc0088fe, + 0x0032f480, +/* 0x05a2: hub_barrier_done */ + 0xf7f001f8, + 0x040e9801, + 0xb904febb, + 0xe7f102ff, + 0xe3f09418, + 0x9d21f440, +/* 0x05ba: ctx_redswitch */ + 0xf7f000f8, + 0x0007f120, + 0x0103f085, + 0xbd000fd0, + 0x08e7f004, +/* 0x05cc: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x07f10200, + 0x03f08500, + 0x000fd001, + 0x00f804bd, +/* 0x05e8: ctx_xfer */ + 0x810007f1, + 0xd00203f0, + 0x04bd000f, + 0xf50711f4, +/* 0x05fb: ctx_xfer_not_load */ + 0xf505ba21, + 0xbd026a21, + 0xfc07f124, + 0x0203f047, + 0xbd0002d0, + 0x012cf004, + 0xf10320b6, + 0xf04afc07, + 0x02d00203, + 0xf004bd00, + 0xa5f001ac, + 0x00b7f102, 0x50b3f000, 0xb6040c98, 0xbcbb0fc4, 0x000c9800, 0xf0010d98, 0x21f500e7, - 0xacf00166, + 0xacf0016f, 0x00b7f101, 0x50b3f040, 0xb6040c98, @@ -434,7 +493,7 @@ uint32_t nve0_grgpc_code[] = { 0x98020d98, 0xe7f1060f, 0x21f50800, - 0xacf00166, + 0xacf0016f, 0x04a5f001, 0x3000b7f1, 0x9850b3f0, @@ -443,18 +502,21 @@ uint32_t nve0_grgpc_code[] = { 0x98020c98, 0x0f98030d, 0x00e7f108, - 0x6621f502, - 0x1521f501, + 0x6f21f502, + 0x5e21f501, 0x0601f402, -/* 0x05a3: ctx_xfer_post */ - 0xf11412f4, - 0xf04afc17, - 0x27f00213, - 0x0012d00d, - 0x021521f5, -/* 0x05b4: ctx_xfer_done */ - 0x04c321f5, - 0x000000f8, +/* 0x0697: ctx_xfer_post */ + 0xf50712f4, +/* 0x069b: ctx_xfer_done */ + 0xf5027f21, + 0xf805a221, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h index f870507be88..1b803197d28 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h @@ -41,14 +41,14 @@ uint32_t nvf0_grgpc_data[] = { }; uint32_t nvf0_grgpc_code[] = { - 0x03180ef5, + 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -72,184 +72,214 @@ uint32_t nvf0_grgpc_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f03700, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f037, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f03700, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f037, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf0370007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x370007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f03700, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x370007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -263,81 +293,97 @@ uint32_t nvf0_grgpc_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0xe0f900f8, - 0x9814e7f1, - 0xf440e3f0, - 0xe0b78d21, - 0xf7f0041c, - 0x8d21f401, - 0x00f8e0fc, -/* 0x0318: init */ - 0x04fe04bd, - 0x0017f100, - 0x0227f012, - 0xf10012d0, - 0xfe047017, - 0x17f10010, - 0x10d00400, - 0x0427f0c0, - 0xf40012d0, - 0x17f11031, - 0x14b60608, - 0x0012cf06, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x10b70603, - 0x12cf0400, + 0xf102ffb9, + 0xf09814e7, + 0x21f440e3, + 0x01f7f09d, + 0xf102ffb9, + 0xf09c1ce7, + 0x21f440e3, + 0xf8e0fc9d, +/* 0x03a1: init */ + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe0530, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, + 0xd00003f0, + 0x04bd0002, + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, 0x04028000, 0x0c30e7f1, 0xbd50e3f0, 0xbd34bd24, -/* 0x0371: init_unk_loop */ +/* 0x0421: init_unk_loop */ 0x6821f444, 0xf400f6b0, 0xf7f00f0b, 0x04f2bb01, 0xb6054ffd, -/* 0x0386: init_unk_next */ +/* 0x0436: init_unk_next */ 0x20b60130, 0x04e0b601, 0xf40226b0, -/* 0x0392: init_unk_done */ +/* 0x0442: init_unk_done */ 0x0380e21b, 0x08048007, 0x010027f1, 0xcf0223f0, 0x34bd0022, - 0x070047f1, - 0x950644b6, - 0x45d00825, - 0x4045d000, - 0x98000e98, - 0x21f5010f, - 0x2fbb0147, - 0x003fbb00, - 0x98010e98, - 0x21f5020f, - 0x0e980147, - 0x00effd05, - 0xbb002ebb, - 0x0e98003e, - 0x030f9802, - 0x014721f5, - 0xfd070e98, - 0x2ebb00ef, - 0x003ebb00, - 0x130040b7, - 0xd00235b6, - 0x25b60043, + 0xf1082595, + 0xf0c00007, + 0x05d00103, + 0xf104bd00, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x020e9800, + 0xf5030f98, + 0x98015021, + 0xeffd070e, + 0x002ebb00, + 0xb6003ebb, + 0x07f10235, + 0x03f0d300, + 0x0003d001, + 0x25b604bd, 0x0635b608, 0xb60120b6, 0x24b60130, 0x0834b608, 0xf5022fb9, - 0xbb027121, + 0xbb02d321, 0x07f1003f, 0x03f00100, 0x0003d002, @@ -345,7 +391,7 @@ uint32_t nvf0_grgpc_code[] = { 0xf11f29f0, 0xf0300007, 0x02d00203, -/* 0x0433: main */ +/* 0x04f3: main */ 0xf404bd00, 0x28f40031, 0x24d7f000, @@ -357,75 +403,88 @@ uint32_t nvf0_grgpc_code[] = { 0xb60412fd, 0x1efd01e4, 0x0018fe05, - 0x04f721f5, -/* 0x0463: main_not_ctx_xfer */ + 0x05e821f5, +/* 0x0523: main_not_ctx_xfer */ 0x94d30ef4, 0xf5f010ef, - 0xfe21f501, - 0xc60ef402, -/* 0x0470: ih */ + 0x7e21f501, + 0xc60ef403, +/* 0x0530: ih */ 0x88fe80f9, 0xf980f901, 0xf9a0f990, 0xf9d0f9b0, 0xbdf0f9e0, - 0x800acf04, - 0xf404abc4, - 0xb7f11d0b, - 0xd7f01900, - 0x40becf24, - 0xf400bfcf, - 0xb0b70421, - 0xe7f00400, - 0x00bed001, -/* 0x04a8: ih_no_fifo */ - 0xfc400ad0, - 0xfce0fcf0, - 0xfcb0fcd0, - 0xfc90fca0, - 0x0088fe80, - 0x32f480fc, -/* 0x04c3: hub_barrier_done */ - 0xf001f800, - 0x0e9801f7, - 0x04febb04, - 0x9418e7f1, - 0xf440e3f0, - 0x00f88d21, -/* 0x04d8: ctx_redswitch */ - 0x0614e7f1, - 0xf006e4b6, - 0xefd020f7, - 0x08f7f000, -/* 0x04e8: ctx_redswitch_delay */ - 0xf401f2b6, - 0xf7f1fd1b, - 0xefd00a20, -/* 0x04f7: ctx_xfer */ - 0xf100f800, - 0xb60a0417, - 0x1fd00614, - 0x0711f400, - 0x04d821f5, -/* 0x0508: ctx_xfer_not_load */ - 0x4afc17f1, - 0xf00213f0, - 0x12d00c27, - 0x1521f500, - 0xfc27f102, - 0x0223f047, - 0xf00020d0, - 0x20b6012c, - 0x0012d003, - 0xf001acf0, - 0xb7f002a5, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x24d7f02c, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, + 0xf00421f4, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x057e: ih_no_fifo */ + 0x07f104bd, + 0x03f00100, + 0x000ad000, + 0xf0fc04bd, + 0xd0fce0fc, + 0xa0fcb0fc, + 0x80fc90fc, + 0xfc0088fe, + 0x0032f480, +/* 0x05a2: hub_barrier_done */ + 0xf7f001f8, + 0x040e9801, + 0xb904febb, + 0xe7f102ff, + 0xe3f09418, + 0x9d21f440, +/* 0x05ba: ctx_redswitch */ + 0xf7f000f8, + 0x0007f120, + 0x0103f085, + 0xbd000fd0, + 0x08e7f004, +/* 0x05cc: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x07f10200, + 0x03f08500, + 0x000fd001, + 0x00f804bd, +/* 0x05e8: ctx_xfer */ + 0x810007f1, + 0xd00203f0, + 0x04bd000f, + 0xf50711f4, +/* 0x05fb: ctx_xfer_not_load */ + 0xf505ba21, + 0xbd026a21, + 0xfc07f124, + 0x0203f047, + 0xbd0002d0, + 0x012cf004, + 0xf10320b6, + 0xf04afc07, + 0x02d00203, + 0xf004bd00, + 0xa5f001ac, + 0x00b7f102, 0x50b3f000, 0xb6040c98, 0xbcbb0fc4, 0x000c9800, 0xf0010d98, 0x21f500e7, - 0xacf00166, + 0xacf0016f, 0x00b7f101, 0x50b3f040, 0xb6040c98, @@ -434,7 +493,7 @@ uint32_t nvf0_grgpc_code[] = { 0x98020d98, 0xe7f1060f, 0x21f50800, - 0xacf00166, + 0xacf0016f, 0x04a5f001, 0x3000b7f1, 0x9850b3f0, @@ -443,18 +502,21 @@ uint32_t nvf0_grgpc_code[] = { 0x98020c98, 0x0f98030d, 0x00e7f108, - 0x6621f502, - 0x1521f501, + 0x6f21f502, + 0x5e21f501, 0x0601f402, -/* 0x05a3: ctx_xfer_post */ - 0xf11412f4, - 0xf04afc17, - 0x27f00213, - 0x0012d00d, - 0x021521f5, -/* 0x05b4: ctx_xfer_done */ - 0x04c321f5, - 0x000000f8, +/* 0x0697: ctx_xfer_post */ + 0xf50712f4, +/* 0x069b: ctx_xfer_done */ + 0xf5027f21, + 0xf805a221, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc index b82d2ae8991..b4ad18bf5a2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc @@ -49,7 +49,7 @@ hub_mmio_list_next: #ifdef INCLUDE_CODE // reports an exception to the host // -// In: $r15 error code (see nvc0.fuc) +// In: $r15 error code (see os.h) // error: nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15) @@ -68,60 +68,57 @@ error: // init: clear b32 $r0 - mov $sp $r0 mov $xdbase $r0 + // setup stack + nv_iord($r1, NV_PGRAPH_FECS_CAPS, 0) + extr $r1 $r1 9:17 + shl b32 $r1 8 + mov $sp $r1 + // enable fifo access - mov $r1 0x1200 - mov $r2 2 - iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE + mov $r2 NV_PGRAPH_FECS_ACCESS_FIFO + nv_iowr(NV_PGRAPH_FECS_ACCESS, 0, $r2) // setup i0 handler, and route all interrupts to it mov $r1 #ih mov $iv0 $r1 - mov $r1 0x400 - iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH - // route HUB_CHANNEL_SWITCH to fuc interrupt 8 - mov $r3 0x404 - shl b32 $r3 6 - mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8 - iowr I[$r3 + 0x000] $r2 + clear b32 $r2 + nv_iowr(NV_PGRAPH_FECS_INTR_ROUTE, 0, $r2) + + // route HUB_CHSW_PULSE to fuc interrupt 8 + mov $r2 0x2003 // { HUB_CHSW_PULSE, ZERO } -> intr 8 + nv_iowr(NV_PGRAPH_FECS_IROUTE, 0, $r2) // not sure what these are, route them because NVIDIA does, and // the IRQ handler will signal the host if we ever get one.. we // may find out if/why we need to handle these if so.. // - mov $r2 0x2004 - iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9 - mov $r2 0x200b - iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10 - mov $r2 0x200c - iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15 + mov $r2 0x2004 // { 0x04, ZERO } -> intr 9 + nv_iowr(NV_PGRAPH_FECS_IROUTE, 1, $r2) + mov $r2 0x200b // { HUB_FIRMWARE_MTHD, ZERO } -> intr 10 + nv_iowr(NV_PGRAPH_FECS_IROUTE, 2, $r2) + mov $r2 0x200c // { 0x0c, ZERO } -> intr 15 + nv_iowr(NV_PGRAPH_FECS_IROUTE, 7, $r2) // enable all INTR_UP interrupts - mov $r2 0xc24 - shl b32 $r2 6 - not b32 $r3 $r0 - iowr I[$r2] $r3 + sub b32 $r3 $r0 1 + nv_iowr(NV_PGRAPH_FECS_INTR_UP_EN, 0, $r3) - // enable fifo, ctxsw, 9, 10, 15 interrupts - mov $r2 -0x78fc // 0x8704 - sethi $r2 0 - iowr I[$r1 + 0x000] $r2 // INTR_EN_SET + // enable fifo, ctxsw, 9, fwmthd, 15 interrupts + imm32($r2, 0x8704) + nv_iowr(NV_PGRAPH_FECS_INTR_EN_SET, 0, $r2) // fifo level triggered, rest edge - sub b32 $r1 0x100 - mov $r2 4 - iowr I[$r1] $r2 + mov $r2 NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL + nv_iowr(NV_PGRAPH_FECS_INTR_MODE, 0, $r2) // enable interrupts bset $flags ie0 // fetch enabled GPC/ROP counts - mov $r14 -0x69fc // 0x409604 - sethi $r14 0x400000 - call #nv_rd32 + nv_rd32($r14, 0x409604) extr $r1 $r15 16:20 st b32 D[$r0 + #rop_count] $r1 and $r15 0x1f @@ -131,37 +128,40 @@ init: mov $r1 1 shl b32 $r1 $r15 sub b32 $r1 1 - mov $r2 0x40c - shl b32 $r2 6 - iowr I[$r2 + 0x000] $r1 - iowr I[$r2 + 0x100] $r1 + nv_iowr(NV_PGRAPH_FECS_BAR_MASK0, 0, $r1) + nv_iowr(NV_PGRAPH_FECS_BAR_MASK1, 0, $r1) // context size calculation, reserve first 256 bytes for use by fuc mov $r1 256 + // + mov $r15 2 + call(ctx_4170s) + call(ctx_4170w) + mov $r15 0x10 + call(ctx_86c) + // calculate size of mmio context data ld b32 $r14 D[$r0 + #hub_mmio_list_head] ld b32 $r15 D[$r0 + #hub_mmio_list_tail] - call #mmctx_size + call(mmctx_size) // set mmctx base addresses now so we don't have to do it later, // they don't (currently) ever change - mov $r3 0x700 - shl b32 $r3 6 shr b32 $r4 $r1 8 - iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE - iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE + nv_iowr(NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE, 0, $r4) + nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE, 0, $r4) add b32 $r3 0x1300 add b32 $r1 $r15 shr b32 $r15 2 - iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!? + nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_COUNT, 0, $r15) // wtf?? // strands, base offset needs to be aligned to 256 bytes shr b32 $r1 8 add b32 $r1 1 shl b32 $r1 8 mov b32 $r15 $r1 - call #strand_ctx_init + call(strand_ctx_init) add b32 $r1 $r15 // initialise each GPC in sequence by passing in the offset of its @@ -173,30 +173,29 @@ init: // in GPCn_CC_SCRATCH[1] // ld b32 $r3 D[$r0 + #gpc_count] - mov $r4 0x2000 - sethi $r4 0x500000 + imm32($r4, 0x502000) init_gpc: // setup, and start GPC ucode running add b32 $r14 $r4 0x804 mov b32 $r15 $r1 - call #nv_wr32 // CC_SCRATCH[1] = ctx offset + call(nv_wr32) // CC_SCRATCH[1] = ctx offset add b32 $r14 $r4 0x10c clear b32 $r15 - call #nv_wr32 + call(nv_wr32) add b32 $r14 $r4 0x104 - call #nv_wr32 // ENTRY + call(nv_wr32) // ENTRY add b32 $r14 $r4 0x100 mov $r15 2 // CTRL_START_TRIGGER - call #nv_wr32 // CTRL + call(nv_wr32) // CTRL // wait for it to complete, and adjust context size add b32 $r14 $r4 0x800 init_gpc_wait: - call #nv_rd32 + call(nv_rd32) xbit $r15 $r15 31 bra e #init_gpc_wait add b32 $r14 $r4 0x804 - call #nv_rd32 + call(nv_rd32) add b32 $r1 $r15 // next! @@ -204,6 +203,12 @@ init: sub b32 $r3 1 bra ne #init_gpc + // + mov $r15 0 + call(ctx_86c) + mov $r15 0 + call(ctx_4170s) + // save context size, and tell host we're ready nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1) clear b32 $r1 @@ -218,17 +223,15 @@ main: bset $flags $p0 sleep $p0 mov $r13 #cmd_queue - call #queue_get + call(queue_get) bra $p1 #main // context switch, requested by GPU? cmpu b32 $r14 0x4001 bra ne #main_not_ctx_switch trace_set(T_AUTO) - mov $r1 0xb00 - shl b32 $r1 6 - iord $r2 I[$r1 + 0x100] // CHAN_NEXT - iord $r1 I[$r1 + 0x000] // CHAN_CUR + nv_iord($r1, NV_PGRAPH_FECS_CHAN_ADDR, 0) + nv_iord($r2, NV_PGRAPH_FECS_CHAN_NEXT, 0) xbit $r3 $r1 31 bra e #chsw_no_prev @@ -239,12 +242,12 @@ main: trace_set(T_SAVE) bclr $flags $p1 bset $flags $p2 - call #ctx_xfer + call(ctx_xfer) trace_clr(T_SAVE); pop $r2 trace_set(T_LOAD); bset $flags $p1 - call #ctx_xfer + call(ctx_xfer) trace_clr(T_LOAD); bra #chsw_done chsw_prev_no_next: @@ -252,25 +255,21 @@ main: mov b32 $r2 $r1 bclr $flags $p1 bclr $flags $p2 - call #ctx_xfer + call(ctx_xfer) pop $r2 - mov $r1 0xb00 - shl b32 $r1 6 - iowr I[$r1] $r2 + nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2) bra #chsw_done chsw_no_prev: xbit $r3 $r2 31 bra e #chsw_done bset $flags $p1 bclr $flags $p2 - call #ctx_xfer + call(ctx_xfer) // ack the context switch request chsw_done: - mov $r1 0xb0c - shl b32 $r1 6 - mov $r2 1 - iowr I[$r1 + 0x000] $r2 // 0x409b0c + mov $r2 NV_PGRAPH_FECS_CHSW_ACK + nv_iowr(NV_PGRAPH_FECS_CHSW, 0, $r2) trace_clr(T_AUTO) bra #main @@ -279,7 +278,7 @@ main: cmpu b32 $r14 0x0001 bra ne #main_not_ctx_chan mov b32 $r2 $r15 - call #ctx_chan + call(ctx_chan) bra #main_done // request to store current channel context? @@ -289,14 +288,14 @@ main: trace_set(T_SAVE) bclr $flags $p1 bclr $flags $p2 - call #ctx_xfer + call(ctx_xfer) trace_clr(T_SAVE) bra #main_done main_not_ctx_save: shl b32 $r15 $r14 16 or $r15 E_BAD_COMMAND - call #error + call(error) bra #main main_done: @@ -319,41 +318,58 @@ ih: clear b32 $r0 // incoming fifo command? - iord $r10 I[$r0 + 0x200] // INTR - and $r11 $r10 0x00000004 + nv_iord($r10, NV_PGRAPH_FECS_INTR, 0) + and $r11 $r10 NV_PGRAPH_FECS_INTR_FIFO bra e #ih_no_fifo // queue incoming fifo command for later processing - mov $r11 0x1900 mov $r13 #cmd_queue - iord $r14 I[$r11 + 0x100] // FIFO_CMD - iord $r15 I[$r11 + 0x000] // FIFO_DATA - call #queue_put + nv_iord($r14, NV_PGRAPH_FECS_FIFO_CMD, 0) + nv_iord($r15, NV_PGRAPH_FECS_FIFO_DATA, 0) + call(queue_put) add b32 $r11 0x400 mov $r14 1 - iowr I[$r11 + 0x000] $r14 // FIFO_ACK + nv_iowr(NV_PGRAPH_FECS_FIFO_ACK, 0, $r14) // context switch request? ih_no_fifo: - and $r11 $r10 0x00000100 + and $r11 $r10 NV_PGRAPH_FECS_INTR_CHSW bra e #ih_no_ctxsw // enqueue a context switch for later processing mov $r13 #cmd_queue mov $r14 0x4001 - call #queue_put + call(queue_put) - // anything we didn't handle, bring it to the host's attention + // firmware method? ih_no_ctxsw: - mov $r11 0x104 + and $r11 $r10 NV_PGRAPH_FECS_INTR_FWMTHD + bra e #ih_no_fwmthd + // none we handle; report to host and ack + nv_rd32($r15, NV_PGRAPH_TRAPPED_DATA_LO) + nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(4), 0, $r15) + nv_rd32($r15, NV_PGRAPH_TRAPPED_ADDR) + nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(3), 0, $r15) + extr $r14 $r15 16:18 + shl b32 $r14 $r14 2 + imm32($r15, NV_PGRAPH_FE_OBJECT_TABLE(0)) + add b32 $r14 $r15 + call(nv_rd32) + nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(2), 0, $r15) + mov $r15 E_BAD_FWMTHD + call(error) + mov $r11 0x100 + nv_wr32(0x400144, $r11) + + // anything we didn't handle, bring it to the host's attention + ih_no_fwmthd: + mov $r11 0x504 // FIFO | CHSW | FWMTHD not b32 $r11 and $r11 $r10 $r11 bra e #ih_no_other - mov $r10 0xc1c - shl b32 $r10 6 - iowr I[$r10] $r11 // INTR_UP_SET + nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r11) // ack, and wake up main() ih_no_other: - iowr I[$r0 + 0x100] $r10 // INTR_ACK + nv_iowr(NV_PGRAPH_FECS_INTR_ACK, 0, $r10) pop $r15 pop $r14 @@ -370,12 +386,10 @@ ih: #if CHIPSET < GK100 // Not real sure, but, MEM_CMD 7 will hang forever if this isn't done ctx_4160s: - mov $r14 0x4160 - sethi $r14 0x400000 mov $r15 1 - call #nv_wr32 + nv_wr32(0x404160, $r15) ctx_4160s_wait: - call #nv_rd32 + nv_rd32($r15, 0x404160) xbit $r15 $r15 4 bra e #ctx_4160s_wait ret @@ -384,10 +398,8 @@ ctx_4160s: // to hang with STATUS=0x00000007 until it's cleared.. fbcon can // still function with it set however... ctx_4160c: - mov $r14 0x4160 - sethi $r14 0x400000 clear b32 $r15 - call #nv_wr32 + nv_wr32(0x404160, $r15) ret #endif @@ -396,18 +408,14 @@ ctx_4160c: // In: $r15 value to set 0x404170 to // ctx_4170s: - mov $r14 0x4170 - sethi $r14 0x400000 or $r15 0x10 - call #nv_wr32 + nv_wr32(0x404170, $r15) ret // Waits for a ctx_4170s() call to complete // ctx_4170w: - mov $r14 0x4170 - sethi $r14 0x400000 - call #nv_rd32 + nv_rd32($r15, 0x404170) and $r15 0x10 bra ne #ctx_4170w ret @@ -419,16 +427,18 @@ ctx_4170w: // funny things happen. // ctx_redswitch: - mov $r14 0x614 - shl b32 $r14 6 - mov $r15 0x270 - iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL + mov $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC + or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP + or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC + or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN + nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14) mov $r15 8 ctx_redswitch_delay: sub b32 $r15 1 bra ne #ctx_redswitch_delay - mov $r15 0x770 - iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL + or $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP + or $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN + nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14) ret // Not a clue what this is for, except that unless the value is 0x10, the @@ -437,15 +447,18 @@ ctx_redswitch: // In: $r15 value to set to (0x00/0x10 are used) // ctx_86c: - mov $r14 0x86c - shl b32 $r14 6 - iowr I[$r14] $r15 // HUB(0x86c) = val - mov $r14 -0x75ec - sethi $r14 0x400000 - call #nv_wr32 // ROP(0xa14) = val - mov $r14 -0x5794 - sethi $r14 0x410000 - call #nv_wr32 // GPC(0x86c) = val + nv_iowr(NV_PGRAPH_FECS_UNK86C, 0, $r15) + nv_wr32(0x408a14, $r15) + nv_wr32(NV_PGRAPH_GPCX_GPCCS_UNK86C, $r15) + ret + +// In: $r15 NV_PGRAPH_FECS_MEM_CMD_* +ctx_mem: + nv_iowr(NV_PGRAPH_FECS_MEM_CMD, 0, $r15) + ctx_mem_wait: + nv_iord($r15, NV_PGRAPH_FECS_MEM_CMD, 0) + or $r15 $r15 + bra ne #ctx_mem_wait ret // ctx_load - load's a channel's ctxctl data, and selects its vm @@ -457,23 +470,14 @@ ctx_load: // switch to channel, somewhat magic in parts.. mov $r10 12 // DONE_UNK12 - call #wait_donez - mov $r1 0xa24 - shl b32 $r1 6 - iowr I[$r1 + 0x000] $r0 // 0x409a24 - mov $r3 0xb00 - shl b32 $r3 6 - iowr I[$r3 + 0x100] $r2 // CHAN_NEXT - mov $r1 0xa0c - shl b32 $r1 6 - mov $r4 7 - iowr I[$r1 + 0x000] $r2 // MEM_CHAN - iowr I[$r1 + 0x100] $r4 // MEM_CMD - ctx_chan_wait_0: - iord $r4 I[$r1 + 0x100] - and $r4 0x1f - bra ne #ctx_chan_wait_0 - iowr I[$r3 + 0x000] $r2 // CHAN_CUR + call(wait_donez) + clear b32 $r15 + nv_iowr(0x409a24, 0, $r15) + nv_iowr(NV_PGRAPH_FECS_CHAN_NEXT, 0, $r2) + nv_iowr(NV_PGRAPH_FECS_MEM_CHAN, 0, $r2) + mov $r15 NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN + call(ctx_mem) + nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2) // load channel header, fetch PGRAPH context pointer mov $xtargets $r0 @@ -482,14 +486,10 @@ ctx_load: add b32 $r2 2 trace_set(T_LCHAN) - mov $r1 0xa04 - shl b32 $r1 6 - iowr I[$r1 + 0x000] $r2 // MEM_BASE - mov $r1 0xa20 - shl b32 $r1 6 - mov $r2 0x0002 - sethi $r2 0x80000000 - iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram + nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r2) + imm32($r2, NV_PGRAPH_FECS_MEM_TARGET_UNK31) + or $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM + nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2) mov $r1 0x10 // chan + 0x0210 mov $r2 #xfer_data sethi $r2 0x00020000 // 16 bytes @@ -507,13 +507,9 @@ ctx_load: // set transfer base to start of context, and fetch context header trace_set(T_LCTXH) - mov $r2 0xa04 - shl b32 $r2 6 - iowr I[$r2 + 0x000] $r1 // MEM_BASE - mov $r2 1 - mov $r1 0xa20 - shl b32 $r1 6 - iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm + nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r1) + mov $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VM + nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2) mov $r1 #chan_data sethi $r1 0x00060000 // 256 bytes xdld $r0 $r1 @@ -532,21 +528,15 @@ ctx_load: // ctx_chan: #if CHIPSET < GK100 - call #ctx_4160s + call(ctx_4160s) #endif - call #ctx_load + call(ctx_load) mov $r10 12 // DONE_UNK12 - call #wait_donez - mov $r1 0xa10 - shl b32 $r1 6 - mov $r2 5 - iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???) - ctx_chan_wait: - iord $r2 I[$r1 + 0x000] - or $r2 $r2 - bra ne #ctx_chan_wait + call(wait_donez) + mov $r15 5 // MEM_CMD 5 ??? + call(ctx_mem) #if CHIPSET < GK100 - call #ctx_4160c + call(ctx_4160c) #endif ret @@ -562,9 +552,7 @@ ctx_chan: ctx_mmio_exec: // set transfer base to be the mmio list ld b32 $r3 D[$r0 + #chan_mmio_address] - mov $r2 0xa04 - shl b32 $r2 6 - iowr I[$r2 + 0x000] $r3 // MEM_BASE + nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3) clear b32 $r3 ctx_mmio_loop: @@ -580,7 +568,7 @@ ctx_mmio_exec: ctx_mmio_pull: ld b32 $r14 D[$r4 + #xfer_data + 0x00] ld b32 $r15 D[$r4 + #xfer_data + 0x04] - call #nv_wr32 + call(nv_wr32) // next! add b32 $r3 8 @@ -590,7 +578,7 @@ ctx_mmio_exec: // set transfer base back to the current context ctx_mmio_done: ld b32 $r3 D[$r0 + #ctx_current] - iowr I[$r2 + 0x000] $r3 // MEM_BASE + nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3) // disable the mmio list now, we don't need/want to execute it again st b32 D[$r0 + #chan_mmio_count] $r0 @@ -610,12 +598,10 @@ ctx_mmio_exec: // ctx_xfer: // according to mwk, some kind of wait for idle - mov $r15 0xc00 - shl b32 $r15 6 mov $r14 4 - iowr I[$r15 + 0x200] $r14 + nv_iowr(0x409c08, 0, $r14) ctx_xfer_idle: - iord $r14 I[$r15 + 0x000] + nv_iord($r14, 0x409c00, 0) and $r14 0x2000 bra ne #ctx_xfer_idle @@ -623,50 +609,42 @@ ctx_xfer: bra $p2 #ctx_xfer_pre_load ctx_xfer_pre: mov $r15 0x10 - call #ctx_86c + call(ctx_86c) #if CHIPSET < GK100 - call #ctx_4160s + call(ctx_4160s) #endif bra not $p1 #ctx_xfer_exec ctx_xfer_pre_load: mov $r15 2 - call #ctx_4170s - call #ctx_4170w - call #ctx_redswitch + call(ctx_4170s) + call(ctx_4170w) + call(ctx_redswitch) clear b32 $r15 - call #ctx_4170s - call #ctx_load + call(ctx_4170s) + call(ctx_load) // fetch context pointer, and initiate xfer on all GPCs ctx_xfer_exec: ld b32 $r1 D[$r0 + #ctx_current] - mov $r2 0x414 - shl b32 $r2 6 - iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset - mov $r14 -0x5b00 - sethi $r14 0x410000 - mov b32 $r15 $r1 - call #nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer - add b32 $r14 4 + + clear b32 $r2 + nv_iowr(NV_PGRAPH_FECS_BAR, 0, $r2) + + nv_wr32(0x41a500, $r1) // GPC_BCAST_WRCMD_DATA = ctx pointer xbit $r15 $flags $p1 xbit $r2 $flags $p2 shl b32 $r2 1 or $r15 $r2 - call #nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type) + nv_wr32(0x41a504, $r15) // GPC_BCAST_WRCMD_CMD = GPC_XFER(type) // strands - mov $r1 0x4afc - sethi $r1 0x20000 - mov $r2 0xc - iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c - call #strand_wait - mov $r2 0x47fc - sethi $r2 0x20000 - iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 - xbit $r2 $flags $p1 - add b32 $r2 3 - iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) + call(strand_pre) + clear b32 $r2 + nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r2) + xbit $r2 $flags $p1 // SAVE/LOAD + add b32 $r2 NV_PGRAPH_FECS_STRAND_CMD_SAVE + nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r2) // mmio context xbit $r10 $flags $p1 // direction @@ -675,48 +653,42 @@ ctx_xfer: ld b32 $r12 D[$r0 + #hub_mmio_list_head] ld b32 $r13 D[$r0 + #hub_mmio_list_tail] mov $r14 0 // not multi - call #mmctx_xfer + call(mmctx_xfer) // wait for GPCs to all complete mov $r10 8 // DONE_BAR - call #wait_doneo + call(wait_doneo) // wait for strand xfer to complete - call #strand_wait + call(strand_wait) // post-op bra $p1 #ctx_xfer_post mov $r10 12 // DONE_UNK12 - call #wait_donez - mov $r1 0xa10 - shl b32 $r1 6 - mov $r2 5 - iowr I[$r1] $r2 // MEM_CMD - ctx_xfer_post_save_wait: - iord $r2 I[$r1] - or $r2 $r2 - bra ne #ctx_xfer_post_save_wait + call(wait_donez) + mov $r15 5 // MEM_CMD 5 ??? + call(ctx_mem) bra $p2 #ctx_xfer_done ctx_xfer_post: mov $r15 2 - call #ctx_4170s + call(ctx_4170s) clear b32 $r15 - call #ctx_86c - call #strand_post - call #ctx_4170w + call(ctx_86c) + call(strand_post) + call(ctx_4170w) clear b32 $r15 - call #ctx_4170s + call(ctx_4170s) bra not $p1 #ctx_xfer_no_post_mmio ld b32 $r1 D[$r0 + #chan_mmio_count] or $r1 $r1 bra e #ctx_xfer_no_post_mmio - call #ctx_mmio_exec + call(ctx_mmio_exec) ctx_xfer_no_post_mmio: #if CHIPSET < GK100 - call #ctx_4160c + call(ctx_4160c) #endif ctx_xfer_done: diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 new file mode 100644 index 00000000000..27591b3086a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 @@ -0,0 +1,40 @@ +/* + * 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> + */ + +#define CHIPSET GK208 +#include "macros.fuc" + +.section #gm107_grhub_data +#define INCLUDE_DATA +#include "com.fuc" +#include "hub.fuc" +#undef INCLUDE_DATA + +.section #gm107_grhub_code +#define INCLUDE_CODE +bra #init +#include "com.fuc" +#include "hub.fuc" +.align 256 +#undef INCLUDE_CODE diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h new file mode 100644 index 00000000000..5f953c5c20b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h @@ -0,0 +1,916 @@ +uint32_t gm107_grhub_data[] = { +/* 0x0000: hub_mmio_list_head */ + 0x00000300, +/* 0x0004: hub_mmio_list_tail */ + 0x00000304, +/* 0x0008: gpc_count */ + 0x00000000, +/* 0x000c: rop_count */ + 0x00000000, +/* 0x0010: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0058: ctx_current */ + 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, +/* 0x0100: chan_data */ +/* 0x0100: chan_mmio_count */ + 0x00000000, +/* 0x0104: chan_mmio_address */ + 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, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0200: xfer_data */ + 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, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0300: hub_mmio_list_base */ + 0x0417e91c, +}; + +uint32_t gm107_grhub_code[] = { + 0x030e0ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0xf489a408, + 0x020f0b1b, + 0x0002f87e, +/* 0x001a: queue_put_next */ + 0x98c400f8, + 0x0384b607, + 0xb6008dbb, + 0x8eb50880, + 0x018fb500, + 0xf00190b6, + 0xd9b50f94, +/* 0x0037: queue_get */ + 0xf400f801, + 0xd8980131, + 0x01d99800, + 0x0bf489a4, + 0x0789c421, + 0xbb0394b6, + 0x90b6009d, + 0x009e9808, + 0xb6019f98, + 0x84f00180, + 0x00d8b50f, +/* 0x0063: queue_get_done */ + 0xf80132f4, +/* 0x0065: nv_rd32 */ + 0xf0ecb200, + 0x00801fc9, + 0x0cf601ca, +/* 0x0073: nv_rd32_wait */ + 0x8c04bd00, + 0xcf01ca00, + 0xccc800cc, + 0xf61bf41f, + 0xec7e060a, + 0x008f0000, + 0xffcf01cb, +/* 0x008f: nv_wr32 */ + 0x8000f800, + 0xf601cc00, + 0x04bd000f, + 0xc9f0ecb2, + 0x1ec9f01f, + 0x01ca0080, + 0xbd000cf6, +/* 0x00a9: nv_wr32_wait */ + 0xca008c04, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f61b, +/* 0x00b8: wait_donez */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x00cf: wait_donez_ne */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf61bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x00ec: wait_doneo */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x0103: wait_doneo_e */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf60bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x0120: mmctx_size */ +/* 0x0122: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0x1bf4efa4, + 0xf89fb2ec, +/* 0x013d: mmctx_xfer */ + 0xf094bd00, + 0x00800199, + 0x09f60237, + 0xbd04bd00, + 0x05bbfd94, + 0x800f0bf4, + 0xf601c400, + 0x04bd000b, +/* 0x015f: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0xc6008018, + 0x000ef601, + 0x008004bd, + 0x0ff601c7, + 0xf004bd00, +/* 0x017a: mmctx_multi_disabled */ + 0xabc80199, + 0x10b4b600, + 0xc80cb9f0, + 0xe4b601ae, + 0x05befd11, + 0x01c50080, + 0xbd000bf6, +/* 0x0195: mmctx_exec_loop */ +/* 0x0195: mmctx_wait_free */ + 0xc5008e04, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f60b, + 0x05e9fd00, + 0x01c80080, + 0xbd000ef6, + 0x04c0b604, + 0x1bf4cda4, + 0x02abc8df, +/* 0x01bf: mmctx_fini_wait */ + 0x8b1c1bf4, + 0xcf01c500, + 0xb4f000bb, + 0x10b4b01f, + 0x0af31bf4, + 0x00b87e05, + 0x250ef400, +/* 0x01d8: mmctx_stop */ + 0xb600abc8, + 0xb9f010b4, + 0x12b9f00c, + 0x01c50080, + 0xbd000bf6, +/* 0x01ed: mmctx_stop_wait */ + 0xc5008b04, + 0x00bbcf01, + 0xf412bbc8, +/* 0x01fa: mmctx_done */ + 0x94bdf61b, + 0x800199f0, + 0xf6021700, + 0x04bd0009, +/* 0x020a: strand_wait */ + 0xa0f900f8, + 0xb87e020a, + 0xa0fc0000, +/* 0x0216: strand_pre */ + 0x0c0900f8, + 0x024afc80, + 0xbd0009f6, + 0x020a7e04, +/* 0x0227: strand_post */ + 0x0900f800, + 0x4afc800d, + 0x0009f602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0238: strand_set */ + 0xfc800f0c, + 0x0cf6024f, + 0x0c04bd00, + 0x4afc800b, + 0x000cf602, + 0xfc8004bd, + 0x0ef6024f, + 0x0c04bd00, + 0x4afc800a, + 0x000cf602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0268: strand_ctx_init */ + 0x99f094bd, + 0x37008003, + 0x0009f602, + 0x167e04bd, + 0x030e0002, + 0x0002387e, + 0xfc80c4bd, + 0x0cf60247, + 0x0c04bd00, + 0x4afc8001, + 0x000cf602, + 0x0a7e04bd, + 0x0c920002, + 0x46fc8001, + 0x000cf602, + 0x020c04bd, + 0x024afc80, + 0xbd000cf6, + 0x020a7e04, + 0x02277e00, + 0x42008800, + 0x20008902, + 0x0099cf02, +/* 0x02c7: ctx_init_strand_loop */ + 0xf608fe95, + 0x8ef6008e, + 0x808acf40, + 0xb606a5b6, + 0xeabb01a0, + 0x0480b600, + 0xf40192b6, + 0xe4b6e81b, + 0xf2efbc08, + 0x99f094bd, + 0x17008003, + 0x0009f602, + 0x00f804bd, +/* 0x02f8: error */ + 0x02050080, + 0xbd000ff6, + 0x80010f04, + 0xf6030700, + 0x04bd000f, +/* 0x030e: init */ + 0x04bd00f8, + 0x410007fe, + 0x11cf4200, + 0x0911e700, + 0x0814b601, + 0x020014fe, + 0x12004002, + 0xbd0002f6, + 0x05c94104, + 0xbd0010fe, + 0x07004024, + 0xbd0002f6, + 0x20034204, + 0x01010080, + 0xbd0002f6, + 0x20044204, + 0x01010480, + 0xbd0002f6, + 0x200b4204, + 0x01010880, + 0xbd0002f6, + 0x200c4204, + 0x01011c80, + 0xbd0002f6, + 0x01039204, + 0x03090080, + 0xbd0003f6, + 0x87044204, + 0xf6040040, + 0x04bd0002, + 0x00400402, + 0x0002f603, + 0x31f404bd, + 0x96048e10, + 0x00657e40, + 0xc7feb200, + 0x01b590f1, + 0x1ff4f003, + 0x01020fb5, + 0x041fbb01, + 0x800112b6, + 0xf6010300, + 0x04bd0001, + 0x01040080, + 0xbd0001f6, + 0x01004104, + 0xa87e020f, + 0xb77e0006, + 0x100f0006, + 0x0006f97e, + 0x98000e98, + 0x207e010f, + 0x14950001, + 0xc0008008, + 0x0004f601, + 0x008004bd, + 0x04f601c1, + 0xb704bd00, + 0xbb130030, + 0xf5b6001f, + 0xd3008002, + 0x000ff601, + 0x15b604bd, + 0x0110b608, + 0xb20814b6, + 0x02687e1f, + 0x001fbb00, + 0x84020398, +/* 0x041f: init_gpc */ + 0xb8502000, + 0x0008044e, + 0x8f7e1fb2, + 0x4eb80000, + 0xbd00010c, + 0x008f7ef4, + 0x044eb800, + 0x8f7e0001, + 0x4eb80000, + 0x0f000100, + 0x008f7e02, + 0x004eb800, +/* 0x044e: init_gpc_wait */ + 0x657e0008, + 0xffc80000, + 0xf90bf41f, + 0x08044eb8, + 0x00657e00, + 0x001fbb00, + 0x800040b7, + 0xf40132b6, + 0x000fb41b, + 0x0006f97e, + 0xa87e000f, + 0x00800006, + 0x01f60201, + 0xbd04bd00, + 0x1f19f014, + 0x02300080, + 0xbd0001f6, +/* 0x0491: main */ + 0x0031f404, + 0x0d0028f4, + 0x00377e10, + 0xf401f400, + 0x4001e4b1, + 0x00c71bf5, + 0x99f094bd, + 0x37008004, + 0x0009f602, + 0x008104bd, + 0x11cf02c0, + 0xc1008200, + 0x0022cf02, + 0xf41f13c8, + 0x23c8770b, + 0x550bf41f, + 0x12b220f9, + 0x99f094bd, + 0x37008007, + 0x0009f602, + 0x32f404bd, + 0x0231f401, + 0x00087c7e, + 0x99f094bd, + 0x17008007, + 0x0009f602, + 0x20fc04bd, + 0x99f094bd, + 0x37008006, + 0x0009f602, + 0x31f404bd, + 0x087c7e01, + 0xf094bd00, + 0x00800699, + 0x09f60217, + 0xf404bd00, +/* 0x0522: chsw_prev_no_next */ + 0x20f92f0e, + 0x32f412b2, + 0x0232f401, + 0x00087c7e, + 0x008020fc, + 0x02f602c0, + 0xf404bd00, +/* 0x053e: chsw_no_prev */ + 0x23c8130e, + 0x0d0bf41f, + 0xf40131f4, + 0x7c7e0232, +/* 0x054e: chsw_done */ + 0x01020008, + 0x02c30080, + 0xbd0002f6, + 0xf094bd04, + 0x00800499, + 0x09f60217, + 0xf504bd00, +/* 0x056b: main_not_ctx_switch */ + 0xb0ff2a0e, + 0x1bf401e4, + 0x7ef2b20c, + 0xf400081c, +/* 0x057a: main_not_ctx_chan */ + 0xe4b0400e, + 0x2c1bf402, + 0x99f094bd, + 0x37008007, + 0x0009f602, + 0x32f404bd, + 0x0232f401, + 0x00087c7e, + 0x99f094bd, + 0x17008007, + 0x0009f602, + 0x0ef404bd, +/* 0x05a9: main_not_ctx_save */ + 0x10ef9411, + 0x7e01f5f0, + 0xf50002f8, +/* 0x05b7: main_done */ + 0xbdfede0e, + 0x1f29f024, + 0x02300080, + 0xbd0002f6, + 0xcc0ef504, +/* 0x05c9: ih */ + 0xfe80f9fe, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0x004a04bd, + 0x00aacf02, + 0xf404abc4, + 0x100d230b, + 0xcf1a004e, + 0x004f00ee, + 0x00ffcf19, + 0x0000047e, + 0x0400b0b7, + 0x0040010e, + 0x000ef61d, +/* 0x060a: ih_no_fifo */ + 0xabe404bd, + 0x0bf40100, + 0x4e100d0c, + 0x047e4001, +/* 0x061a: ih_no_ctxsw */ + 0xabe40000, + 0x0bf40400, + 0x07088e56, + 0x00657e40, + 0x80ffb200, + 0xf6020400, + 0x04bd000f, + 0x4007048e, + 0x0000657e, + 0x0080ffb2, + 0x0ff60203, + 0xc704bd00, + 0xee9450fe, + 0x07008f02, + 0x00efbb40, + 0x0000657e, + 0x02020080, + 0xbd000ff6, + 0x7e030f04, + 0x4b0002f8, + 0xbfb20100, + 0x4001448e, + 0x00008f7e, +/* 0x0674: ih_no_fwmthd */ + 0xbd05044b, + 0xb4abffb0, + 0x800c0bf4, + 0xf6030700, + 0x04bd000b, +/* 0x0688: ih_no_other */ + 0xf6010040, + 0x04bd000a, + 0xe0fcf0fc, + 0xb0fcd0fc, + 0x90fca0fc, + 0x88fe80fc, + 0xf480fc00, + 0x01f80032, +/* 0x06a8: ctx_4170s */ + 0xb210f5f0, + 0x41708eff, + 0x008f7e40, +/* 0x06b7: ctx_4170w */ + 0x8e00f800, + 0x7e404170, + 0xb2000065, + 0x10f4f0ff, + 0xf8f31bf4, +/* 0x06c9: ctx_redswitch */ + 0x02004e00, + 0xf040e5f0, + 0xe5f020e5, + 0x85008010, + 0x000ef601, + 0x080f04bd, +/* 0x06e0: ctx_redswitch_delay */ + 0xf401f2b6, + 0xe5f1fd1b, + 0xe5f10400, + 0x00800100, + 0x0ef60185, + 0xf804bd00, +/* 0x06f9: ctx_86c */ + 0x23008000, + 0x000ff602, + 0xffb204bd, + 0x408a148e, + 0x00008f7e, + 0x8c8effb2, + 0x8f7e41a8, + 0x00f80000, +/* 0x0718: ctx_mem */ + 0x02840080, + 0xbd000ff6, +/* 0x0721: ctx_mem_wait */ + 0x84008f04, + 0x00ffcf02, + 0xf405fffd, + 0x00f8f61b, +/* 0x0730: ctx_load */ + 0x99f094bd, + 0x37008005, + 0x0009f602, + 0x0c0a04bd, + 0x0000b87e, + 0x0080f4bd, + 0x0ff60289, + 0x8004bd00, + 0xf602c100, + 0x04bd0002, + 0x02830080, + 0xbd0002f6, + 0x7e070f04, + 0x80000718, + 0xf602c000, + 0x04bd0002, + 0xf0000bfe, + 0x24b61f2a, + 0x0220b604, + 0x99f094bd, + 0x37008008, + 0x0009f602, + 0x008004bd, + 0x02f60281, + 0xd204bd00, + 0x80000000, + 0x800225f0, + 0xf6028800, + 0x04bd0002, + 0x00421001, + 0x0223f002, + 0xf80512fa, + 0xf094bd03, + 0x00800899, + 0x09f60217, + 0x9804bd00, + 0x14b68101, + 0x80029818, + 0xfd0825b6, + 0x01b50512, + 0xf094bd16, + 0x00800999, + 0x09f60237, + 0x8004bd00, + 0xf6028100, + 0x04bd0001, + 0x00800102, + 0x02f60288, + 0x4104bd00, + 0x13f00100, + 0x0501fa06, + 0x94bd03f8, + 0x800999f0, + 0xf6021700, + 0x04bd0009, + 0x99f094bd, + 0x17008005, + 0x0009f602, + 0x00f804bd, +/* 0x081c: ctx_chan */ + 0x0007307e, + 0xb87e0c0a, + 0x050f0000, + 0x0007187e, +/* 0x082e: ctx_mmio_exec */ + 0x039800f8, + 0x81008041, + 0x0003f602, + 0x34bd04bd, +/* 0x083c: ctx_mmio_loop */ + 0xf4ff34c4, + 0x00450e1b, + 0x0653f002, + 0xf80535fa, +/* 0x084d: ctx_mmio_pull */ + 0x804e9803, + 0x7e814f98, + 0xb600008f, + 0x12b60830, + 0xdf1bf401, +/* 0x0860: ctx_mmio_done */ + 0x80160398, + 0xf6028100, + 0x04bd0003, + 0x414000b5, + 0x13f00100, + 0x0601fa06, + 0x00f803f8, +/* 0x087c: ctx_xfer */ + 0x0080040e, + 0x0ef60302, +/* 0x0887: ctx_xfer_idle */ + 0x8e04bd00, + 0xcf030000, + 0xe4f100ee, + 0x1bf42000, + 0x0611f4f5, +/* 0x089b: ctx_xfer_pre */ + 0x0f0c02f4, + 0x06f97e10, + 0x1b11f400, +/* 0x08a4: ctx_xfer_pre_load */ + 0xa87e020f, + 0xb77e0006, + 0xc97e0006, + 0xf4bd0006, + 0x0006a87e, + 0x0007307e, +/* 0x08bc: ctx_xfer_exec */ + 0xbd160198, + 0x05008024, + 0x0002f601, + 0x1fb204bd, + 0x41a5008e, + 0x00008f7e, + 0xf001fcf0, + 0x24b6022c, + 0x05f2fd01, + 0x048effb2, + 0x8f7e41a5, + 0x167e0000, + 0x24bd0002, + 0x0247fc80, + 0xbd0002f6, + 0x012cf004, + 0x800320b6, + 0xf6024afc, + 0x04bd0002, + 0xf001acf0, + 0x000b06a5, + 0x98000c98, + 0x000e010d, + 0x00013d7e, + 0xec7e080a, + 0x0a7e0000, + 0x01f40002, + 0x7e0c0a12, + 0x0f0000b8, + 0x07187e05, + 0x2d02f400, +/* 0x0938: ctx_xfer_post */ + 0xa87e020f, + 0xf4bd0006, + 0x0006f97e, + 0x0002277e, + 0x0006b77e, + 0xa87ef4bd, + 0x11f40006, + 0x40019810, + 0xf40511fd, + 0x2e7e070b, +/* 0x0962: ctx_xfer_no_post_mmio */ +/* 0x0962: ctx_xfer_done */ + 0x00f80008, + 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, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5 new file mode 100644 index 00000000000..7c5d25630fa --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5 @@ -0,0 +1,40 @@ +/* + * 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> + */ + +#define CHIPSET GK208 +#include "macros.fuc" + +.section #nv108_grhub_data +#define INCLUDE_DATA +#include "com.fuc" +#include "hub.fuc" +#undef INCLUDE_DATA + +.section #nv108_grhub_code +#define INCLUDE_CODE +bra #init +#include "com.fuc" +#include "hub.fuc" +.align 256 +#undef INCLUDE_CODE diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h new file mode 100644 index 00000000000..e49b5a877ae --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h @@ -0,0 +1,916 @@ +uint32_t nv108_grhub_data[] = { +/* 0x0000: hub_mmio_list_head */ + 0x00000300, +/* 0x0004: hub_mmio_list_tail */ + 0x00000304, +/* 0x0008: gpc_count */ + 0x00000000, +/* 0x000c: rop_count */ + 0x00000000, +/* 0x0010: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0058: ctx_current */ + 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, +/* 0x0100: chan_data */ +/* 0x0100: chan_mmio_count */ + 0x00000000, +/* 0x0104: chan_mmio_address */ + 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, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0200: xfer_data */ + 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, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0300: hub_mmio_list_base */ + 0x0417e91c, +}; + +uint32_t nv108_grhub_code[] = { + 0x030e0ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0xf489a408, + 0x020f0b1b, + 0x0002f87e, +/* 0x001a: queue_put_next */ + 0x98c400f8, + 0x0384b607, + 0xb6008dbb, + 0x8eb50880, + 0x018fb500, + 0xf00190b6, + 0xd9b50f94, +/* 0x0037: queue_get */ + 0xf400f801, + 0xd8980131, + 0x01d99800, + 0x0bf489a4, + 0x0789c421, + 0xbb0394b6, + 0x90b6009d, + 0x009e9808, + 0xb6019f98, + 0x84f00180, + 0x00d8b50f, +/* 0x0063: queue_get_done */ + 0xf80132f4, +/* 0x0065: nv_rd32 */ + 0xf0ecb200, + 0x00801fc9, + 0x0cf601ca, +/* 0x0073: nv_rd32_wait */ + 0x8c04bd00, + 0xcf01ca00, + 0xccc800cc, + 0xf61bf41f, + 0xec7e060a, + 0x008f0000, + 0xffcf01cb, +/* 0x008f: nv_wr32 */ + 0x8000f800, + 0xf601cc00, + 0x04bd000f, + 0xc9f0ecb2, + 0x1ec9f01f, + 0x01ca0080, + 0xbd000cf6, +/* 0x00a9: nv_wr32_wait */ + 0xca008c04, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f61b, +/* 0x00b8: wait_donez */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x00cf: wait_donez_ne */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf61bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x00ec: wait_doneo */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x0103: wait_doneo_e */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf60bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x0120: mmctx_size */ +/* 0x0122: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0x1bf4efa4, + 0xf89fb2ec, +/* 0x013d: mmctx_xfer */ + 0xf094bd00, + 0x00800199, + 0x09f60237, + 0xbd04bd00, + 0x05bbfd94, + 0x800f0bf4, + 0xf601c400, + 0x04bd000b, +/* 0x015f: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0xc6008018, + 0x000ef601, + 0x008004bd, + 0x0ff601c7, + 0xf004bd00, +/* 0x017a: mmctx_multi_disabled */ + 0xabc80199, + 0x10b4b600, + 0xc80cb9f0, + 0xe4b601ae, + 0x05befd11, + 0x01c50080, + 0xbd000bf6, +/* 0x0195: mmctx_exec_loop */ +/* 0x0195: mmctx_wait_free */ + 0xc5008e04, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f60b, + 0x05e9fd00, + 0x01c80080, + 0xbd000ef6, + 0x04c0b604, + 0x1bf4cda4, + 0x02abc8df, +/* 0x01bf: mmctx_fini_wait */ + 0x8b1c1bf4, + 0xcf01c500, + 0xb4f000bb, + 0x10b4b01f, + 0x0af31bf4, + 0x00b87e05, + 0x250ef400, +/* 0x01d8: mmctx_stop */ + 0xb600abc8, + 0xb9f010b4, + 0x12b9f00c, + 0x01c50080, + 0xbd000bf6, +/* 0x01ed: mmctx_stop_wait */ + 0xc5008b04, + 0x00bbcf01, + 0xf412bbc8, +/* 0x01fa: mmctx_done */ + 0x94bdf61b, + 0x800199f0, + 0xf6021700, + 0x04bd0009, +/* 0x020a: strand_wait */ + 0xa0f900f8, + 0xb87e020a, + 0xa0fc0000, +/* 0x0216: strand_pre */ + 0x0c0900f8, + 0x024afc80, + 0xbd0009f6, + 0x020a7e04, +/* 0x0227: strand_post */ + 0x0900f800, + 0x4afc800d, + 0x0009f602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0238: strand_set */ + 0xfc800f0c, + 0x0cf6024f, + 0x0c04bd00, + 0x4afc800b, + 0x000cf602, + 0xfc8004bd, + 0x0ef6024f, + 0x0c04bd00, + 0x4afc800a, + 0x000cf602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0268: strand_ctx_init */ + 0x99f094bd, + 0x37008003, + 0x0009f602, + 0x167e04bd, + 0x030e0002, + 0x0002387e, + 0xfc80c4bd, + 0x0cf60247, + 0x0c04bd00, + 0x4afc8001, + 0x000cf602, + 0x0a7e04bd, + 0x0c920002, + 0x46fc8001, + 0x000cf602, + 0x020c04bd, + 0x024afc80, + 0xbd000cf6, + 0x020a7e04, + 0x02277e00, + 0x42008800, + 0x20008902, + 0x0099cf02, +/* 0x02c7: ctx_init_strand_loop */ + 0xf608fe95, + 0x8ef6008e, + 0x808acf40, + 0xb606a5b6, + 0xeabb01a0, + 0x0480b600, + 0xf40192b6, + 0xe4b6e81b, + 0xf2efbc08, + 0x99f094bd, + 0x17008003, + 0x0009f602, + 0x00f804bd, +/* 0x02f8: error */ + 0x02050080, + 0xbd000ff6, + 0x80010f04, + 0xf6030700, + 0x04bd000f, +/* 0x030e: init */ + 0x04bd00f8, + 0x410007fe, + 0x11cf4200, + 0x0911e700, + 0x0814b601, + 0x020014fe, + 0x12004002, + 0xbd0002f6, + 0x05c94104, + 0xbd0010fe, + 0x07004024, + 0xbd0002f6, + 0x20034204, + 0x01010080, + 0xbd0002f6, + 0x20044204, + 0x01010480, + 0xbd0002f6, + 0x200b4204, + 0x01010880, + 0xbd0002f6, + 0x200c4204, + 0x01011c80, + 0xbd0002f6, + 0x01039204, + 0x03090080, + 0xbd0003f6, + 0x87044204, + 0xf6040040, + 0x04bd0002, + 0x00400402, + 0x0002f603, + 0x31f404bd, + 0x96048e10, + 0x00657e40, + 0xc7feb200, + 0x01b590f1, + 0x1ff4f003, + 0x01020fb5, + 0x041fbb01, + 0x800112b6, + 0xf6010300, + 0x04bd0001, + 0x01040080, + 0xbd0001f6, + 0x01004104, + 0xa87e020f, + 0xb77e0006, + 0x100f0006, + 0x0006f97e, + 0x98000e98, + 0x207e010f, + 0x14950001, + 0xc0008008, + 0x0004f601, + 0x008004bd, + 0x04f601c1, + 0xb704bd00, + 0xbb130030, + 0xf5b6001f, + 0xd3008002, + 0x000ff601, + 0x15b604bd, + 0x0110b608, + 0xb20814b6, + 0x02687e1f, + 0x001fbb00, + 0x84020398, +/* 0x041f: init_gpc */ + 0xb8502000, + 0x0008044e, + 0x8f7e1fb2, + 0x4eb80000, + 0xbd00010c, + 0x008f7ef4, + 0x044eb800, + 0x8f7e0001, + 0x4eb80000, + 0x0f000100, + 0x008f7e02, + 0x004eb800, +/* 0x044e: init_gpc_wait */ + 0x657e0008, + 0xffc80000, + 0xf90bf41f, + 0x08044eb8, + 0x00657e00, + 0x001fbb00, + 0x800040b7, + 0xf40132b6, + 0x000fb41b, + 0x0006f97e, + 0xa87e000f, + 0x00800006, + 0x01f60201, + 0xbd04bd00, + 0x1f19f014, + 0x02300080, + 0xbd0001f6, +/* 0x0491: main */ + 0x0031f404, + 0x0d0028f4, + 0x00377e10, + 0xf401f400, + 0x4001e4b1, + 0x00c71bf5, + 0x99f094bd, + 0x37008004, + 0x0009f602, + 0x008104bd, + 0x11cf02c0, + 0xc1008200, + 0x0022cf02, + 0xf41f13c8, + 0x23c8770b, + 0x550bf41f, + 0x12b220f9, + 0x99f094bd, + 0x37008007, + 0x0009f602, + 0x32f404bd, + 0x0231f401, + 0x00087c7e, + 0x99f094bd, + 0x17008007, + 0x0009f602, + 0x20fc04bd, + 0x99f094bd, + 0x37008006, + 0x0009f602, + 0x31f404bd, + 0x087c7e01, + 0xf094bd00, + 0x00800699, + 0x09f60217, + 0xf404bd00, +/* 0x0522: chsw_prev_no_next */ + 0x20f92f0e, + 0x32f412b2, + 0x0232f401, + 0x00087c7e, + 0x008020fc, + 0x02f602c0, + 0xf404bd00, +/* 0x053e: chsw_no_prev */ + 0x23c8130e, + 0x0d0bf41f, + 0xf40131f4, + 0x7c7e0232, +/* 0x054e: chsw_done */ + 0x01020008, + 0x02c30080, + 0xbd0002f6, + 0xf094bd04, + 0x00800499, + 0x09f60217, + 0xf504bd00, +/* 0x056b: main_not_ctx_switch */ + 0xb0ff2a0e, + 0x1bf401e4, + 0x7ef2b20c, + 0xf400081c, +/* 0x057a: main_not_ctx_chan */ + 0xe4b0400e, + 0x2c1bf402, + 0x99f094bd, + 0x37008007, + 0x0009f602, + 0x32f404bd, + 0x0232f401, + 0x00087c7e, + 0x99f094bd, + 0x17008007, + 0x0009f602, + 0x0ef404bd, +/* 0x05a9: main_not_ctx_save */ + 0x10ef9411, + 0x7e01f5f0, + 0xf50002f8, +/* 0x05b7: main_done */ + 0xbdfede0e, + 0x1f29f024, + 0x02300080, + 0xbd0002f6, + 0xcc0ef504, +/* 0x05c9: ih */ + 0xfe80f9fe, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0x004a04bd, + 0x00aacf02, + 0xf404abc4, + 0x100d230b, + 0xcf1a004e, + 0x004f00ee, + 0x00ffcf19, + 0x0000047e, + 0x0400b0b7, + 0x0040010e, + 0x000ef61d, +/* 0x060a: ih_no_fifo */ + 0xabe404bd, + 0x0bf40100, + 0x4e100d0c, + 0x047e4001, +/* 0x061a: ih_no_ctxsw */ + 0xabe40000, + 0x0bf40400, + 0x07088e56, + 0x00657e40, + 0x80ffb200, + 0xf6020400, + 0x04bd000f, + 0x4007048e, + 0x0000657e, + 0x0080ffb2, + 0x0ff60203, + 0xc704bd00, + 0xee9450fe, + 0x07008f02, + 0x00efbb40, + 0x0000657e, + 0x02020080, + 0xbd000ff6, + 0x7e030f04, + 0x4b0002f8, + 0xbfb20100, + 0x4001448e, + 0x00008f7e, +/* 0x0674: ih_no_fwmthd */ + 0xbd05044b, + 0xb4abffb0, + 0x800c0bf4, + 0xf6030700, + 0x04bd000b, +/* 0x0688: ih_no_other */ + 0xf6010040, + 0x04bd000a, + 0xe0fcf0fc, + 0xb0fcd0fc, + 0x90fca0fc, + 0x88fe80fc, + 0xf480fc00, + 0x01f80032, +/* 0x06a8: ctx_4170s */ + 0xb210f5f0, + 0x41708eff, + 0x008f7e40, +/* 0x06b7: ctx_4170w */ + 0x8e00f800, + 0x7e404170, + 0xb2000065, + 0x10f4f0ff, + 0xf8f31bf4, +/* 0x06c9: ctx_redswitch */ + 0x02004e00, + 0xf040e5f0, + 0xe5f020e5, + 0x85008010, + 0x000ef601, + 0x080f04bd, +/* 0x06e0: ctx_redswitch_delay */ + 0xf401f2b6, + 0xe5f1fd1b, + 0xe5f10400, + 0x00800100, + 0x0ef60185, + 0xf804bd00, +/* 0x06f9: ctx_86c */ + 0x23008000, + 0x000ff602, + 0xffb204bd, + 0x408a148e, + 0x00008f7e, + 0x8c8effb2, + 0x8f7e41a8, + 0x00f80000, +/* 0x0718: ctx_mem */ + 0x02840080, + 0xbd000ff6, +/* 0x0721: ctx_mem_wait */ + 0x84008f04, + 0x00ffcf02, + 0xf405fffd, + 0x00f8f61b, +/* 0x0730: ctx_load */ + 0x99f094bd, + 0x37008005, + 0x0009f602, + 0x0c0a04bd, + 0x0000b87e, + 0x0080f4bd, + 0x0ff60289, + 0x8004bd00, + 0xf602c100, + 0x04bd0002, + 0x02830080, + 0xbd0002f6, + 0x7e070f04, + 0x80000718, + 0xf602c000, + 0x04bd0002, + 0xf0000bfe, + 0x24b61f2a, + 0x0220b604, + 0x99f094bd, + 0x37008008, + 0x0009f602, + 0x008004bd, + 0x02f60281, + 0xd204bd00, + 0x80000000, + 0x800225f0, + 0xf6028800, + 0x04bd0002, + 0x00421001, + 0x0223f002, + 0xf80512fa, + 0xf094bd03, + 0x00800899, + 0x09f60217, + 0x9804bd00, + 0x14b68101, + 0x80029818, + 0xfd0825b6, + 0x01b50512, + 0xf094bd16, + 0x00800999, + 0x09f60237, + 0x8004bd00, + 0xf6028100, + 0x04bd0001, + 0x00800102, + 0x02f60288, + 0x4104bd00, + 0x13f00100, + 0x0501fa06, + 0x94bd03f8, + 0x800999f0, + 0xf6021700, + 0x04bd0009, + 0x99f094bd, + 0x17008005, + 0x0009f602, + 0x00f804bd, +/* 0x081c: ctx_chan */ + 0x0007307e, + 0xb87e0c0a, + 0x050f0000, + 0x0007187e, +/* 0x082e: ctx_mmio_exec */ + 0x039800f8, + 0x81008041, + 0x0003f602, + 0x34bd04bd, +/* 0x083c: ctx_mmio_loop */ + 0xf4ff34c4, + 0x00450e1b, + 0x0653f002, + 0xf80535fa, +/* 0x084d: ctx_mmio_pull */ + 0x804e9803, + 0x7e814f98, + 0xb600008f, + 0x12b60830, + 0xdf1bf401, +/* 0x0860: ctx_mmio_done */ + 0x80160398, + 0xf6028100, + 0x04bd0003, + 0x414000b5, + 0x13f00100, + 0x0601fa06, + 0x00f803f8, +/* 0x087c: ctx_xfer */ + 0x0080040e, + 0x0ef60302, +/* 0x0887: ctx_xfer_idle */ + 0x8e04bd00, + 0xcf030000, + 0xe4f100ee, + 0x1bf42000, + 0x0611f4f5, +/* 0x089b: ctx_xfer_pre */ + 0x0f0c02f4, + 0x06f97e10, + 0x1b11f400, +/* 0x08a4: ctx_xfer_pre_load */ + 0xa87e020f, + 0xb77e0006, + 0xc97e0006, + 0xf4bd0006, + 0x0006a87e, + 0x0007307e, +/* 0x08bc: ctx_xfer_exec */ + 0xbd160198, + 0x05008024, + 0x0002f601, + 0x1fb204bd, + 0x41a5008e, + 0x00008f7e, + 0xf001fcf0, + 0x24b6022c, + 0x05f2fd01, + 0x048effb2, + 0x8f7e41a5, + 0x167e0000, + 0x24bd0002, + 0x0247fc80, + 0xbd0002f6, + 0x012cf004, + 0x800320b6, + 0xf6024afc, + 0x04bd0002, + 0xf001acf0, + 0x000b06a5, + 0x98000c98, + 0x000e010d, + 0x00013d7e, + 0xec7e080a, + 0x0a7e0000, + 0x01f40002, + 0x7e0c0a12, + 0x0f0000b8, + 0x07187e05, + 0x2d02f400, +/* 0x0938: ctx_xfer_post */ + 0xa87e020f, + 0xf4bd0006, + 0x0006f97e, + 0x0002277e, + 0x0006b77e, + 0xa87ef4bd, + 0x11f40006, + 0x40019810, + 0xf40511fd, + 0x2e7e070b, +/* 0x0962: ctx_xfer_no_post_mmio */ +/* 0x0962: ctx_xfer_done */ + 0x00f80008, + 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, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h index b59f694c042..92dfe6a4ac8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h @@ -206,14 +206,14 @@ uint32_t nvc0_grhub_data[] = { }; uint32_t nvc0_grhub_code[] = { - 0x031b0ef5, + 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -237,184 +237,214 @@ uint32_t nvc0_grhub_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f00f00, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f00f, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f00f, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf00f0007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f00f00, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -428,7 +458,7 @@ uint32_t nvc0_grhub_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0x07f100f8, 0x03f00500, 0x000fd002, @@ -436,82 +466,117 @@ uint32_t nvc0_grhub_code[] = { 0x0007f101, 0x0303f007, 0xbd000fd0, -/* 0x031b: init */ +/* 0x039b: init */ 0xbd00f804, - 0x0004fe04, - 0xf10007fe, - 0xf0120017, - 0x12d00227, - 0xb117f100, - 0x0010fe05, - 0x040017f1, - 0xf1c010d0, - 0xb6040437, - 0x27f10634, - 0x32d02003, - 0x0427f100, - 0x0132d020, + 0x0007fe04, + 0x420017f1, + 0xcf0013f0, + 0x11e70011, + 0x14b60109, + 0x0014fe08, + 0xf10227f0, + 0xf0120007, + 0x02d00003, + 0xf104bd00, + 0xfe06c817, + 0x24bd0010, + 0x070007f1, + 0xd00003f0, + 0x04bd0002, + 0x200327f1, + 0x010007f1, + 0xd00103f0, + 0x04bd0002, + 0x200427f1, + 0x010407f1, + 0xd00103f0, + 0x04bd0002, 0x200b27f1, - 0xf10232d0, - 0xd0200c27, - 0x27f10732, - 0x24b60c24, - 0x0003b906, - 0xf10023d0, + 0x010807f1, + 0xd00103f0, + 0x04bd0002, + 0x200c27f1, + 0x011c07f1, + 0xd00103f0, + 0x04bd0002, + 0xf1010392, + 0xf0090007, + 0x03d00303, + 0xf104bd00, 0xf0870427, - 0x12d00023, - 0x0012b700, - 0x0427f001, - 0xf40012d0, - 0xe7f11031, - 0xe3f09604, - 0x6821f440, - 0x8090f1c7, - 0xf4f00301, - 0x020f801f, - 0xbb0117f0, - 0x12b6041f, - 0x0c27f101, - 0x0624b604, - 0xd00021d0, - 0x17f14021, - 0x0e980100, - 0x010f9800, - 0x014721f5, - 0x070037f1, - 0x950634b6, - 0x34d00814, - 0x4034d000, - 0x130030b7, - 0xb6001fbb, - 0x3fd002f5, - 0x0815b600, - 0xb60110b6, - 0x1fb90814, - 0x7121f502, - 0x001fbb02, - 0xf1020398, - 0xf0200047, -/* 0x03f6: init_gpc */ - 0x4ea05043, - 0x1fb90804, - 0x8d21f402, - 0x010c4ea0, - 0x21f4f4bd, - 0x044ea08d, - 0x8d21f401, - 0x01004ea0, - 0xf402f7f0, - 0x4ea08d21, -/* 0x041e: init_gpc_wait */ - 0x21f40800, - 0x1fffc868, - 0xa0fa0bf4, - 0xf408044e, - 0x1fbb6821, - 0x0040b700, - 0x0132b680, - 0xf1be1bf4, + 0x07f10023, + 0x03f00400, + 0x0002d000, + 0x27f004bd, + 0x0007f104, + 0x0003f003, + 0xbd0002d0, + 0x1031f404, + 0x9604e7f1, + 0xf440e3f0, + 0xfeb96821, + 0x90f1c702, + 0xf0030180, + 0x0f801ff4, + 0x0117f002, + 0xb6041fbb, + 0x07f10112, + 0x03f00300, + 0x0001d001, + 0x07f104bd, + 0x03f00400, + 0x0001d001, + 0x17f104bd, + 0xf7f00100, + 0x0d21f502, + 0x1f21f508, + 0x10f7f008, + 0x086c21f5, + 0x98000e98, + 0x21f5010f, + 0x14950150, + 0x0007f108, + 0x0103f0c0, + 0xbd0004d0, + 0x0007f104, + 0x0103f0c1, + 0xbd0004d0, + 0x0030b704, + 0x001fbb13, + 0xf102f5b6, + 0xf0d30007, + 0x0fd00103, + 0xb604bd00, + 0x10b60815, + 0x0814b601, + 0xf5021fb9, + 0xbb02d321, + 0x0398001f, + 0x0047f102, + 0x5043f020, +/* 0x04f4: init_gpc */ + 0x08044ea0, + 0xf4021fb9, + 0x4ea09d21, + 0xf4bd010c, + 0xa09d21f4, + 0xf401044e, + 0x4ea09d21, + 0xf7f00100, + 0x9d21f402, + 0x08004ea0, +/* 0x051c: init_gpc_wait */ + 0xc86821f4, + 0x0bf41fff, + 0x044ea0fa, + 0x6821f408, + 0xb7001fbb, + 0xb6800040, + 0x1bf40132, + 0x00f7f0be, + 0x086c21f5, + 0xf500f7f0, + 0xf1080d21, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -519,360 +584,421 @@ uint32_t nvc0_grhub_code[] = { 0x080007f1, 0xd00203f0, 0x04bd0001, -/* 0x0458: main */ +/* 0x0564: main */ 0xf40031f4, 0xd7f00028, 0x3921f410, 0xb1f401f4, 0xf54001e4, - 0xbd00de1b, + 0xbd00e91b, 0x0499f094, 0x0f0007f1, 0xd00203f0, 0x04bd0009, - 0x0b0017f1, - 0xcf0614b6, - 0x11cf4012, - 0x1f13c800, - 0x00870bf5, - 0xf41f23c8, - 0x20f9620b, - 0xbd0212b9, - 0x0799f094, - 0x0f0007f1, - 0xd00203f0, - 0x04bd0009, - 0xf40132f4, - 0x21f50231, - 0x94bd082f, + 0xc00017f1, + 0xcf0213f0, + 0x27f10011, + 0x23f0c100, + 0x0022cf02, + 0xf51f13c8, + 0xc800890b, + 0x0bf41f23, + 0xb920f962, + 0x94bd0212, 0xf10799f0, - 0xf0170007, + 0xf00f0007, 0x09d00203, - 0xfc04bd00, - 0xf094bd20, - 0x07f10699, - 0x03f00f00, - 0x0009d002, - 0x31f404bd, - 0x2f21f501, - 0xf094bd08, - 0x07f10699, + 0xf404bd00, + 0x31f40132, + 0x4021f502, + 0xf094bd0a, + 0x07f10799, 0x03f01700, 0x0009d002, - 0x0ef404bd, -/* 0x04f9: chsw_prev_no_next */ - 0xb920f931, - 0x32f40212, - 0x0232f401, - 0x082f21f5, - 0x17f120fc, - 0x14b60b00, - 0x0012d006, -/* 0x0517: chsw_no_prev */ - 0xc8130ef4, - 0x0bf41f23, - 0x0131f40d, - 0xf50232f4, -/* 0x0527: chsw_done */ - 0xf1082f21, - 0xb60b0c17, - 0x27f00614, - 0x0012d001, + 0x20fc04bd, 0x99f094bd, - 0x0007f104, + 0x0007f106, + 0x0203f00f, + 0xbd0009d0, + 0x0131f404, + 0x0a4021f5, + 0x99f094bd, + 0x0007f106, 0x0203f017, 0xbd0009d0, - 0x130ef504, -/* 0x0549: main_not_ctx_switch */ - 0x01e4b0ff, - 0xb90d1bf4, - 0x21f502f2, - 0x0ef407bb, -/* 0x0559: main_not_ctx_chan */ - 0x02e4b046, - 0xbd321bf4, - 0x0799f094, - 0x0f0007f1, + 0x330ef404, +/* 0x060c: chsw_prev_no_next */ + 0x12b920f9, + 0x0132f402, + 0xf50232f4, + 0xfc0a4021, + 0x0007f120, + 0x0203f0c0, + 0xbd0002d0, + 0x130ef404, +/* 0x062c: chsw_no_prev */ + 0xf41f23c8, + 0x31f40d0b, + 0x0232f401, + 0x0a4021f5, +/* 0x063c: chsw_done */ + 0xf10127f0, + 0xf0c30007, + 0x02d00203, + 0xbd04bd00, + 0x0499f094, + 0x170007f1, 0xd00203f0, 0x04bd0009, - 0xf40132f4, - 0x21f50232, - 0x94bd082f, + 0xff080ef5, +/* 0x0660: main_not_ctx_switch */ + 0xf401e4b0, + 0xf2b90d1b, + 0xd021f502, + 0x460ef409, +/* 0x0670: main_not_ctx_chan */ + 0xf402e4b0, + 0x94bd321b, 0xf10799f0, - 0xf0170007, + 0xf00f0007, 0x09d00203, 0xf404bd00, -/* 0x058e: main_not_ctx_save */ - 0xef94110e, - 0x01f5f010, - 0x02fe21f5, - 0xfec00ef5, -/* 0x059c: main_done */ - 0x29f024bd, - 0x0007f11f, - 0x0203f008, - 0xbd0002d0, - 0xab0ef504, -/* 0x05b1: ih */ - 0xfe80f9fe, - 0x80f90188, - 0xa0f990f9, - 0xd0f9b0f9, - 0xf0f9e0f9, - 0x0acf04bd, - 0x04abc480, - 0xf11d0bf4, - 0xf01900b7, - 0xbecf10d7, - 0x00bfcf40, + 0x32f40132, + 0x4021f502, + 0xf094bd0a, + 0x07f10799, + 0x03f01700, + 0x0009d002, + 0x0ef404bd, +/* 0x06a5: main_not_ctx_save */ + 0x10ef9411, + 0xf501f5f0, + 0xf5037e21, +/* 0x06b3: main_done */ + 0xbdfeb50e, + 0x1f29f024, + 0x080007f1, + 0xd00203f0, + 0x04bd0002, + 0xfea00ef5, +/* 0x06c8: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x10d7f030, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, 0xb70421f4, 0xf00400b0, - 0xbed001e7, -/* 0x05e9: ih_no_fifo */ - 0x00abe400, - 0x0d0bf401, - 0xf110d7f0, - 0xf44001e7, -/* 0x05fa: ih_no_ctxsw */ - 0xb7f10421, - 0xb0bd0104, - 0xf4b4abff, - 0xa7f10d0b, - 0xa4b60c1c, - 0x00abd006, -/* 0x0610: ih_no_other */ - 0xfc400ad0, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x071a: ih_no_fifo */ + 0xabe404bd, + 0x0bf40100, + 0x10d7f00d, + 0x4001e7f1, +/* 0x072b: ih_no_ctxsw */ + 0xe40421f4, + 0xf40400ab, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, + 0xbfb90100, + 0x44e7f102, + 0x40e3f001, +/* 0x079b: ih_no_fwmthd */ + 0xf19d21f4, + 0xbd0504b7, + 0xb4abffb0, + 0xf10f0bf4, + 0xf0070007, + 0x0bd00303, +/* 0x07b3: ih_no_other */ + 0xf104bd00, + 0xf0010007, + 0x0ad00003, + 0xfc04bd00, 0xfce0fcf0, 0xfcb0fcd0, 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x062b: ctx_4160s */ - 0xf101f800, - 0xf04160e7, - 0xf7f040e3, - 0x8d21f401, -/* 0x0638: ctx_4160s_wait */ - 0xc86821f4, - 0x0bf404ff, -/* 0x0643: ctx_4160c */ - 0xf100f8fa, +/* 0x07d7: ctx_4160s */ + 0xf001f800, + 0xffb901f7, + 0x60e7f102, + 0x40e3f041, +/* 0x07e7: ctx_4160s_wait */ + 0xf19d21f4, 0xf04160e7, - 0xf4bd40e3, - 0xf88d21f4, -/* 0x0651: ctx_4170s */ - 0x70e7f100, + 0x21f440e3, + 0x02ffb968, + 0xf404ffc8, + 0x00f8f00b, +/* 0x07fc: ctx_4160c */ + 0xffb9f4bd, + 0x60e7f102, 0x40e3f041, - 0xf410f5f0, - 0x00f88d21, -/* 0x0660: ctx_4170w */ - 0x4170e7f1, - 0xf440e3f0, - 0xf4f06821, - 0xf31bf410, -/* 0x0672: ctx_redswitch */ - 0xe7f100f8, - 0xe4b60614, - 0x70f7f106, - 0x00efd002, -/* 0x0683: ctx_redswitch_delay */ - 0xb608f7f0, - 0x1bf401f2, - 0x70f7f1fd, - 0x00efd007, -/* 0x0692: ctx_86c */ - 0xe7f100f8, - 0xe4b6086c, - 0x00efd006, - 0x8a14e7f1, - 0xf440e3f0, - 0xe7f18d21, - 0xe3f0a86c, - 0x8d21f441, -/* 0x06b2: ctx_load */ + 0xf89d21f4, +/* 0x080d: ctx_4170s */ + 0x10f5f000, + 0xf102ffb9, + 0xf04170e7, + 0x21f440e3, +/* 0x081f: ctx_4170w */ + 0xf100f89d, + 0xf04170e7, + 0x21f440e3, + 0x02ffb968, + 0xf410f4f0, + 0x00f8f01b, +/* 0x0834: ctx_redswitch */ + 0x0200e7f1, + 0xf040e5f0, + 0xe5f020e5, + 0x0007f110, + 0x0103f085, + 0xbd000ed0, + 0x08f7f004, +/* 0x0850: ctx_redswitch_delay */ + 0xf401f2b6, + 0xe5f1fd1b, + 0xe5f10400, + 0x07f10100, + 0x03f08500, + 0x000ed001, + 0x00f804bd, +/* 0x086c: ctx_86c */ + 0x1b0007f1, + 0xd00203f0, + 0x04bd000f, + 0xf102ffb9, + 0xf08a14e7, + 0x21f440e3, + 0x02ffb99d, + 0xa86ce7f1, + 0xf441e3f0, + 0x00f89d21, +/* 0x0894: ctx_mem */ + 0x840007f1, + 0xd00203f0, + 0x04bd000f, +/* 0x08a0: ctx_mem_wait */ + 0x8400f7f1, + 0xcf02f3f0, + 0xfffd00ff, + 0xf31bf405, +/* 0x08b2: ctx_load */ 0x94bd00f8, 0xf10599f0, 0xf00f0007, 0x09d00203, 0xf004bd00, 0x21f40ca7, - 0x2417f1c9, - 0x0614b60a, - 0xf10010d0, - 0xb60b0037, - 0x32d00634, - 0x0c17f140, - 0x0614b60a, - 0xd00747f0, - 0x14d00012, -/* 0x06ed: ctx_chan_wait_0 */ - 0x4014cf40, - 0xf41f44f0, - 0x32d0fa1b, - 0x000bfe00, - 0xb61f2af0, - 0x20b60424, - 0xf094bd02, + 0xf1f4bdd0, + 0xf0890007, + 0x0fd00203, + 0xf104bd00, + 0xf0c10007, + 0x02d00203, + 0xf104bd00, + 0xf0830007, + 0x02d00203, + 0xf004bd00, + 0x21f507f7, + 0x07f10894, + 0x03f0c000, + 0x0002d002, + 0x0bfe04bd, + 0x1f2af000, + 0xb60424b6, + 0x94bd0220, + 0xf10899f0, + 0xf00f0007, + 0x09d00203, + 0xf104bd00, + 0xf0810007, + 0x02d00203, + 0xf104bd00, + 0xf1000027, + 0xf0800023, + 0x07f10225, + 0x03f08800, + 0x0002d002, + 0x17f004bd, + 0x0027f110, + 0x0223f002, + 0xf80512fa, + 0xf094bd03, 0x07f10899, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x17f104bd, - 0x14b60a04, - 0x0012d006, - 0x0a2017f1, - 0xf00614b6, - 0x23f10227, - 0x12d08000, - 0x1017f000, - 0x020027f1, - 0xfa0223f0, - 0x03f80512, + 0x019804bd, + 0x1814b681, + 0xb6800298, + 0x12fd0825, + 0x16018005, 0x99f094bd, - 0x0007f108, - 0x0203f017, + 0x0007f109, + 0x0203f00f, 0xbd0009d0, - 0x81019804, - 0x981814b6, - 0x25b68002, - 0x0512fd08, - 0xbd160180, - 0x0999f094, - 0x0f0007f1, - 0xd00203f0, - 0x04bd0009, - 0x0a0427f1, - 0xd00624b6, - 0x27f00021, - 0x2017f101, - 0x0614b60a, - 0xf10012d0, - 0xf0010017, - 0x01fa0613, - 0xbd03f805, - 0x0999f094, - 0x170007f1, + 0x0007f104, + 0x0203f081, + 0xbd0001d0, + 0x0127f004, + 0x880007f1, 0xd00203f0, - 0x04bd0009, + 0x04bd0002, + 0x010017f1, + 0xfa0613f0, + 0x03f80501, 0x99f094bd, - 0x0007f105, + 0x0007f109, 0x0203f017, 0xbd0009d0, -/* 0x07bb: ctx_chan */ - 0xf500f804, - 0xf5062b21, - 0xf006b221, - 0x21f40ca7, - 0x1017f1c9, - 0x0614b60a, - 0xd00527f0, -/* 0x07d6: ctx_chan_wait */ - 0x12cf0012, - 0x0522fd00, - 0xf5fa1bf4, - 0xf8064321, -/* 0x07e5: ctx_mmio_exec */ - 0x41039800, - 0x0a0427f1, - 0xd00624b6, - 0x34bd0023, -/* 0x07f4: ctx_mmio_loop */ + 0xf094bd04, + 0x07f10599, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x09d0: ctx_chan */ + 0x07d721f5, + 0x08b221f5, + 0xf40ca7f0, + 0xf7f0d021, + 0x9421f505, + 0xfc21f508, +/* 0x09eb: ctx_mmio_exec */ + 0x9800f807, + 0x07f14103, + 0x03f08100, + 0x0003d002, + 0x34bd04bd, +/* 0x09fc: ctx_mmio_loop */ 0xf4ff34c4, 0x57f10f1b, 0x53f00200, 0x0535fa06, -/* 0x0806: ctx_mmio_pull */ +/* 0x0a0e: ctx_mmio_pull */ 0x4e9803f8, 0x814f9880, - 0xb68d21f4, + 0xb69d21f4, 0x12b60830, 0xdf1bf401, -/* 0x0818: ctx_mmio_done */ - 0xd0160398, - 0x00800023, - 0x0017f140, - 0x0613f001, - 0xf80601fa, -/* 0x082f: ctx_xfer */ - 0xf100f803, - 0xb60c00f7, - 0xe7f006f4, - 0x80fed004, -/* 0x083c: ctx_xfer_idle */ - 0xf100fecf, - 0xf42000e4, - 0x11f4f91b, - 0x1102f406, -/* 0x084c: ctx_xfer_pre */ - 0xf510f7f0, - 0xf5069221, - 0xf4062b21, -/* 0x085a: ctx_xfer_pre_load */ - 0xf7f01c11, - 0x5121f502, - 0x6021f506, - 0x7221f506, - 0xf5f4bd06, - 0xf5065121, -/* 0x0873: ctx_xfer_exec */ - 0x9806b221, - 0x27f11601, - 0x24b60414, - 0x0020d006, - 0xa500e7f1, - 0xb941e3f0, - 0x21f4021f, - 0x04e0b68d, - 0xf001fcf0, - 0x24b6022c, - 0x05f2fd01, - 0xf18d21f4, - 0xf04afc17, - 0x27f00213, - 0x0012d00c, - 0x021521f5, - 0x47fc27f1, - 0xd00223f0, - 0x2cf00020, +/* 0x0a20: ctx_mmio_done */ + 0xf1160398, + 0xf0810007, + 0x03d00203, + 0x8004bd00, + 0x17f14000, + 0x13f00100, + 0x0601fa06, + 0x00f803f8, +/* 0x0a40: ctx_xfer */ + 0xf104e7f0, + 0xf0020007, + 0x0ed00303, +/* 0x0a4f: ctx_xfer_idle */ + 0xf104bd00, + 0xf00000e7, + 0xeecf03e3, + 0x00e4f100, + 0xf21bf420, + 0xf40611f4, +/* 0x0a66: ctx_xfer_pre */ + 0xf7f01102, + 0x6c21f510, + 0xd721f508, + 0x1c11f407, +/* 0x0a74: ctx_xfer_pre_load */ + 0xf502f7f0, + 0xf5080d21, + 0xf5081f21, + 0xbd083421, + 0x0d21f5f4, + 0xb221f508, +/* 0x0a8d: ctx_xfer_exec */ + 0x16019808, + 0x07f124bd, + 0x03f00500, + 0x0002d001, + 0x1fb904bd, + 0x00e7f102, + 0x41e3f0a5, + 0xf09d21f4, + 0x2cf001fc, + 0x0124b602, + 0xb905f2fd, + 0xe7f102ff, + 0xe3f0a504, + 0x9d21f441, + 0x026a21f5, + 0x07f124bd, + 0x03f047fc, + 0x0002d002, + 0x2cf004bd, 0x0320b601, - 0xf00012d0, - 0xa5f001ac, - 0x00b7f006, - 0x98000c98, - 0xe7f0010d, - 0x6621f500, - 0x08a7f001, - 0x010921f5, - 0x021521f5, - 0xf02201f4, - 0x21f40ca7, - 0x1017f1c9, - 0x0614b60a, - 0xd00527f0, -/* 0x08fa: ctx_xfer_post_save_wait */ - 0x12cf0012, - 0x0522fd00, - 0xf4fa1bf4, -/* 0x0906: ctx_xfer_post */ - 0xf7f03202, - 0x5121f502, - 0xf5f4bd06, - 0xf5069221, - 0xf5023421, - 0xbd066021, - 0x5121f5f4, - 0x1011f406, - 0xfd400198, - 0x0bf40511, - 0xe521f507, -/* 0x0931: ctx_xfer_no_post_mmio */ - 0x4321f507, -/* 0x0935: ctx_xfer_done */ - 0x0000f806, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x4afc07f1, + 0xd00203f0, + 0x04bd0002, + 0xf001acf0, + 0xb7f006a5, + 0x000c9800, + 0xf0010d98, + 0x21f500e7, + 0xa7f0016f, + 0x1021f508, + 0x5e21f501, + 0x1301f402, + 0xf40ca7f0, + 0xf7f0d021, + 0x9421f505, + 0x3202f408, +/* 0x0b1c: ctx_xfer_post */ + 0xf502f7f0, + 0xbd080d21, + 0x6c21f5f4, + 0x7f21f508, + 0x1f21f502, + 0xf5f4bd08, + 0xf4080d21, + 0x01981011, + 0x0511fd40, + 0xf5070bf4, +/* 0x0b47: ctx_xfer_no_post_mmio */ + 0xf509eb21, +/* 0x0b4b: ctx_xfer_done */ + 0xf807fc21, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h index a1b9f763996..62b0c7601d8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h @@ -206,14 +206,14 @@ uint32_t nvd7_grhub_data[] = { }; uint32_t nvd7_grhub_code[] = { - 0x031b0ef5, + 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -237,184 +237,214 @@ uint32_t nvd7_grhub_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f00f00, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f00f, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f00f, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf00f0007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f00f00, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -428,7 +458,7 @@ uint32_t nvd7_grhub_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0x07f100f8, 0x03f00500, 0x000fd002, @@ -436,82 +466,117 @@ uint32_t nvd7_grhub_code[] = { 0x0007f101, 0x0303f007, 0xbd000fd0, -/* 0x031b: init */ +/* 0x039b: init */ 0xbd00f804, - 0x0004fe04, - 0xf10007fe, - 0xf0120017, - 0x12d00227, - 0xb117f100, - 0x0010fe05, - 0x040017f1, - 0xf1c010d0, - 0xb6040437, - 0x27f10634, - 0x32d02003, - 0x0427f100, - 0x0132d020, + 0x0007fe04, + 0x420017f1, + 0xcf0013f0, + 0x11e70011, + 0x14b60109, + 0x0014fe08, + 0xf10227f0, + 0xf0120007, + 0x02d00003, + 0xf104bd00, + 0xfe06c817, + 0x24bd0010, + 0x070007f1, + 0xd00003f0, + 0x04bd0002, + 0x200327f1, + 0x010007f1, + 0xd00103f0, + 0x04bd0002, + 0x200427f1, + 0x010407f1, + 0xd00103f0, + 0x04bd0002, 0x200b27f1, - 0xf10232d0, - 0xd0200c27, - 0x27f10732, - 0x24b60c24, - 0x0003b906, - 0xf10023d0, + 0x010807f1, + 0xd00103f0, + 0x04bd0002, + 0x200c27f1, + 0x011c07f1, + 0xd00103f0, + 0x04bd0002, + 0xf1010392, + 0xf0090007, + 0x03d00303, + 0xf104bd00, 0xf0870427, - 0x12d00023, - 0x0012b700, - 0x0427f001, - 0xf40012d0, - 0xe7f11031, - 0xe3f09604, - 0x6821f440, - 0x8090f1c7, - 0xf4f00301, - 0x020f801f, - 0xbb0117f0, - 0x12b6041f, - 0x0c27f101, - 0x0624b604, - 0xd00021d0, - 0x17f14021, - 0x0e980100, - 0x010f9800, - 0x014721f5, - 0x070037f1, - 0x950634b6, - 0x34d00814, - 0x4034d000, - 0x130030b7, - 0xb6001fbb, - 0x3fd002f5, - 0x0815b600, - 0xb60110b6, - 0x1fb90814, - 0x7121f502, - 0x001fbb02, - 0xf1020398, - 0xf0200047, -/* 0x03f6: init_gpc */ - 0x4ea05043, - 0x1fb90804, - 0x8d21f402, - 0x010c4ea0, - 0x21f4f4bd, - 0x044ea08d, - 0x8d21f401, - 0x01004ea0, - 0xf402f7f0, - 0x4ea08d21, -/* 0x041e: init_gpc_wait */ - 0x21f40800, - 0x1fffc868, - 0xa0fa0bf4, - 0xf408044e, - 0x1fbb6821, - 0x0040b700, - 0x0132b680, - 0xf1be1bf4, + 0x07f10023, + 0x03f00400, + 0x0002d000, + 0x27f004bd, + 0x0007f104, + 0x0003f003, + 0xbd0002d0, + 0x1031f404, + 0x9604e7f1, + 0xf440e3f0, + 0xfeb96821, + 0x90f1c702, + 0xf0030180, + 0x0f801ff4, + 0x0117f002, + 0xb6041fbb, + 0x07f10112, + 0x03f00300, + 0x0001d001, + 0x07f104bd, + 0x03f00400, + 0x0001d001, + 0x17f104bd, + 0xf7f00100, + 0x0d21f502, + 0x1f21f508, + 0x10f7f008, + 0x086c21f5, + 0x98000e98, + 0x21f5010f, + 0x14950150, + 0x0007f108, + 0x0103f0c0, + 0xbd0004d0, + 0x0007f104, + 0x0103f0c1, + 0xbd0004d0, + 0x0030b704, + 0x001fbb13, + 0xf102f5b6, + 0xf0d30007, + 0x0fd00103, + 0xb604bd00, + 0x10b60815, + 0x0814b601, + 0xf5021fb9, + 0xbb02d321, + 0x0398001f, + 0x0047f102, + 0x5043f020, +/* 0x04f4: init_gpc */ + 0x08044ea0, + 0xf4021fb9, + 0x4ea09d21, + 0xf4bd010c, + 0xa09d21f4, + 0xf401044e, + 0x4ea09d21, + 0xf7f00100, + 0x9d21f402, + 0x08004ea0, +/* 0x051c: init_gpc_wait */ + 0xc86821f4, + 0x0bf41fff, + 0x044ea0fa, + 0x6821f408, + 0xb7001fbb, + 0xb6800040, + 0x1bf40132, + 0x00f7f0be, + 0x086c21f5, + 0xf500f7f0, + 0xf1080d21, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -519,360 +584,421 @@ uint32_t nvd7_grhub_code[] = { 0x080007f1, 0xd00203f0, 0x04bd0001, -/* 0x0458: main */ +/* 0x0564: main */ 0xf40031f4, 0xd7f00028, 0x3921f410, 0xb1f401f4, 0xf54001e4, - 0xbd00de1b, + 0xbd00e91b, 0x0499f094, 0x0f0007f1, 0xd00203f0, 0x04bd0009, - 0x0b0017f1, - 0xcf0614b6, - 0x11cf4012, - 0x1f13c800, - 0x00870bf5, - 0xf41f23c8, - 0x20f9620b, - 0xbd0212b9, - 0x0799f094, - 0x0f0007f1, - 0xd00203f0, - 0x04bd0009, - 0xf40132f4, - 0x21f50231, - 0x94bd082f, + 0xc00017f1, + 0xcf0213f0, + 0x27f10011, + 0x23f0c100, + 0x0022cf02, + 0xf51f13c8, + 0xc800890b, + 0x0bf41f23, + 0xb920f962, + 0x94bd0212, 0xf10799f0, - 0xf0170007, + 0xf00f0007, 0x09d00203, - 0xfc04bd00, - 0xf094bd20, - 0x07f10699, - 0x03f00f00, - 0x0009d002, - 0x31f404bd, - 0x2f21f501, - 0xf094bd08, - 0x07f10699, + 0xf404bd00, + 0x31f40132, + 0x4021f502, + 0xf094bd0a, + 0x07f10799, 0x03f01700, 0x0009d002, - 0x0ef404bd, -/* 0x04f9: chsw_prev_no_next */ - 0xb920f931, - 0x32f40212, - 0x0232f401, - 0x082f21f5, - 0x17f120fc, - 0x14b60b00, - 0x0012d006, -/* 0x0517: chsw_no_prev */ - 0xc8130ef4, - 0x0bf41f23, - 0x0131f40d, - 0xf50232f4, -/* 0x0527: chsw_done */ - 0xf1082f21, - 0xb60b0c17, - 0x27f00614, - 0x0012d001, + 0x20fc04bd, 0x99f094bd, - 0x0007f104, + 0x0007f106, + 0x0203f00f, + 0xbd0009d0, + 0x0131f404, + 0x0a4021f5, + 0x99f094bd, + 0x0007f106, 0x0203f017, 0xbd0009d0, - 0x130ef504, -/* 0x0549: main_not_ctx_switch */ - 0x01e4b0ff, - 0xb90d1bf4, - 0x21f502f2, - 0x0ef407bb, -/* 0x0559: main_not_ctx_chan */ - 0x02e4b046, - 0xbd321bf4, - 0x0799f094, - 0x0f0007f1, + 0x330ef404, +/* 0x060c: chsw_prev_no_next */ + 0x12b920f9, + 0x0132f402, + 0xf50232f4, + 0xfc0a4021, + 0x0007f120, + 0x0203f0c0, + 0xbd0002d0, + 0x130ef404, +/* 0x062c: chsw_no_prev */ + 0xf41f23c8, + 0x31f40d0b, + 0x0232f401, + 0x0a4021f5, +/* 0x063c: chsw_done */ + 0xf10127f0, + 0xf0c30007, + 0x02d00203, + 0xbd04bd00, + 0x0499f094, + 0x170007f1, 0xd00203f0, 0x04bd0009, - 0xf40132f4, - 0x21f50232, - 0x94bd082f, + 0xff080ef5, +/* 0x0660: main_not_ctx_switch */ + 0xf401e4b0, + 0xf2b90d1b, + 0xd021f502, + 0x460ef409, +/* 0x0670: main_not_ctx_chan */ + 0xf402e4b0, + 0x94bd321b, 0xf10799f0, - 0xf0170007, + 0xf00f0007, 0x09d00203, 0xf404bd00, -/* 0x058e: main_not_ctx_save */ - 0xef94110e, - 0x01f5f010, - 0x02fe21f5, - 0xfec00ef5, -/* 0x059c: main_done */ - 0x29f024bd, - 0x0007f11f, - 0x0203f008, - 0xbd0002d0, - 0xab0ef504, -/* 0x05b1: ih */ - 0xfe80f9fe, - 0x80f90188, - 0xa0f990f9, - 0xd0f9b0f9, - 0xf0f9e0f9, - 0x0acf04bd, - 0x04abc480, - 0xf11d0bf4, - 0xf01900b7, - 0xbecf10d7, - 0x00bfcf40, + 0x32f40132, + 0x4021f502, + 0xf094bd0a, + 0x07f10799, + 0x03f01700, + 0x0009d002, + 0x0ef404bd, +/* 0x06a5: main_not_ctx_save */ + 0x10ef9411, + 0xf501f5f0, + 0xf5037e21, +/* 0x06b3: main_done */ + 0xbdfeb50e, + 0x1f29f024, + 0x080007f1, + 0xd00203f0, + 0x04bd0002, + 0xfea00ef5, +/* 0x06c8: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x10d7f030, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, 0xb70421f4, 0xf00400b0, - 0xbed001e7, -/* 0x05e9: ih_no_fifo */ - 0x00abe400, - 0x0d0bf401, - 0xf110d7f0, - 0xf44001e7, -/* 0x05fa: ih_no_ctxsw */ - 0xb7f10421, - 0xb0bd0104, - 0xf4b4abff, - 0xa7f10d0b, - 0xa4b60c1c, - 0x00abd006, -/* 0x0610: ih_no_other */ - 0xfc400ad0, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x071a: ih_no_fifo */ + 0xabe404bd, + 0x0bf40100, + 0x10d7f00d, + 0x4001e7f1, +/* 0x072b: ih_no_ctxsw */ + 0xe40421f4, + 0xf40400ab, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, + 0xbfb90100, + 0x44e7f102, + 0x40e3f001, +/* 0x079b: ih_no_fwmthd */ + 0xf19d21f4, + 0xbd0504b7, + 0xb4abffb0, + 0xf10f0bf4, + 0xf0070007, + 0x0bd00303, +/* 0x07b3: ih_no_other */ + 0xf104bd00, + 0xf0010007, + 0x0ad00003, + 0xfc04bd00, 0xfce0fcf0, 0xfcb0fcd0, 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x062b: ctx_4160s */ - 0xf101f800, - 0xf04160e7, - 0xf7f040e3, - 0x8d21f401, -/* 0x0638: ctx_4160s_wait */ - 0xc86821f4, - 0x0bf404ff, -/* 0x0643: ctx_4160c */ - 0xf100f8fa, +/* 0x07d7: ctx_4160s */ + 0xf001f800, + 0xffb901f7, + 0x60e7f102, + 0x40e3f041, +/* 0x07e7: ctx_4160s_wait */ + 0xf19d21f4, 0xf04160e7, - 0xf4bd40e3, - 0xf88d21f4, -/* 0x0651: ctx_4170s */ - 0x70e7f100, + 0x21f440e3, + 0x02ffb968, + 0xf404ffc8, + 0x00f8f00b, +/* 0x07fc: ctx_4160c */ + 0xffb9f4bd, + 0x60e7f102, 0x40e3f041, - 0xf410f5f0, - 0x00f88d21, -/* 0x0660: ctx_4170w */ - 0x4170e7f1, - 0xf440e3f0, - 0xf4f06821, - 0xf31bf410, -/* 0x0672: ctx_redswitch */ - 0xe7f100f8, - 0xe4b60614, - 0x70f7f106, - 0x00efd002, -/* 0x0683: ctx_redswitch_delay */ - 0xb608f7f0, - 0x1bf401f2, - 0x70f7f1fd, - 0x00efd007, -/* 0x0692: ctx_86c */ - 0xe7f100f8, - 0xe4b6086c, - 0x00efd006, - 0x8a14e7f1, - 0xf440e3f0, - 0xe7f18d21, - 0xe3f0a86c, - 0x8d21f441, -/* 0x06b2: ctx_load */ + 0xf89d21f4, +/* 0x080d: ctx_4170s */ + 0x10f5f000, + 0xf102ffb9, + 0xf04170e7, + 0x21f440e3, +/* 0x081f: ctx_4170w */ + 0xf100f89d, + 0xf04170e7, + 0x21f440e3, + 0x02ffb968, + 0xf410f4f0, + 0x00f8f01b, +/* 0x0834: ctx_redswitch */ + 0x0200e7f1, + 0xf040e5f0, + 0xe5f020e5, + 0x0007f110, + 0x0103f085, + 0xbd000ed0, + 0x08f7f004, +/* 0x0850: ctx_redswitch_delay */ + 0xf401f2b6, + 0xe5f1fd1b, + 0xe5f10400, + 0x07f10100, + 0x03f08500, + 0x000ed001, + 0x00f804bd, +/* 0x086c: ctx_86c */ + 0x1b0007f1, + 0xd00203f0, + 0x04bd000f, + 0xf102ffb9, + 0xf08a14e7, + 0x21f440e3, + 0x02ffb99d, + 0xa86ce7f1, + 0xf441e3f0, + 0x00f89d21, +/* 0x0894: ctx_mem */ + 0x840007f1, + 0xd00203f0, + 0x04bd000f, +/* 0x08a0: ctx_mem_wait */ + 0x8400f7f1, + 0xcf02f3f0, + 0xfffd00ff, + 0xf31bf405, +/* 0x08b2: ctx_load */ 0x94bd00f8, 0xf10599f0, 0xf00f0007, 0x09d00203, 0xf004bd00, 0x21f40ca7, - 0x2417f1c9, - 0x0614b60a, - 0xf10010d0, - 0xb60b0037, - 0x32d00634, - 0x0c17f140, - 0x0614b60a, - 0xd00747f0, - 0x14d00012, -/* 0x06ed: ctx_chan_wait_0 */ - 0x4014cf40, - 0xf41f44f0, - 0x32d0fa1b, - 0x000bfe00, - 0xb61f2af0, - 0x20b60424, - 0xf094bd02, + 0xf1f4bdd0, + 0xf0890007, + 0x0fd00203, + 0xf104bd00, + 0xf0c10007, + 0x02d00203, + 0xf104bd00, + 0xf0830007, + 0x02d00203, + 0xf004bd00, + 0x21f507f7, + 0x07f10894, + 0x03f0c000, + 0x0002d002, + 0x0bfe04bd, + 0x1f2af000, + 0xb60424b6, + 0x94bd0220, + 0xf10899f0, + 0xf00f0007, + 0x09d00203, + 0xf104bd00, + 0xf0810007, + 0x02d00203, + 0xf104bd00, + 0xf1000027, + 0xf0800023, + 0x07f10225, + 0x03f08800, + 0x0002d002, + 0x17f004bd, + 0x0027f110, + 0x0223f002, + 0xf80512fa, + 0xf094bd03, 0x07f10899, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x17f104bd, - 0x14b60a04, - 0x0012d006, - 0x0a2017f1, - 0xf00614b6, - 0x23f10227, - 0x12d08000, - 0x1017f000, - 0x020027f1, - 0xfa0223f0, - 0x03f80512, + 0x019804bd, + 0x1814b681, + 0xb6800298, + 0x12fd0825, + 0x16018005, 0x99f094bd, - 0x0007f108, - 0x0203f017, + 0x0007f109, + 0x0203f00f, 0xbd0009d0, - 0x81019804, - 0x981814b6, - 0x25b68002, - 0x0512fd08, - 0xbd160180, - 0x0999f094, - 0x0f0007f1, - 0xd00203f0, - 0x04bd0009, - 0x0a0427f1, - 0xd00624b6, - 0x27f00021, - 0x2017f101, - 0x0614b60a, - 0xf10012d0, - 0xf0010017, - 0x01fa0613, - 0xbd03f805, - 0x0999f094, - 0x170007f1, + 0x0007f104, + 0x0203f081, + 0xbd0001d0, + 0x0127f004, + 0x880007f1, 0xd00203f0, - 0x04bd0009, + 0x04bd0002, + 0x010017f1, + 0xfa0613f0, + 0x03f80501, 0x99f094bd, - 0x0007f105, + 0x0007f109, 0x0203f017, 0xbd0009d0, -/* 0x07bb: ctx_chan */ - 0xf500f804, - 0xf5062b21, - 0xf006b221, - 0x21f40ca7, - 0x1017f1c9, - 0x0614b60a, - 0xd00527f0, -/* 0x07d6: ctx_chan_wait */ - 0x12cf0012, - 0x0522fd00, - 0xf5fa1bf4, - 0xf8064321, -/* 0x07e5: ctx_mmio_exec */ - 0x41039800, - 0x0a0427f1, - 0xd00624b6, - 0x34bd0023, -/* 0x07f4: ctx_mmio_loop */ + 0xf094bd04, + 0x07f10599, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x09d0: ctx_chan */ + 0x07d721f5, + 0x08b221f5, + 0xf40ca7f0, + 0xf7f0d021, + 0x9421f505, + 0xfc21f508, +/* 0x09eb: ctx_mmio_exec */ + 0x9800f807, + 0x07f14103, + 0x03f08100, + 0x0003d002, + 0x34bd04bd, +/* 0x09fc: ctx_mmio_loop */ 0xf4ff34c4, 0x57f10f1b, 0x53f00200, 0x0535fa06, -/* 0x0806: ctx_mmio_pull */ +/* 0x0a0e: ctx_mmio_pull */ 0x4e9803f8, 0x814f9880, - 0xb68d21f4, + 0xb69d21f4, 0x12b60830, 0xdf1bf401, -/* 0x0818: ctx_mmio_done */ - 0xd0160398, - 0x00800023, - 0x0017f140, - 0x0613f001, - 0xf80601fa, -/* 0x082f: ctx_xfer */ - 0xf100f803, - 0xb60c00f7, - 0xe7f006f4, - 0x80fed004, -/* 0x083c: ctx_xfer_idle */ - 0xf100fecf, - 0xf42000e4, - 0x11f4f91b, - 0x1102f406, -/* 0x084c: ctx_xfer_pre */ - 0xf510f7f0, - 0xf5069221, - 0xf4062b21, -/* 0x085a: ctx_xfer_pre_load */ - 0xf7f01c11, - 0x5121f502, - 0x6021f506, - 0x7221f506, - 0xf5f4bd06, - 0xf5065121, -/* 0x0873: ctx_xfer_exec */ - 0x9806b221, - 0x27f11601, - 0x24b60414, - 0x0020d006, - 0xa500e7f1, - 0xb941e3f0, - 0x21f4021f, - 0x04e0b68d, - 0xf001fcf0, - 0x24b6022c, - 0x05f2fd01, - 0xf18d21f4, - 0xf04afc17, - 0x27f00213, - 0x0012d00c, - 0x021521f5, - 0x47fc27f1, - 0xd00223f0, - 0x2cf00020, +/* 0x0a20: ctx_mmio_done */ + 0xf1160398, + 0xf0810007, + 0x03d00203, + 0x8004bd00, + 0x17f14000, + 0x13f00100, + 0x0601fa06, + 0x00f803f8, +/* 0x0a40: ctx_xfer */ + 0xf104e7f0, + 0xf0020007, + 0x0ed00303, +/* 0x0a4f: ctx_xfer_idle */ + 0xf104bd00, + 0xf00000e7, + 0xeecf03e3, + 0x00e4f100, + 0xf21bf420, + 0xf40611f4, +/* 0x0a66: ctx_xfer_pre */ + 0xf7f01102, + 0x6c21f510, + 0xd721f508, + 0x1c11f407, +/* 0x0a74: ctx_xfer_pre_load */ + 0xf502f7f0, + 0xf5080d21, + 0xf5081f21, + 0xbd083421, + 0x0d21f5f4, + 0xb221f508, +/* 0x0a8d: ctx_xfer_exec */ + 0x16019808, + 0x07f124bd, + 0x03f00500, + 0x0002d001, + 0x1fb904bd, + 0x00e7f102, + 0x41e3f0a5, + 0xf09d21f4, + 0x2cf001fc, + 0x0124b602, + 0xb905f2fd, + 0xe7f102ff, + 0xe3f0a504, + 0x9d21f441, + 0x026a21f5, + 0x07f124bd, + 0x03f047fc, + 0x0002d002, + 0x2cf004bd, 0x0320b601, - 0xf00012d0, - 0xa5f001ac, - 0x00b7f006, - 0x98000c98, - 0xe7f0010d, - 0x6621f500, - 0x08a7f001, - 0x010921f5, - 0x021521f5, - 0xf02201f4, - 0x21f40ca7, - 0x1017f1c9, - 0x0614b60a, - 0xd00527f0, -/* 0x08fa: ctx_xfer_post_save_wait */ - 0x12cf0012, - 0x0522fd00, - 0xf4fa1bf4, -/* 0x0906: ctx_xfer_post */ - 0xf7f03202, - 0x5121f502, - 0xf5f4bd06, - 0xf5069221, - 0xf5023421, - 0xbd066021, - 0x5121f5f4, - 0x1011f406, - 0xfd400198, - 0x0bf40511, - 0xe521f507, -/* 0x0931: ctx_xfer_no_post_mmio */ - 0x4321f507, -/* 0x0935: ctx_xfer_done */ - 0x0000f806, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x4afc07f1, + 0xd00203f0, + 0x04bd0002, + 0xf001acf0, + 0xb7f006a5, + 0x000c9800, + 0xf0010d98, + 0x21f500e7, + 0xa7f0016f, + 0x1021f508, + 0x5e21f501, + 0x1301f402, + 0xf40ca7f0, + 0xf7f0d021, + 0x9421f505, + 0x3202f408, +/* 0x0b1c: ctx_xfer_post */ + 0xf502f7f0, + 0xbd080d21, + 0x6c21f5f4, + 0x7f21f508, + 0x1f21f502, + 0xf5f4bd08, + 0xf4080d21, + 0x01981011, + 0x0511fd40, + 0xf5070bf4, +/* 0x0b47: ctx_xfer_no_post_mmio */ + 0xf509eb21, +/* 0x0b4b: ctx_xfer_done */ + 0xf807fc21, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h index eb7bc0e9576..51c3797d853 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h @@ -206,14 +206,14 @@ uint32_t nve0_grhub_data[] = { }; uint32_t nve0_grhub_code[] = { - 0x031b0ef5, + 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -237,184 +237,214 @@ uint32_t nve0_grhub_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f00f00, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f00f, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f00f00, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f00f, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf00f0007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f00f00, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x0f0007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -428,7 +458,7 @@ uint32_t nve0_grhub_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0x07f100f8, 0x03f00500, 0x000fd002, @@ -436,82 +466,117 @@ uint32_t nve0_grhub_code[] = { 0x0007f101, 0x0303f007, 0xbd000fd0, -/* 0x031b: init */ +/* 0x039b: init */ 0xbd00f804, - 0x0004fe04, - 0xf10007fe, - 0xf0120017, - 0x12d00227, - 0xb117f100, - 0x0010fe05, - 0x040017f1, - 0xf1c010d0, - 0xb6040437, - 0x27f10634, - 0x32d02003, - 0x0427f100, - 0x0132d020, + 0x0007fe04, + 0x420017f1, + 0xcf0013f0, + 0x11e70011, + 0x14b60109, + 0x0014fe08, + 0xf10227f0, + 0xf0120007, + 0x02d00003, + 0xf104bd00, + 0xfe06c817, + 0x24bd0010, + 0x070007f1, + 0xd00003f0, + 0x04bd0002, + 0x200327f1, + 0x010007f1, + 0xd00103f0, + 0x04bd0002, + 0x200427f1, + 0x010407f1, + 0xd00103f0, + 0x04bd0002, 0x200b27f1, - 0xf10232d0, - 0xd0200c27, - 0x27f10732, - 0x24b60c24, - 0x0003b906, - 0xf10023d0, + 0x010807f1, + 0xd00103f0, + 0x04bd0002, + 0x200c27f1, + 0x011c07f1, + 0xd00103f0, + 0x04bd0002, + 0xf1010392, + 0xf0090007, + 0x03d00303, + 0xf104bd00, 0xf0870427, - 0x12d00023, - 0x0012b700, - 0x0427f001, - 0xf40012d0, - 0xe7f11031, - 0xe3f09604, - 0x6821f440, - 0x8090f1c7, - 0xf4f00301, - 0x020f801f, - 0xbb0117f0, - 0x12b6041f, - 0x0c27f101, - 0x0624b604, - 0xd00021d0, - 0x17f14021, - 0x0e980100, - 0x010f9800, - 0x014721f5, - 0x070037f1, - 0x950634b6, - 0x34d00814, - 0x4034d000, - 0x130030b7, - 0xb6001fbb, - 0x3fd002f5, - 0x0815b600, - 0xb60110b6, - 0x1fb90814, - 0x7121f502, - 0x001fbb02, - 0xf1020398, - 0xf0200047, -/* 0x03f6: init_gpc */ - 0x4ea05043, - 0x1fb90804, - 0x8d21f402, - 0x010c4ea0, - 0x21f4f4bd, - 0x044ea08d, - 0x8d21f401, - 0x01004ea0, - 0xf402f7f0, - 0x4ea08d21, -/* 0x041e: init_gpc_wait */ - 0x21f40800, - 0x1fffc868, - 0xa0fa0bf4, - 0xf408044e, - 0x1fbb6821, - 0x0040b700, - 0x0132b680, - 0xf1be1bf4, + 0x07f10023, + 0x03f00400, + 0x0002d000, + 0x27f004bd, + 0x0007f104, + 0x0003f003, + 0xbd0002d0, + 0x1031f404, + 0x9604e7f1, + 0xf440e3f0, + 0xfeb96821, + 0x90f1c702, + 0xf0030180, + 0x0f801ff4, + 0x0117f002, + 0xb6041fbb, + 0x07f10112, + 0x03f00300, + 0x0001d001, + 0x07f104bd, + 0x03f00400, + 0x0001d001, + 0x17f104bd, + 0xf7f00100, + 0xd721f502, + 0xe921f507, + 0x10f7f007, + 0x083621f5, + 0x98000e98, + 0x21f5010f, + 0x14950150, + 0x0007f108, + 0x0103f0c0, + 0xbd0004d0, + 0x0007f104, + 0x0103f0c1, + 0xbd0004d0, + 0x0030b704, + 0x001fbb13, + 0xf102f5b6, + 0xf0d30007, + 0x0fd00103, + 0xb604bd00, + 0x10b60815, + 0x0814b601, + 0xf5021fb9, + 0xbb02d321, + 0x0398001f, + 0x0047f102, + 0x5043f020, +/* 0x04f4: init_gpc */ + 0x08044ea0, + 0xf4021fb9, + 0x4ea09d21, + 0xf4bd010c, + 0xa09d21f4, + 0xf401044e, + 0x4ea09d21, + 0xf7f00100, + 0x9d21f402, + 0x08004ea0, +/* 0x051c: init_gpc_wait */ + 0xc86821f4, + 0x0bf41fff, + 0x044ea0fa, + 0x6821f408, + 0xb7001fbb, + 0xb6800040, + 0x1bf40132, + 0x00f7f0be, + 0x083621f5, + 0xf500f7f0, + 0xf107d721, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -519,340 +584,401 @@ uint32_t nve0_grhub_code[] = { 0x080007f1, 0xd00203f0, 0x04bd0001, -/* 0x0458: main */ +/* 0x0564: main */ 0xf40031f4, 0xd7f00028, 0x3921f410, 0xb1f401f4, 0xf54001e4, - 0xbd00de1b, + 0xbd00e91b, 0x0499f094, 0x0f0007f1, 0xd00203f0, 0x04bd0009, - 0x0b0017f1, - 0xcf0614b6, - 0x11cf4012, - 0x1f13c800, - 0x00870bf5, - 0xf41f23c8, - 0x20f9620b, - 0xbd0212b9, - 0x0799f094, - 0x0f0007f1, - 0xd00203f0, - 0x04bd0009, - 0xf40132f4, - 0x21f50231, - 0x94bd0801, + 0xc00017f1, + 0xcf0213f0, + 0x27f10011, + 0x23f0c100, + 0x0022cf02, + 0xf51f13c8, + 0xc800890b, + 0x0bf41f23, + 0xb920f962, + 0x94bd0212, 0xf10799f0, - 0xf0170007, + 0xf00f0007, 0x09d00203, - 0xfc04bd00, - 0xf094bd20, - 0x07f10699, - 0x03f00f00, - 0x0009d002, - 0x31f404bd, - 0x0121f501, - 0xf094bd08, - 0x07f10699, + 0xf404bd00, + 0x31f40132, + 0x0221f502, + 0xf094bd0a, + 0x07f10799, 0x03f01700, 0x0009d002, - 0x0ef404bd, -/* 0x04f9: chsw_prev_no_next */ - 0xb920f931, - 0x32f40212, - 0x0232f401, - 0x080121f5, - 0x17f120fc, - 0x14b60b00, - 0x0012d006, -/* 0x0517: chsw_no_prev */ - 0xc8130ef4, - 0x0bf41f23, - 0x0131f40d, - 0xf50232f4, -/* 0x0527: chsw_done */ - 0xf1080121, - 0xb60b0c17, - 0x27f00614, - 0x0012d001, + 0x20fc04bd, 0x99f094bd, - 0x0007f104, + 0x0007f106, + 0x0203f00f, + 0xbd0009d0, + 0x0131f404, + 0x0a0221f5, + 0x99f094bd, + 0x0007f106, 0x0203f017, 0xbd0009d0, - 0x130ef504, -/* 0x0549: main_not_ctx_switch */ - 0x01e4b0ff, - 0xb90d1bf4, - 0x21f502f2, - 0x0ef40795, -/* 0x0559: main_not_ctx_chan */ - 0x02e4b046, - 0xbd321bf4, - 0x0799f094, - 0x0f0007f1, + 0x330ef404, +/* 0x060c: chsw_prev_no_next */ + 0x12b920f9, + 0x0132f402, + 0xf50232f4, + 0xfc0a0221, + 0x0007f120, + 0x0203f0c0, + 0xbd0002d0, + 0x130ef404, +/* 0x062c: chsw_no_prev */ + 0xf41f23c8, + 0x31f40d0b, + 0x0232f401, + 0x0a0221f5, +/* 0x063c: chsw_done */ + 0xf10127f0, + 0xf0c30007, + 0x02d00203, + 0xbd04bd00, + 0x0499f094, + 0x170007f1, 0xd00203f0, 0x04bd0009, - 0xf40132f4, - 0x21f50232, - 0x94bd0801, + 0xff080ef5, +/* 0x0660: main_not_ctx_switch */ + 0xf401e4b0, + 0xf2b90d1b, + 0x9a21f502, + 0x460ef409, +/* 0x0670: main_not_ctx_chan */ + 0xf402e4b0, + 0x94bd321b, 0xf10799f0, - 0xf0170007, + 0xf00f0007, 0x09d00203, 0xf404bd00, -/* 0x058e: main_not_ctx_save */ - 0xef94110e, - 0x01f5f010, - 0x02fe21f5, - 0xfec00ef5, -/* 0x059c: main_done */ - 0x29f024bd, - 0x0007f11f, - 0x0203f008, - 0xbd0002d0, - 0xab0ef504, -/* 0x05b1: ih */ - 0xfe80f9fe, - 0x80f90188, - 0xa0f990f9, - 0xd0f9b0f9, - 0xf0f9e0f9, - 0x0acf04bd, - 0x04abc480, - 0xf11d0bf4, - 0xf01900b7, - 0xbecf10d7, - 0x00bfcf40, + 0x32f40132, + 0x0221f502, + 0xf094bd0a, + 0x07f10799, + 0x03f01700, + 0x0009d002, + 0x0ef404bd, +/* 0x06a5: main_not_ctx_save */ + 0x10ef9411, + 0xf501f5f0, + 0xf5037e21, +/* 0x06b3: main_done */ + 0xbdfeb50e, + 0x1f29f024, + 0x080007f1, + 0xd00203f0, + 0x04bd0002, + 0xfea00ef5, +/* 0x06c8: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x10d7f030, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, 0xb70421f4, 0xf00400b0, - 0xbed001e7, -/* 0x05e9: ih_no_fifo */ - 0x00abe400, - 0x0d0bf401, - 0xf110d7f0, - 0xf44001e7, -/* 0x05fa: ih_no_ctxsw */ - 0xb7f10421, - 0xb0bd0104, - 0xf4b4abff, - 0xa7f10d0b, - 0xa4b60c1c, - 0x00abd006, -/* 0x0610: ih_no_other */ - 0xfc400ad0, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x071a: ih_no_fifo */ + 0xabe404bd, + 0x0bf40100, + 0x10d7f00d, + 0x4001e7f1, +/* 0x072b: ih_no_ctxsw */ + 0xe40421f4, + 0xf40400ab, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, + 0xbfb90100, + 0x44e7f102, + 0x40e3f001, +/* 0x079b: ih_no_fwmthd */ + 0xf19d21f4, + 0xbd0504b7, + 0xb4abffb0, + 0xf10f0bf4, + 0xf0070007, + 0x0bd00303, +/* 0x07b3: ih_no_other */ + 0xf104bd00, + 0xf0010007, + 0x0ad00003, + 0xfc04bd00, 0xfce0fcf0, 0xfcb0fcd0, 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x062b: ctx_4170s */ - 0xf101f800, - 0xf04170e7, - 0xf5f040e3, - 0x8d21f410, -/* 0x063a: ctx_4170w */ +/* 0x07d7: ctx_4170s */ + 0xf001f800, + 0xffb910f5, + 0x70e7f102, + 0x40e3f041, + 0xf89d21f4, +/* 0x07e9: ctx_4170w */ + 0x70e7f100, + 0x40e3f041, + 0xb96821f4, + 0xf4f002ff, + 0xf01bf410, +/* 0x07fe: ctx_redswitch */ 0xe7f100f8, - 0xe3f04170, - 0x6821f440, - 0xf410f4f0, + 0xe5f00200, + 0x20e5f040, + 0xf110e5f0, + 0xf0850007, + 0x0ed00103, + 0xf004bd00, +/* 0x081a: ctx_redswitch_delay */ + 0xf2b608f7, + 0xfd1bf401, + 0x0400e5f1, + 0x0100e5f1, + 0x850007f1, + 0xd00103f0, + 0x04bd000e, +/* 0x0836: ctx_86c */ + 0x07f100f8, + 0x03f01b00, + 0x000fd002, + 0xffb904bd, + 0x14e7f102, + 0x40e3f08a, + 0xb99d21f4, + 0xe7f102ff, + 0xe3f0a86c, + 0x9d21f441, +/* 0x085e: ctx_mem */ + 0x07f100f8, + 0x03f08400, + 0x000fd002, +/* 0x086a: ctx_mem_wait */ + 0xf7f104bd, + 0xf3f08400, + 0x00ffcf02, + 0xf405fffd, 0x00f8f31b, -/* 0x064c: ctx_redswitch */ - 0x0614e7f1, - 0xf106e4b6, - 0xd00270f7, - 0xf7f000ef, -/* 0x065d: ctx_redswitch_delay */ - 0x01f2b608, - 0xf1fd1bf4, - 0xd00770f7, - 0x00f800ef, -/* 0x066c: ctx_86c */ - 0x086ce7f1, - 0xd006e4b6, - 0xe7f100ef, - 0xe3f08a14, - 0x8d21f440, - 0xa86ce7f1, - 0xf441e3f0, - 0x00f88d21, -/* 0x068c: ctx_load */ +/* 0x087c: ctx_load */ 0x99f094bd, 0x0007f105, 0x0203f00f, 0xbd0009d0, 0x0ca7f004, - 0xf1c921f4, - 0xb60a2417, - 0x10d00614, - 0x0037f100, - 0x0634b60b, - 0xf14032d0, - 0xb60a0c17, - 0x47f00614, - 0x0012d007, -/* 0x06c7: ctx_chan_wait_0 */ - 0xcf4014d0, - 0x44f04014, - 0xfa1bf41f, - 0xfe0032d0, - 0x2af0000b, - 0x0424b61f, - 0xbd0220b6, + 0xbdd021f4, + 0x0007f1f4, + 0x0203f089, + 0xbd000fd0, + 0x0007f104, + 0x0203f0c1, + 0xbd0002d0, + 0x0007f104, + 0x0203f083, + 0xbd0002d0, + 0x07f7f004, + 0x085e21f5, + 0xc00007f1, + 0xd00203f0, + 0x04bd0002, + 0xf0000bfe, + 0x24b61f2a, + 0x0220b604, + 0x99f094bd, + 0x0007f108, + 0x0203f00f, + 0xbd0009d0, + 0x0007f104, + 0x0203f081, + 0xbd0002d0, + 0x0027f104, + 0x0023f100, + 0x0225f080, + 0x880007f1, + 0xd00203f0, + 0x04bd0002, + 0xf11017f0, + 0xf0020027, + 0x12fa0223, + 0xbd03f805, 0x0899f094, - 0x0f0007f1, + 0x170007f1, 0xd00203f0, 0x04bd0009, - 0x0a0417f1, - 0xd00614b6, - 0x17f10012, - 0x14b60a20, - 0x0227f006, - 0x800023f1, - 0xf00012d0, - 0x27f11017, - 0x23f00200, - 0x0512fa02, - 0x94bd03f8, - 0xf10899f0, - 0xf0170007, + 0xb6810198, + 0x02981814, + 0x0825b680, + 0x800512fd, + 0x94bd1601, + 0xf10999f0, + 0xf00f0007, 0x09d00203, - 0x9804bd00, - 0x14b68101, - 0x80029818, - 0xfd0825b6, - 0x01800512, - 0xf094bd16, - 0x07f10999, - 0x03f00f00, - 0x0009d002, - 0x27f104bd, - 0x24b60a04, - 0x0021d006, - 0xf10127f0, - 0xb60a2017, - 0x12d00614, - 0x0017f100, - 0x0613f001, - 0xf80501fa, - 0xf094bd03, - 0x07f10999, - 0x03f01700, - 0x0009d002, - 0x94bd04bd, - 0xf10599f0, + 0xf104bd00, + 0xf0810007, + 0x01d00203, + 0xf004bd00, + 0x07f10127, + 0x03f08800, + 0x0002d002, + 0x17f104bd, + 0x13f00100, + 0x0501fa06, + 0x94bd03f8, + 0xf10999f0, 0xf0170007, 0x09d00203, - 0xf804bd00, -/* 0x0795: ctx_chan */ - 0x8c21f500, - 0x0ca7f006, - 0xf1c921f4, - 0xb60a1017, - 0x27f00614, - 0x0012d005, -/* 0x07ac: ctx_chan_wait */ - 0xfd0012cf, - 0x1bf40522, -/* 0x07b7: ctx_mmio_exec */ - 0x9800f8fa, - 0x27f14103, - 0x24b60a04, - 0x0023d006, -/* 0x07c6: ctx_mmio_loop */ + 0xbd04bd00, + 0x0599f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x099a: ctx_chan */ + 0x21f500f8, + 0xa7f0087c, + 0xd021f40c, + 0xf505f7f0, + 0xf8085e21, +/* 0x09ad: ctx_mmio_exec */ + 0x41039800, + 0x810007f1, + 0xd00203f0, + 0x04bd0003, +/* 0x09be: ctx_mmio_loop */ 0x34c434bd, 0x0f1bf4ff, 0x020057f1, 0xfa0653f0, 0x03f80535, -/* 0x07d8: ctx_mmio_pull */ +/* 0x09d0: ctx_mmio_pull */ 0x98804e98, 0x21f4814f, - 0x0830b68d, + 0x0830b69d, 0xf40112b6, -/* 0x07ea: ctx_mmio_done */ +/* 0x09e2: ctx_mmio_done */ 0x0398df1b, - 0x0023d016, - 0xf1400080, - 0xf0010017, - 0x01fa0613, - 0xf803f806, -/* 0x0801: ctx_xfer */ - 0x00f7f100, - 0x06f4b60c, - 0xd004e7f0, -/* 0x080e: ctx_xfer_idle */ - 0xfecf80fe, - 0x00e4f100, - 0xf91bf420, - 0xf40611f4, -/* 0x081e: ctx_xfer_pre */ - 0xf7f00d02, - 0x6c21f510, - 0x1c11f406, -/* 0x0828: ctx_xfer_pre_load */ - 0xf502f7f0, - 0xf5062b21, - 0xf5063a21, - 0xbd064c21, - 0x2b21f5f4, - 0x8c21f506, -/* 0x0841: ctx_xfer_exec */ - 0x16019806, - 0x041427f1, - 0xd00624b6, - 0xe7f10020, - 0xe3f0a500, - 0x021fb941, - 0xb68d21f4, - 0xfcf004e0, - 0x022cf001, - 0xfd0124b6, - 0x21f405f2, - 0xfc17f18d, - 0x0213f04a, - 0xd00c27f0, - 0x21f50012, - 0x27f10215, - 0x23f047fc, - 0x0020d002, + 0x0007f116, + 0x0203f081, + 0xbd0003d0, + 0x40008004, + 0x010017f1, + 0xfa0613f0, + 0x03f80601, +/* 0x0a02: ctx_xfer */ + 0xe7f000f8, + 0x0007f104, + 0x0303f002, + 0xbd000ed0, +/* 0x0a11: ctx_xfer_idle */ + 0x00e7f104, + 0x03e3f000, + 0xf100eecf, + 0xf42000e4, + 0x11f4f21b, + 0x0d02f406, +/* 0x0a28: ctx_xfer_pre */ + 0xf510f7f0, + 0xf4083621, +/* 0x0a32: ctx_xfer_pre_load */ + 0xf7f01c11, + 0xd721f502, + 0xe921f507, + 0xfe21f507, + 0xf5f4bd07, + 0xf507d721, +/* 0x0a4b: ctx_xfer_exec */ + 0x98087c21, + 0x24bd1601, + 0x050007f1, + 0xd00103f0, + 0x04bd0002, + 0xf1021fb9, + 0xf0a500e7, + 0x21f441e3, + 0x01fcf09d, + 0xb6022cf0, + 0xf2fd0124, + 0x02ffb905, + 0xa504e7f1, + 0xf441e3f0, + 0x21f59d21, + 0x24bd026a, + 0x47fc07f1, + 0xd00203f0, + 0x04bd0002, 0xb6012cf0, - 0x12d00320, - 0x01acf000, - 0xf006a5f0, - 0x0c9800b7, - 0x010d9800, - 0xf500e7f0, - 0xf0016621, - 0x21f508a7, - 0x21f50109, - 0x01f40215, - 0x0ca7f022, - 0xf1c921f4, - 0xb60a1017, - 0x27f00614, - 0x0012d005, -/* 0x08c8: ctx_xfer_post_save_wait */ - 0xfd0012cf, - 0x1bf40522, - 0x2e02f4fa, -/* 0x08d4: ctx_xfer_post */ - 0xf502f7f0, - 0xbd062b21, - 0x6c21f5f4, - 0x3421f506, - 0x3a21f502, - 0xf5f4bd06, - 0xf4062b21, - 0x01981011, - 0x0511fd40, - 0xf5070bf4, -/* 0x08ff: ctx_xfer_no_post_mmio */ -/* 0x08ff: ctx_xfer_done */ - 0xf807b721, - 0x00000000, - 0x00000000, + 0x07f10320, + 0x03f04afc, + 0x0002d002, + 0xacf004bd, + 0x06a5f001, + 0x9800b7f0, + 0x0d98000c, + 0x00e7f001, + 0x016f21f5, + 0xf508a7f0, + 0xf5011021, + 0xf4025e21, + 0xa7f01301, + 0xd021f40c, + 0xf505f7f0, + 0xf4085e21, +/* 0x0ada: ctx_xfer_post */ + 0xf7f02e02, + 0xd721f502, + 0xf5f4bd07, + 0xf5083621, + 0xf5027f21, + 0xbd07e921, + 0xd721f5f4, + 0x1011f407, + 0xfd400198, + 0x0bf40511, + 0xad21f507, +/* 0x0b05: ctx_xfer_no_post_mmio */ +/* 0x0b05: ctx_xfer_done */ + 0x0000f809, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h index 438506d1474..a0af4b703a8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h @@ -206,14 +206,14 @@ uint32_t nvf0_grhub_data[] = { }; uint32_t nvf0_grhub_code[] = { - 0x031b0ef5, + 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, 0x86f001d9, 0x0489b808, 0xf00c1bf4, 0x21f502f7, - 0x00f802fe, + 0x00f8037e, /* 0x001c: queue_put_next */ 0xb60798c4, 0x8dbb0384, @@ -237,184 +237,214 @@ uint32_t nvf0_grhub_code[] = { /* 0x0066: queue_get_done */ 0x00f80132, /* 0x0068: nv_rd32 */ - 0x0728b7f1, - 0xb906b4b6, - 0xc9f002ec, - 0x00bcd01f, -/* 0x0078: nv_rd32_wait */ - 0xc800bccf, - 0x1bf41fcc, - 0x06a7f0fa, - 0x010921f5, - 0xf840bfcf, -/* 0x008d: nv_wr32 */ - 0x28b7f100, - 0x06b4b607, - 0xb980bfd0, - 0xc9f002ec, - 0x1ec9f01f, -/* 0x00a3: nv_wr32_wait */ - 0xcf00bcd0, - 0xccc800bc, - 0xfa1bf41f, -/* 0x00ae: watchdog_reset */ - 0x87f100f8, - 0x84b60430, - 0x1ff9f006, - 0xf8008fd0, -/* 0x00bd: watchdog_clear */ - 0x3087f100, - 0x0684b604, - 0xf80080d0, -/* 0x00c9: wait_donez */ - 0xf094bd00, - 0x07f10099, - 0x03f03700, - 0x0009d002, - 0x07f104bd, - 0x03f00600, - 0x000ad002, -/* 0x00e6: wait_donez_ne */ - 0x87f104bd, - 0x83f00000, - 0x0088cf01, - 0xf4888aff, - 0x94bdf31b, - 0xf10099f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0109: wait_doneo */ - 0xf094bd00, + 0xf002ecb9, + 0x07f11fc9, + 0x03f0ca00, + 0x000cd001, +/* 0x007a: nv_rd32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0xa7f0f31b, + 0x1021f506, + 0x00f7f101, + 0x01f3f0cb, + 0xf800ffcf, +/* 0x009d: nv_wr32 */ + 0x0007f100, + 0x0103f0cc, + 0xbd000fd0, + 0x02ecb904, + 0xf01fc9f0, + 0x07f11ec9, + 0x03f0ca00, + 0x000cd001, +/* 0x00be: nv_wr32_wait */ + 0xc7f104bd, + 0xc3f0ca00, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f31b, +/* 0x00d0: wait_donez */ + 0x99f094bd, + 0x0007f100, + 0x0203f037, + 0xbd0009d0, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x00ed: wait_donez_ne */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x1bf4888a, + 0xf094bdf3, 0x07f10099, - 0x03f03700, + 0x03f01700, 0x0009d002, - 0x87f104bd, - 0x84b60818, - 0x008ad006, -/* 0x0124: wait_doneo_e */ - 0x040087f1, - 0xcf0684b6, - 0x8aff0088, - 0xf30bf488, + 0x00f804bd, +/* 0x0110: wait_doneo */ 0x99f094bd, 0x0007f100, - 0x0203f017, + 0x0203f037, 0xbd0009d0, -/* 0x0147: mmctx_size */ - 0xbd00f804, -/* 0x0149: nv_mmctx_size_loop */ - 0x00e89894, - 0xb61a85b6, - 0x84b60180, - 0x0098bb02, - 0xb804e0b6, - 0x1bf404ef, - 0x029fb9eb, -/* 0x0166: mmctx_xfer */ - 0x94bd00f8, - 0xf10199f0, - 0xf0370007, - 0x09d00203, - 0xf104bd00, - 0xb6071087, - 0x94bd0684, - 0xf405bbfd, - 0x8bd0090b, - 0x0099f000, -/* 0x018c: mmctx_base_disabled */ - 0xf405eefd, - 0x8ed00c0b, - 0xc08fd080, -/* 0x019b: mmctx_multi_disabled */ - 0xb70199f0, - 0xc8010080, + 0x0007f104, + 0x0203f006, + 0xbd000ad0, +/* 0x012d: wait_doneo_e */ + 0x0087f104, + 0x0183f000, + 0xff0088cf, + 0x0bf4888a, + 0xf094bdf3, + 0x07f10099, + 0x03f01700, + 0x0009d002, + 0x00f804bd, +/* 0x0150: mmctx_size */ +/* 0x0152: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0xf404efb8, + 0x9fb9eb1b, +/* 0x016f: mmctx_xfer */ + 0xbd00f802, + 0x0199f094, + 0x370007f1, + 0xd00203f0, + 0x04bd0009, + 0xbbfd94bd, + 0x120bf405, + 0xc40007f1, + 0xd00103f0, + 0x04bd000b, +/* 0x0197: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0x0007f11e, + 0x0103f0c6, + 0xbd000ed0, + 0x0007f104, + 0x0103f0c7, + 0xbd000fd0, + 0x0199f004, +/* 0x01b8: mmctx_multi_disabled */ + 0xb600abc8, + 0xb9f010b4, + 0x01aec80c, + 0xfd11e4b6, + 0x07f105be, + 0x03f0c500, + 0x000bd001, +/* 0x01d6: mmctx_exec_loop */ +/* 0x01d6: mmctx_wait_free */ + 0xe7f104bd, + 0xe3f0c500, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f30b, + 0x05e9fd00, + 0xc80007f1, + 0xd00103f0, + 0x04bd000e, + 0xb804c0b6, + 0x1bf404cd, + 0x02abc8d8, +/* 0x0207: mmctx_fini_wait */ + 0xf11f1bf4, + 0xf0c500b7, + 0xbbcf01b3, + 0x1fb4f000, + 0xf410b4b0, + 0xa7f0f01b, + 0xd021f405, +/* 0x0223: mmctx_stop */ + 0xc82b0ef4, 0xb4b600ab, 0x0cb9f010, - 0xb601aec8, - 0xbefd11e4, - 0x008bd005, -/* 0x01b4: mmctx_exec_loop */ -/* 0x01b4: mmctx_wait_free */ - 0xf0008ecf, - 0x0bf41fe4, - 0x00ce98fa, - 0xd005e9fd, - 0xc0b6c08e, - 0x04cdb804, - 0xc8e81bf4, - 0x1bf402ab, -/* 0x01d5: mmctx_fini_wait */ - 0x008bcf18, - 0xb01fb4f0, - 0x1bf410b4, - 0x02a7f0f7, - 0xf4c921f4, -/* 0x01ea: mmctx_stop */ - 0xabc81b0e, - 0x10b4b600, - 0xf00cb9f0, - 0x8bd012b9, -/* 0x01f9: mmctx_stop_wait */ - 0x008bcf00, - 0xf412bbc8, -/* 0x0202: mmctx_done */ - 0x94bdfa1b, - 0xf10199f0, - 0xf0170007, - 0x09d00203, - 0xf804bd00, -/* 0x0215: strand_wait */ - 0xf0a0f900, - 0x21f402a7, - 0xf8a0fcc9, -/* 0x0221: strand_pre */ - 0xfc87f100, - 0x0283f04a, - 0xd00c97f0, - 0x21f50089, - 0x00f80215, -/* 0x0234: strand_post */ - 0x4afc87f1, - 0xf00283f0, - 0x89d00d97, - 0x1521f500, -/* 0x0247: strand_set */ - 0xf100f802, - 0xf04ffca7, - 0xaba202a3, - 0xc7f00500, - 0x00acd00f, - 0xd00bc7f0, - 0x21f500bc, - 0xaed00215, - 0x0ac7f000, - 0xf500bcd0, - 0xf8021521, -/* 0x0271: strand_ctx_init */ - 0xf094bd00, - 0x07f10399, - 0x03f03700, + 0xf112b9f0, + 0xf0c50007, + 0x0bd00103, +/* 0x023b: mmctx_stop_wait */ + 0xf104bd00, + 0xf0c500b7, + 0xbbcf01b3, + 0x12bbc800, +/* 0x024b: mmctx_done */ + 0xbdf31bf4, + 0x0199f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x025e: strand_wait */ + 0xa0f900f8, + 0xf402a7f0, + 0xa0fcd021, +/* 0x026a: strand_pre */ + 0x97f000f8, + 0xfc07f10c, + 0x0203f04a, + 0xbd0009d0, + 0x5e21f504, +/* 0x027f: strand_post */ + 0xf000f802, + 0x07f10d97, + 0x03f04afc, 0x0009d002, 0x21f504bd, - 0xe7f00221, - 0x4721f503, - 0xfca7f102, - 0x02a3f046, - 0x0400aba0, - 0xf040a0d0, - 0xbcd001c7, - 0x1521f500, - 0x010c9202, - 0xf000acd0, - 0xbcd002c7, - 0x1521f500, - 0x3421f502, - 0x8087f102, - 0x0684b608, - 0xb70089cf, - 0x95220080, -/* 0x02ca: ctx_init_strand_loop */ + 0x00f8025e, +/* 0x0294: strand_set */ + 0xf10fc7f0, + 0xf04ffc07, + 0x0cd00203, + 0xf004bd00, + 0x07f10bc7, + 0x03f04afc, + 0x000cd002, + 0x07f104bd, + 0x03f04ffc, + 0x000ed002, + 0xc7f004bd, + 0xfc07f10a, + 0x0203f04a, + 0xbd000cd0, + 0x5e21f504, +/* 0x02d3: strand_ctx_init */ + 0xbd00f802, + 0x0399f094, + 0x370007f1, + 0xd00203f0, + 0x04bd0009, + 0x026a21f5, + 0xf503e7f0, + 0xbd029421, + 0xfc07f1c4, + 0x0203f047, + 0xbd000cd0, + 0x01c7f004, + 0x4afc07f1, + 0xd00203f0, + 0x04bd000c, + 0x025e21f5, + 0xf1010c92, + 0xf046fc07, + 0x0cd00203, + 0xf004bd00, + 0x07f102c7, + 0x03f04afc, + 0x000cd002, + 0x21f504bd, + 0x21f5025e, + 0x87f1027f, + 0x83f04200, + 0x0097f102, + 0x0293f020, + 0x950099cf, +/* 0x034a: ctx_init_strand_loop */ 0x8ed008fe, 0x408ed000, 0xb6808acf, @@ -428,7 +458,7 @@ uint32_t nvf0_grhub_code[] = { 0x170007f1, 0xd00203f0, 0x04bd0009, -/* 0x02fe: error */ +/* 0x037e: error */ 0x07f100f8, 0x03f00500, 0x000fd002, @@ -436,82 +466,117 @@ uint32_t nvf0_grhub_code[] = { 0x0007f101, 0x0303f007, 0xbd000fd0, -/* 0x031b: init */ +/* 0x039b: init */ 0xbd00f804, - 0x0004fe04, - 0xf10007fe, - 0xf0120017, - 0x12d00227, - 0xb117f100, - 0x0010fe05, - 0x040017f1, - 0xf1c010d0, - 0xb6040437, - 0x27f10634, - 0x32d02003, - 0x0427f100, - 0x0132d020, + 0x0007fe04, + 0x420017f1, + 0xcf0013f0, + 0x11e70011, + 0x14b60109, + 0x0014fe08, + 0xf10227f0, + 0xf0120007, + 0x02d00003, + 0xf104bd00, + 0xfe06c817, + 0x24bd0010, + 0x070007f1, + 0xd00003f0, + 0x04bd0002, + 0x200327f1, + 0x010007f1, + 0xd00103f0, + 0x04bd0002, + 0x200427f1, + 0x010407f1, + 0xd00103f0, + 0x04bd0002, 0x200b27f1, - 0xf10232d0, - 0xd0200c27, - 0x27f10732, - 0x24b60c24, - 0x0003b906, - 0xf10023d0, + 0x010807f1, + 0xd00103f0, + 0x04bd0002, + 0x200c27f1, + 0x011c07f1, + 0xd00103f0, + 0x04bd0002, + 0xf1010392, + 0xf0090007, + 0x03d00303, + 0xf104bd00, 0xf0870427, - 0x12d00023, - 0x0012b700, - 0x0427f001, - 0xf40012d0, - 0xe7f11031, - 0xe3f09604, - 0x6821f440, - 0x8090f1c7, - 0xf4f00301, - 0x020f801f, - 0xbb0117f0, - 0x12b6041f, - 0x0c27f101, - 0x0624b604, - 0xd00021d0, - 0x17f14021, - 0x0e980100, - 0x010f9800, - 0x014721f5, - 0x070037f1, - 0x950634b6, - 0x34d00814, - 0x4034d000, - 0x130030b7, - 0xb6001fbb, - 0x3fd002f5, - 0x0815b600, - 0xb60110b6, - 0x1fb90814, - 0x7121f502, - 0x001fbb02, - 0xf1020398, - 0xf0200047, -/* 0x03f6: init_gpc */ - 0x4ea05043, - 0x1fb90804, - 0x8d21f402, - 0x010c4ea0, - 0x21f4f4bd, - 0x044ea08d, - 0x8d21f401, - 0x01004ea0, - 0xf402f7f0, - 0x4ea08d21, -/* 0x041e: init_gpc_wait */ - 0x21f40800, - 0x1fffc868, - 0xa0fa0bf4, - 0xf408044e, - 0x1fbb6821, - 0x0040b700, - 0x0132b680, - 0xf1be1bf4, + 0x07f10023, + 0x03f00400, + 0x0002d000, + 0x27f004bd, + 0x0007f104, + 0x0003f003, + 0xbd0002d0, + 0x1031f404, + 0x9604e7f1, + 0xf440e3f0, + 0xfeb96821, + 0x90f1c702, + 0xf0030180, + 0x0f801ff4, + 0x0117f002, + 0xb6041fbb, + 0x07f10112, + 0x03f00300, + 0x0001d001, + 0x07f104bd, + 0x03f00400, + 0x0001d001, + 0x17f104bd, + 0xf7f00100, + 0xd721f502, + 0xe921f507, + 0x10f7f007, + 0x083621f5, + 0x98000e98, + 0x21f5010f, + 0x14950150, + 0x0007f108, + 0x0103f0c0, + 0xbd0004d0, + 0x0007f104, + 0x0103f0c1, + 0xbd0004d0, + 0x0030b704, + 0x001fbb13, + 0xf102f5b6, + 0xf0d30007, + 0x0fd00103, + 0xb604bd00, + 0x10b60815, + 0x0814b601, + 0xf5021fb9, + 0xbb02d321, + 0x0398001f, + 0x0047f102, + 0x5043f020, +/* 0x04f4: init_gpc */ + 0x08044ea0, + 0xf4021fb9, + 0x4ea09d21, + 0xf4bd010c, + 0xa09d21f4, + 0xf401044e, + 0x4ea09d21, + 0xf7f00100, + 0x9d21f402, + 0x08004ea0, +/* 0x051c: init_gpc_wait */ + 0xc86821f4, + 0x0bf41fff, + 0x044ea0fa, + 0x6821f408, + 0xb7001fbb, + 0xb6800040, + 0x1bf40132, + 0x00f7f0be, + 0x083621f5, + 0xf500f7f0, + 0xf107d721, 0xf0010007, 0x01d00203, 0xbd04bd00, @@ -519,340 +584,401 @@ uint32_t nvf0_grhub_code[] = { 0x300007f1, 0xd00203f0, 0x04bd0001, -/* 0x0458: main */ +/* 0x0564: main */ 0xf40031f4, 0xd7f00028, 0x3921f410, 0xb1f401f4, 0xf54001e4, - 0xbd00de1b, + 0xbd00e91b, 0x0499f094, 0x370007f1, 0xd00203f0, 0x04bd0009, - 0x0b0017f1, - 0xcf0614b6, - 0x11cf4012, - 0x1f13c800, - 0x00870bf5, - 0xf41f23c8, - 0x20f9620b, - 0xbd0212b9, - 0x0799f094, - 0x370007f1, - 0xd00203f0, - 0x04bd0009, - 0xf40132f4, - 0x21f50231, - 0x94bd0801, + 0xc00017f1, + 0xcf0213f0, + 0x27f10011, + 0x23f0c100, + 0x0022cf02, + 0xf51f13c8, + 0xc800890b, + 0x0bf41f23, + 0xb920f962, + 0x94bd0212, 0xf10799f0, - 0xf0170007, + 0xf0370007, 0x09d00203, - 0xfc04bd00, - 0xf094bd20, - 0x07f10699, - 0x03f03700, - 0x0009d002, - 0x31f404bd, - 0x0121f501, - 0xf094bd08, - 0x07f10699, + 0xf404bd00, + 0x31f40132, + 0x0221f502, + 0xf094bd0a, + 0x07f10799, 0x03f01700, 0x0009d002, - 0x0ef404bd, -/* 0x04f9: chsw_prev_no_next */ - 0xb920f931, - 0x32f40212, - 0x0232f401, - 0x080121f5, - 0x17f120fc, - 0x14b60b00, - 0x0012d006, -/* 0x0517: chsw_no_prev */ - 0xc8130ef4, - 0x0bf41f23, - 0x0131f40d, - 0xf50232f4, -/* 0x0527: chsw_done */ - 0xf1080121, - 0xb60b0c17, - 0x27f00614, - 0x0012d001, + 0x20fc04bd, 0x99f094bd, - 0x0007f104, + 0x0007f106, + 0x0203f037, + 0xbd0009d0, + 0x0131f404, + 0x0a0221f5, + 0x99f094bd, + 0x0007f106, 0x0203f017, 0xbd0009d0, - 0x130ef504, -/* 0x0549: main_not_ctx_switch */ - 0x01e4b0ff, - 0xb90d1bf4, - 0x21f502f2, - 0x0ef40795, -/* 0x0559: main_not_ctx_chan */ - 0x02e4b046, - 0xbd321bf4, - 0x0799f094, - 0x370007f1, + 0x330ef404, +/* 0x060c: chsw_prev_no_next */ + 0x12b920f9, + 0x0132f402, + 0xf50232f4, + 0xfc0a0221, + 0x0007f120, + 0x0203f0c0, + 0xbd0002d0, + 0x130ef404, +/* 0x062c: chsw_no_prev */ + 0xf41f23c8, + 0x31f40d0b, + 0x0232f401, + 0x0a0221f5, +/* 0x063c: chsw_done */ + 0xf10127f0, + 0xf0c30007, + 0x02d00203, + 0xbd04bd00, + 0x0499f094, + 0x170007f1, 0xd00203f0, 0x04bd0009, - 0xf40132f4, - 0x21f50232, - 0x94bd0801, + 0xff080ef5, +/* 0x0660: main_not_ctx_switch */ + 0xf401e4b0, + 0xf2b90d1b, + 0x9a21f502, + 0x460ef409, +/* 0x0670: main_not_ctx_chan */ + 0xf402e4b0, + 0x94bd321b, 0xf10799f0, - 0xf0170007, + 0xf0370007, 0x09d00203, 0xf404bd00, -/* 0x058e: main_not_ctx_save */ - 0xef94110e, - 0x01f5f010, - 0x02fe21f5, - 0xfec00ef5, -/* 0x059c: main_done */ - 0x29f024bd, - 0x0007f11f, - 0x0203f030, - 0xbd0002d0, - 0xab0ef504, -/* 0x05b1: ih */ - 0xfe80f9fe, - 0x80f90188, - 0xa0f990f9, - 0xd0f9b0f9, - 0xf0f9e0f9, - 0x0acf04bd, - 0x04abc480, - 0xf11d0bf4, - 0xf01900b7, - 0xbecf10d7, - 0x00bfcf40, + 0x32f40132, + 0x0221f502, + 0xf094bd0a, + 0x07f10799, + 0x03f01700, + 0x0009d002, + 0x0ef404bd, +/* 0x06a5: main_not_ctx_save */ + 0x10ef9411, + 0xf501f5f0, + 0xf5037e21, +/* 0x06b3: main_done */ + 0xbdfeb50e, + 0x1f29f024, + 0x300007f1, + 0xd00203f0, + 0x04bd0002, + 0xfea00ef5, +/* 0x06c8: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x10d7f030, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, 0xb70421f4, 0xf00400b0, - 0xbed001e7, -/* 0x05e9: ih_no_fifo */ - 0x00abe400, - 0x0d0bf401, - 0xf110d7f0, - 0xf44001e7, -/* 0x05fa: ih_no_ctxsw */ - 0xb7f10421, - 0xb0bd0104, - 0xf4b4abff, - 0xa7f10d0b, - 0xa4b60c1c, - 0x00abd006, -/* 0x0610: ih_no_other */ - 0xfc400ad0, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x071a: ih_no_fifo */ + 0xabe404bd, + 0x0bf40100, + 0x10d7f00d, + 0x4001e7f1, +/* 0x072b: ih_no_ctxsw */ + 0xe40421f4, + 0xf40400ab, + 0xe7f16c0b, + 0xe3f00708, + 0x6821f440, + 0xf102ffb9, + 0xf0040007, + 0x0fd00203, + 0xf104bd00, + 0xf00704e7, + 0x21f440e3, + 0x02ffb968, + 0x030007f1, + 0xd00203f0, + 0x04bd000f, + 0x9450fec7, + 0xf7f102ee, + 0xf3f00700, + 0x00efbb40, + 0xf16821f4, + 0xf0020007, + 0x0fd00203, + 0xf004bd00, + 0x21f503f7, + 0xb7f1037e, + 0xbfb90100, + 0x44e7f102, + 0x40e3f001, +/* 0x079b: ih_no_fwmthd */ + 0xf19d21f4, + 0xbd0504b7, + 0xb4abffb0, + 0xf10f0bf4, + 0xf0070007, + 0x0bd00303, +/* 0x07b3: ih_no_other */ + 0xf104bd00, + 0xf0010007, + 0x0ad00003, + 0xfc04bd00, 0xfce0fcf0, 0xfcb0fcd0, 0xfc90fca0, 0x0088fe80, 0x32f480fc, -/* 0x062b: ctx_4170s */ - 0xf101f800, - 0xf04170e7, - 0xf5f040e3, - 0x8d21f410, -/* 0x063a: ctx_4170w */ +/* 0x07d7: ctx_4170s */ + 0xf001f800, + 0xffb910f5, + 0x70e7f102, + 0x40e3f041, + 0xf89d21f4, +/* 0x07e9: ctx_4170w */ + 0x70e7f100, + 0x40e3f041, + 0xb96821f4, + 0xf4f002ff, + 0xf01bf410, +/* 0x07fe: ctx_redswitch */ 0xe7f100f8, - 0xe3f04170, - 0x6821f440, - 0xf410f4f0, + 0xe5f00200, + 0x20e5f040, + 0xf110e5f0, + 0xf0850007, + 0x0ed00103, + 0xf004bd00, +/* 0x081a: ctx_redswitch_delay */ + 0xf2b608f7, + 0xfd1bf401, + 0x0400e5f1, + 0x0100e5f1, + 0x850007f1, + 0xd00103f0, + 0x04bd000e, +/* 0x0836: ctx_86c */ + 0x07f100f8, + 0x03f02300, + 0x000fd002, + 0xffb904bd, + 0x14e7f102, + 0x40e3f08a, + 0xb99d21f4, + 0xe7f102ff, + 0xe3f0a88c, + 0x9d21f441, +/* 0x085e: ctx_mem */ + 0x07f100f8, + 0x03f08400, + 0x000fd002, +/* 0x086a: ctx_mem_wait */ + 0xf7f104bd, + 0xf3f08400, + 0x00ffcf02, + 0xf405fffd, 0x00f8f31b, -/* 0x064c: ctx_redswitch */ - 0x0614e7f1, - 0xf106e4b6, - 0xd00270f7, - 0xf7f000ef, -/* 0x065d: ctx_redswitch_delay */ - 0x01f2b608, - 0xf1fd1bf4, - 0xd00770f7, - 0x00f800ef, -/* 0x066c: ctx_86c */ - 0x086ce7f1, - 0xd006e4b6, - 0xe7f100ef, - 0xe3f08a14, - 0x8d21f440, - 0xa86ce7f1, - 0xf441e3f0, - 0x00f88d21, -/* 0x068c: ctx_load */ +/* 0x087c: ctx_load */ 0x99f094bd, 0x0007f105, 0x0203f037, 0xbd0009d0, 0x0ca7f004, - 0xf1c921f4, - 0xb60a2417, - 0x10d00614, - 0x0037f100, - 0x0634b60b, - 0xf14032d0, - 0xb60a0c17, - 0x47f00614, - 0x0012d007, -/* 0x06c7: ctx_chan_wait_0 */ - 0xcf4014d0, - 0x44f04014, - 0xfa1bf41f, - 0xfe0032d0, - 0x2af0000b, - 0x0424b61f, - 0xbd0220b6, + 0xbdd021f4, + 0x0007f1f4, + 0x0203f089, + 0xbd000fd0, + 0x0007f104, + 0x0203f0c1, + 0xbd0002d0, + 0x0007f104, + 0x0203f083, + 0xbd0002d0, + 0x07f7f004, + 0x085e21f5, + 0xc00007f1, + 0xd00203f0, + 0x04bd0002, + 0xf0000bfe, + 0x24b61f2a, + 0x0220b604, + 0x99f094bd, + 0x0007f108, + 0x0203f037, + 0xbd0009d0, + 0x0007f104, + 0x0203f081, + 0xbd0002d0, + 0x0027f104, + 0x0023f100, + 0x0225f080, + 0x880007f1, + 0xd00203f0, + 0x04bd0002, + 0xf11017f0, + 0xf0020027, + 0x12fa0223, + 0xbd03f805, 0x0899f094, - 0x370007f1, + 0x170007f1, 0xd00203f0, 0x04bd0009, - 0x0a0417f1, - 0xd00614b6, - 0x17f10012, - 0x14b60a20, - 0x0227f006, - 0x800023f1, - 0xf00012d0, - 0x27f11017, - 0x23f00200, - 0x0512fa02, - 0x94bd03f8, - 0xf10899f0, - 0xf0170007, + 0xb6810198, + 0x02981814, + 0x0825b680, + 0x800512fd, + 0x94bd1601, + 0xf10999f0, + 0xf0370007, 0x09d00203, - 0x9804bd00, - 0x14b68101, - 0x80029818, - 0xfd0825b6, - 0x01800512, - 0xf094bd16, - 0x07f10999, - 0x03f03700, - 0x0009d002, - 0x27f104bd, - 0x24b60a04, - 0x0021d006, - 0xf10127f0, - 0xb60a2017, - 0x12d00614, - 0x0017f100, - 0x0613f001, - 0xf80501fa, - 0xf094bd03, - 0x07f10999, - 0x03f01700, - 0x0009d002, - 0x94bd04bd, - 0xf10599f0, + 0xf104bd00, + 0xf0810007, + 0x01d00203, + 0xf004bd00, + 0x07f10127, + 0x03f08800, + 0x0002d002, + 0x17f104bd, + 0x13f00100, + 0x0501fa06, + 0x94bd03f8, + 0xf10999f0, 0xf0170007, 0x09d00203, - 0xf804bd00, -/* 0x0795: ctx_chan */ - 0x8c21f500, - 0x0ca7f006, - 0xf1c921f4, - 0xb60a1017, - 0x27f00614, - 0x0012d005, -/* 0x07ac: ctx_chan_wait */ - 0xfd0012cf, - 0x1bf40522, -/* 0x07b7: ctx_mmio_exec */ - 0x9800f8fa, - 0x27f14103, - 0x24b60a04, - 0x0023d006, -/* 0x07c6: ctx_mmio_loop */ + 0xbd04bd00, + 0x0599f094, + 0x170007f1, + 0xd00203f0, + 0x04bd0009, +/* 0x099a: ctx_chan */ + 0x21f500f8, + 0xa7f0087c, + 0xd021f40c, + 0xf505f7f0, + 0xf8085e21, +/* 0x09ad: ctx_mmio_exec */ + 0x41039800, + 0x810007f1, + 0xd00203f0, + 0x04bd0003, +/* 0x09be: ctx_mmio_loop */ 0x34c434bd, 0x0f1bf4ff, 0x020057f1, 0xfa0653f0, 0x03f80535, -/* 0x07d8: ctx_mmio_pull */ +/* 0x09d0: ctx_mmio_pull */ 0x98804e98, 0x21f4814f, - 0x0830b68d, + 0x0830b69d, 0xf40112b6, -/* 0x07ea: ctx_mmio_done */ +/* 0x09e2: ctx_mmio_done */ 0x0398df1b, - 0x0023d016, - 0xf1400080, - 0xf0010017, - 0x01fa0613, - 0xf803f806, -/* 0x0801: ctx_xfer */ - 0x00f7f100, - 0x06f4b60c, - 0xd004e7f0, -/* 0x080e: ctx_xfer_idle */ - 0xfecf80fe, - 0x00e4f100, - 0xf91bf420, - 0xf40611f4, -/* 0x081e: ctx_xfer_pre */ - 0xf7f00d02, - 0x6c21f510, - 0x1c11f406, -/* 0x0828: ctx_xfer_pre_load */ - 0xf502f7f0, - 0xf5062b21, - 0xf5063a21, - 0xbd064c21, - 0x2b21f5f4, - 0x8c21f506, -/* 0x0841: ctx_xfer_exec */ - 0x16019806, - 0x041427f1, - 0xd00624b6, - 0xe7f10020, - 0xe3f0a500, - 0x021fb941, - 0xb68d21f4, - 0xfcf004e0, - 0x022cf001, - 0xfd0124b6, - 0x21f405f2, - 0xfc17f18d, - 0x0213f04a, - 0xd00c27f0, - 0x21f50012, - 0x27f10215, - 0x23f047fc, - 0x0020d002, + 0x0007f116, + 0x0203f081, + 0xbd0003d0, + 0x40008004, + 0x010017f1, + 0xfa0613f0, + 0x03f80601, +/* 0x0a02: ctx_xfer */ + 0xe7f000f8, + 0x0007f104, + 0x0303f002, + 0xbd000ed0, +/* 0x0a11: ctx_xfer_idle */ + 0x00e7f104, + 0x03e3f000, + 0xf100eecf, + 0xf42000e4, + 0x11f4f21b, + 0x0d02f406, +/* 0x0a28: ctx_xfer_pre */ + 0xf510f7f0, + 0xf4083621, +/* 0x0a32: ctx_xfer_pre_load */ + 0xf7f01c11, + 0xd721f502, + 0xe921f507, + 0xfe21f507, + 0xf5f4bd07, + 0xf507d721, +/* 0x0a4b: ctx_xfer_exec */ + 0x98087c21, + 0x24bd1601, + 0x050007f1, + 0xd00103f0, + 0x04bd0002, + 0xf1021fb9, + 0xf0a500e7, + 0x21f441e3, + 0x01fcf09d, + 0xb6022cf0, + 0xf2fd0124, + 0x02ffb905, + 0xa504e7f1, + 0xf441e3f0, + 0x21f59d21, + 0x24bd026a, + 0x47fc07f1, + 0xd00203f0, + 0x04bd0002, 0xb6012cf0, - 0x12d00320, - 0x01acf000, - 0xf006a5f0, - 0x0c9800b7, - 0x010d9800, - 0xf500e7f0, - 0xf0016621, - 0x21f508a7, - 0x21f50109, - 0x01f40215, - 0x0ca7f022, - 0xf1c921f4, - 0xb60a1017, - 0x27f00614, - 0x0012d005, -/* 0x08c8: ctx_xfer_post_save_wait */ - 0xfd0012cf, - 0x1bf40522, - 0x2e02f4fa, -/* 0x08d4: ctx_xfer_post */ - 0xf502f7f0, - 0xbd062b21, - 0x6c21f5f4, - 0x3421f506, - 0x3a21f502, - 0xf5f4bd06, - 0xf4062b21, - 0x01981011, - 0x0511fd40, - 0xf5070bf4, -/* 0x08ff: ctx_xfer_no_post_mmio */ -/* 0x08ff: ctx_xfer_done */ - 0xf807b721, - 0x00000000, - 0x00000000, + 0x07f10320, + 0x03f04afc, + 0x0002d002, + 0xacf004bd, + 0x06a5f001, + 0x9800b7f0, + 0x0d98000c, + 0x00e7f001, + 0x016f21f5, + 0xf508a7f0, + 0xf5011021, + 0xf4025e21, + 0xa7f01301, + 0xd021f40c, + 0xf505f7f0, + 0xf4085e21, +/* 0x0ada: ctx_xfer_post */ + 0xf7f02e02, + 0xd721f502, + 0xf5f4bd07, + 0xf5083621, + 0xf5027f21, + 0xbd07e921, + 0xd721f5f4, + 0x1011f407, + 0xfd400198, + 0x0bf40511, + 0xad21f507, +/* 0x0b05: ctx_xfer_no_post_mmio */ +/* 0x0b05: ctx_xfer_done */ + 0x0000f809, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc index 33a5a82eccb..2a0b0f84429 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc @@ -28,28 +28,142 @@ #define GF117 0xd7 #define GK100 0xe0 #define GK110 0xf0 +#define GK208 0x108 +#define NV_PGRAPH_TRAPPED_ADDR 0x400704 +#define NV_PGRAPH_TRAPPED_DATA_LO 0x400708 +#define NV_PGRAPH_TRAPPED_DATA_HI 0x40070c + +#define NV_PGRAPH_FE_OBJECT_TABLE(n) ((n) * 4 + 0x400700) + +#define NV_PGRAPH_FECS_INTR_ACK 0x409004 +#define NV_PGRAPH_FECS_INTR 0x409008 +#define NV_PGRAPH_FECS_INTR_FWMTHD 0x00000400 +#define NV_PGRAPH_FECS_INTR_CHSW 0x00000100 +#define NV_PGRAPH_FECS_INTR_FIFO 0x00000004 +#define NV_PGRAPH_FECS_INTR_MODE 0x40900c +#define NV_PGRAPH_FECS_INTR_MODE_FIFO 0x00000004 +#define NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL 0x00000004 +#define NV_PGRAPH_FECS_INTR_MODE_FIFO_EDGE 0x00000000 +#define NV_PGRAPH_FECS_INTR_EN_SET 0x409010 +#define NV_PGRAPH_FECS_INTR_EN_SET_FIFO 0x00000004 +#define NV_PGRAPH_FECS_INTR_ROUTE 0x40901c +#define NV_PGRAPH_FECS_ACCESS 0x409048 +#define NV_PGRAPH_FECS_ACCESS_FIFO 0x00000002 +#define NV_PGRAPH_FECS_FIFO_DATA 0x409064 +#define NV_PGRAPH_FECS_FIFO_CMD 0x409068 +#define NV_PGRAPH_FECS_FIFO_ACK 0x409074 +#define NV_PGRAPH_FECS_CAPS 0x409108 #define NV_PGRAPH_FECS_SIGNAL 0x409400 +#define NV_PGRAPH_FECS_IROUTE 0x409404 +#define NV_PGRAPH_FECS_BAR_MASK0 0x40940c +#define NV_PGRAPH_FECS_BAR_MASK1 0x409410 +#define NV_PGRAPH_FECS_BAR 0x409414 +#define NV_PGRAPH_FECS_BAR_SET 0x409418 +#define NV_PGRAPH_FECS_RED_SWITCH 0x409614 +#define NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP 0x00000400 +#define NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC 0x00000200 +#define NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN 0x00000100 +#define NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP 0x00000040 +#define NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC 0x00000020 +#define NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN 0x00000010 +#define NV_PGRAPH_FECS_RED_SWITCH_PAUSE_GPC 0x00000002 +#define NV_PGRAPH_FECS_RED_SWITCH_PAUSE_MAIN 0x00000001 +#define NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE 0x409700 +#define NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE 0x409704 +#define NV_PGRAPH_FECS_MMCTX_LOAD_COUNT 0x40974c +#define NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE 0x409700 +#define NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE 0x409704 +#define NV_PGRAPH_FECS_MMCTX_BASE 0x409710 +#define NV_PGRAPH_FECS_MMCTX_CTRL 0x409714 +#define NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE 0x409718 +#define NV_PGRAPH_FECS_MMCTX_MULTI_MASK 0x40971c +#define NV_PGRAPH_FECS_MMCTX_QUEUE 0x409720 +#define NV_PGRAPH_FECS_MMIO_CTRL 0x409728 +#define NV_PGRAPH_FECS_MMIO_RDVAL 0x40972c +#define NV_PGRAPH_FECS_MMIO_WRVAL 0x409730 +#define NV_PGRAPH_FECS_MMCTX_LOAD_COUNT 0x40974c #if CHIPSET < GK110 #define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x409800) #define NV_PGRAPH_FECS_CC_SCRATCH_SET(n) ((n) * 4 + 0x409820) #define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x409840) +#define NV_PGRAPH_FECS_UNK86C 0x40986c #else #define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x409800) #define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x409840) +#define NV_PGRAPH_FECS_UNK86C 0x40988c #define NV_PGRAPH_FECS_CC_SCRATCH_SET(n) ((n) * 4 + 0x4098c0) #endif +#define NV_PGRAPH_FECS_STRANDS_CNT 0x409880 +#define NV_PGRAPH_FECS_STRAND_SAVE_SWBASE 0x409908 +#define NV_PGRAPH_FECS_STRAND_LOAD_SWBASE 0x40990c +#define NV_PGRAPH_FECS_STRAND_WORDS 0x409910 +#define NV_PGRAPH_FECS_STRAND_DATA 0x409918 +#define NV_PGRAPH_FECS_STRAND_SELECT 0x40991c +#define NV_PGRAPH_FECS_STRAND_CMD 0x409928 +#define NV_PGRAPH_FECS_STRAND_CMD_SEEK 0x00000001 +#define NV_PGRAPH_FECS_STRAND_CMD_GET_INFO 0x00000002 +#define NV_PGRAPH_FECS_STRAND_CMD_SAVE 0x00000003 +#define NV_PGRAPH_FECS_STRAND_CMD_LOAD 0x00000004 +#define NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER 0x0000000a +#define NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER 0x0000000b +#define NV_PGRAPH_FECS_STRAND_CMD_ENABLE 0x0000000c +#define NV_PGRAPH_FECS_STRAND_CMD_DISABLE 0x0000000d +#define NV_PGRAPH_FECS_STRAND_FILTER 0x40993c +#define NV_PGRAPH_FECS_MEM_BASE 0x409a04 +#define NV_PGRAPH_FECS_MEM_CHAN 0x409a0c +#define NV_PGRAPH_FECS_MEM_CMD 0x409a10 +#define NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN 0x00000007 +#define NV_PGRAPH_FECS_MEM_TARGET 0x409a20 +#define NV_PGRAPH_FECS_MEM_TARGET_UNK31 0x80000000 +#define NV_PGRAPH_FECS_MEM_TARGET_AS 0x0000001f +#define NV_PGRAPH_FECS_MEM_TARGET_AS_VM 0x00000001 +#define NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM 0x00000002 +#define NV_PGRAPH_FECS_CHAN_ADDR 0x409b00 +#define NV_PGRAPH_FECS_CHAN_NEXT 0x409b04 +#define NV_PGRAPH_FECS_CHSW 0x409b0c +#define NV_PGRAPH_FECS_CHSW_ACK 0x00000001 #define NV_PGRAPH_FECS_INTR_UP_SET 0x409c1c +#define NV_PGRAPH_FECS_INTR_UP_EN 0x409c24 +#define NV_PGRAPH_GPCX_GPCCS_INTR_ACK 0x41a004 +#define NV_PGRAPH_GPCX_GPCCS_INTR 0x41a008 +#define NV_PGRAPH_GPCX_GPCCS_INTR_FIFO 0x00000004 +#define NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET 0x41a010 +#define NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO 0x00000004 +#define NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE 0x41a01c +#define NV_PGRAPH_GPCX_GPCCS_ACCESS 0x41a048 +#define NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO 0x00000002 +#define NV_PGRAPH_GPCX_GPCCS_FIFO_DATA 0x41a064 +#define NV_PGRAPH_GPCX_GPCCS_FIFO_CMD 0x41a068 +#define NV_PGRAPH_GPCX_GPCCS_FIFO_ACK 0x41a074 +#define NV_PGRAPH_GPCX_GPCCS_UNITS 0x41a608 +#define NV_PGRAPH_GPCX_GPCCS_CAPS 0x41a108 +#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH 0x41a614 +#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11 0x00000800 +#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE 0x00000200 +#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER 0x00000020 +#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_PAUSE 0x00000002 +#define NV_PGRAPH_GPCX_GPCCS_MYINDEX 0x41a618 +#define NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE 0x41a700 +#define NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE 0x41a704 +#define NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT 0x41a74c #if CHIPSET < GK110 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x41a800) #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n) ((n) * 4 + 0x41a820) #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x41a840) +#define NV_PGRAPH_GPCX_GPCCS_UNK86C 0x41a86c #else #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x41a800) #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x41a840) +#define NV_PGRAPH_GPCX_GPCCS_UNK86C 0x41a88c #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n) ((n) * 4 + 0x41a8c0) #endif +#define NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT 0x41a91c +#define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD 0x41a928 +#define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE 0x00000003 +#define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_LOAD 0x00000004 +#define NV_PGRAPH_GPCX_GPCCS_MEM_BASE 0x41aa04 #define mmctx_data(r,c) .b32 (((c - 1) << 26) | r) #define queue_init .skip 72 // (2 * 4) + ((8 * 4) * 2) @@ -65,24 +179,50 @@ #define T_LCHAN 8 #define T_LCTXH 9 -#define nv_mkmm(rv,r) /* -*/ movw rv ((r) & 0x0000fffc) /* -*/ sethi rv ((r) & 0x00ff0000) +#if CHIPSET < GK208 +#define imm32(reg,val) /* +*/ movw reg ((val) & 0x0000ffff) /* +*/ sethi reg ((val) & 0xffff0000) +#else +#define imm32(reg,val) /* +*/ mov reg (val) +#endif + #define nv_mkio(rv,r,i) /* -*/ nv_mkmm(rv, (((r) & 0xffc) << 6) | ((i) << 2)) +*/ imm32(rv, (((r) & 0xffc) << 6) | ((i) << 2)) + +#define hash # +#define fn(a) a +#if CHIPSET < GK208 +#define call(a) call fn(hash)a +#else +#define call(a) lcall fn(hash)a +#endif #define nv_iord(rv,r,i) /* */ nv_mkio(rv,r,i) /* */ iord rv I[rv] + #define nv_iowr(r,i,rv) /* */ nv_mkio($r0,r,i) /* */ iowr I[$r0] rv /* */ clear b32 $r0 +#define nv_rd32(reg,addr) /* +*/ imm32($r14, addr) /* +*/ call(nv_rd32) /* +*/ mov b32 reg $r15 + +#define nv_wr32(addr,reg) /* +*/ mov b32 $r15 reg /* +*/ imm32($r14, addr) /* +*/ call(nv_wr32) + #define trace_set(bit) /* */ clear b32 $r9 /* */ bset $r9 bit /* */ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(7), 0, $r9) + #define trace_clr(bit) /* */ clear b32 $r9 /* */ bset $r9 bit /* diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h index fd1d380de09..1718ae4e822 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h @@ -3,5 +3,6 @@ #define E_BAD_COMMAND 0x00000001 #define E_CMD_OVERFLOW 0x00000002 +#define E_BAD_FWMTHD 0x00000003 #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c new file mode 100644 index 00000000000..83048a56430 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c @@ -0,0 +1,47 @@ +/* + * 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 "nvc0.h" +#include "ctxnvc0.h" + +static struct nouveau_oclass +gk20a_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0xa040, &nouveau_object_ofuncs }, + { 0xa297, &nouveau_object_ofuncs }, + { 0xa0c0, &nouveau_object_ofuncs }, + {} +}; + +struct nouveau_oclass * +gk20a_graph_oclass = &(struct nvc0_graph_oclass) { + .base.handle = NV_ENGINE(GR, 0xea), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_ctor, + .dtor = nvc0_graph_dtor, + .init = nve4_graph_init, + .fini = nve4_graph_fini, + }, + .cclass = &gk20a_grctx_oclass, + .sclass = gk20a_graph_sclass, + .mmio = nve4_graph_pack_mmio, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c new file mode 100644 index 00000000000..21c5f31d607 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c @@ -0,0 +1,465 @@ +/* + * 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 <subdev/bios.h> +#include <subdev/bios/P0260.h> + +#include "nvc0.h" +#include "ctxnvc0.h" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +gm107_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0xa140, &nouveau_object_ofuncs }, + { 0xb097, &nouveau_object_ofuncs }, + { 0xb0c0, &nouveau_object_ofuncs }, + {} +}; + +/******************************************************************************* + * PGRAPH register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +gm107_graph_init_main_0[] = { + { 0x400080, 1, 0x04, 0x003003c2 }, + { 0x400088, 1, 0x04, 0x0001bfe7 }, + { 0x40008c, 1, 0x04, 0x00060000 }, + { 0x400090, 1, 0x04, 0x00000030 }, + { 0x40013c, 1, 0x04, 0x003901f3 }, + { 0x400140, 1, 0x04, 0x00000100 }, + { 0x400144, 1, 0x04, 0x00000000 }, + { 0x400148, 1, 0x04, 0x00000110 }, + { 0x400138, 1, 0x04, 0x00000000 }, + { 0x400130, 2, 0x04, 0x00000000 }, + { 0x400124, 1, 0x04, 0x00000002 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_ds_0[] = { + { 0x405844, 1, 0x04, 0x00ffffff }, + { 0x405850, 1, 0x04, 0x00000000 }, + { 0x405900, 1, 0x04, 0x00000000 }, + { 0x405908, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_scc_0[] = { + { 0x40803c, 1, 0x04, 0x00000010 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_sked_0[] = { + { 0x407010, 1, 0x04, 0x00000000 }, + { 0x407040, 1, 0x04, 0x40440424 }, + { 0x407048, 1, 0x04, 0x0000000a }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_prop_0[] = { + { 0x418408, 1, 0x04, 0x00000000 }, + { 0x4184a0, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_setup_1[] = { + { 0x4188c8, 2, 0x04, 0x00000000 }, + { 0x4188d0, 1, 0x04, 0x00010000 }, + { 0x4188d4, 1, 0x04, 0x00010201 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_zcull_0[] = { + { 0x418910, 1, 0x04, 0x00010001 }, + { 0x418914, 1, 0x04, 0x00000301 }, + { 0x418918, 1, 0x04, 0x00800000 }, + { 0x418930, 2, 0x04, 0x00000000 }, + { 0x418980, 1, 0x04, 0x77777770 }, + { 0x418984, 3, 0x04, 0x77777777 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_gpc_unk_1[] = { + { 0x418d00, 1, 0x04, 0x00000000 }, + { 0x418f00, 1, 0x04, 0x00000400 }, + { 0x418f08, 1, 0x04, 0x00000000 }, + { 0x418e08, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_tpccs_0[] = { + { 0x419dc4, 1, 0x04, 0x00000000 }, + { 0x419dc8, 1, 0x04, 0x00000501 }, + { 0x419dd0, 1, 0x04, 0x00000000 }, + { 0x419dd4, 1, 0x04, 0x00000100 }, + { 0x419dd8, 1, 0x04, 0x00000001 }, + { 0x419ddc, 1, 0x04, 0x00000002 }, + { 0x419de0, 1, 0x04, 0x00000001 }, + { 0x419d0c, 1, 0x04, 0x00000000 }, + { 0x419d10, 1, 0x04, 0x00000014 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_tex_0[] = { + { 0x419ab0, 1, 0x04, 0x00000000 }, + { 0x419ab8, 1, 0x04, 0x000000e7 }, + { 0x419abc, 1, 0x04, 0x00000000 }, + { 0x419acc, 1, 0x04, 0x000000ff }, + { 0x419ac0, 1, 0x04, 0x00000000 }, + { 0x419aa8, 2, 0x04, 0x00000000 }, + { 0x419ad0, 2, 0x04, 0x00000000 }, + { 0x419ae0, 2, 0x04, 0x00000000 }, + { 0x419af0, 4, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_pe_0[] = { + { 0x419900, 1, 0x04, 0x000000ff }, + { 0x41980c, 1, 0x04, 0x00000010 }, + { 0x419844, 1, 0x04, 0x00000000 }, + { 0x419838, 1, 0x04, 0x000000ff }, + { 0x419850, 1, 0x04, 0x00000004 }, + { 0x419854, 2, 0x04, 0x00000000 }, + { 0x419894, 3, 0x04, 0x00100401 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_l1c_0[] = { + { 0x419c98, 1, 0x04, 0x00000000 }, + { 0x419cc0, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_sm_0[] = { + { 0x419e30, 1, 0x04, 0x000000ff }, + { 0x419e00, 1, 0x04, 0x00000000 }, + { 0x419ea0, 1, 0x04, 0x00000000 }, + { 0x419ee4, 1, 0x04, 0x00000000 }, + { 0x419ea4, 1, 0x04, 0x00000100 }, + { 0x419ea8, 1, 0x04, 0x01000000 }, + { 0x419ee8, 1, 0x04, 0x00000091 }, + { 0x419eb4, 1, 0x04, 0x00000000 }, + { 0x419ebc, 2, 0x04, 0x00000000 }, + { 0x419edc, 1, 0x04, 0x000c1810 }, + { 0x419ed8, 1, 0x04, 0x00000000 }, + { 0x419ee0, 1, 0x04, 0x00000000 }, + { 0x419f74, 1, 0x04, 0x00005155 }, + { 0x419f80, 4, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_l1c_1[] = { + { 0x419ccc, 2, 0x04, 0x00000000 }, + { 0x419c80, 1, 0x04, 0x3f006022 }, + { 0x419c88, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_pes_0[] = { + { 0x41be50, 1, 0x04, 0x000000ff }, + { 0x41be04, 1, 0x04, 0x00000000 }, + { 0x41be08, 1, 0x04, 0x00000004 }, + { 0x41be0c, 1, 0x04, 0x00000008 }, + { 0x41be10, 1, 0x04, 0x0e3b8bc7 }, + { 0x41be14, 2, 0x04, 0x00000000 }, + { 0x41be3c, 5, 0x04, 0x00100401 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_wwdx_0[] = { + { 0x41bfd4, 1, 0x04, 0x00800000 }, + { 0x41bfdc, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_cbm_0[] = { + { 0x41becc, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_be_0[] = { + { 0x408890, 1, 0x04, 0x000000ff }, + { 0x40880c, 1, 0x04, 0x00000000 }, + { 0x408850, 1, 0x04, 0x00000004 }, + { 0x408878, 1, 0x04, 0x00c81603 }, + { 0x40887c, 1, 0x04, 0x80543432 }, + { 0x408880, 1, 0x04, 0x0010581e }, + { 0x408884, 1, 0x04, 0x00001205 }, + { 0x408974, 1, 0x04, 0x000000ff }, + { 0x408910, 9, 0x04, 0x00000000 }, + { 0x408950, 1, 0x04, 0x00000000 }, + { 0x408954, 1, 0x04, 0x0000ffff }, + { 0x408958, 1, 0x04, 0x00000034 }, + { 0x40895c, 1, 0x04, 0x8531a003 }, + { 0x408960, 1, 0x04, 0x0561985a }, + { 0x408964, 1, 0x04, 0x04e15c4f }, + { 0x408968, 1, 0x04, 0x02808833 }, + { 0x40896c, 1, 0x04, 0x01f02438 }, + { 0x408970, 1, 0x04, 0x00012c00 }, + { 0x408984, 1, 0x04, 0x00000000 }, + { 0x408988, 1, 0x04, 0x08040201 }, + { 0x40898c, 1, 0x04, 0x80402010 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_sm_1[] = { + { 0x419e5c, 1, 0x04, 0x00000000 }, + { 0x419e58, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_graph_pack_mmio[] = { + { gm107_graph_init_main_0 }, + { nvf0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { gm107_graph_init_ds_0 }, + { gm107_graph_init_scc_0 }, + { gm107_graph_init_sked_0 }, + { nvf0_graph_init_cwd_0 }, + { gm107_graph_init_prop_0 }, + { nv108_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { gm107_graph_init_setup_1 }, + { gm107_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { gm107_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { gm107_graph_init_tpccs_0 }, + { gm107_graph_init_tex_0 }, + { gm107_graph_init_pe_0 }, + { gm107_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { gm107_graph_init_sm_0 }, + { gm107_graph_init_l1c_1 }, + { gm107_graph_init_pes_0 }, + { gm107_graph_init_wwdx_0 }, + { gm107_graph_init_cbm_0 }, + { gm107_graph_init_be_0 }, + { gm107_graph_init_sm_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static void +gm107_graph_init_bios(struct nvc0_graph_priv *priv) +{ + static const struct { + u32 ctrl; + u32 data; + } regs[] = { + { 0x419ed8, 0x419ee0 }, + { 0x419ad0, 0x419ad4 }, + { 0x419ae0, 0x419ae4 }, + { 0x419af0, 0x419af4 }, + { 0x419af8, 0x419afc }, + }; + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_P0260E infoE; + struct nvbios_P0260X infoX; + int E = -1, X; + u8 ver, hdr; + + while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) { + if (X = -1, E < ARRAY_SIZE(regs)) { + nv_wr32(priv, regs[E].ctrl, infoE.data); + while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX)) + nv_wr32(priv, regs[E].data, infoX.data); + } + } +} + +int +gm107_graph_init(struct nouveau_object *object) +{ + struct nvc0_graph_oclass *oclass = (void *)object->oclass; + struct nvc0_graph_priv *priv = (void *)object; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + u32 data[TPC_MAX / 8] = {}; + u8 tpcnr[GPC_MAX]; + int gpc, tpc, ppc, rop; + int ret, i; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); + nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + + nvc0_graph_mmio(priv, oclass->mmio); + + gm107_graph_init_bios(priv); + + nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + + memset(data, 0x00, sizeof(data)); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + + data[i / 8] |= tpc << ((i % 8) * 4); + } + + nv_wr32(priv, GPC_BCAST(0x0980), data[0]); + nv_wr32(priv, GPC_BCAST(0x0984), data[1]); + nv_wr32(priv, GPC_BCAST(0x0988), data[2]); + nv_wr32(priv, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + nv_wr32(priv, GPC_UNIT(gpc, 0x0914), + priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | + priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + } + + nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); + nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); + + nv_wr32(priv, 0x400500, 0x00010001); + + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); + nv_wr32(priv, 0x400124, 0x00000002); + nv_wr32(priv, 0x409c24, 0x000e0000); + + nv_wr32(priv, 0x404000, 0xc0000000); + nv_wr32(priv, 0x404600, 0xc0000000); + nv_wr32(priv, 0x408030, 0xc0000000); + nv_wr32(priv, 0x404490, 0xc0000000); + nv_wr32(priv, 0x406018, 0xc0000000); + nv_wr32(priv, 0x407020, 0x40000000); + nv_wr32(priv, 0x405840, 0xc0000000); + nv_wr32(priv, 0x405844, 0x00ffffff); + nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++) + nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + } + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + } + + for (rop = 0; rop < priv->rop_nr; rop++) { + nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000); + nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000); + nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + } + + nv_wr32(priv, 0x400108, 0xffffffff); + nv_wr32(priv, 0x400138, 0xffffffff); + nv_wr32(priv, 0x400118, 0xffffffff); + nv_wr32(priv, 0x400130, 0xffffffff); + nv_wr32(priv, 0x40011c, 0xffffffff); + nv_wr32(priv, 0x400134, 0xffffffff); + + nv_wr32(priv, 0x400054, 0x2c350f63); + return nvc0_graph_init_ctxctl(priv); +} + +#include "fuc/hubgm107.fuc5.h" + +static struct nvc0_graph_ucode +gm107_graph_fecs_ucode = { + .code.data = gm107_grhub_code, + .code.size = sizeof(gm107_grhub_code), + .data.data = gm107_grhub_data, + .data.size = sizeof(gm107_grhub_data), +}; + +#include "fuc/gpcgm107.fuc5.h" + +static struct nvc0_graph_ucode +gm107_graph_gpccs_ucode = { + .code.data = gm107_grgpc_code, + .code.size = sizeof(gm107_grgpc_code), + .data.data = gm107_grgpc_data, + .data.size = sizeof(gm107_grgpc_data), +}; + +struct nouveau_oclass * +gm107_graph_oclass = &(struct nvc0_graph_oclass) { + .base.handle = NV_ENGINE(GR, 0x07), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_ctor, + .dtor = nvc0_graph_dtor, + .init = gm107_graph_init, + .fini = _nouveau_graph_fini, + }, + .cclass = &gm107_grctx_oclass, + .sclass = gm107_graph_sclass, + .mmio = gm107_graph_pack_mmio, + .fecs.ucode = 0 ? &gm107_graph_fecs_ucode : NULL, + .gpccs.ucode = &gm107_graph_gpccs_ucode, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c index 23c143aaa55..4532f7e5618 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c @@ -945,7 +945,8 @@ nv10_graph_load_context(struct nv10_graph_chan *chan, int chid) for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]); - if (nv_device(priv)->chipset >= 0x17) { + if (nv_device(priv)->card_type >= NV_11 && + nv_device(priv)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]); } @@ -970,7 +971,8 @@ nv10_graph_unload_context(struct nv10_graph_chan *chan) for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]); - if (nv_device(priv)->chipset >= 0x17) { + if (nv_device(priv)->card_type >= NV_11 && + nv_device(priv)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]); } @@ -1052,7 +1054,8 @@ nv10_graph_context_ctor(struct nouveau_object *parent, NV_WRITE_CTX(0x00400e14, 0x00001000); NV_WRITE_CTX(0x00400e30, 0x00080008); NV_WRITE_CTX(0x00400e34, 0x00080008); - if (nv_device(priv)->chipset >= 0x17) { + if (nv_device(priv)->card_type >= NV_11 && + nv_device(priv)->chipset >= 0x17) { /* is it really needed ??? */ NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4, nv_rd32(priv, NV10_PGRAPH_DEBUG_4)); @@ -1231,7 +1234,7 @@ nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_engine(priv)->sclass = nv10_graph_sclass; else if (nv_device(priv)->chipset < 0x17 || - nv_device(priv)->chipset == 0x1a) + nv_device(priv)->card_type < NV_11) nv_engine(priv)->sclass = nv15_graph_sclass; else nv_engine(priv)->sclass = nv17_graph_sclass; @@ -1270,7 +1273,8 @@ nv10_graph_init(struct nouveau_object *object) nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); - if (nv_device(priv)->chipset >= 0x17) { + if (nv_device(priv)->card_type >= NV_11 && + nv_device(priv)->chipset >= 0x17) { nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000); nv_wr32(priv, 0x400a10, 0x03ff3fb6); nv_wr32(priv, 0x400838, 0x002f8684); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c new file mode 100644 index 00000000000..00ea1a08982 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c @@ -0,0 +1,223 @@ +/* + * 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" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +nv108_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0xa140, &nouveau_object_ofuncs }, + { 0xa197, &nouveau_object_ofuncs }, + { 0xa1c0, &nouveau_object_ofuncs }, + {} +}; + +/******************************************************************************* + * PGRAPH register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nv108_graph_init_main_0[] = { + { 0x400080, 1, 0x04, 0x003083c2 }, + { 0x400088, 1, 0x04, 0x0001bfe7 }, + { 0x40008c, 1, 0x04, 0x00000000 }, + { 0x400090, 1, 0x04, 0x00000030 }, + { 0x40013c, 1, 0x04, 0x003901f7 }, + { 0x400140, 1, 0x04, 0x00000100 }, + { 0x400144, 1, 0x04, 0x00000000 }, + { 0x400148, 1, 0x04, 0x00000110 }, + { 0x400138, 1, 0x04, 0x00000000 }, + { 0x400130, 2, 0x04, 0x00000000 }, + { 0x400124, 1, 0x04, 0x00000002 }, + {} +}; + +static const struct nvc0_graph_init +nv108_graph_init_ds_0[] = { + { 0x405844, 1, 0x04, 0x00ffffff }, + { 0x405850, 1, 0x04, 0x00000000 }, + { 0x405900, 1, 0x04, 0x00000000 }, + { 0x405908, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nv108_graph_init_gpc_unk_0[] = { + { 0x418604, 1, 0x04, 0x00000000 }, + { 0x418680, 1, 0x04, 0x00000000 }, + { 0x418714, 1, 0x04, 0x00000000 }, + { 0x418384, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_graph_init_setup_1[] = { + { 0x4188c8, 2, 0x04, 0x00000000 }, + { 0x4188d0, 1, 0x04, 0x00010000 }, + { 0x4188d4, 1, 0x04, 0x00000201 }, + {} +}; + +static const struct nvc0_graph_init +nv108_graph_init_tex_0[] = { + { 0x419ab0, 1, 0x04, 0x00000000 }, + { 0x419ac8, 1, 0x04, 0x00000000 }, + { 0x419ab8, 1, 0x04, 0x000000e7 }, + { 0x419abc, 2, 0x04, 0x00000000 }, + { 0x419ab4, 1, 0x04, 0x00000000 }, + { 0x419aa8, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_graph_init_l1c_0[] = { + { 0x419c98, 1, 0x04, 0x00000000 }, + { 0x419ca8, 1, 0x04, 0x00000000 }, + { 0x419cb0, 1, 0x04, 0x01000000 }, + { 0x419cb4, 1, 0x04, 0x00000000 }, + { 0x419cb8, 1, 0x04, 0x00b08bea }, + { 0x419c84, 1, 0x04, 0x00010384 }, + { 0x419cbc, 1, 0x04, 0x281b3646 }, + { 0x419cc0, 2, 0x04, 0x00000000 }, + { 0x419c80, 1, 0x04, 0x00000230 }, + { 0x419ccc, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +nv108_graph_pack_mmio[] = { + { nv108_graph_init_main_0 }, + { nvf0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nv108_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvf0_graph_init_sked_0 }, + { nvf0_graph_init_cwd_0 }, + { nvd9_graph_init_prop_0 }, + { nv108_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nv108_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 }, + { nv108_graph_init_tex_0 }, + { nve4_graph_init_pe_0 }, + { nv108_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nvf0_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 + ******************************************************************************/ + +static int +nv108_graph_fini(struct nouveau_object *object, bool suspend) +{ + struct nvc0_graph_priv *priv = (void *)object; + static const struct { + u32 addr; + u32 data; + } magic[] = { + { 0x020520, 0xfffffffc }, + { 0x020524, 0xfffffffe }, + { 0x020524, 0xfffffffc }, + { 0x020524, 0xfffffff8 }, + { 0x020524, 0xffffffe0 }, + { 0x020530, 0xfffffffe }, + { 0x02052c, 0xfffffffa }, + { 0x02052c, 0xfffffff0 }, + { 0x02052c, 0xffffffc0 }, + { 0x02052c, 0xffffff00 }, + { 0x02052c, 0xfffffc00 }, + { 0x02052c, 0xfffcfc00 }, + { 0x02052c, 0xfff0fc00 }, + { 0x02052c, 0xff80fc00 }, + { 0x020528, 0xfffffffe }, + { 0x020528, 0xfffffffc }, + }; + int i; + + nv_mask(priv, 0x000200, 0x08001000, 0x00000000); + nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000); + for (i = 0; i < ARRAY_SIZE(magic); i++) { + nv_wr32(priv, magic[i].addr, magic[i].data); + nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000); + } + + return nouveau_graph_fini(&priv->base, suspend); +} + +#include "fuc/hubnv108.fuc5.h" + +static struct nvc0_graph_ucode +nv108_graph_fecs_ucode = { + .code.data = nv108_grhub_code, + .code.size = sizeof(nv108_grhub_code), + .data.data = nv108_grhub_data, + .data.size = sizeof(nv108_grhub_data), +}; + +#include "fuc/gpcnv108.fuc5.h" + +static struct nvc0_graph_ucode +nv108_graph_gpccs_ucode = { + .code.data = nv108_grgpc_code, + .code.size = sizeof(nv108_grgpc_code), + .data.data = nv108_grgpc_data, + .data.size = sizeof(nv108_grgpc_data), +}; + +struct nouveau_oclass * +nv108_graph_oclass = &(struct nvc0_graph_oclass) { + .base.handle = NV_ENGINE(GR, 0x08), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_ctor, + .dtor = nvc0_graph_dtor, + .init = nve4_graph_init, + .fini = nv108_graph_fini, + }, + .cclass = &nv108_grctx_oclass, + .sclass = nv108_graph_sclass, + .mmio = nv108_graph_pack_mmio, + .fecs.ucode = &nv108_graph_fecs_ucode, + .gpccs.ucode = &nv108_graph_gpccs_ucode, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c index b2455931590..d145e080899 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c @@ -349,7 +349,7 @@ nv20_graph_init(struct nouveau_object *object) nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ - vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1; + vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 193a5de1b48..6477fbf6a55 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -484,7 +484,7 @@ nv40_graph_init(struct nouveau_object *object) engine->tile_prog(engine, i); /* begin RAM config */ - vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1; + vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; switch (nv_device(priv)->chipset) { case 0x40: nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c index 03de5175dd9..20665c21d80 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c @@ -197,34 +197,35 @@ static const struct nouveau_bitfield nv50_pgraph_status[] = { { 0x00000080, "UNK7" }, { 0x00000100, "CTXPROG" }, { 0x00000200, "VFETCH" }, - { 0x00000400, "CCACHE_UNK4" }, - { 0x00000800, "STRMOUT_GSCHED_UNK5" }, - { 0x00001000, "UNK14XX" }, - { 0x00002000, "UNK24XX_CSCHED" }, - { 0x00004000, "UNK1CXX" }, + { 0x00000400, "CCACHE_PREGEOM" }, + { 0x00000800, "STRMOUT_VATTR_POSTGEOM" }, + { 0x00001000, "VCLIP" }, + { 0x00002000, "RATTR_APLANE" }, + { 0x00004000, "TRAST" }, { 0x00008000, "CLIPID" }, { 0x00010000, "ZCULL" }, { 0x00020000, "ENG2D" }, - { 0x00040000, "UNK34XX" }, - { 0x00080000, "TPRAST" }, - { 0x00100000, "TPROP" }, - { 0x00200000, "TEX" }, - { 0x00400000, "TPVP" }, - { 0x00800000, "MP" }, + { 0x00040000, "RMASK" }, + { 0x00080000, "TPC_RAST" }, + { 0x00100000, "TPC_PROP" }, + { 0x00200000, "TPC_TEX" }, + { 0x00400000, "TPC_GEOM" }, + { 0x00800000, "TPC_MP" }, { 0x01000000, "ROP" }, {} }; static const char *const nv50_pgraph_vstatus_0[] = { - "VFETCH", "CCACHE", "UNK4", "UNK5", "GSCHED", "STRMOUT", "UNK14XX", NULL + "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP", + NULL }; static const char *const nv50_pgraph_vstatus_1[] = { - "TPRAST", "TPROP", "TEXTURE", "TPVP", "MP", NULL + "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL }; static const char *const nv50_pgraph_vstatus_2[] = { - "UNK24XX", "CSCHED", "UNK1CXX", "CLIPID", "ZCULL", "ENG2D", "UNK34XX", + "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK", "ROP", NULL }; @@ -304,12 +305,37 @@ nv84_graph_tlb_flush(struct nouveau_engine *engine) return timeout ? -EBUSY : 0; } -static const struct nouveau_enum nv50_mp_exec_error_names[] = { - { 3, "STACK_UNDERFLOW", NULL }, - { 4, "QUADON_ACTIVE", NULL }, - { 8, "TIMEOUT", NULL }, - { 0x10, "INVALID_OPCODE", NULL }, - { 0x40, "BREAKPOINT", NULL }, +static const struct nouveau_bitfield nv50_mp_exec_errors[] = { + { 0x01, "STACK_UNDERFLOW" }, + { 0x02, "STACK_MISMATCH" }, + { 0x04, "QUADON_ACTIVE" }, + { 0x08, "TIMEOUT" }, + { 0x10, "INVALID_OPCODE" }, + { 0x20, "PM_OVERFLOW" }, + { 0x40, "BREAKPOINT" }, + {} +}; + +static const struct nouveau_bitfield nv50_mpc_traps[] = { + { 0x0000001, "LOCAL_LIMIT_READ" }, + { 0x0000010, "LOCAL_LIMIT_WRITE" }, + { 0x0000040, "STACK_LIMIT" }, + { 0x0000100, "GLOBAL_LIMIT_READ" }, + { 0x0001000, "GLOBAL_LIMIT_WRITE" }, + { 0x0010000, "MP0" }, + { 0x0020000, "MP1" }, + { 0x0040000, "GLOBAL_LIMIT_RED" }, + { 0x0400000, "GLOBAL_LIMIT_ATOM" }, + { 0x4000000, "MP2" }, + {} +}; + +static const struct nouveau_bitfield nv50_tex_traps[] = { + { 0x00000001, "" }, /* any bit set? */ + { 0x00000002, "FAULT" }, + { 0x00000004, "STORAGE_TYPE_MISMATCH" }, + { 0x00000008, "LINEAR_MISMATCH" }, + { 0x00000020, "WRONG_MEMTYPE" }, {} }; @@ -396,6 +422,60 @@ static const struct nouveau_bitfield nv50_graph_intr_name[] = { {} }; +static const struct nouveau_bitfield nv50_graph_trap_prop[] = { + { 0x00000004, "SURF_WIDTH_OVERRUN" }, + { 0x00000008, "SURF_HEIGHT_OVERRUN" }, + { 0x00000010, "DST2D_FAULT" }, + { 0x00000020, "ZETA_FAULT" }, + { 0x00000040, "RT_FAULT" }, + { 0x00000080, "CUDA_FAULT" }, + { 0x00000100, "DST2D_STORAGE_TYPE_MISMATCH" }, + { 0x00000200, "ZETA_STORAGE_TYPE_MISMATCH" }, + { 0x00000400, "RT_STORAGE_TYPE_MISMATCH" }, + { 0x00000800, "DST2D_LINEAR_MISMATCH" }, + { 0x00001000, "RT_LINEAR_MISMATCH" }, + {} +}; + +static void +nv50_priv_prop_trap(struct nv50_graph_priv *priv, + u32 ustatus_addr, u32 ustatus, u32 tp) +{ + u32 e0c = nv_rd32(priv, ustatus_addr + 0x04); + u32 e10 = nv_rd32(priv, ustatus_addr + 0x08); + u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c); + u32 e18 = nv_rd32(priv, ustatus_addr + 0x10); + u32 e1c = nv_rd32(priv, ustatus_addr + 0x14); + u32 e20 = nv_rd32(priv, ustatus_addr + 0x18); + u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c); + + /* CUDA memory: l[], g[] or stack. */ + if (ustatus & 0x00000080) { + if (e18 & 0x80000000) { + /* g[] read fault? */ + nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n", + tp, e14, e10 | ((e18 >> 24) & 0x1f)); + e18 &= ~0x1f000000; + } else if (e18 & 0xc) { + /* g[] write fault? */ + nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n", + tp, e14, e10 | ((e18 >> 7) & 0x1f)); + e18 &= ~0x00000f80; + } else { + nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n", + tp, e14, e10); + } + ustatus &= ~0x00000080; + } + if (ustatus) { + nv_error(priv, "TRAP_PROP - TP %d -", tp); + nouveau_bitfield_print(nv50_graph_trap_prop, ustatus); + pr_cont(" - Address %02x%08x\n", e14, e10); + } + nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + tp, e0c, e18, e1c, e20, e24); +} + static void nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display) { @@ -420,8 +500,8 @@ nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display) oplow = nv_rd32(priv, addr + 0x70); ophigh = nv_rd32(priv, addr + 0x74); nv_error(priv, "TRAP_MP_EXEC - " - "TP %d MP %d: ", tpid, i); - nouveau_enum_print(nv50_mp_exec_error_names, status); + "TP %d MP %d:", tpid, i); + nouveau_bitfield_print(nv50_mp_exec_errors, status); pr_cont(" at %06x warp %d, opcode %08x %08x\n", pc&0xffffff, pc >> 24, oplow, ophigh); @@ -461,6 +541,13 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old, for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) nv_error(priv, "\t0x%08x: 0x%08x\n", r, nv_rd32(priv, r)); + if (ustatus) { + nv_error(priv, "%s - TP%d:", name, i); + nouveau_bitfield_print(nv50_tex_traps, + ustatus); + pr_cont("\n"); + ustatus = 0; + } } break; case 7: /* MP error */ @@ -468,60 +555,19 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old, nv50_priv_mp_trap(priv, i, display); ustatus &= ~0x04030000; } - break; - case 8: /* TPDMA error */ - { - u32 e0c = nv_rd32(priv, ustatus_addr + 4); - u32 e10 = nv_rd32(priv, ustatus_addr + 8); - u32 e14 = nv_rd32(priv, ustatus_addr + 0xc); - u32 e18 = nv_rd32(priv, ustatus_addr + 0x10); - u32 e1c = nv_rd32(priv, ustatus_addr + 0x14); - u32 e20 = nv_rd32(priv, ustatus_addr + 0x18); - u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c); - /* 2d engine destination */ - if (ustatus & 0x00000010) { - if (display) { - nv_error(priv, "TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", - i, e14, e10); - nv_error(priv, "TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", - i, e0c, e18, e1c, e20, e24); - } - ustatus &= ~0x00000010; - } - /* Render target */ - if (ustatus & 0x00000040) { - if (display) { - nv_error(priv, "TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", - i, e14, e10); - nv_error(priv, "TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", - i, e0c, e18, e1c, e20, e24); - } - ustatus &= ~0x00000040; - } - /* CUDA memory: l[], g[] or stack. */ - if (ustatus & 0x00000080) { - if (display) { - if (e18 & 0x80000000) { - /* g[] read fault? */ - nv_error(priv, "TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", - i, e14, e10 | ((e18 >> 24) & 0x1f)); - e18 &= ~0x1f000000; - } else if (e18 & 0xc) { - /* g[] write fault? */ - nv_error(priv, "TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", - i, e14, e10 | ((e18 >> 7) & 0x1f)); - e18 &= ~0x00000f80; - } else { - nv_error(priv, "TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", - i, e14, e10); - } - nv_error(priv, "TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", - i, e0c, e18, e1c, e20, e24); - } - ustatus &= ~0x00000080; - } + if (ustatus && display) { + nv_error(priv, "%s - TP%d:", name, i); + nouveau_bitfield_print(nv50_mpc_traps, ustatus); + pr_cont("\n"); + ustatus = 0; } break; + case 8: /* PROP error */ + if (display) + nv50_priv_prop_trap( + priv, ustatus_addr, ustatus, i); + ustatus = 0; + break; } if (ustatus) { if (display) @@ -727,11 +773,11 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, status &= ~0x080; } - /* TPDMA: Handles TP-initiated uncached memory accesses: + /* PROP: Handles TP-initiated uncached memory accesses: * l[], g[], stack, 2d surfaces, render targets. */ if (status & 0x100) { nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display, - "TRAP_TPDMA"); + "TRAP_PROP"); nv_wr32(priv, 0x400108, 0x100); status &= ~0x100; } @@ -760,7 +806,7 @@ nv50_graph_intr(struct nouveau_subdev *subdev) u32 mthd = (addr & 0x00001ffc); u32 data = nv_rd32(priv, 0x400708); u32 class = nv_rd32(priv, 0x400814); - u32 show = stat; + u32 show = stat, show_bitfield = stat; int chid; engctx = nouveau_engctx_get(engine, inst); @@ -778,21 +824,26 @@ nv50_graph_intr(struct nouveau_subdev *subdev) nv_error(priv, "DATA_ERROR "); nouveau_enum_print(nv50_data_error_names, ecode); pr_cont("\n"); + show_bitfield &= ~0x00100000; } if (stat & 0x00200000) { if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12, engctx)) show &= ~0x00200000; + show_bitfield &= ~0x00200000; } nv_wr32(priv, 0x400100, stat); nv_wr32(priv, 0x400500, 0x00010001); if (show) { - nv_error(priv, "%s", ""); - nouveau_bitfield_print(nv50_graph_intr_name, show); - pr_cont("\n"); + show &= show_bitfield; + if (show) { + nv_error(priv, "%s", ""); + nouveau_bitfield_print(nv50_graph_intr_name, show); + pr_cont("\n"); + } nv_error(priv, "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, (u64)inst << 12, nouveau_client_name(engctx), @@ -850,7 +901,7 @@ nv50_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_engine(priv)->sclass = nvaf_graph_sclass; break; - }; + } /* unfortunate hw bug workaround... */ if (nv_device(priv)->chipset != 0x50 && @@ -925,7 +976,6 @@ nv50_graph_init(struct nouveau_object *object) break; case 0xa0: default: - nv_wr32(priv, 0x402cc0, 0x00000000); if (nv_device(priv)->chipset == 0xa0 || nv_device(priv)->chipset == 0xaa || nv_device(priv)->chipset == 0xac) { @@ -940,10 +990,10 @@ nv50_graph_init(struct nouveau_object *object) /* zero out zcull regions */ for (i = 0; i < 8; i++) { - nv_wr32(priv, 0x402c20 + (i * 8), 0x00000000); - nv_wr32(priv, 0x402c24 + (i * 8), 0x00000000); - nv_wr32(priv, 0x402c28 + (i * 8), 0x00000000); - nv_wr32(priv, 0x402c2c + (i * 8), 0x00000000); + nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000); + nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000); + nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000); + nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000); } return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index 3f4f35cc384..aa083891635 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -146,11 +147,11 @@ nvc0_graph_context_dtor(struct nouveau_object *object) } /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nvc0_graph_init_regs[] = { +const struct nvc0_graph_init +nvc0_graph_init_main_0[] = { { 0x400080, 1, 0x04, 0x003083c2 }, { 0x400088, 1, 0x04, 0x00006fe7 }, { 0x40008c, 1, 0x04, 0x00000000 }, @@ -165,95 +166,170 @@ nvc0_graph_init_regs[] = { {} }; -struct nvc0_graph_init -nvc0_graph_init_unk40xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_fe_0[] = { { 0x40415c, 1, 0x04, 0x00000000 }, { 0x404170, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk44xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_pri_0[] = { { 0x404488, 2, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk78xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_rstr2d_0[] = { { 0x407808, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk60xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_pd_0[] = { { 0x406024, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk58xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405908, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk80xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_scc_0[] = { { 0x40803c, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_gpc[] = { +const struct nvc0_graph_init +nvc0_graph_init_prop_0[] = { { 0x4184a0, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gpc_unk_0[] = { { 0x418604, 1, 0x04, 0x00000000 }, { 0x418680, 1, 0x04, 0x00000000 }, { 0x418714, 1, 0x04, 0x80000000 }, { 0x418384, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_setup_0[] = { { 0x418814, 3, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_crstr_0[] = { { 0x418b04, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_setup_1[] = { { 0x4188c8, 1, 0x04, 0x80000000 }, { 0x4188cc, 1, 0x04, 0x00000000 }, { 0x4188d0, 1, 0x04, 0x00010000 }, { 0x4188d4, 1, 0x04, 0x00000001 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_zcull_0[] = { { 0x418910, 1, 0x04, 0x00010001 }, { 0x418914, 1, 0x04, 0x00000301 }, { 0x418918, 1, 0x04, 0x00800000 }, { 0x418980, 1, 0x04, 0x77777770 }, { 0x418984, 3, 0x04, 0x77777777 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gpm_0[] = { { 0x418c04, 1, 0x04, 0x00000000 }, { 0x418c88, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000050 }, { 0x418e08, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gcc_0[] = { { 0x41900c, 1, 0x04, 0x00000000 }, { 0x419018, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvc0_graph_init_tpc[] = { +const struct nvc0_graph_init +nvc0_graph_init_tpccs_0[] = { { 0x419d08, 2, 0x04, 0x00000000 }, { 0x419d10, 1, 0x04, 0x00000014 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, { 0x419abc, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_pe_0[] = { { 0x41980c, 3, 0x04, 0x00000000 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x41984c, 1, 0x04, 0x00005bc5 }, { 0x419850, 4, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_l1c_0[] = { { 0x419c98, 1, 0x04, 0x00000000 }, { 0x419ca8, 1, 0x04, 0x80000000 }, { 0x419cb4, 1, 0x04, 0x00000000 }, { 0x419cb8, 1, 0x04, 0x00008bf4 }, { 0x419cbc, 1, 0x04, 0x28137606 }, { 0x419cc0, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_wwdx_0[] = { { 0x419bd4, 1, 0x04, 0x00800000 }, { 0x419bdc, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_tpccs_1[] = { { 0x419d2c, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_mpc_0[] = { { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -270,8 +346,8 @@ nvc0_graph_init_tpc[] = { {} }; -struct nvc0_graph_init -nvc0_graph_init_unk88xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_be_0[] = { { 0x40880c, 1, 0x04, 0x00000000 }, { 0x408910, 9, 0x04, 0x00000000 }, { 0x408950, 1, 0x04, 0x00000000 }, @@ -282,18 +358,64 @@ nvc0_graph_init_unk88xx[] = { {} }; -struct nvc0_graph_init -nvc0_graph_tpc_0[] = { - { 0x50405c, 1, 0x04, 0x00000001 }, +const struct nvc0_graph_init +nvc0_graph_init_fe_1[] = { + { 0x4040f0, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_pe_1[] = { + { 0x419880, 1, 0x04, 0x00000002 }, {} }; +static const struct nvc0_graph_pack +nvc0_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc0_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_graph_init_prop_0 }, + { nvc0_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc0_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { nvc0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc0_graph_init_tex_0 }, + { nvc0_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc0_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + { nvc0_graph_init_pe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + void -nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init) +nvc0_graph_mmio(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p) { - for (; init && init->count; init++) { - u32 addr = init->addr, i; - for (i = 0; i < init->count; i++) { + const struct nvc0_graph_pack *pack; + const struct nvc0_graph_init *init; + + pack_for_each_init(init, pack, p) { + u32 next = init->addr + init->count * init->pitch; + u32 addr = init->addr; + while (addr < next) { nv_wr32(priv, addr, init->data); addr += init->pitch; } @@ -301,49 +423,53 @@ nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init) } void -nvc0_graph_icmd(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init) +nvc0_graph_icmd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p) { - u32 addr, data; - int i, j; + const struct nvc0_graph_pack *pack; + const struct nvc0_graph_init *init; + u32 data = 0; nv_wr32(priv, 0x400208, 0x80000000); - for (i = 0; init->count; init++, i++) { - if (!i || data != init->data) { + + pack_for_each_init(init, pack, p) { + u32 next = init->addr + init->count * init->pitch; + u32 addr = init->addr; + + if ((pack == p && init == p->init) || data != init->data) { nv_wr32(priv, 0x400204, init->data); data = init->data; } - addr = init->addr; - for (j = 0; j < init->count; j++) { + while (addr < next) { nv_wr32(priv, 0x400200, addr); + nv_wait(priv, 0x400700, 0x00000002, 0x00000000); addr += init->pitch; - while (nv_rd32(priv, 0x400700) & 0x00000002) {} } } + nv_wr32(priv, 0x400208, 0x00000000); } void -nvc0_graph_mthd(struct nvc0_graph_priv *priv, struct nvc0_graph_mthd *mthds) +nvc0_graph_mthd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p) { - struct nvc0_graph_mthd *mthd; - struct nvc0_graph_init *init; - int i = 0, j; - u32 data; - - while ((mthd = &mthds[i++]) && (init = mthd->init)) { - u32 addr = 0x80000000 | mthd->oclass; - for (data = 0; init->count; init++) { - if (data != init->data) { - nv_wr32(priv, 0x40448c, init->data); - data = init->data; - } + const struct nvc0_graph_pack *pack; + const struct nvc0_graph_init *init; + u32 data = 0; - addr = (addr & 0x8000ffff) | (init->addr << 14); - for (j = 0; j < init->count; j++) { - nv_wr32(priv, 0x404488, addr); - addr += init->pitch << 14; - } + pack_for_each_init(init, pack, p) { + u32 ctrl = 0x80000000 | pack->type; + u32 next = init->addr + init->count * init->pitch; + u32 addr = init->addr; + + if ((pack == p && init == p->init) || data != init->data) { + nv_wr32(priv, 0x40448c, init->data); + data = init->data; + } + + while (addr < next) { + nv_wr32(priv, 0x404488, ctrl | (addr << 14)); + addr += init->pitch; } } } @@ -663,17 +789,40 @@ nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv) static void nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv) { - u32 ustat = nv_rd32(priv, 0x409c18); + u32 stat = nv_rd32(priv, 0x409c18); + + if (stat & 0x00000001) { + u32 code = nv_rd32(priv, 0x409814); + if (code == E_BAD_FWMTHD) { + u32 class = nv_rd32(priv, 0x409808); + u32 addr = nv_rd32(priv, 0x40980c); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00003ffc); + u32 data = nv_rd32(priv, 0x409810); + + nv_error(priv, "FECS MTHD subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + subc, class, mthd, data); - if (ustat & 0x00000001) - nv_error(priv, "CTXCTL ucode error\n"); - if (ustat & 0x00080000) - nv_error(priv, "CTXCTL watchdog timeout\n"); - if (ustat & ~0x00080001) - nv_error(priv, "CTXCTL 0x%08x\n", ustat); + nv_wr32(priv, 0x409c20, 0x00000001); + stat &= ~0x00000001; + } else { + nv_error(priv, "FECS ucode error %d\n", code); + } + } + + if (stat & 0x00080000) { + nv_error(priv, "FECS watchdog timeout\n"); + nvc0_graph_ctxctl_debug(priv); + nv_wr32(priv, 0x409c20, 0x00080000); + stat &= ~0x00080000; + } - nvc0_graph_ctxctl_debug(priv); - nv_wr32(priv, 0x409c20, ustat); + if (stat) { + nv_error(priv, "FECS 0x%08x\n", stat); + nvc0_graph_ctxctl_debug(priv); + nv_wr32(priv, 0x409c20, stat); + } } static void @@ -768,15 +917,20 @@ nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base, nv_wr32(priv, fuc_base + 0x0188, i >> 6); nv_wr32(priv, fuc_base + 0x0184, code->data[i]); } + + /* code must be padded to 0x40 words */ + for (; i & 0x3f; i++) + nv_wr32(priv, fuc_base + 0x0184, 0); } static void nvc0_graph_init_csdata(struct nvc0_graph_priv *priv, - struct nvc0_graph_init *init, + const struct nvc0_graph_pack *pack, u32 falcon, u32 starstar, u32 base) { - u32 addr = init->addr; - u32 next = addr; + const struct nvc0_graph_pack *iter; + const struct nvc0_graph_init *init; + u32 addr = ~0, prev = ~0, xfer = 0; u32 star, temp; nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar); @@ -786,22 +940,28 @@ nvc0_graph_init_csdata(struct nvc0_graph_priv *priv, star = temp; nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star); - do { - if (init->addr != next) { - while (addr < next) { - u32 nr = min((int)(next - addr) / 4, 32); - nv_wr32(priv, falcon + 0x01c4, - ((nr - 1) << 26) | (addr - base)); - addr += nr * 4; - star += 4; + pack_for_each_init(init, iter, pack) { + u32 head = init->addr - base; + u32 tail = head + init->count * init->pitch; + while (head < tail) { + if (head != prev + 4 || xfer >= 32) { + if (xfer) { + u32 data = ((--xfer << 26) | addr); + nv_wr32(priv, falcon + 0x01c4, data); + star += 4; + } + addr = head; + xfer = 0; } - addr = next = init->addr; + prev = head; + xfer = xfer + 1; + head = head + init->pitch; } - next += init->count * 4; - } while ((init++)->count); + } + nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr); nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar); - nv_wr32(priv, falcon + 0x01c4, star); + nv_wr32(priv, falcon + 0x01c4, star + 4); } int @@ -809,7 +969,6 @@ 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; - struct nvc0_graph_init *init; u32 r000260; int i; @@ -901,6 +1060,9 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) } return 0; + } else + if (!oclass->fecs.ucode) { + return -ENOSYS; } /* load HUB microcode */ @@ -916,10 +1078,6 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]); } - for (i = 0; (init = cclass->hub[i]); i++) { - nvc0_graph_init_csdata(priv, init, 0x409000, 0x000, 0x000000); - } - /* load GPC microcode */ nv_wr32(priv, 0x41a1c0, 0x01000000); for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++) @@ -933,12 +1091,11 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) } nv_wr32(priv, 0x000260, r000260); - if ((init = cclass->gpc[0])) - nvc0_graph_init_csdata(priv, init, 0x41a000, 0x000, 0x418000); - if ((init = cclass->gpc[2])) - nvc0_graph_init_csdata(priv, init, 0x41a000, 0x004, 0x419800); - if ((init = cclass->gpc[3])) - nvc0_graph_init_csdata(priv, init, 0x41a000, 0x008, 0x41be00); + /* load register lists */ + nvc0_graph_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000); + nvc0_graph_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000); + nvc0_graph_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800); + nvc0_graph_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00); /* start HUB ucode running, it'll init the GPCs */ nv_wr32(priv, 0x40910c, 0x00000000); @@ -985,8 +1142,7 @@ nvc0_graph_init(struct nouveau_object *object) nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); - for (i = 0; oclass->mmio[i]; i++) - nvc0_graph_mmio(priv, oclass->mmio[i]); + nvc0_graph_mmio(priv, oclass->mmio); memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); for (i = 0, gpc = -1; i < priv->tpc_total; i++) { @@ -1088,10 +1244,10 @@ nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname, int ret; snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname); - ret = request_firmware(&fw, f, &device->pdev->dev); + ret = request_firmware(&fw, f, nv_device_base(device)); if (ret) { snprintf(f, sizeof(f), "nouveau/%s", fwname); - ret = request_firmware(&fw, f, &device->pdev->dev); + ret = request_firmware(&fw, f, nv_device_base(device)); if (ret) { nv_error(priv, "failed to load %s\n", fwname); return ret; @@ -1130,20 +1286,24 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_graph_oclass *oclass = (void *)bclass; struct nouveau_device *device = nv_device(parent); struct nvc0_graph_priv *priv; + bool use_ext_fw, enable; int ret, i; - ret = nouveau_graph_create(parent, engine, bclass, - (oclass->fecs.ucode != NULL), &priv); + use_ext_fw = nouveau_boolopt(device->cfgopt, "NvGrUseFW", + oclass->fecs.ucode == NULL); + enable = use_ext_fw || oclass->fecs.ucode != NULL; + + ret = nouveau_graph_create(parent, engine, bclass, enable, &priv); *pobject = nv_object(priv); if (ret) return ret; - nv_subdev(priv)->unit = 0x18001000; + nv_subdev(priv)->unit = 0x08001000; nv_subdev(priv)->intr = nvc0_graph_intr; priv->base.units = nvc0_graph_units; - if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) { + if (use_ext_fw) { nv_info(priv, "using external firmware\n"); if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) || nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) || @@ -1217,22 +1377,6 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nvc0_graph_init * -nvc0_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc0_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc0_graph_init_gpc, - nvc0_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL -}; - #include "fuc/hubnvc0.fuc.h" struct nvc0_graph_ucode @@ -1264,7 +1408,7 @@ nvc0_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvc0_grctx_oclass, .sclass = nvc0_graph_sclass, - .mmio = nvc0_graph_init_mmio, + .mmio = nvc0_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h index ea17a80ad7f..ffc289198dd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h @@ -38,6 +38,8 @@ #include <engine/fifo.h> #include <engine/graph.h> +#include "fuc/os.h" + #define GPC_MAX 32 #define TPC_MAX (GPC_MAX * 8) @@ -45,6 +47,7 @@ #define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r)) #define GPC_BCAST(r) (0x418000 + (r)) #define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r)) +#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r)) #define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) struct nvc0_graph_data { @@ -102,8 +105,6 @@ struct nvc0_graph_chan { } data[4]; }; -int nvc0_grctx_generate(struct nvc0_graph_priv *); - int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, void *, u32, struct nouveau_object **); @@ -117,6 +118,7 @@ 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 *); +int nve4_graph_fini(struct nouveau_object *, bool); int nve4_graph_init(struct nouveau_object *); extern struct nouveau_oclass nvc0_graph_sclass[]; @@ -130,34 +132,14 @@ struct nvc0_graph_init { u32 data; }; -struct nvc0_graph_mthd { - u16 oclass; - struct nvc0_graph_init *init; +struct nvc0_graph_pack { + const struct nvc0_graph_init *init; + u32 type; }; -struct nvc0_grctx { - struct nvc0_graph_priv *priv; - struct nvc0_graph_data *data; - struct nvc0_graph_mmio *mmio; - int buffer_nr; - u64 buffer[4]; - u64 addr; -}; - -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 */ - struct nvc0_graph_init **hub; - struct nvc0_graph_init **gpc; - /* indirect context data, generated with icmds/mthds */ - struct nvc0_graph_init *icmd; - struct nvc0_graph_mthd *mthd; -}; +#define pack_for_each_init(init, pack, head) \ + for (pack = head; pack && pack->init; pack++) \ + for (init = pack->init; init && init->count; init++) struct nvc0_graph_ucode { struct nvc0_graph_fuc code; @@ -171,7 +153,7 @@ struct nvc0_graph_oclass { struct nouveau_oclass base; struct nouveau_oclass **cclass; struct nouveau_oclass *sclass; - struct nvc0_graph_init **mmio; + const struct nvc0_graph_pack *mmio; struct { struct nvc0_graph_ucode *ucode; } fecs; @@ -180,109 +162,73 @@ struct nvc0_graph_oclass { } gpccs; }; -void nvc0_graph_mmio(struct nvc0_graph_priv *, struct nvc0_graph_init *); -void nvc0_graph_icmd(struct nvc0_graph_priv *, struct nvc0_graph_init *); -void nvc0_graph_mthd(struct nvc0_graph_priv *, struct nvc0_graph_mthd *); +void nvc0_graph_mmio(struct nvc0_graph_priv *, const struct nvc0_graph_pack *); +void nvc0_graph_icmd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *); +void nvc0_graph_mthd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *); int nvc0_graph_init_ctxctl(struct nvc0_graph_priv *); -extern struct nvc0_graph_init nvc0_graph_init_regs[]; -extern struct nvc0_graph_init nvc0_graph_init_unk40xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk44xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk78xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk60xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk58xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk80xx[]; -extern struct nvc0_graph_init nvc0_graph_init_gpc[]; -extern struct nvc0_graph_init nvc0_graph_init_unk88xx[]; -extern struct nvc0_graph_init nvc0_graph_tpc_0[]; - -extern struct nvc0_graph_init nvc3_graph_init_unk58xx[]; - -extern struct nvc0_graph_init nvd9_graph_init_unk58xx[]; -extern struct nvc0_graph_init nvd9_graph_init_unk64xx[]; - -extern struct nvc0_graph_init nve4_graph_init_regs[]; -extern struct nvc0_graph_init nve4_graph_init_unk[]; -extern struct nvc0_graph_init nve4_graph_init_unk88xx[]; - -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_unkn(struct nvc0_graph_priv *); -void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *); -void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *); - -extern struct nouveau_oclass *nvc0_grctx_oclass; -extern struct nvc0_graph_init *nvc0_grctx_init_hub[]; -extern struct nvc0_graph_init nvc0_grctx_init_base[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk40xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk44xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk46xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk47xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk60xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk64xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk78xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk80xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_gpc_0[]; -extern struct nvc0_graph_init nvc0_grctx_init_gpc_1[]; -extern struct nvc0_graph_init nvc0_grctx_init_tpc[]; -extern struct nvc0_graph_init nvc0_grctx_init_icmd[]; -extern struct nvc0_graph_init nvd9_grctx_init_icmd[]; // - -extern struct nvc0_graph_mthd nvc0_grctx_init_mthd[]; -extern struct nvc0_graph_init nvc0_grctx_init_902d[]; -extern struct nvc0_graph_init nvc0_grctx_init_9039[]; -extern struct nvc0_graph_init nvc0_grctx_init_90c0[]; -extern struct nvc0_graph_init nvc0_grctx_init_mthd_magic[]; - -void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *); -extern struct nouveau_oclass *nvc1_grctx_oclass; -extern struct nvc0_graph_init nvc1_grctx_init_9097[]; - -extern struct nouveau_oclass *nvc3_grctx_oclass; - -extern struct nouveau_oclass *nvc8_grctx_oclass; -extern struct nvc0_graph_init nvc8_grctx_init_9197[]; -extern struct nvc0_graph_init nvc8_grctx_init_9297[]; - -extern struct nouveau_oclass *nvd7_grctx_oclass; - -extern struct nouveau_oclass *nvd9_grctx_oclass; -extern struct nvc0_graph_init nvd9_grctx_init_rop[]; -extern struct nvc0_graph_mthd nvd9_grctx_init_mthd[]; - -void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nve4_grctx_generate_unkn(struct nvc0_graph_priv *); -extern struct nouveau_oclass *nve4_grctx_oclass; -extern struct nvc0_graph_init nve4_grctx_init_unk46xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk47xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk58xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk80xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk90xx[]; - -extern struct nouveau_oclass *nvf0_grctx_oclass; - -#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) +/* register init value lists */ + +extern const struct nvc0_graph_init nvc0_graph_init_main_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_fe_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_pri_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_rstr2d_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_pd_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_ds_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_scc_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_prop_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_setup_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_crstr_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_setup_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_zcull_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_gpm_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_gcc_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_tpccs_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_tex_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_pe_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_l1c_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_wwdx_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_tpccs_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_mpc_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_be_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_fe_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_pe_1[]; + +extern const struct nvc0_graph_init nvc4_graph_init_ds_0[]; +extern const struct nvc0_graph_init nvc4_graph_init_tex_0[]; +extern const struct nvc0_graph_init nvc4_graph_init_sm_0[]; + +extern const struct nvc0_graph_init nvc1_graph_init_gpc_unk_0[]; +extern const struct nvc0_graph_init nvc1_graph_init_setup_1[]; + +extern const struct nvc0_graph_init nvd9_graph_init_pd_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_ds_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_prop_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_gpm_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvd9_graph_init_tex_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_sm_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_fe_1[]; + +extern const struct nvc0_graph_init nvd7_graph_init_pes_0[]; +extern const struct nvc0_graph_init nvd7_graph_init_wwdx_0[]; +extern const struct nvc0_graph_init nvd7_graph_init_cbm_0[]; + +extern const struct nvc0_graph_init nve4_graph_init_main_0[]; +extern const struct nvc0_graph_init nve4_graph_init_tpccs_0[]; +extern const struct nvc0_graph_init nve4_graph_init_pe_0[]; +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_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_sm_0[]; + +extern const struct nvc0_graph_init nv108_graph_init_gpc_unk_0[]; + #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c index bc4a469b86c..30cab0b2eba 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -39,94 +40,82 @@ nvc1_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -static struct nvc0_graph_init -nvc1_graph_init_gpc[] = { - { 0x4184a0, 1, 0x04, 0x00000000 }, +const struct nvc0_graph_init +nvc1_graph_init_gpc_unk_0[] = { { 0x418604, 1, 0x04, 0x00000000 }, { 0x418680, 1, 0x04, 0x00000000 }, { 0x418714, 1, 0x04, 0x00000000 }, { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc1_graph_init_setup_1[] = { { 0x4188c8, 2, 0x04, 0x00000000 }, { 0x4188d0, 1, 0x04, 0x00010000 }, { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc1_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000003 }, { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvc1_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ac8, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x41980c, 2, 0x04, 0x00000000 }, +static const struct nvc0_graph_init +nvc1_graph_init_pe_0[] = { + { 0x41980c, 1, 0x04, 0x00000010 }, + { 0x419810, 1, 0x04, 0x00000000 }, { 0x419814, 1, 0x04, 0x00000004 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x41984c, 1, 0x04, 0x00005bc5 }, { 0x419850, 4, 0x04, 0x00000000 }, { 0x419880, 1, 0x04, 0x00000002 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419bd4, 1, 0x04, 0x00800000 }, - { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, - { 0x419e00, 1, 0x04, 0x00000000 }, - { 0x419ea0, 1, 0x04, 0x00000000 }, - { 0x419ea4, 1, 0x04, 0x00000100 }, - { 0x419ea8, 1, 0x04, 0x00001100 }, - { 0x419eac, 1, 0x04, 0x11100702 }, - { 0x419eb0, 1, 0x04, 0x00000003 }, - { 0x419eb4, 4, 0x04, 0x00000000 }, - { 0x419ec8, 1, 0x04, 0x0e063818 }, - { 0x419ecc, 1, 0x04, 0x0e060e06 }, - { 0x419ed0, 1, 0x04, 0x00003818 }, - { 0x419ed4, 1, 0x04, 0x011104f1 }, - { 0x419edc, 1, 0x04, 0x00000000 }, - { 0x419f00, 1, 0x04, 0x00000000 }, - { 0x419f2c, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init * -nvc1_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc3_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc1_graph_init_gpc, - nvc1_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +static const struct nvc0_graph_pack +nvc1_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc4_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_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 }, + { nvc0_graph_init_gpm_0 }, + { nvc1_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc4_graph_init_tex_0 }, + { nvc1_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc4_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} }; +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * nvc1_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xc1), @@ -138,7 +127,7 @@ nvc1_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvc1_grctx_oclass, .sclass = nvc1_graph_sclass, - .mmio = nvc1_graph_init_mmio, + .mmio = nvc1_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c index d44b3b3ee80..e82e70c5313 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c @@ -23,13 +23,14 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nvc3_graph_init_unk58xx[] = { +const struct nvc0_graph_init +nvc4_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x00002834 }, @@ -37,29 +38,27 @@ nvc3_graph_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nvc3_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, +const struct nvc0_graph_init +nvc4_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, { 0x419abc, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc4_graph_init_pe_0[] = { { 0x41980c, 3, 0x04, 0x00000000 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x41984c, 1, 0x04, 0x00005bc5 }, { 0x419850, 4, 0x04, 0x00000000 }, { 0x419880, 1, 0x04, 0x00000002 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419bd4, 1, 0x04, 0x00800000 }, - { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc4_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -77,24 +76,43 @@ nvc3_graph_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvc3_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc3_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc0_graph_init_gpc, - nvc3_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +static const struct nvc0_graph_pack +nvc4_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc4_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_graph_init_prop_0 }, + { nvc0_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc0_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { nvc0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc4_graph_init_tex_0 }, + { nvc4_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc4_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} }; +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * -nvc3_graph_oclass = &(struct nvc0_graph_oclass) { +nvc4_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xc3), .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_graph_ctor, @@ -102,9 +120,9 @@ nvc3_graph_oclass = &(struct nvc0_graph_oclass) { .init = nvc0_graph_init, .fini = _nouveau_graph_fini, }, - .cclass = &nvc3_grctx_oclass, + .cclass = &nvc4_grctx_oclass, .sclass = nvc0_graph_sclass, - .mmio = nvc3_graph_init_mmio, + .mmio = nvc4_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c index 02845e56731..a6bf783e125 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -40,58 +41,11 @@ nvc8_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -static struct nvc0_graph_init -nvc8_graph_init_gpc[] = { - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x80000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418f08, 1, 0x04, 0x00000000 }, - { 0x418e00, 1, 0x04, 0x00000050 }, - { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, - {} -}; - -static struct nvc0_graph_init -nvc8_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x41980c, 3, 0x04, 0x00000000 }, - { 0x419844, 1, 0x04, 0x00000000 }, - { 0x41984c, 1, 0x04, 0x00005bc5 }, - { 0x419850, 4, 0x04, 0x00000000 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419bd4, 1, 0x04, 0x00800000 }, - { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_init +nvc8_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -108,22 +62,42 @@ nvc8_graph_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvc8_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc0_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc8_graph_init_gpc, - nvc8_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +static const struct nvc0_graph_pack +nvc8_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc0_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_graph_init_prop_0 }, + { nvc0_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 }, + { nvc0_graph_init_gpm_0 }, + { nvc0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc0_graph_init_tex_0 }, + { nvc0_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc8_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + { nvc0_graph_init_pe_1 }, + {} }; +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * nvc8_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xc8), @@ -135,7 +109,7 @@ nvc8_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvc8_grctx_oclass, .sclass = nvc8_graph_sclass, - .mmio = nvc8_graph_init_mmio, + .mmio = nvc8_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c index 5052d7ab4d7..2a6a94e2a04 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c @@ -23,6 +23,77 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" + +/******************************************************************************* + * PGRAPH register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvd7_graph_init_pe_0[] = { + { 0x41980c, 1, 0x04, 0x00000010 }, + { 0x419844, 1, 0x04, 0x00000000 }, + { 0x41984c, 1, 0x04, 0x00005bc8 }, + { 0x419850, 3, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd7_graph_init_pes_0[] = { + { 0x41be04, 1, 0x04, 0x00000000 }, + { 0x41be08, 1, 0x04, 0x00000004 }, + { 0x41be0c, 1, 0x04, 0x00000000 }, + { 0x41be10, 1, 0x04, 0x003b8bc7 }, + { 0x41be14, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd7_graph_init_wwdx_0[] = { + { 0x41bfd4, 1, 0x04, 0x00800000 }, + { 0x41bfdc, 1, 0x04, 0x00000000 }, + { 0x41bff8, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd7_graph_init_cbm_0[] = { + { 0x41becc, 1, 0x04, 0x00000000 }, + { 0x41bee8, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +nvd7_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nvd9_graph_init_ds_0 }, + { nvc0_graph_init_scc_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 }, + { nvd9_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvd9_graph_init_tex_0 }, + { nvd7_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nvd9_graph_init_sm_0 }, + { nvd7_graph_init_pes_0 }, + { nvd7_graph_init_wwdx_0 }, + { nvd7_graph_init_cbm_0 }, + { nvc0_graph_init_be_0 }, + { nvd9_graph_init_fe_1 }, + {} +}; /******************************************************************************* * PGRAPH engine/subdev functions @@ -48,108 +119,6 @@ nvd7_graph_gpccs_ucode = { .data.size = sizeof(nvd7_grgpc_data), }; -static struct nvc0_graph_init -nvd7_graph_init_gpc[] = { - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418cb4, 2, 0x04, 0x00000000 }, - { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418f00, 1, 0x04, 0x00000000 }, - { 0x418f08, 1, 0x04, 0x00000000 }, - { 0x418f20, 2, 0x04, 0x00000000 }, - { 0x418e00, 1, 0x04, 0x00000003 }, - { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x418e1c, 1, 0x04, 0x00000000 }, - { 0x418e20, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, - {} -}; - -static struct nvc0_graph_init -nvd7_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ac8, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x419ab4, 1, 0x04, 0x00000000 }, - { 0x41980c, 1, 0x04, 0x00000010 }, - { 0x419844, 1, 0x04, 0x00000000 }, - { 0x41984c, 1, 0x04, 0x00005bc8 }, - { 0x419850, 2, 0x04, 0x00000000 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, - { 0x419e00, 1, 0x04, 0x00000000 }, - { 0x419ea0, 1, 0x04, 0x00000000 }, - { 0x419ea4, 1, 0x04, 0x00000100 }, - { 0x419ea8, 1, 0x04, 0x02001100 }, - { 0x419eac, 1, 0x04, 0x11100702 }, - { 0x419eb0, 1, 0x04, 0x00000003 }, - { 0x419eb4, 4, 0x04, 0x00000000 }, - { 0x419ec8, 1, 0x04, 0x0e063818 }, - { 0x419ecc, 1, 0x04, 0x0e060e06 }, - { 0x419ed0, 1, 0x04, 0x00003818 }, - { 0x419ed4, 1, 0x04, 0x011104f1 }, - { 0x419edc, 1, 0x04, 0x00000000 }, - { 0x419f00, 1, 0x04, 0x00000000 }, - { 0x419f2c, 1, 0x04, 0x00000000 }, - {} -}; - -static struct nvc0_graph_init -nvd7_graph_init_tpc_0[] = { - { 0x40402c, 1, 0x04, 0x00000000 }, - { 0x4040f0, 1, 0x04, 0x00000000 }, - { 0x404174, 1, 0x04, 0x00000000 }, - { 0x503018, 1, 0x04, 0x00000001 }, - {} -}; - -static struct nvc0_graph_init * -nvd7_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nvd9_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvd7_graph_init_gpc, - nvd7_graph_init_tpc, - nve4_graph_init_unk, - nvc0_graph_init_unk88xx, - nvd7_graph_init_tpc_0, - NULL -}; - struct nouveau_oclass * nvd7_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xd7), @@ -161,7 +130,7 @@ nvd7_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvd7_grctx_oclass, .sclass = nvc8_graph_sclass, - .mmio = nvd7_graph_init_mmio, + .mmio = nvd7_graph_pack_mmio, .fecs.ucode = &nvd7_graph_fecs_ucode, .gpccs.ucode = &nvd7_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c index 652098e0df3..00fdf202fb9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c @@ -23,76 +23,70 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nvd9_graph_init_unk64xx[] = { +const struct nvc0_graph_init +nvd9_graph_init_pd_0[] = { + { 0x406024, 1, 0x04, 0x00000000 }, { 0x4064f0, 3, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvd9_graph_init_unk58xx[] = { +const struct nvc0_graph_init +nvd9_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x00002834 }, { 0x405908, 1, 0x04, 0x00000000 }, - { 0x405928, 1, 0x04, 0x00000000 }, - { 0x40592c, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvd9_graph_init_gpc[] = { +const struct nvc0_graph_init +nvd9_graph_init_prop_0[] = { { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, + { 0x4184a0, 3, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_graph_init_gpm_0[] = { { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, + { 0x418c64, 2, 0x04, 0x00000000 }, { 0x418c88, 1, 0x04, 0x00000000 }, { 0x418cb4, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418d2c, 1, 0x04, 0x00000000 }, + { 0x418d28, 2, 0x04, 0x00000000 }, { 0x418f00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418f20, 2, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000003 }, { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x418e1c, 1, 0x04, 0x00000000 }, - { 0x418e20, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, + { 0x418e1c, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvd9_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, +const struct nvc0_graph_init +nvd9_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, { 0x419abc, 2, 0x04, 0x00000000 }, { 0x419ab4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_graph_init_pe_0[] = { { 0x41980c, 1, 0x04, 0x00000010 }, { 0x419810, 1, 0x04, 0x00000000 }, { 0x419814, 1, 0x04, 0x00000004 }, @@ -100,20 +94,26 @@ nvd9_graph_init_tpc[] = { { 0x41984c, 1, 0x04, 0x0000a918 }, { 0x419850, 4, 0x04, 0x00000000 }, { 0x419880, 1, 0x04, 0x00000002 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_graph_init_wwdx_0[] = { { 0x419bd4, 1, 0x04, 0x00800000 }, { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419bf8, 1, 0x04, 0x00000000 }, - { 0x419bfc, 1, 0x04, 0x00000000 }, + { 0x419bf8, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_graph_init_tpccs_1[] = { { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419d48, 1, 0x04, 0x00000000 }, - { 0x419d4c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + { 0x419d48, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -131,23 +131,49 @@ nvd9_graph_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvd9_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nvd9_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvd9_graph_init_gpc, - nvd9_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +const struct nvc0_graph_init +nvd9_graph_init_fe_1[] = { + { 0x40402c, 1, 0x04, 0x00000000 }, + { 0x4040f0, 1, 0x04, 0x00000000 }, + { 0x404174, 1, 0x04, 0x00000000 }, + {} }; +static const struct nvc0_graph_pack +nvd9_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nvd9_graph_init_ds_0 }, + { nvc0_graph_init_scc_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 }, + { nvd9_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvd9_graph_init_tex_0 }, + { nvd9_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvd9_graph_init_wwdx_0 }, + { nvd9_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvd9_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvd9_graph_init_fe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * nvd9_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xd9), @@ -159,7 +185,7 @@ nvd9_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvd9_grctx_oclass, .sclass = nvc8_graph_sclass, - .mmio = nvd9_graph_init_mmio, + .mmio = nvd9_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c index 05ec09c8851..51e0c075ad3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -38,11 +39,11 @@ nve4_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nve4_graph_init_regs[] = { +const struct nvc0_graph_init +nve4_graph_init_main_0[] = { { 0x400080, 1, 0x04, 0x003083c2 }, { 0x400088, 1, 0x04, 0x0001ffe7 }, { 0x40008c, 1, 0x04, 0x00000000 }, @@ -57,81 +58,59 @@ nve4_graph_init_regs[] = { {} }; -static struct nvc0_graph_init -nve4_graph_init_unk58xx[] = { +static const struct nvc0_graph_init +nve4_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x0000ff34 }, { 0x405908, 1, 0x04, 0x00000000 }, - { 0x405928, 1, 0x04, 0x00000000 }, - { 0x40592c, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nve4_graph_init_unk70xx[] = { +static const struct nvc0_graph_init +nve4_graph_init_sked_0[] = { { 0x407010, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nve4_graph_init_unk5bxx[] = { +static const struct nvc0_graph_init +nve4_graph_init_cwd_0[] = { { 0x405b50, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nve4_graph_init_gpc[] = { - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418cb4, 2, 0x04, 0x00000000 }, +static const struct nvc0_graph_init +nve4_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418d2c, 1, 0x04, 0x00000000 }, + { 0x418d28, 2, 0x04, 0x00000000 }, { 0x418f00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418f20, 2, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000060 }, { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x418e1c, 1, 0x04, 0x00000000 }, - { 0x418e20, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, + { 0x418e1c, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nve4_graph_init_tpc[] = { +const struct nvc0_graph_init +nve4_graph_init_tpccs_0[] = { { 0x419d0c, 1, 0x04, 0x00000000 }, { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ac8, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x419ab4, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nve4_graph_init_pe_0[] = { { 0x41980c, 1, 0x04, 0x00000010 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x419850, 1, 0x04, 0x00000004 }, { 0x419854, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nve4_graph_init_l1c_0[] = { { 0x419c98, 1, 0x04, 0x00000000 }, { 0x419ca8, 1, 0x04, 0x00000000 }, { 0x419cb0, 1, 0x04, 0x01000000 }, @@ -141,39 +120,25 @@ nve4_graph_init_tpc[] = { { 0x419cbc, 1, 0x04, 0x28137646 }, { 0x419cc0, 2, 0x04, 0x00000000 }, { 0x419c80, 1, 0x04, 0x00020232 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nve4_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ee4, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, { 0x419ea8, 1, 0x04, 0x00000000 }, - { 0x419eb4, 1, 0x04, 0x00000000 }, - { 0x419eb8, 3, 0x04, 0x00000000 }, + { 0x419eb4, 4, 0x04, 0x00000000 }, { 0x419edc, 1, 0x04, 0x00000000 }, { 0x419f00, 1, 0x04, 0x00000000 }, { 0x419f74, 1, 0x04, 0x00000555 }, {} }; -struct nvc0_graph_init -nve4_graph_init_unk[] = { - { 0x41be04, 1, 0x04, 0x00000000 }, - { 0x41be08, 1, 0x04, 0x00000004 }, - { 0x41be0c, 1, 0x04, 0x00000000 }, - { 0x41be10, 1, 0x04, 0x003b8bc7 }, - { 0x41be14, 2, 0x04, 0x00000000 }, - { 0x41bfd4, 1, 0x04, 0x00800000 }, - { 0x41bfdc, 1, 0x04, 0x00000000 }, - { 0x41bff8, 1, 0x04, 0x00000000 }, - { 0x41bffc, 1, 0x04, 0x00000000 }, - { 0x41becc, 1, 0x04, 0x00000000 }, - { 0x41bee8, 1, 0x04, 0x00000000 }, - { 0x41beec, 1, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_init -nve4_graph_init_unk88xx[] = { +const struct nvc0_graph_init +nve4_graph_init_be_0[] = { { 0x40880c, 1, 0x04, 0x00000000 }, { 0x408850, 1, 0x04, 0x00000004 }, { 0x408910, 9, 0x04, 0x00000000 }, @@ -186,6 +151,67 @@ nve4_graph_init_unk88xx[] = { {} }; +const struct nvc0_graph_pack +nve4_graph_pack_mmio[] = { + { nve4_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nve4_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nve4_graph_init_sked_0 }, + { nve4_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 }, + { nve4_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nve4_graph_init_tpccs_0 }, + { nvd9_graph_init_tex_0 }, + { nve4_graph_init_pe_0 }, + { nve4_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nve4_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 + ******************************************************************************/ + +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) { @@ -210,8 +236,7 @@ nve4_graph_init(struct nouveau_object *object) nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); - for (i = 0; oclass->mmio[i]; i++) - nvc0_graph_mmio(priv, oclass->mmio[i]); + nvc0_graph_mmio(priv, oclass->mmio); nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); @@ -298,25 +323,6 @@ nve4_graph_init(struct nouveau_object *object) return nvc0_graph_init_ctxctl(priv); } -static struct nvc0_graph_init * -nve4_graph_init_mmio[] = { - nve4_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nve4_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nve4_graph_init_unk70xx, - nve4_graph_init_unk5bxx, - nve4_graph_init_gpc, - nve4_graph_init_tpc, - nve4_graph_init_unk, - nve4_graph_init_unk88xx, - NULL -}; - #include "fuc/hubnve0.fuc.h" static struct nvc0_graph_ucode @@ -344,11 +350,11 @@ nve4_graph_oclass = &(struct nvc0_graph_oclass) { .ctor = nvc0_graph_ctor, .dtor = nvc0_graph_dtor, .init = nve4_graph_init, - .fini = _nouveau_graph_fini, + .fini = nve4_graph_fini, }, .cclass = &nve4_grctx_oclass, .sclass = nve4_graph_sclass, - .mmio = nve4_graph_init_mmio, + .mmio = nve4_graph_pack_mmio, .fecs.ucode = &nve4_graph_fecs_ucode, .gpccs.ucode = &nve4_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c index 2f0ac783223..c96762122b9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -38,86 +39,57 @@ nvf0_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -static struct nvc0_graph_init -nvf0_graph_init_unk40xx[] = { +const struct nvc0_graph_init +nvf0_graph_init_fe_0[] = { { 0x40415c, 1, 0x04, 0x00000000 }, { 0x404170, 1, 0x04, 0x00000000 }, { 0x4041b4, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvf0_graph_init_unk58xx[] = { +static const struct nvc0_graph_init +nvf0_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x0000ff00 }, { 0x405908, 1, 0x04, 0x00000000 }, - { 0x405928, 1, 0x04, 0x00000000 }, - { 0x40592c, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvf0_graph_init_unk70xx[] = { +const struct nvc0_graph_init +nvf0_graph_init_sked_0[] = { { 0x407010, 1, 0x04, 0x00000000 }, { 0x407040, 1, 0x04, 0x80440424 }, { 0x407048, 1, 0x04, 0x0000000a }, {} }; -static struct nvc0_graph_init -nvf0_graph_init_unk5bxx[] = { +const struct nvc0_graph_init +nvf0_graph_init_cwd_0[] = { { 0x405b44, 1, 0x04, 0x00000000 }, { 0x405b50, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvf0_graph_init_gpc[] = { - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418cb4, 2, 0x04, 0x00000000 }, +const struct nvc0_graph_init +nvf0_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418d2c, 1, 0x04, 0x00000000 }, + { 0x418d28, 2, 0x04, 0x00000000 }, { 0x418f00, 1, 0x04, 0x00000400 }, { 0x418f08, 1, 0x04, 0x00000000 }, - { 0x418f20, 1, 0x04, 0x00000000 }, - { 0x418f24, 1, 0x04, 0x00000000 }, + { 0x418f20, 2, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000000 }, { 0x418e08, 1, 0x04, 0x00000000 }, { 0x418e1c, 2, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvf0_graph_init_tpc[] = { - { 0x419d0c, 1, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, +static const struct nvc0_graph_init +nvf0_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, @@ -125,10 +97,11 @@ nvf0_graph_init_tpc[] = { { 0x419abc, 2, 0x04, 0x00000000 }, { 0x419ab4, 1, 0x04, 0x00000000 }, { 0x419aa8, 2, 0x04, 0x00000000 }, - { 0x41980c, 1, 0x04, 0x00000010 }, - { 0x419844, 1, 0x04, 0x00000000 }, - { 0x419850, 1, 0x04, 0x00000004 }, - { 0x419854, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_graph_init_l1c_0[] = { { 0x419c98, 1, 0x04, 0x00000000 }, { 0x419ca8, 1, 0x04, 0x00000000 }, { 0x419cb0, 1, 0x04, 0x01000000 }, @@ -139,7 +112,11 @@ nvf0_graph_init_tpc[] = { { 0x419cc0, 2, 0x04, 0x00000000 }, { 0x419c80, 1, 0x04, 0x00020230 }, { 0x419ccc, 2, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvf0_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000080 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ee4, 1, 0x04, 0x00000000 }, @@ -155,6 +132,44 @@ nvf0_graph_init_tpc[] = { {} }; +static const struct nvc0_graph_pack +nvf0_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 }, + { nvf0_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nvf0_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 + ******************************************************************************/ + static int nvf0_graph_fini(struct nouveau_object *object, bool suspend) { @@ -192,25 +207,6 @@ nvf0_graph_fini(struct nouveau_object *object, bool suspend) return nouveau_graph_fini(&priv->base, suspend); } -static struct nvc0_graph_init * -nvf0_graph_init_mmio[] = { - nve4_graph_init_regs, - nvf0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nvf0_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvf0_graph_init_unk70xx, - nvf0_graph_init_unk5bxx, - nvf0_graph_init_gpc, - nvf0_graph_init_tpc, - nve4_graph_init_unk, - nve4_graph_init_unk88xx, - NULL -}; - #include "fuc/hubnvf0.fuc.h" static struct nvc0_graph_ucode @@ -242,7 +238,7 @@ nvf0_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvf0_grctx_oclass, .sclass = nvf0_graph_sclass, - .mmio = nvf0_graph_init_mmio, - .fecs.ucode = 0 ? &nvf0_graph_fecs_ucode : NULL, + .mmio = nvf0_graph_pack_mmio, + .fecs.ucode = &nvf0_graph_fecs_ucode, .gpccs.ucode = &nvf0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c index c1900430130..7eb6d94c84e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c @@ -34,16 +34,7 @@ #include <engine/fifo.h> #include <engine/mpeg.h> -#include <engine/graph/nv40.h> - -struct nv31_mpeg_priv { - struct nouveau_mpeg base; - atomic_t refcount; -}; - -struct nv31_mpeg_chan { - struct nouveau_object base; -}; +#include <engine/mpeg/nv31.h> /******************************************************************************* * MPEG object classes @@ -89,18 +80,18 @@ nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len) if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000)); + nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0); nv_wr32(priv, 0x00b334, base); nv_wr32(priv, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); + nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0); nv_wr32(priv, 0x00b360, base); nv_wr32(priv, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ - if (dma0 & 0x000c0000) + if (dma0 & 0x00030000) return -EINVAL; nv_wr32(priv, 0x00b370, base); @@ -110,7 +101,7 @@ nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len) return 0; } -static struct nouveau_ofuncs +struct nouveau_ofuncs nv31_mpeg_ofuncs = { .ctor = nv31_mpeg_object_ctor, .dtor = _nouveau_gpuobj_dtor, @@ -146,16 +137,23 @@ nv31_mpeg_context_ctor(struct nouveau_object *parent, { struct nv31_mpeg_priv *priv = (void *)engine; struct nv31_mpeg_chan *chan; + unsigned long flags; int ret; - if (!atomic_add_unless(&priv->refcount, 1, 1)) - return -EBUSY; - ret = nouveau_object_create(parent, engine, oclass, 0, &chan); *pobject = nv_object(chan); if (ret) return ret; + spin_lock_irqsave(&nv_engine(priv)->lock, flags); + if (priv->chan) { + spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); + nouveau_object_destroy(&chan->base); + *pobject = NULL; + return -EBUSY; + } + priv->chan = chan; + spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); return 0; } @@ -164,11 +162,15 @@ nv31_mpeg_context_dtor(struct nouveau_object *object) { struct nv31_mpeg_priv *priv = (void *)object->engine; struct nv31_mpeg_chan *chan = (void *)object; - atomic_dec(&priv->refcount); + unsigned long flags; + + spin_lock_irqsave(&nv_engine(priv)->lock, flags); + priv->chan = NULL; + spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); nouveau_object_destroy(&chan->base); } -static struct nouveau_oclass +struct nouveau_oclass nv31_mpeg_cclass = { .handle = NV_ENGCTX(MPEG, 0x31), .ofuncs = &(struct nouveau_ofuncs) { @@ -197,21 +199,19 @@ nv31_mpeg_tile_prog(struct nouveau_engine *engine, int i) void nv31_mpeg_intr(struct nouveau_subdev *subdev) { + struct nv31_mpeg_priv *priv = (void *)subdev; struct nouveau_fifo *pfifo = nouveau_fifo(subdev); - struct nouveau_engine *engine = nv_engine(subdev); - struct nouveau_object *engctx; struct nouveau_handle *handle; - struct nv31_mpeg_priv *priv = (void *)subdev; - u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff; + struct nouveau_object *engctx; u32 stat = nv_rd32(priv, 0x00b100); u32 type = nv_rd32(priv, 0x00b230); u32 mthd = nv_rd32(priv, 0x00b234); u32 data = nv_rd32(priv, 0x00b238); u32 show = stat; - int chid; + unsigned long flags; - engctx = nouveau_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + spin_lock_irqsave(&nv_engine(priv)->lock, flags); + engctx = nv_object(priv->chan); if (stat & 0x01000000) { /* happens on initial binding of the object */ @@ -220,7 +220,7 @@ nv31_mpeg_intr(struct nouveau_subdev *subdev) show &= ~0x01000000; } - if (type == 0x00000010) { + if (type == 0x00000010 && engctx) { handle = nouveau_handle_get_class(engctx, 0x3174); if (handle && !nv_call(handle->object, mthd, data)) show &= ~0x01000000; @@ -232,13 +232,12 @@ nv31_mpeg_intr(struct nouveau_subdev *subdev) nv_wr32(priv, 0x00b230, 0x00000001); if (show) { - nv_error(priv, - "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n", - chid, inst << 4, nouveau_client_name(engctx), stat, - type, mthd, data); + nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n", + pfifo->chid(pfifo, engctx), + nouveau_client_name(engctx), stat, type, mthd, data); } - nouveau_engctx_put(engctx); + spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); } static int @@ -284,10 +283,7 @@ nv31_mpeg_init(struct nouveau_object *object) /* PMPEG init */ nv_wr32(priv, 0x00b32c, 0x00000000); nv_wr32(priv, 0x00b314, 0x00000100); - if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv)) - nv_wr32(priv, 0x00b220, 0x00000044); - else - nv_wr32(priv, 0x00b220, 0x00000031); + nv_wr32(priv, 0x00b220, 0x00000031); nv_wr32(priv, 0x00b300, 0x02001ec1); nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h new file mode 100644 index 00000000000..d08629d0b6a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h @@ -0,0 +1,15 @@ +#ifndef __NV31_MPEG_H__ +#define __NV31_MPEG_H__ + +#include <engine/mpeg.h> + +struct nv31_mpeg_chan { + struct nouveau_object base; +}; + +struct nv31_mpeg_priv { + struct nouveau_mpeg base; + struct nv31_mpeg_chan *chan; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c index dd6196072e9..d4e7ec0ba68 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c @@ -31,66 +31,63 @@ #include <subdev/instmem.h> #include <engine/mpeg.h> -#include <engine/graph/nv40.h> - -struct nv40_mpeg_priv { - struct nouveau_mpeg base; -}; - -struct nv40_mpeg_chan { - struct nouveau_mpeg_chan base; -}; +#include <engine/mpeg/nv31.h> /******************************************************************************* - * PMPEG context + * MPEG object classes ******************************************************************************/ static int -nv40_mpeg_context_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +nv40_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len) { - struct nv40_mpeg_chan *chan; - int ret; - - ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, - 264 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + struct nouveau_instmem *imem = nouveau_instmem(object); + struct nv31_mpeg_priv *priv = (void *)object->engine; + u32 inst = *(u32 *)arg << 4; + u32 dma0 = nv_ro32(imem, inst + 0); + u32 dma1 = nv_ro32(imem, inst + 4); + u32 dma2 = nv_ro32(imem, inst + 8); + u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); + u32 size = dma1 + 1; + + /* only allow linear DMA objects */ + if (!(dma0 & 0x00002000)) + return -EINVAL; + + if (mthd == 0x0190) { + /* DMA_CMD */ + nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000)); + nv_wr32(priv, 0x00b334, base); + nv_wr32(priv, 0x00b324, size); + } else + if (mthd == 0x01a0) { + /* DMA_DATA */ + nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); + nv_wr32(priv, 0x00b360, base); + nv_wr32(priv, 0x00b364, size); + } else { + /* DMA_IMAGE, VRAM only */ + if (dma0 & 0x00030000) + return -EINVAL; + + nv_wr32(priv, 0x00b370, base); + nv_wr32(priv, 0x00b374, size); + } - nv_wo32(&chan->base.base, 0x78, 0x02001ec1); return 0; } -static int -nv40_mpeg_context_fini(struct nouveau_object *object, bool suspend) -{ - - struct nv40_mpeg_priv *priv = (void *)object->engine; - struct nv40_mpeg_chan *chan = (void *)object; - u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4; - - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000); - if (nv_rd32(priv, 0x00b318) == inst) - nv_mask(priv, 0x00b318, 0x80000000, 0x00000000); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); - return 0; -} +static struct nouveau_omthds +nv40_mpeg_omthds[] = { + { 0x0190, 0x0190, nv40_mpeg_mthd_dma }, + { 0x01a0, 0x01a0, nv40_mpeg_mthd_dma }, + { 0x01b0, 0x01b0, nv40_mpeg_mthd_dma }, + {} +}; -static struct nouveau_oclass -nv40_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x40), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv40_mpeg_context_ctor, - .dtor = _nouveau_mpeg_context_dtor, - .init = _nouveau_mpeg_context_init, - .fini = nv40_mpeg_context_fini, - .rd32 = _nouveau_mpeg_context_rd32, - .wr32 = _nouveau_mpeg_context_wr32, - }, +struct nouveau_oclass +nv40_mpeg_sclass[] = { + { 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds }, + {} }; /******************************************************************************* @@ -100,7 +97,7 @@ nv40_mpeg_cclass = { static void nv40_mpeg_intr(struct nouveau_subdev *subdev) { - struct nv40_mpeg_priv *priv = (void *)subdev; + struct nv31_mpeg_priv *priv = (void *)subdev; u32 stat; if ((stat = nv_rd32(priv, 0x00b100))) @@ -117,7 +114,7 @@ nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv40_mpeg_priv *priv; + struct nv31_mpeg_priv *priv; int ret; ret = nouveau_mpeg_create(parent, engine, oclass, &priv); @@ -127,8 +124,8 @@ nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_subdev(priv)->unit = 0x00000002; nv_subdev(priv)->intr = nv40_mpeg_intr; - nv_engine(priv)->cclass = &nv40_mpeg_cclass; - nv_engine(priv)->sclass = nv31_mpeg_sclass; + nv_engine(priv)->cclass = &nv31_mpeg_cclass; + nv_engine(priv)->sclass = nv40_mpeg_sclass; nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c new file mode 100644 index 00000000000..3d8c2133e0e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c @@ -0,0 +1,194 @@ +/* + * 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 <core/os.h> +#include <core/class.h> +#include <core/client.h> +#include <core/engctx.h> +#include <core/handle.h> + +#include <subdev/fb.h> +#include <subdev/timer.h> +#include <subdev/instmem.h> + +#include <engine/fifo.h> +#include <engine/mpeg.h> + +struct nv44_mpeg_priv { + struct nouveau_mpeg base; +}; + +struct nv44_mpeg_chan { + struct nouveau_mpeg_chan base; +}; + +/******************************************************************************* + * PMPEG context + ******************************************************************************/ + +static int +nv44_mpeg_context_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv44_mpeg_chan *chan; + int ret; + + ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, + 264 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + nv_wo32(&chan->base.base, 0x78, 0x02001ec1); + return 0; +} + +static int +nv44_mpeg_context_fini(struct nouveau_object *object, bool suspend) +{ + + struct nv44_mpeg_priv *priv = (void *)object->engine; + struct nv44_mpeg_chan *chan = (void *)object; + u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4; + + nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000); + if (nv_rd32(priv, 0x00b318) == inst) + nv_mask(priv, 0x00b318, 0x80000000, 0x00000000); + nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + return 0; +} + +static struct nouveau_oclass +nv44_mpeg_cclass = { + .handle = NV_ENGCTX(MPEG, 0x44), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv44_mpeg_context_ctor, + .dtor = _nouveau_mpeg_context_dtor, + .init = _nouveau_mpeg_context_init, + .fini = nv44_mpeg_context_fini, + .rd32 = _nouveau_mpeg_context_rd32, + .wr32 = _nouveau_mpeg_context_wr32, + }, +}; + +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ + +static void +nv44_mpeg_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_fifo *pfifo = nouveau_fifo(subdev); + struct nouveau_engine *engine = nv_engine(subdev); + struct nouveau_object *engctx; + struct nouveau_handle *handle; + struct nv44_mpeg_priv *priv = (void *)subdev; + u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff; + u32 stat = nv_rd32(priv, 0x00b100); + u32 type = nv_rd32(priv, 0x00b230); + u32 mthd = nv_rd32(priv, 0x00b234); + u32 data = nv_rd32(priv, 0x00b238); + u32 show = stat; + int chid; + + engctx = nouveau_engctx_get(engine, inst); + chid = pfifo->chid(pfifo, engctx); + + if (stat & 0x01000000) { + /* happens on initial binding of the object */ + if (type == 0x00000020 && mthd == 0x0000) { + nv_mask(priv, 0x00b308, 0x00000000, 0x00000000); + show &= ~0x01000000; + } + + if (type == 0x00000010) { + handle = nouveau_handle_get_class(engctx, 0x3174); + if (handle && !nv_call(handle->object, mthd, data)) + show &= ~0x01000000; + nouveau_handle_put(handle); + } + } + + nv_wr32(priv, 0x00b100, stat); + nv_wr32(priv, 0x00b230, 0x00000001); + + if (show) { + nv_error(priv, + "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n", + chid, inst << 4, nouveau_client_name(engctx), stat, + type, mthd, data); + } + + nouveau_engctx_put(engctx); +} + +static void +nv44_mpeg_me_intr(struct nouveau_subdev *subdev) +{ + struct nv44_mpeg_priv *priv = (void *)subdev; + u32 stat; + + if ((stat = nv_rd32(priv, 0x00b100))) + nv44_mpeg_intr(subdev); + + if ((stat = nv_rd32(priv, 0x00b800))) { + nv_error(priv, "PMSRCH 0x%08x\n", stat); + nv_wr32(priv, 0x00b800, stat); + } +} + +static int +nv44_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv44_mpeg_priv *priv; + int ret; + + ret = nouveau_mpeg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->unit = 0x00000002; + nv_subdev(priv)->intr = nv44_mpeg_me_intr; + nv_engine(priv)->cclass = &nv44_mpeg_cclass; + nv_engine(priv)->sclass = nv40_mpeg_sclass; + nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; + return 0; +} + +struct nouveau_oclass +nv44_mpeg_oclass = { + .handle = NV_ENGINE(MPEG, 0x44), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv44_mpeg_ctor, + .dtor = _nouveau_mpeg_dtor, + .init = nv31_mpeg_init, + .fini = _nouveau_mpeg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c new file mode 100644 index 00000000000..e9c5e51943e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c @@ -0,0 +1,449 @@ +/* + * 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 <core/option.h> +#include <core/class.h> + +#include <subdev/clock.h> + +#include "priv.h" + +#define QUAD_MASK 0x0f +#define QUAD_FREE 0x01 + +static struct nouveau_perfsig * +nouveau_perfsig_find_(struct nouveau_perfdom *dom, const char *name, u32 size) +{ + char path[64]; + int i; + + if (name[0] != '/') { + for (i = 0; i < dom->signal_nr; i++) { + if ( dom->signal[i].name && + !strncmp(name, dom->signal[i].name, size)) + return &dom->signal[i]; + } + } else { + for (i = 0; i < dom->signal_nr; i++) { + snprintf(path, sizeof(path), "/%s/%02x", dom->name, i); + if (!strncmp(name, path, size)) + return &dom->signal[i]; + } + } + + return NULL; +} + +struct nouveau_perfsig * +nouveau_perfsig_find(struct nouveau_perfmon *ppm, const char *name, u32 size, + struct nouveau_perfdom **pdom) +{ + struct nouveau_perfdom *dom = *pdom; + struct nouveau_perfsig *sig; + + if (dom == NULL) { + list_for_each_entry(dom, &ppm->domains, head) { + sig = nouveau_perfsig_find_(dom, name, size); + if (sig) { + *pdom = dom; + return sig; + } + } + + return NULL; + } + + return nouveau_perfsig_find_(dom, name, size); +} + +struct nouveau_perfctr * +nouveau_perfsig_wrap(struct nouveau_perfmon *ppm, const char *name, + struct nouveau_perfdom **pdom) +{ + struct nouveau_perfsig *sig; + struct nouveau_perfctr *ctr; + + sig = nouveau_perfsig_find(ppm, name, strlen(name), pdom); + if (!sig) + return NULL; + + ctr = kzalloc(sizeof(*ctr), GFP_KERNEL); + if (ctr) { + ctr->signal[0] = sig; + ctr->logic_op = 0xaaaa; + } + + return ctr; +} + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ +static int +nouveau_perfctr_query(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + 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; + + di = (args->iter & 0xff000000) >> 24; + si = (args->iter & 0x00ffffff) - 1; + + list_for_each_entry(chk, &ppm->domains, head) { + if (tmp++ == di) { + dom = chk; + break; + } + } + + if (dom == NULL || si >= (int)dom->signal_nr) + return -EINVAL; + + if (si >= 0) { + if (raw || !(name = dom->signal[si].name)) { + snprintf(path, sizeof(path), "/%s/%02x", dom->name, si); + name = path; + } + + 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; + return 0; + } + } + si = -1; + di = di + 1; + dom = list_entry(dom->head.next, typeof(*dom), head); + } while (&dom->head != &ppm->domains); + + args->iter = 0xffffffff; + return 0; +} + +static int +nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + struct nouveau_perfmon *ppm = (void *)object->engine; + struct nouveau_perfctr *ctr, *tmp; + struct nouveau_perfdom *dom; + struct nv_perfctr_sample *args = data; + + if (size < sizeof(*args)) + return -EINVAL; + ppm->sequence++; + + list_for_each_entry(dom, &ppm->domains, head) { + /* sample previous batch of counters */ + if (dom->quad != QUAD_MASK) { + dom->func->next(ppm, dom); + tmp = NULL; + while (!list_empty(&dom->list)) { + ctr = list_first_entry(&dom->list, + typeof(*ctr), head); + if (ctr->slot < 0) break; + if ( tmp && tmp == ctr) break; + if (!tmp) tmp = ctr; + dom->func->read(ppm, dom, ctr); + ctr->slot = -1; + list_move_tail(&ctr->head, &dom->list); + } + } + + dom->quad = QUAD_MASK; + + /* setup next batch of counters for sampling */ + list_for_each_entry(ctr, &dom->list, head) { + ctr->slot = ffs(dom->quad) - 1; + if (ctr->slot < 0) + break; + dom->quad &= ~(QUAD_FREE << ctr->slot); + dom->func->init(ppm, dom, ctr); + } + + if (dom->quad != QUAD_MASK) + dom->func->next(ppm, dom); + } + + return 0; +} + +static int +nouveau_perfctr_read(struct nouveau_object *object, u32 mthd, + void *data, u32 size) +{ + struct nouveau_perfctr *ctr = (void *)object; + struct nv_perfctr_read *args = data; + + if (size < sizeof(*args)) + return -EINVAL; + if (!ctr->clk) + return -EAGAIN; + + args->clk = ctr->clk; + args->ctr = ctr->ctr; + return 0; +} + +static void +nouveau_perfctr_dtor(struct nouveau_object *object) +{ + struct nouveau_perfctr *ctr = (void *)object; + if (ctr->head.next) + list_del(&ctr->head); + nouveau_object_destroy(&ctr->base); +} + +static int +nouveau_perfctr_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + 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; + + 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); + if (!sig[i]) + return -EINVAL; + } + + ret = nouveau_object_create(parent, engine, oclass, 0, &ctr); + *pobject = nv_object(ctr); + if (ret) + return ret; + + ctr->slot = -1; + ctr->logic_op = args->logic_op; + ctr->signal[0] = sig[0]; + ctr->signal[1] = sig[1]; + ctr->signal[2] = sig[2]; + ctr->signal[3] = sig[3]; + if (dom) + list_add_tail(&ctr->head, &dom->list); + return 0; +} + +static struct nouveau_ofuncs +nouveau_perfctr_ofuncs = { + .ctor = nouveau_perfctr_ctor, + .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 }, + {} +}; + +struct nouveau_oclass +nouveau_perfmon_sclass[] = { + { .handle = NV_PERFCTR_CLASS, + .ofuncs = &nouveau_perfctr_ofuncs, + .omthds = nouveau_perfctr_omthds, + }, + {}, +}; + +/******************************************************************************* + * PPM context + ******************************************************************************/ +static void +nouveau_perfctx_dtor(struct nouveau_object *object) +{ + struct nouveau_perfmon *ppm = (void *)object->engine; + mutex_lock(&nv_subdev(ppm)->mutex); + ppm->context = NULL; + mutex_unlock(&nv_subdev(ppm)->mutex); +} + +static int +nouveau_perfctx_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_perfmon *ppm = (void *)engine; + struct nouveau_perfctx *ctx; + int ret; + + ret = nouveau_engctx_create(parent, engine, oclass, NULL, + 0, 0, 0, &ctx); + *pobject = nv_object(ctx); + if (ret) + return ret; + + mutex_lock(&nv_subdev(ppm)->mutex); + if (ppm->context == NULL) + ppm->context = ctx; + mutex_unlock(&nv_subdev(ppm)->mutex); + + if (ctx != ppm->context) + return -EBUSY; + + return 0; +} + +struct nouveau_oclass +nouveau_perfmon_cclass = { + .handle = NV_ENGCTX(PERFMON, 0x00), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nouveau_perfctx_ctor, + .dtor = nouveau_perfctx_dtor, + .init = _nouveau_engctx_init, + .fini = _nouveau_engctx_fini, + }, +}; + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ +int +nouveau_perfdom_new(struct nouveau_perfmon *ppm, const char *name, u32 mask, + u32 base, u32 size_unit, u32 size_domain, + const struct nouveau_specdom *spec) +{ + const struct nouveau_specdom *sdom; + const struct nouveau_specsig *ssig; + struct nouveau_perfdom *dom; + int i; + + for (i = 0; i == 0 || mask; i++) { + u32 addr = base + (i * size_unit); + if (i && !(mask & (1 << i))) + continue; + + sdom = spec; + while (sdom->signal_nr) { + dom = kzalloc(sizeof(*dom) + sdom->signal_nr * + sizeof(*dom->signal), GFP_KERNEL); + if (!dom) + return -ENOMEM; + + if (mask) { + snprintf(dom->name, sizeof(dom->name), + "%s/%02x/%02x", name, i, + (int)(sdom - spec)); + } else { + snprintf(dom->name, sizeof(dom->name), + "%s/%02x", name, (int)(sdom - spec)); + } + + list_add_tail(&dom->head, &ppm->domains); + INIT_LIST_HEAD(&dom->list); + dom->func = sdom->func; + dom->addr = addr; + dom->quad = QUAD_MASK; + dom->signal_nr = sdom->signal_nr; + + ssig = (sdom++)->signal; + while (ssig->name) { + dom->signal[ssig->signal].name = ssig->name; + ssig++; + } + + addr += size_domain; + } + + mask &= ~(1 << i); + } + + return 0; +} + +int +_nouveau_perfmon_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_perfmon *ppm = (void *)object; + return nouveau_engine_fini(&ppm->base, suspend); +} + +int +_nouveau_perfmon_init(struct nouveau_object *object) +{ + struct nouveau_perfmon *ppm = (void *)object; + return nouveau_engine_init(&ppm->base); +} + +void +_nouveau_perfmon_dtor(struct nouveau_object *object) +{ + struct nouveau_perfmon *ppm = (void *)object; + struct nouveau_perfdom *dom, *tmp; + + list_for_each_entry_safe(dom, tmp, &ppm->domains, head) { + list_del(&dom->head); + kfree(dom); + } + + nouveau_engine_destroy(&ppm->base); +} + +int +nouveau_perfmon_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + int length, void **pobject) +{ + struct nouveau_perfmon *ppm; + int ret; + + ret = nouveau_engine_create_(parent, engine, oclass, true, "PPM", + "perfmon", length, pobject); + ppm = *pobject; + if (ret) + return ret; + + INIT_LIST_HEAD(&ppm->domains); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c new file mode 100644 index 00000000000..50696cc7b7d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c @@ -0,0 +1,109 @@ +/* + * 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" + +static void +pwr_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom, + struct nouveau_perfctr *ctr) +{ + u32 mask = 0x00000000; + u32 ctrl = 0x00000001; + int i; + + for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++) + mask |= 1 << (ctr->signal[i] - dom->signal); + + nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask); + nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl); + nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003); +} + +static void +pwr_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom, + struct nouveau_perfctr *ctr) +{ + ctr->ctr = ppm->pwr[ctr->slot]; + ctr->clk = ppm->pwr[ppm->last]; +} + +static void +pwr_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom) +{ + int i; + + for (i = 0; i <= ppm->last; i++) { + ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10)); + nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000); + } +} + +static const struct nouveau_funcdom +pwr_perfctr_func = { + .init = pwr_perfctr_init, + .read = pwr_perfctr_read, + .next = pwr_perfctr_next, +}; + +const struct nouveau_specdom +nva3_perfmon_pwr[] = { + { 0x20, (const struct nouveau_specsig[]) { + { 0x00, "pwr_gr_idle" }, + { 0x04, "pwr_bsp_idle" }, + { 0x05, "pwr_vp_idle" }, + { 0x06, "pwr_ppp_idle" }, + { 0x13, "pwr_ce0_idle" }, + {} + }, &pwr_perfctr_func }, + {} +}; + +const struct nouveau_specdom +nvc0_perfmon_pwr[] = { + { 0x20, (const struct nouveau_specsig[]) { + { 0x00, "pwr_gr_idle" }, + { 0x04, "pwr_bsp_idle" }, + { 0x05, "pwr_vp_idle" }, + { 0x06, "pwr_ppp_idle" }, + { 0x13, "pwr_ce0_idle" }, + { 0x14, "pwr_ce1_idle" }, + {} + }, &pwr_perfctr_func }, + {} +}; + +const struct nouveau_specdom +nve0_perfmon_pwr[] = { + { 0x20, (const struct nouveau_specsig[]) { + { 0x00, "pwr_gr_idle" }, + { 0x04, "pwr_bsp_idle" }, + { 0x05, "pwr_vp_idle" }, + { 0x06, "pwr_ppp_idle" }, + { 0x13, "pwr_ce0_idle" }, + { 0x14, "pwr_ce1_idle" }, + { 0x15, "pwr_ce2_idle" }, + {} + }, &pwr_perfctr_func }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c new file mode 100644 index 00000000000..b2a10785adb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c @@ -0,0 +1,143 @@ +/* + * 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 "nv40.h" + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ + +/******************************************************************************* + * PPM context + ******************************************************************************/ + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + +static void +nv40_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom, + struct nouveau_perfctr *ctr) +{ + struct nv40_perfmon_priv *priv = (void *)ppm; + struct nv40_perfmon_cntr *cntr = (void *)ctr; + u32 log = ctr->logic_op; + u32 src = 0x00000000; + int i; + + for (i = 0; i < 4 && ctr->signal[i]; i++) + src |= (ctr->signal[i] - dom->signal) << (i * 8); + + nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001); + nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); + nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); +} + +static void +nv40_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom, + struct nouveau_perfctr *ctr) +{ + struct nv40_perfmon_priv *priv = (void *)ppm; + struct nv40_perfmon_cntr *cntr = (void *)ctr; + + switch (cntr->base.slot) { + case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break; + case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break; + case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break; + case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break; + } + cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr); +} + +static void +nv40_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom) +{ + struct nv40_perfmon_priv *priv = (void *)ppm; + if (priv->sequence != ppm->sequence) { + nv_wr32(priv, 0x400084, 0x00000020); + priv->sequence = ppm->sequence; + } +} + +const struct nouveau_funcdom +nv40_perfctr_func = { + .init = nv40_perfctr_init, + .read = nv40_perfctr_read, + .next = nv40_perfctr_next, +}; + +static const struct nouveau_specdom +nv40_perfmon[] = { + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + {} +}; + +int +nv40_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv40_perfmon_oclass *mclass = (void *)oclass; + struct nv40_perfmon_priv *priv; + int ret; + + ret = nouveau_perfmon_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nouveau_perfmon_cclass; + nv_engine(priv)->sclass = nouveau_perfmon_sclass; + return 0; +} + +struct nouveau_oclass * +nv40_perfmon_oclass = &(struct nv40_perfmon_oclass) { + .base.handle = NV_ENGINE(PERFMON, 0x40), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_perfmon_ctor, + .dtor = _nouveau_perfmon_dtor, + .init = _nouveau_perfmon_init, + .fini = _nouveau_perfmon_fini, + }, + .doms = nv40_perfmon, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h new file mode 100644 index 00000000000..1b5792d1df1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h @@ -0,0 +1,26 @@ +#ifndef __NVKM_PM_NV40_H__ +#define __NVKM_PM_NV40_H__ + +#include "priv.h" + +struct nv40_perfmon_oclass { + struct nouveau_oclass base; + const struct nouveau_specdom *doms; +}; + +struct nv40_perfmon_priv { + struct nouveau_perfmon base; + u32 sequence; +}; + +int nv40_perfmon_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *data, u32 size, + struct nouveau_object **pobject); + +struct nv40_perfmon_cntr { + struct nouveau_perfctr base; +}; + +extern const struct nouveau_funcdom nv40_perfctr_func; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c new file mode 100644 index 00000000000..94217691fe6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c @@ -0,0 +1,70 @@ +/* + * 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 "nv40.h" + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ + +/******************************************************************************* + * PPM context + ******************************************************************************/ + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + +static const struct nouveau_specdom +nv50_perfmon[] = { + { 0x040, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x100, (const struct nouveau_specsig[]) { + { 0xc8, "gr_idle" }, + {} + }, &nv40_perfctr_func }, + { 0x100, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x020, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x040, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + {} +}; + +struct nouveau_oclass * +nv50_perfmon_oclass = &(struct nv40_perfmon_oclass) { + .base.handle = NV_ENGINE(PERFMON, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_perfmon_ctor, + .dtor = _nouveau_perfmon_dtor, + .init = _nouveau_perfmon_init, + .fini = _nouveau_perfmon_fini, + }, + .doms = nv50_perfmon, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c new file mode 100644 index 00000000000..9232c7fc625 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c @@ -0,0 +1,78 @@ +/* + * 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 "nv40.h" + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ + +/******************************************************************************* + * PPM context + ******************************************************************************/ + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + +static const struct nouveau_specdom +nv84_perfmon[] = { + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + {} +}; + +struct nouveau_oclass * +nv84_perfmon_oclass = &(struct nv40_perfmon_oclass) { + .base.handle = NV_ENGINE(PERFMON, 0x84), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_perfmon_ctor, + .dtor = _nouveau_perfmon_dtor, + .init = _nouveau_perfmon_init, + .fini = _nouveau_perfmon_fini, + }, + .doms = nv84_perfmon, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c new file mode 100644 index 00000000000..6197ebdeb64 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c @@ -0,0 +1,96 @@ +/* + * 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 "nv40.h" + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ + +/******************************************************************************* + * PPM context + ******************************************************************************/ + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + +static const struct nouveau_specdom +nva3_perfmon[] = { + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nouveau_specsig[]) { + {} + }, &nv40_perfctr_func }, + {} +}; + +static int +nva3_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **object) +{ + int ret = nv40_perfmon_ctor(parent, engine, oclass, data, size, object); + if (ret == 0) { + struct nv40_perfmon_priv *priv = (void *)*object; + ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, + nva3_perfmon_pwr); + if (ret) + return ret; + + priv->base.last = 3; + } + return ret; +} + +struct nouveau_oclass * +nva3_perfmon_oclass = &(struct nv40_perfmon_oclass) { + .base.handle = NV_ENGINE(PERFMON, 0xa3), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nva3_perfmon_ctor, + .dtor = _nouveau_perfmon_dtor, + .init = _nouveau_perfmon_init, + .fini = _nouveau_perfmon_fini, + }, + .doms = nva3_perfmon, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c new file mode 100644 index 00000000000..74b24104250 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c @@ -0,0 +1,173 @@ +/* + * 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 "nvc0.h" + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ + +/******************************************************************************* + * PPM context + ******************************************************************************/ + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + +static const struct nouveau_specdom +nvc0_perfmon_hub[] = { + {} +}; + +static const struct nouveau_specdom +nvc0_perfmon_gpc[] = { + {} +}; + +static const struct nouveau_specdom +nvc0_perfmon_part[] = { + {} +}; + +static void +nvc0_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom, + struct nouveau_perfctr *ctr) +{ + struct nvc0_perfmon_priv *priv = (void *)ppm; + struct nvc0_perfmon_cntr *cntr = (void *)ctr; + u32 log = ctr->logic_op; + u32 src = 0x00000000; + int i; + + for (i = 0; i < 4 && ctr->signal[i]; i++) + src |= (ctr->signal[i] - dom->signal) << (i * 8); + + nv_wr32(priv, dom->addr + 0x09c, 0x00040002); + nv_wr32(priv, dom->addr + 0x100, 0x00000000); + nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); + nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); +} + +static void +nvc0_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom, + struct nouveau_perfctr *ctr) +{ + struct nvc0_perfmon_priv *priv = (void *)ppm; + struct nvc0_perfmon_cntr *cntr = (void *)ctr; + + switch (cntr->base.slot) { + case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break; + case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break; + case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break; + case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break; + } + cntr->base.clk = nv_rd32(priv, dom->addr + 0x070); +} + +static void +nvc0_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom) +{ + struct nvc0_perfmon_priv *priv = (void *)ppm; + nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27); + nv_wr32(priv, dom->addr + 0x0ec, 0x00000011); +} + +const struct nouveau_funcdom +nvc0_perfctr_func = { + .init = nvc0_perfctr_init, + .read = nvc0_perfctr_read, + .next = nvc0_perfctr_next, +}; + +int +nvc0_perfmon_fini(struct nouveau_object *object, bool suspend) +{ + struct nvc0_perfmon_priv *priv = (void *)object; + nv_mask(priv, 0x000200, 0x10000000, 0x00000000); + nv_mask(priv, 0x000200, 0x10000000, 0x10000000); + return nouveau_perfmon_fini(&priv->base, suspend); +} + +static int +nvc0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_perfmon_priv *priv; + u32 mask; + int ret; + + ret = nouveau_perfmon_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, + nvc0_perfmon_pwr); + if (ret) + return ret; + + /* HUB */ + ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, + nvc0_perfmon_hub); + if (ret) + return ret; + + /* GPC */ + mask = (1 << nv_rd32(priv, 0x022430)) - 1; + mask &= ~nv_rd32(priv, 0x022504); + mask &= ~nv_rd32(priv, 0x022584); + + ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000, + 0x1000, 0x200, nvc0_perfmon_gpc); + if (ret) + return ret; + + /* PART */ + mask = (1 << nv_rd32(priv, 0x022438)) - 1; + mask &= ~nv_rd32(priv, 0x022548); + mask &= ~nv_rd32(priv, 0x0225c8); + + ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000, + 0x1000, 0x200, nvc0_perfmon_part); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nouveau_perfmon_cclass; + nv_engine(priv)->sclass = nouveau_perfmon_sclass; + priv->base.last = 7; + return 0; +} + +struct nouveau_oclass +nvc0_perfmon_oclass = { + .handle = NV_ENGINE(PERFMON, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_perfmon_ctor, + .dtor = _nouveau_perfmon_dtor, + .init = _nouveau_perfmon_init, + .fini = nvc0_perfmon_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h new file mode 100644 index 00000000000..f66bca48426 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h @@ -0,0 +1,17 @@ +#ifndef __NVKM_PM_NVC0_H__ +#define __NVKM_PM_NVC0_H__ + +#include "priv.h" + +struct nvc0_perfmon_priv { + struct nouveau_perfmon base; +}; + +struct nvc0_perfmon_cntr { + struct nouveau_perfctr base; +}; + +extern const struct nouveau_funcdom nvc0_perfctr_func; +int nvc0_perfmon_fini(struct nouveau_object *, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c new file mode 100644 index 00000000000..71d718c1207 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c @@ -0,0 +1,162 @@ +/* + * 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 "nvc0.h" + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ + +/******************************************************************************* + * PPM context + ******************************************************************************/ + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + +static const struct nouveau_specdom +nve0_perfmon_hub[] = { + { 0x60, (const struct nouveau_specsig[]) { + { 0x47, "hub00_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0x40, (const struct nouveau_specsig[]) { + { 0x27, "hub01_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0x60, (const struct nouveau_specsig[]) { + { 0x47, "hub02_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0x60, (const struct nouveau_specsig[]) { + { 0x47, "hub03_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0x40, (const struct nouveau_specsig[]) { + { 0x03, "host_mmio_rd" }, + { 0x27, "hub04_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0x60, (const struct nouveau_specsig[]) { + { 0x47, "hub05_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0xc0, (const struct nouveau_specsig[]) { + { 0x74, "host_fb_rd3x" }, + { 0x75, "host_fb_rd3x_2" }, + { 0xa7, "hub06_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0x60, (const struct nouveau_specsig[]) { + { 0x47, "hub07_user_0" }, + {} + }, &nvc0_perfctr_func }, + {} +}; + +static const struct nouveau_specdom +nve0_perfmon_gpc[] = { + { 0xe0, (const struct nouveau_specsig[]) { + { 0xc7, "gpc00_user_0" }, + {} + }, &nvc0_perfctr_func }, + {} +}; + +static const struct nouveau_specdom +nve0_perfmon_part[] = { + { 0x60, (const struct nouveau_specsig[]) { + { 0x47, "part00_user_0" }, + {} + }, &nvc0_perfctr_func }, + { 0x60, (const struct nouveau_specsig[]) { + { 0x47, "part01_user_0" }, + {} + }, &nvc0_perfctr_func }, + {} +}; + +static int +nve0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_perfmon_priv *priv; + u32 mask; + int ret; + + ret = nouveau_perfmon_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + /* PDAEMON */ + ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, + nve0_perfmon_pwr); + if (ret) + return ret; + + /* HUB */ + ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, + nve0_perfmon_hub); + if (ret) + return ret; + + /* GPC */ + mask = (1 << nv_rd32(priv, 0x022430)) - 1; + mask &= ~nv_rd32(priv, 0x022504); + mask &= ~nv_rd32(priv, 0x022584); + + ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000, + 0x1000, 0x200, nve0_perfmon_gpc); + if (ret) + return ret; + + /* PART */ + mask = (1 << nv_rd32(priv, 0x022438)) - 1; + mask &= ~nv_rd32(priv, 0x022548); + mask &= ~nv_rd32(priv, 0x0225c8); + + ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000, + 0x1000, 0x200, nve0_perfmon_part); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nouveau_perfmon_cclass; + nv_engine(priv)->sclass = nouveau_perfmon_sclass; + priv->base.last = 7; + return 0; +} + +struct nouveau_oclass +nve0_perfmon_oclass = { + .handle = NV_ENGINE(PERFMON, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_perfmon_ctor, + .dtor = _nouveau_perfmon_dtor, + .init = _nouveau_perfmon_init, + .fini = nvc0_perfmon_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c new file mode 100644 index 00000000000..47256f78a89 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c @@ -0,0 +1,71 @@ +/* + * 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 "nvc0.h" + +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ + +/******************************************************************************* + * PPM context + ******************************************************************************/ + +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + +static int +nvf0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvc0_perfmon_priv *priv; + int ret; + + ret = nouveau_perfmon_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, + nve0_perfmon_pwr); + if (ret) + return ret; + + nv_engine(priv)->cclass = &nouveau_perfmon_cclass; + nv_engine(priv)->sclass = nouveau_perfmon_sclass; + return 0; +} + +struct nouveau_oclass +nvf0_perfmon_oclass = { + .handle = NV_ENGINE(PERFMON, 0xf0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvf0_perfmon_ctor, + .dtor = _nouveau_perfmon_dtor, + .init = _nouveau_perfmon_init, + .fini = nvc0_perfmon_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h new file mode 100644 index 00000000000..0ac8714fe0b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h @@ -0,0 +1,91 @@ +#ifndef __NVKM_PERFMON_PRIV_H__ +#define __NVKM_PERFMON_PRIV_H__ + +#include <engine/perfmon.h> + +struct nouveau_perfctr { + struct nouveau_object base; + struct list_head head; + struct nouveau_perfsig *signal[4]; + int slot; + u32 logic_op; + u32 clk; + u32 ctr; +}; + +extern struct nouveau_oclass nouveau_perfmon_sclass[]; + +struct nouveau_perfctx { + struct nouveau_engctx base; +}; + +extern struct nouveau_oclass nouveau_perfmon_cclass; + +struct nouveau_specsig { + u8 signal; + const char *name; +}; + +struct nouveau_perfsig { + const char *name; +}; + +struct nouveau_perfdom; +struct nouveau_perfctr * +nouveau_perfsig_wrap(struct nouveau_perfmon *, const char *, + struct nouveau_perfdom **); + +struct nouveau_specdom { + u16 signal_nr; + const struct nouveau_specsig *signal; + const struct nouveau_funcdom *func; +}; + +extern const struct nouveau_specdom nva3_perfmon_pwr[]; +extern const struct nouveau_specdom nvc0_perfmon_pwr[]; +extern const struct nouveau_specdom nve0_perfmon_pwr[]; + +struct nouveau_perfdom { + struct list_head head; + struct list_head list; + const struct nouveau_funcdom *func; + char name[32]; + u32 addr; + u8 quad; + u32 signal_nr; + struct nouveau_perfsig signal[]; +}; + +struct nouveau_funcdom { + void (*init)(struct nouveau_perfmon *, struct nouveau_perfdom *, + struct nouveau_perfctr *); + void (*read)(struct nouveau_perfmon *, struct nouveau_perfdom *, + struct nouveau_perfctr *); + void (*next)(struct nouveau_perfmon *, struct nouveau_perfdom *); +}; + +int nouveau_perfdom_new(struct nouveau_perfmon *, const char *, u32, + u32, u32, u32, const struct nouveau_specdom *); + +#define nouveau_perfmon_create(p,e,o,d) \ + nouveau_perfmon_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_perfmon_dtor(p) ({ \ + struct nouveau_perfmon *c = (p); \ + _nouveau_perfmon_dtor(nv_object(c)); \ +}) +#define nouveau_perfmon_init(p) ({ \ + struct nouveau_perfmon *c = (p); \ + _nouveau_perfmon_init(nv_object(c)); \ +}) +#define nouveau_perfmon_fini(p,s) ({ \ + struct nouveau_perfmon *c = (p); \ + _nouveau_perfmon_fini(nv_object(c), (s)); \ +}) + +int nouveau_perfmon_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void _nouveau_perfmon_dtor(struct nouveau_object *); +int _nouveau_perfmon_init(struct nouveau_object *); +int _nouveau_perfmon_fini(struct nouveau_object *, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c index 2a859a31c30..c571758e4a2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c @@ -135,8 +135,8 @@ nv04_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv04_software_oclass = { +struct nouveau_oclass * +nv04_software_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(SW, 0x04), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_software_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c index a019364b1e1..a62f11a7843 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c @@ -117,8 +117,8 @@ nv10_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv10_software_oclass = { +struct nouveau_oclass * +nv10_software_oclass = &(struct nouveau_oclass) { .handle = NV_ENGINE(SW, 0x10), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv10_software_ctor, diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c index c48e7495377..f3b4d9dbf23 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c @@ -32,16 +32,9 @@ #include <subdev/bar.h> -#include <engine/software.h> #include <engine/disp.h> -struct nv50_software_priv { - struct nouveau_software base; -}; - -struct nv50_software_chan { - struct nouveau_software_chan base; -}; +#include "nv50.h" /******************************************************************************* * software object classes @@ -62,7 +55,7 @@ nv50_software_mthd_dma_vblsem(struct nouveau_object *object, u32 mthd, if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { struct nouveau_gpuobj *gpuobj = nv_gpuobj(handle->object); - chan->base.vblank.ctxdma = gpuobj->node->offset >> 4; + chan->vblank.ctxdma = gpuobj->node->offset >> 4; ret = 0; } nouveau_namedb_put(handle); @@ -74,34 +67,33 @@ nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd, void *args, u32 size) { struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); - chan->base.vblank.offset = *(u32 *)args; + chan->vblank.offset = *(u32 *)args; return 0; } -static int +int nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd, void *args, u32 size) { struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); - chan->base.vblank.value = *(u32 *)args; + chan->vblank.value = *(u32 *)args; return 0; } -static int +int nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, void *args, u32 size) { struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); - struct nouveau_disp *disp = nouveau_disp(object); - u32 crtc = *(u32 *)args; - if (crtc > 1) + u32 head = *(u32 *)args; + if (head >= chan->vblank.nr_event) return -EINVAL; - nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event); + nouveau_event_get(chan->vblank.event[head]); return 0; } -static int +int nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd, void *args, u32 size) { @@ -132,10 +124,9 @@ nv50_software_sclass[] = { ******************************************************************************/ static int -nv50_software_vblsem_release(struct nouveau_eventh *event, int head) +nv50_software_vblsem_release(void *data, u32 type, int head) { - struct nouveau_software_chan *chan = - container_of(event, struct nouveau_software_chan, vblank.event); + struct nv50_software_chan *chan = data; struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nouveau_bar *bar = nouveau_bar(priv); @@ -154,45 +145,76 @@ nv50_software_vblsem_release(struct nouveau_eventh *event, int head) return NVKM_EVENT_DROP; } -static int +void +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); + } + + nouveau_software_context_destroy(&chan->base); +} + +int nv50_software_context_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + struct nouveau_disp *pdisp = nouveau_disp(parent); + struct nv50_software_cclass *pclass = (void *)oclass; struct nv50_software_chan *chan; - int ret; + int ret, i; ret = nouveau_software_context_create(parent, engine, oclass, &chan); *pobject = nv_object(chan); if (ret) return ret; - chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; - chan->base.vblank.event.func = nv50_software_vblsem_release; + 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]); + if (ret) + return ret; + } + + chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; return 0; } -static struct nouveau_oclass +static struct nv50_software_cclass nv50_software_cclass = { - .handle = NV_ENGCTX(SW, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { + .base.handle = NV_ENGCTX(SW, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_software_context_ctor, .dtor = _nouveau_software_context_dtor, .init = _nouveau_software_context_init, .fini = _nouveau_software_context_fini, }, + .vblank = nv50_software_vblsem_release, }; /******************************************************************************* * software engine/subdev functions ******************************************************************************/ -static int +int nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + struct nv50_software_oclass *pclass = (void *)oclass; struct nv50_software_priv *priv; int ret; @@ -201,19 +223,21 @@ nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - nv_engine(priv)->cclass = &nv50_software_cclass; - nv_engine(priv)->sclass = nv50_software_sclass; + nv_engine(priv)->cclass = pclass->cclass; + nv_engine(priv)->sclass = pclass->sclass; nv_subdev(priv)->intr = nv04_software_intr; return 0; } -struct nouveau_oclass -nv50_software_oclass = { - .handle = NV_ENGINE(SW, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv50_software_oclass = &(struct nv50_software_oclass) { + .base.handle = NV_ENGINE(SW, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_software_ctor, .dtor = _nouveau_software_dtor, .init = _nouveau_software_init, .fini = _nouveau_software_fini, }, -}; + .cclass = &nv50_software_cclass.base, + .sclass = nv50_software_sclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h new file mode 100644 index 00000000000..bb49a7a2085 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h @@ -0,0 +1,47 @@ +#ifndef __NVKM_SW_NV50_H__ +#define __NVKM_SW_NV50_H__ + +#include <engine/software.h> + +struct nv50_software_oclass { + struct nouveau_oclass base; + struct nouveau_oclass *cclass; + struct nouveau_oclass *sclass; +}; + +struct nv50_software_priv { + struct nouveau_software base; +}; + +int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); + +struct nv50_software_cclass { + struct nouveau_oclass base; + int (*vblank)(void *, u32, int); +}; + +struct nv50_software_chan { + struct nouveau_software_chan base; + struct { + struct nouveau_eventh **event; + int nr_event; + u32 channel; + u32 ctxdma; + u64 offset; + u32 value; + } vblank; +}; + +int nv50_software_context_ctor(struct nouveau_object *, + struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nv50_software_context_dtor(struct nouveau_object *); + +int nv50_software_mthd_vblsem_value(struct nouveau_object *, u32, void *, u32); +int nv50_software_mthd_vblsem_release(struct nouveau_object *, u32, void *, u32); +int nv50_software_mthd_flip(struct nouveau_object *, u32, void *, u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c index d698e710ddd..135c20f3835 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c @@ -32,13 +32,7 @@ #include <engine/software.h> #include <engine/disp.h> -struct nvc0_software_priv { - struct nouveau_software base; -}; - -struct nvc0_software_chan { - struct nouveau_software_chan base; -}; +#include "nv50.h" /******************************************************************************* * software object classes @@ -48,58 +42,24 @@ static int nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd, void *args, u32 size) { - struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); + struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); u64 data = *(u32 *)args; if (mthd == 0x0400) { - chan->base.vblank.offset &= 0x00ffffffffULL; - chan->base.vblank.offset |= data << 32; + chan->vblank.offset &= 0x00ffffffffULL; + chan->vblank.offset |= data << 32; } else { - chan->base.vblank.offset &= 0xff00000000ULL; - chan->base.vblank.offset |= data; + chan->vblank.offset &= 0xff00000000ULL; + chan->vblank.offset |= data; } return 0; } static int -nvc0_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd, - void *args, u32 size) -{ - struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); - chan->base.vblank.value = *(u32 *)args; - return 0; -} - -static int -nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, - void *args, u32 size) -{ - struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); - struct nouveau_disp *disp = nouveau_disp(object); - u32 crtc = *(u32 *)args; - - if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3) - return -EINVAL; - - nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event); - return 0; -} - -static int -nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd, - void *args, u32 size) -{ - struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); - if (chan->base.flip) - return chan->base.flip(chan->base.flip_data); - return -EINVAL; -} - -static int nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd, void *args, u32 size) { - struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); - struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine; + struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); + struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; u32 data = *(u32 *)args; switch (mthd) { @@ -124,9 +84,9 @@ static struct nouveau_omthds nvc0_software_omthds[] = { { 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset }, { 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset }, - { 0x0408, 0x0408, nvc0_software_mthd_vblsem_value }, - { 0x040c, 0x040c, nvc0_software_mthd_vblsem_release }, - { 0x0500, 0x0500, nvc0_software_mthd_flip }, + { 0x0408, 0x0408, nv50_software_mthd_vblsem_value }, + { 0x040c, 0x040c, nv50_software_mthd_vblsem_release }, + { 0x0500, 0x0500, nv50_software_mthd_flip }, { 0x0600, 0x0600, nvc0_software_mthd_mp_control }, { 0x0644, 0x0644, nvc0_software_mthd_mp_control }, { 0x06ac, 0x06ac, nvc0_software_mthd_mp_control }, @@ -144,11 +104,10 @@ nvc0_software_sclass[] = { ******************************************************************************/ static int -nvc0_software_vblsem_release(struct nouveau_eventh *event, int head) +nvc0_software_vblsem_release(void *data, u32 type, int head) { - struct nouveau_software_chan *chan = - container_of(event, struct nouveau_software_chan, vblank.event); - struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine; + struct nv50_software_chan *chan = data; + struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nouveau_bar *bar = nouveau_bar(priv); nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); @@ -160,66 +119,31 @@ nvc0_software_vblsem_release(struct nouveau_eventh *event, int head) return NVKM_EVENT_DROP; } -static int -nvc0_software_context_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvc0_software_chan *chan; - int ret; - - ret = nouveau_software_context_create(parent, engine, oclass, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; - chan->base.vblank.event.func = nvc0_software_vblsem_release; - return 0; -} - -static struct nouveau_oclass +static struct nv50_software_cclass nvc0_software_cclass = { - .handle = NV_ENGCTX(SW, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_software_context_ctor, + .base.handle = NV_ENGCTX(SW, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_software_context_ctor, .dtor = _nouveau_software_context_dtor, .init = _nouveau_software_context_init, .fini = _nouveau_software_context_fini, }, + .vblank = nvc0_software_vblsem_release, }; /******************************************************************************* * software engine/subdev functions ******************************************************************************/ -static int -nvc0_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvc0_software_priv *priv; - int ret; - - ret = nouveau_software_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_engine(priv)->cclass = &nvc0_software_cclass; - nv_engine(priv)->sclass = nvc0_software_sclass; - nv_subdev(priv)->intr = nv04_software_intr; - return 0; -} - -struct nouveau_oclass -nvc0_software_oclass = { - .handle = NV_ENGINE(SW, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_software_ctor, +struct nouveau_oclass * +nvc0_software_oclass = &(struct nv50_software_oclass) { + .base.handle = NV_ENGINE(SW, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_software_ctor, .dtor = _nouveau_software_dtor, .init = _nouveau_software_init, .fini = _nouveau_software_fini, }, -}; + .cclass = &nvc0_software_cclass.base, + .sclass = nvc0_software_sclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c index 5f6ede7c489..92384759d2f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/core/engine/xtensa.c @@ -112,7 +112,7 @@ _nouveau_xtensa_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x", xtensa->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nv_warn(xtensa, "unable to load firmware %s\n", name); return ret; diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 5a5961b6a6a..e0c812bc884 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -22,7 +22,7 @@ #define NV_DEVICE_DISABLE_PPP 0x0000004000000000ULL #define NV_DEVICE_DISABLE_COPY0 0x0000008000000000ULL #define NV_DEVICE_DISABLE_COPY1 0x0000010000000000ULL -#define NV_DEVICE_DISABLE_UNK1C1 0x0000020000000000ULL +#define NV_DEVICE_DISABLE_VIC 0x0000020000000000ULL #define NV_DEVICE_DISABLE_VENC 0x0000040000000000ULL struct nv_device_class { @@ -98,6 +98,77 @@ struct nv_dma_class { 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 @@ -159,9 +230,26 @@ struct nve0_channel_ind_class { #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 @@ -170,6 +258,7 @@ struct nv04_display_class { * 9070: NVD0_DISP * 9170: NVE0_DISP * 9270: NVF0_DISP + * 9470: GM107_DISP */ #define NV50_DISP_CLASS 0x00005070 @@ -180,6 +269,12 @@ struct nv04_display_class { #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 @@ -200,6 +295,10 @@ struct nv04_display_class { #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 @@ -249,6 +348,7 @@ struct nv50_display_class { * 907a: NVD0_DISP_CURS * 917a: NVE0_DISP_CURS * 927a: NVF0_DISP_CURS + * 947a: GM107_DISP_CURS */ #define NV50_DISP_CURS_CLASS 0x0000507a @@ -259,6 +359,7 @@ struct nv50_display_class { #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; @@ -272,6 +373,7 @@ struct nv50_display_curs_class { * 907b: NVD0_DISP_OIMM * 917b: NVE0_DISP_OIMM * 927b: NVE0_DISP_OIMM + * 947b: GM107_DISP_OIMM */ #define NV50_DISP_OIMM_CLASS 0x0000507b @@ -282,6 +384,7 @@ struct nv50_display_curs_class { #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; @@ -295,6 +398,7 @@ struct nv50_display_oimm_class { * 907c: NVD0_DISP_SYNC * 917c: NVE0_DISP_SYNC * 927c: NVF0_DISP_SYNC + * 947c: GM107_DISP_SYNC */ #define NV50_DISP_SYNC_CLASS 0x0000507c @@ -305,6 +409,7 @@ struct nv50_display_oimm_class { #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; @@ -319,6 +424,7 @@ struct nv50_display_sync_class { * 907d: NVD0_DISP_MAST * 917d: NVE0_DISP_MAST * 927d: NVF0_DISP_MAST + * 947d: GM107_DISP_MAST */ #define NV50_DISP_MAST_CLASS 0x0000507d @@ -329,6 +435,7 @@ struct nv50_display_sync_class { #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; @@ -342,6 +449,7 @@ struct nv50_display_mast_class { * 907e: NVD0_DISP_OVLY * 917e: NVE0_DISP_OVLY * 927e: NVF0_DISP_OVLY + * 947e: GM107_DISP_OVLY */ #define NV50_DISP_OVLY_CLASS 0x0000507e @@ -352,6 +460,7 @@ struct nv50_display_mast_class { #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; diff --git a/drivers/gpu/drm/nouveau/core/include/core/debug.h b/drivers/gpu/drm/nouveau/core/include/core/debug.h index 9ea18dfcb4d..8092e2e9032 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/debug.h +++ b/drivers/gpu/drm/nouveau/core/include/core/debug.h @@ -1,13 +1,20 @@ #ifndef __NOUVEAU_DEBUG_H__ #define __NOUVEAU_DEBUG_H__ +extern int nv_info_debug_level; + #define NV_DBG_FATAL 0 #define NV_DBG_ERROR 1 #define NV_DBG_WARN 2 -#define NV_DBG_INFO 3 +#define NV_DBG_INFO nv_info_debug_level #define NV_DBG_DEBUG 4 #define NV_DBG_TRACE 5 #define NV_DBG_PARANOIA 6 #define NV_DBG_SPAM 7 +#define NV_DBG_INFO_NORMAL 3 +#define NV_DBG_INFO_SILENT NV_DBG_DEBUG + +#define nv_debug_level(a) nv_info_debug_level = NV_DBG_INFO_##a + #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h index 99b6600fe80..a8a9a9cf16c 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/device.h +++ b/drivers/gpu/drm/nouveau/core/include/core/device.h @@ -33,11 +33,14 @@ enum nv_subdev_type { NVDEV_SUBDEV_INSTMEM, NVDEV_SUBDEV_VM, NVDEV_SUBDEV_BAR, + NVDEV_SUBDEV_PWR, NVDEV_SUBDEV_VOLT, - NVDEV_SUBDEV_CLOCK, NVDEV_SUBDEV_THERM, + NVDEV_SUBDEV_CLOCK, - NVDEV_ENGINE_DMAOBJ, + NVDEV_ENGINE_FIRST, + NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST, + NVDEV_ENGINE_IFB, NVDEV_ENGINE_FIFO, NVDEV_ENGINE_SW, NVDEV_ENGINE_GR, @@ -50,9 +53,10 @@ enum nv_subdev_type { NVDEV_ENGINE_COPY0, NVDEV_ENGINE_COPY1, NVDEV_ENGINE_COPY2, - NVDEV_ENGINE_UNK1C1, + NVDEV_ENGINE_VIC, NVDEV_ENGINE_VENC, NVDEV_ENGINE_DISP, + NVDEV_ENGINE_PERFMON, NVDEV_SUBDEV_NR, }; @@ -62,16 +66,19 @@ struct nouveau_device { struct list_head head; struct pci_dev *pdev; + struct platform_device *platformdev; u64 handle; const char *cfgopt; const char *dbgopt; const char *name; const char *cname; + u64 disable_mask; enum { NV_04 = 0x04, NV_10 = 0x10, + NV_11 = 0x11, NV_20 = 0x20, NV_30 = 0x30, NV_40 = 0x40, @@ -79,6 +86,7 @@ struct nouveau_device { NV_C0 = 0xc0, NV_D0 = 0xd0, NV_E0 = 0xe0, + GM100 = 0x110, } card_type; u32 chipset; u32 crystal; @@ -135,4 +143,32 @@ nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub) device->pdev->subsystem_device == sub; } +static inline bool +nv_device_is_pci(struct nouveau_device *device) +{ + return device->pdev != NULL; +} + +static inline struct device * +nv_device_base(struct nouveau_device *device) +{ + return nv_device_is_pci(device) ? &device->pdev->dev : + &device->platformdev->dev; +} + +resource_size_t +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); + #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/event.h b/drivers/gpu/drm/nouveau/core/include/core/event.h index 9e094408f14..ba3f1a76a81 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/event.h +++ b/drivers/gpu/drm/nouveau/core/include/core/event.h @@ -5,32 +5,43 @@ #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; - int (*func)(struct nouveau_eventh *, int index); + unsigned long flags; + u32 types; + int index; + int (*func)(void *, u32, int); + void *priv; }; struct nouveau_event { - spinlock_t lock; - void *priv; - void (*enable)(struct nouveau_event *, int index); - void (*disable)(struct nouveau_event *, int index); + 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); + int types_nr; int index_nr; - struct { - struct list_head list; - int refs; - } index[]; + + spinlock_t list_lock; + struct list_head *list; + spinlock_t refs_lock; + int refs[]; }; -int nouveau_event_create(int index_nr, struct nouveau_event **); +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 *, int index); - -void nouveau_event_get(struct nouveau_event *, int index, - struct nouveau_eventh *); -void nouveau_event_put(struct nouveau_event *, int index, - struct nouveau_eventh *); +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 *); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/namedb.h b/drivers/gpu/drm/nouveau/core/include/core/namedb.h index 8897e088608..f5b5fd8e1fc 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/namedb.h +++ b/drivers/gpu/drm/nouveau/core/include/core/namedb.h @@ -33,7 +33,7 @@ nv_namedb(void *obj) int nouveau_namedb_create_(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, u32 pclass, - struct nouveau_oclass *, u32 engcls, + struct nouveau_oclass *, u64 engcls, int size, void **); int _nouveau_namedb_ctor(struct nouveau_object *, struct nouveau_object *, diff --git a/drivers/gpu/drm/nouveau/core/include/core/option.h b/drivers/gpu/drm/nouveau/core/include/core/option.h index 27074957fd2..ed055847887 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/option.h +++ b/drivers/gpu/drm/nouveau/core/include/core/option.h @@ -8,4 +8,13 @@ bool nouveau_boolopt(const char *optstr, const char *opt, bool value); int nouveau_dbgopt(const char *optstr, const char *sub); +/* compares unterminated string 'str' with zero-terminated string 'cmp' */ +static inline int +strncasecmpz(const char *str, const char *cmp, size_t len) +{ + if (strlen(cmp) != len) + return len; + return strncasecmp(str, cmp, len); +} + #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/printk.h b/drivers/gpu/drm/nouveau/core/include/core/printk.h index d87836e3a70..0f9a37bd32b 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/printk.h +++ b/drivers/gpu/drm/nouveau/core/include/core/printk.h @@ -6,27 +6,12 @@ struct nouveau_object; -#define NV_PRINTK_FATAL KERN_CRIT -#define NV_PRINTK_ERROR KERN_ERR -#define NV_PRINTK_WARN KERN_WARNING -#define NV_PRINTK_INFO KERN_INFO -#define NV_PRINTK_DEBUG KERN_DEBUG -#define NV_PRINTK_PARANOIA KERN_DEBUG -#define NV_PRINTK_TRACE KERN_DEBUG -#define NV_PRINTK_SPAM KERN_DEBUG - -extern int nv_printk_suspend_level; - -#define NV_DBG_SUSPEND (nv_printk_suspend_level) -#define NV_PRINTK_SUSPEND (nv_printk_level_to_pfx(nv_printk_suspend_level)) - -const char *nv_printk_level_to_pfx(int level); -void __printf(4, 5) -nv_printk_(struct nouveau_object *, const char *, int, const char *, ...); +void __printf(3, 4) +nv_printk_(struct nouveau_object *, int, const char *, ...); #define nv_printk(o,l,f,a...) do { \ if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \ - nv_printk_(nv_object(o), NV_PRINTK_##l, NV_DBG_##l, f, ##a); \ + nv_printk_(nv_object(o), NV_DBG_##l, f, ##a); \ } while(0) #define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a) @@ -37,16 +22,9 @@ nv_printk_(struct nouveau_object *, const char *, int, const char *, ...); #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_suspend(o,f,a...) nv_printk((o), SUSPEND, f, ##a) - -static inline void nv_suspend_set_printk_level(int level) -{ - nv_printk_suspend_level = level; -} - #define nv_assert(f,a...) do { \ if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG) \ - nv_printk_(NULL, NV_PRINTK_FATAL, NV_DBG_FATAL, f "\n", ##a); \ + nv_printk_(NULL, NV_DBG_FATAL, f "\n", ##a); \ BUG_ON(1); \ } while(0) diff --git a/drivers/gpu/drm/nouveau/core/include/engine/device.h b/drivers/gpu/drm/nouveau/core/include/engine/device.h index b3dd2c4c2f1..672d3c8f414 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/device.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/device.h @@ -3,11 +3,20 @@ #include <core/device.h> -#define nouveau_device_create(p,n,s,c,d,u) \ - nouveau_device_create_((p), (n), (s), (c), (d), sizeof(**u), (void **)u) +struct platform_device; -int nouveau_device_create_(struct pci_dev *, u64 name, const char *sname, - const char *cfg, const char *dbg, int, void **); +enum nv_bus_type { + NOUVEAU_BUS_PCI, + NOUVEAU_BUS_PLATFORM, +}; + +#define nouveau_device_create(p,t,n,s,c,d,u) \ + nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d), \ + sizeof(**u), (void **)u) + +int nouveau_device_create_(void *, enum nv_bus_type type, u64 name, + const char *sname, const char *cfg, const char *dbg, + int, void **); int nv04_identify(struct nouveau_device *); int nv10_identify(struct nouveau_device *); @@ -17,6 +26,7 @@ int nv40_identify(struct nouveau_device *); int nv50_identify(struct nouveau_device *); int nvc0_identify(struct nouveau_device *); int nve0_identify(struct nouveau_device *); +int gm100_identify(struct nouveau_device *); struct nouveau_device *nouveau_device_find(u64 name); diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h index 4b21fabfbdd..fde84289680 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h @@ -6,8 +6,19 @@ #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; }; @@ -17,33 +28,15 @@ nouveau_disp(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP]; } -#define nouveau_disp_create(p,e,c,h,i,x,d) \ - nouveau_disp_create_((p), (e), (c), (h), (i), (x), \ - sizeof(**d), (void **)d) -#define nouveau_disp_destroy(d) ({ \ - struct nouveau_disp *disp = (d); \ - _nouveau_disp_dtor(nv_object(disp)); \ -}) -#define nouveau_disp_init(d) \ - nouveau_engine_init(&(d)->base) -#define nouveau_disp_fini(d,s) \ - nouveau_engine_fini(&(d)->base, (s)) - -int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int heads, - const char *, const char *, int, void **); -void _nouveau_disp_dtor(struct nouveau_object *); -#define _nouveau_disp_init _nouveau_engine_init -#define _nouveau_disp_fini _nouveau_engine_fini - -extern struct nouveau_oclass nv04_disp_oclass; -extern struct nouveau_oclass nv50_disp_oclass; -extern struct nouveau_oclass nv84_disp_oclass; -extern struct nouveau_oclass nva0_disp_oclass; -extern struct nouveau_oclass nv94_disp_oclass; -extern struct nouveau_oclass nva3_disp_oclass; -extern struct nouveau_oclass nvd0_disp_oclass; -extern struct nouveau_oclass nve0_disp_oclass; -extern struct nouveau_oclass nvf0_disp_oclass; +extern struct nouveau_oclass *nv04_disp_oclass; +extern struct nouveau_oclass *nv50_disp_oclass; +extern struct nouveau_oclass *nv84_disp_oclass; +extern struct nouveau_oclass *nva0_disp_oclass; +extern struct nouveau_oclass *nv94_disp_oclass; +extern struct nouveau_oclass *nva3_disp_oclass; +extern struct nouveau_oclass *nvd0_disp_oclass; +extern struct nouveau_oclass *nve0_disp_oclass; +extern struct nouveau_oclass *nvf0_disp_oclass; +extern struct nouveau_oclass *gm107_disp_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 633c2f80648..b639eb2c74f 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h @@ -101,14 +101,16 @@ nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid); #define _nouveau_fifo_init _nouveau_engine_init #define _nouveau_fifo_fini _nouveau_engine_fini -extern struct nouveau_oclass nv04_fifo_oclass; -extern struct nouveau_oclass nv10_fifo_oclass; -extern struct nouveau_oclass nv17_fifo_oclass; -extern struct nouveau_oclass nv40_fifo_oclass; -extern struct nouveau_oclass nv50_fifo_oclass; -extern struct nouveau_oclass nv84_fifo_oclass; -extern struct nouveau_oclass nvc0_fifo_oclass; -extern struct nouveau_oclass nve0_fifo_oclass; +extern struct nouveau_oclass *nv04_fifo_oclass; +extern struct nouveau_oclass *nv10_fifo_oclass; +extern struct nouveau_oclass *nv17_fifo_oclass; +extern struct nouveau_oclass *nv40_fifo_oclass; +extern struct nouveau_oclass *nv50_fifo_oclass; +extern struct nouveau_oclass *nv84_fifo_oclass; +extern struct nouveau_oclass *nvc0_fifo_oclass; +extern struct nouveau_oclass *nve0_fifo_oclass; +extern struct nouveau_oclass *gk20a_fifo_oclass; +extern struct nouveau_oclass *nv108_fifo_oclass; 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 8e1b52312dd..8c1d4772da0 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/graph.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/graph.h @@ -63,12 +63,15 @@ extern struct nouveau_oclass nv40_graph_oclass; extern struct nouveau_oclass nv50_graph_oclass; extern struct nouveau_oclass *nvc0_graph_oclass; extern struct nouveau_oclass *nvc1_graph_oclass; -extern struct nouveau_oclass *nvc3_graph_oclass; +extern struct nouveau_oclass *nvc4_graph_oclass; extern struct nouveau_oclass *nvc8_graph_oclass; extern struct nouveau_oclass *nvd7_graph_oclass; 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 *nv108_graph_oclass; +extern struct nouveau_oclass *gm107_graph_oclass; extern const struct nouveau_bitfield nv04_graph_nsource[]; extern struct nouveau_ofuncs nv04_graph_ofuncs; diff --git a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h index 1d1a89a06ee..9b0d938199f 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h @@ -42,10 +42,13 @@ struct nouveau_mpeg { extern struct nouveau_oclass nv31_mpeg_oclass; extern struct nouveau_oclass nv40_mpeg_oclass; +extern struct nouveau_oclass nv44_mpeg_oclass; extern struct nouveau_oclass nv50_mpeg_oclass; extern struct nouveau_oclass nv84_mpeg_oclass; - +extern struct nouveau_ofuncs nv31_mpeg_ofuncs; +extern struct nouveau_oclass nv31_mpeg_cclass; extern struct nouveau_oclass nv31_mpeg_sclass[]; +extern struct nouveau_oclass nv40_mpeg_sclass[]; void nv31_mpeg_intr(struct nouveau_subdev *); void nv31_mpeg_tile_prog(struct nouveau_engine *, int); int nv31_mpeg_init(struct nouveau_object *); diff --git a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h b/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h new file mode 100644 index 00000000000..49b0024910f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h @@ -0,0 +1,39 @@ +#ifndef __NVKM_PERFMON_H__ +#define __NVKM_PERFMON_H__ + +#include <core/device.h> +#include <core/engine.h> +#include <core/engctx.h> +#include <core/class.h> + +struct nouveau_perfdom; +struct nouveau_perfctr; +struct nouveau_perfmon { + struct nouveau_engine base; + + struct nouveau_perfctx *context; + void *profile_data; + + struct list_head domains; + u32 sequence; + + /*XXX: temp for daemon backend */ + u32 pwr[8]; + u32 last; +}; + +static inline struct nouveau_perfmon * +nouveau_perfmon(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_PERFMON]; +} + +extern struct nouveau_oclass *nv40_perfmon_oclass; +extern struct nouveau_oclass *nv50_perfmon_oclass; +extern struct nouveau_oclass *nv84_perfmon_oclass; +extern struct nouveau_oclass *nva3_perfmon_oclass; +extern struct nouveau_oclass nvc0_perfmon_oclass; +extern struct nouveau_oclass nve0_perfmon_oclass; +extern struct nouveau_oclass nvf0_perfmon_oclass; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h index 45799487e57..23a462b50d0 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/software.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/software.h @@ -3,19 +3,10 @@ #include <core/engine.h> #include <core/engctx.h> -#include <core/event.h> struct nouveau_software_chan { struct nouveau_engctx base; - struct { - struct nouveau_eventh event; - u32 channel; - u32 ctxdma; - u64 offset; - u32 value; - } vblank; - int (*flip)(void *); void *flip_data; }; @@ -50,10 +41,10 @@ struct nouveau_software { #define _nouveau_software_init _nouveau_engine_init #define _nouveau_software_fini _nouveau_engine_fini -extern struct nouveau_oclass nv04_software_oclass; -extern struct nouveau_oclass nv10_software_oclass; -extern struct nouveau_oclass nv50_software_oclass; -extern struct nouveau_oclass nvc0_software_oclass; +extern struct nouveau_oclass *nv04_software_oclass; +extern struct nouveau_oclass *nv10_software_oclass; +extern struct nouveau_oclass *nv50_software_oclass; +extern struct nouveau_oclass *nvc0_software_oclass; void nv04_software_intr(struct nouveau_subdev *); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h index 4f4ff4502c3..9faa98e67ad 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h @@ -4,8 +4,7 @@ #include <core/subdev.h> #include <core/device.h> -#include <subdev/fb.h> - +struct nouveau_mem; struct nouveau_vma; struct nouveau_bar { @@ -29,27 +28,7 @@ nouveau_bar(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BAR]; } -#define nouveau_bar_create(p,e,o,d) \ - nouveau_bar_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nouveau_bar_init(p) \ - nouveau_subdev_init(&(p)->base) -#define nouveau_bar_fini(p,s) \ - nouveau_subdev_fini(&(p)->base, (s)) - -int nouveau_bar_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); -void nouveau_bar_destroy(struct nouveau_bar *); - -void _nouveau_bar_dtor(struct nouveau_object *); -#define _nouveau_bar_init _nouveau_subdev_init -#define _nouveau_bar_fini _nouveau_subdev_fini - extern struct nouveau_oclass nv50_bar_oclass; extern struct nouveau_oclass nvc0_bar_oclass; -int nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *, - struct nouveau_mem *, struct nouveau_object **); - -void nv84_bar_flush(struct nouveau_bar *); - #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h new file mode 100644 index 00000000000..bba01ab1e04 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h @@ -0,0 +1,23 @@ +#ifndef __NVBIOS_P0260_H__ +#define __NVBIOS_P0260_H__ + +u32 nvbios_P0260Te(struct nouveau_bios *, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz); + +struct nvbios_P0260E { + u32 data; +}; + +u32 nvbios_P0260Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr); +u32 nvbios_P0260Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr, + struct nvbios_P0260E *); + +struct nvbios_P0260X { + u32 data; +}; + +u32 nvbios_P0260Xe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr); +u32 nvbios_P0260Xp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr, + struct nvbios_P0260X *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h new file mode 100644 index 00000000000..662b2072685 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h @@ -0,0 +1,29 @@ +#ifndef __NVBIOS_BOOST_H__ +#define __NVBIOS_BOOST_H__ + +u16 nvbios_boostTe(struct nouveau_bios *, u8 *, u8 *, u8 *, u8 *, u8 *, u8 *); + +struct nvbios_boostE { + u8 pstate; + u32 min; + u32 max; +}; + +u16 nvbios_boostEe(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *); +u16 nvbios_boostEp(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *, + struct nvbios_boostE *); +u16 nvbios_boostEm(struct nouveau_bios *, u8, u8 *, u8 *, u8 *, u8 *, + struct nvbios_boostE *); + +struct nvbios_boostS { + u8 domain; + u8 percent; + u32 min; + u32 max; +}; + +u16 nvbios_boostSe(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8); +u16 nvbios_boostSp(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8, + struct nvbios_boostS *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h index c1270548fd0..f3930c27cb7 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h @@ -16,12 +16,31 @@ enum dcb_connector_type { DCB_CONNECTOR_eDP = 0x47, DCB_CONNECTOR_HDMI_0 = 0x60, DCB_CONNECTOR_HDMI_1 = 0x61, + DCB_CONNECTOR_HDMI_C = 0x63, DCB_CONNECTOR_DMS59_DP0 = 0x64, DCB_CONNECTOR_DMS59_DP1 = 0x65, DCB_CONNECTOR_NONE = 0xff }; -u16 dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); -u16 dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len); +struct nvbios_connT { +}; + +u32 nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u32 nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_connT *info); + +struct nvbios_connE { + u8 type; + u8 location; + u8 hpd; + u8 dp; + u8 di; + u8 sr; + u8 lcdid; +}; + +u32 nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr); +u32 nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr, + struct nvbios_connE *info); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h new file mode 100644 index 00000000000..a80a4380988 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h @@ -0,0 +1,28 @@ +#ifndef __NVBIOS_CSTEP_H__ +#define __NVBIOS_CSTEP_H__ + +u16 nvbios_cstepTe(struct nouveau_bios *, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz); + +struct nvbios_cstepE { + u8 pstate; + u8 index; +}; + +u16 nvbios_cstepEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr); +u16 nvbios_cstepEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr, + struct nvbios_cstepE *); +u16 nvbios_cstepEm(struct nouveau_bios *, u8 pstate, u8 *ver, u8 *hdr, + struct nvbios_cstepE *); + +struct nvbios_cstepX { + u32 freq; + u8 unkn[2]; + u8 voltage; +}; + +u16 nvbios_cstepXe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr); +u16 nvbios_cstepXp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr, + struct nvbios_cstepX *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h index 6e54218b55f..728206e2177 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h @@ -17,9 +17,10 @@ u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask, struct nvbios_dpout *); struct nvbios_dpcfg { - u8 drv; - u8 pre; - u8 unk; + u8 pc; + u8 dc; + u8 pe; + u8 tx_pu; }; u16 @@ -27,7 +28,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *); u16 -nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 un, u8 vs, u8 pe, +nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 pc, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h index 96d3364f6db..c7b2e586be0 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h @@ -7,7 +7,15 @@ enum dcb_gpio_func_name { DCB_GPIO_TVDAC1 = 0x2d, DCB_GPIO_FAN = 0x09, DCB_GPIO_FAN_SENSE = 0x3d, - DCB_GPIO_UNUSED = 0xff + DCB_GPIO_UNUSED = 0xff, + DCB_GPIO_VID0 = 0x04, + DCB_GPIO_VID1 = 0x05, + DCB_GPIO_VID2 = 0x06, + DCB_GPIO_VID3 = 0x1a, + DCB_GPIO_VID4 = 0x73, + DCB_GPIO_VID5 = 0x74, + DCB_GPIO_VID6 = 0x75, + DCB_GPIO_VID7 = 0x76, }; #define DCB_GPIO_LOG_DIR 0x02 diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h index 0b285e99be5..16ff06ec2a8 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h @@ -3,6 +3,39 @@ struct nouveau_bios; +u16 nvbios_perf_table(struct nouveau_bios *, u8 *ver, u8 *hdr, + u8 *cnt, u8 *len, u8 *snr, u8 *ssz); + +struct nvbios_perfE { + u8 pstate; + u8 fanspeed; + u8 voltage; + u32 core; + u32 shader; + u32 memory; + u32 vdec; + u32 disp; + u32 script; +}; + +u16 nvbios_perf_entry(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 nvbios_perfEp(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *); + +struct nvbios_perfS { + union { + struct { + u32 freq; + } v40; + }; +}; + +u32 nvbios_perfSe(struct nouveau_bios *, u32 data, int idx, + u8 *ver, u8 *hdr, u8 cnt, u8 len); +u32 nvbios_perfSp(struct nouveau_bios *, u32 data, int idx, + u8 *ver, u8 *hdr, u8 cnt, u8 len, struct nvbios_perfS *); + struct nvbios_perf_fan { u32 pwm_divisor; }; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h new file mode 100644 index 00000000000..c086ac6d677 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h @@ -0,0 +1,66 @@ +#ifndef __NVBIOS_RAMCFG_H__ +#define __NVBIOS_RAMCFG_H__ + +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 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[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; +}; + +u8 nvbios_ramcfg_count(struct nouveau_bios *); +u8 nvbios_ramcfg_index(struct nouveau_subdev *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h new file mode 100644 index 00000000000..5bdf8e4db40 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h @@ -0,0 +1,25 @@ +#ifndef __NVBIOS_RAMMAP_H__ +#define __NVBIOS_RAMMAP_H__ + +struct nvbios_ramcfg; + +u32 nvbios_rammapTe(struct nouveau_bios *, u8 *ver, u8 *hdr, + u8 *cnt, u8 *len, u8 *snr, u8 *ssz); + +u32 nvbios_rammapEe(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +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 *); + +u32 nvbios_rammapSe(struct nouveau_bios *, u32 data, + u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, + u8 *ver, u8 *hdr); +u32 nvbios_rammapSp(struct nouveau_bios *, u32 data, + u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, + u8 *ver, u8 *hdr, + struct nvbios_ramcfg *); + +#endif 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 083541dbe9c..8dc5051df55 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h @@ -31,6 +31,12 @@ struct nouveau_therm_trip_point { int hysteresis; }; +enum nvbios_therm_fan_mode { + NVBIOS_THERM_FAN_TRIP = 0, + NVBIOS_THERM_FAN_LINEAR = 1, + NVBIOS_THERM_FAN_OTHER = 2, +}; + struct nvbios_therm_fan { u16 pwm_freq; @@ -40,6 +46,7 @@ struct nvbios_therm_fan { u16 bump_period; u16 slow_down_period; + enum nvbios_therm_fan_mode fan_mode; struct nouveau_therm_trip_point trip[NOUVEAU_TEMP_FAN_TRIP_MAX]; u8 nr_fan_trip; u8 linear_min_temp; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h new file mode 100644 index 00000000000..76d914b67ab --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h @@ -0,0 +1,14 @@ +#ifndef __NVBIOS_TIMING_H__ +#define __NVBIOS_TIMING_H__ + +struct nvbios_ramcfg; + +u16 nvbios_timingTe(struct nouveau_bios *, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz); +u16 nvbios_timingEe(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 nvbios_timingEp(struct nouveau_bios *, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_ramcfg *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h new file mode 100644 index 00000000000..ad5a8f20e11 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h @@ -0,0 +1,25 @@ +#ifndef __NVBIOS_VMAP_H__ +#define __NVBIOS_VMAP_H__ + +struct nouveau_bios; + +struct nvbios_vmap { +}; + +u16 nvbios_vmap_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 nvbios_vmap_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_vmap *); + +struct nvbios_vmap_entry { + u8 unk0; + u8 link; + u32 min; + u32 max; + s32 arg[6]; +}; + +u16 nvbios_vmap_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len); +u16 nvbios_vmap_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len, + struct nvbios_vmap_entry *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h new file mode 100644 index 00000000000..6a11dcd5977 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h @@ -0,0 +1,27 @@ +#ifndef __NVBIOS_VOLT_H__ +#define __NVBIOS_VOLT_H__ + +struct nouveau_bios; + +struct nvbios_volt { + u8 vidmask; + u32 min; + u32 max; + u32 base; + s16 step; +}; + +u16 nvbios_volt_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u16 nvbios_volt_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_volt *); + +struct nvbios_volt_entry { + u32 voltage; + u8 vid; +}; + +u16 nvbios_volt_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len); +u16 nvbios_volt_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len, + struct nvbios_volt_entry *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bus.h b/drivers/gpu/drm/nouveau/core/include/subdev/bus.h index 7d88ec4a6d0..697f7ce70aa 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bus.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bus.h @@ -11,6 +11,8 @@ struct nouveau_bus_intr { struct nouveau_bus { struct nouveau_subdev base; + int (*hwsq_exec)(struct nouveau_bus *, u32 *, u32); + u32 hwsq_size; }; static inline struct nouveau_bus * @@ -33,9 +35,19 @@ nouveau_bus(void *obj) #define _nouveau_bus_init _nouveau_subdev_init #define _nouveau_bus_fini _nouveau_subdev_fini -extern struct nouveau_oclass nv04_bus_oclass; -extern struct nouveau_oclass nv31_bus_oclass; -extern struct nouveau_oclass nv50_bus_oclass; -extern struct nouveau_oclass nvc0_bus_oclass; +extern struct nouveau_oclass *nv04_bus_oclass; +extern struct nouveau_oclass *nv31_bus_oclass; +extern struct nouveau_oclass *nv50_bus_oclass; +extern struct nouveau_oclass *nv94_bus_oclass; +extern struct nouveau_oclass *nvc0_bus_oclass; + +/* interface to sequencer */ +struct nouveau_hwsq; +int nouveau_hwsq_init(struct nouveau_bus *, struct nouveau_hwsq **); +int nouveau_hwsq_fini(struct nouveau_hwsq **, bool exec); +void nouveau_hwsq_wr32(struct nouveau_hwsq *, u32 addr, u32 data); +void nouveau_hwsq_setf(struct nouveau_hwsq *, u8 flag, int data); +void nouveau_hwsq_wait(struct nouveau_hwsq *, u8 flag, u8 data); +void nouveau_hwsq_nsec(struct nouveau_hwsq *, u32 nsec); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index 89ee289097a..c01e29c9f89 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -7,9 +7,83 @@ struct nouveau_pll_vals; struct nvbios_pll; +enum nv_clk_src { + nv_clk_src_crystal, + nv_clk_src_href, + + nv_clk_src_hclk, + nv_clk_src_hclkm3, + nv_clk_src_hclkm3d2, + nv_clk_src_hclkm2d3, /* NVAA */ + nv_clk_src_hclkm4, /* NVAA */ + nv_clk_src_cclk, /* NVAA */ + + nv_clk_src_host, + + nv_clk_src_sppll0, + nv_clk_src_sppll1, + + nv_clk_src_mpllsrcref, + nv_clk_src_mpllsrc, + nv_clk_src_mpll, + nv_clk_src_mdiv, + + nv_clk_src_core, + nv_clk_src_shader, + + nv_clk_src_mem, + + nv_clk_src_gpc, + nv_clk_src_rop, + nv_clk_src_hubk01, + nv_clk_src_hubk06, + nv_clk_src_hubk07, + nv_clk_src_copy, + nv_clk_src_daemon, + nv_clk_src_disp, + nv_clk_src_vdec, + + nv_clk_src_dom6, + + nv_clk_src_max, +}; + +struct nouveau_cstate { + struct list_head head; + u8 voltage; + u32 domain[nv_clk_src_max]; +}; + +struct nouveau_pstate { + struct list_head head; + struct list_head list; /* c-states */ + struct nouveau_cstate base; + u8 pstate; + u8 fanspeed; +}; + struct nouveau_clock { struct nouveau_subdev base; + struct nouveau_clocks *domains; + struct nouveau_pstate bstate; + + struct list_head states; + int state_nr; + + int pstate; /* current */ + int ustate; /* user-requested (-1 disabled, -2 perfmon) */ + int astate; /* perfmon adjustment (base) */ + int tstate; /* thermal adjustment (max-) */ + int dstate; /* display adjustment (min+) */ + + bool allow_reclock; + + int (*read)(struct nouveau_clock *, enum nv_clk_src); + int (*calc)(struct nouveau_clock *, struct nouveau_cstate *); + int (*prog)(struct nouveau_clock *); + void (*tidy)(struct nouveau_clock *); + /*XXX: die, these are here *only* to support the completely * bat-shit insane what-was-nouveau_hw.c code */ @@ -25,27 +99,43 @@ nouveau_clock(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_CLOCK]; } -#define nouveau_clock_create(p,e,o,d) \ - nouveau_subdev_create((p), (e), (o), 0, "CLOCK", "clock", d) -#define nouveau_clock_destroy(p) \ - nouveau_subdev_destroy(&(p)->base) -#define nouveau_clock_init(p) \ - nouveau_subdev_init(&(p)->base) +struct nouveau_clocks { + enum nv_clk_src name; + u8 bios; /* 0xff for none */ +#define NVKM_CLK_DOM_FLAG_CORE 0x01 + u8 flags; + const char *mname; + 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_destroy(p) ({ \ + struct nouveau_clock *clk = (p); \ + _nouveau_clock_dtor(nv_object(clk)); \ +}) +#define nouveau_clock_init(p) ({ \ + struct nouveau_clock *clk = (p); \ + _nouveau_clock_init(nv_object(clk)); \ +}) #define nouveau_clock_fini(p,s) \ nouveau_subdev_fini(&(p)->base, (s)) int nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, void *, u32, int, void **); - -#define _nouveau_clock_dtor _nouveau_subdev_dtor -#define _nouveau_clock_init _nouveau_subdev_init + struct nouveau_oclass *, + struct nouveau_clocks *, bool, int, void **); +void _nouveau_clock_dtor(struct nouveau_object *); +int _nouveau_clock_init(struct nouveau_object *); #define _nouveau_clock_fini _nouveau_subdev_fini extern struct nouveau_oclass nv04_clock_oclass; extern struct nouveau_oclass nv40_clock_oclass; -extern struct nouveau_oclass nv50_clock_oclass; +extern struct nouveau_oclass *nv50_clock_oclass; +extern struct nouveau_oclass *nv84_clock_oclass; +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; int nv04_clock_pll_set(struct nouveau_clock *, u32 type, u32 freq); int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, @@ -55,4 +145,9 @@ 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_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); + #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h index 685c9b12ee4..e292271a84e 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h @@ -9,7 +9,7 @@ struct nouveau_devinit { bool post; void (*meminit)(struct nouveau_devinit *); int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq); - + u32 (*mmio)(struct nouveau_devinit *, u32 addr); }; static inline struct nouveau_devinit * @@ -18,32 +18,17 @@ nouveau_devinit(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_DEVINIT]; } -#define nouveau_devinit_create(p,e,o,d) \ - nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nouveau_devinit_destroy(p) \ - nouveau_subdev_destroy(&(p)->base) -#define nouveau_devinit_init(p) ({ \ - struct nouveau_devinit *d = (p); \ - _nouveau_devinit_init(nv_object(d)); \ -}) -#define nouveau_devinit_fini(p,s) ({ \ - struct nouveau_devinit *d = (p); \ - _nouveau_devinit_fini(nv_object(d), (s)); \ -}) - -int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); -#define _nouveau_devinit_dtor _nouveau_subdev_dtor -int _nouveau_devinit_init(struct nouveau_object *); -int _nouveau_devinit_fini(struct nouveau_object *, bool suspend); - -extern struct nouveau_oclass nv04_devinit_oclass; -extern struct nouveau_oclass nv05_devinit_oclass; -extern struct nouveau_oclass nv10_devinit_oclass; -extern struct nouveau_oclass nv1a_devinit_oclass; -extern struct nouveau_oclass nv20_devinit_oclass; -extern struct nouveau_oclass nv50_devinit_oclass; -extern struct nouveau_oclass nva3_devinit_oclass; -extern struct nouveau_oclass nvc0_devinit_oclass; +extern struct nouveau_oclass *nv04_devinit_oclass; +extern struct nouveau_oclass *nv05_devinit_oclass; +extern struct nouveau_oclass *nv10_devinit_oclass; +extern struct nouveau_oclass *nv1a_devinit_oclass; +extern struct nouveau_oclass *nv20_devinit_oclass; +extern struct nouveau_oclass *nv50_devinit_oclass; +extern struct nouveau_oclass *nv84_devinit_oclass; +extern struct nouveau_oclass *nv98_devinit_oclass; +extern struct nouveau_oclass *nva3_devinit_oclass; +extern struct nouveau_oclass *nvaf_devinit_oclass; +extern struct nouveau_oclass *nvc0_devinit_oclass; +extern struct nouveau_oclass *gm107_devinit_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h index 2e740508426..871e73914b2 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h @@ -75,26 +75,45 @@ struct nouveau_fb { static inline struct nouveau_fb * nouveau_fb(void *obj) { + /* fbram uses this before device subdev pointer is valid */ + if (nv_iclass(obj, NV_SUBDEV_CLASS) && + nv_subidx(obj) == NVDEV_SUBDEV_FB) + return obj; + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB]; } -extern struct nouveau_oclass nv04_fb_oclass; -extern struct nouveau_oclass nv10_fb_oclass; -extern struct nouveau_oclass nv1a_fb_oclass; -extern struct nouveau_oclass nv20_fb_oclass; -extern struct nouveau_oclass nv25_fb_oclass; -extern struct nouveau_oclass nv30_fb_oclass; -extern struct nouveau_oclass nv35_fb_oclass; -extern struct nouveau_oclass nv36_fb_oclass; -extern struct nouveau_oclass nv40_fb_oclass; -extern struct nouveau_oclass nv41_fb_oclass; -extern struct nouveau_oclass nv44_fb_oclass; -extern struct nouveau_oclass nv46_fb_oclass; -extern struct nouveau_oclass nv47_fb_oclass; -extern struct nouveau_oclass nv49_fb_oclass; -extern struct nouveau_oclass nv4e_fb_oclass; -extern struct nouveau_oclass nv50_fb_oclass; -extern struct nouveau_oclass nvc0_fb_oclass; +extern struct nouveau_oclass *nv04_fb_oclass; +extern struct nouveau_oclass *nv10_fb_oclass; +extern struct nouveau_oclass *nv1a_fb_oclass; +extern struct nouveau_oclass *nv20_fb_oclass; +extern struct nouveau_oclass *nv25_fb_oclass; +extern struct nouveau_oclass *nv30_fb_oclass; +extern struct nouveau_oclass *nv35_fb_oclass; +extern struct nouveau_oclass *nv36_fb_oclass; +extern struct nouveau_oclass *nv40_fb_oclass; +extern struct nouveau_oclass *nv41_fb_oclass; +extern struct nouveau_oclass *nv44_fb_oclass; +extern struct nouveau_oclass *nv46_fb_oclass; +extern struct nouveau_oclass *nv47_fb_oclass; +extern struct nouveau_oclass *nv49_fb_oclass; +extern struct nouveau_oclass *nv4e_fb_oclass; +extern struct nouveau_oclass *nv50_fb_oclass; +extern struct nouveau_oclass *nv84_fb_oclass; +extern struct nouveau_oclass *nva3_fb_oclass; +extern struct nouveau_oclass *nvaa_fb_oclass; +extern struct nouveau_oclass *nvaf_fb_oclass; +extern struct nouveau_oclass *nvc0_fb_oclass; +extern struct nouveau_oclass *nve0_fb_oclass; +extern struct nouveau_oclass *gk20a_fb_oclass; +extern struct nouveau_oclass *gm107_fb_oclass; + +#include <subdev/bios/ramcfg.h> + +struct nouveau_ram_data { + struct nvbios_ramcfg bios; + u32 freq; +}; struct nouveau_ram { struct nouveau_object base; @@ -121,6 +140,23 @@ struct nouveau_ram { int (*get)(struct nouveau_fb *, u64 size, u32 align, u32 size_nc, u32 type, struct nouveau_mem **); void (*put)(struct nouveau_fb *, struct nouveau_mem **); + + 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; + + struct nouveau_ram_data *next; + struct nouveau_ram_data former; + struct nouveau_ram_data xition; + struct nouveau_ram_data target; }; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h index c85b9f1579a..612d82ab683 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h @@ -8,17 +8,18 @@ #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 nouveau_gpio { struct nouveau_subdev base; struct nouveau_event *events; - /* hardware interfaces */ void (*reset)(struct nouveau_gpio *, u8 func); - int (*drive)(struct nouveau_gpio *, int line, int dir, int out); - int (*sense)(struct nouveau_gpio *, int line); - - /* software interfaces */ int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, struct dcb_gpio_func *); int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); @@ -31,23 +32,10 @@ nouveau_gpio(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO]; } -#define nouveau_gpio_create(p,e,o,l,d) \ - nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d) -#define nouveau_gpio_destroy(p) ({ \ - struct nouveau_gpio *gpio = (p); \ - _nouveau_gpio_dtor(nv_object(gpio)); \ -}) -#define nouveau_gpio_fini(p,s) \ - nouveau_subdev_fini(&(p)->base, (s)) - -int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, int, void **); -void _nouveau_gpio_dtor(struct nouveau_object *); -int nouveau_gpio_init(struct nouveau_gpio *); - -extern struct nouveau_oclass nv10_gpio_oclass; -extern struct nouveau_oclass nv50_gpio_oclass; -extern struct nouveau_oclass nvd0_gpio_oclass; -extern struct nouveau_oclass nve0_gpio_oclass; +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 *nvd0_gpio_oclass; +extern struct nouveau_oclass *nve0_gpio_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h index 7e4e2775f24..825f7bb46b6 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h @@ -14,61 +14,62 @@ #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 nouveau_i2c_port { struct nouveau_object base; struct i2c_adapter adapter; + struct mutex mutex; struct list_head head; u8 index; + int aux; const struct nouveau_i2c_func *func; }; struct nouveau_i2c_func { - void (*acquire)(struct nouveau_i2c_port *); - void (*release)(struct nouveau_i2c_port *); - void (*drive_scl)(struct nouveau_i2c_port *, int); void (*drive_sda)(struct nouveau_i2c_port *, int); int (*sense_scl)(struct nouveau_i2c_port *); int (*sense_sda)(struct nouveau_i2c_port *); - int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8); + int (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8); int (*pattern)(struct nouveau_i2c_port *, int pattern); int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh); int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe); }; -#define nouveau_i2c_port_create(p,e,o,i,a,f,d) \ - nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \ - sizeof(**d), (void **)d) -#define nouveau_i2c_port_destroy(p) ({ \ - struct nouveau_i2c_port *port = (p); \ - _nouveau_i2c_port_dtor(nv_object(i2c)); \ -}) -#define nouveau_i2c_port_init(p) \ - nouveau_object_init(&(p)->base) -#define nouveau_i2c_port_fini(p,s) \ - nouveau_object_fini(&(p)->base, (s)) - -int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, u8, - const struct i2c_algorithm *, - const struct nouveau_i2c_func *, - int, void **); -void _nouveau_i2c_port_dtor(struct nouveau_object *); -#define _nouveau_i2c_port_init nouveau_object_init -#define _nouveau_i2c_port_fini nouveau_object_fini +struct nouveau_i2c_board_info { + struct i2c_board_info dev; + u8 udelay; /* set to 0 to use the standard delay */ +}; struct nouveau_i2c { struct nouveau_subdev base; + struct nouveau_event *ntfy; struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); + int (*acquire_pad)(struct nouveau_i2c_port *, unsigned long timeout); + void (*release_pad)(struct nouveau_i2c_port *); + int (*acquire)(struct nouveau_i2c_port *, unsigned long timeout); + void (*release)(struct nouveau_i2c_port *); int (*identify)(struct nouveau_i2c *, int index, - const char *what, struct i2c_board_info *, + const char *what, struct nouveau_i2c_board_info *, bool (*match)(struct nouveau_i2c_port *, - struct i2c_board_info *)); + struct i2c_board_info *, void *), void *); + + wait_queue_head_t wait; struct list_head ports; }; @@ -78,37 +79,13 @@ nouveau_i2c(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C]; } -#define nouveau_i2c_create(p,e,o,s,d) \ - nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d) -#define nouveau_i2c_destroy(p) ({ \ - struct nouveau_i2c *i2c = (p); \ - _nouveau_i2c_dtor(nv_object(i2c)); \ -}) -#define nouveau_i2c_init(p) ({ \ - struct nouveau_i2c *i2c = (p); \ - _nouveau_i2c_init(nv_object(i2c)); \ -}) -#define nouveau_i2c_fini(p,s) ({ \ - struct nouveau_i2c *i2c = (p); \ - _nouveau_i2c_fini(nv_object(i2c), (s)); \ -}) - -int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, struct nouveau_oclass *, - int, void **); -void _nouveau_i2c_dtor(struct nouveau_object *); -int _nouveau_i2c_init(struct nouveau_object *); -int _nouveau_i2c_fini(struct nouveau_object *, bool); - -extern struct nouveau_oclass nv04_i2c_oclass; -extern struct nouveau_oclass nv4e_i2c_oclass; -extern struct nouveau_oclass nv50_i2c_oclass; -extern struct nouveau_oclass nv94_i2c_oclass; -extern struct nouveau_oclass nvd0_i2c_oclass; -extern struct nouveau_oclass nouveau_anx9805_sclass[]; - -extern const struct i2c_algorithm nouveau_i2c_bit_algo; -extern const struct i2c_algorithm nouveau_i2c_aux_algo; +extern struct nouveau_oclass *nv04_i2c_oclass; +extern struct nouveau_oclass *nv4e_i2c_oclass; +extern struct nouveau_oclass *nv50_i2c_oclass; +extern struct nouveau_oclass *nv94_i2c_oclass; +extern struct nouveau_oclass *nvd0_i2c_oclass; +extern struct nouveau_oclass *gf117_i2c_oclass; +extern struct nouveau_oclass *nve0_i2c_oclass; static inline int nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h b/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h index 88814f159d8..31df634c0fd 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h @@ -30,5 +30,6 @@ nouveau_ibus(void *obj) extern struct nouveau_oclass nvc0_ibus_oclass; extern struct nouveau_oclass nve0_ibus_oclass; +extern struct nouveau_oclass gk20a_ibus_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h index ec7a54e91a0..c1df26f3230 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h @@ -23,21 +23,6 @@ nv_memobj(void *obj) return obj; } -#define nouveau_instobj_create(p,e,o,d) \ - nouveau_instobj_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nouveau_instobj_init(p) \ - nouveau_object_init(&(p)->base) -#define nouveau_instobj_fini(p,s) \ - nouveau_object_fini(&(p)->base, (s)) - -int nouveau_instobj_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); -void nouveau_instobj_destroy(struct nouveau_instobj *); - -void _nouveau_instobj_dtor(struct nouveau_object *); -#define _nouveau_instobj_init nouveau_object_init -#define _nouveau_instobj_fini nouveau_object_fini - struct nouveau_instmem { struct nouveau_subdev base; struct list_head list; @@ -50,24 +35,18 @@ struct nouveau_instmem { static inline struct nouveau_instmem * nouveau_instmem(void *obj) { + /* nv04/nv40 impls need to create objects in their constructor, + * which is before the subdev pointer is valid + */ + if (nv_iclass(obj, NV_SUBDEV_CLASS) && + nv_subidx(obj) == NVDEV_SUBDEV_INSTMEM) + return obj; + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_INSTMEM]; } -#define nouveau_instmem_create(p,e,o,d) \ - nouveau_instmem_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nouveau_instmem_destroy(p) \ - nouveau_subdev_destroy(&(p)->base) -int nouveau_instmem_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); -int nouveau_instmem_init(struct nouveau_instmem *); -int nouveau_instmem_fini(struct nouveau_instmem *, bool); - -#define _nouveau_instmem_dtor _nouveau_subdev_dtor -int _nouveau_instmem_init(struct nouveau_object *); -int _nouveau_instmem_fini(struct nouveau_object *, bool); - -extern struct nouveau_oclass nv04_instmem_oclass; -extern struct nouveau_oclass nv40_instmem_oclass; -extern struct nouveau_oclass nv50_instmem_oclass; +extern struct nouveau_oclass *nv04_instmem_oclass; +extern struct nouveau_oclass *nv40_instmem_oclass; +extern struct nouveau_oclass *nv50_instmem_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h index a1985ed3d58..c9c1950b774 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h @@ -35,6 +35,7 @@ nouveau_ltcg(void *obj) #define _nouveau_ltcg_init _nouveau_subdev_init #define _nouveau_ltcg_fini _nouveau_subdev_fini -extern struct nouveau_oclass nvc0_ltcg_oclass; +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 ce6569f365a..72b176831be 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h @@ -11,8 +11,8 @@ struct nouveau_mc_intr { struct nouveau_mc { struct nouveau_subdev base; - const struct nouveau_mc_intr *intr_map; bool use_msi; + unsigned int irq; }; static inline struct nouveau_mc * @@ -21,8 +21,8 @@ nouveau_mc(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC]; } -#define nouveau_mc_create(p,e,o,m,d) \ - nouveau_mc_create_((p), (e), (o), (m), sizeof(**d), (void **)d) +#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)); \ }) @@ -34,20 +34,25 @@ nouveau_mc(void *obj) }) int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, const struct nouveau_mc_intr *, - int, void **); + 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); -extern struct nouveau_oclass nv04_mc_oclass; -extern struct nouveau_oclass nv44_mc_oclass; -extern struct nouveau_oclass nv50_mc_oclass; -extern struct nouveau_oclass nv98_mc_oclass; -extern struct nouveau_oclass nvc0_mc_oclass; +struct nouveau_mc_oclass { + struct nouveau_oclass base; + const struct nouveau_mc_intr *intr; + void (*msi_rearm)(struct nouveau_mc *); +}; -extern const struct nouveau_mc_intr nv04_mc_intr[]; -int nv04_mc_init(struct nouveau_object *); -int nv50_mc_init(struct nouveau_object *); +extern struct nouveau_oclass *nv04_mc_oclass; +extern struct nouveau_oclass *nv40_mc_oclass; +extern struct nouveau_oclass *nv44_mc_oclass; +extern struct nouveau_oclass *nv4c_mc_oclass; +extern struct nouveau_oclass *nv50_mc_oclass; +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; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h b/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h new file mode 100644 index 00000000000..c5c92cbed33 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h @@ -0,0 +1,80 @@ +#ifndef __NOUVEAU_PWR_H__ +#define __NOUVEAU_PWR_H__ + +#include <core/subdev.h> +#include <core/device.h> + +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; + + struct { + u32 base; + u32 size; + + struct work_struct work; + wait_queue_head_t wait; + u32 process; + u32 message; + u32 data[2]; + } recv; + + int (*message)(struct nouveau_pwr *, u32[2], u32, u32, u32, u32); +}; + +static inline struct nouveau_pwr * +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; + +/* interface to MEMX process running on PPWR */ +struct nouveau_memx; +int nouveau_memx_init(struct nouveau_pwr *, struct nouveau_memx **); +int nouveau_memx_fini(struct nouveau_memx **, bool exec); +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); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h index c075998d82e..d4a68179e58 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h @@ -31,7 +31,7 @@ struct nouveau_therm { int (*pwm_ctrl)(struct nouveau_therm *, int line, bool); int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *); int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); - int (*pwm_clock)(struct nouveau_therm *); + int (*pwm_clock)(struct nouveau_therm *, int line); int (*fan_get)(struct nouveau_therm *); int (*fan_set)(struct nouveau_therm *, int); @@ -71,6 +71,8 @@ void _nouveau_therm_dtor(struct nouveau_object *); int _nouveau_therm_init(struct nouveau_object *); int _nouveau_therm_fini(struct nouveau_object *, bool); +int nouveau_therm_cstate(struct nouveau_therm *, int, int); + extern struct nouveau_oclass nv40_therm_oclass; extern struct nouveau_oclass nv50_therm_oclass; extern struct nouveau_oclass nv84_therm_oclass; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h index 9ab70dfe5b0..db9be803a87 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h @@ -59,5 +59,6 @@ int nouveau_timer_create_(struct nouveau_object *, struct nouveau_engine *, struct nouveau_oclass *, int size, void **); extern struct nouveau_oclass nv04_timer_oclass; +extern struct nouveau_oclass gk20a_timer_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h index fcf57fa309b..c9509039f94 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h @@ -131,9 +131,5 @@ void nouveau_vm_map(struct nouveau_vma *, struct nouveau_mem *); void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_mem *); void nouveau_vm_unmap(struct nouveau_vma *); void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length); -void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length, - struct nouveau_mem *); -void nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length, - struct nouveau_mem *mem); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h new file mode 100644 index 00000000000..820b62ffd75 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h @@ -0,0 +1,60 @@ +#ifndef __NOUVEAU_VOLT_H__ +#define __NOUVEAU_VOLT_H__ + +#include <core/subdev.h> +#include <core/device.h> + +struct nouveau_voltage { + u32 uv; + u8 id; +}; + +struct nouveau_volt { + struct nouveau_subdev base; + + int (*vid_get)(struct nouveau_volt *); + int (*get)(struct nouveau_volt *); + int (*vid_set)(struct nouveau_volt *, u8 vid); + int (*set)(struct nouveau_volt *, u32 uv); + int (*set_id)(struct nouveau_volt *, u8 id, int condition); + + u8 vid_mask; + u8 vid_nr; + struct { + u32 uv; + u8 vid; + } vid[256]; +}; + +static inline struct nouveau_volt * +nouveau_volt(void *obj) +{ + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VOLT]; +} + +#define nouveau_volt_create(p, e, o, d) \ + nouveau_volt_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_volt_destroy(p) ({ \ + struct nouveau_volt *v = (p); \ + _nouveau_volt_dtor(nv_object(v)); \ +}) +#define nouveau_volt_init(p) ({ \ + struct nouveau_volt *v = (p); \ + _nouveau_volt_init(nv_object(v)); \ +}) +#define nouveau_volt_fini(p,s) \ + nouveau_subdev_fini((p), (s)) + +int nouveau_volt_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void _nouveau_volt_dtor(struct nouveau_object *); +int _nouveau_volt_init(struct nouveau_object *); +#define _nouveau_volt_fini _nouveau_subdev_fini + +extern struct nouveau_oclass nv40_volt_oclass; + +int nouveau_voltgpio_init(struct nouveau_volt *); +int nouveau_voltgpio_get(struct nouveau_volt *); +int nouveau_voltgpio_set(struct nouveau_volt *, u8); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h index 191e739f30d..d0ced94ca54 100644 --- a/drivers/gpu/drm/nouveau/core/os.h +++ b/drivers/gpu/drm/nouveau/core/os.h @@ -5,6 +5,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/pci.h> +#include <linux/platform_device.h> #include <linux/printk.h> #include <linux/bitops.h> #include <linux/firmware.h> @@ -23,17 +24,6 @@ #include <asm/unaligned.h> -static inline int -ffsll(u64 mask) -{ - int i; - for (i = 0; i < 64; i++) { - if (mask & (1ULL << i)) - return i + 1; - } - return 0; -} - #ifndef ioread32_native #ifdef __BIG_ENDIAN #define ioread16_native ioread16be diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c index d70ba342aa2..73b1ed20c8d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c @@ -23,7 +23,11 @@ */ #include <core/object.h> -#include <subdev/bar.h> + +#include <subdev/fb.h> +#include <subdev/vm.h> + +#include "priv.h" struct nouveau_barobj { struct nouveau_object base; @@ -114,8 +118,10 @@ nouveau_bar_create_(struct nouveau_object *parent, if (ret) return ret; - bar->iomem = ioremap(pci_resource_start(device->pdev, 3), - pci_resource_len(device->pdev, 3)); + 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; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c index 160d27f3c7b..f748ba49dfc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c @@ -25,10 +25,11 @@ #include <core/gpuobj.h> #include <subdev/timer.h> -#include <subdev/bar.h> #include <subdev/fb.h> #include <subdev/vm.h> +#include "priv.h" + struct nv50_bar_priv { struct nouveau_bar base; spinlock_t lock; @@ -138,7 +139,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, /* BAR3 */ start = 0x0100000000ULL; - limit = start + pci_resource_len(device->pdev, 3); + limit = start + nv_device_resource_len(device, 3); ret = nouveau_vm_new(device, start, limit, start, &vm); if (ret) @@ -172,7 +173,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, /* BAR1 */ start = 0x0000000000ULL; - limit = start + pci_resource_len(device->pdev, 1); + limit = start + nv_device_resource_len(device, 1); ret = nouveau_vm_new(device, start, limit--, start, &vm); if (ret) @@ -230,7 +231,7 @@ static int nv50_bar_init(struct nouveau_object *object) { struct nv50_bar_priv *priv = (void *)object; - int ret; + int ret, i; ret = nouveau_bar_init(&priv->base); if (ret) @@ -248,6 +249,8 @@ nv50_bar_init(struct nouveau_object *object) nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12); nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4); nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4); + for (i = 0; i < 8; i++) + nv_wr32(priv, 0x001900 + (i * 4), 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c index b2ec7411eb2..ca8139b9ab2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c @@ -25,18 +25,21 @@ #include <core/gpuobj.h> #include <subdev/timer.h> -#include <subdev/bar.h> #include <subdev/fb.h> #include <subdev/vm.h> +#include "priv.h" + +struct nvc0_bar_priv_vm { + struct nouveau_gpuobj *mem; + struct nouveau_gpuobj *pgd; + struct nouveau_vm *vm; +}; + struct nvc0_bar_priv { struct nouveau_bar base; spinlock_t lock; - struct { - struct nouveau_gpuobj *mem; - struct nouveau_gpuobj *pgd; - struct nouveau_vm *vm; - } bar[2]; + struct nvc0_bar_priv_vm bar[2]; }; static int @@ -78,88 +81,87 @@ nvc0_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma) } static int -nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +nvc0_bar_init_vm(struct nvc0_bar_priv *priv, struct nvc0_bar_priv_vm *bar_vm, + int bar_nr) { - struct nouveau_device *device = nv_device(parent); - struct pci_dev *pdev = device->pdev; - struct nvc0_bar_priv *priv; - struct nouveau_gpuobj *mem; + struct nouveau_device *device = nv_device(&priv->base); struct nouveau_vm *vm; + resource_size_t bar_len; int ret; - ret = nouveau_bar_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - /* BAR3 */ ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0, - &priv->bar[0].mem); - mem = priv->bar[0].mem; + &bar_vm->mem); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0, - &priv->bar[0].pgd); + &bar_vm->pgd); if (ret) return ret; - ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 3), 0, &vm); + bar_len = nv_device_resource_len(device, bar_nr); + + ret = nouveau_vm_new(device, 0, bar_len, 0, &vm); if (ret) return ret; atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); - ret = nouveau_gpuobj_new(nv_object(priv), NULL, - (pci_resource_len(pdev, 3) >> 12) * 8, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, - &vm->pgt[0].obj[0]); - vm->pgt[0].refcount[0] = 1; - if (ret) - return ret; + /* + * Bootstrap page table lookup. + */ + if (bar_nr == 3) { + ret = nouveau_gpuobj_new(nv_object(priv), NULL, + (bar_len >> 12) * 8, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, + &vm->pgt[0].obj[0]); + vm->pgt[0].refcount[0] = 1; + if (ret) + return ret; + } - ret = nouveau_vm_ref(vm, &priv->bar[0].vm, priv->bar[0].pgd); + ret = nouveau_vm_ref(vm, &bar_vm->vm, bar_vm->pgd); nouveau_vm_ref(NULL, &vm, NULL); if (ret) return ret; - nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[0].pgd->addr)); - nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[0].pgd->addr)); - nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 3) - 1)); - nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 3) - 1)); + nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr)); + nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr)); + nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1)); + nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1)); - /* BAR1 */ - ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0, - &priv->bar[1].mem); - mem = priv->bar[1].mem; - if (ret) - return ret; + return 0; +} - ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0, - &priv->bar[1].pgd); - if (ret) - return ret; +static int +nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_device *device = nv_device(parent); + struct nvc0_bar_priv *priv; + bool has_bar3 = nv_device_resource_len(device, 3) != 0; + int ret; - ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 1), 0, &vm); + ret = nouveau_bar_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); if (ret) return ret; - atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + /* BAR3 */ + if (has_bar3) { + ret = nvc0_bar_init_vm(priv, &priv->bar[0], 3); + if (ret) + return ret; + priv->base.alloc = nouveau_bar_alloc; + priv->base.kmap = nvc0_bar_kmap; + } - ret = nouveau_vm_ref(vm, &priv->bar[1].vm, priv->bar[1].pgd); - nouveau_vm_ref(NULL, &vm, NULL); + /* BAR1 */ + ret = nvc0_bar_init_vm(priv, &priv->bar[1], 1); if (ret) return ret; - nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[1].pgd->addr)); - nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[1].pgd->addr)); - nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 1) - 1)); - nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 1) - 1)); - - priv->base.alloc = nouveau_bar_alloc; - priv->base.kmap = nvc0_bar_kmap; priv->base.umap = nvc0_bar_umap; priv->base.unmap = nvc0_bar_unmap; priv->base.flush = nv84_bar_flush; @@ -201,7 +203,9 @@ nvc0_bar_init(struct nouveau_object *object) nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12); - nv_wr32(priv, 0x001714, 0xc0000000 | priv->bar[0].mem->addr >> 12); + if (priv->bar[0].mem) + nv_wr32(priv, 0x001714, + 0xc0000000 | priv->bar[0].mem->addr >> 12); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h new file mode 100644 index 00000000000..ffad8f337ea --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h @@ -0,0 +1,26 @@ +#ifndef __NVKM_BAR_PRIV_H__ +#define __NVKM_BAR_PRIV_H__ + +#include <subdev/bar.h> + +#define nouveau_bar_create(p,e,o,d) \ + nouveau_bar_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_bar_init(p) \ + nouveau_subdev_init(&(p)->base) +#define nouveau_bar_fini(p,s) \ + nouveau_subdev_fini(&(p)->base, (s)) + +int nouveau_bar_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void nouveau_bar_destroy(struct nouveau_bar *); + +void _nouveau_bar_dtor(struct nouveau_object *); +#define _nouveau_bar_init _nouveau_subdev_init +#define _nouveau_bar_fini _nouveau_subdev_fini + +int nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *, + struct nouveau_mem *, struct nouveau_object **); + +void nv84_bar_flush(struct nouveau_bar *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c new file mode 100644 index 00000000000..199f4e5f748 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c @@ -0,0 +1,109 @@ +/* + * 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/ramcfg.h> +#include <subdev/bios/P0260.h> + +u32 +nvbios_P0260Te(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz) +{ + struct bit_entry bit_P; + u32 data = 0x00000000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2 && bit_P.length > 0x63) + data = nv_ro32(bios, bit_P.offset + 0x60); + if (data) { + *ver = nv_ro08(bios, data + 0); + switch (*ver) { + case 0x10: + *hdr = nv_ro08(bios, data + 1); + *cnt = nv_ro08(bios, data + 2); + *len = 4; + *xnr = nv_ro08(bios, data + 3); + *xsz = 4; + return data; + default: + break; + } + } + } + + return 0x00000000; +} + +u32 +nvbios_P0260Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt, xnr, xsz; + u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, len, &xnr, &xsz); + if (data && idx < cnt) + return data + hdr + (idx * *len); + return 0x00000000; +} + +u32 +nvbios_P0260Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len, + struct nvbios_P0260E *info) +{ + u32 data = nvbios_P0260Ee(bios, idx, ver, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->data = nv_ro32(bios, data); + return data; + default: + break; + } + return 0x00000000; +} + +u32 +nvbios_P0260Xe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *xsz) +{ + u8 hdr, cnt, len, xnr; + u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, &len, &xnr, xsz); + if (data && idx < xnr) + return data + hdr + (cnt * len) + (idx * *xsz); + return 0x00000000; +} + +u32 +nvbios_P0260Xp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr, + struct nvbios_P0260X *info) +{ + u32 data = nvbios_P0260Xe(bios, idx, ver, hdr); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->data = nv_ro32(bios, data); + return data; + default: + break; + } + return 0x00000000; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index aa0fbbec7f0..d45704a2c2d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -90,10 +90,26 @@ nouveau_bios_shadow_pramin(struct nouveau_bios *bios) int i; if (device->card_type >= NV_50) { - if ( device->card_type < NV_C0 || - !(nv_rd32(bios, 0x022500) & 0x00000001)) - addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8; + if (device->card_type >= NV_C0 && device->card_type < GM100) { + if (nv_rd32(bios, 0x022500) & 0x00000001) + return; + } else + if (device->card_type >= GM100) { + if (nv_rd32(bios, 0x021c04) & 0x00000001) + return; + } + + addr = nv_rd32(bios, 0x619f04); + if (!(addr & 0x00000008)) { + nv_debug(bios, "... not enabled\n"); + return; + } + if ( (addr & 0x00000003) != 1) { + nv_debug(bios, "... not in vram\n"); + return; + } + addr = (addr & 0xffffff00) << 8; if (!addr) { addr = (u64)nv_rd32(bios, 0x001700) << 16; addr += 0xf0000; @@ -130,6 +146,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) u16 pcir; int i; + /* there is no prom on nv4x IGP's */ + if (device->card_type == NV_40 && device->chipset >= 0x4c) + return; + /* enable access to rom */ if (device->card_type >= NV_50) pcireg = 0x088050; @@ -137,6 +157,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) pcireg = 0x001850; access = nv_mask(bios, pcireg, 0x00000001, 0x00000000); + /* WARNING: PROM accesses should always be 32-bits aligned. Other + * accesses work on most chipset but do not on Kepler chipsets + */ + /* bail if no rom signature, with a workaround for a PROM reading * issue on some chipsets. the first read after a period of * inactivity returns the wrong result, so retry the first header @@ -144,31 +168,35 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) */ i = 16; do { - if (nv_rd08(bios, 0x300000) == 0x55) + u32 data = le32_to_cpu(nv_rd32(bios, 0x300000)) & 0xffff; + if (data == 0xaa55) break; } while (i--); - if (!i || nv_rd08(bios, 0x300001) != 0xaa) - goto out; - - /* additional check (see note below) - read PCI record header */ - pcir = nv_rd08(bios, 0x300018) | - nv_rd08(bios, 0x300019) << 8; - if (nv_rd08(bios, 0x300000 + pcir) != 'P' || - nv_rd08(bios, 0x300001 + pcir) != 'C' || - nv_rd08(bios, 0x300002 + pcir) != 'I' || - nv_rd08(bios, 0x300003 + pcir) != 'R') + if (!i) goto out; /* read entire bios image to system memory */ - bios->size = nv_rd08(bios, 0x300002) * 512; + bios->size = (le32_to_cpu(nv_rd32(bios, 0x300000)) >> 16) & 0xff; + bios->size = bios->size * 512; if (!bios->size) goto out; bios->data = kmalloc(bios->size, GFP_KERNEL); - if (bios->data) { - for (i = 0; i < bios->size; i++) - nv_wo08(bios, i, nv_rd08(bios, 0x300000 + i)); + if (!bios->data) + goto out; + + for (i = 0; i < bios->size; i += 4) + ((u32 *)bios->data)[i/4] = nv_rd32(bios, 0x300000 + i); + + /* check the PCI record header */ + pcir = nv_ro16(bios, 0x0018); + if (bios->data[pcir + 0] != 'P' || + bios->data[pcir + 1] != 'C' || + bios->data[pcir + 2] != 'I' || + bios->data[pcir + 3] != 'R') { + bios->size = 0; + kfree(bios->data); } out: diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c b/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c new file mode 100644 index 00000000000..c1835e591c4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c @@ -0,0 +1,127 @@ +/* + * 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/boost.h> + +u16 +nvbios_boostTe(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) +{ + struct bit_entry bit_P; + u16 boost = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2) + boost = nv_ro16(bios, bit_P.offset + 0x30); + + if (boost) { + *ver = nv_ro08(bios, boost + 0); + switch (*ver) { + case 0x11: + *hdr = nv_ro08(bios, boost + 1); + *cnt = nv_ro08(bios, boost + 5); + *len = nv_ro08(bios, boost + 2); + *snr = nv_ro08(bios, boost + 4); + *ssz = nv_ro08(bios, boost + 3); + return boost; + default: + break; + } + } + } + + return 0x0000; +} + +u16 +nvbios_boostEe(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u8 snr, ssz; + u16 data = nvbios_boostTe(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 0x0000; +} + +u16 +nvbios_boostEp(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info) +{ + u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + if (data) { + info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5; + info->min = nv_ro16(bios, data + 0x02) * 1000; + info->max = nv_ro16(bios, data + 0x04) * 1000; + } + return data; +} + +u16 +nvbios_boostEm(struct nouveau_bios *bios, u8 pstate, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info) +{ + u32 data, idx = 0; + while ((data = nvbios_boostEp(bios, idx++, ver, hdr, cnt, len, info))) { + if (info->pstate == pstate) + break; + } + return data; +} + +u16 +nvbios_boostSe(struct nouveau_bios *bios, int idx, + u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len) +{ + if (data && idx < cnt) { + data = data + *hdr + (idx * len); + *hdr = len; + return data; + } + return 0x0000; +} + +u16 +nvbios_boostSp(struct nouveau_bios *bios, int idx, + u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len, + struct nvbios_boostS *info) +{ + data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + if (data) { + info->domain = nv_ro08(bios, data + 0x00); + info->percent = nv_ro08(bios, data + 0x01); + info->min = nv_ro16(bios, data + 0x02) * 1000; + info->max = nv_ro16(bios, data + 0x04) * 1000; + } + return data; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c index 5ac010efd95..2ede3bcd96a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c @@ -28,12 +28,12 @@ #include <subdev/bios/dcb.h> #include <subdev/bios/conn.h> -u16 -dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +u32 +nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { - u16 dcb = dcb_table(bios, ver, hdr, cnt, len); + u32 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb && *ver >= 0x30 && *hdr >= 0x16) { - u16 data = nv_ro16(bios, dcb + 0x14); + u32 data = nv_ro16(bios, dcb + 0x14); if (data) { *ver = nv_ro08(bios, data + 0); *hdr = nv_ro08(bios, data + 1); @@ -42,15 +42,59 @@ dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) return data; } } - return 0x0000; + return 0x00000000; } -u16 -dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) +u32 +nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_connT *info) +{ + u32 data = nvbios_connTe(bios, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x30: + case 0x40: + return data; + default: + break; + } + return 0x00000000; +} + +u32 +nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) { u8 hdr, cnt; - u16 data = dcb_conntab(bios, ver, &hdr, &cnt, len); + u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len); if (data && idx < cnt) return data + hdr + (idx * *len); - return 0x0000; + return 0x00000000; +} + +u32 +nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, + struct nvbios_connE *info) +{ + u32 data = nvbios_connEe(bios, idx, ver, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x30: + case 0x40: + info->type = nv_ro08(bios, data + 0x00); + info->location = nv_ro08(bios, data + 0x01) & 0x0f; + info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4; + info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6; + if (*len < 4) + return data; + info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2; + info->dp |= nv_ro08(bios, data + 0x02) & 0x0c; + info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4; + info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4; + info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3; + info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4; + return data; + default: + break; + } + return 0x00000000; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c b/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c new file mode 100644 index 00000000000..d3b15327fbf --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c @@ -0,0 +1,123 @@ +/* + * 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/cstep.h> + +u16 +nvbios_cstepTe(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz) +{ + struct bit_entry bit_P; + u16 cstep = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2) + cstep = nv_ro16(bios, bit_P.offset + 0x34); + + if (cstep) { + *ver = nv_ro08(bios, cstep + 0); + switch (*ver) { + case 0x10: + *hdr = nv_ro08(bios, cstep + 1); + *cnt = nv_ro08(bios, cstep + 3); + *len = nv_ro08(bios, cstep + 2); + *xnr = nv_ro08(bios, cstep + 5); + *xsz = nv_ro08(bios, cstep + 4); + return cstep; + default: + break; + } + } + } + + return 0x0000; +} + +u16 +nvbios_cstepEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr) +{ + u8 cnt, len, xnr, xsz; + u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz); + if (data && idx < cnt) { + data = data + *hdr + (idx * len); + *hdr = len; + return data; + } + return 0x0000; +} + +u16 +nvbios_cstepEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr, + struct nvbios_cstepE *info) +{ + u16 data = nvbios_cstepEe(bios, idx, ver, hdr); + memset(info, 0x00, sizeof(*info)); + if (data) { + info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5; + info->index = nv_ro08(bios, data + 0x03); + } + return data; +} + +u16 +nvbios_cstepEm(struct nouveau_bios *bios, u8 pstate, u8 *ver, u8 *hdr, + struct nvbios_cstepE *info) +{ + u32 data, idx = 0; + while ((data = nvbios_cstepEp(bios, idx++, ver, hdr, info))) { + if (info->pstate == pstate) + break; + } + return data; +} + +u16 +nvbios_cstepXe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr) +{ + u8 cnt, len, xnr, xsz; + u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz); + if (data && idx < xnr) { + data = data + *hdr + (cnt * len) + (idx * xsz); + *hdr = xsz; + return data; + } + return 0x0000; +} + +u16 +nvbios_cstepXp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr, + struct nvbios_cstepX *info) +{ + u16 data = nvbios_cstepXe(bios, idx, ver, hdr); + memset(info, 0x00, sizeof(*info)); + if (data) { + info->freq = nv_ro16(bios, data + 0x00) * 1000; + info->unkn[0] = nv_ro08(bios, data + 0x02); + info->unkn[1] = nv_ro08(bios, data + 0x03); + info->voltage = nv_ro08(bios, data + 0x04); + } + return data; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 2d9b9d7a799..88606bfaf84 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -142,9 +142,36 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, if (*ver >= 0x40) { u32 conf = nv_ro32(bios, dcb + 0x04); switch (outp->type) { + case DCB_OUTPUT_DP: + switch (conf & 0x00e00000) { + case 0x00000000: + outp->dpconf.link_bw = 0x06; + break; + case 0x00200000: + outp->dpconf.link_bw = 0x0a; + break; + case 0x00400000: + default: + outp->dpconf.link_bw = 0x14; + break; + } + + switch (conf & 0x0f000000) { + case 0x0f000000: + outp->dpconf.link_nr = 4; + break; + case 0x03000000: + outp->dpconf.link_nr = 2; + break; + case 0x01000000: + default: + outp->dpconf.link_nr = 1; + break; + } + + /* fall-through... */ case DCB_OUTPUT_TMDS: case DCB_OUTPUT_LVDS: - case DCB_OUTPUT_DP: outp->link = (conf & 0x00000030) >> 4; outp->sorconf.link = outp->link; /*XXX*/ outp->extdev = 0x00; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c index 663853bcca8..f309dd65725 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c @@ -89,6 +89,7 @@ nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx, struct nvbios_dpout *info) { u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); if (data && *ver) { info->type = nv_ro16(bios, data + 0x00); info->mask = nv_ro16(bios, data + 0x02); @@ -99,9 +100,12 @@ nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx, info->script[0] = nv_ro16(bios, data + 0x06); info->script[1] = nv_ro16(bios, data + 0x08); info->lnkcmp = nv_ro16(bios, data + 0x0a); - info->script[2] = nv_ro16(bios, data + 0x0c); - info->script[3] = nv_ro16(bios, data + 0x0e); - info->script[4] = nv_ro16(bios, data + 0x10); + if (*len >= 0x0f) { + info->script[2] = nv_ro16(bios, data + 0x0c); + info->script[3] = nv_ro16(bios, data + 0x0e); + } + if (*len >= 0x11) + info->script[4] = nv_ro16(bios, data + 0x10); break; case 0x40: info->flags = nv_ro08(bios, data + 0x04); @@ -158,18 +162,20 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, struct nvbios_dpcfg *info) { u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); if (data) { switch (*ver) { case 0x21: - info->drv = nv_ro08(bios, data + 0x02); - info->pre = nv_ro08(bios, data + 0x03); - info->unk = nv_ro08(bios, data + 0x04); + info->dc = nv_ro08(bios, data + 0x02); + info->pe = nv_ro08(bios, data + 0x03); + info->tx_pu = nv_ro08(bios, data + 0x04); break; case 0x30: case 0x40: - info->drv = nv_ro08(bios, data + 0x01); - info->pre = nv_ro08(bios, data + 0x02); - info->unk = nv_ro08(bios, data + 0x03); + info->pc = nv_ro08(bios, data + 0x00); + info->dc = nv_ro08(bios, data + 0x01); + info->pe = nv_ro08(bios, data + 0x02); + info->tx_pu = nv_ro08(bios, data + 0x03); break; default: data = 0x0000; @@ -180,7 +186,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, } u16 -nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, +nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *info) { @@ -189,16 +195,15 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, if (*ver >= 0x30) { const u8 vsoff[] = { 0, 4, 7, 9 }; - idx = (un * 10) + vsoff[vs] + pe; + idx = (pc * 10) + vsoff[vs] + pe; } else { - while ((data = nvbios_dpcfg_entry(bios, outp, idx, + while ((data = nvbios_dpcfg_entry(bios, outp, ++idx, ver, hdr, cnt, len))) { if (nv_ro08(bios, data + 0x00) == vs && nv_ro08(bios, data + 0x01) == pe) break; - idx++; } } - return nvbios_dpcfg_parse(bios, outp, pe, ver, hdr, cnt, len, info); + return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index 57cda2a1437..626380f9e4c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -9,6 +9,7 @@ #include <subdev/bios/dp.h> #include <subdev/bios/gpio.h> #include <subdev/bios/init.h> +#include <subdev/bios/ramcfg.h> #include <subdev/devinit.h> #include <subdev/i2c.h> #include <subdev/vga.h> @@ -97,15 +98,16 @@ static u8 init_conn(struct nvbios_init *init) { struct nouveau_bios *bios = init->bios; - u8 ver, len; - u16 conn; + struct nvbios_connE connE; + u8 ver, hdr; + u32 conn; if (init_exec(init)) { if (init->outp) { conn = init->outp->connector; - conn = dcb_conn(bios, conn, &ver, &len); + conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE); if (conn) - return nv_ro08(bios, conn); + return connE.type; } error("script needs connector type\n"); @@ -117,6 +119,8 @@ init_conn(struct nvbios_init *init) static inline u32 init_nvreg(struct nvbios_init *init, u32 reg) { + struct nouveau_devinit *devinit = nouveau_devinit(init->bios); + /* C51 (at least) sometimes has the lower bits set which the VBIOS * interprets to mean that access needs to go through certain IO * ports instead. The NVIDIA binary driver has been seen to access @@ -146,6 +150,9 @@ init_nvreg(struct nvbios_init *init, u32 reg) if (reg & ~0x00fffffc) warn("unknown bits in register 0x%08x\n", reg); + + if (devinit->mmio) + reg = devinit->mmio(devinit, reg); return reg; } @@ -153,7 +160,7 @@ static u32 init_rd32(struct nvbios_init *init, u32 reg) { reg = init_nvreg(init, reg); - if (init_exec(init)) + if (reg != ~0 && init_exec(init)) return nv_rd32(init->subdev, reg); return 0x00000000; } @@ -162,7 +169,7 @@ static void init_wr32(struct nvbios_init *init, u32 reg, u32 val) { reg = init_nvreg(init, reg); - if (init_exec(init)) + if (reg != ~0 && init_exec(init)) nv_wr32(init->subdev, reg, val); } @@ -170,7 +177,7 @@ static u32 init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val) { reg = init_nvreg(init, reg); - if (init_exec(init)) { + if (reg != ~0 && init_exec(init)) { u32 tmp = nv_rd32(init->subdev, reg); nv_wr32(init->subdev, reg, (tmp & ~mask) | val); return tmp; @@ -365,13 +372,13 @@ static u16 init_script(struct nouveau_bios *bios, int index) { struct nvbios_init init = { .bios = bios }; - u16 data; + u16 bmp_ver = bmp_version(bios), data; - if (bmp_version(bios) && bmp_version(bios) < 0x0510) { - if (index > 1) + if (bmp_ver && bmp_ver < 0x0510) { + if (index > 1 || bmp_ver < 0x0100) return 0x0000; - data = bios->bmp_offset + (bios->version.major < 2 ? 14 : 18); + data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18); return nv_ro16(bios, data + (index * 2)); } @@ -391,43 +398,14 @@ init_unknown_script(struct nouveau_bios *bios) return 0x0000; } -static u16 -init_ram_restrict_table(struct nvbios_init *init) -{ - struct nouveau_bios *bios = init->bios; - struct bit_entry bit_M; - u16 data = 0x0000; - - if (!bit_entry(bios, 'M', &bit_M)) { - if (bit_M.version == 1 && bit_M.length >= 5) - data = nv_ro16(bios, bit_M.offset + 3); - if (bit_M.version == 2 && bit_M.length >= 3) - data = nv_ro16(bios, bit_M.offset + 1); - } - - if (data == 0x0000) - warn("ram restrict table not found\n"); - return data; -} - static u8 init_ram_restrict_group_count(struct nvbios_init *init) { - struct nouveau_bios *bios = init->bios; - struct bit_entry bit_M; - - if (!bit_entry(bios, 'M', &bit_M)) { - if (bit_M.version == 1 && bit_M.length >= 5) - return nv_ro08(bios, bit_M.offset + 2); - if (bit_M.version == 2 && bit_M.length >= 3) - return nv_ro08(bios, bit_M.offset + 0); - } - - return 0x00; + return nvbios_ramcfg_count(init->bios); } static u8 -init_ram_restrict_strap(struct nvbios_init *init) +init_ram_restrict(struct nvbios_init *init) { /* This appears to be the behaviour of the VBIOS parser, and *is* * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to @@ -438,18 +416,8 @@ init_ram_restrict_strap(struct nvbios_init *init) * in case *not* re-reading the strap causes similar breakage. */ if (!init->ramcfg || init->bios->version.major < 0x70) - init->ramcfg = init_rd32(init, 0x101000); - return (init->ramcfg & 0x00000003c) >> 2; -} - -static u8 -init_ram_restrict(struct nvbios_init *init) -{ - u8 strap = init_ram_restrict_strap(init); - u16 table = init_ram_restrict_table(init); - if (table) - return nv_ro08(init->bios, table + strap); - return 0x00; + init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev); + return (init->ramcfg & 0x7fffffff); } static u8 @@ -883,9 +851,8 @@ init_idx_addr_latched(struct nvbios_init *init) u32 data = nv_ro32(bios, init->offset + 13); u8 count = nv_ro08(bios, init->offset + 17); - trace("INDEX_ADDRESS_LATCHED\t" - "R[0x%06x] : R[0x%06x]\n\tCTRL &= 0x%08x |= 0x%08x\n", - creg, dreg, mask, data); + trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg); + trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data); init->offset += 18; while (count--) { @@ -1294,7 +1261,11 @@ init_jump(struct nvbios_init *init) u16 offset = nv_ro16(bios, init->offset + 1); trace("JUMP\t0x%04x\n", offset); - init->offset = offset; + + if (init_exec(init)) + init->offset = offset; + else + init->offset += 3; } /** @@ -2180,7 +2151,7 @@ nvbios_init(struct nouveau_subdev *subdev, bool execute) u16 data; if (execute) - nv_suspend(bios, "running init tables\n"); + nv_info(bios, "running init tables\n"); while (!ret && (data = (init_script(bios, ++i)))) { struct nvbios_init init = { .subdev = subdev, @@ -2210,5 +2181,5 @@ nvbios_init(struct nouveau_subdev *subdev, bool execute) ret = nvbios_exec(&init); } - return 0; + return ret; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c index bcbb056c288..675e221680a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c @@ -26,8 +26,9 @@ #include <subdev/bios/bit.h> #include <subdev/bios/perf.h> -static u16 -perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +u16 +nvbios_perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, + u8 *cnt, u8 *len, u8 *snr, u8 *ssz) { struct bit_entry bit_P; u16 perf = 0x0000; @@ -38,10 +39,22 @@ perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (perf) { *ver = nv_ro08(bios, perf + 0); *hdr = nv_ro08(bios, perf + 1); + if (*ver >= 0x40 && *ver < 0x41) { + *cnt = nv_ro08(bios, perf + 5); + *len = nv_ro08(bios, perf + 2); + *snr = nv_ro08(bios, perf + 4); + *ssz = nv_ro08(bios, perf + 3); + return perf; + } else + if (*ver >= 0x20 && *ver < 0x40) { + *cnt = nv_ro08(bios, perf + 2); + *len = nv_ro08(bios, perf + 3); + *snr = nv_ro08(bios, perf + 4); + *ssz = nv_ro08(bios, perf + 5); + return perf; + } } - } else - nv_error(bios, "unknown offset for perf in BIT P %d\n", - bit_P.version); + } } if (bios->bmp_offset) { @@ -50,19 +63,132 @@ perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (perf) { *hdr = nv_ro08(bios, perf + 0); *ver = nv_ro08(bios, perf + 1); + *cnt = nv_ro08(bios, perf + 2); + *len = nv_ro08(bios, perf + 3); + *snr = 0; + *ssz = 0; + return perf; } } } + return 0x0000; +} + +u16 +nvbios_perf_entry(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u8 snr, ssz; + u16 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz); + if (perf && idx < *cnt) { + perf = perf + *hdr + (idx * (*len + (snr * ssz))); + *hdr = *len; + *cnt = snr; + *len = ssz; + return perf; + } + return 0x0000; +} + +u16 +nvbios_perfEp(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_perfE *info) +{ + u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + info->pstate = nv_ro08(bios, perf + 0x00); + switch (!!perf * *ver) { + case 0x12: + case 0x13: + case 0x14: + info->core = nv_ro32(bios, perf + 0x01) * 10; + info->memory = nv_ro32(bios, perf + 0x05) * 20; + info->fanspeed = nv_ro08(bios, perf + 0x37); + if (*hdr > 0x38) + info->voltage = nv_ro08(bios, perf + 0x38); + break; + case 0x21: + case 0x23: + case 0x24: + info->fanspeed = nv_ro08(bios, perf + 0x04); + info->voltage = nv_ro08(bios, perf + 0x05); + info->shader = nv_ro16(bios, perf + 0x06) * 1000; + info->core = info->shader + (signed char) + nv_ro08(bios, perf + 0x08) * 1000; + switch (nv_device(bios)->chipset) { + case 0x49: + case 0x4b: + info->memory = nv_ro16(bios, perf + 0x0b) * 1000; + break; + default: + info->memory = nv_ro16(bios, perf + 0x0b) * 2000; + break; + } + break; + case 0x25: + info->fanspeed = nv_ro08(bios, perf + 0x04); + info->voltage = nv_ro08(bios, perf + 0x05); + info->core = nv_ro16(bios, perf + 0x06) * 1000; + info->shader = nv_ro16(bios, perf + 0x0a) * 1000; + info->memory = nv_ro16(bios, perf + 0x0c) * 1000; + break; + case 0x30: + info->script = nv_ro16(bios, perf + 0x02); + case 0x35: + info->fanspeed = nv_ro08(bios, perf + 0x06); + info->voltage = nv_ro08(bios, perf + 0x07); + info->core = nv_ro16(bios, perf + 0x08) * 1000; + info->shader = nv_ro16(bios, perf + 0x0a) * 1000; + info->memory = nv_ro16(bios, perf + 0x0c) * 1000; + info->vdec = nv_ro16(bios, perf + 0x10) * 1000; + info->disp = nv_ro16(bios, perf + 0x14) * 1000; + break; + case 0x40: + info->voltage = nv_ro08(bios, perf + 0x02); + break; + default: + return 0x0000; + } return perf; } +u32 +nvbios_perfSe(struct nouveau_bios *bios, u32 perfE, int idx, + u8 *ver, u8 *hdr, u8 cnt, u8 len) +{ + u32 data = 0x00000000; + if (idx < cnt) { + data = perfE + *hdr + (idx * len); + *hdr = len; + } + return data; +} + +u32 +nvbios_perfSp(struct nouveau_bios *bios, u32 perfE, int idx, + u8 *ver, u8 *hdr, u8 cnt, u8 len, + struct nvbios_perfS *info) +{ + u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x40: + info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000; + break; + default: + break; + } + return data; +} + int nvbios_perf_fan_parse(struct nouveau_bios *bios, struct nvbios_perf_fan *fan) { - u8 ver = 0, hdr = 0, cnt = 0, len = 0; - u16 perf = perf_table(bios, &ver, &hdr, &cnt, &len); + u8 ver, hdr, cnt, len, snr, ssz; + u16 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz); if (!perf) return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c index f835501203e..1f76de597d4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c @@ -114,6 +114,7 @@ pll_map(struct nouveau_bios *bios) switch (nv_device(bios)->card_type) { case NV_04: case NV_10: + case NV_11: case NV_20: case NV_30: return nv04_pll_mapping; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c new file mode 100644 index 00000000000..6c401f70ab9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c @@ -0,0 +1,68 @@ +/* + * 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 <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/ramcfg.h> + +static u8 +nvbios_ramcfg_strap(struct nouveau_subdev *subdev) +{ + return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2; +} + +u8 +nvbios_ramcfg_count(struct nouveau_bios *bios) +{ + struct bit_entry bit_M; + + if (!bit_entry(bios, 'M', &bit_M)) { + if (bit_M.version == 1 && bit_M.length >= 5) + return nv_ro08(bios, bit_M.offset + 2); + if (bit_M.version == 2 && bit_M.length >= 3) + return nv_ro08(bios, bit_M.offset + 0); + } + + return 0x00; +} + +u8 +nvbios_ramcfg_index(struct nouveau_subdev *subdev) +{ + struct nouveau_bios *bios = nouveau_bios(subdev); + u8 strap = nvbios_ramcfg_strap(subdev); + u32 xlat = 0x00000000; + struct bit_entry bit_M; + + if (!bit_entry(bios, 'M', &bit_M)) { + if (bit_M.version == 1 && bit_M.length >= 5) + xlat = nv_ro16(bios, bit_M.offset + 3); + if (bit_M.version == 2 && bit_M.length >= 3) + xlat = nv_ro16(bios, bit_M.offset + 1); + } + + if (xlat) + strap = nv_ro08(bios, xlat + strap); + return strap; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c new file mode 100644 index 00000000000..1811b2cb047 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c @@ -0,0 +1,173 @@ +/* + * 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/ramcfg.h> +#include <subdev/bios/rammap.h> + +u32 +nvbios_rammapTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, + u8 *cnt, u8 *len, u8 *snr, u8 *ssz) +{ + struct bit_entry bit_P; + u16 rammap = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2) + rammap = nv_ro16(bios, bit_P.offset + 4); + + if (rammap) { + *ver = nv_ro08(bios, rammap + 0); + switch (*ver) { + case 0x10: + case 0x11: + *hdr = nv_ro08(bios, rammap + 1); + *cnt = nv_ro08(bios, rammap + 5); + *len = nv_ro08(bios, rammap + 2); + *snr = nv_ro08(bios, rammap + 4); + *ssz = nv_ro08(bios, rammap + 3); + return rammap; + default: + break; + } + } + } + + return 0x0000; +} + +u32 +nvbios_rammapEe(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u8 snr, ssz; + u16 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz); + if (rammap && idx < *cnt) { + rammap = rammap + *hdr + (idx * (*len + (snr * ssz))); + *hdr = *len; + *cnt = snr; + *len = ssz; + return rammap; + } + return 0x0000; +} + +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, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_ramcfg *p) +{ + u32 data = nvbios_rammapEm(bios, khz, ver, hdr, cnt, len); + memset(p, 0x00, sizeof(*p)); + switch (!!data * *ver) { + case 0x11: + 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; + p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2; + break; + default: + data = 0; + 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) +{ + if (idx < ecnt) { + data = data + ehdr + (idx * elen); + *ver = ever; + *hdr = elen; + return data; + } + return 0; +} + +u32 +nvbios_rammapSp(struct nouveau_bios *bios, u32 data, + u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, + u8 *ver, u8 *hdr, struct nvbios_ramcfg *p) +{ + data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr); + switch (!!data * *ver) { + case 0x11: + 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; + p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3; + p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4; + p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5; + p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6; + p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7; + p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0; + p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2; + p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; + p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; + p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; + p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7; + p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; + p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4; + p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6; + p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4; + p->ramcfg_11_04 = (nv_ro08(bios, data + 0x04) & 0xff) >> 0; + p->ramcfg_11_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1; + p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2; + p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3; + p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4; + p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6; + p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7; + p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0; + p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1; + p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2; + p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3; + p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4; + p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5; + p->ramcfg_11_09 = (nv_ro08(bios, data + 0x09) & 0xff) >> 0; + break; + default: + data = 0; + break; + } + return data; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c index 22ac6dbd6c8..d1585409407 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c @@ -164,6 +164,7 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, i = 0; fan->nr_fan_trip = 0; + fan->fan_mode = NVBIOS_THERM_FAN_OTHER; while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { s16 value = nv_ro16(bios, entry + 1); @@ -174,6 +175,8 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, break; case 0x24: fan->nr_fan_trip++; + if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP) + fan->fan_mode = NVBIOS_THERM_FAN_TRIP; cur_trip = &fan->trip[fan->nr_fan_trip - 1]; cur_trip->hysteresis = value & 0xf; cur_trip->temp = (value & 0xff0) >> 4; @@ -194,11 +197,19 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, fan->slow_down_period = value; break; case 0x46: + if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR) + fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; fan->linear_min_temp = nv_ro08(bios, entry + 1); fan->linear_max_temp = nv_ro08(bios, entry + 2); break; } } + /* starting from fermi, fan management is always linear */ + if (nv_device(bios)->card_type >= NV_C0 && + fan->fan_mode == NVBIOS_THERM_FAN_OTHER) { + fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; + } + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c new file mode 100644 index 00000000000..350d44ab2ba --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c @@ -0,0 +1,127 @@ +/* + * 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/ramcfg.h> +#include <subdev/bios/timing.h> + +u16 +nvbios_timingTe(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) +{ + struct bit_entry bit_P; + u16 timing = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 1) + timing = nv_ro16(bios, bit_P.offset + 4); + else + if (bit_P.version == 2) + timing = nv_ro16(bios, bit_P.offset + 8); + + if (timing) { + *ver = nv_ro08(bios, timing + 0); + switch (*ver) { + case 0x10: + *hdr = nv_ro08(bios, timing + 1); + *cnt = nv_ro08(bios, timing + 2); + *len = nv_ro08(bios, timing + 3); + *snr = 0; + *ssz = 0; + return timing; + case 0x20: + *hdr = nv_ro08(bios, timing + 1); + *cnt = nv_ro08(bios, timing + 5); + *len = nv_ro08(bios, timing + 2); + *snr = nv_ro08(bios, timing + 4); + *ssz = nv_ro08(bios, timing + 3); + return timing; + default: + break; + } + } + } + + return 0x0000; +} + +u16 +nvbios_timingEe(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u8 snr, ssz; + u16 timing = nvbios_timingTe(bios, ver, hdr, cnt, len, &snr, &ssz); + if (timing && idx < *cnt) { + timing += *hdr + idx * (*len + (snr * ssz)); + *hdr = *len; + *cnt = snr; + *len = ssz; + return timing; + } + return 0x0000; +} + +u16 +nvbios_timingEp(struct nouveau_bios *bios, int idx, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_ramcfg *p) +{ + u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp; + switch (!!data * *ver) { + case 0x20: + p->timing[0] = nv_ro32(bios, data + 0x00); + p->timing[1] = nv_ro32(bios, data + 0x04); + p->timing[2] = nv_ro32(bios, data + 0x08); + p->timing[3] = nv_ro32(bios, data + 0x0c); + p->timing[4] = nv_ro32(bios, data + 0x10); + p->timing[5] = nv_ro32(bios, data + 0x14); + p->timing[6] = nv_ro32(bios, data + 0x18); + p->timing[7] = nv_ro32(bios, data + 0x1c); + p->timing[8] = nv_ro32(bios, data + 0x20); + p->timing[9] = nv_ro32(bios, data + 0x24); + p->timing[10] = nv_ro32(bios, data + 0x28); + p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0; + p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4; + p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6; + p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0; + temp = nv_ro16(bios, data + 0x2c); + p->timing_20_2c_003f = (temp & 0x003f) >> 0; + p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6; + p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0; + p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3; + temp = nv_ro16(bios, data + 0x31); + p->timing_20_31_0007 = (temp & 0x0007) >> 0; + p->timing_20_31_0078 = (temp & 0x0078) >> 3; + p->timing_20_31_0780 = (temp & 0x0780) >> 7; + p->timing_20_31_0800 = (temp & 0x0800) >> 11; + p->timing_20_31_7000 = (temp & 0x7000) >> 12; + p->timing_20_31_8000 = (temp & 0x8000) >> 15; + break; + default: + data = 0; + break; + } + return data; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c new file mode 100644 index 00000000000..f343a1b060e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c @@ -0,0 +1,112 @@ +/* + * Copyright 2012 Nouveau Community + * + * 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/vmap.h> + +u16 +nvbios_vmap_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + struct bit_entry bit_P; + u16 vmap = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2) { + vmap = nv_ro16(bios, bit_P.offset + 0x20); + if (vmap) { + *ver = nv_ro08(bios, vmap + 0); + switch (*ver) { + case 0x10: + case 0x20: + *hdr = nv_ro08(bios, vmap + 1); + *cnt = nv_ro08(bios, vmap + 3); + *len = nv_ro08(bios, vmap + 2); + return vmap; + default: + break; + } + } + } + } + + return 0x0000; +} + +u16 +nvbios_vmap_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_vmap *info) +{ + u16 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + switch (!!vmap * *ver) { + case 0x10: + case 0x20: + break; + } + return vmap; +} + +u16 +nvbios_vmap_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 vmap = nvbios_vmap_table(bios, ver, &hdr, &cnt, len); + if (vmap && idx < cnt) { + vmap = vmap + hdr + (idx * *len); + return vmap; + } + return 0x0000; +} + +u16 +nvbios_vmap_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len, + struct nvbios_vmap_entry *info) +{ + u16 vmap = nvbios_vmap_entry(bios, idx, ver, len); + memset(info, 0x00, sizeof(*info)); + switch (!!vmap * *ver) { + case 0x10: + info->link = 0xff; + info->min = nv_ro32(bios, vmap + 0x00); + info->max = nv_ro32(bios, vmap + 0x04); + info->arg[0] = nv_ro32(bios, vmap + 0x08); + info->arg[1] = nv_ro32(bios, vmap + 0x0c); + info->arg[2] = nv_ro32(bios, vmap + 0x10); + break; + case 0x20: + info->unk0 = nv_ro08(bios, vmap + 0x00); + info->link = nv_ro08(bios, vmap + 0x01); + info->min = nv_ro32(bios, vmap + 0x02); + info->max = nv_ro32(bios, vmap + 0x06); + info->arg[0] = nv_ro32(bios, vmap + 0x0a); + info->arg[1] = nv_ro32(bios, vmap + 0x0e); + info->arg[2] = nv_ro32(bios, vmap + 0x12); + info->arg[3] = nv_ro32(bios, vmap + 0x16); + info->arg[4] = nv_ro32(bios, vmap + 0x1a); + info->arg[5] = nv_ro32(bios, vmap + 0x1e); + break; + } + return vmap; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c new file mode 100644 index 00000000000..bb590de4ecb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c @@ -0,0 +1,137 @@ +/* + * Copyright 2012 Nouveau Community + * + * 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/volt.h> + +u16 +nvbios_volt_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + struct bit_entry bit_P; + u16 volt = 0x0000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2) + volt = nv_ro16(bios, bit_P.offset + 0x0c); + else + if (bit_P.version == 1) + volt = nv_ro16(bios, bit_P.offset + 0x10); + + if (volt) { + *ver = nv_ro08(bios, volt + 0); + switch (*ver) { + case 0x12: + *hdr = 5; + *cnt = nv_ro08(bios, volt + 2); + *len = nv_ro08(bios, volt + 1); + return volt; + case 0x20: + *hdr = nv_ro08(bios, volt + 1); + *cnt = nv_ro08(bios, volt + 2); + *len = nv_ro08(bios, volt + 3); + return volt; + case 0x30: + case 0x40: + case 0x50: + *hdr = nv_ro08(bios, volt + 1); + *cnt = nv_ro08(bios, volt + 3); + *len = nv_ro08(bios, volt + 2); + return volt; + } + } + } + + return 0x0000; +} + +u16 +nvbios_volt_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_volt *info) +{ + u16 volt = nvbios_volt_table(bios, ver, hdr, cnt, len); + memset(info, 0x00, sizeof(*info)); + switch (!!volt * *ver) { + case 0x12: + info->vidmask = nv_ro08(bios, volt + 0x04); + break; + case 0x20: + info->vidmask = nv_ro08(bios, volt + 0x05); + break; + case 0x30: + info->vidmask = nv_ro08(bios, volt + 0x04); + break; + case 0x40: + info->base = nv_ro32(bios, volt + 0x04); + info->step = nv_ro16(bios, volt + 0x08); + info->vidmask = nv_ro08(bios, volt + 0x0b); + /*XXX*/ + info->min = 0; + info->max = info->base; + break; + case 0x50: + info->vidmask = nv_ro08(bios, volt + 0x06); + info->min = nv_ro32(bios, volt + 0x0a); + info->max = nv_ro32(bios, volt + 0x0e); + info->base = nv_ro32(bios, volt + 0x12) & 0x00ffffff; + info->step = nv_ro16(bios, volt + 0x16); + break; + } + return volt; +} + +u16 +nvbios_volt_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 volt = nvbios_volt_table(bios, ver, &hdr, &cnt, len); + if (volt && idx < cnt) { + volt = volt + hdr + (idx * *len); + return volt; + } + return 0x0000; +} + +u16 +nvbios_volt_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len, + struct nvbios_volt_entry *info) +{ + u16 volt = nvbios_volt_entry(bios, idx, ver, len); + memset(info, 0x00, sizeof(*info)); + switch (!!volt * *ver) { + case 0x12: + case 0x20: + info->voltage = nv_ro08(bios, volt + 0x00) * 10000; + info->vid = nv_ro08(bios, volt + 0x01); + break; + case 0x30: + info->voltage = nv_ro08(bios, volt + 0x00) * 10000; + info->vid = nv_ro08(bios, volt + 0x01) >> 2; + break; + case 0x40: + case 0x50: + break; + } + return volt; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c new file mode 100644 index 00000000000..f757470e228 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c @@ -0,0 +1,145 @@ +/* + * 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 <subdev/timer.h> +#include <subdev/bus.h> + +struct nouveau_hwsq { + struct nouveau_bus *pbus; + u32 addr; + u32 data; + struct { + u8 data[512]; + u8 size; + } c; +}; + +static void +hwsq_cmd(struct nouveau_hwsq *hwsq, int size, u8 data[]) +{ + memcpy(&hwsq->c.data[hwsq->c.size], data, size * sizeof(data[0])); + hwsq->c.size += size; +} + +int +nouveau_hwsq_init(struct nouveau_bus *pbus, struct nouveau_hwsq **phwsq) +{ + struct nouveau_hwsq *hwsq; + + hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL); + if (hwsq) { + hwsq->pbus = pbus; + hwsq->addr = ~0; + hwsq->data = ~0; + memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data)); + hwsq->c.size = 0; + } + + return hwsq ? 0 : -ENOMEM; +} + +int +nouveau_hwsq_fini(struct nouveau_hwsq **phwsq, bool exec) +{ + struct nouveau_hwsq *hwsq = *phwsq; + int ret = 0, i; + if (hwsq) { + struct nouveau_bus *pbus = hwsq->pbus; + hwsq->c.size = (hwsq->c.size + 4) / 4; + if (hwsq->c.size <= pbus->hwsq_size) { + if (exec) + ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data, + hwsq->c.size); + if (ret) + nv_error(pbus, "hwsq exec failed: %d\n", ret); + } else { + nv_error(pbus, "hwsq ucode too large\n"); + ret = -ENOSPC; + } + + for (i = 0; ret && i < hwsq->c.size; i++) + nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]); + + *phwsq = NULL; + kfree(hwsq); + } + return ret; +} + +void +nouveau_hwsq_wr32(struct nouveau_hwsq *hwsq, u32 addr, u32 data) +{ + nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data); + + if (hwsq->data != data) { + if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) { + hwsq_cmd(hwsq, 5, (u8[]){ 0xe2, data, data >> 8, + data >> 16, data >> 24 }); + } else { + hwsq_cmd(hwsq, 3, (u8[]){ 0x42, data, data >> 8 }); + } + } + + if ((addr & 0xffff0000) != (hwsq->addr & 0xffff0000)) { + hwsq_cmd(hwsq, 5, (u8[]){ 0xe0, addr, addr >> 8, + addr >> 16, addr >> 24 }); + } else { + hwsq_cmd(hwsq, 3, (u8[]){ 0x40, addr, addr >> 8 }); + } + + hwsq->addr = addr; + hwsq->data = data; +} + +void +nouveau_hwsq_setf(struct nouveau_hwsq *hwsq, u8 flag, int data) +{ + nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data); + flag += 0x80; + if (data >= 0) + flag += 0x20; + if (data >= 1) + flag += 0x20; + hwsq_cmd(hwsq, 1, (u8[]){ flag }); +} + +void +nouveau_hwsq_wait(struct nouveau_hwsq *hwsq, u8 flag, u8 data) +{ + nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data); + hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data }); +} + +void +nouveau_hwsq_nsec(struct nouveau_hwsq *hwsq, u32 nsec) +{ + u8 shift = 0, usec = nsec / 1000; + while (usec & ~3) { + usec >>= 2; + shift++; + } + + nv_debug(hwsq->pbus, " DELAY = %d ns\n", nsec); + hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec }); +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h new file mode 100644 index 00000000000..12176f9c1bc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h @@ -0,0 +1,113 @@ +#ifndef __NVKM_BUS_HWSQ_H__ +#define __NVKM_BUS_HWSQ_H__ + +#include <subdev/bus.h> + +struct hwsq { + struct nouveau_subdev *subdev; + struct nouveau_hwsq *hwsq; + int sequence; +}; + +struct hwsq_reg { + int sequence; + bool force; + u32 addr[2]; + u32 data; +}; + +static inline struct hwsq_reg +hwsq_reg2(u32 addr1, u32 addr2) +{ + return (struct hwsq_reg) { + .sequence = 0, + .force = 0, + .addr = { addr1, addr2 }, + .data = 0xdeadbeef, + }; +} + +static inline struct hwsq_reg +hwsq_reg(u32 addr) +{ + return hwsq_reg2(addr, addr); +} + +static inline int +hwsq_init(struct hwsq *ram, struct nouveau_subdev *subdev) +{ + struct nouveau_bus *pbus = nouveau_bus(subdev); + int ret; + + ret = nouveau_hwsq_init(pbus, &ram->hwsq); + if (ret) + return ret; + + ram->sequence++; + ram->subdev = subdev; + return 0; +} + +static inline int +hwsq_exec(struct hwsq *ram, bool exec) +{ + int ret = 0; + if (ram->subdev) { + ret = nouveau_hwsq_fini(&ram->hwsq, exec); + ram->subdev = NULL; + } + return ret; +} + +static inline u32 +hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg) +{ + if (reg->sequence != ram->sequence) + reg->data = nv_rd32(ram->subdev, reg->addr[0]); + return reg->data; +} + +static inline void +hwsq_wr32(struct hwsq *ram, struct hwsq_reg *reg, u32 data) +{ + reg->sequence = ram->sequence; + reg->data = data; + if (reg->addr[0] != reg->addr[1]) + nouveau_hwsq_wr32(ram->hwsq, reg->addr[1], reg->data); + nouveau_hwsq_wr32(ram->hwsq, reg->addr[0], reg->data); +} + +static inline void +hwsq_nuke(struct hwsq *ram, struct hwsq_reg *reg) +{ + reg->force = true; +} + +static inline u32 +hwsq_mask(struct hwsq *ram, struct hwsq_reg *reg, u32 mask, u32 data) +{ + u32 temp = hwsq_rd32(ram, reg); + if (temp != ((temp & ~mask) | data) || reg->force) + hwsq_wr32(ram, reg, (temp & ~mask) | data); + return temp; +} + +static inline void +hwsq_setf(struct hwsq *ram, u8 flag, int data) +{ + nouveau_hwsq_setf(ram->hwsq, flag, data); +} + +static inline void +hwsq_wait(struct hwsq *ram, u8 flag, u8 data) +{ + nouveau_hwsq_wait(ram->hwsq, flag, data); +} + +static inline void +hwsq_nsec(struct hwsq *ram, u32 nsec) +{ + nouveau_hwsq_nsec(ram->hwsq, nsec); +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c index 8c7f8057a18..23921b5351d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c @@ -23,11 +23,7 @@ * Ben Skeggs */ -#include <subdev/bus.h> - -struct nv04_bus_priv { - struct nouveau_bus base; -}; +#include "nv04.h" static void nv04_bus_intr(struct nouveau_subdev *subdev) @@ -56,10 +52,22 @@ nv04_bus_intr(struct nouveau_subdev *subdev) } static int +nv04_bus_init(struct nouveau_object *object) +{ + struct nv04_bus_priv *priv = (void *)object; + + nv_wr32(priv, 0x001100, 0xffffffff); + nv_wr32(priv, 0x001140, 0x00000111); + + return nouveau_bus_init(&priv->base); +} + +int nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + struct nv04_bus_impl *impl = (void *)oclass; struct nv04_bus_priv *priv; int ret; @@ -68,28 +76,20 @@ nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - nv_subdev(priv)->intr = nv04_bus_intr; + nv_subdev(priv)->intr = impl->intr; + priv->base.hwsq_exec = impl->hwsq_exec; + priv->base.hwsq_size = impl->hwsq_size; return 0; } -static int -nv04_bus_init(struct nouveau_object *object) -{ - struct nv04_bus_priv *priv = (void *)object; - - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x00000111); - - return nouveau_bus_init(&priv->base); -} - -struct nouveau_oclass -nv04_bus_oclass = { - .handle = NV_SUBDEV(BUS, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv04_bus_oclass = &(struct nv04_bus_impl) { + .base.handle = NV_SUBDEV(BUS, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_bus_ctor, .dtor = _nouveau_bus_dtor, .init = nv04_bus_init, .fini = _nouveau_bus_fini, }, -}; + .intr = nv04_bus_intr, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h new file mode 100644 index 00000000000..4d7602450a2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h @@ -0,0 +1,23 @@ +#ifndef __NVKM_BUS_NV04_H__ +#define __NVKM_BUS_NV04_H__ + +#include <subdev/bus.h> + +struct nv04_bus_priv { + struct nouveau_bus base; +}; + +int nv04_bus_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +int nv50_bus_init(struct nouveau_object *); +void nv50_bus_intr(struct nouveau_subdev *); + +struct nv04_bus_impl { + struct nouveau_oclass base; + void (*intr)(struct nouveau_subdev *); + int (*hwsq_exec)(struct nouveau_bus *, u32 *, u32); + u32 hwsq_size; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c index 34132aef34e..94da46f6162 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c @@ -23,11 +23,7 @@ * Ben Skeggs */ -#include <subdev/bus.h> - -struct nv31_bus_priv { - struct nouveau_bus base; -}; +#include "nv04.h" static void nv31_bus_intr(struct nouveau_subdev *subdev) @@ -71,7 +67,7 @@ nv31_bus_intr(struct nouveau_subdev *subdev) static int nv31_bus_init(struct nouveau_object *object) { - struct nv31_bus_priv *priv = (void *)object; + struct nv04_bus_priv *priv = (void *)object; int ret; ret = nouveau_bus_init(&priv->base); @@ -83,30 +79,14 @@ nv31_bus_init(struct nouveau_object *object) return 0; } -static int -nv31_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv31_bus_priv *priv; - int ret; - - ret = nouveau_bus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->intr = nv31_bus_intr; - return 0; -} - -struct nouveau_oclass -nv31_bus_oclass = { - .handle = NV_SUBDEV(BUS, 0x31), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv31_bus_ctor, +struct nouveau_oclass * +nv31_bus_oclass = &(struct nv04_bus_impl) { + .base.handle = NV_SUBDEV(BUS, 0x31), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_bus_ctor, .dtor = _nouveau_bus_dtor, .init = nv31_bus_init, .fini = _nouveau_bus_fini, }, -}; + .intr = nv31_bus_intr, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c index f5b2117fa8c..11918f7e2ac 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c @@ -23,13 +23,27 @@ * Ben Skeggs */ -#include <subdev/bus.h> +#include <subdev/timer.h> -struct nv50_bus_priv { - struct nouveau_bus base; -}; +#include "nv04.h" -static void +static int +nv50_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size) +{ + struct nv50_bus_priv *priv = (void *)pbus; + int i; + + nv_mask(pbus, 0x001098, 0x00000008, 0x00000000); + nv_wr32(pbus, 0x001304, 0x00000000); + for (i = 0; i < size; i++) + nv_wr32(priv, 0x001400 + (i * 4), data[i]); + nv_mask(pbus, 0x001098, 0x00000018, 0x00000018); + nv_wr32(pbus, 0x00130c, 0x00000003); + + return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; +} + +void nv50_bus_intr(struct nouveau_subdev *subdev) { struct nouveau_bus *pbus = nouveau_bus(subdev); @@ -61,10 +75,10 @@ nv50_bus_intr(struct nouveau_subdev *subdev) } } -static int +int nv50_bus_init(struct nouveau_object *object) { - struct nv50_bus_priv *priv = (void *)object; + struct nv04_bus_priv *priv = (void *)object; int ret; ret = nouveau_bus_init(&priv->base); @@ -76,30 +90,16 @@ nv50_bus_init(struct nouveau_object *object) return 0; } -static int -nv50_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_bus_priv *priv; - int ret; - - ret = nouveau_bus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->intr = nv50_bus_intr; - return 0; -} - -struct nouveau_oclass -nv50_bus_oclass = { - .handle = NV_SUBDEV(BUS, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_bus_ctor, +struct nouveau_oclass * +nv50_bus_oclass = &(struct nv04_bus_impl) { + .base.handle = NV_SUBDEV(BUS, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_bus_ctor, .dtor = _nouveau_bus_dtor, .init = nv50_bus_init, .fini = _nouveau_bus_fini, }, -}; + .intr = nv50_bus_intr, + .hwsq_exec = nv50_bus_hwsq_exec, + .hwsq_size = 64, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c new file mode 100644 index 00000000000..d3659055fa4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c @@ -0,0 +1,59 @@ +/* + * Copyright 2012 Nouveau Community + * + * 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 <martin.peres@labri.fr> + * Ben Skeggs + */ + +#include <subdev/timer.h> + +#include "nv04.h" + +static int +nv94_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size) +{ + struct nv50_bus_priv *priv = (void *)pbus; + int i; + + nv_mask(pbus, 0x001098, 0x00000008, 0x00000000); + nv_wr32(pbus, 0x001304, 0x00000000); + nv_wr32(pbus, 0x001318, 0x00000000); + for (i = 0; i < size; i++) + nv_wr32(priv, 0x080000 + (i * 4), data[i]); + nv_mask(pbus, 0x001098, 0x00000018, 0x00000018); + nv_wr32(pbus, 0x00130c, 0x00000001); + + return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; +} + +struct nouveau_oclass * +nv94_bus_oclass = &(struct nv04_bus_impl) { + .base.handle = NV_SUBDEV(BUS, 0x94), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_bus_ctor, + .dtor = _nouveau_bus_dtor, + .init = nv50_bus_init, + .fini = _nouveau_bus_fini, + }, + .intr = nv50_bus_intr, + .hwsq_exec = nv94_bus_hwsq_exec, + .hwsq_size = 128, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c index b192d624636..73839d7151a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c @@ -23,11 +23,7 @@ * Ben Skeggs */ -#include <subdev/bus.h> - -struct nvc0_bus_priv { - struct nouveau_bus base; -}; +#include "nv04.h" static void nvc0_bus_intr(struct nouveau_subdev *subdev) @@ -60,7 +56,7 @@ nvc0_bus_intr(struct nouveau_subdev *subdev) static int nvc0_bus_init(struct nouveau_object *object) { - struct nvc0_bus_priv *priv = (void *)object; + struct nv04_bus_priv *priv = (void *)object; int ret; ret = nouveau_bus_init(&priv->base); @@ -72,30 +68,14 @@ nvc0_bus_init(struct nouveau_object *object) return 0; } -static int -nvc0_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvc0_bus_priv *priv; - int ret; - - ret = nouveau_bus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->intr = nvc0_bus_intr; - return 0; -} - -struct nouveau_oclass -nvc0_bus_oclass = { - .handle = NV_SUBDEV(BUS, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_bus_ctor, +struct nouveau_oclass * +nvc0_bus_oclass = &(struct nv04_bus_impl) { + .base.handle = NV_SUBDEV(BUS, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_bus_ctor, .dtor = _nouveau_bus_dtor, .init = nvc0_bus_init, .fini = _nouveau_bus_fini, }, -}; + .intr = nvc0_bus_intr, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c new file mode 100644 index 00000000000..22351f594d2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c @@ -0,0 +1,500 @@ +/* + * 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 <core/option.h> + +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/volt.h> +#include <subdev/fb.h> + +#include <subdev/bios.h> +#include <subdev/bios/boost.h> +#include <subdev/bios/cstep.h> +#include <subdev/bios/perf.h> + +/****************************************************************************** + * misc + *****************************************************************************/ +static u32 +nouveau_clock_adjust(struct nouveau_clock *clk, bool adjust, + u8 pstate, u8 domain, u32 input) +{ + struct nouveau_bios *bios = nouveau_bios(clk); + struct nvbios_boostE boostE; + u8 ver, hdr, cnt, len; + u16 data; + + data = nvbios_boostEm(bios, pstate, &ver, &hdr, &cnt, &len, &boostE); + if (data) { + struct nvbios_boostS boostS; + u8 idx = 0, sver, shdr; + u16 subd; + + input = max(boostE.min, input); + input = min(boostE.max, input); + do { + sver = ver; + shdr = hdr; + subd = nvbios_boostSp(bios, idx++, data, &sver, &shdr, + cnt, len, &boostS); + if (subd && boostS.domain == domain) { + if (adjust) + input = input * boostS.percent / 100; + input = max(boostS.min, input); + input = min(boostS.max, input); + break; + } + } while (subd); + } + + return input; +} + +/****************************************************************************** + * C-States + *****************************************************************************/ +static int +nouveau_cstate_prog(struct nouveau_clock *clk, + struct nouveau_pstate *pstate, int cstatei) +{ + struct nouveau_therm *ptherm = nouveau_therm(clk); + struct nouveau_volt *volt = nouveau_volt(clk); + struct nouveau_cstate *cstate; + int ret; + + if (!list_empty(&pstate->list)) { + cstate = list_entry(pstate->list.prev, typeof(*cstate), head); + } else { + 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; + } + + 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); + if (ret == 0) { + ret = clk->prog(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); + + 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; +} + +static void +nouveau_cstate_del(struct nouveau_cstate *cstate) +{ + list_del(&cstate->head); + kfree(cstate); +} + +static int +nouveau_cstate_new(struct nouveau_clock *clk, int idx, + struct nouveau_pstate *pstate) +{ + struct nouveau_bios *bios = nouveau_bios(clk); + struct nouveau_clocks *domain = clk->domains; + struct nouveau_cstate *cstate = NULL; + struct nvbios_cstepX cstepX; + u8 ver, hdr; + u16 data; + + data = nvbios_cstepXp(bios, idx, &ver, &hdr, &cstepX); + if (!data) + return -ENOENT; + + cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); + if (!cstate) + return -ENOMEM; + + *cstate = pstate->base; + cstate->voltage = cstepX.voltage; + + while (domain && domain->name != nv_clk_src_max) { + if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) { + u32 freq = nouveau_clock_adjust(clk, true, + pstate->pstate, + domain->bios, + cstepX.freq); + cstate->domain[domain->name] = freq; + } + domain++; + } + + list_add(&cstate->head, &pstate->list); + return 0; +} + +/****************************************************************************** + * P-States + *****************************************************************************/ +static int +nouveau_pstate_prog(struct nouveau_clock *clk, int pstatei) +{ + struct nouveau_fb *pfb = nouveau_fb(clk); + struct nouveau_pstate *pstate; + int ret, idx = 0; + + list_for_each_entry(pstate, &clk->states, head) { + if (idx++ == pstatei) + break; + } + + nv_debug(clk, "setting performance state %d\n", pstatei); + clk->pstate = pstatei; + + if (pfb->ram->calc) { + int khz = pstate->base.domain[nv_clk_src_mem]; + do { + ret = pfb->ram->calc(pfb, khz); + if (ret == 0) + ret = pfb->ram->prog(pfb); + } while (ret > 0); + pfb->ram->tidy(pfb); + } + + return nouveau_cstate_prog(clk, pstate, 0); +} + +static int +nouveau_pstate_calc(struct nouveau_clock *clk) +{ + int pstate, ret = 0; + + 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 (clk->state_nr && clk->ustate != -1) { + pstate = (clk->ustate < 0) ? clk->astate : clk->ustate; + pstate = min(pstate, clk->state_nr - 1 - clk->tstate); + pstate = max(pstate, clk->dstate); + } else { + pstate = clk->pstate = -1; + } + + nv_trace(clk, "-> %d\n", pstate); + if (pstate != clk->pstate) + ret = nouveau_pstate_prog(clk, pstate); + return ret; +} + +static void +nouveau_pstate_info(struct nouveau_clock *clk, struct nouveau_pstate *pstate) +{ + struct nouveau_clocks *clock = clk->domains - 1; + struct nouveau_cstate *cstate; + char info[3][32] = { "", "", "" }; + char name[4] = "--"; + int i = -1; + + if (pstate->pstate != 0xff) + snprintf(name, sizeof(name), "%02x", pstate->pstate); + + while ((++clock)->name != nv_clk_src_max) { + u32 lo = pstate->base.domain[clock->name]; + u32 hi = lo; + if (hi == 0) + continue; + + nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo); + list_for_each_entry(cstate, &pstate->list, head) { + u32 freq = cstate->domain[clock->name]; + lo = min(lo, freq); + hi = max(hi, freq); + nv_debug(clk, "%10d KHz\n", freq); + } + + if (clock->mname && ++i < ARRAY_SIZE(info)) { + lo /= clock->mdiv; + hi /= clock->mdiv; + if (lo == hi) { + snprintf(info[i], sizeof(info[i]), "%s %d MHz", + clock->mname, lo); + } else { + snprintf(info[i], sizeof(info[i]), + "%s %d-%d MHz", clock->mname, lo, hi); + } + } + } + + nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]); +} + +static void +nouveau_pstate_del(struct nouveau_pstate *pstate) +{ + struct nouveau_cstate *cstate, *temp; + + list_for_each_entry_safe(cstate, temp, &pstate->list, head) { + nouveau_cstate_del(cstate); + } + + list_del(&pstate->head); + kfree(pstate); +} + +static int +nouveau_pstate_new(struct nouveau_clock *clk, int idx) +{ + struct nouveau_bios *bios = nouveau_bios(clk); + struct nouveau_clocks *domain = clk->domains - 1; + struct nouveau_pstate *pstate; + struct nouveau_cstate *cstate; + struct nvbios_cstepE cstepE; + struct nvbios_perfE perfE; + u8 ver, hdr, cnt, len; + u16 data; + + data = nvbios_perfEp(bios, idx, &ver, &hdr, &cnt, &len, &perfE); + if (!data) + return -EINVAL; + if (perfE.pstate == 0xff) + return 0; + + pstate = kzalloc(sizeof(*pstate), GFP_KERNEL); + cstate = &pstate->base; + if (!pstate) + return -ENOMEM; + + INIT_LIST_HEAD(&pstate->list); + + pstate->pstate = perfE.pstate; + pstate->fanspeed = perfE.fanspeed; + cstate->voltage = perfE.voltage; + cstate->domain[nv_clk_src_core] = perfE.core; + cstate->domain[nv_clk_src_shader] = perfE.shader; + cstate->domain[nv_clk_src_mem] = perfE.memory; + cstate->domain[nv_clk_src_vdec] = perfE.vdec; + cstate->domain[nv_clk_src_dom6] = perfE.disp; + + while (ver >= 0x40 && (++domain)->name != nv_clk_src_max) { + struct nvbios_perfS perfS; + u8 sver = ver, shdr = hdr; + u32 perfSe = nvbios_perfSp(bios, data, domain->bios, + &sver, &shdr, cnt, len, &perfS); + if (perfSe == 0 || sver != 0x40) + continue; + + if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) { + perfS.v40.freq = nouveau_clock_adjust(clk, false, + pstate->pstate, + domain->bios, + perfS.v40.freq); + } + + cstate->domain[domain->name] = perfS.v40.freq; + } + + data = nvbios_cstepEm(bios, pstate->pstate, &ver, &hdr, &cstepE); + if (data) { + int idx = cstepE.index; + do { + nouveau_cstate_new(clk, idx, pstate); + } while(idx--); + } + + nouveau_pstate_info(clk, pstate); + list_add_tail(&pstate->head, &clk->states); + clk->state_nr++; + return 0; +} + +/****************************************************************************** + * Adjustment triggers + *****************************************************************************/ +static int +nouveau_clock_ustate_update(struct nouveau_clock *clk, int req) +{ + struct nouveau_pstate *pstate; + int i = 0; + + if (!clk->allow_reclock) + return -ENOSYS; + + if (req != -1 && req != -2) { + list_for_each_entry(pstate, &clk->states, head) { + if (pstate->pstate == req) + break; + i++; + } + + if (pstate->pstate != req) + return -EINVAL; + req = i; + } + + clk->ustate = req; + return 0; +} + +int +nouveau_clock_ustate(struct nouveau_clock *clk, int req) +{ + int ret = nouveau_clock_ustate_update(clk, req); + if (ret) + return ret; + return nouveau_pstate_calc(clk); +} + +int +nouveau_clock_astate(struct nouveau_clock *clk, int req, int rel) +{ + if (!rel) clk->astate = req; + 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); +} + +int +nouveau_clock_tstate(struct nouveau_clock *clk, int req, int rel) +{ + if (!rel) clk->tstate = req; + 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); +} + +int +nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel) +{ + if (!rel) clk->dstate = req; + 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); +} + +/****************************************************************************** + * subdev base class implementation + *****************************************************************************/ +int +_nouveau_clock_init(struct nouveau_object *object) +{ + struct nouveau_clock *clk = (void *)object; + struct nouveau_clocks *clock = clk->domains; + int ret; + + memset(&clk->bstate, 0x00, sizeof(clk->bstate)); + INIT_LIST_HEAD(&clk->bstate.list); + clk->bstate.pstate = 0xff; + + while (clock->name != nv_clk_src_max) { + ret = clk->read(clk, clock->name); + if (ret < 0) { + nv_error(clk, "%02x freq unknown\n", clock->name); + return ret; + } + clk->bstate.base.domain[clock->name] = ret; + clock++; + } + + nouveau_pstate_info(clk, &clk->bstate); + + clk->astate = clk->state_nr - 1; + clk->tstate = 0; + clk->dstate = 0; + clk->pstate = -1; + nouveau_pstate_calc(clk); + return 0; +} + +void +_nouveau_clock_dtor(struct nouveau_object *object) +{ + struct nouveau_clock *clk = (void *)object; + struct nouveau_pstate *pstate, *temp; + + list_for_each_entry_safe(pstate, temp, &clk->states, head) { + nouveau_pstate_del(pstate); + } + + nouveau_subdev_destroy(&clk->base); +} + +int +nouveau_clock_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + struct nouveau_clocks *clocks, + bool allow_reclock, + int length, void **object) +{ + struct nouveau_device *device = nv_device(parent); + struct nouveau_clock *clk; + int ret, idx, arglen; + const char *mode; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "CLK", + "clock", length, object); + clk = *object; + if (ret) + return ret; + + INIT_LIST_HEAD(&clk->states); + clk->domains = clocks; + clk->ustate = -1; + + idx = 0; + do { + ret = nouveau_pstate_new(clk, idx++); + } while (ret == 0); + + clk->allow_reclock = allow_reclock; + + 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; + } + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c index a1427758659..eb2d4425a49 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c @@ -25,7 +25,7 @@ #include <subdev/bios.h> #include <subdev/bios/pll.h> #include <subdev/clock.h> -#include <subdev/devinit/priv.h> +#include <subdev/devinit/nv04.h> #include "pll.h" @@ -69,6 +69,11 @@ nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1, return 0; } +static struct nouveau_clocks +nv04_domain[] = { + { nv_clk_src_max } +}; + static int nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -77,7 +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, &priv); + ret = nouveau_clock_create(parent, engine, oclass, nv04_domain, 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 0db5dbfd91b..8a9e1683979 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c @@ -23,11 +23,188 @@ */ #include <subdev/clock.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" struct nv40_clock_priv { struct nouveau_clock base; + u32 ctrl; + u32 npll_ctrl; + u32 npll_coef; + u32 spll; +}; + +static struct nouveau_clocks +nv40_domain[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_max } }; +static u32 +read_pll_1(struct nv40_clock_priv *priv, u32 reg) +{ + u32 ctrl = nv_rd32(priv, reg + 0x00); + int P = (ctrl & 0x00070000) >> 16; + int N = (ctrl & 0x0000ff00) >> 8; + int M = (ctrl & 0x000000ff) >> 0; + u32 ref = 27000, clk = 0; + + if (ctrl & 0x80000000) + clk = ref * N / M; + + return clk >> P; +} + +static u32 +read_pll_2(struct nv40_clock_priv *priv, u32 reg) +{ + u32 ctrl = nv_rd32(priv, reg + 0x00); + u32 coef = nv_rd32(priv, reg + 0x04); + int N2 = (coef & 0xff000000) >> 24; + int M2 = (coef & 0x00ff0000) >> 16; + int N1 = (coef & 0x0000ff00) >> 8; + int M1 = (coef & 0x000000ff) >> 0; + int P = (ctrl & 0x00070000) >> 16; + u32 ref = 27000, clk = 0; + + if ((ctrl & 0x80000000) && M1) { + clk = ref * N1 / M1; + if ((ctrl & 0x40000100) == 0x40000000) { + if (M2) + clk = clk * N2 / M2; + else + clk = 0; + } + } + + return clk >> P; +} + +static u32 +read_clk(struct nv40_clock_priv *priv, u32 src) +{ + switch (src) { + case 3: + return read_pll_2(priv, 0x004000); + case 2: + return read_pll_1(priv, 0x004008); + default: + break; + } + + return 0; +} + +static int +nv40_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) +{ + struct nv40_clock_priv *priv = (void *)clk; + u32 mast = nv_rd32(priv, 0x00c040); + + switch (src) { + case nv_clk_src_crystal: + return nv_device(priv)->crystal; + case nv_clk_src_href: + return 100000; /*XXX: PCIE/AGP differ*/ + case nv_clk_src_core: + return read_clk(priv, (mast & 0x00000003) >> 0); + case nv_clk_src_shader: + return read_clk(priv, (mast & 0x00000030) >> 4); + case nv_clk_src_mem: + return read_pll_2(priv, 0x4020); + default: + break; + } + + nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + return -EINVAL; +} + +static int +nv40_clock_calc_pll(struct nv40_clock_priv *priv, u32 reg, u32 clk, + int *N1, int *M1, int *N2, int *M2, int *log2P) +{ + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll pll; + int ret; + + ret = nvbios_pll_parse(bios, reg, &pll); + if (ret) + return ret; + + if (clk < pll.vco1.max_freq) + pll.vco2.max_freq = 0; + + ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P); + if (ret == 0) + return -ERANGE; + return ret; +} + +static int +nv40_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) +{ + struct nv40_clock_priv *priv = (void *)clk; + int gclk = cstate->domain[nv_clk_src_core]; + int sclk = cstate->domain[nv_clk_src_shader]; + int N1, M1, N2, M2, log2P; + int ret; + + /* core/geometric clock */ + ret = nv40_clock_calc_pll(priv, 0x004000, gclk, + &N1, &M1, &N2, &M2, &log2P); + if (ret < 0) + return ret; + + if (N2 == M2) { + priv->npll_ctrl = 0x80000100 | (log2P << 16); + priv->npll_coef = (N1 << 8) | M1; + } else { + priv->npll_ctrl = 0xc0000000 | (log2P << 16); + priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; + } + + /* use the second pll for shader/rop clock, if it differs from core */ + if (sclk && sclk != gclk) { + ret = nv40_clock_calc_pll(priv, 0x004008, sclk, + &N1, &M1, NULL, NULL, &log2P); + if (ret < 0) + return ret; + + priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; + priv->ctrl = 0x00000223; + } else { + priv->spll = 0x00000000; + priv->ctrl = 0x00000333; + } + + return 0; +} + +static int +nv40_clock_prog(struct nouveau_clock *clk) +{ + struct nv40_clock_priv *priv = (void *)clk; + nv_mask(priv, 0x00c040, 0x00000333, 0x00000000); + nv_wr32(priv, 0x004004, priv->npll_coef); + nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl); + nv_mask(priv, 0x004008, 0xc007ffff, priv->spll); + mdelay(5); + nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl); + return 0; +} + +static void +nv40_clock_tidy(struct nouveau_clock *clk) +{ +} + static int nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -36,13 +213,18 @@ 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, &priv); + ret = nouveau_clock_create(parent, engine, oclass, nv40_domain, true, + &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.pll_calc = nv04_clock_pll_calc; priv->base.pll_prog = nv04_clock_pll_prog; + priv->base.read = nv40_clock_read; + priv->base.calc = nv40_clock_calc; + priv->base.prog = nv40_clock_prog; + priv->base.tidy = nv40_clock_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c index d09d3e78040..8c132772ba9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c @@ -22,40 +22,538 @@ * Authors: Ben Skeggs */ -#include <subdev/clock.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> +#include "nv50.h" #include "pll.h" +#include "seq.h" -struct nv50_clock_priv { - struct nouveau_clock base; -}; +static u32 +read_div(struct nv50_clock_priv *priv) +{ + switch (nv_device(priv)->chipset) { + case 0x50: /* it exists, but only has bit 31, not the dividers.. */ + case 0x84: + case 0x86: + case 0x98: + case 0xa0: + return nv_rd32(priv, 0x004700); + case 0x92: + case 0x94: + case 0x96: + return nv_rd32(priv, 0x004800); + default: + return 0x00000000; + } +} + +static u32 +read_pll_src(struct nv50_clock_priv *priv, u32 base) +{ + struct nouveau_clock *clk = &priv->base; + u32 coef, ref = clk->read(clk, nv_clk_src_crystal); + u32 rsel = nv_rd32(priv, 0x00e18c); + int P, N, M, id; + + switch (nv_device(priv)->chipset) { + case 0x50: + case 0xa0: + switch (base) { + case 0x4020: + case 0x4028: id = !!(rsel & 0x00000004); break; + case 0x4008: id = !!(rsel & 0x00000008); break; + case 0x4030: id = 0; break; + default: + nv_error(priv, "ref: bad pll 0x%06x\n", base); + return 0; + } + + coef = nv_rd32(priv, 0x00e81c + (id * 0x0c)); + ref *= (coef & 0x01000000) ? 2 : 4; + P = (coef & 0x00070000) >> 16; + N = ((coef & 0x0000ff00) >> 8) + 1; + M = ((coef & 0x000000ff) >> 0) + 1; + break; + case 0x84: + case 0x86: + case 0x92: + coef = nv_rd32(priv, 0x00e81c); + P = (coef & 0x00070000) >> 16; + N = (coef & 0x0000ff00) >> 8; + M = (coef & 0x000000ff) >> 0; + break; + case 0x94: + case 0x96: + case 0x98: + rsel = nv_rd32(priv, 0x00c050); + switch (base) { + case 0x4020: rsel = (rsel & 0x00000003) >> 0; break; + case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break; + case 0x4028: rsel = (rsel & 0x00001800) >> 11; break; + case 0x4030: rsel = 3; break; + default: + nv_error(priv, "ref: bad pll 0x%06x\n", base); + return 0; + } + + switch (rsel) { + case 0: id = 1; break; + case 1: return clk->read(clk, nv_clk_src_crystal); + case 2: return clk->read(clk, nv_clk_src_href); + case 3: id = 0; break; + } + + coef = nv_rd32(priv, 0x00e81c + (id * 0x28)); + P = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7; + P += (coef & 0x00070000) >> 16; + N = (coef & 0x0000ff00) >> 8; + M = (coef & 0x000000ff) >> 0; + break; + default: + BUG_ON(1); + } + + if (M) + return (ref * N / M) >> P; + return 0; +} + +static u32 +read_pll_ref(struct nv50_clock_priv *priv, u32 base) +{ + struct nouveau_clock *clk = &priv->base; + u32 src, mast = nv_rd32(priv, 0x00c040); + + switch (base) { + case 0x004028: + src = !!(mast & 0x00200000); + break; + case 0x004020: + src = !!(mast & 0x00400000); + break; + case 0x004008: + src = !!(mast & 0x00010000); + break; + case 0x004030: + src = !!(mast & 0x02000000); + break; + case 0x00e810: + return clk->read(clk, nv_clk_src_crystal); + default: + nv_error(priv, "bad pll 0x%06x\n", base); + return 0; + } + + if (src) + return clk->read(clk, nv_clk_src_href); + return read_pll_src(priv, base); +} + +static u32 +read_pll(struct nv50_clock_priv *priv, u32 base) +{ + struct nouveau_clock *clk = &priv->base; + u32 mast = nv_rd32(priv, 0x00c040); + u32 ctrl = nv_rd32(priv, base + 0); + u32 coef = nv_rd32(priv, base + 4); + u32 ref = read_pll_ref(priv, base); + u32 freq = 0; + int N1, N2, M1, M2; + + if (base == 0x004028 && (mast & 0x00100000)) { + /* wtf, appears to only disable post-divider on nva0 */ + if (nv_device(priv)->chipset != 0xa0) + return clk->read(clk, nv_clk_src_dom6); + } + + N2 = (coef & 0xff000000) >> 24; + M2 = (coef & 0x00ff0000) >> 16; + N1 = (coef & 0x0000ff00) >> 8; + M1 = (coef & 0x000000ff); + if ((ctrl & 0x80000000) && M1) { + freq = ref * N1 / M1; + if ((ctrl & 0x40000100) == 0x40000000) { + if (M2) + freq = freq * N2 / M2; + else + freq = 0; + } + } + + return freq; +} static int +nv50_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) +{ + struct nv50_clock_priv *priv = (void *)clk; + u32 mast = nv_rd32(priv, 0x00c040); + u32 P = 0; + + switch (src) { + case nv_clk_src_crystal: + return nv_device(priv)->crystal; + case nv_clk_src_href: + return 100000; /* PCIE reference clock */ + case nv_clk_src_hclk: + return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000); + case nv_clk_src_hclkm3: + return clk->read(clk, nv_clk_src_hclk) * 3; + case nv_clk_src_hclkm3d2: + return clk->read(clk, nv_clk_src_hclk) * 3 / 2; + case nv_clk_src_host: + switch (mast & 0x30000000) { + case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x10000000: break; + case 0x20000000: /* !0x50 */ + case 0x30000000: return clk->read(clk, nv_clk_src_hclk); + } + break; + case nv_clk_src_core: + if (!(mast & 0x00100000)) + P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16; + switch (mast & 0x00000003) { + case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000001: return clk->read(clk, nv_clk_src_dom6); + case 0x00000002: return read_pll(priv, 0x004020) >> P; + case 0x00000003: return read_pll(priv, 0x004028) >> P; + } + break; + case nv_clk_src_shader: + P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16; + switch (mast & 0x00000030) { + case 0x00000000: + if (mast & 0x00000080) + return clk->read(clk, nv_clk_src_host) >> P; + return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000010: break; + case 0x00000020: return read_pll(priv, 0x004028) >> P; + case 0x00000030: return read_pll(priv, 0x004020) >> P; + } + break; + case nv_clk_src_mem: + P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16; + if (nv_rd32(priv, 0x004008) & 0x00000200) { + switch (mast & 0x0000c000) { + case 0x00000000: + return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00008000: + case 0x0000c000: + return clk->read(clk, nv_clk_src_href) >> P; + } + } else { + return read_pll(priv, 0x004008) >> P; + } + break; + case nv_clk_src_vdec: + P = (read_div(priv) & 0x00000700) >> 8; + switch (nv_device(priv)->chipset) { + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0xa0: + switch (mast & 0x00000c00) { + case 0x00000000: + if (nv_device(priv)->chipset == 0xa0) /* wtf?? */ + return clk->read(clk, nv_clk_src_core) >> P; + return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000400: + return 0; + case 0x00000800: + if (mast & 0x01000000) + return read_pll(priv, 0x004028) >> P; + return read_pll(priv, 0x004030) >> P; + case 0x00000c00: + return clk->read(clk, nv_clk_src_core) >> P; + } + break; + case 0x98: + switch (mast & 0x00000c00) { + case 0x00000000: + return clk->read(clk, nv_clk_src_core) >> P; + case 0x00000400: + return 0; + case 0x00000800: + return clk->read(clk, nv_clk_src_hclkm3d2) >> P; + case 0x00000c00: + return clk->read(clk, nv_clk_src_mem) >> P; + } + break; + } + break; + case nv_clk_src_dom6: + switch (nv_device(priv)->chipset) { + case 0x50: + case 0xa0: + return read_pll(priv, 0x00e810) >> 2; + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + P = (read_div(priv) & 0x00000007) >> 0; + switch (mast & 0x0c000000) { + case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x04000000: break; + case 0x08000000: return clk->read(clk, nv_clk_src_hclk); + case 0x0c000000: + return clk->read(clk, nv_clk_src_hclkm3) >> P; + } + break; + default: + break; + } + default: + break; + } + + nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + return -EINVAL; +} + +static u32 +calc_pll(struct nv50_clock_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P) +{ + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll pll; + int ret; + + ret = nvbios_pll_parse(bios, reg, &pll); + if (ret) + return 0; + + pll.vco2.max_freq = 0; + pll.refclk = read_pll_ref(priv, reg); + if (!pll.refclk) + return 0; + + return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P); +} + +static inline u32 +calc_div(u32 src, u32 target, int *div) +{ + u32 clk0 = src, clk1 = src; + for (*div = 0; *div <= 7; (*div)++) { + if (clk0 <= target) { + clk1 = clk0 << (*div ? 1 : 0); + break; + } + clk0 >>= 1; + } + + if (target - clk0 <= clk1 - target) + return clk0; + (*div)--; + return clk1; +} + +static inline u32 +clk_same(u32 a, u32 b) +{ + return ((a / 1000) == (b / 1000)); +} + +static int +nv50_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) +{ + struct nv50_clock_priv *priv = (void *)clk; + struct nv50_clock_hwsq *hwsq = &priv->hwsq; + const int shader = cstate->domain[nv_clk_src_shader]; + const int core = cstate->domain[nv_clk_src_core]; + const int vdec = cstate->domain[nv_clk_src_vdec]; + const int dom6 = cstate->domain[nv_clk_src_dom6]; + u32 mastm = 0, mastv = 0; + u32 divsm = 0, divsv = 0; + int N, M, P1, P2; + int freq, out; + + /* prepare a hwsq script from which we'll perform the reclock */ + out = clk_init(hwsq, nv_subdev(clk)); + if (out) + return out; + + clk_wr32(hwsq, fifo, 0x00000001); /* block fifo */ + clk_nsec(hwsq, 8000); + clk_setf(hwsq, 0x10, 0x00); /* disable fb */ + clk_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */ + + /* vdec: avoid modifying xpll until we know exactly how the other + * clock domains work, i suspect at least some of them can also be + * tied to xpll... + */ + if (vdec) { + /* see how close we can get using nvclk as a source */ + freq = calc_div(core, vdec, &P1); + + /* see how close we can get using xpll/hclk as a source */ + if (nv_device(priv)->chipset != 0x98) + out = read_pll(priv, 0x004030); + else + out = clk->read(clk, nv_clk_src_hclkm3d2); + out = calc_div(out, vdec, &P2); + + /* select whichever gets us closest */ + if (abs(vdec - freq) <= abs(vdec - out)) { + if (nv_device(priv)->chipset != 0x98) + mastv |= 0x00000c00; + divsv |= P1 << 8; + } else { + mastv |= 0x00000800; + divsv |= P2 << 8; + } + + mastm |= 0x00000c00; + divsm |= 0x00000700; + } + + /* dom6: nfi what this is, but we're limited to various combinations + * of the host clock frequency + */ + if (dom6) { + if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) { + mastv |= 0x00000000; + } else + if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) { + mastv |= 0x08000000; + } else { + freq = clk->read(clk, nv_clk_src_hclk) * 3; + freq = calc_div(freq, dom6, &P1); + + mastv |= 0x0c000000; + divsv |= P1; + } + + mastm |= 0x0c000000; + divsm |= 0x00000007; + } + + /* vdec/dom6: switch to "safe" clocks temporarily, update dividers + * and then switch to target clocks + */ + clk_mask(hwsq, mast, mastm, 0x00000000); + clk_mask(hwsq, divs, divsm, divsv); + clk_mask(hwsq, mast, mastm, mastv); + + /* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6, + * sclk to hclk) before reprogramming + */ + if (nv_device(priv)->chipset < 0x92) + clk_mask(hwsq, mast, 0x001000b0, 0x00100080); + else + clk_mask(hwsq, mast, 0x000000b3, 0x00000081); + + /* core: for the moment at least, always use nvpll */ + freq = calc_pll(priv, 0x4028, core, &N, &M, &P1); + if (freq == 0) + return -ERANGE; + + clk_mask(hwsq, nvpll[0], 0xc03f0100, + 0x80000000 | (P1 << 19) | (P1 << 16)); + clk_mask(hwsq, nvpll[1], 0x0000ffff, (N << 8) | M); + + /* shader: tie to nvclk if possible, otherwise use spll. have to be + * very careful that the shader clock is at least twice the core, or + * some chipsets will be very unhappy. i expect most or all of these + * cases will be handled by tying to nvclk, but it's possible there's + * corners + */ + if (P1-- && shader == (core << 1)) { + clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16)); + clk_mask(hwsq, mast, 0x00100033, 0x00000023); + } else { + freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1); + if (freq == 0) + return -ERANGE; + + clk_mask(hwsq, spll[0], 0xc03f0100, + 0x80000000 | (P1 << 19) | (P1 << 16)); + clk_mask(hwsq, spll[1], 0x0000ffff, (N << 8) | M); + clk_mask(hwsq, mast, 0x00100033, 0x00000033); + } + + /* restore normal operation */ + clk_setf(hwsq, 0x10, 0x01); /* enable fb */ + clk_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */ + clk_wr32(hwsq, fifo, 0x00000000); /* un-block fifo */ + return 0; +} + +static int +nv50_clock_prog(struct nouveau_clock *clk) +{ + struct nv50_clock_priv *priv = (void *)clk; + return clk_exec(&priv->hwsq, true); +} + +static void +nv50_clock_tidy(struct nouveau_clock *clk) +{ + struct nv50_clock_priv *priv = (void *)clk; + clk_exec(&priv->hwsq, false); +} + +int nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + struct nv50_clock_oclass *pclass = (void *)oclass; struct nv50_clock_priv *priv; int ret; - ret = nouveau_clock_create(parent, engine, oclass, &priv); + ret = nouveau_clock_create(parent, engine, oclass, pclass->domains, + false, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.pll_calc = nv04_clock_pll_calc; + priv->hwsq.r_fifo = hwsq_reg(0x002504); + priv->hwsq.r_spll[0] = hwsq_reg(0x004020); + priv->hwsq.r_spll[1] = hwsq_reg(0x004024); + priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028); + priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c); + switch (nv_device(priv)->chipset) { + case 0x92: + case 0x94: + case 0x96: + priv->hwsq.r_divs = hwsq_reg(0x004800); + break; + default: + priv->hwsq.r_divs = hwsq_reg(0x004700); + break; + } + priv->hwsq.r_mast = hwsq_reg(0x00c040); + + priv->base.read = nv50_clock_read; + priv->base.calc = nv50_clock_calc; + priv->base.prog = nv50_clock_prog; + priv->base.tidy = nv50_clock_tidy; return 0; } -struct nouveau_oclass -nv50_clock_oclass = { - .handle = NV_SUBDEV(CLOCK, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { +static struct nouveau_clocks +nv50_domains[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_max } +}; + +struct nouveau_oclass * +nv50_clock_oclass = &(struct nv50_clock_oclass) { + .base.handle = NV_SUBDEV(CLOCK, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_clock_ctor, .dtor = _nouveau_clock_dtor, .init = _nouveau_clock_init, .fini = _nouveau_clock_fini, }, -}; + .domains = nv50_domains, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h new file mode 100644 index 00000000000..f10917d789e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h @@ -0,0 +1,31 @@ +#ifndef __NVKM_CLK_NV50_H__ +#define __NVKM_CLK_NV50_H__ + +#include <subdev/bus.h> +#include <subdev/bus/hwsq.h> +#include <subdev/clock.h> + +struct nv50_clock_hwsq { + struct hwsq base; + struct hwsq_reg r_fifo; + struct hwsq_reg r_spll[2]; + struct hwsq_reg r_nvpll[2]; + struct hwsq_reg r_divs; + struct hwsq_reg r_mast; +}; + +struct nv50_clock_priv { + struct nouveau_clock base; + struct nv50_clock_hwsq hwsq; +}; + +int nv50_clock_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); + +struct nv50_clock_oclass { + struct nouveau_oclass base; + struct nouveau_clocks *domains; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c new file mode 100644 index 00000000000..b0b7c1437f1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c @@ -0,0 +1,48 @@ +/* + * 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 "nv50.h" + +static struct nouveau_clocks +nv84_domains[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0xff }, + { nv_clk_src_max } +}; + +struct nouveau_oclass * +nv84_clock_oclass = &(struct nv50_clock_oclass) { + .base.handle = NV_SUBDEV(CLOCK, 0x84), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, + .domains = nv84_domains, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index f074cd20bc9..9fb58354a80 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -22,33 +22,277 @@ * Authors: Ben Skeggs */ -#include <subdev/clock.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> +#include <subdev/timer.h> #include "pll.h" +#include "nva3.h" + struct nva3_clock_priv { struct nouveau_clock base; + struct nva3_clock_info eng[nv_clk_src_max]; }; +static u32 read_clk(struct nva3_clock_priv *, int, bool); +static u32 read_pll(struct nva3_clock_priv *, int, u32); + +static u32 +read_vco(struct nva3_clock_priv *priv, int clk) +{ + u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + if ((sctl & 0x00000030) != 0x00000030) + return read_pll(priv, 0x41, 0x00e820); + return read_pll(priv, 0x42, 0x00e8a0); +} + +static u32 +read_clk(struct nva3_clock_priv *priv, int clk, bool ignore_en) +{ + u32 sctl, sdiv, sclk; + + /* refclk for the 0xe8xx plls is a fixed frequency */ + if (clk >= 0x40) { + if (nv_device(priv)->chipset == 0xaf) { + /* no joke.. seriously.. sigh.. */ + return nv_rd32(priv, 0x00471c) * 1000; + } + + return nv_device(priv)->crystal; + } + + sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + if (!ignore_en && !(sctl & 0x00000100)) + return 0; + + switch (sctl & 0x00003000) { + case 0x00000000: + return nv_device(priv)->crystal; + case 0x00002000: + if (sctl & 0x00000040) + return 108000; + return 100000; + case 0x00003000: + sclk = read_vco(priv, clk); + sdiv = ((sctl & 0x003f0000) >> 16) + 2; + return (sclk * 2) / sdiv; + default: + return 0; + } +} + +static u32 +read_pll(struct nva3_clock_priv *priv, int clk, u32 pll) +{ + u32 ctrl = nv_rd32(priv, pll + 0); + u32 sclk = 0, P = 1, N = 1, M = 1; + + if (!(ctrl & 0x00000008)) { + if (ctrl & 0x00000001) { + u32 coef = nv_rd32(priv, pll + 4); + M = (coef & 0x000000ff) >> 0; + N = (coef & 0x0000ff00) >> 8; + P = (coef & 0x003f0000) >> 16; + + /* no post-divider on these.. */ + if ((pll & 0x00ff00) == 0x00e800) + P = 1; + + sclk = read_clk(priv, 0x00 + clk, false); + } + } else { + sclk = read_clk(priv, 0x10 + clk, false); + } + + if (M * P) + return sclk * N / (M * P); + return 0; +} + +static int +nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) +{ + struct nva3_clock_priv *priv = (void *)clk; + + switch (src) { + case nv_clk_src_crystal: + return nv_device(priv)->crystal; + case nv_clk_src_href: + return 100000; + case nv_clk_src_core: + return read_pll(priv, 0x00, 0x4200); + case nv_clk_src_shader: + return read_pll(priv, 0x01, 0x4220); + case nv_clk_src_mem: + return read_pll(priv, 0x02, 0x4000); + case nv_clk_src_disp: + return read_clk(priv, 0x20, false); + case nv_clk_src_vdec: + return read_clk(priv, 0x21, false); + case nv_clk_src_daemon: + return read_clk(priv, 0x25, false); + default: + nv_error(clk, "invalid clock source %d\n", src); + return -EINVAL; + } +} + int -nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, - int clk, struct nouveau_pll_vals *pv) +nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz, + struct nva3_clock_info *info) { - int ret, N, M, P; + 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; + + info->pll = 0; + info->clk = 0; + + switch (khz) { + case 27000: + info->clk = 0x00000100; + return khz; + case 100000: + info->clk = 0x00002100; + return khz; + case 108000: + info->clk = 0x00002140; + 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 + * and the VBIOS on my NVA8 seem to prefer using the PLL + * for 810MHz - is there a good reason? + */ + if (sdiv > 4) { + oclk = (sclk * 2) / sdiv; + diff = khz - oclk; + if (!pll || (diff >= -2000 && diff < 3000)) { + info->clk = (((sdiv - 2) << 16) | 0x00003100); + return oclk; + } + } + + if (!pll) + return -ERANGE; + break; + } - ret = nva3_pll_calc(nv_subdev(clock), info, clk, &N, NULL, &M, &P); + ret = nvbios_pll_parse(bios, pll, &limits); + if (ret) + return ret; + + limits.refclk = read_clk(priv, clk - 0x10, true); + if (!limits.refclk) + return -EINVAL; - if (ret > 0) { - pv->refclk = info->refclk; - pv->N1 = N; - pv->M1 = M; - pv->log2P = P; + 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; } + + return ret ? ret : -ERANGE; +} + +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], + &priv->eng[idx]); + if (ret >= 0) + return 0; return ret; } +static void +prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx) +{ + struct nva3_clock_info *info = &priv->eng[idx]; + const u32 src0 = 0x004120 + (clk * 4); + const u32 src1 = 0x004160 + (clk * 4); + const u32 ctrl = pll + 0; + const u32 coef = pll + 4; + + if (info->pll) { + nv_mask(priv, src0, 0x00000101, 0x00000101); + nv_wr32(priv, coef, info->pll); + nv_mask(priv, ctrl, 0x00000015, 0x00000015); + nv_mask(priv, ctrl, 0x00000010, 0x00000000); + nv_wait(priv, ctrl, 0x00020000, 0x00020000); + nv_mask(priv, ctrl, 0x00000010, 0x00000010); + nv_mask(priv, ctrl, 0x00000008, 0x00000000); + nv_mask(priv, src1, 0x00000100, 0x00000000); + nv_mask(priv, src1, 0x00000001, 0x00000000); + } 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); + } +} + +static void +prog_clk(struct nva3_clock_priv *priv, int clk, int idx) +{ + struct nva3_clock_info *info = &priv->eng[idx]; + nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk); +} + +static int +nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) +{ + struct nva3_clock_priv *priv = (void *)clk; + 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))) + return ret; + + return 0; +} + +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); + 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; +} + +static void +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_max } +}; static int nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -58,12 +302,16 @@ 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, &priv); + ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, false, + &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.pll_calc = nva3_clock_pll_calc; + priv->base.read = nva3_clock_read; + priv->base.calc = nva3_clock_calc; + priv->base.prog = nva3_clock_prog; + priv->base.tidy = nva3_clock_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h new file mode 100644 index 00000000000..6229a509b42 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h @@ -0,0 +1,14 @@ +#ifndef __NVKM_CLK_NVA3_H__ +#define __NVKM_CLK_NVA3_H__ + +#include <subdev/clock.h> + +struct nva3_clock_info { + u32 clk; + u32 pll; +}; + +int nva3_clock_info(struct nouveau_clock *, int, u32, u32, + struct nva3_clock_info *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c new file mode 100644 index 00000000000..6a65fc9e966 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c @@ -0,0 +1,446 @@ +/* + * 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 <engine/fifo.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> +#include <subdev/timer.h> +#include <subdev/clock.h> + +#include "pll.h" + +struct nvaa_clock_priv { + struct nouveau_clock base; + enum nv_clk_src csrc, ssrc, vsrc; + u32 cctrl, sctrl; + u32 ccoef, scoef; + u32 cpost, spost; + u32 vdiv; +}; + +static u32 +read_div(struct nouveau_clock *clk) +{ + return nv_rd32(clk, 0x004600); +} + +static u32 +read_pll(struct nouveau_clock *clk, u32 base) +{ + u32 ctrl = nv_rd32(clk, base + 0); + u32 coef = nv_rd32(clk, base + 4); + u32 ref = clk->read(clk, nv_clk_src_href); + u32 post_div = 0; + u32 clock = 0; + int N1, M1; + + switch (base){ + case 0x4020: + post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16); + break; + case 0x4028: + post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16; + break; + default: + break; + } + + N1 = (coef & 0x0000ff00) >> 8; + M1 = (coef & 0x000000ff); + if ((ctrl & 0x80000000) && M1) { + clock = ref * N1 / M1; + clock = clock / post_div; + } + + return clock; +} + +static int +nvaa_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) +{ + struct nvaa_clock_priv *priv = (void *)clk; + u32 mast = nv_rd32(clk, 0x00c054); + u32 P = 0; + + switch (src) { + case nv_clk_src_crystal: + return nv_device(priv)->crystal; + case nv_clk_src_href: + return 100000; /* PCIE reference clock */ + case nv_clk_src_hclkm4: + return clk->read(clk, nv_clk_src_href) * 4; + case nv_clk_src_hclkm2d3: + return clk->read(clk, nv_clk_src_href) * 2 / 3; + case nv_clk_src_host: + switch (mast & 0x000c0000) { + case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3); + case 0x00040000: break; + case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4); + case 0x000c0000: return clk->read(clk, nv_clk_src_cclk); + } + break; + case nv_clk_src_core: + P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; + + switch (mast & 0x00000003) { + case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000001: return 0; + case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P; + case 0x00000003: return read_pll(clk, 0x004028) >> P; + } + break; + case nv_clk_src_cclk: + if ((mast & 0x03000000) != 0x03000000) + return clk->read(clk, nv_clk_src_core); + + if ((mast & 0x00000200) == 0x00000000) + return clk->read(clk, nv_clk_src_core); + + switch (mast & 0x00000c00) { + case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4); + case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3); + default: return 0; + } + case nv_clk_src_shader: + P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; + switch (mast & 0x00000030) { + case 0x00000000: + if (mast & 0x00000040) + return clk->read(clk, nv_clk_src_href) >> P; + return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000010: break; + case 0x00000020: return read_pll(clk, 0x004028) >> P; + case 0x00000030: return read_pll(clk, 0x004020) >> P; + } + break; + case nv_clk_src_mem: + return 0; + break; + case nv_clk_src_vdec: + P = (read_div(clk) & 0x00000700) >> 8; + + switch (mast & 0x00400000) { + case 0x00400000: + return clk->read(clk, nv_clk_src_core) >> P; + break; + default: + return 500000 >> P; + break; + } + break; + default: + break; + } + + nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + return 0; +} + +static u32 +calc_pll(struct nvaa_clock_priv *priv, u32 reg, + u32 clock, int *N, int *M, int *P) +{ + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll pll; + struct nouveau_clock *clk = &priv->base; + int ret; + + ret = nvbios_pll_parse(bios, reg, &pll); + if (ret) + return 0; + + pll.vco2.max_freq = 0; + pll.refclk = clk->read(clk, nv_clk_src_href); + if (!pll.refclk) + return 0; + + return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P); +} + +static inline u32 +calc_P(u32 src, u32 target, int *div) +{ + u32 clk0 = src, clk1 = src; + for (*div = 0; *div <= 7; (*div)++) { + if (clk0 <= target) { + clk1 = clk0 << (*div ? 1 : 0); + break; + } + clk0 >>= 1; + } + + if (target - clk0 <= clk1 - target) + return clk0; + (*div)--; + return clk1; +} + +static int +nvaa_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) +{ + struct nvaa_clock_priv *priv = (void *)clk; + const int shader = cstate->domain[nv_clk_src_shader]; + const int core = cstate->domain[nv_clk_src_core]; + const int vdec = cstate->domain[nv_clk_src_vdec]; + u32 out = 0, clock = 0; + int N, M, P1, P2 = 0; + int divs = 0; + + /* cclk: find suitable source, disable PLL if we can */ + if (core < clk->read(clk, nv_clk_src_hclkm4)) + out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs); + + /* Calculate clock * 2, so shader clock can use it too */ + clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1); + + if (abs(core - out) <= + abs(core - (clock >> 1))) { + priv->csrc = nv_clk_src_hclkm4; + priv->cctrl = divs << 16; + } else { + /* NVCTRL is actually used _after_ NVPOST, and after what we + * call NVPLL. To make matters worse, NVPOST is an integer + * divider instead of a right-shift number. */ + if(P1 > 2) { + P2 = P1 - 2; + P1 = 2; + } + + priv->csrc = nv_clk_src_core; + priv->ccoef = (N << 8) | M; + + priv->cctrl = (P2 + 1) << 16; + priv->cpost = (1 << P1) << 16; + } + + /* sclk: nvpll + divisor, href or spll */ + out = 0; + if (shader == clk->read(clk, nv_clk_src_href)) { + priv->ssrc = nv_clk_src_href; + } else { + clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1); + if (priv->csrc == nv_clk_src_core) { + out = calc_P((core << 1), shader, &divs); + } + + if (abs(shader - out) <= + abs(shader - clock) && + (divs + P2) <= 7) { + priv->ssrc = nv_clk_src_core; + priv->sctrl = (divs + P2) << 16; + } else { + priv->ssrc = nv_clk_src_shader; + priv->scoef = (N << 8) | M; + priv->sctrl = P1 << 16; + } + } + + /* vclk */ + out = calc_P(core, vdec, &divs); + clock = calc_P(500000, vdec, &P1); + if(abs(vdec - out) <= + abs(vdec - clock)) { + priv->vsrc = nv_clk_src_cclk; + priv->vdiv = divs << 16; + } else { + priv->vsrc = nv_clk_src_vdec; + priv->vdiv = P1 << 16; + } + + /* Print strategy! */ + nv_debug(priv, "nvpll: %08x %08x %08x\n", + priv->ccoef, priv->cpost, priv->cctrl); + nv_debug(priv, " spll: %08x %08x %08x\n", + priv->scoef, priv->spost, priv->sctrl); + nv_debug(priv, " vdiv: %08x\n", priv->vdiv); + if (priv->csrc == nv_clk_src_hclkm4) + nv_debug(priv, "core: hrefm4\n"); + else + nv_debug(priv, "core: nvpll\n"); + + if (priv->ssrc == nv_clk_src_hclkm4) + nv_debug(priv, "shader: hrefm4\n"); + else if (priv->ssrc == nv_clk_src_core) + nv_debug(priv, "shader: nvpll\n"); + else + nv_debug(priv, "shader: spll\n"); + + if (priv->vsrc == nv_clk_src_hclkm4) + nv_debug(priv, "vdec: 500MHz\n"); + else + nv_debug(priv, "vdec: core\n"); + + return 0; +} + +static int +nvaa_clock_prog(struct nouveau_clock *clk) +{ + struct nvaa_clock_priv *priv = (void *)clk; + struct nouveau_fifo *pfifo = nouveau_fifo(clk); + 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); + + if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) + goto resume; + if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) + goto resume; + + /* First switch to safe clocks: href */ + mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640); + mast &= ~0x00400e73; + mast |= 0x03000000; + + switch (priv->csrc) { + case nv_clk_src_hclkm4: + nv_mask(clk, 0x4028, 0x00070000, priv->cctrl); + mast |= 0x00000002; + break; + case nv_clk_src_core: + nv_wr32(clk, 0x402c, priv->ccoef); + nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl); + nv_wr32(clk, 0x4040, priv->cpost); + pllmask |= (0x3 << 8); + mast |= 0x00000003; + break; + default: + nv_warn(priv,"Reclocking failed: unknown core clock\n"); + goto resume; + } + + switch (priv->ssrc) { + case nv_clk_src_href: + nv_mask(clk, 0x4020, 0x00070000, 0x00000000); + /* mast |= 0x00000000; */ + break; + case nv_clk_src_core: + nv_mask(clk, 0x4020, 0x00070000, priv->sctrl); + mast |= 0x00000020; + break; + case nv_clk_src_shader: + nv_wr32(clk, 0x4024, priv->scoef); + nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl); + nv_wr32(clk, 0x4070, priv->spost); + pllmask |= (0x3 << 12); + mast |= 0x00000030; + break; + default: + nv_warn(priv,"Reclocking failed: unknown sclk clock\n"); + goto resume; + } + + if (!nv_wait(clk, 0x004080, pllmask, pllmask)) { + nv_warn(priv,"Reclocking failed: unstable PLLs\n"); + goto resume; + } + + switch (priv->vsrc) { + case nv_clk_src_cclk: + mast |= 0x00400000; + default: + nv_wr32(clk, 0x4600, priv->vdiv); + } + + 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); + nv_mask(clk, 0x4028, 0x80000000, 0x00000000); + } + + if (priv->ssrc != nv_clk_src_shader) { + nv_wr32(clk, 0x4070, 0x00000000); + nv_mask(clk, 0x4020, 0x80000000, 0x00000000); + } + + return ret; +} + +static void +nvaa_clock_tidy(struct nouveau_clock *clk) +{ +} + +static struct nouveau_clocks +nvaa_domains[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, + { nv_clk_src_max } +}; + +static int +nvaa_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nvaa_clock_priv *priv; + int ret; + + ret = nouveau_clock_create(parent, engine, oclass, nvaa_domains, true, + &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.read = nvaa_clock_read; + priv->base.calc = nvaa_clock_calc; + priv->base.prog = nvaa_clock_prog; + priv->base.tidy = nvaa_clock_tidy; + return 0; +} + +struct nouveau_oclass * +nvaa_clock_oclass = &(struct nouveau_oclass) { + .handle = NV_SUBDEV(CLOCK, 0xaa), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvaa_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index 439d81c2613..dbf8517f54d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -25,11 +25,408 @@ #include <subdev/clock.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> +#include <subdev/timer.h> #include "pll.h" +struct nvc0_clock_info { + u32 freq; + u32 ssel; + u32 mdiv; + u32 dsrc; + u32 ddiv; + u32 coef; +}; + struct nvc0_clock_priv { struct nouveau_clock base; + struct nvc0_clock_info eng[16]; +}; + +static u32 read_div(struct nvc0_clock_priv *, int, u32, u32); + +static u32 +read_vco(struct nvc0_clock_priv *priv, u32 dsrc) +{ + struct nouveau_clock *clk = &priv->base; + u32 ssrc = nv_rd32(priv, dsrc); + if (!(ssrc & 0x00000100)) + return clk->read(clk, nv_clk_src_sppll0); + return clk->read(clk, nv_clk_src_sppll1); +} + +static u32 +read_pll(struct nvc0_clock_priv *priv, u32 pll) +{ + struct nouveau_clock *clk = &priv->base; + u32 ctrl = nv_rd32(priv, pll + 0x00); + u32 coef = nv_rd32(priv, pll + 0x04); + u32 P = (coef & 0x003f0000) >> 16; + u32 N = (coef & 0x0000ff00) >> 8; + u32 M = (coef & 0x000000ff) >> 0; + u32 sclk; + + if (!(ctrl & 0x00000001)) + return 0; + + switch (pll) { + case 0x00e800: + case 0x00e820: + sclk = nv_device(priv)->crystal; + P = 1; + break; + case 0x132000: + sclk = clk->read(clk, nv_clk_src_mpllsrc); + break; + case 0x132020: + sclk = clk->read(clk, nv_clk_src_mpllsrcref); + break; + case 0x137000: + case 0x137020: + case 0x137040: + case 0x1370e0: + sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + break; + default: + return 0; + } + + return sclk * N / M / P; +} + +static u32 +read_div(struct nvc0_clock_priv *priv, int doff, u32 dsrc, u32 dctl) +{ + u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); + u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + + switch (ssrc & 0x00000003) { + case 0: + if ((ssrc & 0x00030000) != 0x00030000) + return nv_device(priv)->crystal; + return 108000; + case 2: + return 100000; + case 3: + if (sctl & 0x80000000) { + u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sdiv = (sctl & 0x0000003f) + 2; + return (sclk * 2) / sdiv; + } + + return read_vco(priv, dsrc + (doff * 4)); + default: + return 0; + } +} + +static u32 +read_clk(struct nvc0_clock_priv *priv, int clk) +{ + u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); + u32 ssel = nv_rd32(priv, 0x137100); + u32 sclk, sdiv; + + if (ssel & (1 << clk)) { + if (clk < 7) + sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + else + sclk = read_pll(priv, 0x1370e0); + sdiv = ((sctl & 0x00003f00) >> 8) + 2; + } else { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sdiv = ((sctl & 0x0000003f) >> 0) + 2; + } + + if (sctl & 0x80000000) + return (sclk * 2) / sdiv; + + return sclk; +} + +static int +nvc0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) +{ + struct nouveau_device *device = nv_device(clk); + struct nvc0_clock_priv *priv = (void *)clk; + + switch (src) { + case nv_clk_src_crystal: + return device->crystal; + case nv_clk_src_href: + return 100000; + case nv_clk_src_sppll0: + return read_pll(priv, 0x00e800); + case nv_clk_src_sppll1: + return read_pll(priv, 0x00e820); + + case nv_clk_src_mpllsrcref: + return read_div(priv, 0, 0x137320, 0x137330); + case nv_clk_src_mpllsrc: + return read_pll(priv, 0x132020); + case nv_clk_src_mpll: + return read_pll(priv, 0x132000); + case nv_clk_src_mdiv: + return read_div(priv, 0, 0x137300, 0x137310); + case nv_clk_src_mem: + if (nv_rd32(priv, 0x1373f0) & 0x00000002) + return clk->read(clk, nv_clk_src_mpll); + return clk->read(clk, nv_clk_src_mdiv); + + case nv_clk_src_gpc: + return read_clk(priv, 0x00); + case nv_clk_src_rop: + return read_clk(priv, 0x01); + case nv_clk_src_hubk07: + return read_clk(priv, 0x02); + case nv_clk_src_hubk06: + return read_clk(priv, 0x07); + case nv_clk_src_hubk01: + return read_clk(priv, 0x08); + case nv_clk_src_copy: + return read_clk(priv, 0x09); + case nv_clk_src_daemon: + return read_clk(priv, 0x0c); + case nv_clk_src_vdec: + return read_clk(priv, 0x0e); + default: + nv_error(clk, "invalid clock source %d\n", src); + return -EINVAL; + } +} + +static u32 +calc_div(struct nvc0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +{ + u32 div = min((ref * 2) / freq, (u32)65); + if (div < 2) + div = 2; + + *ddiv = div - 2; + return (ref * 2) / div; +} + +static u32 +calc_src(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +{ + u32 sclk; + + /* use one of the fixed frequencies if possible */ + *ddiv = 0x00000000; + switch (freq) { + case 27000: + case 108000: + *dsrc = 0x00000000; + if (freq == 108000) + *dsrc |= 0x00030000; + return freq; + case 100000: + *dsrc = 0x00000002; + return freq; + default: + *dsrc = 0x00000003; + break; + } + + /* otherwise, calculate the closest divider */ + sclk = read_vco(priv, 0x137160 + (clk * 4)); + if (clk < 7) + sclk = calc_div(priv, clk, sclk, freq, ddiv); + return sclk; +} + +static u32 +calc_pll(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *coef) +{ + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll limits; + int N, M, P, ret; + + ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + if (ret) + return 0; + + limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + if (!limits.refclk) + return 0; + + ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + if (ret <= 0) + return 0; + + *coef = (P << 16) | (N << 8) | M; + return ret; +} + +static int +calc_clk(struct nvc0_clock_priv *priv, + struct nouveau_cstate *cstate, int clk, int dom) +{ + struct nvc0_clock_info *info = &priv->eng[clk]; + u32 freq = cstate->domain[dom]; + u32 src0, div0, div1D, div1P = 0; + u32 clk0, clk1 = 0; + + /* invalid clock domain */ + if (!freq) + return 0; + + /* first possible path, using only dividers */ + clk0 = calc_src(priv, clk, freq, &src0, &div0); + clk0 = calc_div(priv, clk, clk0, freq, &div1D); + + /* see if we can get any closer using PLLs */ + if (clk0 != freq && (0x00004387 & (1 << clk))) { + if (clk <= 7) + clk1 = calc_pll(priv, clk, freq, &info->coef); + else + clk1 = cstate->domain[nv_clk_src_hubk06]; + clk1 = calc_div(priv, clk, clk1, freq, &div1P); + } + + /* select the method which gets closest to target freq */ + if (abs((int)freq - clk0) <= abs((int)freq - clk1)) { + info->dsrc = src0; + if (div0) { + info->ddiv |= 0x80000000; + info->ddiv |= div0 << 8; + info->ddiv |= div0; + } + if (div1D) { + info->mdiv |= 0x80000000; + info->mdiv |= div1D; + } + info->ssel = info->coef = 0; + info->freq = clk0; + } else { + if (div1P) { + info->mdiv |= 0x80000000; + info->mdiv |= div1P << 8; + } + info->ssel = (1 << clk); + info->freq = clk1; + } + + return 0; +} + +static int +nvc0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) +{ + struct nvc0_clock_priv *priv = (void *)clk; + int ret; + + if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) || + (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + return ret; + + return 0; +} + +static void +nvc0_clock_prog_0(struct nvc0_clock_priv *priv, int clk) +{ + struct nvc0_clock_info *info = &priv->eng[clk]; + if (clk < 7 && !info->ssel) { + nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); + nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + } +} + +static void +nvc0_clock_prog_1(struct nvc0_clock_priv *priv, int clk) +{ + nv_mask(priv, 0x137100, (1 << clk), 0x00000000); + nv_wait(priv, 0x137100, (1 << clk), 0x00000000); +} + +static void +nvc0_clock_prog_2(struct nvc0_clock_priv *priv, int clk) +{ + struct nvc0_clock_info *info = &priv->eng[clk]; + const u32 addr = 0x137000 + (clk * 0x20); + if (clk <= 7) { + nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + if (info->coef) { + nv_wr32(priv, addr + 0x04, info->coef); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); + nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); + nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + } + } +} + +static void +nvc0_clock_prog_3(struct nvc0_clock_priv *priv, int clk) +{ + struct nvc0_clock_info *info = &priv->eng[clk]; + if (info->ssel) { + nv_mask(priv, 0x137100, (1 << clk), info->ssel); + nv_wait(priv, 0x137100, (1 << clk), info->ssel); + } +} + +static void +nvc0_clock_prog_4(struct nvc0_clock_priv *priv, int clk) +{ + struct nvc0_clock_info *info = &priv->eng[clk]; + nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); +} + +static int +nvc0_clock_prog(struct nouveau_clock *clk) +{ + struct nvc0_clock_priv *priv = (void *)clk; + struct { + void (*exec)(struct nvc0_clock_priv *, int); + } stage[] = { + { nvc0_clock_prog_0 }, /* div programming */ + { nvc0_clock_prog_1 }, /* select div mode */ + { nvc0_clock_prog_2 }, /* (maybe) program pll */ + { nvc0_clock_prog_3 }, /* (maybe) select pll mode */ + { nvc0_clock_prog_4 }, /* final divider */ + }; + int i, j; + + for (i = 0; i < ARRAY_SIZE(stage); i++) { + for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { + if (!priv->eng[j].freq) + continue; + stage[i].exec(priv, j); + } + } + + return 0; +} + +static void +nvc0_clock_tidy(struct nouveau_clock *clk) +{ + struct nvc0_clock_priv *priv = (void *)clk; + memset(priv->eng, 0x00, sizeof(priv->eng)); +} + +static struct nouveau_clocks +nvc0_domain[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_hubk06 , 0x00 }, + { nv_clk_src_hubk01 , 0x01 }, + { nv_clk_src_copy , 0x02 }, + { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, + { nv_clk_src_rop , 0x04 }, + { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x0a }, + { nv_clk_src_hubk07 , 0x0b }, + { nv_clk_src_max } }; static int @@ -40,12 +437,16 @@ 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, &priv); + ret = nouveau_clock_create(parent, engine, oclass, nvc0_domain, false, + &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.pll_calc = nva3_clock_pll_calc; + priv->base.read = nvc0_clock_read; + priv->base.calc = nvc0_clock_calc; + priv->base.prog = nvc0_clock_prog; + priv->base.tidy = nvc0_clock_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c new file mode 100644 index 00000000000..0e62a324014 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c @@ -0,0 +1,500 @@ +/* + * 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/clock.h> +#include <subdev/timer.h> +#include <subdev/bios.h> +#include <subdev/bios/pll.h> + +#include "pll.h" + +struct nve0_clock_info { + u32 freq; + u32 ssel; + u32 mdiv; + u32 dsrc; + u32 ddiv; + u32 coef; +}; + +struct nve0_clock_priv { + struct nouveau_clock base; + struct nve0_clock_info eng[16]; +}; + +static u32 read_div(struct nve0_clock_priv *, int, u32, u32); +static u32 read_pll(struct nve0_clock_priv *, u32); + +static u32 +read_vco(struct nve0_clock_priv *priv, u32 dsrc) +{ + u32 ssrc = nv_rd32(priv, dsrc); + if (!(ssrc & 0x00000100)) + return read_pll(priv, 0x00e800); + return read_pll(priv, 0x00e820); +} + +static u32 +read_pll(struct nve0_clock_priv *priv, u32 pll) +{ + u32 ctrl = nv_rd32(priv, pll + 0x00); + u32 coef = nv_rd32(priv, pll + 0x04); + u32 P = (coef & 0x003f0000) >> 16; + u32 N = (coef & 0x0000ff00) >> 8; + u32 M = (coef & 0x000000ff) >> 0; + u32 sclk; + u16 fN = 0xf000; + + if (!(ctrl & 0x00000001)) + return 0; + + switch (pll) { + case 0x00e800: + case 0x00e820: + sclk = nv_device(priv)->crystal; + P = 1; + break; + case 0x132000: + sclk = read_pll(priv, 0x132020); + P = (coef & 0x10000000) ? 2 : 1; + break; + case 0x132020: + sclk = read_div(priv, 0, 0x137320, 0x137330); + fN = nv_rd32(priv, pll + 0x10) >> 16; + break; + case 0x137000: + case 0x137020: + case 0x137040: + case 0x1370e0: + sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + break; + default: + return 0; + } + + if (P == 0) + P = 1; + + sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13); + return sclk / (M * P); +} + +static u32 +read_div(struct nve0_clock_priv *priv, int doff, u32 dsrc, u32 dctl) +{ + u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); + u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + + switch (ssrc & 0x00000003) { + case 0: + if ((ssrc & 0x00030000) != 0x00030000) + return nv_device(priv)->crystal; + return 108000; + case 2: + return 100000; + case 3: + if (sctl & 0x80000000) { + u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sdiv = (sctl & 0x0000003f) + 2; + return (sclk * 2) / sdiv; + } + + return read_vco(priv, dsrc + (doff * 4)); + default: + return 0; + } +} + +static u32 +read_mem(struct nve0_clock_priv *priv) +{ + switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) { + case 1: return read_pll(priv, 0x132020); + case 2: return read_pll(priv, 0x132000); + default: + return 0; + } +} + +static u32 +read_clk(struct nve0_clock_priv *priv, int clk) +{ + u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); + u32 sclk, sdiv; + + if (clk < 7) { + u32 ssel = nv_rd32(priv, 0x137100); + if (ssel & (1 << clk)) { + sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + sdiv = 1; + } else { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sdiv = 0; + } + } else { + u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04)); + if ((ssrc & 0x00000003) == 0x00000003) { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + if (ssrc & 0x00000100) { + if (ssrc & 0x40000000) + sclk = read_pll(priv, 0x1370e0); + sdiv = 1; + } else { + sdiv = 0; + } + } else { + sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sdiv = 0; + } + } + + if (sctl & 0x80000000) { + if (sdiv) + sdiv = ((sctl & 0x00003f00) >> 8) + 2; + else + sdiv = ((sctl & 0x0000003f) >> 0) + 2; + return (sclk * 2) / sdiv; + } + + return sclk; +} + +static int +nve0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) +{ + struct nouveau_device *device = nv_device(clk); + struct nve0_clock_priv *priv = (void *)clk; + + switch (src) { + case nv_clk_src_crystal: + return device->crystal; + case nv_clk_src_href: + return 100000; + case nv_clk_src_mem: + return read_mem(priv); + case nv_clk_src_gpc: + return read_clk(priv, 0x00); + case nv_clk_src_rop: + return read_clk(priv, 0x01); + case nv_clk_src_hubk07: + return read_clk(priv, 0x02); + case nv_clk_src_hubk06: + return read_clk(priv, 0x07); + case nv_clk_src_hubk01: + return read_clk(priv, 0x08); + case nv_clk_src_daemon: + return read_clk(priv, 0x0c); + case nv_clk_src_vdec: + return read_clk(priv, 0x0e); + default: + nv_error(clk, "invalid clock source %d\n", src); + return -EINVAL; + } +} + +static u32 +calc_div(struct nve0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +{ + u32 div = min((ref * 2) / freq, (u32)65); + if (div < 2) + div = 2; + + *ddiv = div - 2; + return (ref * 2) / div; +} + +static u32 +calc_src(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +{ + u32 sclk; + + /* use one of the fixed frequencies if possible */ + *ddiv = 0x00000000; + switch (freq) { + case 27000: + case 108000: + *dsrc = 0x00000000; + if (freq == 108000) + *dsrc |= 0x00030000; + return freq; + case 100000: + *dsrc = 0x00000002; + return freq; + default: + *dsrc = 0x00000003; + break; + } + + /* otherwise, calculate the closest divider */ + sclk = read_vco(priv, 0x137160 + (clk * 4)); + if (clk < 7) + sclk = calc_div(priv, clk, sclk, freq, ddiv); + return sclk; +} + +static u32 +calc_pll(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *coef) +{ + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_pll limits; + int N, M, P, ret; + + ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + if (ret) + return 0; + + limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + if (!limits.refclk) + return 0; + + ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + if (ret <= 0) + return 0; + + *coef = (P << 16) | (N << 8) | M; + return ret; +} + +static int +calc_clk(struct nve0_clock_priv *priv, + struct nouveau_cstate *cstate, int clk, int dom) +{ + struct nve0_clock_info *info = &priv->eng[clk]; + u32 freq = cstate->domain[dom]; + u32 src0, div0, div1D, div1P = 0; + u32 clk0, clk1 = 0; + + /* invalid clock domain */ + if (!freq) + return 0; + + /* first possible path, using only dividers */ + clk0 = calc_src(priv, clk, freq, &src0, &div0); + clk0 = calc_div(priv, clk, clk0, freq, &div1D); + + /* see if we can get any closer using PLLs */ + if (clk0 != freq && (0x0000ff87 & (1 << clk))) { + if (clk <= 7) + clk1 = calc_pll(priv, clk, freq, &info->coef); + else + clk1 = cstate->domain[nv_clk_src_hubk06]; + clk1 = calc_div(priv, clk, clk1, freq, &div1P); + } + + /* select the method which gets closest to target freq */ + if (abs((int)freq - clk0) <= abs((int)freq - clk1)) { + info->dsrc = src0; + if (div0) { + info->ddiv |= 0x80000000; + info->ddiv |= div0; + } + if (div1D) { + info->mdiv |= 0x80000000; + info->mdiv |= div1D; + } + info->ssel = 0; + info->freq = clk0; + } else { + if (div1P) { + info->mdiv |= 0x80000000; + info->mdiv |= div1P << 8; + } + info->ssel = (1 << clk); + info->dsrc = 0x40000100; + info->freq = clk1; + } + + return 0; +} + +static int +nve0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) +{ + struct nve0_clock_priv *priv = (void *)clk; + int ret; + + if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + return ret; + + return 0; +} + +static void +nve0_clock_prog_0(struct nve0_clock_priv *priv, int clk) +{ + struct nve0_clock_info *info = &priv->eng[clk]; + if (!info->ssel) { + nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv); + nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + } +} + +static void +nve0_clock_prog_1_0(struct nve0_clock_priv *priv, int clk) +{ + nv_mask(priv, 0x137100, (1 << clk), 0x00000000); + nv_wait(priv, 0x137100, (1 << clk), 0x00000000); +} + +static void +nve0_clock_prog_1_1(struct nve0_clock_priv *priv, int clk) +{ + nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000); +} + +static void +nve0_clock_prog_2(struct nve0_clock_priv *priv, int clk) +{ + struct nve0_clock_info *info = &priv->eng[clk]; + const u32 addr = 0x137000 + (clk * 0x20); + nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + if (info->coef) { + nv_wr32(priv, addr + 0x04, info->coef); + nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); + nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); + nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + } +} + +static void +nve0_clock_prog_3(struct nve0_clock_priv *priv, int clk) +{ + struct nve0_clock_info *info = &priv->eng[clk]; + if (info->ssel) + nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv); + else + nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv); +} + +static void +nve0_clock_prog_4_0(struct nve0_clock_priv *priv, int clk) +{ + struct nve0_clock_info *info = &priv->eng[clk]; + if (info->ssel) { + nv_mask(priv, 0x137100, (1 << clk), info->ssel); + nv_wait(priv, 0x137100, (1 << clk), info->ssel); + } +} + +static void +nve0_clock_prog_4_1(struct nve0_clock_priv *priv, int clk) +{ + struct nve0_clock_info *info = &priv->eng[clk]; + if (info->ssel) { + nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000); + nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100); + } +} + +static int +nve0_clock_prog(struct nouveau_clock *clk) +{ + struct nve0_clock_priv *priv = (void *)clk; + struct { + u32 mask; + void (*exec)(struct nve0_clock_priv *, int); + } stage[] = { + { 0x007f, nve0_clock_prog_0 }, /* div programming */ + { 0x007f, nve0_clock_prog_1_0 }, /* select div mode */ + { 0xff80, nve0_clock_prog_1_1 }, + { 0x00ff, nve0_clock_prog_2 }, /* (maybe) program pll */ + { 0xff80, nve0_clock_prog_3 }, /* final divider */ + { 0x007f, nve0_clock_prog_4_0 }, /* (maybe) select pll mode */ + { 0xff80, nve0_clock_prog_4_1 }, + }; + int i, j; + + for (i = 0; i < ARRAY_SIZE(stage); i++) { + for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { + if (!(stage[i].mask & (1 << j))) + continue; + if (!priv->eng[j].freq) + continue; + stage[i].exec(priv, j); + } + } + + return 0; +} + +static void +nve0_clock_tidy(struct nouveau_clock *clk) +{ + struct nve0_clock_priv *priv = (void *)clk; + memset(priv->eng, 0x00, sizeof(priv->eng)); +} + +static struct nouveau_clocks +nve0_domain[] = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, + { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_mem , 0x03, 0, "memory", 500 }, + { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_hubk01 , 0x05 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x07 }, + { nv_clk_src_max } +}; + +static int +nve0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nve0_clock_priv *priv; + int ret; + + ret = nouveau_clock_create(parent, engine, oclass, nve0_domain, true, + &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.read = nve0_clock_read; + priv->base.calc = nve0_clock_calc; + priv->base.prog = nve0_clock_prog; + priv->base.tidy = nve0_clock_tidy; + return 0; +} + +struct nouveau_oclass +nve0_clock_oclass = { + .handle = NV_SUBDEV(CLOCK, 0xe0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_clock_ctor, + .dtor = _nouveau_clock_dtor, + .init = _nouveau_clock_init, + .fini = _nouveau_clock_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c index cf1ed0dc9bc..b47d543ab2e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c @@ -38,7 +38,7 @@ getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - int cv = nouveau_bios(subdev)->version.chip; + struct nouveau_bios *bios = nouveau_bios(subdev); int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq; int minM = info->vco1.min_m, maxM = info->vco1.max_m; int minN = info->vco1.min_n, maxN = info->vco1.max_n; @@ -54,18 +54,21 @@ getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, /* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */ /* possibly correlated with introduction of 27MHz crystal */ - if (cv < 0x17 || cv == 0x1a || cv == 0x20) { - if (clk > 250000) - maxM = 6; - if (clk > 340000) - maxM = 2; - } else if (cv < 0x40) { - if (clk > 150000) - maxM = 6; - if (clk > 200000) - maxM = 4; - if (clk > 340000) - maxM = 2; + if (bios->version.major < 0x60) { + int cv = bios->version.chip; + if (cv < 0x17 || cv == 0x1a || cv == 0x20) { + if (clk > 250000) + maxM = 6; + if (clk > 340000) + maxM = 2; + } else if (cv < 0x40) { + if (clk > 150000) + maxM = 6; + if (clk > 200000) + maxM = 4; + if (clk > 340000) + maxM = 2; + } } P = 1 << maxP; @@ -227,10 +230,12 @@ nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq, { int ret; - if (!info->vco2.max_freq) { + if (!info->vco2.max_freq || !N2) { ret = getMNP_single(subdev, info, freq, N1, M1, P); - *N2 = 1; - *M2 = 1; + if (N2) { + *N2 = 1; + *M2 = 1; + } } else { ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c index 2fe1f712eef..8eca457c281 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c @@ -45,6 +45,7 @@ nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, lM = max(lM, (int)info->vco1.min_m); hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq; hM = min(hM, (int)info->vco1.max_m); + lM = min(lM, hM); for (M = lM; M <= hM; M++) { u32 tmp = freq * *P * M; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h b/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h new file mode 100644 index 00000000000..fb33f06ebd5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h @@ -0,0 +1,17 @@ +#ifndef __NVKM_CLK_SEQ_H__ +#define __NVKM_CLK_SEQ_H__ + +#include <subdev/bus.h> +#include <subdev/bus/hwsq.h> + +#define clk_init(s,p) hwsq_init(&(s)->base, (p)) +#define clk_exec(s,e) hwsq_exec(&(s)->base, (e)) +#define clk_have(s,r) ((s)->r_##r.addr != 0x000000) +#define clk_rd32(s,r) hwsq_rd32(&(s)->base, &(s)->r_##r) +#define clk_wr32(s,r,d) hwsq_wr32(&(s)->base, &(s)->r_##r, (d)) +#define clk_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d)) +#define clk_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d)) +#define clk_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d)) +#define clk_nsec(s,n) hwsq_nsec(&(s)->base, (n)) + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c index 79c81d3d9ba..239acfe876c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c @@ -24,9 +24,11 @@ #include <core/option.h> -#include <subdev/devinit.h> #include <subdev/bios.h> #include <subdev/bios/init.h> +#include <subdev/vga.h> + +#include "priv.h" int _nouveau_devinit_fini(struct nouveau_object *object, bool suspend) @@ -37,18 +39,41 @@ _nouveau_devinit_fini(struct nouveau_object *object, bool suspend) if (suspend) devinit->post = true; + /* unlock the extended vga crtc regs */ + nv_lockvgac(devinit, false); + return nouveau_subdev_fini(&devinit->base, suspend); } int _nouveau_devinit_init(struct nouveau_object *object) { + struct nouveau_devinit_impl *impl = (void *)object->oclass; struct nouveau_devinit *devinit = (void *)object; - int ret = nouveau_subdev_init(&devinit->base); + int ret; + + ret = nouveau_subdev_init(&devinit->base); + if (ret) + return ret; + + ret = nvbios_init(&devinit->base, devinit->post); if (ret) return ret; - return nvbios_init(&devinit->base, devinit->post); + if (impl->disable) + nv_device(devinit)->disable_mask |= impl->disable(devinit); + return 0; +} + +void +_nouveau_devinit_dtor(struct nouveau_object *object) +{ + struct nouveau_devinit *devinit = (void *)object; + + /* lock crtc regs */ + nv_lockvgac(devinit, true); + + nouveau_subdev_destroy(&devinit->base); } int @@ -57,6 +82,7 @@ nouveau_devinit_create_(struct nouveau_object *parent, struct nouveau_oclass *oclass, int size, void **pobject) { + struct nouveau_devinit_impl *impl = (void *)oclass; struct nouveau_device *device = nv_device(parent); struct nouveau_devinit *devinit; int ret; @@ -68,5 +94,8 @@ nouveau_devinit_create_(struct nouveau_object *parent, return ret; devinit->post = nouveau_boolopt(device->cfgopt, "NvForcePost", false); + devinit->meminit = impl->meminit; + devinit->pll_set = impl->pll_set; + devinit->mmio = impl->mmio; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h index 6b56a0f4cb4..4fe49cf4c99 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h @@ -24,6 +24,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 @@ -60,10 +62,10 @@ # define NV10_PFB_REFCTRL_VALID_1 (1 << 31) static inline struct io_mapping * -fbmem_init(struct pci_dev *pdev) +fbmem_init(struct nouveau_device *dev) { - return io_mapping_create_wc(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); + return io_mapping_create_wc(nv_device_resource_start(dev, 1), + nv_device_resource_len(dev, 1)); } static inline void diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c new file mode 100644 index 00000000000..c69bc7f54e3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c @@ -0,0 +1,56 @@ +/* + * 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 "nv50.h" + +static u64 +gm107_devinit_disable(struct nouveau_devinit *devinit) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r021c00 = nv_rd32(priv, 0x021c00); + u32 r021c04 = nv_rd32(priv, 0x021c04); + u64 disable = 0ULL; + + if (r021c00 & 0x00000001) + disable |= (1ULL << NVDEV_ENGINE_COPY0); + if (r021c00 & 0x00000004) + disable |= (1ULL << NVDEV_ENGINE_COPY2); + if (r021c04 & 0x00000001) + disable |= (1ULL << NVDEV_ENGINE_DISP); + + return disable; +} + +struct nouveau_oclass * +gm107_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x07), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_devinit_ctor, + .dtor = _nouveau_devinit_dtor, + .init = nv50_devinit_init, + .fini = _nouveau_devinit_fini, + }, + .pll_set = nvc0_devinit_pll_set, + .disable = gm107_devinit_disable, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c index b22357d9b82..052ad690b46 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c @@ -27,12 +27,7 @@ #include <subdev/vga.h> #include "fbmem.h" -#include "priv.h" - -struct nv04_devinit_priv { - struct nouveau_devinit base; - int owner; -}; +#include "nv04.h" static void nv04_devinit_meminit(struct nouveau_devinit *devinit) @@ -43,7 +38,7 @@ nv04_devinit_meminit(struct nouveau_devinit *devinit) int i; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; @@ -168,7 +163,8 @@ setPLL_single(struct nouveau_devinit *devinit, u32 reg, /* downclock -- write new NM first */ nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1); - if (chip_version < 0x17 && chip_version != 0x11) + if ((chip_version < 0x17 || chip_version == 0x1a) && + chip_version != 0x11) /* wait a bit on older chips */ msleep(64); nv_rd32(devinit, reg); @@ -392,17 +388,21 @@ int nv04_devinit_fini(struct nouveau_object *object, bool suspend) { struct nv04_devinit_priv *priv = (void *)object; + int ret; /* make i2c busses accessible */ nv_mask(priv, 0x000200, 0x00000001, 0x00000001); - /* unlock extended vga crtc regs, and unslave crtcs */ - nv_lockvgac(priv, false); + ret = nouveau_devinit_fini(&priv->base, suspend); + if (ret) + return ret; + + /* unslave crtcs */ if (priv->owner < 0) priv->owner = nv_rdvgaowner(priv); nv_wrvgaowner(priv, 0); - return nouveau_devinit_fini(&priv->base, suspend); + return 0; } int @@ -430,14 +430,13 @@ nv04_devinit_dtor(struct nouveau_object *object) { struct nv04_devinit_priv *priv = (void *)object; - /* restore vga owner saved at first init, and lock crtc regs */ + /* restore vga owner saved at first init */ nv_wrvgaowner(priv, priv->owner); - nv_lockvgac(priv, true); nouveau_devinit_destroy(&priv->base); } -static int +int nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -450,19 +449,19 @@ nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.meminit = nv04_devinit_meminit; - priv->base.pll_set = nv04_devinit_pll_set; priv->owner = -1; return 0; } -struct nouveau_oclass -nv04_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv04_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_devinit_ctor, .dtor = nv04_devinit_dtor, .init = nv04_devinit_init, .fini = nv04_devinit_fini, }, -}; + .meminit = nv04_devinit_meminit, + .pll_set = nv04_devinit_pll_set, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h new file mode 100644 index 00000000000..23470a57510 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h @@ -0,0 +1,23 @@ +#ifndef __NVKM_DEVINIT_NV04_H__ +#define __NVKM_DEVINIT_NV04_H__ + +#include "priv.h" + +struct nv04_devinit_priv { + struct nouveau_devinit base; + u8 owner; +}; + +int nv04_devinit_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nv04_devinit_dtor(struct nouveau_object *); +int nv04_devinit_init(struct nouveau_object *); +int nv04_devinit_fini(struct nouveau_object *, bool); +int nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32); + +void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); +void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); +void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c index b1912a8a894..4a19c10e517 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c @@ -29,12 +29,7 @@ #include <subdev/vga.h> #include "fbmem.h" -#include "priv.h" - -struct nv05_devinit_priv { - struct nouveau_devinit base; - u8 owner; -}; +#include "nv04.h" static void nv05_devinit_meminit(struct nouveau_devinit *devinit) @@ -49,7 +44,7 @@ nv05_devinit_meminit(struct nouveau_devinit *devinit) { 0x06, 0x00 }, { 0x00, 0x00 } }; - struct nv05_devinit_priv *priv = (void *)devinit; + struct nv04_devinit_priv *priv = (void *)devinit; struct nouveau_bios *bios = nouveau_bios(priv); struct io_mapping *fb; u32 patt = 0xdeadbeef; @@ -58,7 +53,7 @@ nv05_devinit_meminit(struct nouveau_devinit *devinit) int i, v; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; @@ -130,31 +125,15 @@ out: fbmem_fini(fb); } -static int -nv05_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv05_devinit_priv *priv; - int ret; - - ret = nouveau_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.meminit = nv05_devinit_meminit; - priv->base.pll_set = nv04_devinit_pll_set; - return 0; -} - -struct nouveau_oclass -nv05_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0x05), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv05_devinit_ctor, +struct nouveau_oclass * +nv05_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x05), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_devinit_ctor, .dtor = nv04_devinit_dtor, .init = nv04_devinit_init, .fini = nv04_devinit_fini, }, -}; + .meminit = nv05_devinit_meminit, + .pll_set = nv04_devinit_pll_set, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c index 463b08fa096..3b8d657da27 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c @@ -27,25 +27,26 @@ #include <subdev/vga.h> #include "fbmem.h" -#include "priv.h" - -struct nv10_devinit_priv { - struct nouveau_devinit base; - u8 owner; -}; +#include "nv04.h" static void nv10_devinit_meminit(struct nouveau_devinit *devinit) { - struct nv10_devinit_priv *priv = (void *)devinit; - const int mem_width[] = { 0x10, 0x00, 0x20 }; - const int mem_width_count = nv_device(priv)->chipset >= 0x17 ? 3 : 2; + struct nv04_devinit_priv *priv = (void *)devinit; + static const int mem_width[] = { 0x10, 0x00, 0x20 }; + int mem_width_count; uint32_t patt = 0xdeadbeef; struct io_mapping *fb; int i, j, k; + if (nv_device(priv)->card_type >= NV_11 && + nv_device(priv)->chipset >= 0x17) + mem_width_count = 3; + else + mem_width_count = 2; + /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; @@ -95,31 +96,15 @@ amount_found: fbmem_fini(fb); } -static int -nv10_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv10_devinit_priv *priv; - int ret; - - ret = nouveau_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.meminit = nv10_devinit_meminit; - priv->base.pll_set = nv04_devinit_pll_set; - return 0; -} - -struct nouveau_oclass -nv10_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0x10), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv10_devinit_ctor, +struct nouveau_oclass * +nv10_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x10), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_devinit_ctor, .dtor = nv04_devinit_dtor, .init = nv04_devinit_init, .fini = nv04_devinit_fini, }, -}; + .meminit = nv10_devinit_meminit, + .pll_set = nv04_devinit_pll_set, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c index e9743cdabe7..526d0c6faac 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c @@ -22,37 +22,16 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv04.h" -struct nv1a_devinit_priv { - struct nouveau_devinit base; - u8 owner; -}; - -static int -nv1a_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv1a_devinit_priv *priv; - int ret; - - ret = nouveau_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.pll_set = nv04_devinit_pll_set; - return 0; -} - -struct nouveau_oclass -nv1a_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0x1a), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv1a_devinit_ctor, +struct nouveau_oclass * +nv1a_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x1a), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_devinit_ctor, .dtor = nv04_devinit_dtor, .init = nv04_devinit_init, .fini = nv04_devinit_fini, }, -}; + .pll_set = nv04_devinit_pll_set, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c index 6cc6080d3bc..04bc9732644 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c @@ -24,25 +24,20 @@ * */ -#include "priv.h" +#include "nv04.h" #include "fbmem.h" -struct nv20_devinit_priv { - struct nouveau_devinit base; - u8 owner; -}; - static void nv20_devinit_meminit(struct nouveau_devinit *devinit) { - struct nv20_devinit_priv *priv = (void *)devinit; + struct nv04_devinit_priv *priv = (void *)devinit; struct nouveau_device *device = nv_device(priv); uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900); uint32_t amount, off; struct io_mapping *fb; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; @@ -65,31 +60,15 @@ nv20_devinit_meminit(struct nouveau_devinit *devinit) fbmem_fini(fb); } -static int -nv20_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv20_devinit_priv *priv; - int ret; - - ret = nouveau_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.meminit = nv20_devinit_meminit; - priv->base.pll_set = nv04_devinit_pll_set; - return 0; -} - -struct nouveau_oclass -nv20_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0x20), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv20_devinit_ctor, +struct nouveau_oclass * +nv20_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x20), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_devinit_ctor, .dtor = nv04_devinit_dtor, .init = nv04_devinit_init, .fini = nv04_devinit_fini, }, -}; + .meminit = nv20_devinit_meminit, + .pll_set = nv04_devinit_pll_set, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c index 6df72247c47..b46c62a1d5d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c @@ -28,9 +28,9 @@ #include <subdev/bios/init.h> #include <subdev/vga.h> -#include "priv.h" +#include "nv50.h" -static int +int nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nv50_devinit_priv *priv = (void *)devinit; @@ -74,6 +74,19 @@ nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) return 0; } +static u64 +nv50_devinit_disable(struct nouveau_devinit *devinit) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r001540 = nv_rd32(priv, 0x001540); + u64 disable = 0ULL; + + if (!(r001540 & 0x40000000)) + disable |= (1ULL << NVDEV_ENGINE_MPEG); + + return disable; +} + int nv50_devinit_init(struct nouveau_object *object) { @@ -120,7 +133,7 @@ nv50_devinit_init(struct nouveau_object *object) return 0; } -static int +int nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -133,17 +146,18 @@ nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.pll_set = nv50_devinit_pll_set; return 0; } -struct nouveau_oclass -nv50_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv50_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_devinit_ctor, .dtor = _nouveau_devinit_dtor, .init = nv50_devinit_init, .fini = _nouveau_devinit_fini, }, -}; + .pll_set = nv50_devinit_pll_set, + .disable = nv50_devinit_disable, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h new file mode 100644 index 00000000000..51d5076333e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h @@ -0,0 +1,21 @@ +#ifndef __NVKM_DEVINIT_NV50_H__ +#define __NVKM_DEVINIT_NV50_H__ + +#include "priv.h" + +struct nv50_devinit_priv { + struct nouveau_devinit base; + u32 r001540; +}; + +int nv50_devinit_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +int nv50_devinit_init(struct nouveau_object *); +int nv50_devinit_pll_set(struct nouveau_devinit *, u32, u32); + +int nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32); + +int nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c new file mode 100644 index 00000000000..787422505d8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c @@ -0,0 +1,63 @@ +/* + * 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 "nv50.h" + +static u64 +nv84_devinit_disable(struct nouveau_devinit *devinit) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r001540 = nv_rd32(priv, 0x001540); + u32 r00154c = nv_rd32(priv, 0x00154c); + u64 disable = 0ULL; + + if (!(r001540 & 0x40000000)) { + disable |= (1ULL << NVDEV_ENGINE_MPEG); + disable |= (1ULL << NVDEV_ENGINE_VP); + disable |= (1ULL << NVDEV_ENGINE_BSP); + disable |= (1ULL << NVDEV_ENGINE_CRYPT); + } + + if (!(r00154c & 0x00000004)) + disable |= (1ULL << NVDEV_ENGINE_DISP); + if (!(r00154c & 0x00000020)) + disable |= (1ULL << NVDEV_ENGINE_BSP); + if (!(r00154c & 0x00000040)) + disable |= (1ULL << NVDEV_ENGINE_CRYPT); + + return disable; +} + +struct nouveau_oclass * +nv84_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x84), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_devinit_ctor, + .dtor = _nouveau_devinit_dtor, + .init = nv50_devinit_init, + .fini = _nouveau_devinit_fini, + }, + .pll_set = nv50_devinit_pll_set, + .disable = nv84_devinit_disable, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c new file mode 100644 index 00000000000..2b0e963fc6f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c @@ -0,0 +1,62 @@ +/* + * 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 "nv50.h" + +static u64 +nv98_devinit_disable(struct nouveau_devinit *devinit) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r001540 = nv_rd32(priv, 0x001540); + u32 r00154c = nv_rd32(priv, 0x00154c); + u64 disable = 0ULL; + + if (!(r001540 & 0x40000000)) { + disable |= (1ULL << NVDEV_ENGINE_VP); + disable |= (1ULL << NVDEV_ENGINE_BSP); + disable |= (1ULL << NVDEV_ENGINE_PPP); + } + + if (!(r00154c & 0x00000004)) + disable |= (1ULL << NVDEV_ENGINE_DISP); + if (!(r00154c & 0x00000020)) + disable |= (1ULL << NVDEV_ENGINE_BSP); + if (!(r00154c & 0x00000040)) + disable |= (1ULL << NVDEV_ENGINE_CRYPT); + + return disable; +} + +struct nouveau_oclass * +nv98_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x98), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_devinit_ctor, + .dtor = _nouveau_devinit_dtor, + .init = nv50_devinit_init, + .fini = _nouveau_devinit_fini, + }, + .pll_set = nv50_devinit_pll_set, + .disable = nv98_devinit_disable, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c index 76a68b29014..006cf348bda 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c @@ -22,12 +22,12 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv50.h" -static int +int nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { - struct nva3_devinit_priv *priv = (void *)devinit; + struct nv50_devinit_priv *priv = (void *)devinit; struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_pll info; int N, fN, M, P; @@ -58,30 +58,88 @@ nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) return ret; } -static int -nva3_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +static u64 +nva3_devinit_disable(struct nouveau_devinit *devinit) { - struct nv50_devinit_priv *priv; - int ret; + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r001540 = nv_rd32(priv, 0x001540); + u32 r00154c = nv_rd32(priv, 0x00154c); + u64 disable = 0ULL; - ret = nouveau_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(r001540 & 0x40000000)) { + disable |= (1ULL << NVDEV_ENGINE_VP); + disable |= (1ULL << NVDEV_ENGINE_PPP); + } + + if (!(r00154c & 0x00000004)) + disable |= (1ULL << NVDEV_ENGINE_DISP); + if (!(r00154c & 0x00000020)) + disable |= (1ULL << NVDEV_ENGINE_BSP); + if (!(r00154c & 0x00000200)) + disable |= (1ULL << NVDEV_ENGINE_COPY0); + + return disable; +} - priv->base.pll_set = nva3_devinit_pll_set; - return 0; +static u32 +nva3_devinit_mmio_part[] = { + 0x100720, 0x1008bc, 4, + 0x100a20, 0x100adc, 4, + 0x100d80, 0x100ddc, 4, + 0x110000, 0x110f9c, 4, + 0x111000, 0x11103c, 8, + 0x111080, 0x1110fc, 4, + 0x111120, 0x1111fc, 4, + 0x111300, 0x1114bc, 4, + 0, +}; + +static u32 +nva3_devinit_mmio(struct nouveau_devinit *devinit, u32 addr) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 *mmio = nva3_devinit_mmio_part; + + /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP + * instructions which touch registers that may not even exist on + * some configurations (Quadro 400), which causes the register + * interface to screw up for some amount of time after attempting to + * write to one of these, and results in all sorts of things going + * horribly wrong. + * + * the binary driver avoids touching these registers at all, however, + * the video bios doesn't care and does what the scripts say. it's + * presumed that the io-port access to priv registers isn't effected + * by the screw-up bug mentioned above. + * + * really, a new opcode should've been invented to handle these + * requirements, but whatever, it's too late for that now. + */ + while (mmio[0]) { + if (addr >= mmio[0] && addr <= mmio[1]) { + u32 part = (addr / mmio[2]) & 7; + if (!priv->r001540) + priv->r001540 = nv_rd32(priv, 0x001540); + if (part >= hweight8((priv->r001540 >> 16) & 0xff)) + return ~0; + return addr; + } + mmio += 3; + } + + return addr; } -struct nouveau_oclass -nva3_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0xa3), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nva3_devinit_ctor, +struct nouveau_oclass * +nva3_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0xa3), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_devinit_ctor, .dtor = _nouveau_devinit_dtor, .init = nv50_devinit_init, .fini = _nouveau_devinit_fini, }, -}; + .pll_set = nva3_devinit_pll_set, + .disable = nva3_devinit_disable, + .mmio = nva3_devinit_mmio, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c new file mode 100644 index 00000000000..4fc68d27eff --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c @@ -0,0 +1,63 @@ +/* + * 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 "nv50.h" + +static u64 +nvaf_devinit_disable(struct nouveau_devinit *devinit) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r001540 = nv_rd32(priv, 0x001540); + u32 r00154c = nv_rd32(priv, 0x00154c); + u64 disable = 0; + + if (!(r001540 & 0x40000000)) { + disable |= (1ULL << NVDEV_ENGINE_VP); + disable |= (1ULL << NVDEV_ENGINE_PPP); + } + + if (!(r00154c & 0x00000004)) + disable |= (1ULL << NVDEV_ENGINE_DISP); + if (!(r00154c & 0x00000020)) + disable |= (1ULL << NVDEV_ENGINE_BSP); + if (!(r00154c & 0x00000040)) + disable |= (1ULL << NVDEV_ENGINE_VIC); + if (!(r00154c & 0x00000200)) + disable |= (1ULL << NVDEV_ENGINE_COPY0); + + return disable; +} + +struct nouveau_oclass * +nvaf_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0xaf), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_devinit_ctor, + .dtor = _nouveau_devinit_dtor, + .init = nv50_devinit_init, + .fini = _nouveau_devinit_fini, + }, + .pll_set = nva3_devinit_pll_set, + .disable = nvaf_devinit_disable, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c index 19e265bf457..30c765747ee 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c @@ -22,12 +22,12 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv50.h" -static int +int nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { - struct nvc0_devinit_priv *priv = (void *)devinit; + struct nv50_devinit_priv *priv = (void *)devinit; struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_pll info; int N, fN, M, P; @@ -59,6 +59,33 @@ nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) return ret; } +static u64 +nvc0_devinit_disable(struct nouveau_devinit *devinit) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r022500 = nv_rd32(priv, 0x022500); + u64 disable = 0ULL; + + if (r022500 & 0x00000001) + disable |= (1ULL << NVDEV_ENGINE_DISP); + + if (r022500 & 0x00000002) { + disable |= (1ULL << NVDEV_ENGINE_VP); + disable |= (1ULL << NVDEV_ENGINE_PPP); + } + + if (r022500 & 0x00000004) + disable |= (1ULL << NVDEV_ENGINE_BSP); + if (r022500 & 0x00000008) + disable |= (1ULL << NVDEV_ENGINE_VENC); + if (r022500 & 0x00000100) + disable |= (1ULL << NVDEV_ENGINE_COPY0); + if (r022500 & 0x00000200) + disable |= (1ULL << NVDEV_ENGINE_COPY1); + + return disable; +} + static int nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -72,19 +99,20 @@ nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.pll_set = nvc0_devinit_pll_set; if (nv_rd32(priv, 0x022500) & 0x00000001) priv->base.post = true; return 0; } -struct nouveau_oclass -nvc0_devinit_oclass = { - .handle = NV_SUBDEV(DEVINIT, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nvc0_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_devinit_ctor, .dtor = _nouveau_devinit_dtor, .init = nv50_devinit_init, .fini = _nouveau_devinit_fini, }, -}; + .pll_set = nvc0_devinit_pll_set, + .disable = nvc0_devinit_disable, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h index 7d622e2b017..f0e8683ad84 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h @@ -6,20 +6,33 @@ #include <subdev/clock/pll.h> #include <subdev/devinit.h> -void nv04_devinit_dtor(struct nouveau_object *); -int nv04_devinit_init(struct nouveau_object *); -int nv04_devinit_fini(struct nouveau_object *, bool); -int nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32); - -void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); -void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); -void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); - - -struct nv50_devinit_priv { - struct nouveau_devinit base; +struct nouveau_devinit_impl { + struct nouveau_oclass base; + void (*meminit)(struct nouveau_devinit *); + int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq); + u64 (*disable)(struct nouveau_devinit *); + u32 (*mmio)(struct nouveau_devinit *, u32); }; -int nv50_devinit_init(struct nouveau_object *); +#define nouveau_devinit_create(p,e,o,d) \ + nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_devinit_destroy(p) ({ \ + struct nouveau_devinit *d = (p); \ + _nouveau_devinit_dtor(nv_object(d)); \ +}) +#define nouveau_devinit_init(p) ({ \ + struct nouveau_devinit *d = (p); \ + _nouveau_devinit_init(nv_object(d)); \ +}) +#define nouveau_devinit_fini(p,s) ({ \ + struct nouveau_devinit *d = (p); \ + _nouveau_devinit_fini(nv_object(d), (s)); \ +}) + +int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void _nouveau_devinit_dtor(struct nouveau_object *); +int _nouveau_devinit_init(struct nouveau_object *); +int _nouveau_devinit_fini(struct nouveau_object *, bool suspend); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c index 821cd75b86a..f009d8a39d9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c @@ -22,9 +22,10 @@ * Authors: Ben Skeggs */ -#include "subdev/fb.h" -#include "subdev/bios.h" -#include "subdev/bios/bit.h" +#include <subdev/bios.h> +#include <subdev/bios/bit.h> + +#include "priv.h" int nouveau_fb_bios_memtype(struct nouveau_bios *bios) @@ -106,9 +107,9 @@ _nouveau_fb_dtor(struct nouveau_object *object) int nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, struct nouveau_oclass *ramcls, - int length, void **pobject) + struct nouveau_oclass *oclass, int length, void **pobject) { + struct nouveau_fb_impl *impl = (void *)oclass; static const char *name[] = { [NV_MEM_TYPE_UNKNOWN] = "unknown", [NV_MEM_TYPE_STOLEN ] = "stolen system memory", @@ -132,8 +133,10 @@ nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + pfb->memtype_valid = impl->memtype; + ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb), - ramcls, NULL, 0, &ram); + impl->ram, NULL, 0, &ram); if (ret) { nv_fatal(pfb, "error detecting memory configuration!!\n"); return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c new file mode 100644 index 00000000000..66fe959b4f7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c @@ -0,0 +1,122 @@ +/* + * 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 <subdev/bios.h> +#include "priv.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 + +int +nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts) +{ + int pd, lf, xd, vh, vr, vo, l3; + int WL, CL, WR, at[2], dt, ds; + int rq = ram->freq < 1000000; /* XXX */ + + switch (ram->ramcfg.version) { + case 0x11: + pd = ram->next->bios.ramcfg_11_01_80; + lf = ram->next->bios.ramcfg_11_01_40; + xd = !ram->next->bios.ramcfg_11_01_20; + vh = ram->next->bios.ramcfg_11_02_10; + vr = ram->next->bios.ramcfg_11_02_04; + vo = ram->next->bios.ramcfg_11_06; + l3 = !ram->next->bios.ramcfg_11_07_02; + break; + default: + return -ENOSYS; + } + + switch (ram->timing.version) { + case 0x20: + WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7; + CL = (ram->next->bios.timing[1] & 0x0000001f); + WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16; + at[0] = ram->next->bios.timing_20_2e_c0; + at[1] = ram->next->bios.timing_20_2e_30; + dt = ram->next->bios.timing_20_2e_03; + ds = ram->next->bios.timing_20_2f_03; + break; + default: + return -ENOSYS; + } + + if (WL < 1 || WL > 7 || CL < 5 || CL > 36 || WR < 4 || WR > 35) + return -EINVAL; + CL -= 5; + WR -= 4; + + ram->mr[0] &= ~0xf7f; + ram->mr[0] |= (WR & 0x0f) << 8; + ram->mr[0] |= (CL & 0x0f) << 3; + ram->mr[0] |= (WL & 0x07) << 0; + + ram->mr[1] &= ~0x0bf; + ram->mr[1] |= (xd & 0x01) << 7; + ram->mr[1] |= (at[0] & 0x03) << 4; + ram->mr[1] |= (dt & 0x03) << 2; + ram->mr[1] |= (ds & 0x03) << 0; + + /* this seems wrong, alternate field used for the broadcast + * on nuts vs non-nuts configs.. meh, it matches for now. + */ + ram->mr1_nuts = ram->mr[1]; + if (nuts) { + ram->mr[1] &= ~0x030; + ram->mr[1] |= (at[1] & 0x03) << 4; + } + + ram->mr[3] &= ~0x020; + ram->mr[3] |= (rq & 0x01) << 5; + + ram->mr[5] &= ~0x004; + ram->mr[5] |= (l3 << 2); + + if (!vo) + vo = (ram->mr[6] & 0xff0) >> 4; + if (ram->mr[6] & 0x001) + pd = 1; /* binary driver does this.. bug? */ + ram->mr[6] &= ~0xff1; + ram->mr[6] |= (vo & 0xff) << 4; + ram->mr[6] |= (pd & 0x01) << 0; + + if (NOTE00(vr)) { + ram->mr[7] &= ~0x300; + ram->mr[7] |= (vr & 0x03) << 8; + } + ram->mr[7] &= ~0x088; + ram->mr[7] |= (vh & 0x01) << 7; + ram->mr[7] |= (lf & 0x01) << 3; + + ram->mr[8] &= ~0x003; + ram->mr[8] |= (WR & 0x10) >> 3; + ram->mr[8] |= (CL & 0x10) >> 4; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c new file mode 100644 index 00000000000..a16024a7477 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c @@ -0,0 +1,56 @@ +/* + * 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 "nvc0.h" + +struct gk20a_fb_priv { + struct nouveau_fb base; +}; + +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) +{ + struct gk20a_fb_priv *priv; + int ret; + + ret = nouveau_fb_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass * +gk20a_fb_oclass = &(struct nouveau_fb_impl) { + .base.handle = NV_SUBDEV(FB, 0xea), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = gk20a_fb_ctor, + .dtor = _nouveau_fb_dtor, + .init = _nouveau_fb_init, + .fini = _nouveau_fb_fini, + }, + .memtype = nvc0_fb_memtype_valid, + .ram = &gk20a_ram_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c new file mode 100644 index 00000000000..c4840aedc2d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.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 "nvc0.h" + +struct nouveau_oclass * +gm107_fb_oclass = &(struct nouveau_fb_impl) { + .base.handle = NV_SUBDEV(FB, 0x07), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_fb_ctor, + .dtor = nvc0_fb_dtor, + .init = nvc0_fb_init, + .fini = _nouveau_fb_fini, + }, + .memtype = nvc0_fb_memtype_valid, + .ram = &gm107_ram_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c index 1f103c7b89f..8309fe33fe8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c @@ -22,14 +22,10 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv04.h" #define NV04_PFB_CFG0 0x00100200 -struct nv04_fb_priv { - struct nouveau_fb base; -}; - bool nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) { @@ -57,30 +53,37 @@ nv04_fb_init(struct nouveau_object *object) return 0; } -static int +int nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + struct nv04_fb_impl *impl = (void *)oclass; struct nv04_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &nv04_ram_oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.memtype_valid = nv04_fb_memtype_valid; + priv->base.tile.regions = impl->tile.regions; + priv->base.tile.init = impl->tile.init; + priv->base.tile.comp = impl->tile.comp; + priv->base.tile.fini = impl->tile.fini; + priv->base.tile.prog = impl->tile.prog; return 0; } -struct nouveau_oclass -nv04_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv04_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x04), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv04_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv04_ram_oclass, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h new file mode 100644 index 00000000000..06ce71f87a7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h @@ -0,0 +1,55 @@ +#ifndef __NVKM_FB_NV04_H__ +#define __NVKM_FB_NV04_H__ + +#include "priv.h" + +struct nv04_fb_priv { + struct nouveau_fb base; +}; + +int nv04_fb_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); + +struct nv04_fb_impl { + struct nouveau_fb_impl base; + struct { + int regions; + void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); + void (*comp)(struct nouveau_fb *, int i, u32 size, u32 flags, + struct nouveau_fb_tile *); + void (*fini)(struct nouveau_fb *, int i, + struct nouveau_fb_tile *); + void (*prog)(struct nouveau_fb *, int i, + struct nouveau_fb_tile *); + } tile; +}; + +void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); +void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *); +void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); +void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *); +void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +int nv30_fb_init(struct nouveau_object *); +void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); + +void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags, + struct nouveau_fb_tile *); + +int nv41_fb_init(struct nouveau_object *); +void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +int nv44_fb_init(struct nouveau_object *); +void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c index be069b5306b..ffb7ec6d97a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv10_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" void nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, @@ -57,34 +53,19 @@ nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) nv_rd32(pfb, 0x100240 + (i * 0x10)); } -static int -nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv10_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv10_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv10_fb_tile_init; - priv->base.tile.fini = nv10_fb_tile_fini; - priv->base.tile.prog = nv10_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv10_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x10), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv10_fb_ctor, +struct nouveau_oclass * +nv10_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x10), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = _nouveau_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv10_ram_oclass, + .tile.regions = 8, + .tile.init = nv10_fb_tile_init, + .tile.fini = nv10_fb_tile_fini, + .tile.prog = nv10_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c index 57a2af0079b..265d1253624 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c @@ -24,40 +24,21 @@ * */ -#include "priv.h" +#include "nv04.h" -struct nv1a_fb_priv { - struct nouveau_fb base; -}; - -static int -nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv1a_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv1a_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv10_fb_tile_init; - priv->base.tile.fini = nv10_fb_tile_fini; - priv->base.tile.prog = nv10_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv1a_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x1a), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv1a_fb_ctor, +struct nouveau_oclass * +nv1a_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x1a), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = _nouveau_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv1a_ram_oclass, + .tile.regions = 8, + .tile.init = nv10_fb_tile_init, + .tile.fini = nv10_fb_tile_fini, + .tile.prog = nv10_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c index b18c4e63bb4..f003c1b1893 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv20_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" void nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, @@ -80,35 +76,20 @@ nv20_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp); } -static int -nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv20_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv20_fb_tile_init; - priv->base.tile.comp = nv20_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv20_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv20_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x20), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv20_fb_ctor, +struct nouveau_oclass * +nv20_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x20), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = _nouveau_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv20_ram_oclass, + .tile.regions = 8, + .tile.init = nv20_fb_tile_init, + .tile.comp = nv20_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv20_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c index 32ccabf10c4..f34f4223210 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv25_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" static void nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, @@ -46,35 +42,20 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, } } -static int -nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv25_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv20_fb_tile_init; - priv->base.tile.comp = nv25_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv20_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv25_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x25), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv25_fb_ctor, +struct nouveau_oclass * +nv25_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x25), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = _nouveau_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv20_ram_oclass, + .tile.regions = 8, + .tile.init = nv20_fb_tile_init, + .tile.comp = nv25_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv20_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c index bef756d43d3..69093f7151f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv30_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" void nv30_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, @@ -67,7 +63,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, } static int -calc_bias(struct nv30_fb_priv *priv, int k, int i, int j) +calc_bias(struct nv04_fb_priv *priv, int k, int i, int j) { struct nouveau_device *device = nv_device(priv); int b = (device->chipset > 0x30 ? @@ -78,7 +74,7 @@ calc_bias(struct nv30_fb_priv *priv, int k, int i, int j) } static int -calc_ref(struct nv30_fb_priv *priv, int l, int k, int i) +calc_ref(struct nv04_fb_priv *priv, int l, int k, int i) { int j, x = 0; @@ -95,7 +91,7 @@ int nv30_fb_init(struct nouveau_object *object) { struct nouveau_device *device = nv_device(object); - struct nv30_fb_priv *priv = (void *)object; + struct nv04_fb_priv *priv = (void *)object; int ret, i, j; ret = nouveau_fb_init(&priv->base); @@ -124,35 +120,20 @@ nv30_fb_init(struct nouveau_object *object) return 0; } -static int -nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv30_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv30_fb_tile_init; - priv->base.tile.comp = nv30_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv20_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv30_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x30), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv30_fb_ctor, +struct nouveau_oclass * +nv30_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x30), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv30_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv20_ram_oclass, + .tile.regions = 8, + .tile.init = nv30_fb_tile_init, + .tile.comp = nv30_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv20_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c index 097d8e3824f..161b06e8fc3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv35_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" static void nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, @@ -47,35 +43,20 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, } } -static int -nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv35_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv30_fb_tile_init; - priv->base.tile.comp = nv35_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv20_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv35_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x35), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv35_fb_ctor, +struct nouveau_oclass * +nv35_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x35), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv30_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv20_ram_oclass, + .tile.regions = 8, + .tile.init = nv30_fb_tile_init, + .tile.comp = nv35_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv20_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c index 9d6d9df896d..2dd3d0aab6b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv36_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" static void nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, @@ -47,35 +43,20 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, } } -static int -nv36_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv36_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv30_fb_tile_init; - priv->base.tile.comp = nv36_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv20_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv36_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x36), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv36_fb_ctor, +struct nouveau_oclass * +nv36_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x36), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv30_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv20_ram_oclass, + .tile.regions = 8, + .tile.init = nv30_fb_tile_init, + .tile.comp = nv36_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv20_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c index 33b4393a782..95a115ab0c8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv40_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" void nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, @@ -50,7 +46,7 @@ nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, static int nv40_fb_init(struct nouveau_object *object) { - struct nv40_fb_priv *priv = (void *)object; + struct nv04_fb_priv *priv = (void *)object; int ret; ret = nouveau_fb_init(&priv->base); @@ -61,36 +57,20 @@ nv40_fb_init(struct nouveau_object *object) return 0; } -static int -nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv40_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv40_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 8; - priv->base.tile.init = nv30_fb_tile_init; - priv->base.tile.comp = nv40_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv20_fb_tile_prog; - return 0; -} - - -struct nouveau_oclass -nv40_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x40), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv40_fb_ctor, +struct nouveau_oclass * +nv40_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x40), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv40_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv40_ram_oclass, + .tile.regions = 8, + .tile.init = nv30_fb_tile_init, + .tile.comp = nv40_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv20_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h new file mode 100644 index 00000000000..581f808527f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h @@ -0,0 +1,17 @@ +#ifndef __NVKM_FB_NV40_H__ +#define __NVKM_FB_NV40_H__ + +#include "priv.h" + +struct nv40_ram { + struct nouveau_ram base; + u32 ctrl; + u32 coef; +}; + + +int nv40_ram_calc(struct nouveau_fb *, u32); +int nv40_ram_prog(struct nouveau_fb *); +void nv40_ram_tidy(struct nouveau_fb *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c index 02cd83789cd..b239a861559 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv41_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" void nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) @@ -43,7 +39,7 @@ nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) int nv41_fb_init(struct nouveau_object *object) { - struct nv41_fb_priv *priv = (void *)object; + struct nv04_fb_priv *priv = (void *)object; int ret; ret = nouveau_fb_init(&priv->base); @@ -54,36 +50,20 @@ nv41_fb_init(struct nouveau_object *object) return 0; } -static int -nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv41_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 12; - priv->base.tile.init = nv30_fb_tile_init; - priv->base.tile.comp = nv40_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv41_fb_tile_prog; - return 0; -} - - -struct nouveau_oclass -nv41_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x41), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv41_fb_ctor, +struct nouveau_oclass * +nv41_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x41), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv41_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv41_ram_oclass, + .tile.regions = 12, + .tile.init = nv30_fb_tile_init, + .tile.comp = nv40_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv41_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c index c5246c29f29..d8478208a68 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv44_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" static void nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, @@ -52,7 +48,7 @@ nv44_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) int nv44_fb_init(struct nouveau_object *object) { - struct nv44_fb_priv *priv = (void *)object; + struct nv04_fb_priv *priv = (void *)object; int ret; ret = nouveau_fb_init(&priv->base); @@ -64,35 +60,19 @@ nv44_fb_init(struct nouveau_object *object) return 0; } -static int -nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv44_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 12; - priv->base.tile.init = nv44_fb_tile_init; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv44_fb_tile_prog; - return 0; -} - - -struct nouveau_oclass -nv44_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x44), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv44_fb_ctor, +struct nouveau_oclass * +nv44_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x44), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv44_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv44_ram_oclass, + .tile.regions = 12, + .tile.init = nv44_fb_tile_init, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv44_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c index e2b57909bfc..a5b77514d35 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c @@ -24,11 +24,7 @@ * */ -#include "priv.h" - -struct nv46_fb_priv { - struct nouveau_fb base; -}; +#include "nv04.h" void nv46_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, @@ -44,35 +40,19 @@ nv46_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, tile->pitch = pitch; } -static int -nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv46_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 15; - priv->base.tile.init = nv46_fb_tile_init; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv44_fb_tile_prog; - return 0; -} - - -struct nouveau_oclass -nv46_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x46), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv46_fb_ctor, +struct nouveau_oclass * +nv46_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x46), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv44_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv44_ram_oclass, + .tile.regions = 15, + .tile.init = nv46_fb_tile_init, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv44_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c index fe6a2278621..3bea142376b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c @@ -24,42 +24,22 @@ * */ -#include "priv.h" +#include "nv04.h" -struct nv47_fb_priv { - struct nouveau_fb base; -}; - -static int -nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv47_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 15; - priv->base.tile.init = nv30_fb_tile_init; - priv->base.tile.comp = nv40_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv41_fb_tile_prog; - return 0; -} - - -struct nouveau_oclass -nv47_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x47), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv47_fb_ctor, +struct nouveau_oclass * +nv47_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x47), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv41_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv41_ram_oclass, + .tile.regions = 15, + .tile.init = nv30_fb_tile_init, + .tile.comp = nv40_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv41_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c index 5eca99b8c7e..666cbd5d47f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c @@ -24,42 +24,22 @@ * */ -#include "priv.h" +#include "nv04.h" -struct nv49_fb_priv { - struct nouveau_fb base; -}; - -static int -nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv49_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv49_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 15; - priv->base.tile.init = nv30_fb_tile_init; - priv->base.tile.comp = nv40_fb_tile_comp; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv41_fb_tile_prog; - return 0; -} - - -struct nouveau_oclass -nv49_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x49), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv49_fb_ctor, +struct nouveau_oclass * +nv49_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x49), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv41_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv49_ram_oclass, + .tile.regions = 15, + .tile.init = nv30_fb_tile_init, + .tile.comp = nv40_fb_tile_comp, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv41_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c index 1190b78a1e9..42e64f364ec 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c @@ -24,40 +24,21 @@ * */ -#include "priv.h" +#include "nv04.h" -struct nv4e_fb_priv { - struct nouveau_fb base; -}; - -static int -nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv4e_fb_priv *priv; - int ret; - - ret = nouveau_fb_create(parent, engine, oclass, &nv4e_ram_oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.tile.regions = 12; - priv->base.tile.init = nv46_fb_tile_init; - priv->base.tile.fini = nv20_fb_tile_fini; - priv->base.tile.prog = nv44_fb_tile_prog; - return 0; -} - -struct nouveau_oclass -nv4e_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x4e), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv4e_fb_ctor, +struct nouveau_oclass * +nv4e_fb_oclass = &(struct nv04_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x4e), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_fb_ctor, .dtor = _nouveau_fb_dtor, .init = nv44_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv04_fb_memtype_valid, + .base.ram = &nv4e_ram_oclass, + .tile.regions = 12, + .tile.init = nv46_fb_tile_init, + .tile.fini = nv20_fb_tile_fini, + .tile.prog = nv44_fb_tile_prog, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index da614ec5564..1fc55c1e91a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -27,14 +27,9 @@ #include <core/engctx.h> #include <core/object.h> -#include "priv.h" #include <subdev/bios.h> -struct nv50_fb_priv { - struct nouveau_fb base; - struct page *r100c08_page; - dma_addr_t r100c08; -}; +#include "nv50.h" int nv50_fb_memtype[0x80] = { @@ -48,7 +43,7 @@ nv50_fb_memtype[0x80] = { 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 }; -static bool +bool nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype) { return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0; @@ -239,7 +234,7 @@ nv50_fb_intr(struct nouveau_subdev *subdev) pr_cont("0x%08x\n", st1); } -static int +int nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -248,46 +243,42 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv50_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &nv50_ram_oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (priv->r100c08_page) { - priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page, - 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(device->pdev, priv->r100c08)) + priv->r100c08 = nv_device_map_page(device, priv->r100c08_page); + if (!priv->r100c08) nv_warn(priv, "failed 0x100c08 page map\n"); } else { nv_warn(priv, "failed 0x100c08 page alloc\n"); } - priv->base.memtype_valid = nv50_fb_memtype_valid; nv_subdev(priv)->intr = nv50_fb_intr; return 0; } -static void +void nv50_fb_dtor(struct nouveau_object *object) { struct nouveau_device *device = nv_device(object); struct nv50_fb_priv *priv = (void *)object; if (priv->r100c08_page) { - pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, priv->r100c08); __free_page(priv->r100c08_page); } nouveau_fb_destroy(&priv->base); } -static int +int nv50_fb_init(struct nouveau_object *object) { - struct nouveau_device *device = nv_device(object); + struct nv50_fb_impl *impl = (void *)object->oclass; struct nv50_fb_priv *priv = (void *)object; int ret; @@ -303,33 +294,20 @@ nv50_fb_init(struct nouveau_object *object) /* This is needed to get meaningful information from 100c90 * on traps. No idea what these values mean exactly. */ - switch (device->chipset) { - case 0x50: - nv_wr32(priv, 0x100c90, 0x000707ff); - break; - case 0xa3: - case 0xa5: - case 0xa8: - nv_wr32(priv, 0x100c90, 0x000d0fff); - break; - case 0xaf: - nv_wr32(priv, 0x100c90, 0x089d1fff); - break; - default: - nv_wr32(priv, 0x100c90, 0x001d07ff); - break; - } - + nv_wr32(priv, 0x100c90, impl->trap); return 0; } -struct nouveau_oclass -nv50_fb_oclass = { - .handle = NV_SUBDEV(FB, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv50_fb_oclass = &(struct nv50_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x50), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_fb_ctor, .dtor = nv50_fb_dtor, .init = nv50_fb_init, .fini = _nouveau_fb_fini, }, -}; + .base.memtype = nv50_fb_memtype_valid, + .base.ram = &nv50_ram_oclass, + .trap = 0x000707ff, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h new file mode 100644 index 00000000000..c5e5a888c60 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h @@ -0,0 +1,33 @@ +#ifndef __NVKM_FB_NV50_H__ +#define __NVKM_FB_NV50_H__ + +#include "priv.h" + +struct nv50_fb_priv { + struct nouveau_fb base; + struct page *r100c08_page; + dma_addr_t r100c08; +}; + +int nv50_fb_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nv50_fb_dtor(struct nouveau_object *); +int nv50_fb_init(struct nouveau_object *); + +struct nv50_fb_impl { + struct nouveau_fb_impl base; + u32 trap; +}; + +#define nv50_ram_create(p,e,o,d) \ + nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d) +int nv50_ram_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int nv50_ram_get(struct nouveau_fb *, u64 size, u32 align, u32 ncmin, + u32 memtype, struct nouveau_mem **); +void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **); +void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *); +extern int nv50_fb_memtype[0x80]; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c new file mode 100644 index 00000000000..cf0e767d383 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c @@ -0,0 +1,39 @@ +/* + * 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 "nv50.h" + +struct nouveau_oclass * +nv84_fb_oclass = &(struct nv50_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0x84), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fb_ctor, + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .fini = _nouveau_fb_fini, + }, + .base.memtype = nv50_fb_memtype_valid, + .base.ram = &nv50_ram_oclass, + .trap = 0x001d07ff, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c new file mode 100644 index 00000000000..dab6e1c63d4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c @@ -0,0 +1,39 @@ +/* + * 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 "nv50.h" + +struct nouveau_oclass * +nva3_fb_oclass = &(struct nv50_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0xa3), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fb_ctor, + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .fini = _nouveau_fb_fini, + }, + .base.memtype = nv50_fb_memtype_valid, + .base.ram = &nva3_ram_oclass, + .trap = 0x000d0fff, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c new file mode 100644 index 00000000000..cba8e681803 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c @@ -0,0 +1,39 @@ +/* + * 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 "nv50.h" + +struct nouveau_oclass * +nvaa_fb_oclass = &(struct nv50_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0xaa), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fb_ctor, + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .fini = _nouveau_fb_fini, + }, + .base.memtype = nv50_fb_memtype_valid, + .base.ram = &nvaa_ram_oclass, + .trap = 0x001d07ff, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c new file mode 100644 index 00000000000..5423faa2c09 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c @@ -0,0 +1,39 @@ +/* + * 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 "nv50.h" + +struct nouveau_oclass * +nvaf_fb_oclass = &(struct nv50_fb_impl) { + .base.base.handle = NV_SUBDEV(FB, 0xaf), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_fb_ctor, + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .fini = _nouveau_fb_fini, + }, + .base.memtype = nv50_fb_memtype_valid, + .base.ram = &nvaa_ram_oclass, + .trap = 0x089d1fff, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c index f35d76fd746..0670ae33ee4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c @@ -22,24 +22,33 @@ * Authors: Ben Skeggs */ -#include "priv.h" - -struct nvc0_fb_priv { - struct nouveau_fb base; - struct page *r100c10_page; - dma_addr_t r100c10; -}; +#include "nvc0.h" extern const u8 nvc0_pte_storage_type_map[256]; -static bool +bool nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) { u8 memtype = (tile_flags & 0x0000ff00) >> 8; return likely((nvc0_pte_storage_type_map[memtype] != 0xff)); } -static int +static void +nvc0_fb_intr(struct nouveau_subdev *subdev) +{ + struct nvc0_fb_priv *priv = (void *)subdev; + u32 intr = nv_rd32(priv, 0x000100); + if (intr & 0x08000000) { + nv_debug(priv, "PFFB intr\n"); + intr &= ~0x08000000; + } + if (intr & 0x00002000) { + nv_debug(priv, "PBFB intr\n"); + intr &= ~0x00002000; + } +} + +int nvc0_fb_init(struct nouveau_object *object) { struct nvc0_fb_priv *priv = (void *)object; @@ -54,22 +63,21 @@ nvc0_fb_init(struct nouveau_object *object) return 0; } -static void +void nvc0_fb_dtor(struct nouveau_object *object) { struct nouveau_device *device = nv_device(object); struct nvc0_fb_priv *priv = (void *)object; if (priv->r100c10_page) { - pci_unmap_page(device->pdev, priv->r100c10, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, priv->r100c10); __free_page(priv->r100c10_page); } nouveau_fb_destroy(&priv->base); } -static int +int nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -78,33 +86,31 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &nvc0_ram_oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.memtype_valid = nvc0_fb_memtype_valid; - priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (priv->r100c10_page) { - priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page, - 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(device->pdev, priv->r100c10)) + priv->r100c10 = nv_device_map_page(device, priv->r100c10_page); + if (!priv->r100c10) return -EFAULT; } + nv_subdev(priv)->intr = nvc0_fb_intr; return 0; } - -struct nouveau_oclass -nvc0_fb_oclass = { - .handle = NV_SUBDEV(FB, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nvc0_fb_oclass = &(struct nouveau_fb_impl) { + .base.handle = NV_SUBDEV(FB, 0xc0), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_fb_ctor, .dtor = nvc0_fb_dtor, .init = nvc0_fb_init, .fini = _nouveau_fb_fini, }, -}; + .memtype = nvc0_fb_memtype_valid, + .ram = &nvc0_ram_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h new file mode 100644 index 00000000000..705a06d755a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h @@ -0,0 +1,31 @@ +#ifndef __NVKM_RAM_NVC0_H__ +#define __NVKM_RAM_NVC0_H__ + +#include "priv.h" +#include "nv50.h" + +struct nvc0_fb_priv { + struct nouveau_fb base; + struct page *r100c10_page; + dma_addr_t r100c10; +}; + +int nvc0_fb_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nvc0_fb_dtor(struct nouveau_object *); +int nvc0_fb_init(struct nouveau_object *); +bool nvc0_fb_memtype_valid(struct nouveau_fb *, u32); + + +#define nvc0_ram_create(p,e,o,m,d) \ + nvc0_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d) +int nvc0_ram_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u32, int, void **); +int nvc0_ram_get(struct nouveau_fb *, u64, u32, u32, u32, + struct nouveau_mem **); +void nvc0_ram_put(struct nouveau_fb *, struct nouveau_mem **); + +int nve0_ram_init(struct nouveau_object*); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c new file mode 100644 index 00000000000..595db50cfef --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.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 "nvc0.h" + +struct nouveau_oclass * +nve0_fb_oclass = &(struct nouveau_fb_impl) { + .base.handle = NV_SUBDEV(FB, 0xe0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_fb_ctor, + .dtor = nvc0_fb_dtor, + .init = nvc0_fb_init, + .fini = _nouveau_fb_fini, + }, + .memtype = nvc0_fb_memtype_valid, + .ram = &nve0_ram_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h index db9d6ddde52..82273f832e4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h @@ -12,6 +12,8 @@ #define nouveau_ram_fini(p,s) \ nouveau_object_fini(&(p)->base, (s)) +#define nouveau_ram_create_(p,e,o,s,d) \ + nouveau_object_create_((p), (e), (o), 0, (s), (void **)d) #define _nouveau_ram_dtor nouveau_object_destroy #define _nouveau_ram_init nouveau_object_init #define _nouveau_ram_fini nouveau_object_fini @@ -26,10 +28,18 @@ extern struct nouveau_oclass nv44_ram_oclass; extern struct nouveau_oclass nv49_ram_oclass; extern struct nouveau_oclass nv4e_ram_oclass; extern struct nouveau_oclass nv50_ram_oclass; +extern struct nouveau_oclass nva3_ram_oclass; +extern struct nouveau_oclass nvaa_ram_oclass; extern struct nouveau_oclass nvc0_ram_oclass; +extern struct nouveau_oclass nve0_ram_oclass; +extern struct nouveau_oclass gk20a_ram_oclass; +extern struct nouveau_oclass gm107_ram_oclass; -#define nouveau_fb_create(p,e,c,r,d) \ - nouveau_fb_create_((p), (e), (c), (r), sizeof(**d), (void **)d) +int nouveau_sddr3_calc(struct nouveau_ram *ram); +int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts); + +#define nouveau_fb_create(p,e,c,d) \ + nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d) #define nouveau_fb_destroy(p) ({ \ struct nouveau_fb *pfb = (p); \ _nouveau_fb_dtor(nv_object(pfb)); \ @@ -44,44 +54,21 @@ extern struct nouveau_oclass nvc0_ram_oclass; }) int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, struct nouveau_oclass *, - int length, void **pobject); + struct nouveau_oclass *, int, void **); void _nouveau_fb_dtor(struct nouveau_object *); int _nouveau_fb_init(struct nouveau_object *); int _nouveau_fb_fini(struct nouveau_object *, bool); -struct nouveau_bios; -int nouveau_fb_bios_memtype(struct nouveau_bios *); +struct nouveau_fb_impl { + struct nouveau_oclass base; + struct nouveau_oclass *ram; + bool (*memtype)(struct nouveau_fb *, u32); +}; bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype); +bool nv50_fb_memtype_valid(struct nouveau_fb *, u32 memtype); -void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nouveau_fb_tile *); -void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *); -void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); - -void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nouveau_fb_tile *); -void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *); -void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); - -int nv30_fb_init(struct nouveau_object *); -void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nouveau_fb_tile *); - -void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags, - struct nouveau_fb_tile *); - -int nv41_fb_init(struct nouveau_object *); -void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); - -int nv44_fb_init(struct nouveau_object *); -void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); - -void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nouveau_fb_tile *); - -void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *); -extern int nv50_fb_memtype[0x80]; +struct nouveau_bios; +int nouveau_fb_bios_memtype(struct nouveau_bios *); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h new file mode 100644 index 00000000000..2af9cfd2c60 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h @@ -0,0 +1,118 @@ +#ifndef __NVKM_FBRAM_FUC_H__ +#define __NVKM_FBRAM_FUC_H__ + +#include <subdev/pwr.h> + +struct ramfuc { + struct nouveau_memx *memx; + struct nouveau_fb *pfb; + int sequence; +}; + +struct ramfuc_reg { + int sequence; + bool force; + u32 addr[2]; + u32 data; +}; + +static inline struct ramfuc_reg +ramfuc_reg2(u32 addr1, u32 addr2) +{ + return (struct ramfuc_reg) { + .sequence = 0, + .addr = { addr1, addr2 }, + .data = 0xdeadbeef, + }; +} + +static noinline struct ramfuc_reg +ramfuc_reg(u32 addr) +{ + return ramfuc_reg2(addr, addr); +} + +static inline int +ramfuc_init(struct ramfuc *ram, struct nouveau_fb *pfb) +{ + struct nouveau_pwr *ppwr = nouveau_pwr(pfb); + int ret; + + ret = nouveau_memx_init(ppwr, &ram->memx); + if (ret) + return ret; + + ram->sequence++; + ram->pfb = pfb; + return 0; +} + +static inline int +ramfuc_exec(struct ramfuc *ram, bool exec) +{ + int ret = 0; + if (ram->pfb) { + ret = nouveau_memx_fini(&ram->memx, exec); + ram->pfb = NULL; + } + return ret; +} + +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]); + return reg->data; +} + +static inline void +ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data) +{ + 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); +} + +static inline void +ramfuc_nuke(struct ramfuc *ram, struct ramfuc_reg *reg) +{ + reg->force = true; +} + +static inline u32 +ramfuc_mask(struct ramfuc *ram, struct ramfuc_reg *reg, u32 mask, u32 data) +{ + u32 temp = ramfuc_rd32(ram, reg); + if (temp != ((temp & ~mask) | data) || reg->force) { + ramfuc_wr32(ram, reg, (temp & ~mask) | data); + reg->force = false; + } + return temp; +} + +static inline void +ramfuc_wait(struct ramfuc *ram, u32 addr, u32 mask, u32 data, u32 nsec) +{ + nouveau_memx_wait(ram->memx, addr, mask, data, nsec); +} + +static inline void +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)) + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c new file mode 100644 index 00000000000..4d77d75e467 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c @@ -0,0 +1,152 @@ +/* + * 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 "priv.h" + +#include <subdev/fb.h> + +struct gk20a_mem { + struct nouveau_mem base; + void *cpuaddr; + dma_addr_t handle; +}; +#define to_gk20a_mem(m) container_of(m, struct gk20a_mem, base) + +static void +gk20a_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) +{ + struct device *dev = nv_device_base(nv_device(pfb)); + struct gk20a_mem *mem = to_gk20a_mem(*pmem); + + *pmem = NULL; + if (unlikely(mem == NULL)) + return; + + if (likely(mem->cpuaddr)) + dma_free_coherent(dev, mem->base.size << PAGE_SHIFT, + mem->cpuaddr, mem->handle); + + kfree(mem->base.pages); + kfree(mem); +} + +static int +gk20a_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, + u32 memtype, struct nouveau_mem **pmem) +{ + struct device *dev = nv_device_base(nv_device(pfb)); + struct gk20a_mem *mem; + u32 type = memtype & 0xff; + u32 npages, order; + int i; + + nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size, + align, ncmin); + + npages = size >> PAGE_SHIFT; + if (npages == 0) + npages = 1; + + if (align == 0) + align = PAGE_SIZE; + align >>= PAGE_SHIFT; + + /* round alignment to the next power of 2, if needed */ + order = fls(align); + if ((align & (align - 1)) == 0) + order--; + align = BIT(order); + + /* ensure returned address is correctly aligned */ + npages = max(align, npages); + + mem = kzalloc(sizeof(*mem), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + mem->base.size = npages; + mem->base.memtype = type; + + mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL); + if (!mem->base.pages) { + kfree(mem); + return -ENOMEM; + } + + *pmem = &mem->base; + + mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT, + &mem->handle, GFP_KERNEL); + if (!mem->cpuaddr) { + nv_error(pfb, "%s: cannot allocate memory!\n", __func__); + gk20a_ram_put(pfb, pmem); + return -ENOMEM; + } + + align <<= PAGE_SHIFT; + + /* alignment check */ + if (unlikely(mem->handle & (align - 1))) + nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n", + &mem->handle, align); + + nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n", + npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr); + + for (i = 0; i < npages; i++) + mem->base.pages[i] = mem->handle + (PAGE_SIZE * i); + + mem->base.offset = (u64)mem->base.pages[0]; + + return 0; +} + +static int +gk20a_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 datasize, + struct nouveau_object **pobject) +{ + struct nouveau_ram *ram; + int ret; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + ram->type = NV_MEM_TYPE_STOLEN; + ram->size = get_num_physpages() << PAGE_SHIFT; + + ram->get = gk20a_ram_get; + ram->put = gk20a_ram_put; + + return 0; +} + +struct nouveau_oclass +gk20a_ram_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gk20a_ram_ctor, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c new file mode 100644 index 00000000000..4c6363595c7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c @@ -0,0 +1,56 @@ +/* + * 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 "nvc0.h" + +struct gm107_ram { + struct nouveau_ram base; +}; + +static int +gm107_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gm107_ram *ram; + int ret; + + ret = nvc0_ram_create(parent, engine, oclass, 0x021c14, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass +gm107_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_ram_ctor, + .dtor = _nouveau_ram_dtor, + .init = nve0_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c index ee49ac4dbdb..7648beb1119 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c @@ -22,7 +22,154 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/pll.h> +#include <subdev/bios/init.h> +#include <subdev/clock.h> +#include <subdev/clock/pll.h> +#include <subdev/timer.h> + +#include <engine/fifo.h> + +#include "nv40.h" + +int +nv40_ram_calc(struct nouveau_fb *pfb, u32 freq) +{ + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nv40_ram *ram = (void *)pfb->ram; + struct nvbios_pll pll; + int N1, M1, N2, M2; + int log2P, ret; + + ret = nvbios_pll_parse(bios, 0x04, &pll); + if (ret) { + nv_error(pfb, "mclk pll data not found\n"); + return ret; + } + + ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq, + &N1, &M1, &N2, &M2, &log2P); + if (ret < 0) + return ret; + + ram->ctrl = 0x80000000 | (log2P << 16); + ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20; + if (N2 == M2) { + ram->ctrl |= 0x00000100; + ram->coef = (N1 << 8) | M1; + } else { + ram->ctrl |= 0x40000000; + ram->coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; + } + + return 0; +} + +int +nv40_ram_prog(struct nouveau_fb *pfb) +{ + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nv40_ram *ram = (void *)pfb->ram; + struct bit_entry M; + u32 crtc_mask = 0; + u8 sr1[2]; + int i; + + /* determine which CRTCs are active, fetch VGA_SR1 for each */ + for (i = 0; i < 2; i++) { + u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000)); + u32 cnt = 0; + do { + if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) { + nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); + sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000)); + if (!(sr1[i] & 0x20)) + crtc_mask |= (1 << i); + break; + } + udelay(1); + } while (cnt++ < 32); + } + + /* wait for vblank start on active crtcs, disable memory access */ + for (i = 0; i < 2; i++) { + if (!(crtc_mask & (1 << i))) + continue; + nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); + nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); + nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); + } + + /* prepare ram for reclocking */ + nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */ + nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */ + nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */ + nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ + nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */ + + /* change the PLL of each memory partition */ + nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000); + switch (nv_device(pfb)->chipset) { + case 0x40: + case 0x45: + case 0x41: + case 0x42: + case 0x47: + nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl); + nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl); + nv_wr32(pfb, 0x004048, ram->coef); + nv_wr32(pfb, 0x004030, ram->coef); + case 0x43: + case 0x49: + case 0x4b: + nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl); + nv_wr32(pfb, 0x00403c, ram->coef); + default: + nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl); + nv_wr32(pfb, 0x004024, ram->coef); + break; + } + udelay(100); + nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000); + + /* re-enable normal operation of memory controller */ + nv_wr32(pfb, 0x1002dc, 0x00000000); + nv_mask(pfb, 0x100210, 0x80000000, 0x80000000); + udelay(100); + + /* execute memory reset script from vbios */ + if (!bit_entry(bios, 'M', &M)) { + struct nvbios_init init = { + .subdev = nv_subdev(pfb), + .bios = bios, + .offset = nv_ro16(bios, M.offset + 0x00), + .execute = 1, + }; + + nvbios_exec(&init); + } + + /* make sure we're in vblank (hopefully the same one as before), and + * then re-enable crtc memory access + */ + for (i = 0; i < 2; i++) { + if (!(crtc_mask & (1 << i))) + continue; + nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); + nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]); + } + + return 0; +} + +void +nv40_ram_tidy(struct nouveau_fb *pfb) +{ +} static int nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, @@ -30,7 +177,7 @@ nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_object **pobject) { struct nouveau_fb *pfb = nouveau_fb(parent); - struct nouveau_ram *ram; + struct nv40_ram *ram; u32 pbus1218 = nv_rd32(pfb, 0x001218); int ret; @@ -40,15 +187,18 @@ nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, return ret; switch (pbus1218 & 0x00000300) { - case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: ram->type = NV_MEM_TYPE_DDR2; break; + case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break; + case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break; + case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break; + case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break; } - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->tags = nv_rd32(pfb, 0x100320); + ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; + ram->base.tags = nv_rd32(pfb, 0x100320); + ram->base.calc = nv40_ram_calc; + ram->base.prog = nv40_ram_prog; + ram->base.tidy = nv40_ram_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c index 1dab7e12aba..d64498a4d9e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv40.h" static int nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, @@ -30,7 +30,7 @@ nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_object **pobject) { struct nouveau_fb *pfb = nouveau_fb(parent); - struct nouveau_ram *ram; + struct nv40_ram *ram; u32 pfb474 = nv_rd32(pfb, 0x100474); int ret; @@ -40,15 +40,18 @@ nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, return ret; if (pfb474 & 0x00000004) - ram->type = NV_MEM_TYPE_GDDR3; + ram->base.type = NV_MEM_TYPE_GDDR3; if (pfb474 & 0x00000002) - ram->type = NV_MEM_TYPE_DDR2; + ram->base.type = NV_MEM_TYPE_DDR2; if (pfb474 & 0x00000001) - ram->type = NV_MEM_TYPE_DDR1; + ram->base.type = NV_MEM_TYPE_DDR1; - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->tags = nv_rd32(pfb, 0x100320); + ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; + ram->base.tags = nv_rd32(pfb, 0x100320); + ram->base.calc = nv40_ram_calc; + ram->base.prog = nv40_ram_prog; + ram->base.tidy = nv40_ram_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c index 25fff842e5c..089acac810c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv40.h" static int nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, @@ -30,7 +30,7 @@ nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_object **pobject) { struct nouveau_fb *pfb = nouveau_fb(parent); - struct nouveau_ram *ram; + struct nv40_ram *ram; u32 pfb474 = nv_rd32(pfb, 0x100474); int ret; @@ -40,13 +40,16 @@ nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, return ret; if (pfb474 & 0x00000004) - ram->type = NV_MEM_TYPE_GDDR3; + ram->base.type = NV_MEM_TYPE_GDDR3; if (pfb474 & 0x00000002) - ram->type = NV_MEM_TYPE_DDR2; + ram->base.type = NV_MEM_TYPE_DDR2; if (pfb474 & 0x00000001) - ram->type = NV_MEM_TYPE_DDR1; + ram->base.type = NV_MEM_TYPE_DDR1; - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->base.calc = nv40_ram_calc; + ram->base.prog = nv40_ram_prog; + ram->base.tidy = nv40_ram_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c index ab7ef0ac9e3..baa013afa57 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv40.h" static int nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, @@ -30,7 +30,7 @@ nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_object **pobject) { struct nouveau_fb *pfb = nouveau_fb(parent); - struct nouveau_ram *ram; + struct nv40_ram *ram; u32 pfb914 = nv_rd32(pfb, 0x100914); int ret; @@ -40,15 +40,18 @@ nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, return ret; switch (pfb914 & 0x00000003) { - case 0x00000000: ram->type = NV_MEM_TYPE_DDR1; break; - case 0x00000001: ram->type = NV_MEM_TYPE_DDR2; break; - case 0x00000002: ram->type = NV_MEM_TYPE_GDDR3; break; + case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break; + case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break; + case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break; case 0x00000003: break; } - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->tags = nv_rd32(pfb, 0x100320); + ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; + ram->base.tags = nv_rd32(pfb, 0x100320); + ram->base.calc = nv40_ram_calc; + ram->base.prog = nv40_ram_prog; + ram->base.tidy = nv40_ram_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c index 903baff77fd..e5d12c24cc4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c @@ -23,8 +23,205 @@ */ #include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/pll.h> +#include <subdev/bios/perf.h> +#include <subdev/bios/timing.h> +#include <subdev/clock/pll.h> +#include <subdev/fb.h> + +#include <core/option.h> #include <core/mm.h> -#include "priv.h" + +#include "ramseq.h" + +#include "nv50.h" + +struct nv50_ramseq { + struct hwsq base; + struct hwsq_reg r_0x002504; + struct hwsq_reg r_0x004008; + struct hwsq_reg r_0x00400c; + struct hwsq_reg r_0x00c040; + struct hwsq_reg r_0x100210; + struct hwsq_reg r_0x1002d0; + struct hwsq_reg r_0x1002d4; + struct hwsq_reg r_0x1002dc; + struct hwsq_reg r_0x100da0[8]; + struct hwsq_reg r_0x100e20; + struct hwsq_reg r_0x100e24; + struct hwsq_reg r_0x611200; + struct hwsq_reg r_timing[9]; + struct hwsq_reg r_mr[4]; +}; + +struct nv50_ram { + struct nouveau_ram base; + struct nv50_ramseq hwsq; +}; + +#define QFX5800NVA0 1 + +static int +nv50_ram_calc(struct nouveau_fb *pfb, u32 freq) +{ + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nv50_ram *ram = (void *)pfb->ram; + struct nv50_ramseq *hwsq = &ram->hwsq; + struct nvbios_perfE perfE; + struct nvbios_pll mpll; + struct { + u32 data; + u8 size; + } ramcfg, timing; + u8 ver, hdr, cnt, len, strap; + int N1, M1, N2, M2, P; + int ret, i; + + /* lookup closest matching performance table entry for frequency */ + i = 0; + do { + ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt, + &ramcfg.size, &perfE); + if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) || + (ramcfg.size < 2)) { + nv_error(pfb, "invalid/missing perftab entry\n"); + return -EINVAL; + } + } while (perfE.memory < freq); + + /* locate specific data set for the attached memory */ + strap = nvbios_ramcfg_index(nv_subdev(pfb)); + if (strap >= cnt) { + nv_error(pfb, "invalid ramcfg strap\n"); + return -EINVAL; + } + + ramcfg.data += hdr + (strap * ramcfg.size); + + /* 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, &hdr, + &cnt, &len); + if (!timing.data || ver != 0x10 || hdr < 0x12) { + nv_error(pfb, "invalid/missing timing entry " + "%02x %04x %02x %02x\n", + strap, timing.data, ver, hdr); + return -EINVAL; + } + } else { + timing.data = 0; + } + + ret = ram_init(hwsq, nv_subdev(pfb)); + if (ret) + return ret; + + ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */ + ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */ + ram_wr32(hwsq, 0x611200, 0x00003300); + ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */ + ram_nsec(hwsq, 8000); + ram_setf(hwsq, 0x10, 0x00); /* disable fb */ + ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */ + + ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */ + ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */ + ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */ + ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */ + ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */ + + ret = nvbios_pll_parse(bios, 0x004008, &mpll); + mpll.vco2.max_freq = 0; + if (ret == 0) { + ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq, + &N1, &M1, &N2, &M2, &P); + if (ret == 0) + ret = -EINVAL; + } + + if (ret < 0) + return ret; + + ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000); + ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200); + ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1); + ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) | + (P << 22) | (P << 16)); +#if QFX5800NVA0 + for (i = 0; i < 8; i++) + ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/ +#endif + ram_nsec(hwsq, 96000); /*XXX*/ + ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000); + + ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */ + ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */ + + ram_nsec(hwsq, 12000); + + switch (ram->base.type) { + case NV_MEM_TYPE_DDR2: + ram_nuke(hwsq, mr[0]); /* force update */ + ram_mask(hwsq, mr[0], 0x000, 0x000); + break; + case NV_MEM_TYPE_GDDR3: + ram_mask(hwsq, mr[2], 0x000, 0x000); + ram_nuke(hwsq, mr[0]); /* force update */ + ram_mask(hwsq, mr[0], 0x000, 0x000); + break; + default: + break; + } + + ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/ + + ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/ + +#if QFX5800NVA0 + ram_nuke(hwsq, 0x100e24); + ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000); + ram_nuke(hwsq, 0x100e20); + ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000); +#endif + + ram_mask(hwsq, mr[0], 0x100, 0x100); + ram_mask(hwsq, mr[0], 0x100, 0x000); + + ram_setf(hwsq, 0x10, 0x01); /* enable fb */ + ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */ + ram_wr32(hwsq, 0x611200, 0x00003330); + ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */ + return 0; +} + +static int +nv50_ram_prog(struct nouveau_fb *pfb) +{ + struct nouveau_device *device = nv_device(pfb); + struct nv50_ram *ram = (void *)pfb->ram; + struct nv50_ramseq *hwsq = &ram->hwsq; + + ram_exec(hwsq, nouveau_boolopt(device->cfgopt, "NvMemExec", true)); + return 0; +} + +static void +nv50_ram_tidy(struct nouveau_fb *pfb) +{ + struct nv50_ram *ram = (void *)pfb->ram; + struct nv50_ramseq *hwsq = &ram->hwsq; + ram_exec(hwsq, false); +} void __nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem) @@ -57,7 +254,7 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) kfree(mem); } -static int +int nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, u32 memtype, struct nouveau_mem **pmem) { @@ -160,77 +357,114 @@ nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram) return rblock_size; } -static int -nv50_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 datasize, - struct nouveau_object **pobject) +int +nv50_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) { - struct nouveau_fb *pfb = nouveau_fb(parent); - struct nouveau_device *device = nv_device(pfb); - struct nouveau_bios *bios = nouveau_bios(device); - struct nouveau_ram *ram; const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 size; + struct nouveau_bios *bios = nouveau_bios(parent); + struct nouveau_fb *pfb = nouveau_fb(parent); + struct nouveau_ram *ram; int ret; - ret = nouveau_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + ret = nouveau_ram_create_(parent, engine, oclass, length, pobject); + ram = *pobject; if (ret) return ret; ram->size = nv_rd32(pfb, 0x10020c); - ram->size = (ram->size & 0xffffff00) | - ((ram->size & 0x000000ff) << 32); - - size = (ram->size >> 12) - rsvd_head - rsvd_tail; - switch (device->chipset) { - case 0xaa: - case 0xac: - case 0xaf: /* IGPs, no reordering, no real VRAM */ - ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1); - if (ret) - return ret; + ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); - ram->type = NV_MEM_TYPE_STOLEN; - ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12; + switch (nv_rd32(pfb, 0x100714) & 0x00000007) { + case 0: ram->type = NV_MEM_TYPE_DDR1; break; + case 1: + if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) + ram->type = NV_MEM_TYPE_DDR3; + else + ram->type = NV_MEM_TYPE_DDR2; break; + case 2: ram->type = NV_MEM_TYPE_GDDR3; break; + case 3: ram->type = NV_MEM_TYPE_GDDR4; break; + case 4: ram->type = NV_MEM_TYPE_GDDR5; break; default: - switch (nv_rd32(pfb, 0x100714) & 0x00000007) { - case 0: ram->type = NV_MEM_TYPE_DDR1; break; - case 1: - if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) - ram->type = NV_MEM_TYPE_DDR3; - else - ram->type = NV_MEM_TYPE_DDR2; - break; - case 2: ram->type = NV_MEM_TYPE_GDDR3; break; - case 3: ram->type = NV_MEM_TYPE_GDDR4; break; - case 4: ram->type = NV_MEM_TYPE_GDDR5; break; - default: - break; - } - - ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, - nv50_fb_vram_rblock(pfb, ram) >> 12); - if (ret) - return ret; - - ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; - ram->tags = nv_rd32(pfb, 0x100320); break; } + ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) - + (rsvd_head + rsvd_tail), + nv50_fb_vram_rblock(pfb, ram) >> 12); + if (ret) + return ret; + + ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; + ram->tags = nv_rd32(pfb, 0x100320); ram->get = nv50_ram_get; ram->put = nv50_ram_put; return 0; } +static int +nv50_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 datasize, + struct nouveau_object **pobject) +{ + struct nv50_ram *ram; + int ret, i; + + ret = nv50_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + switch (ram->base.type) { + case NV_MEM_TYPE_DDR2: + case NV_MEM_TYPE_GDDR3: + ram->base.calc = nv50_ram_calc; + ram->base.prog = nv50_ram_prog; + ram->base.tidy = nv50_ram_tidy; + break; + default: + nv_warn(ram, "reclocking of this ram type unsupported\n"); + return 0; + } + + ram->hwsq.r_0x002504 = hwsq_reg(0x002504); + ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040); + ram->hwsq.r_0x004008 = hwsq_reg(0x004008); + ram->hwsq.r_0x00400c = hwsq_reg(0x00400c); + ram->hwsq.r_0x100210 = hwsq_reg(0x100210); + ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0); + ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4); + ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc); + for (i = 0; i < 8; i++) + ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04)); + ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20); + ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24); + ram->hwsq.r_0x611200 = hwsq_reg(0x611200); + + for (i = 0; i < 9; i++) + ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04)); + + if (ram->base.ranks > 1) { + ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8); + ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc); + ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8); + ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec); + } else { + ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0); + ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4); + ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0); + ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4); + } + + return 0; +} + struct nouveau_oclass nv50_ram_oclass = { - .handle = 0, .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_ram_create, + .ctor = nv50_ram_ctor, .dtor = _nouveau_ram_dtor, .init = _nouveau_ram_init, .fini = _nouveau_ram_fini, diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c new file mode 100644 index 00000000000..8076fb195dd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c @@ -0,0 +1,439 @@ +/* + * 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/pll.h> +#include <subdev/bios/rammap.h> +#include <subdev/bios/timing.h> + +#include <subdev/clock/nva3.h> +#include <subdev/clock/pll.h> + +#include <core/option.h> + +#include "ramfuc.h" + +#include "nv50.h" + +struct nva3_ramfuc { + struct ramfuc base; + struct ramfuc_reg r_0x004000; + struct ramfuc_reg r_0x004004; + struct ramfuc_reg r_0x004018; + struct ramfuc_reg r_0x004128; + struct ramfuc_reg r_0x004168; + struct ramfuc_reg r_0x100200; + struct ramfuc_reg r_0x100210; + struct ramfuc_reg r_0x100220[9]; + struct ramfuc_reg r_0x1002d0; + struct ramfuc_reg r_0x1002d4; + struct ramfuc_reg r_0x1002dc; + struct ramfuc_reg r_0x10053c; + struct ramfuc_reg r_0x1005a0; + struct ramfuc_reg r_0x1005a4; + struct ramfuc_reg r_0x100714; + struct ramfuc_reg r_0x100718; + struct ramfuc_reg r_0x10071c; + struct ramfuc_reg r_0x100760; + struct ramfuc_reg r_0x1007a0; + struct ramfuc_reg r_0x1007e0; + struct ramfuc_reg r_0x10f804; + struct ramfuc_reg r_0x1110e0; + struct ramfuc_reg r_0x111100; + struct ramfuc_reg r_0x111104; + struct ramfuc_reg r_0x611200; + struct ramfuc_reg r_mr[4]; +}; + +struct nva3_ram { + struct nouveau_ram base; + struct nva3_ramfuc fuc; +}; + +static int +nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) +{ + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nva3_ram *ram = (void *)pfb->ram; + struct nva3_ramfuc *fuc = &ram->fuc; + struct nva3_clock_info mclk; + u8 ver, cnt, len, strap; + u32 data; + struct { + u32 data; + u8 size; + } rammap, ramcfg, timing; + u32 r004018, r100760, ctrl; + u32 unk714, unk718, unk71c; + int ret; + + /* 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) { + 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)); + if (strap >= cnt) { + nv_error(pfb, "invalid ramcfg strap\n"); + return -EINVAL; + } + + ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); + if (!ramcfg.data || ver != 0x10 || ramcfg.size < 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) { + 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); + if (ret < 0) { + nv_error(pfb, "failed mclk calculation\n"); + return ret; + } + + ret = ram_init(fuc, pfb); + if (ret) + return ret; + + /* XXX: where the fuck does 750MHz come from? */ + if (freq <= 750000) { + r004018 = 0x10000000; + r100760 = 0x22222222; + } else { + r004018 = 0x00000000; + r100760 = 0x00000000; + } + + ctrl = ram_rd32(fuc, 0x004000); + if (ctrl & 0x00000008) { + if (mclk.pll) { + ram_mask(fuc, 0x004128, 0x00000101, 0x00000101); + ram_wr32(fuc, 0x004004, mclk.pll); + ram_wr32(fuc, 0x004000, (ctrl |= 0x00000001)); + ram_wr32(fuc, 0x004000, (ctrl &= 0xffffffef)); + ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000); + ram_wr32(fuc, 0x004000, (ctrl |= 0x00000010)); + ram_wr32(fuc, 0x004018, 0x00005000 | r004018); + ram_wr32(fuc, 0x004000, (ctrl |= 0x00000004)); + } + } else { + u32 ssel = 0x00000101; + if (mclk.clk) + ssel |= mclk.clk; + else + ssel |= 0x00080000; /* 324MHz, shouldn't matter... */ + ram_mask(fuc, 0x004168, 0x003f3141, ctrl); + } + + if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) { + 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)) + ram_mask(fuc, 0x100200, 0x00000800, 0x00000000); + ram_wr32(fuc, 0x611200, 0x00003300); + if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) + ram_wr32(fuc, 0x111100, 0x4c020000); /*XXX*/ + + ram_wr32(fuc, 0x1002d4, 0x00000001); + ram_wr32(fuc, 0x1002d0, 0x00000001); + ram_wr32(fuc, 0x1002d0, 0x00000001); + ram_wr32(fuc, 0x100210, 0x00000000); + ram_wr32(fuc, 0x1002dc, 0x00000001); + ram_nsec(fuc, 2000); + + ctrl = ram_rd32(fuc, 0x004000); + if (!(ctrl & 0x00000008) && mclk.pll) { + ram_wr32(fuc, 0x004000, (ctrl |= 0x00000008)); + ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000); + ram_wr32(fuc, 0x004018, 0x00001000); + ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000001)); + ram_wr32(fuc, 0x004004, mclk.pll); + ram_wr32(fuc, 0x004000, (ctrl |= 0x00000001)); + udelay(64); + ram_wr32(fuc, 0x004018, 0x00005000 | r004018); + udelay(20); + } else + if (!mclk.pll) { + ram_mask(fuc, 0x004168, 0x003f3040, mclk.clk); + ram_wr32(fuc, 0x004000, (ctrl |= 0x00000008)); + ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000); + 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); + ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000); + } else { + ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000); + ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000); + ram_mask(fuc, 0x100760, 0x22222222, r100760); + ram_mask(fuc, 0x1007a0, 0x22222222, r100760); + ram_mask(fuc, 0x1007e0, 0x22222222, r100760); + } + + if (mclk.pll) { + ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000); + ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000008)); + } + + /*XXX: LEAVE */ + ram_wr32(fuc, 0x1002dc, 0x00000000); + ram_wr32(fuc, 0x1002d4, 0x00000001); + ram_wr32(fuc, 0x100210, 0x80000000); + ram_nsec(fuc, 1000); + ram_nsec(fuc, 1000); + + ram_mask(fuc, mr[2], 0x00000000, 0x00000000); + ram_nsec(fuc, 1000); + ram_nuke(fuc, mr[0]); + ram_mask(fuc, mr[0], 0x00000000, 0x00000000); + ram_nsec(fuc, 1000); + + ram_mask(fuc, 0x100220[3], 0x00000000, 0x00000000); + ram_mask(fuc, 0x100220[1], 0x00000000, 0x00000000); + ram_mask(fuc, 0x100220[6], 0x00000000, 0x00000000); + ram_mask(fuc, 0x100220[7], 0x00000000, 0x00000000); + ram_mask(fuc, 0x100220[2], 0x00000000, 0x00000000); + ram_mask(fuc, 0x100220[4], 0x00000000, 0x00000000); + ram_mask(fuc, 0x100220[5], 0x00000000, 0x00000000); + 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); + + 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)) + unk714 |= 0xf0000000; + if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x04)) + unk714 |= 0x00000010; + ram_wr32(fuc, 0x100714, unk714); + + if (nv_ro08(bios, ramcfg.data + 0x02) & 0x01) + unk71c |= 0x00000100; + ram_wr32(fuc, 0x10071c, unk71c); + + if (nv_ro08(bios, ramcfg.data + 0x02) & 0x02) + unk718 |= 0x00000100; + ram_wr32(fuc, 0x100718, unk718); + + if (nv_ro08(bios, ramcfg.data + 0x02) & 0x10) + ram_wr32(fuc, 0x111100, 0x48000000); /*XXX*/ + + ram_mask(fuc, mr[0], 0x100, 0x100); + ram_nsec(fuc, 1000); + ram_mask(fuc, mr[0], 0x100, 0x000); + ram_nsec(fuc, 1000); + + ram_nsec(fuc, 2000); + ram_nsec(fuc, 12000); + + ram_wr32(fuc, 0x611200, 0x00003330); + if ( (nv_ro08(bios, rammap.data + 0x04) & 0x02)) + ram_mask(fuc, 0x100200, 0x00000800, 0x00000800); + if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) { + ram_mask(fuc, 0x111104, 0x00000180, 0x00000180); + ram_mask(fuc, 0x111100, 0x40000000, 0x00000000); + } else { + ram_mask(fuc, 0x111104, 0x00000600, 0x00000600); + } + + if (mclk.pll) { + ram_mask(fuc, 0x004168, 0x00000001, 0x00000000); + ram_mask(fuc, 0x004168, 0x00000100, 0x00000000); + } else { + ram_mask(fuc, 0x004000, 0x00000001, 0x00000000); + ram_mask(fuc, 0x004128, 0x00000001, 0x00000000); + ram_mask(fuc, 0x004128, 0x00000100, 0x00000000); + } + + return 0; +} + +static int +nva3_ram_prog(struct nouveau_fb *pfb) +{ + struct nouveau_device *device = nv_device(pfb); + struct nva3_ram *ram = (void *)pfb->ram; + struct nva3_ramfuc *fuc = &ram->fuc; + ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true)); + return 0; +} + +static void +nva3_ram_tidy(struct nouveau_fb *pfb) +{ + struct nva3_ram *ram = (void *)pfb->ram; + struct nva3_ramfuc *fuc = &ram->fuc; + ram_exec(fuc, false); +} + +static int +nva3_ram_init(struct nouveau_object *object) +{ + struct nouveau_fb *pfb = (void *)object->parent; + struct nva3_ram *ram = (void *)object; + int ret, i; + + ret = nouveau_ram_init(&ram->base); + if (ret) + return ret; + + /* prepare for ddr link training, and load training patterns */ + switch (ram->base.type) { + case NV_MEM_TYPE_DDR3: { + if (nv_device(pfb)->chipset == 0xa8) { + static const u32 pattern[16] = { + 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, + 0x00000000, 0x11111111, 0x44444444, 0xdddddddd, + 0x33333333, 0x55555555, 0x77777777, 0x66666666, + 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, + }; + + nv_wr32(pfb, 0x100538, 0x10001ff6); /*XXX*/ + nv_wr32(pfb, 0x1005a8, 0x0000ffff); + nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001); + for (i = 0; i < 0x30; i++) { + nv_wr32(pfb, 0x10f8c0, (i << 8) | i); + nv_wr32(pfb, 0x10f8e0, (i << 8) | i); + nv_wr32(pfb, 0x10f900, pattern[i % 16]); + nv_wr32(pfb, 0x10f920, pattern[i % 16]); + } + } + } + break; + default: + break; + } + + return 0; +} + +static int +nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 datasize, + struct nouveau_object **pobject) +{ + struct nva3_ram *ram; + int ret, i; + + ret = nv50_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + switch (ram->base.type) { + case NV_MEM_TYPE_DDR3: + ram->base.calc = nva3_ram_calc; + ram->base.prog = nva3_ram_prog; + ram->base.tidy = nva3_ram_tidy; + break; + default: + nv_warn(ram, "reclocking of this ram type unsupported\n"); + return 0; + } + + ram->fuc.r_0x004000 = ramfuc_reg(0x004000); + ram->fuc.r_0x004004 = ramfuc_reg(0x004004); + ram->fuc.r_0x004018 = ramfuc_reg(0x004018); + ram->fuc.r_0x004128 = ramfuc_reg(0x004128); + ram->fuc.r_0x004168 = ramfuc_reg(0x004168); + ram->fuc.r_0x100200 = ramfuc_reg(0x100200); + ram->fuc.r_0x100210 = ramfuc_reg(0x100210); + for (i = 0; i < 9; i++) + ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4)); + ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0); + ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4); + ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc); + ram->fuc.r_0x10053c = ramfuc_reg(0x10053c); + ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0); + ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4); + 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_0x10f804 = ramfuc_reg(0x10f804); + ram->fuc.r_0x1110e0 = ramfuc_reg(0x1110e0); + ram->fuc.r_0x111100 = ramfuc_reg(0x111100); + ram->fuc.r_0x111104 = ramfuc_reg(0x111104); + ram->fuc.r_0x611200 = ramfuc_reg(0x611200); + + if (ram->base.ranks > 1) { + ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8); + ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc); + ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8); + ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec); + } else { + ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0); + ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4); + ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0); + ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4); + } + + return 0; +} + +struct nouveau_oclass +nva3_ram_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nva3_ram_ctor, + .dtor = _nouveau_ram_dtor, + .init = nva3_ram_init, + .fini = _nouveau_ram_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c new file mode 100644 index 00000000000..00f2ca7e44a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c @@ -0,0 +1,66 @@ +/* + * 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 "nv50.h" + +static int +nvaa_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 datasize, + struct nouveau_object **pobject) +{ + const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ + const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ + struct nouveau_fb *pfb = nouveau_fb(parent); + struct nouveau_ram *ram; + int ret; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + ram->size = nv_rd32(pfb, 0x10020c); + ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); + + ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) - + (rsvd_head + rsvd_tail), 1); + if (ret) + return ret; + + ram->type = NV_MEM_TYPE_STOLEN; + ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12; + ram->get = nv50_ram_get; + ram->put = nv50_ram_put; + return 0; +} + +struct nouveau_oclass +nvaa_ram_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvaa_ram_ctor, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c index cf97c4de4a6..5a6a5027f74 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c @@ -23,9 +23,402 @@ */ #include <subdev/bios.h> +#include <subdev/bios/pll.h> +#include <subdev/bios/rammap.h> +#include <subdev/bios/timing.h> #include <subdev/ltcg.h> -#include "priv.h" +#include <subdev/clock.h> +#include <subdev/clock/pll.h> + +#include <core/option.h> + +#include "ramfuc.h" + +#include "nvc0.h" + +struct nvc0_ramfuc { + struct ramfuc base; + + struct ramfuc_reg r_0x10fe20; + struct ramfuc_reg r_0x10fe24; + struct ramfuc_reg r_0x137320; + struct ramfuc_reg r_0x137330; + + struct ramfuc_reg r_0x132000; + struct ramfuc_reg r_0x132004; + struct ramfuc_reg r_0x132100; + + struct ramfuc_reg r_0x137390; + + struct ramfuc_reg r_0x10f290; + struct ramfuc_reg r_0x10f294; + struct ramfuc_reg r_0x10f298; + struct ramfuc_reg r_0x10f29c; + struct ramfuc_reg r_0x10f2a0; + + struct ramfuc_reg r_0x10f300; + struct ramfuc_reg r_0x10f338; + struct ramfuc_reg r_0x10f340; + struct ramfuc_reg r_0x10f344; + struct ramfuc_reg r_0x10f348; + + struct ramfuc_reg r_0x10f910; + struct ramfuc_reg r_0x10f914; + + struct ramfuc_reg r_0x100b0c; + struct ramfuc_reg r_0x10f050; + struct ramfuc_reg r_0x10f090; + struct ramfuc_reg r_0x10f200; + struct ramfuc_reg r_0x10f210; + struct ramfuc_reg r_0x10f310; + struct ramfuc_reg r_0x10f314; + struct ramfuc_reg r_0x10f610; + struct ramfuc_reg r_0x10f614; + struct ramfuc_reg r_0x10f800; + struct ramfuc_reg r_0x10f808; + struct ramfuc_reg r_0x10f824; + struct ramfuc_reg r_0x10f830; + struct ramfuc_reg r_0x10f988; + struct ramfuc_reg r_0x10f98c; + struct ramfuc_reg r_0x10f990; + struct ramfuc_reg r_0x10f998; + struct ramfuc_reg r_0x10f9b0; + struct ramfuc_reg r_0x10f9b4; + struct ramfuc_reg r_0x10fb04; + struct ramfuc_reg r_0x10fb08; + struct ramfuc_reg r_0x137300; + struct ramfuc_reg r_0x137310; + struct ramfuc_reg r_0x137360; + struct ramfuc_reg r_0x1373ec; + struct ramfuc_reg r_0x1373f0; + struct ramfuc_reg r_0x1373f8; + + struct ramfuc_reg r_0x61c140; + struct ramfuc_reg r_0x611200; + + struct ramfuc_reg r_0x13d8f4; +}; + +struct nvc0_ram { + struct nouveau_ram base; + struct nvc0_ramfuc fuc; + struct nvbios_pll refpll; + struct nvbios_pll mempll; +}; + +static void +nvc0_ram_train(struct nvc0_ramfuc *fuc, u32 magic) +{ + struct nvc0_ram *ram = container_of(fuc, typeof(*ram), fuc); + struct nouveau_fb *pfb = nouveau_fb(ram); + u32 part = nv_rd32(pfb, 0x022438), i; + u32 mask = nv_rd32(pfb, 0x022554); + u32 addr = 0x110974; + + ram_wr32(fuc, 0x10f910, magic); + ram_wr32(fuc, 0x10f914, magic); + + for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) { + if (mask & (1 << i)) + continue; + ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000); + } +} + +static int +nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq) +{ + struct nouveau_clock *clk = nouveau_clock(pfb); + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nvc0_ram *ram = (void *)pfb->ram; + struct nvc0_ramfuc *fuc = &ram->fuc; + u8 ver, cnt, len, strap; + struct { + u32 data; + u8 size; + } rammap, ramcfg, timing; + int ref, div, out; + int from, mode; + int N1, M1, P; + int ret; + + /* 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) { + 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)); + if (strap >= cnt) { + nv_error(pfb, "invalid ramcfg strap\n"); + return -EINVAL; + } + + ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); + if (!ramcfg.data || ver != 0x10 || ramcfg.size < 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) { + nv_error(pfb, "invalid/missing timing entry\n"); + return -EINVAL; + } + } else { + timing.data = 0; + } + + ret = ram_init(fuc, pfb); + if (ret) + return ret; + + /* determine current mclk configuration */ + from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */ + + /* determine target mclk configuration */ + if (!(ram_rd32(fuc, 0x137300) & 0x00000100)) + ref = clk->read(clk, nv_clk_src_sppll0); + else + ref = clk->read(clk, nv_clk_src_sppll1); + div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2; + out = (ref * 2) / (div + 2); + mode = freq != out; + + ram_mask(fuc, 0x137360, 0x00000002, 0x00000000); + + if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) { + ram_nuke(fuc, 0x132000); + ram_mask(fuc, 0x132000, 0x00000002, 0x00000002); + ram_mask(fuc, 0x132000, 0x00000002, 0x00000000); + } + + if (mode == 1) { + ram_nuke(fuc, 0x10fe20); + ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002); + ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000); + } + +// 0x00020034 // 0x0000000a + ram_wr32(fuc, 0x132100, 0x00000001); + + if (mode == 1 && from == 0) { + /* calculate refpll */ + ret = nva3_pll_calc(nv_subdev(pfb), &ram->refpll, + ram->mempll.refclk, &N1, NULL, &M1, &P); + if (ret <= 0) { + nv_error(pfb, "unable to calc refpll\n"); + return ret ? ret : -ERANGE; + } + + ram_wr32(fuc, 0x10fe20, 0x20010000); + ram_wr32(fuc, 0x137320, 0x00000003); + ram_wr32(fuc, 0x137330, 0x81200006); + ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1); + ram_wr32(fuc, 0x10fe20, 0x20010001); + ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000); + + /* calculate mempll */ + ret = nva3_pll_calc(nv_subdev(pfb), &ram->mempll, freq, + &N1, NULL, &M1, &P); + if (ret <= 0) { + nv_error(pfb, "unable to calc refpll\n"); + return ret ? ret : -ERANGE; + } + + ram_wr32(fuc, 0x10fe20, 0x20010005); + ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1); + ram_wr32(fuc, 0x132000, 0x18010101); + ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000); + } else + if (mode == 0) { + ram_wr32(fuc, 0x137300, 0x00000003); + } + + if (from == 0) { + ram_nuke(fuc, 0x10fb04); + ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000); + ram_nuke(fuc, 0x10fb08); + ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000); + ram_wr32(fuc, 0x10f988, 0x2004ff00); + ram_wr32(fuc, 0x10f98c, 0x003fc040); + ram_wr32(fuc, 0x10f990, 0x20012001); + ram_wr32(fuc, 0x10f998, 0x00011a00); + ram_wr32(fuc, 0x13d8f4, 0x00000000); + } else { + ram_wr32(fuc, 0x10f988, 0x20010000); + ram_wr32(fuc, 0x10f98c, 0x00000000); + ram_wr32(fuc, 0x10f990, 0x20012001); + ram_wr32(fuc, 0x10f998, 0x00010a00); + } + + if (from == 0) { +// 0x00020039 // 0x000000ba + } + +// 0x0002003a // 0x00000002 + ram_wr32(fuc, 0x100b0c, 0x00080012); +// 0x00030014 // 0x00000000 // 0x02b5f070 +// 0x00030014 // 0x00010000 // 0x02b5f070 + ram_wr32(fuc, 0x611200, 0x00003300); +// 0x00020034 // 0x0000000a +// 0x00030020 // 0x00000001 // 0x00000000 + + ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000); + ram_wr32(fuc, 0x10f210, 0x00000000); + ram_nsec(fuc, 1000); + if (mode == 0) + nvc0_ram_train(fuc, 0x000c1001); + ram_wr32(fuc, 0x10f310, 0x00000001); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f090, 0x00000061); + ram_wr32(fuc, 0x10f090, 0xc000007f); + ram_nsec(fuc, 1000); + + if (from == 0) { + ram_wr32(fuc, 0x10f824, 0x00007fd4); + } else { + ram_wr32(fuc, 0x1373ec, 0x00020404); + } + + if (mode == 0) { + ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000); + ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000); + ram_wr32(fuc, 0x10f830, 0x41500010); + ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000); + ram_mask(fuc, 0x132100, 0x00000100, 0x00000100); + ram_wr32(fuc, 0x10f050, 0xff000090); + ram_wr32(fuc, 0x1373ec, 0x00020f0f); + ram_wr32(fuc, 0x1373f0, 0x00000003); + ram_wr32(fuc, 0x137310, 0x81201616); + ram_wr32(fuc, 0x132100, 0x00000001); +// 0x00020039 // 0x000000ba + ram_wr32(fuc, 0x10f830, 0x00300017); + ram_wr32(fuc, 0x1373f0, 0x00000001); + ram_wr32(fuc, 0x10f824, 0x00007e77); + ram_wr32(fuc, 0x132000, 0x18030001); + ram_wr32(fuc, 0x10f090, 0x4000007e); + ram_nsec(fuc, 2000); + ram_wr32(fuc, 0x10f314, 0x00000001); + ram_wr32(fuc, 0x10f210, 0x80000000); + ram_wr32(fuc, 0x10f338, 0x00300220); + ram_wr32(fuc, 0x10f300, 0x0000011d); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f290, 0x02060505); + ram_wr32(fuc, 0x10f294, 0x34208288); + ram_wr32(fuc, 0x10f298, 0x44050411); + ram_wr32(fuc, 0x10f29c, 0x0000114c); + ram_wr32(fuc, 0x10f2a0, 0x42e10069); + ram_wr32(fuc, 0x10f614, 0x40044f77); + ram_wr32(fuc, 0x10f610, 0x40044f77); + ram_wr32(fuc, 0x10f344, 0x00600009); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f348, 0x00700008); + ram_wr32(fuc, 0x61c140, 0x19240000); + ram_wr32(fuc, 0x10f830, 0x00300017); + nvc0_ram_train(fuc, 0x80021001); + nvc0_ram_train(fuc, 0x80081001); + ram_wr32(fuc, 0x10f340, 0x00500004); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f830, 0x01300017); + ram_wr32(fuc, 0x10f830, 0x00300017); +// 0x00030020 // 0x00000000 // 0x00000000 +// 0x00020034 // 0x0000000b + ram_wr32(fuc, 0x100b0c, 0x00080028); + ram_wr32(fuc, 0x611200, 0x00003330); + } else { + ram_wr32(fuc, 0x10f800, 0x00001800); + ram_wr32(fuc, 0x13d8f4, 0x00000000); + ram_wr32(fuc, 0x1373ec, 0x00020404); + ram_wr32(fuc, 0x1373f0, 0x00000003); + ram_wr32(fuc, 0x10f830, 0x40700010); + ram_wr32(fuc, 0x10f830, 0x40500010); + ram_wr32(fuc, 0x13d8f4, 0x00000000); + ram_wr32(fuc, 0x1373f8, 0x00000000); + ram_wr32(fuc, 0x132100, 0x00000101); + ram_wr32(fuc, 0x137310, 0x89201616); + ram_wr32(fuc, 0x10f050, 0xff000090); + ram_wr32(fuc, 0x1373ec, 0x00030404); + ram_wr32(fuc, 0x1373f0, 0x00000002); + // 0x00020039 // 0x00000011 + ram_wr32(fuc, 0x132100, 0x00000001); + ram_wr32(fuc, 0x1373f8, 0x00002000); + ram_nsec(fuc, 2000); + ram_wr32(fuc, 0x10f808, 0x7aaa0050); + ram_wr32(fuc, 0x10f830, 0x00500010); + ram_wr32(fuc, 0x10f200, 0x00ce1000); + ram_wr32(fuc, 0x10f090, 0x4000007e); + ram_nsec(fuc, 2000); + ram_wr32(fuc, 0x10f314, 0x00000001); + ram_wr32(fuc, 0x10f210, 0x80000000); + ram_wr32(fuc, 0x10f338, 0x00300200); + ram_wr32(fuc, 0x10f300, 0x0000084d); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f290, 0x0b343825); + ram_wr32(fuc, 0x10f294, 0x3483028e); + ram_wr32(fuc, 0x10f298, 0x440c0600); + ram_wr32(fuc, 0x10f29c, 0x0000214c); + ram_wr32(fuc, 0x10f2a0, 0x42e20069); + ram_wr32(fuc, 0x10f200, 0x00ce0000); + ram_wr32(fuc, 0x10f614, 0x60044e77); + ram_wr32(fuc, 0x10f610, 0x60044e77); + ram_wr32(fuc, 0x10f340, 0x00500000); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f344, 0x00600228); + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f348, 0x00700000); + ram_wr32(fuc, 0x13d8f4, 0x00000000); + ram_wr32(fuc, 0x61c140, 0x09a40000); + + nvc0_ram_train(fuc, 0x800e1008); + + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f800, 0x00001804); + // 0x00030020 // 0x00000000 // 0x00000000 + // 0x00020034 // 0x0000000b + ram_wr32(fuc, 0x13d8f4, 0x00000000); + ram_wr32(fuc, 0x100b0c, 0x00080028); + ram_wr32(fuc, 0x611200, 0x00003330); + ram_nsec(fuc, 100000); + ram_wr32(fuc, 0x10f9b0, 0x05313f41); + ram_wr32(fuc, 0x10f9b4, 0x00002f50); + + nvc0_ram_train(fuc, 0x010c1001); + } + + ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800); +// 0x00020016 // 0x00000000 + + if (mode == 0) + ram_mask(fuc, 0x132000, 0x00000001, 0x00000000); + return 0; +} + +static int +nvc0_ram_prog(struct nouveau_fb *pfb) +{ + struct nouveau_device *device = nv_device(pfb); + struct nvc0_ram *ram = (void *)pfb->ram; + struct nvc0_ramfuc *fuc = &ram->fuc; + ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true)); + return 0; +} + +static void +nvc0_ram_tidy(struct nouveau_fb *pfb) +{ + struct nvc0_ram *ram = (void *)pfb->ram; + struct nvc0_ramfuc *fuc = &ram->fuc; + ram_exec(fuc, false); +} extern const u8 nvc0_pte_storage_type_map[256]; @@ -110,10 +503,10 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, return 0; } -static int -nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +int +nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, u32 maskaddr, int size, + void **pobject) { struct nouveau_fb *pfb = nouveau_fb(parent); struct nouveau_bios *bios = nouveau_bios(pfb); @@ -121,14 +514,14 @@ nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ u32 parts = nv_rd32(pfb, 0x022438); - u32 pmask = nv_rd32(pfb, 0x022554); + u32 pmask = nv_rd32(pfb, maskaddr); u32 bsize = nv_rd32(pfb, 0x10f20c); u32 offset, length; bool uniform = true; int ret, part; - ret = nouveau_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + ret = nouveau_ram_create_(parent, engine, oclass, size, pobject); + ram = *pobject; if (ret) return ret; @@ -182,13 +575,158 @@ nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } +static int +nvc0_ram_init(struct nouveau_object *object) +{ + struct nouveau_fb *pfb = (void *)object->parent; + struct nvc0_ram *ram = (void *)object; + int ret, i; + + ret = nouveau_ram_init(&ram->base); + if (ret) + return ret; + + /* prepare for ddr link training, and load training patterns */ + switch (ram->base.type) { + case NV_MEM_TYPE_GDDR5: { + static const u8 train0[] = { + 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, + 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + }; + static const u32 train1[] = { + 0x00000000, 0xffffffff, + 0x55555555, 0xaaaaaaaa, + 0x33333333, 0xcccccccc, + 0xf0f0f0f0, 0x0f0f0f0f, + 0x00ff00ff, 0xff00ff00, + 0x0000ffff, 0xffff0000, + }; + + for (i = 0; i < 0x30; i++) { + nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8)); + nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8)); + nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]); + nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]); + nv_wr32(pfb, 0x10f918, train1[i % 12]); + nv_wr32(pfb, 0x10f91c, train1[i % 12]); + nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]); + nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]); + nv_wr32(pfb, 0x10f918, train1[i % 12]); + nv_wr32(pfb, 0x10f91c, train1[i % 12]); + } + } break; + default: + break; + } + + return 0; +} + +static int +nvc0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_bios *bios = nouveau_bios(parent); + struct nvc0_ram *ram; + int ret; + + ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll); + if (ret) { + nv_error(ram, "mclk refpll data not found\n"); + return ret; + } + + ret = nvbios_pll_parse(bios, 0x04, &ram->mempll); + if (ret) { + nv_error(ram, "mclk pll data not found\n"); + return ret; + } + + switch (ram->base.type) { + case NV_MEM_TYPE_GDDR5: + ram->base.calc = nvc0_ram_calc; + ram->base.prog = nvc0_ram_prog; + ram->base.tidy = nvc0_ram_tidy; + break; + default: + nv_warn(ram, "reclocking of this ram type unsupported\n"); + return 0; + } + + ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20); + ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24); + ram->fuc.r_0x137320 = ramfuc_reg(0x137320); + ram->fuc.r_0x137330 = ramfuc_reg(0x137330); + + ram->fuc.r_0x132000 = ramfuc_reg(0x132000); + ram->fuc.r_0x132004 = ramfuc_reg(0x132004); + ram->fuc.r_0x132100 = ramfuc_reg(0x132100); + + ram->fuc.r_0x137390 = ramfuc_reg(0x137390); + + ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290); + ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294); + ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298); + ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c); + ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0); + + ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300); + ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338); + ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340); + ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344); + ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348); + + ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910); + ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914); + + ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c); + ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050); + ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090); + ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200); + ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210); + ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310); + ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314); + ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610); + ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614); + ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800); + ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808); + ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824); + ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830); + ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988); + ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c); + ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990); + ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998); + ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0); + ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4); + ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04); + ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08); + ram->fuc.r_0x137310 = ramfuc_reg(0x137300); + ram->fuc.r_0x137310 = ramfuc_reg(0x137310); + ram->fuc.r_0x137360 = ramfuc_reg(0x137360); + ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec); + ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0); + ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8); + + ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140); + ram->fuc.r_0x611200 = ramfuc_reg(0x611200); + + ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4); + return 0; +} + struct nouveau_oclass nvc0_ram_oclass = { .handle = 0, .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_ram_create, + .ctor = nvc0_ram_ctor, .dtor = _nouveau_ram_dtor, - .init = _nouveau_ram_init, + .init = nvc0_ram_init, .fini = _nouveau_ram_fini, } }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c new file mode 100644 index 00000000000..c5b46e30231 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c @@ -0,0 +1,1392 @@ +/* + * 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/gpio.h> + +#include <subdev/bios.h> +#include <subdev/bios/pll.h> +#include <subdev/bios/init.h> +#include <subdev/bios/rammap.h> +#include <subdev/bios/timing.h> + +#include <subdev/clock.h> +#include <subdev/clock/pll.h> + +#include <subdev/timer.h> + +#include <core/option.h> + +#include "nvc0.h" + +#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; + + struct nvbios_pll refpll; + struct nvbios_pll mempll; + + struct ramfuc_reg r_gpioMV; + u32 r_funcMV[2]; + struct ramfuc_reg r_gpio2E; + u32 r_func2E[2]; + struct ramfuc_reg r_gpiotrig; + + struct ramfuc_reg r_0x132020; + struct ramfuc_reg r_0x132028; + struct ramfuc_reg r_0x132024; + struct ramfuc_reg r_0x132030; + struct ramfuc_reg r_0x132034; + struct ramfuc_reg r_0x132000; + struct ramfuc_reg r_0x132004; + struct ramfuc_reg r_0x132040; + + struct ramfuc_reg r_0x10f248; + struct ramfuc_reg r_0x10f290; + struct ramfuc_reg r_0x10f294; + struct ramfuc_reg r_0x10f298; + struct ramfuc_reg r_0x10f29c; + struct ramfuc_reg r_0x10f2a0; + struct ramfuc_reg r_0x10f2a4; + struct ramfuc_reg r_0x10f2a8; + struct ramfuc_reg r_0x10f2ac; + struct ramfuc_reg r_0x10f2cc; + struct ramfuc_reg r_0x10f2e8; + struct ramfuc_reg r_0x10f250; + struct ramfuc_reg r_0x10f24c; + struct ramfuc_reg r_0x10fec4; + struct ramfuc_reg r_0x10fec8; + struct ramfuc_reg r_0x10f604; + struct ramfuc_reg r_0x10f614; + struct ramfuc_reg r_0x10f610; + struct ramfuc_reg r_0x100770; + struct ramfuc_reg r_0x100778; + struct ramfuc_reg r_0x10f224; + + struct ramfuc_reg r_0x10f870; + struct ramfuc_reg r_0x10f698; + struct ramfuc_reg r_0x10f694; + struct ramfuc_reg r_0x10f6b8; + struct ramfuc_reg r_0x10f808; + struct ramfuc_reg r_0x10f670; + struct ramfuc_reg r_0x10f60c; + struct ramfuc_reg r_0x10f830; + struct ramfuc_reg r_0x1373ec; + struct ramfuc_reg r_0x10f800; + struct ramfuc_reg r_0x10f82c; + + struct ramfuc_reg r_0x10f978; + struct ramfuc_reg r_0x10f910; + struct ramfuc_reg r_0x10f914; + + struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */ + + struct ramfuc_reg r_0x62c000; + + struct ramfuc_reg r_0x10f200; + + struct ramfuc_reg r_0x10f210; + struct ramfuc_reg r_0x10f310; + struct ramfuc_reg r_0x10f314; + struct ramfuc_reg r_0x10f318; + struct ramfuc_reg r_0x10f090; + struct ramfuc_reg r_0x10f69c; + struct ramfuc_reg r_0x10f824; + struct ramfuc_reg r_0x1373f0; + struct ramfuc_reg r_0x1373f4; + struct ramfuc_reg r_0x137320; + struct ramfuc_reg r_0x10f65c; + struct ramfuc_reg r_0x10f6bc; + struct ramfuc_reg r_0x100710; + struct ramfuc_reg r_0x100750; +}; + +struct nve0_ram { + struct nouveau_ram base; + struct nve0_ramfuc fuc; + + u32 parts; + u32 pmask; + u32 pnuts; + + int from; + int mode; + int N1, fN1, M1, P1; + int N2, M2, P2; +}; + +/******************************************************************************* + * GDDR5 + ******************************************************************************/ +static void +nve0_ram_train(struct nve0_ramfuc *fuc, u32 mask, u32 data) +{ + struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc); + u32 addr = 0x110974, i; + + ram_mask(fuc, 0x10f910, mask, data); + ram_mask(fuc, 0x10f914, mask, data); + + for (i = 0; (data & 0x80000000) && i < ram->parts; addr += 0x1000, i++) { + if (ram->pmask & (1 << i)) + continue; + ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000); + } +} + +static void +r1373f4_init(struct nve0_ramfuc *fuc) +{ + struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc); + const u32 mcoef = ((--ram->P2 << 28) | (ram->N2 << 8) | ram->M2); + const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1); + const u32 runk0 = ram->fN1 << 16; + const u32 runk1 = ram->fN1; + + if (ram->from == 2) { + ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100); + ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010); + } else { + ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010); + } + + ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000); + ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000); + + /* (re)program refpll, if required */ + if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef || + (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) { + ram_mask(fuc, 0x132000, 0x00000001, 0x00000000); + ram_mask(fuc, 0x132020, 0x00000001, 0x00000000); + ram_wr32(fuc, 0x137320, 0x00000000); + ram_mask(fuc, 0x132030, 0xffff0000, runk0); + ram_mask(fuc, 0x132034, 0x0000ffff, runk1); + ram_wr32(fuc, 0x132024, rcoef); + ram_mask(fuc, 0x132028, 0x00080000, 0x00080000); + ram_mask(fuc, 0x132020, 0x00000001, 0x00000001); + ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000); + ram_mask(fuc, 0x132028, 0x00080000, 0x00000000); + } + + /* (re)program mempll, if required */ + if (ram->mode == 2) { + ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000); + ram_mask(fuc, 0x132000, 0x80000000, 0x80000000); + ram_mask(fuc, 0x132000, 0x00000001, 0x00000000); + ram_mask(fuc, 0x132004, 0x103fffff, mcoef); + ram_mask(fuc, 0x132000, 0x00000001, 0x00000001); + ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000); + ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100); + } else { + ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010100); + } + + ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010); +} + +static void +r1373f4_fini(struct nve0_ramfuc *fuc) +{ + struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc); + struct nouveau_ram_data *next = ram->base.next; + u8 v0 = next->bios.ramcfg_11_03_c0; + u8 v1 = next->bios.ramcfg_11_03_30; + u32 tmp; + + tmp = ram_rd32(fuc, 0x1373ec) & ~0x00030000; + ram_wr32(fuc, 0x1373ec, tmp | (v1 << 16)); + ram_mask(fuc, 0x1373f0, (~ram->mode & 3), 0x00000000); + if (ram->mode == 2) { + ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000002); + ram_mask(fuc, 0x1373f4, 0x00001100, 0x000000000); + } else { + ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000001); + ram_mask(fuc, 0x1373f4, 0x00010000, 0x000000000); + } + ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4); +} + +static void +nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg, + u32 _mask, u32 _data, u32 _copy) +{ + struct nve0_fb_priv *priv = (void *)nouveau_fb(ram); + struct ramfuc *fuc = &ram->fuc.base; + u32 addr = 0x110000 + (reg->addr[0] & 0xfff); + u32 mask = _mask | _copy; + u32 data = (_data & _mask) | (reg->data & _copy); + u32 i; + + for (i = 0; i < 16; i++, addr += 0x1000) { + if (ram->pnuts & (1 << i)) { + u32 prev = nv_rd32(priv, addr); + u32 next = (prev & ~mask) | data; + nouveau_memx_wr32(fuc->memx, addr, next); + } + } +} +#define ram_nuts(s,r,m,d,c) \ + nve0_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c)) + +static int +nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq) +{ + struct nve0_ram *ram = (void *)pfb->ram; + struct nve0_ramfuc *fuc = &ram->fuc; + struct nouveau_ram_data *next = ram->base.next; + int vc = !next->bios.ramcfg_11_02_08; + int mv = !next->bios.ramcfg_11_02_04; + u32 mask, data; + + ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); + ram_wr32(fuc, 0x62c000, 0x0f0f0000); + + /* MR1: turn termination on early, for some reason.. */ + if ((ram->base.mr[1] & 0x03c) != 0x030) { + ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c); + ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000); + } + + if (vc == 1 && ram_have(fuc, gpio2E)) { + u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]); + if (temp != ram_rd32(fuc, gpio2E)) { + ram_wr32(fuc, gpiotrig, 1); + ram_nsec(fuc, 20000); + } + } + + ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000); + + nve0_ram_train(fuc, 0x01020000, 0x000c0000); + + ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */ + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */ + ram_nsec(fuc, 1000); + + ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000); + ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */ + ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000); + ram_wr32(fuc, 0x10f090, 0x00000061); + ram_wr32(fuc, 0x10f090, 0xc000007f); + ram_nsec(fuc, 1000); + + ram_wr32(fuc, 0x10f698, 0x00000000); + ram_wr32(fuc, 0x10f69c, 0x00000000); + + /*XXX: there does appear to be some kind of condition here, simply + * modifying these bits in the vbios from the default pl0 + * entries shows no change. however, the data does appear to + * be correct and may be required for the transition back + */ + mask = 0x800f07e0; + data = 0x00030000; + if (ram_rd32(fuc, 0x10f978) & 0x00800000) + data |= 0x00040000; + + if (1) { + data |= 0x800807e0; + switch (next->bios.ramcfg_11_03_c0) { + case 3: data &= ~0x00000040; break; + case 2: data &= ~0x00000100; break; + case 1: data &= ~0x80000000; break; + case 0: data &= ~0x00000400; break; + } + + switch (next->bios.ramcfg_11_03_30) { + case 3: data &= ~0x00000020; break; + case 2: data &= ~0x00000080; break; + case 1: data &= ~0x00080000; break; + case 0: data &= ~0x00000200; break; + } + } + + if (next->bios.ramcfg_11_02_80) + mask |= 0x03000000; + if (next->bios.ramcfg_11_02_40) + mask |= 0x00002000; + if (next->bios.ramcfg_11_07_10) + mask |= 0x00004000; + if (next->bios.ramcfg_11_07_08) + mask |= 0x00000003; + else { + mask |= 0x34000000; + if (ram_rd32(fuc, 0x10f978) & 0x00800000) + mask |= 0x40000000; + } + ram_mask(fuc, 0x10f824, mask, data); + + ram_mask(fuc, 0x132040, 0x00010000, 0x00000000); + + if (ram->from == 2 && ram->mode != 2) { + ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000); + ram_mask(fuc, 0x10f200, 0x18008000, 0x00008000); + ram_mask(fuc, 0x10f800, 0x00000000, 0x00000004); + ram_mask(fuc, 0x10f830, 0x00008000, 0x01040010); + ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000); + r1373f4_init(fuc); + ram_mask(fuc, 0x1373f0, 0x00000002, 0x00000001); + r1373f4_fini(fuc); + ram_mask(fuc, 0x10f830, 0x00c00000, 0x00240001); + } else + if (ram->from != 2 && ram->mode != 2) { + r1373f4_init(fuc); + r1373f4_fini(fuc); + } + + if (ram_have(fuc, gpioMV)) { + u32 temp = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]); + if (temp != ram_rd32(fuc, gpioMV)) { + ram_wr32(fuc, gpiotrig, 1); + ram_nsec(fuc, 64000); + } + } + + if (next->bios.ramcfg_11_02_40 || + next->bios.ramcfg_11_07_10) { + ram_mask(fuc, 0x132040, 0x00010000, 0x00010000); + ram_nsec(fuc, 20000); + } + + if (ram->from != 2 && ram->mode == 2) { + if (0 /*XXX: Titan */) + ram_mask(fuc, 0x10f200, 0x18000000, 0x18000000); + ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000); + ram_mask(fuc, 0x1373f0, 0x00000000, 0x00000002); + ram_mask(fuc, 0x10f830, 0x00800001, 0x00408010); + r1373f4_init(fuc); + r1373f4_fini(fuc); + ram_mask(fuc, 0x10f808, 0x00000000, 0x00080000); + ram_mask(fuc, 0x10f200, 0x00808000, 0x00800000); + } else + if (ram->from == 2 && ram->mode == 2) { + ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000); + r1373f4_init(fuc); + r1373f4_fini(fuc); + } + + if (ram->mode != 2) /*XXX*/ { + if (next->bios.ramcfg_11_07_40) + ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000); + } + + ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c); + ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09); + ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09); + + if (!next->bios.ramcfg_11_07_08 && !next->bios.ramcfg_11_07_04) { + ram_wr32(fuc, 0x10f698, 0x01010101 * next->bios.ramcfg_11_04); + ram_wr32(fuc, 0x10f69c, 0x01010101 * next->bios.ramcfg_11_04); + } else + if (!next->bios.ramcfg_11_07_08) { + ram_wr32(fuc, 0x10f698, 0x00000000); + ram_wr32(fuc, 0x10f69c, 0x00000000); + } + + if (ram->mode != 2) { + u32 data = 0x01000100 * next->bios.ramcfg_11_04; + ram_nuke(fuc, 0x10f694); + ram_mask(fuc, 0x10f694, 0xff00ff00, data); + } + + if (ram->mode == 2 && next->bios.ramcfg_11_08_10) + data = 0x00000080; + else + data = 0x00000000; + ram_mask(fuc, 0x10f60c, 0x00000080, data); + + mask = 0x00070000; + data = 0x00000000; + if (!next->bios.ramcfg_11_02_80) + data |= 0x03000000; + if (!next->bios.ramcfg_11_02_40) + data |= 0x00002000; + if (!next->bios.ramcfg_11_07_10) + data |= 0x00004000; + if (!next->bios.ramcfg_11_07_08) + data |= 0x00000003; + else + data |= 0x74000000; + ram_mask(fuc, 0x10f824, mask, data); + + if (next->bios.ramcfg_11_01_08) + data = 0x00000000; + else + data = 0x00001000; + ram_mask(fuc, 0x10f200, 0x00001000, data); + + if (ram_rd32(fuc, 0x10f670) & 0x80000000) { + ram_nsec(fuc, 10000); + ram_mask(fuc, 0x10f670, 0x80000000, 0x00000000); + } + + if (next->bios.ramcfg_11_08_01) + data = 0x00100000; + else + data = 0x00000000; + ram_mask(fuc, 0x10f82c, 0x00100000, data); + + data = 0x00000000; + if (next->bios.ramcfg_11_08_08) + data |= 0x00002000; + if (next->bios.ramcfg_11_08_04) + data |= 0x00001000; + if (next->bios.ramcfg_11_08_02) + data |= 0x00004000; + ram_mask(fuc, 0x10f830, 0x00007000, data); + + /* PFB timing */ + ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]); + ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]); + ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]); + ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]); + ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]); + ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]); + ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]); + ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]); + ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]); + ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]); + ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]); + + data = mask = 0x00000000; + if (NOTE00(ramcfg_08_20)) { + if (next->bios.ramcfg_11_08_20) + data |= 0x01000000; + mask |= 0x01000000; + } + ram_mask(fuc, 0x10f200, mask, data); + + data = mask = 0x00000000; + if (NOTE00(ramcfg_02_03 != 0)) { + data |= next->bios.ramcfg_11_02_03 << 8; + mask |= 0x00000300; + } + if (NOTE00(ramcfg_01_10)) { + if (next->bios.ramcfg_11_01_10) + data |= 0x70000000; + mask |= 0x70000000; + } + ram_mask(fuc, 0x10f604, mask, data); + + data = mask = 0x00000000; + if (NOTE00(timing_30_07 != 0)) { + data |= next->bios.timing_20_30_07 << 28; + mask |= 0x70000000; + } + if (NOTE00(ramcfg_01_01)) { + if (next->bios.ramcfg_11_01_01) + data |= 0x00000100; + mask |= 0x00000100; + } + ram_mask(fuc, 0x10f614, mask, data); + + data = mask = 0x00000000; + if (NOTE00(timing_30_07 != 0)) { + data |= next->bios.timing_20_30_07 << 28; + mask |= 0x70000000; + } + if (NOTE00(ramcfg_01_02)) { + if (next->bios.ramcfg_11_01_02) + data |= 0x00000100; + mask |= 0x00000100; + } + ram_mask(fuc, 0x10f610, mask, data); + + mask = 0x33f00000; + data = 0x00000000; + if (!next->bios.ramcfg_11_01_04) + data |= 0x20200000; + if (!next->bios.ramcfg_11_07_80) + data |= 0x12800000; + /*XXX: see note above about there probably being some condition + * for the 10f824 stuff that uses ramcfg 3... + */ + if (next->bios.ramcfg_11_03_f0) { + if (next->bios.rammap_11_08_0c) { + if (!next->bios.ramcfg_11_07_80) + mask |= 0x00000020; + else + data |= 0x00000020; + mask |= 0x00000004; + } + } else { + mask |= 0x40000020; + data |= 0x00000004; + } + + ram_mask(fuc, 0x10f808, mask, data); + + ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f); + + data = mask = 0x00000000; + if (NOTE00(ramcfg_02_03 != 0)) { + data |= next->bios.ramcfg_11_02_03; + mask |= 0x00000003; + } + if (NOTE00(ramcfg_01_10)) { + if (next->bios.ramcfg_11_01_10) + data |= 0x00000004; + mask |= 0x00000004; + } + + if ((ram_mask(fuc, 0x100770, mask, data) & mask & 4) != (data & 4)) { + ram_mask(fuc, 0x100750, 0x00000008, 0x00000008); + ram_wr32(fuc, 0x100710, 0x00000000); + ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000); + } + + data = next->bios.timing_20_30_07 << 8; + if (next->bios.ramcfg_11_01_01) + data |= 0x80000000; + ram_mask(fuc, 0x100778, 0x00000700, data); + + ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4); + data = (next->bios.timing[10] & 0x7f000000) >> 24; + if (data < next->bios.timing_20_2c_1fc0) + data = next->bios.timing_20_2c_1fc0; + ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24); + ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16); + + ram_mask(fuc, 0x10fec4, 0x041e0f07, next->bios.timing_20_31_0800 << 26 | + next->bios.timing_20_31_0780 << 17 | + next->bios.timing_20_31_0078 << 8 | + next->bios.timing_20_31_0007); + ram_mask(fuc, 0x10fec8, 0x00000027, next->bios.timing_20_31_8000 << 5 | + next->bios.timing_20_31_7000); + + ram_wr32(fuc, 0x10f090, 0x4000007e); + ram_nsec(fuc, 2000); + ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */ + ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */ + ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */ + + if (next->bios.ramcfg_11_08_10 && (ram->mode == 2) /*XXX*/) { + u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000); + nve0_ram_train(fuc, 0xbc0e0000, 0xa4010000); /*XXX*/ + ram_nsec(fuc, 1000); + ram_wr32(fuc, 0x10f294, temp); + } + + ram_mask(fuc, mr[3], 0xfff, ram->base.mr[3]); + ram_wr32(fuc, mr[0], ram->base.mr[0]); + ram_mask(fuc, mr[8], 0xfff, ram->base.mr[8]); + ram_nsec(fuc, 1000); + ram_mask(fuc, mr[1], 0xfff, ram->base.mr[1]); + ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5] & ~0x004); /* LP3 later */ + ram_mask(fuc, mr[6], 0xfff, ram->base.mr[6]); + ram_mask(fuc, mr[7], 0xfff, ram->base.mr[7]); + + if (vc == 0 && ram_have(fuc, gpio2E)) { + u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]); + if (temp != ram_rd32(fuc, gpio2E)) { + ram_wr32(fuc, gpiotrig, 1); + ram_nsec(fuc, 20000); + } + } + + ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000); + ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */ + ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000); + ram_nsec(fuc, 1000); + ram_nuts(ram, 0x10f200, 0x18808800, 0x00000000, 0x18808800); + + data = ram_rd32(fuc, 0x10f978); + data &= ~0x00046144; + data |= 0x0000000b; + if (!next->bios.ramcfg_11_07_08) { + if (!next->bios.ramcfg_11_07_04) + data |= 0x0000200c; + else + data |= 0x00000000; + } else { + data |= 0x00040044; + } + ram_wr32(fuc, 0x10f978, data); + + if (ram->mode == 1) { + data = ram_rd32(fuc, 0x10f830) | 0x00000001; + ram_wr32(fuc, 0x10f830, data); + } + + if (!next->bios.ramcfg_11_07_08) { + data = 0x88020000; + if ( next->bios.ramcfg_11_07_04) + data |= 0x10000000; + if (!next->bios.rammap_11_08_10) + data |= 0x00080000; + } else { + data = 0xa40e0000; + } + nve0_ram_train(fuc, 0xbc0f0000, data); + if (1) /* XXX: not always? */ + ram_nsec(fuc, 1000); + + if (ram->mode == 2) { /*XXX*/ + ram_mask(fuc, 0x10f800, 0x00000004, 0x00000004); + } + + /* LP3 */ + if (ram_mask(fuc, mr[5], 0x004, ram->base.mr[5]) != ram->base.mr[5]) + ram_nsec(fuc, 1000); + + if (ram->mode != 2) { + ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000); + ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000); + } + + if (next->bios.ramcfg_11_07_02) + nve0_ram_train(fuc, 0x80020000, 0x01000000); + + ram_wr32(fuc, 0x62c000, 0x0f0f0f00); + + if (next->bios.rammap_11_08_01) + data = 0x00000800; + else + data = 0x00000000; + ram_mask(fuc, 0x10f200, 0x00000800, data); + ram_nuts(ram, 0x10f200, 0x18808800, data, 0x18808800); + return 0; +} + +/******************************************************************************* + * DDR3 + ******************************************************************************/ + +static int +nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq) +{ + struct nve0_ram *ram = (void *)pfb->ram; + struct nve0_ramfuc *fuc = &ram->fuc; + const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1); + const u32 runk0 = ram->fN1 << 16; + const u32 runk1 = ram->fN1; + struct nouveau_ram_data *next = ram->base.next; + int vc = !next->bios.ramcfg_11_02_08; + int mv = !next->bios.ramcfg_11_02_04; + u32 mask, data; + + ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); + ram_wr32(fuc, 0x62c000, 0x0f0f0000); + + if (vc == 1 && ram_have(fuc, gpio2E)) { + u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]); + if (temp != ram_rd32(fuc, gpio2E)) { + ram_wr32(fuc, gpiotrig, 1); + ram_nsec(fuc, 20000); + } + } + + ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000); + if (next->bios.ramcfg_11_03_f0) + ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000); + + ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */ + ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */ + ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */ + ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000); + ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */ + ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000); + ram_nsec(fuc, 1000); + + ram_wr32(fuc, 0x10f090, 0x00000060); + ram_wr32(fuc, 0x10f090, 0xc000007e); + + /*XXX: there does appear to be some kind of condition here, simply + * modifying these bits in the vbios from the default pl0 + * entries shows no change. however, the data does appear to + * be correct and may be required for the transition back + */ + mask = 0x00010000; + data = 0x00010000; + + if (1) { + mask |= 0x800807e0; + data |= 0x800807e0; + switch (next->bios.ramcfg_11_03_c0) { + case 3: data &= ~0x00000040; break; + case 2: data &= ~0x00000100; break; + case 1: data &= ~0x80000000; break; + case 0: data &= ~0x00000400; break; + } + + switch (next->bios.ramcfg_11_03_30) { + case 3: data &= ~0x00000020; break; + case 2: data &= ~0x00000080; break; + case 1: data &= ~0x00080000; break; + case 0: data &= ~0x00000200; break; + } + } + + if (next->bios.ramcfg_11_02_80) + mask |= 0x03000000; + if (next->bios.ramcfg_11_02_40) + mask |= 0x00002000; + if (next->bios.ramcfg_11_07_10) + mask |= 0x00004000; + if (next->bios.ramcfg_11_07_08) + mask |= 0x00000003; + else + mask |= 0x14000000; + ram_mask(fuc, 0x10f824, mask, data); + + ram_mask(fuc, 0x132040, 0x00010000, 0x00000000); + + ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010); + data = ram_rd32(fuc, 0x1373ec) & ~0x00030000; + data |= next->bios.ramcfg_11_03_30 << 16; + ram_wr32(fuc, 0x1373ec, data); + ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000); + ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000); + + /* (re)program refpll, if required */ + if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef || + (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) { + ram_mask(fuc, 0x132000, 0x00000001, 0x00000000); + ram_mask(fuc, 0x132020, 0x00000001, 0x00000000); + ram_wr32(fuc, 0x137320, 0x00000000); + ram_mask(fuc, 0x132030, 0xffff0000, runk0); + ram_mask(fuc, 0x132034, 0x0000ffff, runk1); + ram_wr32(fuc, 0x132024, rcoef); + ram_mask(fuc, 0x132028, 0x00080000, 0x00080000); + ram_mask(fuc, 0x132020, 0x00000001, 0x00000001); + ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000); + ram_mask(fuc, 0x132028, 0x00080000, 0x00000000); + } + + ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000010); + ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000001); + ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000); + + if (ram_have(fuc, gpioMV)) { + u32 temp = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]); + if (temp != ram_rd32(fuc, gpioMV)) { + ram_wr32(fuc, gpiotrig, 1); + ram_nsec(fuc, 64000); + } + } + + if (next->bios.ramcfg_11_02_40 || + next->bios.ramcfg_11_07_10) { + ram_mask(fuc, 0x132040, 0x00010000, 0x00010000); + ram_nsec(fuc, 20000); + } + + if (ram->mode != 2) /*XXX*/ { + if (next->bios.ramcfg_11_07_40) + ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000); + } + + ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c); + ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09); + ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09); + + mask = 0x00010000; + data = 0x00000000; + if (!next->bios.ramcfg_11_02_80) + data |= 0x03000000; + if (!next->bios.ramcfg_11_02_40) + data |= 0x00002000; + if (!next->bios.ramcfg_11_07_10) + data |= 0x00004000; + if (!next->bios.ramcfg_11_07_08) + data |= 0x00000003; + else + data |= 0x14000000; + ram_mask(fuc, 0x10f824, mask, data); + ram_nsec(fuc, 1000); + + if (next->bios.ramcfg_11_08_01) + data = 0x00100000; + else + data = 0x00000000; + ram_mask(fuc, 0x10f82c, 0x00100000, data); + + /* PFB timing */ + ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]); + ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]); + ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]); + ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]); + ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]); + ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]); + ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]); + ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]); + ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]); + ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]); + ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]); + + mask = 0x33f00000; + data = 0x00000000; + if (!next->bios.ramcfg_11_01_04) + data |= 0x20200000; + if (!next->bios.ramcfg_11_07_80) + data |= 0x12800000; + /*XXX: see note above about there probably being some condition + * for the 10f824 stuff that uses ramcfg 3... + */ + if (next->bios.ramcfg_11_03_f0) { + if (next->bios.rammap_11_08_0c) { + if (!next->bios.ramcfg_11_07_80) + mask |= 0x00000020; + else + data |= 0x00000020; + mask |= 0x08000004; + } + data |= 0x04000000; + } else { + mask |= 0x44000020; + data |= 0x08000004; + } + + ram_mask(fuc, 0x10f808, mask, data); + + ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f); + + ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4); + + data = (next->bios.timing[10] & 0x7f000000) >> 24; + if (data < next->bios.timing_20_2c_1fc0) + data = next->bios.timing_20_2c_1fc0; + ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24); + + ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16); + + ram_wr32(fuc, 0x10f090, 0x4000007f); + ram_nsec(fuc, 1000); + + ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */ + ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */ + ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */ + ram_nsec(fuc, 1000); + + ram_nuke(fuc, mr[0]); + ram_mask(fuc, mr[0], 0x100, 0x100); + ram_mask(fuc, mr[0], 0x100, 0x000); + + ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]); + ram_wr32(fuc, mr[0], ram->base.mr[0]); + ram_nsec(fuc, 1000); + + ram_nuke(fuc, mr[0]); + ram_mask(fuc, mr[0], 0x100, 0x100); + ram_mask(fuc, mr[0], 0x100, 0x000); + + if (vc == 0 && ram_have(fuc, gpio2E)) { + u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]); + if (temp != ram_rd32(fuc, gpio2E)) { + ram_wr32(fuc, gpiotrig, 1); + ram_nsec(fuc, 20000); + } + } + + if (ram->mode != 2) { + ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000); + ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000); + } + + ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000); + ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */ + ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000); + ram_nsec(fuc, 1000); + + ram_wr32(fuc, 0x62c000, 0x0f0f0f00); + + if (next->bios.rammap_11_08_01) + data = 0x00000800; + else + data = 0x00000000; + ram_mask(fuc, 0x10f200, 0x00000800, data); + return 0; +} + +/******************************************************************************* + * main hooks + ******************************************************************************/ + +static int +nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq, + 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; + } + } else { + ram->base.timing.data = 0; + } + + data->freq = freq; + return 0; +} + +static int +nve0_ram_calc_xits(struct nouveau_fb *pfb, struct nouveau_ram_data *next) +{ + struct nve0_ram *ram = (void *)pfb->ram; + struct nve0_ramfuc *fuc = &ram->fuc; + int refclk, i; + int ret; + + ret = ram_init(fuc, pfb); + if (ret) + return ret; + + ram->mode = (next->freq > fuc->refpll.vco1.max_freq) ? 2 : 1; + ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f; + + /* XXX: this is *not* what nvidia do. on fermi nvidia generally + * select, based on some unknown condition, one of the two possible + * reference frequencies listed in the vbios table for mempll and + * program refpll to that frequency. + * + * so far, i've seen very weird values being chosen by nvidia on + * kepler boards, no idea how/why they're chosen. + */ + refclk = next->freq; + if (ram->mode == 2) + refclk = fuc->mempll.refclk; + + /* calculate refpll coefficients */ + ret = nva3_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1, + &ram->fN1, &ram->M1, &ram->P1); + fuc->mempll.refclk = ret; + if (ret <= 0) { + nv_error(pfb, "unable to calc refpll\n"); + return -EINVAL; + } + + /* calculate mempll coefficients, if we're using it */ + if (ram->mode == 2) { + /* post-divider doesn't work... the reg takes the values but + * appears to completely ignore it. there *is* a bit at + * bit 28 that appears to divide the clock by 2 if set. + */ + fuc->mempll.min_p = 1; + fuc->mempll.max_p = 2; + + ret = nva3_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq, + &ram->N2, NULL, &ram->M2, &ram->P2); + if (ret <= 0) { + nv_error(pfb, "unable to calc mempll\n"); + return -EINVAL; + } + } + + for (i = 0; i < ARRAY_SIZE(fuc->r_mr); i++) { + if (ram_have(fuc, mr[i])) + ram->base.mr[i] = ram_rd32(fuc, mr[i]); + } + ram->base.freq = next->freq; + + switch (ram->base.type) { + case NV_MEM_TYPE_DDR3: + ret = nouveau_sddr3_calc(&ram->base); + if (ret == 0) + ret = nve0_ram_calc_sddr3(pfb, next->freq); + break; + case NV_MEM_TYPE_GDDR5: + ret = nouveau_gddr5_calc(&ram->base, ram->pnuts != 0); + if (ret == 0) + ret = nve0_ram_calc_gddr5(pfb, next->freq); + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} + +static int +nve0_ram_calc(struct nouveau_fb *pfb, u32 freq) +{ + struct nouveau_clock *clk = nouveau_clock(pfb); + struct nve0_ram *ram = (void *)pfb->ram; + struct nouveau_ram_data *xits = &ram->base.xition; + struct nouveau_ram_data *copy; + int ret; + + if (ram->base.next == NULL) { + ret = nve0_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem), + &ram->base.former); + if (ret) + return ret; + + ret = nve0_ram_calc_data(pfb, freq, &ram->base.target); + if (ret) + return ret; + + if (ram->base.target.freq < ram->base.former.freq) { + *xits = ram->base.target; + copy = &ram->base.former; + } else { + *xits = ram->base.former; + copy = &ram->base.target; + } + + xits->bios.ramcfg_11_02_04 = copy->bios.ramcfg_11_02_04; + xits->bios.ramcfg_11_02_03 = copy->bios.ramcfg_11_02_03; + xits->bios.timing_20_30_07 = copy->bios.timing_20_30_07; + + ram->base.next = &ram->base.target; + if (memcmp(xits, &ram->base.former, sizeof(xits->bios))) + ram->base.next = &ram->base.xition; + } else { + BUG_ON(ram->base.next != &ram->base.xition); + ram->base.next = &ram->base.target; + } + + return nve0_ram_calc_xits(pfb, ram->base.next); +} + +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)); + return (ram->base.next == &ram->base.xition); +} + +static void +nve0_ram_tidy(struct nouveau_fb *pfb) +{ + struct nve0_ram *ram = (void *)pfb->ram; + struct nve0_ramfuc *fuc = &ram->fuc; + ram->base.next = NULL; + ram_exec(fuc, false); +} + +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; + + ret = nouveau_ram_init(&ram->base); + if (ret) + return ret; + + /* run a bunch of tables from rammap table. there's actually + * individual pointers for each rammap entry too, but, nvidia + * seem to just run the last two entries' scripts early on in + * their init, and never again.. we'll just run 'em all once + * for now. + * + * i strongly suspect that each script is for a separate mode + * (likely selected by 0x10f65c's lower bits?), and the + * binary driver skips the one that's already been setup by + * the init tables. + */ + data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz); + if (!data || hdr < 0x15) + return -EINVAL; + + cnt = 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); + nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000); + + 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]); + } + + for (i = 0; i < 0x100; i++) { + nv_wr32(pfb, 0x10f968, i); + nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]); + } + + for (i = 0; i < 0x100; i++) { + nv_wr32(pfb, 0x10f96c, i); + nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]); + } + break; + default: + break; + } + + return 0; +} + +static int +nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_fb *pfb = nouveau_fb(parent); + struct nouveau_bios *bios = nouveau_bios(pfb); + struct nouveau_gpio *gpio = nouveau_gpio(pfb); + struct dcb_gpio_func func; + struct nve0_ram *ram; + int ret, i; + u32 tmp; + + ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + switch (ram->base.type) { + case NV_MEM_TYPE_DDR3: + case NV_MEM_TYPE_GDDR5: + ram->base.calc = nve0_ram_calc; + ram->base.prog = nve0_ram_prog; + ram->base.tidy = nve0_ram_tidy; + break; + default: + nv_warn(pfb, "reclocking of this RAM type is unsupported\n"); + break; + } + + /* calculate a mask of differently configured memory partitions, + * because, of course reclocking wasn't complicated enough + * already without having to treat some of them differently to + * the others.... + */ + ram->parts = nv_rd32(pfb, 0x022438); + ram->pmask = nv_rd32(pfb, 0x022554); + ram->pnuts = 0; + for (i = 0, tmp = 0; i < ram->parts; i++) { + if (!(ram->pmask & (1 << i))) { + u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000)); + if (tmp && tmp != cfg1) { + ram->pnuts |= (1 << i); + continue; + } + tmp = cfg1; + } + } + + // 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"); + return ret; + } + + ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll); + if (ret) { + nv_error(pfb, "mclk pll data not found\n"); + return ret; + } + + ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func); + if (ret == 0) { + ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04)); + ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12; + ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12; + } + + ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); + if (ret == 0) { + ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04)); + ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12; + ram->fuc.r_func2E[1] = (func.log[1] ^ 2) << 12; + } + + ram->fuc.r_gpiotrig = ramfuc_reg(0x00d604); + + ram->fuc.r_0x132020 = ramfuc_reg(0x132020); + ram->fuc.r_0x132028 = ramfuc_reg(0x132028); + ram->fuc.r_0x132024 = ramfuc_reg(0x132024); + ram->fuc.r_0x132030 = ramfuc_reg(0x132030); + ram->fuc.r_0x132034 = ramfuc_reg(0x132034); + ram->fuc.r_0x132000 = ramfuc_reg(0x132000); + ram->fuc.r_0x132004 = ramfuc_reg(0x132004); + ram->fuc.r_0x132040 = ramfuc_reg(0x132040); + + ram->fuc.r_0x10f248 = ramfuc_reg(0x10f248); + ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290); + ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294); + ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298); + ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c); + ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0); + ram->fuc.r_0x10f2a4 = ramfuc_reg(0x10f2a4); + ram->fuc.r_0x10f2a8 = ramfuc_reg(0x10f2a8); + ram->fuc.r_0x10f2ac = ramfuc_reg(0x10f2ac); + ram->fuc.r_0x10f2cc = ramfuc_reg(0x10f2cc); + ram->fuc.r_0x10f2e8 = ramfuc_reg(0x10f2e8); + ram->fuc.r_0x10f250 = ramfuc_reg(0x10f250); + ram->fuc.r_0x10f24c = ramfuc_reg(0x10f24c); + ram->fuc.r_0x10fec4 = ramfuc_reg(0x10fec4); + ram->fuc.r_0x10fec8 = ramfuc_reg(0x10fec8); + ram->fuc.r_0x10f604 = ramfuc_reg(0x10f604); + ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614); + ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610); + ram->fuc.r_0x100770 = ramfuc_reg(0x100770); + ram->fuc.r_0x100778 = ramfuc_reg(0x100778); + ram->fuc.r_0x10f224 = ramfuc_reg(0x10f224); + + ram->fuc.r_0x10f870 = ramfuc_reg(0x10f870); + ram->fuc.r_0x10f698 = ramfuc_reg(0x10f698); + ram->fuc.r_0x10f694 = ramfuc_reg(0x10f694); + ram->fuc.r_0x10f6b8 = ramfuc_reg(0x10f6b8); + ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808); + ram->fuc.r_0x10f670 = ramfuc_reg(0x10f670); + ram->fuc.r_0x10f60c = ramfuc_reg(0x10f60c); + ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830); + ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec); + ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800); + ram->fuc.r_0x10f82c = ramfuc_reg(0x10f82c); + + ram->fuc.r_0x10f978 = ramfuc_reg(0x10f978); + ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910); + ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914); + + switch (ram->base.type) { + case NV_MEM_TYPE_GDDR5: + ram->fuc.r_mr[0] = ramfuc_reg(0x10f300); + ram->fuc.r_mr[1] = ramfuc_reg(0x10f330); + ram->fuc.r_mr[2] = ramfuc_reg(0x10f334); + ram->fuc.r_mr[3] = ramfuc_reg(0x10f338); + ram->fuc.r_mr[4] = ramfuc_reg(0x10f33c); + ram->fuc.r_mr[5] = ramfuc_reg(0x10f340); + ram->fuc.r_mr[6] = ramfuc_reg(0x10f344); + ram->fuc.r_mr[7] = ramfuc_reg(0x10f348); + ram->fuc.r_mr[8] = ramfuc_reg(0x10f354); + ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c); + break; + case NV_MEM_TYPE_DDR3: + ram->fuc.r_mr[0] = ramfuc_reg(0x10f300); + ram->fuc.r_mr[2] = ramfuc_reg(0x10f320); + break; + default: + break; + } + + ram->fuc.r_0x62c000 = ramfuc_reg(0x62c000); + ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200); + ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210); + ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310); + ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314); + ram->fuc.r_0x10f318 = ramfuc_reg(0x10f318); + ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090); + ram->fuc.r_0x10f69c = ramfuc_reg(0x10f69c); + ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824); + ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0); + ram->fuc.r_0x1373f4 = ramfuc_reg(0x1373f4); + ram->fuc.r_0x137320 = ramfuc_reg(0x137320); + ram->fuc.r_0x10f65c = ramfuc_reg(0x10f65c); + ram->fuc.r_0x10f6bc = ramfuc_reg(0x10f6bc); + ram->fuc.r_0x100710 = ramfuc_reg(0x100710); + ram->fuc.r_0x100750 = ramfuc_reg(0x100750); + return 0; +} + +struct nouveau_oclass +nve0_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nve0_ram_ctor, + .dtor = _nouveau_ram_dtor, + .init = nve0_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h new file mode 100644 index 00000000000..571077e3907 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_FBRAM_SEQ_H__ +#define __NVKM_FBRAM_SEQ_H__ + +#include <subdev/bus.h> +#include <subdev/bus/hwsq.h> + +#define ram_init(s,p) hwsq_init(&(s)->base, (p)) +#define ram_exec(s,e) hwsq_exec(&(s)->base, (e)) +#define ram_have(s,r) ((s)->r_##r.addr != 0x000000) +#define ram_rd32(s,r) hwsq_rd32(&(s)->base, &(s)->r_##r) +#define ram_wr32(s,r,d) hwsq_wr32(&(s)->base, &(s)->r_##r, (d)) +#define ram_nuke(s,r) hwsq_nuke(&(s)->base, &(s)->r_##r) +#define ram_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d)) +#define ram_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d)) +#define ram_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d)) +#define ram_nsec(s,n) hwsq_nsec(&(s)->base, (n)) + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c new file mode 100644 index 00000000000..ebd4cd9c35d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c @@ -0,0 +1,99 @@ +/* + * 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 <subdev/bios.h> +#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 +ramddr3_cl[] = { + { 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 }, + { 11, 14 }, + /* the below are mentioned in some, but not all, ddr3 docs */ + { 12, 1 }, { 13, 3 }, { 14, 5 }, + { -1 } +}; + +static const struct ramxlat +ramddr3_wr[] = { + { 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 }, + /* the below are mentioned in some, but not all, ddr3 docs */ + { 14, 7 }, { 16, 0 }, + { -1 } +}; + +static const struct ramxlat +ramddr3_cwl[] = { + { 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 }, + /* the below are mentioned in some, but not all, ddr3 docs */ + { 9, 4 }, + { -1 } +}; + +int +nouveau_sddr3_calc(struct nouveau_ram *ram) +{ + struct nouveau_bios *bios = nouveau_bios(ram); + int WL, CL, WR; + + switch (!!ram->timing.data * ram->timing.version) { + 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; + 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) + return -EINVAL; + + ram->mr[0] &= ~0xe74; + ram->mr[0] |= (WR & 0x07) << 9; + ram->mr[0] |= (CL & 0x0e) << 3; + ram->mr[0] |= (CL & 0x01) << 2; + + ram->mr[2] &= ~0x038; + ram->mr[2] |= (WL & 0x07) << 3; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c index d422acc9af1..45e0202f315 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c @@ -22,21 +22,24 @@ * Authors: Ben Skeggs */ -#include <subdev/gpio.h> #include <subdev/bios.h> #include <subdev/bios/gpio.h> +#include "priv.h" + static int nouveau_gpio_drive(struct nouveau_gpio *gpio, int idx, int line, int dir, int out) { - return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV; + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV; } static int nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line) { - return gpio->sense ? gpio->sense(gpio, line) : -ENODEV; + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + return impl->sense ? impl->sense(gpio, line) : -ENODEV; } static int @@ -67,7 +70,7 @@ nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, } } - return -EINVAL; + return -ENOENT; } static int @@ -102,6 +105,80 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) return ret; } +static void +nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index) +{ + struct nouveau_gpio *gpio = nouveau_gpio(event->priv); + 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) +{ + struct nouveau_gpio *gpio = nouveau_gpio(event->priv); + const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; + impl->intr_mask(gpio, type, 1 << index, 1 << index); +} + +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; + + 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); + } +} + +int +_nouveau_gpio_fini(struct nouveau_object *object, bool suspend) +{ + const struct nouveau_gpio_impl *impl = (void *)object->oclass; + struct nouveau_gpio *gpio = nouveau_gpio(object); + u32 mask = (1 << impl->lines) - 1; + + impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); + impl->intr_stat(gpio, &mask, &mask); + + return nouveau_subdev_fini(&gpio->base, suspend); +} + +static struct dmi_system_id gpio_reset_ids[] = { + { + .ident = "Apple Macbook 10,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), + } + }, + { } +}; + +int +_nouveau_gpio_init(struct nouveau_object *object) +{ + struct nouveau_gpio *gpio = nouveau_gpio(object); + int ret; + + ret = nouveau_subdev_init(&gpio->base); + if (ret) + return ret; + + if (gpio->reset && dmi_check_system(gpio_reset_ids)) + gpio->reset(gpio, DCB_GPIO_UNUSED); + + return ret; +} + void _nouveau_gpio_dtor(struct nouveau_object *object) { @@ -113,9 +190,10 @@ _nouveau_gpio_dtor(struct nouveau_object *object) int nouveau_gpio_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, int lines, + struct nouveau_oclass *oclass, int length, void **pobject) { + const struct nouveau_gpio_impl *impl = (void *)oclass; struct nouveau_gpio *gpio; int ret; @@ -125,34 +203,34 @@ nouveau_gpio_create_(struct nouveau_object *parent, if (ret) return ret; - ret = nouveau_event_create(lines, &gpio->events); - if (ret) - return ret; - gpio->find = nouveau_gpio_find; gpio->set = nouveau_gpio_set; gpio->get = nouveau_gpio_get; + gpio->reset = impl->reset; + + ret = nouveau_event_create(2, impl->lines, &gpio->events); + 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; } -static struct dmi_system_id gpio_reset_ids[] = { - { - .ident = "Apple Macbook 10,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), - } - }, - { } -}; - int -nouveau_gpio_init(struct nouveau_gpio *gpio) +_nouveau_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - int ret = nouveau_subdev_init(&gpio->base); - if (ret == 0 && gpio->reset) { - if (dmi_check_system(gpio_reset_ids)) - gpio->reset(gpio, DCB_GPIO_UNUSED); - } - return ret; + struct nouveau_gpio *gpio; + int ret; + + ret = nouveau_gpio_create(parent, engine, oclass, &gpio); + *pobject = nv_object(gpio); + if (ret) + return ret; + + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c index 76d5d5465dd..27ad23eaf18 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c @@ -26,10 +26,6 @@ #include "priv.h" -struct nv10_gpio_priv { - struct nouveau_gpio base; -}; - static int nv10_gpio_sense(struct nouveau_gpio *gpio, int line) { @@ -83,95 +79,38 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) } static void -nv10_gpio_intr(struct nouveau_subdev *subdev) -{ - struct nv10_gpio_priv *priv = (void *)subdev; - u32 intr = nv_rd32(priv, 0x001104); - u32 hi = (intr & 0x0000ffff) >> 0; - u32 lo = (intr & 0xffff0000) >> 16; - int i; - - for (i = 0; (hi | lo) && i < 32; i++) { - if ((hi | lo) & (1 << i)) - nouveau_event_trigger(priv->base.events, i); - } - - nv_wr32(priv, 0x001104, intr); -} - -static void -nv10_gpio_intr_enable(struct nouveau_event *event, int line) -{ - nv_wr32(event->priv, 0x001104, 0x00010001 << line); - nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line); -} - -static void -nv10_gpio_intr_disable(struct nouveau_event *event, int line) -{ - nv_wr32(event->priv, 0x001104, 0x00010001 << line); - nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000); -} - -static int -nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +nv10_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) { - struct nv10_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, 16, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.drive = nv10_gpio_drive; - priv->base.sense = nv10_gpio_sense; - priv->base.events->priv = priv; - priv->base.events->enable = nv10_gpio_intr_enable; - priv->base.events->disable = nv10_gpio_intr_disable; - nv_subdev(priv)->intr = nv10_gpio_intr; - return 0; + u32 intr = nv_rd32(gpio, 0x001104); + u32 stat = nv_rd32(gpio, 0x001144) & intr; + *lo = (stat & 0xffff0000) >> 16; + *hi = (stat & 0x0000ffff); + nv_wr32(gpio, 0x001104, intr); } static void -nv10_gpio_dtor(struct nouveau_object *object) -{ - struct nv10_gpio_priv *priv = (void *)object; - nouveau_gpio_destroy(&priv->base); -} - -static int -nv10_gpio_init(struct nouveau_object *object) -{ - struct nv10_gpio_priv *priv = (void *)object; - int ret; - - ret = nouveau_gpio_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x001144, 0x00000000); - nv_wr32(priv, 0x001104, 0xffffffff); - return 0; -} - -static int -nv10_gpio_fini(struct nouveau_object *object, bool suspend) +nv10_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) { - struct nv10_gpio_priv *priv = (void *)object; - nv_wr32(priv, 0x001144, 0x00000000); - return nouveau_gpio_fini(&priv->base, suspend); + u32 inte = nv_rd32(gpio, 0x001144); + if (type & NVKM_GPIO_LO) + inte = (inte & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte = (inte & ~mask) | data; + nv_wr32(gpio, 0x001144, inte); } -struct nouveau_oclass -nv10_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0x10), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv10_gpio_ctor, - .dtor = nv10_gpio_dtor, - .init = nv10_gpio_init, - .fini = nv10_gpio_fini, +struct nouveau_oclass * +nv10_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0x10), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, }, -}; + .lines = 16, + .intr_stat = nv10_gpio_intr_stat, + .intr_mask = nv10_gpio_intr_mask, + .drive = nv10_gpio_drive, + .sense = nv10_gpio_sense, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index c4c1d415e7f..1864fa98e6b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -24,15 +24,10 @@ #include "priv.h" -struct nv50_gpio_priv { - struct nouveau_gpio base; -}; - -static void +void nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) { struct nouveau_bios *bios = nouveau_bios(gpio); - struct nv50_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; int ent = -1; @@ -46,7 +41,8 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) u8 unk0 = !!(data & 0x02000000); u8 unk1 = !!(data & 0x04000000); u32 val = (unk1 << 16) | unk0; - u32 reg = regs[line >> 4]; line &= 0x0f; + u32 reg = regs[line >> 4]; + u32 lsh = line & 0x0f; if ( func == DCB_GPIO_UNUSED || (match != DCB_GPIO_UNUSED && match != func)) @@ -54,7 +50,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) gpio->set(gpio, 0, func, line, defs); - nv_mask(priv, reg, 0x00010001 << line, val << line); + nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh); } } @@ -71,7 +67,7 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift) return 0; } -static int +int nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) { u32 reg, shift; @@ -79,11 +75,11 @@ nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) if (nv50_gpio_location(line, ®, &shift)) return -EINVAL; - nv_mask(gpio, reg, 7 << shift, (((dir ^ 1) << 1) | out) << shift); + nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift); return 0; } -static int +int nv50_gpio_sense(struct nouveau_gpio *gpio, int line) { u32 reg, shift; @@ -94,119 +90,40 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line) return !!(nv_rd32(gpio, reg) & (4 << shift)); } -void -nv50_gpio_intr(struct nouveau_subdev *subdev) -{ - struct nv50_gpio_priv *priv = (void *)subdev; - u32 intr0, intr1 = 0; - u32 hi, lo; - int i; - - intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); - if (nv_device(priv)->chipset > 0x92) - intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070); - - hi = (intr0 & 0x0000ffff) | (intr1 << 16); - lo = (intr0 >> 16) | (intr1 & 0xffff0000); - - for (i = 0; (hi | lo) && i < 32; i++) { - if ((hi | lo) & (1 << i)) - nouveau_event_trigger(priv->base.events, i); - } - - nv_wr32(priv, 0xe054, intr0); - if (nv_device(priv)->chipset > 0x92) - nv_wr32(priv, 0xe074, intr1); -} - -void -nv50_gpio_intr_enable(struct nouveau_event *event, int line) -{ - const u32 addr = line < 16 ? 0xe050 : 0xe070; - const u32 mask = 0x00010001 << (line & 0xf); - nv_wr32(event->priv, addr + 0x04, mask); - nv_mask(event->priv, addr + 0x00, mask, mask); -} - -void -nv50_gpio_intr_disable(struct nouveau_event *event, int line) -{ - const u32 addr = line < 16 ? 0xe050 : 0xe070; - const u32 mask = 0x00010001 << (line & 0xf); - nv_wr32(event->priv, addr + 0x04, mask); - nv_mask(event->priv, addr + 0x00, mask, 0x00000000); -} - -static int -nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, - nv_device(parent)->chipset > 0x92 ? 32 : 16, - &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.reset = nv50_gpio_reset; - priv->base.drive = nv50_gpio_drive; - priv->base.sense = nv50_gpio_sense; - priv->base.events->priv = priv; - priv->base.events->enable = nv50_gpio_intr_enable; - priv->base.events->disable = nv50_gpio_intr_disable; - nv_subdev(priv)->intr = nv50_gpio_intr; - return 0; -} - -void -nv50_gpio_dtor(struct nouveau_object *object) -{ - struct nv50_gpio_priv *priv = (void *)object; - nouveau_gpio_destroy(&priv->base); -} - -int -nv50_gpio_init(struct nouveau_object *object) +static void +nv50_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) { - struct nv50_gpio_priv *priv = (void *)object; - int ret; - - ret = nouveau_gpio_init(&priv->base); - if (ret) - return ret; - - /* disable, and ack any pending gpio interrupts */ - nv_wr32(priv, 0xe050, 0x00000000); - nv_wr32(priv, 0xe054, 0xffffffff); - if (nv_device(priv)->chipset > 0x92) { - nv_wr32(priv, 0xe070, 0x00000000); - nv_wr32(priv, 0xe074, 0xffffffff); - } - - return 0; + u32 intr = nv_rd32(gpio, 0x00e054); + u32 stat = nv_rd32(gpio, 0x00e050) & intr; + *lo = (stat & 0xffff0000) >> 16; + *hi = (stat & 0x0000ffff); + nv_wr32(gpio, 0x00e054, intr); } -int -nv50_gpio_fini(struct nouveau_object *object, bool suspend) +static void +nv50_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) { - struct nv50_gpio_priv *priv = (void *)object; - nv_wr32(priv, 0xe050, 0x00000000); - if (nv_device(priv)->chipset > 0x92) - nv_wr32(priv, 0xe070, 0x00000000); - return nouveau_gpio_fini(&priv->base, suspend); + u32 inte = nv_rd32(gpio, 0x00e050); + if (type & NVKM_GPIO_LO) + inte = (inte & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte = (inte & ~mask) | data; + nv_wr32(gpio, 0x00e050, inte); } -struct nouveau_oclass -nv50_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_gpio_ctor, - .dtor = nv50_gpio_dtor, - .init = nv50_gpio_init, - .fini = nv50_gpio_fini, +struct nouveau_oclass * +nv50_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, }, -}; + .lines = 16, + .intr_stat = nv50_gpio_intr_stat, + .intr_mask = nv50_gpio_intr_mask, + .drive = nv50_gpio_drive, + .sense = nv50_gpio_sense, + .reset = nv50_gpio_reset, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c new file mode 100644 index 00000000000..252083d376f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv92.c @@ -0,0 +1,74 @@ +/* + * 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" + +void +nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) +{ + u32 intr0 = nv_rd32(gpio, 0x00e054); + u32 intr1 = nv_rd32(gpio, 0x00e074); + u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0; + u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1; + *lo = (stat1 & 0xffff0000) | (stat0 >> 16); + *hi = (stat1 << 16) | (stat0 & 0x0000ffff); + nv_wr32(gpio, 0x00e054, intr0); + nv_wr32(gpio, 0x00e074, intr1); +} + +void +nv92_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); + if (type & NVKM_GPIO_LO) + inte0 = (inte0 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff); + mask >>= 16; + data >>= 16; + if (type & NVKM_GPIO_LO) + inte1 = (inte1 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte1 = (inte1 & ~mask) | data; + nv_wr32(gpio, 0x00e050, inte0); + nv_wr32(gpio, 0x00e070, inte1); +} + +struct nouveau_oclass * +nv92_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0x92), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, + }, + .lines = 32, + .intr_stat = nv92_gpio_intr_stat, + .intr_mask = nv92_gpio_intr_mask, + .drive = nv50_gpio_drive, + .sense = nv50_gpio_sense, + .reset = nv50_gpio_reset, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c index 010431e3ace..a4682b0956a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c @@ -24,15 +24,10 @@ #include "priv.h" -struct nvd0_gpio_priv { - struct nouveau_gpio base; -}; - void nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) { struct nouveau_bios *bios = nouveau_bios(gpio); - struct nvd0_gpio_priv *priv = (void *)gpio; u8 ver, len; u16 entry; int ent = -1; @@ -51,9 +46,9 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match) gpio->set(gpio, 0, func, line, defs); - nv_mask(priv, 0x00d610 + (line * 4), 0xff, unk0); + nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0); if (unk1--) - nv_mask(priv, 0x00d740 + (unk1 * 4), 0xff, line); + nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line); } } @@ -72,36 +67,19 @@ nvd0_gpio_sense(struct nouveau_gpio *gpio, int line) return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); } -static int -nvd0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nvd0_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.reset = nvd0_gpio_reset; - priv->base.drive = nvd0_gpio_drive; - priv->base.sense = nvd0_gpio_sense; - priv->base.events->priv = priv; - priv->base.events->enable = nv50_gpio_intr_enable; - priv->base.events->disable = nv50_gpio_intr_disable; - nv_subdev(priv)->intr = nv50_gpio_intr; - return 0; -} - -struct nouveau_oclass -nvd0_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0xd0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvd0_gpio_ctor, - .dtor = nv50_gpio_dtor, - .init = nv50_gpio_init, - .fini = nv50_gpio_fini, +struct nouveau_oclass * +nvd0_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0xd0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, }, -}; + .lines = 32, + .intr_stat = nv92_gpio_intr_stat, + .intr_mask = nv92_gpio_intr_mask, + .drive = nvd0_gpio_drive, + .sense = nvd0_gpio_sense, + .reset = nvd0_gpio_reset, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c index 16b8c5bf5ef..e1145b48c76 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c @@ -24,108 +24,51 @@ #include "priv.h" -struct nve0_gpio_priv { - struct nouveau_gpio base; -}; - -void -nve0_gpio_intr(struct nouveau_subdev *subdev) +static void +nve0_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo) { - struct nve0_gpio_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0xdc00) & nv_rd32(priv, 0xdc08); - u32 intr1 = nv_rd32(priv, 0xdc80) & nv_rd32(priv, 0xdc88); - u32 hi = (intr0 & 0x0000ffff) | (intr1 << 16); - u32 lo = (intr0 >> 16) | (intr1 & 0xffff0000); - int i; - - for (i = 0; (hi | lo) && i < 32; i++) { - if ((hi | lo) & (1 << i)) - nouveau_event_trigger(priv->base.events, i); - } - - nv_wr32(priv, 0xdc00, intr0); - nv_wr32(priv, 0xdc88, intr1); + u32 intr0 = nv_rd32(gpio, 0x00dc00); + u32 intr1 = nv_rd32(gpio, 0x00dc80); + u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0; + u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1; + *lo = (stat1 & 0xffff0000) | (stat0 >> 16); + *hi = (stat1 << 16) | (stat0 & 0x0000ffff); + nv_wr32(gpio, 0x00dc00, intr0); + nv_wr32(gpio, 0x00dc80, intr1); } void -nve0_gpio_intr_enable(struct nouveau_event *event, int line) +nve0_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data) { - const u32 addr = line < 16 ? 0xdc00 : 0xdc80; - const u32 mask = 0x00010001 << (line & 0xf); - nv_wr32(event->priv, addr + 0x08, mask); - nv_mask(event->priv, addr + 0x00, mask, mask); -} - -void -nve0_gpio_intr_disable(struct nouveau_event *event, int line) -{ - const u32 addr = line < 16 ? 0xdc00 : 0xdc80; - const u32 mask = 0x00010001 << (line & 0xf); - nv_wr32(event->priv, addr + 0x08, mask); - nv_mask(event->priv, addr + 0x00, mask, 0x00000000); -} - -int -nve0_gpio_fini(struct nouveau_object *object, bool suspend) -{ - struct nve0_gpio_priv *priv = (void *)object; - nv_wr32(priv, 0xdc08, 0x00000000); - nv_wr32(priv, 0xdc88, 0x00000000); - return nouveau_gpio_fini(&priv->base, suspend); -} - -int -nve0_gpio_init(struct nouveau_object *object) -{ - struct nve0_gpio_priv *priv = (void *)object; - int ret; - - ret = nouveau_gpio_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0xdc00, 0xffffffff); - nv_wr32(priv, 0xdc80, 0xffffffff); - return 0; -} - -void -nve0_gpio_dtor(struct nouveau_object *object) -{ - struct nve0_gpio_priv *priv = (void *)object; - nouveau_gpio_destroy(&priv->base); -} - -static int -nve0_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nve0_gpio_priv *priv; - int ret; - - ret = nouveau_gpio_create(parent, engine, oclass, 32, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.reset = nvd0_gpio_reset; - priv->base.drive = nvd0_gpio_drive; - priv->base.sense = nvd0_gpio_sense; - priv->base.events->priv = priv; - priv->base.events->enable = nve0_gpio_intr_enable; - priv->base.events->disable = nve0_gpio_intr_disable; - nv_subdev(priv)->intr = nve0_gpio_intr; - return 0; + u32 inte0 = nv_rd32(gpio, 0x00dc08); + u32 inte1 = nv_rd32(gpio, 0x00dc88); + if (type & NVKM_GPIO_LO) + inte0 = (inte0 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff); + mask >>= 16; + data >>= 16; + if (type & NVKM_GPIO_LO) + inte1 = (inte1 & ~(mask << 16)) | (data << 16); + if (type & NVKM_GPIO_HI) + inte1 = (inte1 & ~mask) | data; + nv_wr32(gpio, 0x00dc08, inte0); + nv_wr32(gpio, 0x00dc88, inte1); } -struct nouveau_oclass -nve0_gpio_oclass = { - .handle = NV_SUBDEV(GPIO, 0xe0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nve0_gpio_ctor, - .dtor = nv50_gpio_dtor, - .init = nve0_gpio_init, - .fini = nve0_gpio_fini, +struct nouveau_oclass * +nve0_gpio_oclass = &(struct nouveau_gpio_impl) { + .base.handle = NV_SUBDEV(GPIO, 0xe0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_gpio_ctor, + .dtor = _nouveau_gpio_dtor, + .init = _nouveau_gpio_init, + .fini = _nouveau_gpio_fini, }, -}; + .lines = 32, + .intr_stat = nve0_gpio_intr_stat, + .intr_mask = nve0_gpio_intr_mask, + .drive = nvd0_gpio_drive, + .sense = nvd0_gpio_sense, + .reset = nvd0_gpio_reset, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h index 2ee1c895c78..e1724dfc86a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h @@ -3,15 +3,65 @@ #include <subdev/gpio.h> -void nv50_gpio_dtor(struct nouveau_object *); -int nv50_gpio_init(struct nouveau_object *); -int nv50_gpio_fini(struct nouveau_object *, bool); -void nv50_gpio_intr(struct nouveau_subdev *); -void nv50_gpio_intr_enable(struct nouveau_event *, int line); -void nv50_gpio_intr_disable(struct nouveau_event *, int line); +#define nouveau_gpio_create(p,e,o,d) \ + nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_gpio_destroy(p) ({ \ + struct nouveau_gpio *gpio = (p); \ + _nouveau_gpio_dtor(nv_object(gpio)); \ +}) +#define nouveau_gpio_init(p) ({ \ + struct nouveau_gpio *gpio = (p); \ + _nouveau_gpio_init(nv_object(gpio)); \ +}) +#define nouveau_gpio_fini(p,s) ({ \ + struct nouveau_gpio *gpio = (p); \ + _nouveau_gpio_fini(nv_object(gpio), (s)); \ +}) + +int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int _nouveau_gpio_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nouveau_gpio_dtor(struct nouveau_object *); +int _nouveau_gpio_init(struct nouveau_object *); +int _nouveau_gpio_fini(struct nouveau_object *, bool); + +struct nouveau_gpio_impl { + struct nouveau_oclass base; + int lines; + + /* read and ack pending interrupts, returning only data + * for lines that have not been masked off, while still + * performing the ack for anything that was pending. + */ + void (*intr_stat)(struct nouveau_gpio *, u32 *, u32 *); + + /* mask on/off interrupts for hi/lo transitions on a + * given set of gpio lines + */ + void (*intr_mask)(struct nouveau_gpio *, u32, u32, u32); + + /* configure gpio direction and output value */ + int (*drive)(struct nouveau_gpio *, int line, int dir, int out); + + /* sense current state of given gpio line */ + int (*sense)(struct nouveau_gpio *, int line); + + /*XXX*/ + void (*reset)(struct nouveau_gpio *, u8); +}; + +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 nvd0_gpio_reset(struct nouveau_gpio *, u8); int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int); int nvd0_gpio_sense(struct nouveau_gpio *, int); + #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c index 4b195ac4da6..2c2731a6cf9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include <subdev/i2c.h> +#include "port.h" struct anx9805_i2c_port { struct nouveau_i2c_port base; @@ -37,6 +37,8 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; u8 tmp, i; + DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh); + nv_wri2cr(mast, chan->addr, 0xa0, link_bw); nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); nv_wri2cr(mast, chan->addr, 0xa2, 0x01); @@ -60,21 +62,29 @@ anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) } static int -anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) +anx9805_aux(struct nouveau_i2c_port *port, bool retry, + u8 type, u32 addr, u8 *data, u8 size) { struct anx9805_i2c_port *chan = (void *)port; struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; int i, ret = -ETIMEDOUT; + u8 buf[16] = {}; u8 tmp; + DBG("%02x %05x %d\n", type, addr, size); + tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); nv_wri2cr(mast, chan->ctrl, 0x07, tmp); nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); nv_wri2cr(mast, chan->addr, 0xe4, 0x80); - for (i = 0; !(type & 1) && i < size; i++) - nv_wri2cr(mast, chan->addr, 0xf0 + i, data[i]); + if (!(type & 1)) { + memcpy(buf, data, size); + DBG("%16ph", buf); + for (i = 0; i < size; i++) + nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]); + } nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); @@ -93,8 +103,13 @@ anx9805_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size) goto done; } - for (i = 0; (type & 1) && i < size; i++) - data[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); + if (type & 1) { + for (i = 0; i < size; i++) + buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); + DBG("%16ph", buf); + memcpy(data, buf, size); + } + ret = 0; done: nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c index 5de074ad170..02eb42be2e9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c @@ -22,15 +22,19 @@ * Authors: Ben Skeggs */ -#include <subdev/i2c.h> +#include "priv.h" int nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) { + struct nouveau_i2c *i2c = nouveau_i2c(port); if (port->func->aux) { - if (port->func->acquire) - port->func->acquire(port); - return port->func->aux(port, 9, addr, data, size); + int ret = i2c->acquire(port, 0); + if (ret == 0) { + ret = port->func->aux(port, true, 9, addr, data, size); + i2c->release(port); + } + return ret; } return -ENODEV; } @@ -38,10 +42,14 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) int nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size) { + struct nouveau_i2c *i2c = nouveau_i2c(port); if (port->func->aux) { - if (port->func->acquire) - port->func->acquire(port); - return port->func->aux(port, 8, addr, data, size); + int ret = i2c->acquire(port, 0); + if (ret == 0) { + ret = port->func->aux(port, true, 8, addr, data, size); + i2c->release(port); + } + return ret; } return -ENODEV; } @@ -50,13 +58,16 @@ static int aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct nouveau_i2c_port *port = adap->algo_data; + struct nouveau_i2c *i2c = nouveau_i2c(port); struct i2c_msg *msg = msgs; int ret, mcnt = num; if (!port->func->aux) return -ENODEV; - if ( port->func->acquire) - port->func->acquire(port); + + ret = i2c->acquire(port, 0); + if (ret) + return ret; while (mcnt--) { u8 remaining = msg->len; @@ -74,9 +85,11 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (mcnt || remaining > 16) cmd |= 4; /* MOT */ - ret = port->func->aux(port, cmd, msg->addr, ptr, cnt); - if (ret < 0) + ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt); + if (ret < 0) { + i2c->release(port); return ret; + } ptr += cnt; remaining -= cnt; @@ -85,6 +98,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) msg++; } + i2c->release(port); return num; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index 2895c19bb15..09ba2cc851c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c @@ -23,13 +23,16 @@ */ #include <core/option.h> +#include <core/event.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> #include <subdev/bios/i2c.h> -#include <subdev/i2c.h> #include <subdev/vga.h> +#include "priv.h" +#include "pad.h" + /****************************************************************************** * interface to linux i2c bit-banging algorithm *****************************************************************************/ @@ -45,9 +48,15 @@ nouveau_i2c_pre_xfer(struct i2c_adapter *adap) { struct i2c_algo_bit_data *bit = adap->algo_data; struct nouveau_i2c_port *port = bit->data; - if (port->func->acquire) - port->func->acquire(port); - return 0; + return nouveau_i2c(port)->acquire(port, bit->timeout); +} + +static void +nouveau_i2c_post_xfer(struct i2c_adapter *adap) +{ + struct i2c_algo_bit_data *bit = adap->algo_data; + struct nouveau_i2c_port *port = bit->data; + return nouveau_i2c(port)->release(port); } static void @@ -82,6 +91,15 @@ nouveau_i2c_getsda(void *data) * base i2c "port" class implementation *****************************************************************************/ +int +_nouveau_i2c_port_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_i2c_port *port = (void *)object; + struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); + nv_ofuncs(pad)->fini(nv_object(pad), suspend); + return nouveau_object_fini(&port->base, suspend); +} + void _nouveau_i2c_port_dtor(struct nouveau_object *object) { @@ -98,7 +116,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, const struct nouveau_i2c_func *func, int size, void **pobject) { - struct nouveau_device *device = nv_device(parent); + struct nouveau_device *device = nv_device(engine); struct nouveau_i2c *i2c = (void *)engine; struct nouveau_i2c_port *port; int ret; @@ -111,10 +129,11 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, snprintf(port->adapter.name, sizeof(port->adapter.name), "nouveau-%s-%d", device->name, index); port->adapter.owner = THIS_MODULE; - port->adapter.dev.parent = &device->pdev->dev; + port->adapter.dev.parent = nv_device_base(device); port->index = index; + port->aux = -1; port->func = func; - i2c_set_adapdata(&port->adapter, i2c); + mutex_init(&port->mutex); if ( algo == &nouveau_i2c_bit_algo && !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { @@ -128,6 +147,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, bit->timeout = usecs_to_jiffies(2200); bit->data = port; bit->pre_xfer = nouveau_i2c_pre_xfer; + bit->post_xfer = nouveau_i2c_post_xfer; bit->setsda = nouveau_i2c_setsda; bit->setscl = nouveau_i2c_setscl; bit->getsda = nouveau_i2c_getsda; @@ -141,7 +161,6 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, ret = i2c_add_adapter(&port->adapter); } - /* drop port's i2c subdev refcount, i2c handles this itself */ if (ret == 0) list_add_tail(&port->head, &i2c->ports); return ret; @@ -193,11 +212,80 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type) return NULL; } +static void +nouveau_i2c_release_pad(struct nouveau_i2c_port *port) +{ + struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); + struct nouveau_i2c *i2c = nouveau_i2c(port); + + if (atomic_dec_and_test(&nv_object(pad)->usecount)) { + nv_ofuncs(pad)->fini(nv_object(pad), false); + wake_up_all(&i2c->wait); + } +} + +static int +nouveau_i2c_try_acquire_pad(struct nouveau_i2c_port *port) +{ + struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); + + if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) { + struct nouveau_object *owner = (void *)pad->port; + do { + if (owner == (void *)port) + return 0; + owner = owner->parent; + } while(owner); + nouveau_i2c_release_pad(port); + return -EBUSY; + } + + pad->next = port; + nv_ofuncs(pad)->init(nv_object(pad)); + return 0; +} + +static int +nouveau_i2c_acquire_pad(struct nouveau_i2c_port *port, unsigned long timeout) +{ + struct nouveau_i2c *i2c = nouveau_i2c(port); + + if (timeout) { + if (wait_event_timeout(i2c->wait, + nouveau_i2c_try_acquire_pad(port) == 0, + timeout) == 0) + return -EBUSY; + } else { + wait_event(i2c->wait, nouveau_i2c_try_acquire_pad(port) == 0); + } + + return 0; +} + +static void +nouveau_i2c_release(struct nouveau_i2c_port *port) +__releases(pad->mutex) +{ + nouveau_i2c(port)->release_pad(port); + mutex_unlock(&port->mutex); +} + +static int +nouveau_i2c_acquire(struct nouveau_i2c_port *port, unsigned long timeout) +__acquires(pad->mutex) +{ + int ret; + mutex_lock(&port->mutex); + if ((ret = nouveau_i2c(port)->acquire_pad(port, timeout))) + mutex_unlock(&port->mutex); + return ret; +} + static int nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, - struct i2c_board_info *info, + struct nouveau_i2c_board_info *info, bool (*match)(struct nouveau_i2c_port *, - struct i2c_board_info *)) + struct i2c_board_info *, void *), void *data) { struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index); int i; @@ -208,23 +296,88 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, } nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index); - for (i = 0; info[i].addr; i++) { - if (nv_probe_i2c(port, info[i].addr) && - (!match || match(port, &info[i]))) { - nv_info(i2c, "detected %s: %s\n", what, info[i].type); + for (i = 0; info[i].dev.addr; i++) { + u8 orig_udelay = 0; + + if ((port->adapter.algo == &i2c_bit_algo) && + (info[i].udelay != 0)) { + struct i2c_algo_bit_data *algo = port->adapter.algo_data; + nv_debug(i2c, "using custom udelay %d instead of %d\n", + info[i].udelay, algo->udelay); + orig_udelay = algo->udelay; + algo->udelay = info[i].udelay; + } + + if (nv_probe_i2c(port, info[i].dev.addr) && + (!match || match(port, &info[i].dev, data))) { + nv_info(i2c, "detected %s: %s\n", what, + info[i].dev.type); return i; } + + if (orig_udelay) { + struct i2c_algo_bit_data *algo = port->adapter.algo_data; + algo->udelay = orig_udelay; + } } nv_debug(i2c, "no devices found.\n"); return -ENODEV; } +static void +nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index) +{ + struct nouveau_i2c *i2c = nouveau_i2c(event->priv); + 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, 0); +} + +static void +nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index) +{ + struct nouveau_i2c *i2c = nouveau_i2c(event->priv); + 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 void +nouveau_i2c_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev); + struct nouveau_i2c *i2c = nouveau_i2c(subdev); + struct nouveau_i2c_port *port; + u32 hi, lo, rq, tx, e; + + if (impl->aux_stat) { + impl->aux_stat(i2c, &hi, &lo, &rq, &tx); + if (hi || lo || rq || tx) { + list_for_each_entry(port, &i2c->ports, head) { + if (e = 0, port->aux < 0) + continue; + + if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG; + 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); + } + } + } +} + int _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) { + struct nouveau_i2c_impl *impl = (void *)nv_oclass(object); struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port; + u32 mask; int ret; list_for_each_entry(port, &i2c->ports, head) { @@ -233,6 +386,11 @@ _nouveau_i2c_fini(struct nouveau_object *object, bool suspend) goto fail; } + if ((mask = (1 << impl->aux) - 1), impl->aux_stat) { + impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); + impl->aux_stat(i2c, &mask, &mask, &mask, &mask); + } + return nouveau_subdev_fini(&i2c->base, suspend); fail: list_for_each_entry_continue_reverse(port, &i2c->ports, head) { @@ -273,6 +431,8 @@ _nouveau_i2c_dtor(struct nouveau_object *object) struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c_port *port, *temp; + nouveau_event_destroy(&i2c->ntfy); + list_for_each_entry_safe(port, temp, &i2c->ports, head) { nouveau_object_ref(NULL, (struct nouveau_object **)&port); } @@ -289,14 +449,14 @@ int nouveau_i2c_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, - struct nouveau_oclass *sclass, int length, void **pobject) { + const struct nouveau_i2c_impl *impl = (void *)oclass; struct nouveau_bios *bios = nouveau_bios(parent); struct nouveau_i2c *i2c; struct nouveau_object *object; struct dcb_i2c_entry info; - int ret, i, j, index = -1; + int ret, i, j, index = -1, pad; struct dcb_output outp; u8 ver, hdr; u32 data; @@ -307,24 +467,48 @@ nouveau_i2c_create_(struct nouveau_object *parent, if (ret) return ret; + nv_subdev(i2c)->intr = nouveau_i2c_intr; i2c->find = nouveau_i2c_find; i2c->find_type = nouveau_i2c_find_type; + i2c->acquire_pad = nouveau_i2c_acquire_pad; + i2c->release_pad = nouveau_i2c_release_pad; + i2c->acquire = nouveau_i2c_acquire; + i2c->release = nouveau_i2c_release; i2c->identify = nouveau_i2c_identify; + init_waitqueue_head(&i2c->wait); INIT_LIST_HEAD(&i2c->ports); while (!dcb_i2c_parse(bios, ++index, &info)) { if (info.type == DCB_I2C_UNUSED) continue; - oclass = sclass; + if (info.share != DCB_I2C_UNUSED) { + if (info.type == DCB_I2C_NVIO_AUX) + pad = info.drive; + else + pad = info.share; + oclass = impl->pad_s; + } else { + pad = 0x100 + info.drive; + oclass = impl->pad_x; + } + + ret = nouveau_object_ctor(NULL, *pobject, oclass, + NULL, pad, &parent); + if (ret < 0) + continue; + + oclass = impl->sclass; do { ret = -EINVAL; if (oclass->handle == info.type) { - ret = nouveau_object_ctor(*pobject, *pobject, + ret = nouveau_object_ctor(parent, *pobject, oclass, &info, index, &object); } } while (ret && (++oclass)->handle); + + nouveau_object_ref(NULL, &parent); } /* in addition to the busses specified in the i2c table, there @@ -363,5 +547,28 @@ nouveau_i2c_create_(struct nouveau_object *parent, } } + ret = nouveau_event_create(4, index, &i2c->ntfy); + if (ret) + return ret; + + i2c->ntfy->priv = i2c; + i2c->ntfy->enable = nouveau_i2c_intr_enable; + i2c->ntfy->disable = nouveau_i2c_intr_disable; + return 0; +} + +int +_nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_i2c *i2c; + int ret; + + ret = nouveau_i2c_create(parent, engine, oclass, &i2c); + *pobject = nv_object(i2c); + if (ret) + return ret; + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c index a6e72d3b06b..813ffc96e86 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs */ -#include "subdev/i2c.h" +#include "priv.h" #ifdef CONFIG_NOUVEAU_I2C_INTERNAL #define T_TIMEOUT 2200000 @@ -187,8 +187,9 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_msg *msg = msgs; int ret = 0, mcnt = num; - if (port->func->acquire) - port->func->acquire(port); + ret = nouveau_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT)); + if (ret) + return ret; while (!ret && mcnt--) { u8 remaining = msg->len; @@ -210,6 +211,7 @@ i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) } i2c_stop(port); + nouveau_i2c(port)->release(port); return (ret < 0) ? ret : num; } #else diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c new file mode 100644 index 00000000000..fa891c39866 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c @@ -0,0 +1,39 @@ +/* + * 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 "nv50.h" + +struct nouveau_oclass * +gf117_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0xd7), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, + .dtor = _nouveau_i2c_dtor, + .init = _nouveau_i2c_init, + .fini = _nouveau_i2c_fini, + }, + .sclass = nvd0_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c index 860d5d2365d..b1725bdea96 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c @@ -22,9 +22,10 @@ * Authors: Ben Skeggs */ -#include <subdev/i2c.h> #include <subdev/vga.h> +#include "priv.h" + struct nv04_i2c_priv { struct nouveau_i2c base; }; @@ -115,29 +116,15 @@ nv04_i2c_sclass[] = { {} }; -static int -nv04_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv04_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv04_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv04_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv04_i2c_ctor, +struct nouveau_oclass * +nv04_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv04_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c index 0c2655a03bb..f16c87ce5ba 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c @@ -22,9 +22,10 @@ * Authors: Ben Skeggs */ -#include <subdev/i2c.h> #include <subdev/vga.h> +#include "priv.h" + struct nv4e_i2c_priv { struct nouveau_i2c base; }; @@ -107,29 +108,15 @@ nv4e_i2c_sclass[] = { {} }; -static int -nv4e_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv4e_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv4e_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv4e_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x4e), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv4e_i2c_ctor, +struct nouveau_oclass * +nv4e_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x4e), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv4e_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c index a8d67a28770..7b8756d4df0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c @@ -121,29 +121,15 @@ nv50_i2c_sclass[] = { {} }; -static int -nv50_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv50_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv50_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_i2c_ctor, +struct nouveau_oclass * +nv50_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv50_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h index 4e5ba48ebf5..5d2a77421c7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h @@ -1,7 +1,7 @@ #ifndef __NV50_I2C_H__ #define __NV50_I2C_H__ -#include <subdev/i2c.h> +#include "priv.h" struct nv50_i2c_priv { struct nouveau_i2c base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c index df6d3e4b68b..f59c3a25546 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c @@ -24,6 +24,36 @@ #include "nv50.h" +void +nv94_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) +{ + u32 intr = nv_rd32(i2c, 0x00e06c); + u32 stat = nv_rd32(i2c, 0x00e068) & intr, i; + for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { + if ((stat & (1 << (i * 4)))) *hi |= 1 << i; + if ((stat & (2 << (i * 4)))) *lo |= 1 << i; + if ((stat & (4 << (i * 4)))) *rq |= 1 << i; + if ((stat & (8 << (i * 4)))) *tx |= 1 << i; + } + nv_wr32(i2c, 0x00e06c, intr); +} + +void +nv94_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data) +{ + u32 temp = nv_rd32(i2c, 0x00e068), i; + for (i = 0; i < 8; i++) { + if (mask & (1 << i)) { + if (!(data & (1 << i))) { + temp &= ~(type << (i * 4)); + continue; + } + temp |= type << (i * 4); + } + } + nv_wr32(i2c, 0x00e068, temp); +} + #define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) #define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) @@ -69,7 +99,8 @@ auxch_init(struct nouveau_i2c *aux, int ch) } int -nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) +nv94_aux(struct nouveau_i2c_port *base, bool retry, + u8 type, u32 addr, u8 *data, u8 size) { struct nouveau_i2c *aux = nouveau_i2c(base); struct nv50_i2c_port *port = (void *)base; @@ -105,9 +136,8 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) ctrl |= size - 1; nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); - /* retry transaction a number of times on failure... */ - ret = -EREMOTEIO; - for (retries = 0; retries < 32; retries++) { + /* (maybe) retry transaction a number of times on failure... */ + for (retries = 0; !ret && retries < 32; retries++) { /* reset, and delay a while if this is a retry */ nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); @@ -123,16 +153,21 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) udelay(1); if (!timeout--) { AUX_ERR("tx req timeout 0x%08x\n", ctrl); + ret = -EIO; goto out; } } while (ctrl & 0x00010000); + ret = 1; /* read status, and check if transaction completed ok */ stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); - if (!(stat & 0x000f0f00)) { - ret = 0; - break; - } + if ((stat & 0x000f0000) == 0x00080000 || + (stat & 0x000f0000) == 0x00020000) + ret = retry ? 0 : 1; + if ((stat & 0x00000100)) + ret = -ETIMEDOUT; + if ((stat & 0x00000e00)) + ret = -EIO; AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); } @@ -147,29 +182,11 @@ nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size) out: auxch_fini(aux, ch); - return ret; -} - -void -nv94_i2c_acquire(struct nouveau_i2c_port *base) -{ - struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; - struct nv50_i2c_port *port = (void *)base; - if (port->ctrl) { - nv_mask(priv, port->ctrl + 0x0c, 0x00000001, 0x00000000); - nv_mask(priv, port->ctrl + 0x00, 0x0000f003, port->data); - } -} - -void -nv94_i2c_release(struct nouveau_i2c_port *base) -{ + return ret < 0 ? ret : (stat & 0x000f0000) >> 16; } static const struct nouveau_i2c_func nv94_i2c_func = { - .acquire = nv94_i2c_acquire, - .release = nv94_i2c_release, .drive_scl = nv50_i2c_drive_scl, .drive_sda = nv50_i2c_drive_sda, .sense_scl = nv50_i2c_sense_scl, @@ -206,8 +223,6 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, static const struct nouveau_i2c_func nv94_aux_func = { - .acquire = nv94_i2c_acquire, - .release = nv94_i2c_release, .aux = nv94_aux, }; @@ -227,6 +242,7 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + port->base.aux = info->drive; port->addr = info->drive; if (info->share != DCB_I2C_UNUSED) { port->ctrl = 0x00e500 + (info->drive * 0x50); @@ -257,29 +273,19 @@ nv94_i2c_sclass[] = { {} }; -static int -nv94_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nv94_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv94_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0x94), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv94_i2c_ctor, +struct nouveau_oclass * +nv94_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0x94), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nv94_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv94_i2c_pad_oclass, + .aux = 4, + .aux_stat = nv94_aux_stat, + .aux_mask = nv94_aux_mask, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c index 29967d30f97..364ddb1c5f0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c @@ -42,8 +42,6 @@ nvd0_i2c_sense_sda(struct nouveau_i2c_port *base) static const struct nouveau_i2c_func nvd0_i2c_func = { - .acquire = nv94_i2c_acquire, - .release = nv94_i2c_release, .drive_scl = nv50_i2c_drive_scl, .drive_sda = nv50_i2c_drive_sda, .sense_scl = nvd0_i2c_sense_scl, @@ -75,7 +73,7 @@ nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -static struct nouveau_oclass +struct nouveau_oclass nvd0_i2c_sclass[] = { { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), .ofuncs = &(struct nouveau_ofuncs) { @@ -96,29 +94,19 @@ nvd0_i2c_sclass[] = { {} }; -static int -nvd0_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv50_i2c_priv *priv; - int ret; - - ret = nouveau_i2c_create(parent, engine, oclass, nvd0_i2c_sclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nvd0_i2c_oclass = { - .handle = NV_SUBDEV(I2C, 0xd0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvd0_i2c_ctor, +struct nouveau_oclass * +nvd0_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0xd0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, .dtor = _nouveau_i2c_dtor, .init = _nouveau_i2c_init, .fini = _nouveau_i2c_fini, }, -}; + .sclass = nvd0_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv94_i2c_pad_oclass, + .aux = 4, + .aux_stat = nv94_aux_stat, + .aux_mask = nv94_aux_mask, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c new file mode 100644 index 00000000000..cae77e1ad8d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c @@ -0,0 +1,72 @@ +/* + * 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 "nv50.h" + +static void +nve0_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) +{ + u32 intr = nv_rd32(i2c, 0x00dc60); + u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i; + for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { + if ((stat & (1 << (i * 4)))) *hi |= 1 << i; + if ((stat & (2 << (i * 4)))) *lo |= 1 << i; + if ((stat & (4 << (i * 4)))) *rq |= 1 << i; + if ((stat & (8 << (i * 4)))) *tx |= 1 << i; + } + nv_wr32(i2c, 0x00dc60, intr); +} + +static void +nve0_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data) +{ + u32 temp = nv_rd32(i2c, 0x00dc68), i; + for (i = 0; i < 8; i++) { + if (mask & (1 << i)) { + if (!(data & (1 << i))) { + temp &= ~(type << (i * 4)); + continue; + } + temp |= type << (i * 4); + } + } + nv_wr32(i2c, 0x00dc68, temp); +} + +struct nouveau_oclass * +nve0_i2c_oclass = &(struct nouveau_i2c_impl) { + .base.handle = NV_SUBDEV(I2C, 0xe0), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nouveau_i2c_ctor, + .dtor = _nouveau_i2c_dtor, + .init = _nouveau_i2c_init, + .fini = _nouveau_i2c_fini, + }, + .sclass = nvd0_i2c_sclass, + .pad_x = &nv04_i2c_pad_oclass, + .pad_s = &nv94_i2c_pad_oclass, + .aux = 4, + .aux_stat = nve0_aux_stat, + .aux_mask = nve0_aux_mask, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c new file mode 100644 index 00000000000..e9e412477c1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c @@ -0,0 +1,84 @@ +/* + * 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 "pad.h" + +int +_nvkm_i2c_pad_fini(struct nouveau_object *object, bool suspend) +{ + struct nvkm_i2c_pad *pad = (void *)object; + DBG("-> NULL\n"); + pad->port = NULL; + return nouveau_object_fini(&pad->base, suspend); +} + +int +_nvkm_i2c_pad_init(struct nouveau_object *object) +{ + struct nvkm_i2c_pad *pad = (void *)object; + DBG("-> PORT:%02x\n", pad->next->index); + pad->port = pad->next; + return nouveau_object_init(&pad->base); +} + +int +nvkm_i2c_pad_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int index, + int size, void **pobject) +{ + struct nouveau_i2c *i2c = (void *)engine; + struct nouveau_i2c_port *port; + struct nvkm_i2c_pad *pad; + int ret; + + list_for_each_entry(port, &i2c->ports, head) { + pad = nvkm_i2c_pad(port); + if (pad->index == index) { + atomic_inc(&nv_object(pad)->refcount); + *pobject = pad; + return 1; + } + } + + ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject); + pad = *pobject; + if (ret) + return ret; + + pad->index = index; + return 0; +} + +int +_nvkm_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 index, + struct nouveau_object **pobject) +{ + struct nvkm_i2c_pad *pad; + int ret; + ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); + *pobject = nv_object(pad); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h new file mode 100644 index 00000000000..452ac10c300 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h @@ -0,0 +1,58 @@ +#ifndef __NVKM_I2C_PAD_H__ +#define __NVKM_I2C_PAD_H__ + +#include "priv.h" + +struct nvkm_i2c_pad { + struct nouveau_object base; + int index; + struct nouveau_i2c_port *port; + struct nouveau_i2c_port *next; +}; + +static inline struct nvkm_i2c_pad * +nvkm_i2c_pad(struct nouveau_i2c_port *port) +{ + struct nouveau_object *pad = nv_object(port); + while (pad->parent) + pad = pad->parent; + return (void *)pad; +} + +#define nvkm_i2c_pad_create(p,e,o,i,d) \ + nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d) +#define nvkm_i2c_pad_destroy(p) ({ \ + struct nvkm_i2c_pad *_p = (p); \ + _nvkm_i2c_pad_dtor(nv_object(_p)); \ +}) +#define nvkm_i2c_pad_init(p) ({ \ + struct nvkm_i2c_pad *_p = (p); \ + _nvkm_i2c_pad_init(nv_object(_p)); \ +}) +#define nvkm_i2c_pad_fini(p,s) ({ \ + struct nvkm_i2c_pad *_p = (p); \ + _nvkm_i2c_pad_fini(nv_object(_p), (s)); \ +}) + +int nvkm_i2c_pad_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int index, int, void **); + +int _nvkm_i2c_pad_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +#define _nvkm_i2c_pad_dtor nouveau_object_destroy +int _nvkm_i2c_pad_init(struct nouveau_object *); +int _nvkm_i2c_pad_fini(struct nouveau_object *, bool); + +#ifndef MSG +#define MSG(l,f,a...) do { \ + struct nvkm_i2c_pad *_pad = (void *)pad; \ + nv_##l(nv_object(_pad)->engine, "PAD:%c:%02x: "f, \ + _pad->index >= 0x100 ? 'X' : 'S', \ + _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \ +} while(0) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c new file mode 100644 index 00000000000..2c4b61296dd --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c @@ -0,0 +1,35 @@ +/* + * 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 "pad.h" + +struct nouveau_oclass +nv04_i2c_pad_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = _nvkm_i2c_pad_ctor, + .dtor = _nvkm_i2c_pad_dtor, + .init = _nvkm_i2c_pad_init, + .fini = _nvkm_i2c_pad_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c new file mode 100644 index 00000000000..0dc6753014f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c @@ -0,0 +1,86 @@ +/* + * 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 "pad.h" + +struct nv94_i2c_pad { + struct nvkm_i2c_pad base; + int addr; +}; + +static int +nv94_i2c_pad_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_i2c *i2c = (void *)object->engine; + struct nv94_i2c_pad *pad = (void *)object; + nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001); + return nvkm_i2c_pad_fini(&pad->base, suspend); +} + +static int +nv94_i2c_pad_init(struct nouveau_object *object) +{ + struct nouveau_i2c *i2c = (void *)object->engine; + struct nv94_i2c_pad *pad = (void *)object; + + switch (nv_oclass(pad->base.next)->handle) { + case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): + nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002); + break; + case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): + default: + nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001); + break; + } + + nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000); + return nvkm_i2c_pad_init(&pad->base); +} + +static int +nv94_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 index, + struct nouveau_object **pobject) +{ + struct nv94_i2c_pad *pad; + int ret; + + ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); + *pobject = nv_object(pad); + if (ret) + return ret; + + pad->addr = index * 0x50;; + return 0; +} + +struct nouveau_oclass +nv94_i2c_pad_oclass = { + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv94_i2c_pad_ctor, + .dtor = _nvkm_i2c_pad_dtor, + .init = nv94_i2c_pad_init, + .fini = nv94_i2c_pad_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h new file mode 100644 index 00000000000..a8ff6e077af --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h @@ -0,0 +1,15 @@ +#ifndef __NVKM_I2C_PORT_H__ +#define __NVKM_I2C_PORT_H__ + +#include "priv.h" + +#ifndef MSG +#define MSG(l,f,a...) do { \ + struct nouveau_i2c_port *_port = (void *)port; \ + nv_##l(nv_object(_port)->engine, "PORT:%02x: "f, _port->index, ##a); \ +} while(0) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h new file mode 100644 index 00000000000..780090b6425 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h @@ -0,0 +1,85 @@ +#ifndef __NVKM_I2C_H__ +#define __NVKM_I2C_H__ + +#include <subdev/i2c.h> + +extern struct nouveau_oclass nv04_i2c_pad_oclass; +extern struct nouveau_oclass nv94_i2c_pad_oclass; + +#define nouveau_i2c_port_create(p,e,o,i,a,f,d) \ + nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \ + sizeof(**d), (void **)d) +#define nouveau_i2c_port_destroy(p) ({ \ + struct nouveau_i2c_port *port = (p); \ + _nouveau_i2c_port_dtor(nv_object(i2c)); \ +}) +#define nouveau_i2c_port_init(p) \ + nouveau_object_init(&(p)->base) +#define nouveau_i2c_port_fini(p,s) \ + nouveau_object_fini(&(p)->base, (s)) + +int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u8, + const struct i2c_algorithm *, + const struct nouveau_i2c_func *, + int, void **); +void _nouveau_i2c_port_dtor(struct nouveau_object *); +#define _nouveau_i2c_port_init nouveau_object_init +int _nouveau_i2c_port_fini(struct nouveau_object *, bool); + +#define nouveau_i2c_create(p,e,o,d) \ + nouveau_i2c_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_i2c_destroy(p) ({ \ + struct nouveau_i2c *i2c = (p); \ + _nouveau_i2c_dtor(nv_object(i2c)); \ +}) +#define nouveau_i2c_init(p) ({ \ + struct nouveau_i2c *i2c = (p); \ + _nouveau_i2c_init(nv_object(i2c)); \ +}) +#define nouveau_i2c_fini(p,s) ({ \ + struct nouveau_i2c *i2c = (p); \ + _nouveau_i2c_fini(nv_object(i2c), (s)); \ +}) + +int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +int _nouveau_i2c_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void _nouveau_i2c_dtor(struct nouveau_object *); +int _nouveau_i2c_init(struct nouveau_object *); +int _nouveau_i2c_fini(struct nouveau_object *, bool); + +extern struct nouveau_oclass nouveau_anx9805_sclass[]; +extern struct nouveau_oclass nvd0_i2c_sclass[]; + +extern const struct i2c_algorithm nouveau_i2c_bit_algo; +extern const struct i2c_algorithm nouveau_i2c_aux_algo; + +struct nouveau_i2c_impl { + struct nouveau_oclass base; + + /* supported i2c port classes */ + struct nouveau_oclass *sclass; + struct nouveau_oclass *pad_x; + struct nouveau_oclass *pad_s; + + /* number of native dp aux channels present */ + int aux; + + /* read and ack pending interrupts, returning only data + * for ports that have not been masked off, while still + * performing the ack for anything that was pending. + */ + void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *); + + /* mask on/off interrupt types for a given set of auxch + */ + void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32); +}; + +void nv94_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *); +void nv94_aux_mask(struct nouveau_i2c *, u32, u32, u32); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c new file mode 100644 index 00000000000..245f0ebaa6a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c @@ -0,0 +1,103 @@ +/* + * 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/ibus.h> +#include <subdev/timer.h> + +struct gk20a_ibus_priv { + struct nouveau_ibus base; +}; + +static void +gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv) +{ + nv_mask(priv, 0x137250, 0x3f, 0); + + nv_mask(priv, 0x000200, 0x20, 0); + usleep_range(20, 30); + nv_mask(priv, 0x000200, 0x20, 0x20); + + nv_wr32(priv, 0x12004c, 0x4); + nv_wr32(priv, 0x122204, 0x2); + nv_rd32(priv, 0x122204); +} + +static void +gk20a_ibus_intr(struct nouveau_subdev *subdev) +{ + struct gk20a_ibus_priv *priv = (void *)subdev; + u32 status0 = nv_rd32(priv, 0x120058); + + if (status0 & 0x7) { + nv_debug(priv, "resetting priv ring\n"); + gk20a_ibus_init_priv_ring(priv); + } + + /* Acknowledge interrupt */ + nv_mask(priv, 0x12004c, 0x2, 0x2); + + if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00)) + nv_warn(priv, "timeout waiting for ringmaster ack\n"); +} + +static int +gk20a_ibus_init(struct nouveau_object *object) +{ + struct gk20a_ibus_priv *priv = (void *)object; + int ret; + + ret = _nouveau_ibus_init(object); + if (ret) + return ret; + + gk20a_ibus_init_priv_ring(priv); + + return 0; +} + +static int +gk20a_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gk20a_ibus_priv *priv; + int ret; + + ret = nouveau_ibus_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_subdev(priv)->intr = gk20a_ibus_intr; + return 0; +} + +struct nouveau_oclass +gk20a_ibus_oclass = { + .handle = NV_SUBDEV(IBUS, 0xea), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gk20a_ibus_ctor, + .dtor = _nouveau_ibus_dtor, + .init = gk20a_ibus_init, + .fini = _nouveau_ibus_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c index 7120124dcea..ebef970a064 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c @@ -95,6 +95,23 @@ nve0_ibus_intr(struct nouveau_subdev *subdev) } static int +nve0_ibus_init(struct nouveau_object *object) +{ + struct nve0_ibus_priv *priv = (void *)object; + int ret = nouveau_ibus_init(&priv->base); + if (ret == 0) { + nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000); + nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200); + nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800); + nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100); + nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff); + nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200); + nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880); + } + return ret; +} + +static int nve0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -117,7 +134,7 @@ nve0_ibus_oclass = { .ofuncs = &(struct nouveau_ofuncs) { .ctor = nve0_ibus_ctor, .dtor = _nouveau_ibus_dtor, - .init = _nouveau_ibus_init, + .init = nve0_ibus_init, .fini = _nouveau_ibus_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c index 6565f3dbbe0..14706d9842c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c @@ -22,7 +22,24 @@ * Authors: Ben Skeggs */ -#include <subdev/instmem.h> +#include "priv.h" + +/****************************************************************************** + * instmem object base implementation + *****************************************************************************/ + +void +_nouveau_instobj_dtor(struct nouveau_object *object) +{ + struct nouveau_instmem *imem = (void *)object->engine; + struct nouveau_instobj *iobj = (void *)object; + + mutex_lock(&nv_subdev(imem)->mutex); + list_del(&iobj->head); + mutex_unlock(&nv_subdev(imem)->mutex); + + return nouveau_object_destroy(&iobj->base); +} int nouveau_instobj_create_(struct nouveau_object *parent, @@ -46,73 +63,26 @@ nouveau_instobj_create_(struct nouveau_object *parent, return 0; } -void -nouveau_instobj_destroy(struct nouveau_instobj *iobj) -{ - struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine); +/****************************************************************************** + * instmem subdev base implementation + *****************************************************************************/ - mutex_lock(&subdev->mutex); - list_del(&iobj->head); - mutex_unlock(&subdev->mutex); - - return nouveau_object_destroy(&iobj->base); -} - -void -_nouveau_instobj_dtor(struct nouveau_object *object) +static int +nouveau_instmem_alloc(struct nouveau_instmem *imem, + struct nouveau_object *parent, u32 size, u32 align, + struct nouveau_object **pobject) { - struct nouveau_instobj *iobj = (void *)object; - return nouveau_instobj_destroy(iobj); + struct nouveau_object *engine = nv_object(imem); + struct nouveau_instmem_impl *impl = (void *)engine->oclass; + struct nouveau_instobj_args args = { .size = size, .align = align }; + return nouveau_object_ctor(parent, engine, impl->instobj, &args, + sizeof(args), pobject); } int -nouveau_instmem_create_(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, - int length, void **pobject) -{ - struct nouveau_instmem *imem; - int ret; - - ret = nouveau_subdev_create_(parent, engine, oclass, 0, - "INSTMEM", "instmem", length, pobject); - imem = *pobject; - if (ret) - return ret; - - INIT_LIST_HEAD(&imem->list); - return 0; -} - -int -nouveau_instmem_init(struct nouveau_instmem *imem) -{ - struct nouveau_instobj *iobj; - int ret, i; - - ret = nouveau_subdev_init(&imem->base); - if (ret) - return ret; - - mutex_lock(&imem->base.mutex); - - list_for_each_entry(iobj, &imem->list, head) { - if (iobj->suspend) { - for (i = 0; i < iobj->size; i += 4) - nv_wo32(iobj, i, iobj->suspend[i / 4]); - vfree(iobj->suspend); - iobj->suspend = NULL; - } - } - - mutex_unlock(&imem->base.mutex); - - return 0; -} - -int -nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) +_nouveau_instmem_fini(struct nouveau_object *object, bool suspend) { + struct nouveau_instmem *imem = (void *)object; struct nouveau_instobj *iobj; int i, ret = 0; @@ -143,12 +113,45 @@ int _nouveau_instmem_init(struct nouveau_object *object) { struct nouveau_instmem *imem = (void *)object; - return nouveau_instmem_init(imem); + struct nouveau_instobj *iobj; + int ret, i; + + ret = nouveau_subdev_init(&imem->base); + if (ret) + return ret; + + mutex_lock(&imem->base.mutex); + + list_for_each_entry(iobj, &imem->list, head) { + if (iobj->suspend) { + for (i = 0; i < iobj->size; i += 4) + nv_wo32(iobj, i, iobj->suspend[i / 4]); + vfree(iobj->suspend); + iobj->suspend = NULL; + } + } + + mutex_unlock(&imem->base.mutex); + + return 0; } int -_nouveau_instmem_fini(struct nouveau_object *object, bool suspend) +nouveau_instmem_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, + int length, void **pobject) { - struct nouveau_instmem *imem = (void *)object; - return nouveau_instmem_fini(imem, suspend); + struct nouveau_instmem *imem; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, + "INSTMEM", "instmem", length, pobject); + imem = *pobject; + if (ret) + return ret; + + INIT_LIST_HEAD(&imem->list); + imem->alloc = nouveau_instmem_alloc; + 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 795393d7b2f..7b64befee48 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c @@ -22,10 +22,35 @@ * Authors: Ben Skeggs */ -#include <subdev/fb.h> - #include "nv04.h" +/****************************************************************************** + * instmem object implementation + *****************************************************************************/ + +static u32 +nv04_instobj_rd32(struct nouveau_object *object, u64 addr) +{ + struct nv04_instobj_priv *node = (void *)object; + return nv_ro32(object->engine, node->mem->offset + addr); +} + +static void +nv04_instobj_wr32(struct nouveau_object *object, u64 addr, u32 data) +{ + struct nv04_instobj_priv *node = (void *)object; + nv_wo32(object->engine, node->mem->offset + addr, data); +} + +static void +nv04_instobj_dtor(struct nouveau_object *object) +{ + struct nv04_instmem_priv *priv = (void *)object->engine; + struct nv04_instobj_priv *node = (void *)object; + nouveau_mm_free(&priv->heap, &node->mem); + nouveau_instobj_destroy(&node->base); +} + static int nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -33,18 +58,19 @@ nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, { struct nv04_instmem_priv *priv = (void *)engine; struct nv04_instobj_priv *node; - int ret, align; + struct nouveau_instobj_args *args = data; + int ret; - align = (unsigned long)data; - if (!align) - align = 1; + if (!args->align) + args->align = 1; ret = nouveau_instobj_create(parent, engine, oclass, &node); *pobject = nv_object(node); if (ret) return ret; - ret = nouveau_mm_head(&priv->heap, 1, size, size, align, &node->mem); + ret = nouveau_mm_head(&priv->heap, 1, args->size, args->size, + args->align, &node->mem); if (ret) return ret; @@ -53,32 +79,9 @@ nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -static void -nv04_instobj_dtor(struct nouveau_object *object) -{ - struct nv04_instmem_priv *priv = (void *)object->engine; - struct nv04_instobj_priv *node = (void *)object; - nouveau_mm_free(&priv->heap, &node->mem); - nouveau_instobj_destroy(&node->base); -} - -static u32 -nv04_instobj_rd32(struct nouveau_object *object, u64 addr) -{ - struct nv04_instobj_priv *node = (void *)object; - return nv_ro32(object->engine, node->mem->offset + addr); -} - -static void -nv04_instobj_wr32(struct nouveau_object *object, u64 addr, u32 data) -{ - struct nv04_instobj_priv *node = (void *)object; - nv_wo32(object->engine, node->mem->offset + addr, data); -} - -static struct nouveau_oclass +struct nouveau_instobj_impl nv04_instobj_oclass = { - .ofuncs = &(struct nouveau_ofuncs) { + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_instobj_ctor, .dtor = nv04_instobj_dtor, .init = _nouveau_instobj_init, @@ -88,19 +91,34 @@ nv04_instobj_oclass = { }, }; -int -nv04_instmem_alloc(struct nouveau_instmem *imem, struct nouveau_object *parent, - u32 size, u32 align, struct nouveau_object **pobject) +/****************************************************************************** + * instmem subdev implementation + *****************************************************************************/ + +static u32 +nv04_instmem_rd32(struct nouveau_object *object, u64 addr) { - struct nouveau_object *engine = nv_object(imem); - int ret; + return nv_rd32(object, 0x700000 + addr); +} - ret = nouveau_object_ctor(parent, engine, &nv04_instobj_oclass, - (void *)(unsigned long)align, size, pobject); - if (ret) - return ret; +static void +nv04_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data) +{ + return nv_wr32(object, 0x700000 + addr, data); +} - return 0; +void +nv04_instmem_dtor(struct nouveau_object *object) +{ + struct nv04_instmem_priv *priv = (void *)object; + nouveau_gpuobj_ref(NULL, &priv->ramfc); + nouveau_gpuobj_ref(NULL, &priv->ramro); + nouveau_ramht_ref(NULL, &priv->ramht); + nouveau_gpuobj_ref(NULL, &priv->vbios); + nouveau_mm_fini(&priv->heap); + if (priv->iomem) + iounmap(priv->iomem); + nouveau_instmem_destroy(&priv->base); } static int @@ -118,7 +136,6 @@ nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, /* PRAMIN aperture maps over the end of VRAM, reserve it */ priv->base.reserved = 512 * 1024; - priv->base.alloc = nv04_instmem_alloc; ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1); if (ret) @@ -150,36 +167,10 @@ nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -void -nv04_instmem_dtor(struct nouveau_object *object) -{ - struct nv04_instmem_priv *priv = (void *)object; - nouveau_gpuobj_ref(NULL, &priv->ramfc); - nouveau_gpuobj_ref(NULL, &priv->ramro); - nouveau_ramht_ref(NULL, &priv->ramht); - nouveau_gpuobj_ref(NULL, &priv->vbios); - nouveau_mm_fini(&priv->heap); - if (priv->iomem) - iounmap(priv->iomem); - nouveau_instmem_destroy(&priv->base); -} - -static u32 -nv04_instmem_rd32(struct nouveau_object *object, u64 addr) -{ - return nv_rd32(object, 0x700000 + addr); -} - -static void -nv04_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data) -{ - return nv_wr32(object, 0x700000 + addr, data); -} - -struct nouveau_oclass -nv04_instmem_oclass = { - .handle = NV_SUBDEV(INSTMEM, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv04_instmem_oclass = &(struct nouveau_instmem_impl) { + .base.handle = NV_SUBDEV(INSTMEM, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_instmem_ctor, .dtor = nv04_instmem_dtor, .init = _nouveau_instmem_init, @@ -187,4 +178,5 @@ nv04_instmem_oclass = { .rd32 = nv04_instmem_rd32, .wr32 = nv04_instmem_wr32, }, -}; + .instobj = &nv04_instobj_oclass.base, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h index b15b6131023..095fbc6fc09 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h @@ -5,7 +5,9 @@ #include <core/ramht.h> #include <core/mm.h> -#include <subdev/instmem.h> +#include "priv.h" + +extern struct nouveau_instobj_impl nv04_instobj_oclass; struct nv04_instmem_priv { struct nouveau_instmem base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c index b10a143787a..8803809f9fc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c @@ -26,13 +26,30 @@ #include "nv04.h" +/****************************************************************************** + * instmem subdev implementation + *****************************************************************************/ + +static u32 +nv40_instmem_rd32(struct nouveau_object *object, u64 addr) +{ + struct nv04_instmem_priv *priv = (void *)object; + return ioread32_native(priv->iomem + addr); +} + +static void +nv40_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data) +{ + struct nv04_instmem_priv *priv = (void *)object; + iowrite32_native(data, priv->iomem + addr); +} + static int nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nouveau_device *device = nv_device(parent); - struct pci_dev *pdev = device->pdev; struct nv04_instmem_priv *priv; int ret, bar, vs; @@ -42,13 +59,13 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; /* map bar */ - if (pci_resource_len(pdev, 2)) + if (nv_device_resource_len(device, 2)) bar = 2; else bar = 3; - priv->iomem = ioremap(pci_resource_start(pdev, bar), - pci_resource_len(pdev, bar)); + priv->iomem = ioremap(nv_device_resource_start(device, bar), + nv_device_resource_len(device, bar)); if (!priv->iomem) { nv_error(priv, "unable to map PRAMIN BAR\n"); return -EFAULT; @@ -69,7 +86,6 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->base.reserved += 512 * 1024; /* object storage */ priv->base.reserved = round_up(priv->base.reserved, 4096); - priv->base.alloc = nv04_instmem_alloc; ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1); if (ret) @@ -106,24 +122,10 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -static u32 -nv40_instmem_rd32(struct nouveau_object *object, u64 addr) -{ - struct nv04_instmem_priv *priv = (void *)object; - return ioread32_native(priv->iomem + addr); -} - -static void -nv40_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data) -{ - struct nv04_instmem_priv *priv = (void *)object; - iowrite32_native(data, priv->iomem + addr); -} - -struct nouveau_oclass -nv40_instmem_oclass = { - .handle = NV_SUBDEV(INSTMEM, 0x40), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv40_instmem_oclass = &(struct nouveau_instmem_impl) { + .base.handle = NV_SUBDEV(INSTMEM, 0x40), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv40_instmem_ctor, .dtor = nv04_instmem_dtor, .init = _nouveau_instmem_init, @@ -131,4 +133,5 @@ nv40_instmem_oclass = { .rd32 = nv40_instmem_rd32, .wr32 = nv40_instmem_wr32, }, -}; + .instobj = &nv04_instobj_oclass.base, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c index 97bc5dff93e..7cb3b098a08 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c @@ -22,11 +22,11 @@ * Authors: Ben Skeggs */ -#include <subdev/instmem.h> #include <subdev/fb.h> - #include <core/mm.h> +#include "priv.h" + struct nv50_instmem_priv { struct nouveau_instmem base; spinlock_t lock; @@ -38,42 +38,9 @@ struct nv50_instobj_priv { struct nouveau_mem *mem; }; -static int -nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nouveau_fb *pfb = nouveau_fb(parent); - struct nv50_instobj_priv *node; - u32 align = (unsigned long)data; - int ret; - - size = max((size + 4095) & ~4095, (u32)4096); - align = max((align + 4095) & ~4095, (u32)4096); - - ret = nouveau_instobj_create(parent, engine, oclass, &node); - *pobject = nv_object(node); - if (ret) - return ret; - - ret = pfb->ram->get(pfb, size, align, 0, 0x800, &node->mem); - if (ret) - return ret; - - node->base.addr = node->mem->offset; - node->base.size = node->mem->size << 12; - node->mem->page_shift = 12; - return 0; -} - -static void -nv50_instobj_dtor(struct nouveau_object *object) -{ - struct nv50_instobj_priv *node = (void *)object; - struct nouveau_fb *pfb = nouveau_fb(object); - pfb->ram->put(pfb, &node->mem); - nouveau_instobj_destroy(&node->base); -} +/****************************************************************************** + * instmem object implementation + *****************************************************************************/ static u32 nv50_instobj_rd32(struct nouveau_object *object, u64 offset) @@ -113,9 +80,46 @@ nv50_instobj_wr32(struct nouveau_object *object, u64 offset, u32 data) spin_unlock_irqrestore(&priv->lock, flags); } -static struct nouveau_oclass +static void +nv50_instobj_dtor(struct nouveau_object *object) +{ + struct nv50_instobj_priv *node = (void *)object; + struct nouveau_fb *pfb = nouveau_fb(object); + pfb->ram->put(pfb, &node->mem); + nouveau_instobj_destroy(&node->base); +} + +static int +nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nouveau_fb *pfb = nouveau_fb(parent); + struct nouveau_instobj_args *args = data; + struct nv50_instobj_priv *node; + int ret; + + args->size = max((args->size + 4095) & ~4095, (u32)4096); + args->align = max((args->align + 4095) & ~4095, (u32)4096); + + ret = nouveau_instobj_create(parent, engine, oclass, &node); + *pobject = nv_object(node); + if (ret) + return ret; + + ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem); + if (ret) + return ret; + + node->base.addr = node->mem->offset; + node->base.size = node->mem->size << 12; + node->mem->page_shift = 12; + return 0; +} + +static struct nouveau_instobj_impl nv50_instobj_oclass = { - .ofuncs = &(struct nouveau_ofuncs) { + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_instobj_ctor, .dtor = nv50_instobj_dtor, .init = _nouveau_instobj_init, @@ -125,13 +129,16 @@ nv50_instobj_oclass = { }, }; +/****************************************************************************** + * instmem subdev implementation + *****************************************************************************/ + static int -nv50_instmem_alloc(struct nouveau_instmem *imem, struct nouveau_object *parent, - u32 size, u32 align, struct nouveau_object **pobject) +nv50_instmem_fini(struct nouveau_object *object, bool suspend) { - struct nouveau_object *engine = nv_object(imem); - return nouveau_object_ctor(parent, engine, &nv50_instobj_oclass, - (void *)(unsigned long)align, size, pobject); + struct nv50_instmem_priv *priv = (void *)object; + priv->addr = ~0ULL; + return nouveau_instmem_fini(&priv->base, suspend); } static int @@ -148,25 +155,17 @@ nv50_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; spin_lock_init(&priv->lock); - priv->base.alloc = nv50_instmem_alloc; return 0; } -static int -nv50_instmem_fini(struct nouveau_object *object, bool suspend) -{ - struct nv50_instmem_priv *priv = (void *)object; - priv->addr = ~0ULL; - return nouveau_instmem_fini(&priv->base, suspend); -} - -struct nouveau_oclass -nv50_instmem_oclass = { - .handle = NV_SUBDEV(INSTMEM, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv50_instmem_oclass = &(struct nouveau_instmem_impl) { + .base.handle = NV_SUBDEV(INSTMEM, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_instmem_ctor, .dtor = _nouveau_instmem_dtor, .init = _nouveau_instmem_init, .fini = nv50_instmem_fini, }, -}; + .instobj = &nv50_instobj_oclass.base, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h new file mode 100644 index 00000000000..8d67dedc5bb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h @@ -0,0 +1,56 @@ +#ifndef __NVKM_INSTMEM_PRIV_H__ +#define __NVKM_INSTMEM_PRIV_H__ + +#include <subdev/instmem.h> + +struct nouveau_instobj_impl { + struct nouveau_oclass base; +}; + +struct nouveau_instobj_args { + u32 size; + u32 align; +}; + +#define nouveau_instobj_create(p,e,o,d) \ + nouveau_instobj_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_instobj_destroy(p) ({ \ + struct nouveau_instobj *iobj = (p); \ + _nouveau_instobj_dtor(nv_object(iobj)); \ +}) +#define nouveau_instobj_init(p) \ + nouveau_object_init(&(p)->base) +#define nouveau_instobj_fini(p,s) \ + nouveau_object_fini(&(p)->base, (s)) + +int nouveau_instobj_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +void _nouveau_instobj_dtor(struct nouveau_object *); +#define _nouveau_instobj_init nouveau_object_init +#define _nouveau_instobj_fini nouveau_object_fini + +struct nouveau_instmem_impl { + struct nouveau_oclass base; + struct nouveau_oclass *instobj; +}; + +#define nouveau_instmem_create(p,e,o,d) \ + nouveau_instmem_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_instmem_destroy(p) \ + nouveau_subdev_destroy(&(p)->base) +#define nouveau_instmem_init(p) ({ \ + struct nouveau_instmem *imem = (p); \ + _nouveau_instmem_init(nv_object(imem)); \ +}) +#define nouveau_instmem_fini(p,s) ({ \ + struct nouveau_instmem *imem = (p); \ + _nouveau_instmem_fini(nv_object(imem), (s)); \ +}) + +int nouveau_instmem_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, void **); +#define _nouveau_instmem_dtor _nouveau_subdev_dtor +int _nouveau_instmem_init(struct nouveau_object *); +int _nouveau_instmem_fini(struct nouveau_object *, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c index cce65cc5651..f2f3338a967 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c @@ -22,44 +22,35 @@ * Authors: Ben Skeggs */ -#include <subdev/ltcg.h> #include <subdev/fb.h> #include <subdev/timer.h> -struct nvc0_ltcg_priv { - struct nouveau_ltcg base; - u32 part_nr; - u32 subp_nr; - u32 num_tags; - u32 tag_base; - struct nouveau_mm tags; - struct nouveau_mm_node *tag_ram; -}; +#include "gf100.h" static void -nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp) +gf100_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) { - u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); - u32 stat = nv_rd32(priv, subp_base + 0x020); + u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400); + u32 stat = nv_rd32(priv, base + 0x020); if (stat) { - nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat); - nv_wr32(priv, subp_base + 0x020, stat); + nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); + nv_wr32(priv, base + 0x020, stat); } } static void -nvc0_ltcg_intr(struct nouveau_subdev *subdev) +gf100_ltcg_intr(struct nouveau_subdev *subdev) { - struct nvc0_ltcg_priv *priv = (void *)subdev; - u32 units; - - units = nv_rd32(priv, 0x00017c); - while (units) { - u32 subp, unit = ffs(units) - 1; - for (subp = 0; subp < priv->subp_nr; subp++) - nvc0_ltcg_subp_isr(priv, unit, subp); - units &= ~(1 << unit); + struct gf100_ltcg_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); + mask &= ~(1 << ltc); } /* we do something horribly wrong and upset PMFB a lot, so mask off @@ -68,11 +59,11 @@ nvc0_ltcg_intr(struct nouveau_subdev *subdev) nv_mask(priv, 0x000640, 0x02000000, 0x00000000); } -static int -nvc0_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n, +int +gf100_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n, struct nouveau_mm_node **pnode) { - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; int ret; ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode); @@ -82,18 +73,18 @@ nvc0_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n, return ret; } -static void -nvc0_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode) +void +gf100_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode) { - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; nouveau_mm_free(&priv->tags, pnode); } static void -nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) +gf100_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) { - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; u32 last = first + count - 1; int p, i; @@ -104,16 +95,16 @@ nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) nv_wr32(priv, 0x17e8c8, 0x4); /* trigger clear */ /* wait until it's finished with clearing */ - for (p = 0; p < priv->part_nr; ++p) { - for (i = 0; i < priv->subp_nr; ++i) + 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); } } /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ -static int -nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) +int +gf100_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct gf100_ltcg_priv *priv) { u32 tag_size, tag_margin, tag_align; int ret; @@ -124,7 +115,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) priv->num_tags = 1 << 17; /* we have 17 bits in PTE */ priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */ - tag_align = priv->part_nr * 0x800; + tag_align = priv->ltc_nr * 0x800; tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align; /* 4 part 4 sub: 0x2000 bytes for 56 tags */ @@ -157,11 +148,11 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) } static int -nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, +gf100_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nvc0_ltcg_priv *priv; + struct gf100_ltcg_priv *priv; struct nouveau_fb *pfb = nouveau_fb(parent); u32 parts, mask; int ret, i; @@ -175,27 +166,27 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, mask = nv_rd32(priv, 0x022554); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) - priv->part_nr++; + priv->ltc_nr++; } - priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; + priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; - ret = nvc0_ltcg_init_tag_ram(pfb, priv); + ret = gf100_ltcg_init_tag_ram(pfb, priv); if (ret) return ret; - priv->base.tags_alloc = nvc0_ltcg_tags_alloc; - priv->base.tags_free = nvc0_ltcg_tags_free; - priv->base.tags_clear = nvc0_ltcg_tags_clear; + 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 = nvc0_ltcg_intr; + nv_subdev(priv)->intr = gf100_ltcg_intr; return 0; } -static void -nvc0_ltcg_dtor(struct nouveau_object *object) +void +gf100_ltcg_dtor(struct nouveau_object *object) { struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + 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); @@ -205,10 +196,10 @@ nvc0_ltcg_dtor(struct nouveau_object *object) } static int -nvc0_ltcg_init(struct nouveau_object *object) +gf100_ltcg_init(struct nouveau_object *object) { struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; int ret; ret = nouveau_ltcg_init(ltcg); @@ -216,20 +207,20 @@ nvc0_ltcg_init(struct nouveau_object *object) return ret; nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - nv_wr32(priv, 0x17e8d8, priv->part_nr); + nv_wr32(priv, 0x17e8d8, priv->ltc_nr); if (nv_device(ltcg)->card_type >= NV_E0) - nv_wr32(priv, 0x17e000, priv->part_nr); + nv_wr32(priv, 0x17e000, priv->ltc_nr); nv_wr32(priv, 0x17e8d4, priv->tag_base); return 0; } -struct nouveau_oclass -nvc0_ltcg_oclass = { +struct nouveau_oclass * +gf100_ltcg_oclass = &(struct nouveau_oclass) { .handle = NV_SUBDEV(LTCG, 0xc0), .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_ltcg_ctor, - .dtor = nvc0_ltcg_dtor, - .init = nvc0_ltcg_init, + .ctor = gf100_ltcg_ctor, + .dtor = gf100_ltcg_dtor, + .init = gf100_ltcg_init, .fini = _nouveau_ltcg_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h new file mode 100644 index 00000000000..87b10b8412e --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h @@ -0,0 +1,21 @@ +#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/ltcg/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c new file mode 100644 index 00000000000..e79d0e81de4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c @@ -0,0 +1,142 @@ +/* + * 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 <subdev/fb.h> +#include <subdev/timer.h> + +#include "gf100.h" + +static void +gm107_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) +{ + u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400); + u32 stat = nv_rd32(priv, base + 0x00c); + + if (stat) { + nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); + nv_wr32(priv, base + 0x00c, stat); + } +} + +static void +gm107_ltcg_intr(struct nouveau_subdev *subdev) +{ + struct gf100_ltcg_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); + 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) +{ + 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)); + + nv_wr32(priv, 0x17e270, first); + nv_wr32(priv, 0x17e274, last); + nv_wr32(priv, 0x17e26c, 0x4); /* trigger clear */ + + /* 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); + } +} + +static int +gm107_ltcg_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); + u32 parts, mask; + int ret, i; + + ret = nouveau_ltcg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + parts = nv_rd32(priv, 0x022438); + mask = nv_rd32(priv, 0x021c14); + for (i = 0; i < parts; i++) { + if (!(mask & (1 << i))) + priv->ltc_nr++; + } + 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); + 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, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c index 37712a6df92..8a5555192fa 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c @@ -25,38 +25,48 @@ #include <subdev/mc.h> #include <core/option.h> +static inline u32 +nouveau_mc_intr_mask(struct nouveau_mc *pmc) +{ + u32 intr = nv_rd32(pmc, 0x000100); + if (intr == 0xffffffff) /* likely fallen off the bus */ + intr = 0x00000000; + return intr; +} + static irqreturn_t nouveau_mc_intr(int irq, void *arg) { struct nouveau_mc *pmc = arg; - const struct nouveau_mc_intr *map = pmc->intr_map; - struct nouveau_device *device = nv_device(pmc); + const struct nouveau_mc_oclass *oclass = (void *)nv_object(pmc)->oclass; + const struct nouveau_mc_intr *map = oclass->intr; struct nouveau_subdev *unit; - u32 stat, intr; - - intr = stat = nv_rd32(pmc, 0x000100); - if (intr == 0xffffffff) - return IRQ_NONE; - while (stat && map->stat) { - if (stat & map->stat) { - unit = nouveau_subdev(pmc, map->unit); - if (unit && unit->intr) - unit->intr(unit); - intr &= ~map->stat; - } - map++; - } + u32 intr; + nv_wr32(pmc, 0x000140, 0x00000000); + nv_rd32(pmc, 0x000140); + intr = nouveau_mc_intr_mask(pmc); if (pmc->use_msi) - nv_wr08(pmc->base.base.parent, 0x00088068, 0xff); + oclass->msi_rearm(pmc); if (intr) { - nv_error(pmc, "unknown intr 0x%08x\n", stat); + u32 stat = intr = nouveau_mc_intr_mask(pmc); + while (map->stat) { + if (intr & map->stat) { + unit = nouveau_subdev(pmc, map->unit); + if (unit && unit->intr) + unit->intr(unit); + stat &= ~map->stat; + } + map++; + } + + if (stat) + nv_error(pmc, "unknown intr 0x%08x\n", stat); } - if (stat == IRQ_HANDLED) - pm_runtime_mark_last_busy(&device->pdev->dev); - return stat ? IRQ_HANDLED : IRQ_NONE; + nv_wr32(pmc, 0x000140, 0x00000001); + return intr ? IRQ_HANDLED : IRQ_NONE; } int @@ -83,7 +93,7 @@ _nouveau_mc_dtor(struct nouveau_object *object) { struct nouveau_device *device = nv_device(object); struct nouveau_mc *pmc = (void *)object; - free_irq(device->pdev->irq, pmc); + free_irq(pmc->irq, pmc); if (pmc->use_msi) pci_disable_msi(device->pdev); nouveau_subdev_destroy(&pmc->base); @@ -91,41 +101,57 @@ _nouveau_mc_dtor(struct nouveau_object *object) int nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, - const struct nouveau_mc_intr *intr_map, - int length, void **pobject) + struct nouveau_oclass *bclass, int length, void **pobject) { + const struct nouveau_mc_oclass *oclass = (void *)bclass; struct nouveau_device *device = nv_device(parent); struct nouveau_mc *pmc; int ret; - ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PMC", + ret = nouveau_subdev_create_(parent, engine, bclass, 0, "PMC", "master", length, pobject); pmc = *pobject; if (ret) return ret; - pmc->intr_map = intr_map; + if (nv_device_is_pci(device)) + switch (device->pdev->device & 0x0ff0) { + case 0x00f0: + case 0x02e0: + /* BR02? NFI how these would be handled yet exactly */ + break; + default: + switch (device->chipset) { + case 0xaa: + /* reported broken, nv also disable it */ + break; + default: + pmc->use_msi = true; + break; + } + + pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", + pmc->use_msi); - switch (device->pdev->device & 0x0ff0) { - case 0x00f0: /* BR02? */ - case 0x02e0: /* BR02? */ - pmc->use_msi = false; - break; - default: - pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", true); - if (pmc->use_msi) { + if (pmc->use_msi && oclass->msi_rearm) { pmc->use_msi = pci_enable_msi(device->pdev) == 0; if (pmc->use_msi) { nv_info(pmc, "MSI interrupts enabled\n"); - nv_wr08(device, 0x00088068, 0xff); + oclass->msi_rearm(pmc); } + } else { + pmc->use_msi = false; } - break; } - ret = request_irq(device->pdev->irq, nouveau_mc_intr, - IRQF_SHARED, "nouveau", pmc); + ret = nv_device_get_irq(device, true); + if (ret < 0) + return ret; + pmc->irq = ret; + + ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau", + pmc); + if (ret < 0) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c index 64aa4edb0d9..2d787e4dfef 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c @@ -22,17 +22,14 @@ * Authors: Ben Skeggs */ -#include <subdev/mc.h> - -struct nv04_mc_priv { - struct nouveau_mc base; -}; +#include "nv04.h" const struct nouveau_mc_intr nv04_mc_intr[] = { { 0x00000001, NVDEV_ENGINE_MPEG }, /* NV17- MPEG/ME */ { 0x00000100, NVDEV_ENGINE_FIFO }, { 0x00001000, NVDEV_ENGINE_GR }, + { 0x00010000, NVDEV_ENGINE_DISP }, { 0x00020000, NVDEV_ENGINE_VP }, /* NV40- */ { 0x00100000, NVDEV_SUBDEV_TIMER }, { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */ @@ -42,7 +39,18 @@ nv04_mc_intr[] = { {} }; -static int +int +nv04_mc_init(struct nouveau_object *object) +{ + struct nv04_mc_priv *priv = (void *)object; + + nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ + nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */ + + return nouveau_mc_init(&priv->base); +} + +int nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -50,7 +58,7 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv04_mc_priv *priv; int ret; - ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv); + ret = nouveau_mc_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -58,24 +66,14 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -int -nv04_mc_init(struct nouveau_object *object) -{ - struct nv04_mc_priv *priv = (void *)object; - - nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ - nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */ - - return nouveau_mc_init(&priv->base); -} - -struct nouveau_oclass -nv04_mc_oclass = { - .handle = NV_SUBDEV(MC, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv04_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_mc_ctor, .dtor = _nouveau_mc_dtor, .init = nv04_mc_init, .fini = _nouveau_mc_fini, }, -}; + .intr = nv04_mc_intr, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h new file mode 100644 index 00000000000..81a408e7d03 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h @@ -0,0 +1,22 @@ +#ifndef __NVKM_MC_NV04_H__ +#define __NVKM_MC_NV04_H__ + +#include <subdev/mc.h> + +struct nv04_mc_priv { + struct nouveau_mc base; +}; + +int nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); + +extern const struct nouveau_mc_intr nv04_mc_intr[]; +int nv04_mc_init(struct nouveau_object *); +void nv40_mc_msi_rearm(struct nouveau_mc *); +int nv44_mc_init(struct nouveau_object *object); +int nv50_mc_init(struct nouveau_object *); +extern const struct nouveau_mc_intr nv50_mc_intr[]; +extern const struct nouveau_mc_intr nvc0_mc_intr[]; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c new file mode 100644 index 00000000000..5b1faecfed2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c @@ -0,0 +1,45 @@ +/* + * 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" + +void +nv40_mc_msi_rearm(struct nouveau_mc *pmc) +{ + struct nv04_mc_priv *priv = (void *)pmc; + nv_wr08(priv, 0x088068, 0xff); +} + +struct nouveau_oclass * +nv40_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x40), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv04_mc_init, + .fini = _nouveau_mc_fini, + }, + .intr = nv04_mc_intr, + .msi_rearm = nv40_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c index d9891782bf2..cc4d0d2d886 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c @@ -22,32 +22,12 @@ * Authors: Ben Skeggs */ -#include <subdev/mc.h> +#include "nv04.h" -struct nv44_mc_priv { - struct nouveau_mc base; -}; - -static int -nv44_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv44_mc_priv *priv; - int ret; - - ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -static int +int nv44_mc_init(struct nouveau_object *object) { - struct nv44_mc_priv *priv = (void *)object; + struct nv04_mc_priv *priv = (void *)object; u32 tmp = nv_rd32(priv, 0x10020c); nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ @@ -60,13 +40,15 @@ nv44_mc_init(struct nouveau_object *object) return nouveau_mc_init(&priv->base); } -struct nouveau_oclass -nv44_mc_oclass = { - .handle = NV_SUBDEV(MC, 0x44), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv44_mc_ctor, +struct nouveau_oclass * +nv44_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x44), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, .dtor = _nouveau_mc_dtor, .init = nv44_mc_init, .fini = _nouveau_mc_fini, }, -}; + .intr = nv04_mc_intr, + .msi_rearm = nv40_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c new file mode 100644 index 00000000000..a75c35ccf25 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c @@ -0,0 +1,45 @@ +/* + * Copyright 2014 Ilia Mirkin + * + * 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: Ilia Mirkin + */ + +#include "nv04.h" + +static void +nv4c_mc_msi_rearm(struct nouveau_mc *pmc) +{ + struct nv04_mc_priv *priv = (void *)pmc; + nv_wr08(priv, 0x088050, 0xff); +} + +struct nouveau_oclass * +nv4c_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x4c), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv44_mc_init, + .fini = _nouveau_mc_fini, + }, + .intr = nv04_mc_intr, + .msi_rearm = nv4c_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c index 2b1afe225db..9ca93e2718f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c @@ -22,14 +22,11 @@ * Authors: Ben Skeggs */ -#include <subdev/mc.h> +#include "nv04.h" -struct nv50_mc_priv { - struct nouveau_mc base; -}; - -static const struct nouveau_mc_intr +const struct nouveau_mc_intr nv50_mc_intr[] = { + { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */ { 0x00000001, NVDEV_ENGINE_MPEG }, { 0x00000100, NVDEV_ENGINE_FIFO }, { 0x00001000, NVDEV_ENGINE_GR }, @@ -37,45 +34,38 @@ nv50_mc_intr[] = { { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */ { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, - { 0x04000000, NVDEV_ENGINE_DISP }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ { 0x10000000, NVDEV_SUBDEV_BUS }, { 0x80000000, NVDEV_ENGINE_SW }, { 0x0002d101, NVDEV_SUBDEV_FB }, {}, }; -static int -nv50_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +static void +nv50_mc_msi_rearm(struct nouveau_mc *pmc) { - struct nv50_mc_priv *priv; - int ret; - - ret = nouveau_mc_create(parent, engine, oclass, nv50_mc_intr, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; + struct nouveau_device *device = nv_device(pmc); + pci_write_config_byte(device->pdev, 0x68, 0xff); } int nv50_mc_init(struct nouveau_object *object) { - struct nv50_mc_priv *priv = (void *)object; + struct nv04_mc_priv *priv = (void *)object; nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */ return nouveau_mc_init(&priv->base); } -struct nouveau_oclass -nv50_mc_oclass = { - .handle = NV_SUBDEV(MC, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv50_mc_ctor, +struct nouveau_oclass * +nv50_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x50), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, .dtor = _nouveau_mc_dtor, .init = nv50_mc_init, .fini = _nouveau_mc_fini, }, -}; + .intr = nv50_mc_intr, + .msi_rearm = nv50_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c new file mode 100644 index 00000000000..5f4541105e7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.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 * +nv94_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x94), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv50_mc_init, + .fini = _nouveau_mc_fini, + }, + .intr = nv50_mc_intr, + .msi_rearm = nv40_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c index 06710419a59..3c76d9038f3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c @@ -22,54 +22,38 @@ * Authors: Ben Skeggs */ -#include <subdev/mc.h> - -struct nv98_mc_priv { - struct nouveau_mc base; -}; +#include "nv04.h" static const struct nouveau_mc_intr nv98_mc_intr[] = { + { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */ { 0x00000001, NVDEV_ENGINE_PPP }, { 0x00000100, NVDEV_ENGINE_FIFO }, { 0x00001000, NVDEV_ENGINE_GR }, { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84:NVA3 */ { 0x00008000, NVDEV_ENGINE_BSP }, { 0x00020000, NVDEV_ENGINE_VP }, + { 0x00040000, NVDEV_SUBDEV_PWR }, /* NVA3:NVC0 */ { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */ { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */ - { 0x04000000, NVDEV_ENGINE_DISP }, { 0x10000000, NVDEV_SUBDEV_BUS }, { 0x80000000, NVDEV_ENGINE_SW }, { 0x0042d101, NVDEV_SUBDEV_FB }, {}, }; -static int -nv98_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv98_mc_priv *priv; - int ret; - - ret = nouveau_mc_create(parent, engine, oclass, nv98_mc_intr, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; -} - -struct nouveau_oclass -nv98_mc_oclass = { - .handle = NV_SUBDEV(MC, 0x98), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nv98_mc_ctor, +struct nouveau_oclass * +nv98_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x98), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, .dtor = _nouveau_mc_dtor, .init = nv50_mc_init, .fini = _nouveau_mc_fini, }, -}; + .intr = nv98_mc_intr, + .msi_rearm = nv40_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c index 104175c5a2d..f9c6a678b47 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c @@ -22,56 +22,49 @@ * Authors: Ben Skeggs */ -#include <subdev/mc.h> +#include "nv04.h" -struct nvc0_mc_priv { - struct nouveau_mc base; -}; - -static const struct nouveau_mc_intr +const struct nouveau_mc_intr nvc0_mc_intr[] = { + { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work. */ { 0x00000001, NVDEV_ENGINE_PPP }, { 0x00000020, NVDEV_ENGINE_COPY0 }, { 0x00000040, NVDEV_ENGINE_COPY1 }, { 0x00000080, NVDEV_ENGINE_COPY2 }, { 0x00000100, NVDEV_ENGINE_FIFO }, { 0x00001000, NVDEV_ENGINE_GR }, + { 0x00002000, NVDEV_SUBDEV_FB }, { 0x00008000, NVDEV_ENGINE_BSP }, { 0x00040000, NVDEV_SUBDEV_THERM }, { 0x00020000, NVDEV_ENGINE_VP }, { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, + { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ + { 0x01000000, NVDEV_SUBDEV_PWR }, { 0x02000000, NVDEV_SUBDEV_LTCG }, - { 0x04000000, NVDEV_ENGINE_DISP }, + { 0x08000000, NVDEV_SUBDEV_FB }, { 0x10000000, NVDEV_SUBDEV_BUS }, { 0x40000000, NVDEV_SUBDEV_IBUS }, { 0x80000000, NVDEV_ENGINE_SW }, {}, }; -static int -nvc0_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +static void +nvc0_mc_msi_rearm(struct nouveau_mc *pmc) { - struct nvc0_mc_priv *priv; - int ret; - - ret = nouveau_mc_create(parent, engine, oclass, nvc0_mc_intr, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - return 0; + struct nv04_mc_priv *priv = (void *)pmc; + nv_wr32(priv, 0x088704, 0x00000000); } -struct nouveau_oclass -nvc0_mc_oclass = { - .handle = NV_SUBDEV(MC, 0xc0), - .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_mc_ctor, +struct nouveau_oclass * +nvc0_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0xc0), + .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 = nvc0_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c new file mode 100644 index 00000000000..837e545aeb9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.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 * +nvc3_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0xc3), + .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/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c index e286e132c7e..51fcf796041 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c @@ -87,55 +87,39 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version) 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 }; u32 mxms_args[] = { 0x00000000 }; - union acpi_object args[4] = { - /* _DSM MUID */ - { .buffer.type = 3, - .buffer.length = sizeof(muid), - .buffer.pointer = muid, - }, - /* spec says this can be zero to mean "highest revision", but - * of course there's at least one bios out there which fails - * unless you pass in exactly the version it supports.. - */ - { .integer.type = ACPI_TYPE_INTEGER, - .integer.value = (version & 0xf0) << 4 | (version & 0x0f), - }, - /* MXMS function */ - { .integer.type = ACPI_TYPE_INTEGER, - .integer.value = 0x00000010, - }, - /* Pointer to MXMS arguments */ - { .buffer.type = ACPI_TYPE_BUFFER, - .buffer.length = sizeof(mxms_args), - .buffer.pointer = (char *)mxms_args, - }, + union acpi_object argv4 = { + .buffer.type = ACPI_TYPE_BUFFER, + .buffer.length = sizeof(mxms_args), + .buffer.pointer = (char *)mxms_args, }; - struct acpi_object_list list = { ARRAY_SIZE(args), args }; - struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_handle handle; - int ret; + int rev; - handle = DEVICE_ACPI_HANDLE(&device->pdev->dev); + handle = ACPI_HANDLE(nv_device_base(device)); if (!handle) return false; - ret = acpi_evaluate_object(handle, "_DSM", &list, &retn); - if (ret) { - nv_debug(mxm, "DSM MXMS failed: %d\n", ret); + /* + * spec says this can be zero to mean "highest revision", but + * of course there's at least one bios out there which fails + * unless you pass in exactly the version it supports.. + */ + rev = (version & 0xf0) << 4 | (version & 0x0f); + obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4); + if (!obj) { + nv_debug(mxm, "DSM MXMS failed\n"); return false; } - obj = retn.pointer; if (obj->type == ACPI_TYPE_BUFFER) { mxm->mxms = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL); - } else - if (obj->type == ACPI_TYPE_INTEGER) { + } else if (obj->type == ACPI_TYPE_INTEGER) { nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); } - kfree(obj); + ACPI_FREE(obj); return mxm->mxms != NULL; } #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c index af129c2e811..fcaabe8456e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c @@ -100,7 +100,7 @@ mxm_match_dcb(struct nouveau_mxm *mxm, u8 *data, void *info) static int mxm_dcb_sanitise_entry(struct nouveau_bios *bios, void *data, int idx, u16 pdcb) { - struct nouveau_mxm *mxm = nouveau_mxm(bios); + struct nouveau_mxm *mxm = data; struct context ctx = { .outp = (u32 *)(bios->data + pdcb) }; u8 type, i2cidx, link, ver, len; u8 *conn; @@ -150,7 +150,7 @@ mxm_dcb_sanitise_entry(struct nouveau_bios *bios, void *data, int idx, u16 pdcb) * common example is DP->eDP. */ conn = bios->data; - conn += dcb_conn(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len); + conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len); type = conn[0]; switch (ctx.desc.conn_type) { case 0x01: /* LVDS */ @@ -199,7 +199,7 @@ mxm_dcb_sanitise(struct nouveau_mxm *mxm) return; } - dcb_outp_foreach(bios, NULL, mxm_dcb_sanitise_entry); + dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry); mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c new file mode 100644 index 00000000000..d4fd3bc9c66 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c @@ -0,0 +1,247 @@ +/* + * 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/pwr.h> +#include <subdev/timer.h> + +static int +nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2], + u32 process, u32 message, u32 data0, u32 data1) +{ + struct nouveau_subdev *subdev = nv_subdev(ppwr); + u32 addr; + + /* wait for a free slot in the fifo */ + addr = nv_rd32(ppwr, 0x10a4a0); + if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8)) + return -EBUSY; + + /* we currently only support a single process at a time waiting + * on a synchronous reply, take the PPWR mutex and tell the + * receive handler what we're waiting for + */ + if (reply) { + mutex_lock(&subdev->mutex); + ppwr->recv.message = message; + ppwr->recv.process = process; + } + + /* acquire data segment access */ + do { + nv_wr32(ppwr, 0x10a580, 0x00000001); + } while (nv_rd32(ppwr, 0x10a580) != 0x00000001); + + /* write the packet */ + nv_wr32(ppwr, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) + + ppwr->send.base)); + nv_wr32(ppwr, 0x10a1c4, process); + nv_wr32(ppwr, 0x10a1c4, message); + nv_wr32(ppwr, 0x10a1c4, data0); + nv_wr32(ppwr, 0x10a1c4, data1); + nv_wr32(ppwr, 0x10a4a0, (addr + 1) & 0x0f); + + /* release data segment access */ + nv_wr32(ppwr, 0x10a580, 0x00000000); + + /* wait for reply, if requested */ + if (reply) { + wait_event(ppwr->recv.wait, (ppwr->recv.process == 0)); + reply[0] = ppwr->recv.data[0]; + reply[1] = ppwr->recv.data[1]; + mutex_unlock(&subdev->mutex); + } + + return 0; +} + +static void +nouveau_pwr_recv(struct work_struct *work) +{ + struct nouveau_pwr *ppwr = + container_of(work, struct nouveau_pwr, recv.work); + u32 process, message, data0, data1; + + /* nothing to do if GET == PUT */ + u32 addr = nv_rd32(ppwr, 0x10a4cc); + if (addr == nv_rd32(ppwr, 0x10a4c8)) + return; + + /* acquire data segment access */ + do { + nv_wr32(ppwr, 0x10a580, 0x00000002); + } while (nv_rd32(ppwr, 0x10a580) != 0x00000002); + + /* read the packet */ + nv_wr32(ppwr, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) + + ppwr->recv.base)); + process = nv_rd32(ppwr, 0x10a1c4); + message = nv_rd32(ppwr, 0x10a1c4); + data0 = nv_rd32(ppwr, 0x10a1c4); + data1 = nv_rd32(ppwr, 0x10a1c4); + nv_wr32(ppwr, 0x10a4cc, (addr + 1) & 0x0f); + + /* release data segment access */ + nv_wr32(ppwr, 0x10a580, 0x00000000); + + /* wake process if it's waiting on a synchronous reply */ + if (ppwr->recv.process) { + if (process == ppwr->recv.process && + message == ppwr->recv.message) { + ppwr->recv.data[0] = data0; + ppwr->recv.data[1] = data1; + ppwr->recv.process = 0; + wake_up(&ppwr->recv.wait); + return; + } + } + + /* right now there's no other expected responses from the engine, + * so assume that any unexpected message is an error. + */ + nv_warn(ppwr, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n", + (char)((process & 0x000000ff) >> 0), + (char)((process & 0x0000ff00) >> 8), + (char)((process & 0x00ff0000) >> 16), + (char)((process & 0xff000000) >> 24), + process, message, data0, data1); +} + +static void +nouveau_pwr_intr(struct nouveau_subdev *subdev) +{ + struct nouveau_pwr *ppwr = (void *)subdev; + u32 disp = nv_rd32(ppwr, 0x10a01c); + u32 intr = nv_rd32(ppwr, 0x10a008) & disp & ~(disp >> 16); + + if (intr & 0x00000020) { + u32 stat = nv_rd32(ppwr, 0x10a16c); + if (stat & 0x80000000) { + nv_error(ppwr, "UAS fault at 0x%06x addr 0x%08x\n", + stat & 0x00ffffff, nv_rd32(ppwr, 0x10a168)); + nv_wr32(ppwr, 0x10a16c, 0x00000000); + intr &= ~0x00000020; + } + } + + if (intr & 0x00000040) { + schedule_work(&ppwr->recv.work); + nv_wr32(ppwr, 0x10a004, 0x00000040); + intr &= ~0x00000040; + } + + if (intr & 0x00000080) { + nv_info(ppwr, "wr32 0x%06x 0x%08x\n", nv_rd32(ppwr, 0x10a7a0), + nv_rd32(ppwr, 0x10a7a4)); + nv_wr32(ppwr, 0x10a004, 0x00000080); + intr &= ~0x00000080; + } + + if (intr) { + nv_error(ppwr, "intr 0x%08x\n", intr); + nv_wr32(ppwr, 0x10a004, intr); + } +} + +int +_nouveau_pwr_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_pwr *ppwr = (void *)object; + + nv_wr32(ppwr, 0x10a014, 0x00000060); + flush_work(&ppwr->recv.work); + + return nouveau_subdev_fini(&ppwr->base, suspend); +} + +int +_nouveau_pwr_init(struct nouveau_object *object) +{ + struct nouveau_pwr *ppwr = (void *)object; + int ret, i; + + ret = nouveau_subdev_init(&ppwr->base); + if (ret) + return ret; + + nv_subdev(ppwr)->intr = nouveau_pwr_intr; + ppwr->message = nouveau_pwr_send; + + /* 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); + + /* 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]); + + /* upload code segment */ + nv_wr32(ppwr, 0x10a180, 0x01000000); + for (i = 0; i < ppwr->code.size / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(ppwr, 0x10a188, i >> 6); + nv_wr32(ppwr, 0x10a184, ppwr->code.data[i]); + } + + /* start it running */ + nv_wr32(ppwr, 0x10a10c, 0x00000000); + nv_wr32(ppwr, 0x10a104, 0x00000000); + nv_wr32(ppwr, 0x10a100, 0x00000002); + + /* wait for valid host->pwr ring configuration */ + if (!nv_wait_ne(ppwr, 0x10a4d0, 0xffffffff, 0x00000000)) + return -EBUSY; + ppwr->send.base = nv_rd32(ppwr, 0x10a4d0) & 0x0000ffff; + ppwr->send.size = nv_rd32(ppwr, 0x10a4d0) >> 16; + + /* wait for valid pwr->host ring configuration */ + if (!nv_wait_ne(ppwr, 0x10a4dc, 0xffffffff, 0x00000000)) + return -EBUSY; + ppwr->recv.base = nv_rd32(ppwr, 0x10a4dc) & 0x0000ffff; + ppwr->recv.size = nv_rd32(ppwr, 0x10a4dc) >> 16; + + nv_wr32(ppwr, 0x10a010, 0x000000e0); + return 0; +} + +int +nouveau_pwr_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) +{ + struct nouveau_pwr *ppwr; + int ret; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PPWR", + "pwr", length, pobject); + ppwr = *pobject; + if (ret) + return ret; + + INIT_WORK(&ppwr->recv.work, nouveau_pwr_recv); + init_waitqueue_head(&ppwr->recv.wait); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc new file mode 100644 index 00000000000..c2bb616a8da --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc @@ -0,0 +1,151 @@ +/* + * 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 + */ + +#ifdef INCLUDE_PROC +process(PROC_HOST, #host_init, #host_recv) +#endif + +/****************************************************************************** + * HOST data segment + *****************************************************************************/ +#ifdef INCLUDE_DATA +// HOST (R)FIFO packet format +.equ #fifo_process 0x00 +.equ #fifo_message 0x04 +.equ #fifo_data0 0x08 +.equ #fifo_data1 0x0c + +// HOST HOST->PWR queue description +.equ #fifo_qlen 4 // log2(size of queue entry in bytes) +.equ #fifo_qnum 3 // log2(max number of entries in queue) +.equ #fifo_qmaskb (1 << #fifo_qnum) // max number of entries in queue +.equ #fifo_qmaskp (#fifo_qmaskb - 1) +.equ #fifo_qmaskf ((#fifo_qmaskb << 1) - 1) +.equ #fifo_qsize (1 << (#fifo_qlen + #fifo_qnum)) +fifo_queue: .skip 128 // #fifo_qsize + +// HOST PWR->HOST queue description +.equ #rfifo_qlen 4 // log2(size of queue entry in bytes) +.equ #rfifo_qnum 3 // log2(max number of entries in queue) +.equ #rfifo_qmaskb (1 << #rfifo_qnum) // max number of entries in queue +.equ #rfifo_qmaskp (#rfifo_qmaskb - 1) +.equ #rfifo_qmaskf ((#rfifo_qmaskb << 1) - 1) +.equ #rfifo_qsize (1 << (#rfifo_qlen + #rfifo_qnum)) +rfifo_queue: .skip 128 // #rfifo_qsize +#endif + +/****************************************************************************** + * HOST code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE +// HOST->PWR comms - dequeue message(s) for process(es) from FIFO +// +// $r15 - current (host) +// $r0 - zero +host_send: + nv_iord($r1, NV_PPWR_FIFO_GET(0)) + nv_iord($r2, NV_PPWR_FIFO_PUT(0)) + cmp b32 $r1 $r2 + bra e #host_send_done + // calculate address of message + and $r14 $r1 #fifo_qmaskp + shl b32 $r14 $r14 #fifo_qlen + add b32 $r14 #fifo_queue + + // read message data, and pass to appropriate process + ld b32 $r11 D[$r14 + #fifo_data1] + ld b32 $r12 D[$r14 + #fifo_data0] + ld b32 $r13 D[$r14 + #fifo_message] + ld b32 $r14 D[$r14 + #fifo_process] + call(send) + + // increment GET + add b32 $r1 0x1 + and $r14 $r1 #fifo_qmaskf + nv_iowr(NV_PPWR_FIFO_GET(0), $r14) + bra #host_send + host_send_done: + ret + +// PWR->HOST comms - enqueue message for HOST to RFIFO +// +// $r15 - current (host) +// $r14 - process +// $r13 - message +// $r12 - message data 0 +// $r11 - message data 1 +// $r0 - zero +host_recv: + // message from intr handler == HOST->PWR comms pending + mov $r1 (PROC_KERN & 0x0000ffff) + sethi $r1 (PROC_KERN & 0xffff0000) + cmp b32 $r14 $r1 + bra e #host_send + + // wait for space in RFIFO + host_recv_wait: + nv_iord($r1, NV_PPWR_RFIFO_GET) + nv_iord($r2, NV_PPWR_RFIFO_PUT) + xor $r1 #rfifo_qmaskb + cmp b32 $r1 $r2 + bra e #host_recv_wait + + and $r3 $r2 #rfifo_qmaskp + shl b32 $r3 #rfifo_qlen + add b32 $r3 #rfifo_queue + + // enqueue message + st b32 D[$r3 + #fifo_data1] $r11 + st b32 D[$r3 + #fifo_data0] $r12 + st b32 D[$r3 + #fifo_message] $r13 + st b32 D[$r3 + #fifo_process] $r14 + + add b32 $r2 0x1 + and $r2 #rfifo_qmaskf + nv_iowr(NV_PPWR_RFIFO_PUT, $r2) + + // notify host of pending message + mov $r2 NV_PPWR_INTR_TRIGGER_USER0 + nv_iowr(NV_PPWR_INTR_TRIGGER, $r2) + ret + +// $r15 - current (host) +// $r0 - zero +host_init: + // store each fifo's base/size in H2D/D2H scratch regs + mov $r1 #fifo_qsize + shl b32 $r1 16 + or $r1 #fifo_queue + nv_iowr(NV_PPWR_H2D, $r1); + + mov $r1 #rfifo_qsize + shl b32 $r1 16 + or $r1 #rfifo_queue + nv_iowr(NV_PPWR_D2H, $r1); + + // enable fifo subintr for first fifo + mov $r1 1 + nv_iowr(NV_PPWR_FIFO_INTR_EN, $r1) + ret +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc new file mode 100644 index 00000000000..757dda70002 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc @@ -0,0 +1,393 @@ +/* + * 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 + */ + +#define T_TIMEOUT 2200000 +#define T_RISEFALL 1000 +#define T_HOLD 5000 + +#ifdef INCLUDE_PROC +process(PROC_I2C_, #i2c_init, #i2c_recv) +#endif + +/****************************************************************************** + * I2C_ data segment + *****************************************************************************/ +#ifdef INCLUDE_DATA +i2c_scl_map: +.b32 NV_PPWR_OUTPUT_I2C_0_SCL +.b32 NV_PPWR_OUTPUT_I2C_1_SCL +.b32 NV_PPWR_OUTPUT_I2C_2_SCL +.b32 NV_PPWR_OUTPUT_I2C_3_SCL +.b32 NV_PPWR_OUTPUT_I2C_4_SCL +.b32 NV_PPWR_OUTPUT_I2C_5_SCL +.b32 NV_PPWR_OUTPUT_I2C_6_SCL +.b32 NV_PPWR_OUTPUT_I2C_7_SCL +.b32 NV_PPWR_OUTPUT_I2C_8_SCL +.b32 NV_PPWR_OUTPUT_I2C_9_SCL +i2c_sda_map: +.b32 NV_PPWR_OUTPUT_I2C_0_SDA +.b32 NV_PPWR_OUTPUT_I2C_1_SDA +.b32 NV_PPWR_OUTPUT_I2C_2_SDA +.b32 NV_PPWR_OUTPUT_I2C_3_SDA +.b32 NV_PPWR_OUTPUT_I2C_4_SDA +.b32 NV_PPWR_OUTPUT_I2C_5_SDA +.b32 NV_PPWR_OUTPUT_I2C_6_SDA +.b32 NV_PPWR_OUTPUT_I2C_7_SDA +.b32 NV_PPWR_OUTPUT_I2C_8_SDA +.b32 NV_PPWR_OUTPUT_I2C_9_SDA +#if NVKM_PPWR_CHIPSET < GF119 +i2c_ctrl: +.b32 0x00e138 +.b32 0x00e150 +.b32 0x00e168 +.b32 0x00e180 +.b32 0x00e254 +.b32 0x00e274 +.b32 0x00e764 +.b32 0x00e780 +.b32 0x00e79c +.b32 0x00e7b8 +#endif +#endif + +/****************************************************************************** + * I2C_ code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE + +// $r3 - value +// $r2 - sda line +// $r1 - scl line +// $r0 - zero +i2c_drive_scl: + cmp b32 $r3 0 + bra e #i2c_drive_scl_lo + nv_iowr(NV_PPWR_OUTPUT_SET, $r1) + ret + i2c_drive_scl_lo: + nv_iowr(NV_PPWR_OUTPUT_CLR, $r1) + ret + +i2c_drive_sda: + cmp b32 $r3 0 + bra e #i2c_drive_sda_lo + nv_iowr(NV_PPWR_OUTPUT_SET, $r2) + ret + i2c_drive_sda_lo: + nv_iowr(NV_PPWR_OUTPUT_CLR, $r2) + ret + +i2c_sense_scl: + bclr $flags $p1 + nv_iord($r3, NV_PPWR_INPUT) + and $r3 $r1 + bra z #i2c_sense_scl_done + bset $flags $p1 + i2c_sense_scl_done: + ret + +i2c_sense_sda: + bclr $flags $p1 + nv_iord($r3, NV_PPWR_INPUT) + and $r3 $r2 + bra z #i2c_sense_sda_done + bset $flags $p1 + i2c_sense_sda_done: + ret + +#define i2c_drive_scl(v) /* +*/ mov $r3 (v) /* +*/ call(i2c_drive_scl) +#define i2c_drive_sda(v) /* +*/ mov $r3 (v) /* +*/ call(i2c_drive_sda) +#define i2c_sense_scl() /* +*/ call(i2c_sense_scl) +#define i2c_sense_sda() /* +*/ call(i2c_sense_sda) +#define i2c_delay(v) /* +*/ mov $r14 (v) /* +*/ call(nsec) + +#define i2c_trace_init() /* +*/ imm32($r6, 0x10000000) /* +*/ sub b32 $r7 $r6 1 /* +*/ +#define i2c_trace_down() /* +*/ shr b32 $r6 4 /* +*/ push $r5 /* +*/ shl b32 $r5 $r6 4 /* +*/ sub b32 $r5 $r6 /* +*/ not b32 $r5 /* +*/ and $r7 $r5 /* +*/ pop $r5 /* +*/ +#define i2c_trace_exit() /* +*/ shl b32 $r6 4 /* +*/ +#define i2c_trace_next() /* +*/ add b32 $r7 $r6 /* +*/ +#define i2c_trace_call(func) /* +*/ i2c_trace_next() /* +*/ i2c_trace_down() /* +*/ call(func) /* +*/ i2c_trace_exit() /* +*/ + +i2c_raise_scl: + push $r4 + mov $r4 (T_TIMEOUT / T_RISEFALL) + i2c_drive_scl(1) + i2c_raise_scl_wait: + i2c_delay(T_RISEFALL) + i2c_sense_scl() + bra $p1 #i2c_raise_scl_done + sub b32 $r4 1 + bra nz #i2c_raise_scl_wait + i2c_raise_scl_done: + pop $r4 + ret + +i2c_start: + i2c_sense_scl() + bra not $p1 #i2c_start_rep + i2c_sense_sda() + bra not $p1 #i2c_start_rep + bra #i2c_start_send + i2c_start_rep: + i2c_drive_scl(0) + i2c_drive_sda(1) + i2c_trace_call(i2c_raise_scl) + bra not $p1 #i2c_start_out + i2c_start_send: + i2c_drive_sda(0) + i2c_delay(T_HOLD) + i2c_drive_scl(0) + i2c_delay(T_HOLD) + i2c_start_out: + ret + +i2c_stop: + i2c_drive_scl(0) + i2c_drive_sda(0) + i2c_delay(T_RISEFALL) + i2c_drive_scl(1) + i2c_delay(T_HOLD) + i2c_drive_sda(1) + i2c_delay(T_HOLD) + ret + +// $r3 - value +// $r2 - sda line +// $r1 - scl line +// $r0 - zero +i2c_bitw: + call(i2c_drive_sda) + i2c_delay(T_RISEFALL) + i2c_trace_call(i2c_raise_scl) + bra not $p1 #i2c_bitw_out + i2c_delay(T_HOLD) + i2c_drive_scl(0) + i2c_delay(T_HOLD) + i2c_bitw_out: + ret + +// $r3 - value (out) +// $r2 - sda line +// $r1 - scl line +// $r0 - zero +i2c_bitr: + i2c_drive_sda(1) + i2c_delay(T_RISEFALL) + i2c_trace_call(i2c_raise_scl) + bra not $p1 #i2c_bitr_done + i2c_sense_sda() + i2c_drive_scl(0) + i2c_delay(T_HOLD) + xbit $r3 $flags $p1 + bset $flags $p1 + i2c_bitr_done: + ret + +i2c_get_byte: + mov $r5 0 + mov $r4 8 + i2c_get_byte_next: + shl b32 $r5 1 + i2c_trace_call(i2c_bitr) + bra not $p1 #i2c_get_byte_done + or $r5 $r3 + sub b32 $r4 1 + bra nz #i2c_get_byte_next + mov $r3 1 + i2c_trace_call(i2c_bitw) + i2c_get_byte_done: + ret + +i2c_put_byte: + mov $r4 8 + i2c_put_byte_next: + sub b32 $r4 1 + xbit $r3 $r5 $r4 + i2c_trace_call(i2c_bitw) + bra not $p1 #i2c_put_byte_done + cmp b32 $r4 0 + bra ne #i2c_put_byte_next + i2c_trace_call(i2c_bitr) + bra not $p1 #i2c_put_byte_done + i2c_trace_next() + cmp b32 $r3 1 + bra ne #i2c_put_byte_done + bclr $flags $p1 // nack + i2c_put_byte_done: + ret + +i2c_addr: + i2c_trace_call(i2c_start) + bra not $p1 #i2c_addr_done + extr $r3 $r12 I2C__MSG_DATA0_ADDR + shl b32 $r3 1 + or $r5 $r3 + i2c_trace_call(i2c_put_byte) + i2c_addr_done: + ret + +i2c_acquire_addr: + extr $r14 $r12 I2C__MSG_DATA0_PORT +#if NVKM_PPWR_CHIPSET < GF119 + shl b32 $r14 2 + add b32 $r14 #i2c_ctrl + ld b32 $r14 D[$r14] +#else + shl b32 $r14 5 + add b32 $r14 0x00d014 +#endif + ret + +i2c_acquire: + call(i2c_acquire_addr) + call(rd32) + bset $r13 3 + call(wr32) + ret + +i2c_release: + call(i2c_acquire_addr) + call(rd32) + bclr $r13 3 + call(wr32) + ret + +// description +// +// $r15 - current (i2c) +// $r14 - sender process name +// $r13 - message +// $r12 - data0 +// $r11 - data1 +// $r0 - zero +i2c_recv: + bclr $flags $p1 + extr $r1 $r12 I2C__MSG_DATA0_PORT + shl b32 $r1 2 + cmp b32 $r1 (#i2c_sda_map - #i2c_scl_map) + bra ge #i2c_recv_done + add b32 $r3 $r1 #i2c_sda_map + ld b32 $r2 D[$r3] + add b32 $r3 $r1 #i2c_scl_map + ld b32 $r1 D[$r3] + + bset $flags $p2 + push $r13 + push $r14 + + push $r13 + i2c_trace_init() + i2c_trace_call(i2c_acquire) + pop $r13 + + cmp b32 $r13 I2C__MSG_RD08 + bra ne #i2c_recv_not_rd08 + mov $r5 0 + i2c_trace_call(i2c_addr) + bra not $p1 #i2c_recv_done + extr $r5 $r12 I2C__MSG_DATA0_RD08_REG + i2c_trace_call(i2c_put_byte) + bra not $p1 #i2c_recv_done + mov $r5 1 + i2c_trace_call(i2c_addr) + bra not $p1 #i2c_recv_done + i2c_trace_call(i2c_get_byte) + bra not $p1 #i2c_recv_done + ins $r11 $r5 I2C__MSG_DATA1_RD08_VAL + i2c_trace_call(i2c_stop) + mov b32 $r11 $r5 + clear b32 $r7 + bra #i2c_recv_done + + i2c_recv_not_rd08: + cmp b32 $r13 I2C__MSG_WR08 + bra ne #i2c_recv_not_wr08 + mov $r5 0 + call(i2c_addr) + bra not $p1 #i2c_recv_done + extr $r5 $r12 I2C__MSG_DATA0_WR08_REG + call(i2c_put_byte) + bra not $p1 #i2c_recv_done + mov $r5 0 + call(i2c_addr) + bra not $p1 #i2c_recv_done + extr $r5 $r11 I2C__MSG_DATA1_WR08_VAL + call(i2c_put_byte) + bra not $p1 #i2c_recv_done + call(i2c_stop) + clear b32 $r7 + extr $r5 $r12 I2C__MSG_DATA0_WR08_SYNC + bra nz #i2c_recv_done + bclr $flags $p2 + bra #i2c_recv_done + + i2c_recv_not_wr08: + + i2c_recv_done: + extr $r14 $r12 I2C__MSG_DATA0_PORT + call(i2c_release) + + pop $r14 + pop $r13 + bra not $p2 #i2c_recv_exit + mov b32 $r12 $r7 + call(send) + + i2c_recv_exit: + ret + +// description +// +// $r15 - current (i2c) +// $r0 - zero +i2c_init: + ret +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc new file mode 100644 index 00000000000..98f1c3738b4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc @@ -0,0 +1,84 @@ +/* + * 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 + */ + +#ifdef INCLUDE_PROC +process(PROC_IDLE, #idle, #idle_recv) +#endif + +/****************************************************************************** + * IDLE data segment + *****************************************************************************/ +#ifdef INCLUDE_DATA +#endif + +/****************************************************************************** + * IDLE code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE +// description +// +// $r15 - current (idle) +// $r14 - message +// $r0 - zero +idle_recv: + ret + +// description +// +// $r15 - current (idle) +// $r0 - zero +idle: + // set our "no interrupt has occurred during our execution" flag + bset $flags $p0 + + // count IDLE invocations for debugging purposes + nv_iord($r1, NV_PPWR_DSCRATCH(1)) + add b32 $r1 1 + nv_iowr(NV_PPWR_DSCRATCH(1), $r1) + + // keep looping while there's pending messages for any process + idle_loop: + mov $r1 #proc_list_head + bclr $flags $p2 + idle_proc: + // process the process' messages until there's none left + idle_proc_exec: + push $r1 + mov b32 $r14 $r1 + call(recv) + pop $r1 + bra not $p1 #idle_proc_next + bset $flags $p2 + bra #idle_proc_exec + // next process! + idle_proc_next: + add b32 $r1 #proc_size + cmp b32 $r1 $r15 + bra ne #idle_proc + bra $p2 #idle_loop + + // sleep if no interrupts have occurred + sleep $p0 + bra #idle +#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 new file mode 100644 index 00000000000..8f29badd785 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc @@ -0,0 +1,454 @@ +/* + * 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 + */ + +/****************************************************************************** + * kernel data segment + *****************************************************************************/ +#ifdef INCLUDE_PROC +proc_kern: +process(PROC_KERN, 0, 0) +proc_list_head: +#endif + +#ifdef INCLUDE_DATA +proc_list_tail: +time_prev: .b32 0 +time_next: .b32 0 +#endif + +/****************************************************************************** + * kernel code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE + bra #init + +// read nv register +// +// $r15 - current +// $r14 - addr +// $r13 - data (return) +// $r0 - zero +rd32: + nv_iowr(NV_PPWR_MMIO_ADDR, $r14) + mov $r13 NV_PPWR_MMIO_CTRL_OP_RD + sethi $r13 NV_PPWR_MMIO_CTRL_TRIGGER + nv_iowr(NV_PPWR_MMIO_CTRL, $r13) + rd32_wait: + nv_iord($r13, NV_PPWR_MMIO_CTRL) + and $r13 NV_PPWR_MMIO_CTRL_STATUS + bra nz #rd32_wait + nv_iord($r13, NV_PPWR_MMIO_DATA) + ret + +// write nv register +// +// $r15 - current +// $r14 - addr +// $r13 - data +// $r0 - zero +wr32: + nv_iowr(NV_PPWR_MMIO_ADDR, $r14) + nv_iowr(NV_PPWR_MMIO_DATA, $r13) + mov $r13 NV_PPWR_MMIO_CTRL_OP_WR + or $r13 NV_PPWR_MMIO_CTRL_MASK_B32_0 + sethi $r13 NV_PPWR_MMIO_CTRL_TRIGGER + +#ifdef NVKM_FALCON_MMIO_TRAP + push $r13 + mov $r13 NV_PPWR_INTR_TRIGGER_USER1 + nv_iowr(NV_PPWR_INTR_TRIGGER, $r13) + wr32_host: + nv_iord($r13, NV_PPWR_INTR) + and $r13 NV_PPWR_INTR_USER1 + bra nz #wr32_host + pop $r13 +#endif + + nv_iowr(NV_PPWR_MMIO_CTRL, $r13) + wr32_wait: + nv_iord($r13, NV_PPWR_MMIO_CTRL) + and $r13 NV_PPWR_MMIO_CTRL_STATUS + bra nz #wr32_wait + ret + +// busy-wait for a period of time +// +// $r15 - current +// $r14 - ns +// $r0 - zero +nsec: + 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 + ret + +// busy-wait for a period of time +// +// $r15 - current +// $r14 - addr +// $r13 - mask +// $r12 - data +// $r11 - timeout (ns) +// $r0 - zero +wait: + nv_iord($r8, NV_PPWR_TIMER_LOW) + wait_loop: + nv_rd32($r10, $r14) + and $r10 $r13 + cmp b32 $r10 $r12 + bra e #wait_done + nv_iord($r9, NV_PPWR_TIMER_LOW) + sub b32 $r9 $r8 + cmp b32 $r9 $r11 + bra l #wait_loop + wait_done: + ret + +// $r15 - current (kern) +// $r14 - process +// $r8 - NV_PPWR_INTR +intr_watchdog: + // read process' timer status, skip if not enabled + ld b32 $r9 D[$r14 + #proc_time] + cmp b32 $r9 0 + bra z #intr_watchdog_next_proc + + // subtract last timer's value from process' timer, + // if it's <= 0 then the timer has expired + ld b32 $r10 D[$r0 + #time_prev] + sub b32 $r9 $r10 + bra g #intr_watchdog_next_time + mov $r13 KMSG_ALARM + call(send_proc) + clear b32 $r9 + bra #intr_watchdog_next_proc + + // otherwise, update the next timer's value if this + // process' timer is the soonest + intr_watchdog_next_time: + // ... or if there's no next timer yet + ld b32 $r10 D[$r0 + #time_next] + cmp b32 $r10 0 + bra z #intr_watchdog_next_time_set + + cmp b32 $r9 $r10 + bra g #intr_watchdog_next_proc + intr_watchdog_next_time_set: + st b32 D[$r0 + #time_next] $r9 + + // update process' timer status, and advance + intr_watchdog_next_proc: + st b32 D[$r14 + #proc_time] $r9 + add b32 $r14 #proc_size + cmp b32 $r14 #proc_list_tail + bra ne #intr_watchdog + ret + +intr: + push $r0 + clear b32 $r0 + push $r8 + push $r9 + push $r10 + push $r11 + push $r12 + push $r13 + push $r14 + push $r15 + mov $r15 #proc_kern + mov $r8 $flags + push $r8 + + nv_iord($r8, NV_PPWR_DSCRATCH(0)) + add b32 $r8 1 + nv_iowr(NV_PPWR_DSCRATCH(0), $r8) + + nv_iord($r8, NV_PPWR_INTR) + and $r9 $r8 NV_PPWR_INTR_WATCHDOG + bra z #intr_skip_watchdog + st b32 D[$r0 + #time_next] $r0 + mov $r14 #proc_list_head + call(intr_watchdog) + ld b32 $r9 D[$r0 + #time_next] + cmp b32 $r9 0 + bra z #intr_skip_watchdog + nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9) + st b32 D[$r0 + #time_prev] $r9 + + intr_skip_watchdog: + and $r9 $r8 NV_PPWR_INTR_SUBINTR + bra z #intr_skip_subintr + nv_iord($r9, NV_PPWR_SUBINTR) + and $r10 $r9 NV_PPWR_SUBINTR_FIFO + bra z #intr_subintr_skip_fifo + nv_iord($r12, NV_PPWR_FIFO_INTR) + push $r12 + mov $r14 (PROC_HOST & 0x0000ffff) + sethi $r14 (PROC_HOST & 0xffff0000) + mov $r13 KMSG_FIFO + call(send) + pop $r12 + nv_iowr(NV_PPWR_FIFO_INTR, $r12) + intr_subintr_skip_fifo: + nv_iowr(NV_PPWR_SUBINTR, $r9) + + intr_skip_subintr: + and $r9 $r8 NV_PPWR_INTR_PAUSE + bra z #intr_skip_pause + and $r10 0xffbf + + intr_skip_pause: + and $r9 $r8 NV_PPWR_INTR_USER0 + bra z #intr_skip_user0 + and $r10 0xffbf + + intr_skip_user0: + nv_iowr(NV_PPWR_INTR_ACK, $r8) + pop $r8 + mov $flags $r8 + pop $r15 + pop $r14 + pop $r13 + pop $r12 + pop $r11 + pop $r10 + pop $r9 + pop $r8 + pop $r0 + bclr $flags $p0 + iret + +// request the current process be sent a message after a timeout expires +// +// $r15 - current +// $r14 - ticks +// $r0 - zero +timer: + // interrupts off to prevent racing with timer isr + bclr $flags ie0 + + // if current process already has a timer set, bail + 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 + nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8) + nv_iord($r8, NV_PPWR_INTR) + and $r8 NV_PPWR_INTR_WATCHDOG + bra nz #timer_enable + + // update the watchdog if this timer should expire first, + // or if there's no timeout already set + nv_iord($r8, NV_PPWR_WATCHDOG_TIME) + 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 + + // re-enable the watchdog timer + timer_enable: + mov $r8 1 + nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8) + + // interrupts back on + timer_done: + bset $flags ie0 + ret + +// send message to another process +// +// $r15 - current +// $r14 - process +// $r13 - message +// $r12 - message data 0 +// $r11 - message data 1 +// $r0 - zero +send_proc: + push $r8 + push $r9 + // check for space in queue + ld b32 $r8 D[$r14 + #proc_qget] + ld b32 $r9 D[$r14 + #proc_qput] + xor $r8 #proc_qmaskb + cmp b32 $r8 $r9 + bra e #send_done + + // enqueue message + and $r8 $r9 #proc_qmaskp + shl b32 $r8 $r8 #proc_qlen + add b32 $r8 #proc_queue + add b32 $r8 $r14 + + ld b32 $r10 D[$r15 + #proc_id] + st b32 D[$r8 + #msg_process] $r10 + st b32 D[$r8 + #msg_message] $r13 + st b32 D[$r8 + #msg_data0] $r12 + st b32 D[$r8 + #msg_data1] $r11 + + // increment PUT + add b32 $r9 1 + and $r9 #proc_qmaskf + st b32 D[$r14 + #proc_qput] $r9 + bset $flags $p2 + send_done: + pop $r9 + pop $r8 + ret + +// lookup process structure by its name +// +// $r15 - current +// $r14 - process name +// $r0 - zero +// +// $r14 - process +// $p1 - success +find: + push $r8 + mov $r8 #proc_list_head + bset $flags $p1 + find_loop: + ld b32 $r10 D[$r8 + #proc_id] + cmp b32 $r10 $r14 + bra e #find_done + add b32 $r8 #proc_size + cmp b32 $r8 #proc_list_tail + bra ne #find_loop + bclr $flags $p1 + find_done: + mov b32 $r14 $r8 + pop $r8 + ret + +// send message to another process +// +// $r15 - current +// $r14 - process id +// $r13 - message +// $r12 - message data 0 +// $r11 - message data 1 +// $r0 - zero +send: + call(find) + bra $p1 #send_proc + ret + +// process single message for a given process +// +// $r15 - current +// $r14 - process +// $r0 - zero +recv: + ld b32 $r8 D[$r14 + #proc_qget] + ld b32 $r9 D[$r14 + #proc_qput] + bclr $flags $p1 + cmp b32 $r8 $r9 + bra e #recv_done + // dequeue message + and $r9 $r8 #proc_qmaskp + add b32 $r8 1 + and $r8 #proc_qmaskf + st b32 D[$r14 + #proc_qget] $r8 + ld b32 $r10 D[$r14 + #proc_recv] + + push $r15 + mov $r15 $flags + push $r15 + mov b32 $r15 $r14 + + shl b32 $r9 $r9 #proc_qlen + add b32 $r14 $r9 + add b32 $r14 #proc_queue + ld b32 $r11 D[$r14 + #msg_data1] + ld b32 $r12 D[$r14 + #msg_data0] + ld b32 $r13 D[$r14 + #msg_message] + ld b32 $r14 D[$r14 + #msg_process] + + // process it + call $r10 + pop $r15 + mov $flags $r15 + bset $flags $p1 + pop $r15 + recv_done: + ret + +init: + // setup stack + nv_iord($r1, NV_PPWR_CAPS) + extr $r1 $r1 9:17 + shl b32 $r1 8 + mov $sp $r1 + +#ifdef NVKM_FALCON_MMIO_UAS + // somehow allows the magic "access mmio via D[]" stuff that's + // used by the nv_rd32/nv_wr32 macros to work + mov $r1 0x0010 + sethi $r1 NV_PPWR_UAS_CONFIG_ENABLE + nv_iowrs(NV_PPWR_UAS_CONFIG, $r1) +#endif + + // route all interrupts except user0/1 and pause to fuc + mov $r1 0x00e0 + sethi $r1 0x00000000 + nv_iowr(NV_PPWR_INTR_ROUTE, $r1) + + // enable watchdog and subintr intrs + mov $r1 NV_PPWR_INTR_EN_CLR_MASK + nv_iowr(NV_PPWR_INTR_EN_CLR, $r1) + mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG + or $r1 NV_PPWR_INTR_EN_SET_SUBINTR + nv_iowr(NV_PPWR_INTR_EN_SET, $r1) + + // enable interrupts globally + mov $r1 #intr + sethi $r1 0x00000000 + mov $iv0 $r1 + bset $flags ie0 + + // enable watchdog timer + mov $r1 1 + nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1) + + // bootstrap processes, idle process will be last, and not return + mov $r15 #proc_list_head + init_proc: + ld b32 $r1 D[$r15 + #proc_init] + cmp b32 $r1 0 + bra z #init_proc + call $r1 + add b32 $r15 #proc_size + bra #init_proc +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc new file mode 100644 index 00000000000..e2a63ac5422 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc @@ -0,0 +1,252 @@ +/* + * 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 + */ + +#define GT215 0xa3 +#define GF100 0xc0 +#define GF119 0xd9 +#define GK208 0x108 + +#include "os.h" + +// IO addresses +#define NV_PPWR_INTR_TRIGGER 0x0000 +#define NV_PPWR_INTR_TRIGGER_USER1 0x00000080 +#define NV_PPWR_INTR_TRIGGER_USER0 0x00000040 +#define NV_PPWR_INTR_ACK 0x0004 +#define NV_PPWR_INTR_ACK_SUBINTR 0x00000800 +#define NV_PPWR_INTR_ACK_WATCHDOG 0x00000002 +#define NV_PPWR_INTR 0x0008 +#define NV_PPWR_INTR_SUBINTR 0x00000800 +#define NV_PPWR_INTR_USER1 0x00000080 +#define NV_PPWR_INTR_USER0 0x00000040 +#define NV_PPWR_INTR_PAUSE 0x00000020 +#define NV_PPWR_INTR_WATCHDOG 0x00000002 +#define NV_PPWR_INTR_EN_SET 0x0010 +#define NV_PPWR_INTR_EN_SET_SUBINTR 0x00000800 +#define NV_PPWR_INTR_EN_SET_WATCHDOG 0x00000002 +#define NV_PPWR_INTR_EN_CLR 0x0014 +#define NV_PPWR_INTR_EN_CLR_MASK /* fuck i hate envyas */ -1 +#define NV_PPWR_INTR_ROUTE 0x001c +#define NV_PPWR_TIMER_LOW 0x002c +#define NV_PPWR_WATCHDOG_TIME 0x0034 +#define NV_PPWR_WATCHDOG_ENABLE 0x0038 +#define NV_PPWR_CAPS 0x0108 +#define NV_PPWR_UAS_CONFIG 0x0164 +#define NV_PPWR_UAS_CONFIG_ENABLE 0x00010000 +#if NVKM_PPWR_CHIPSET >= GK208 +#define NV_PPWR_DSCRATCH(i) (4 * (i) + 0x0450) +#endif +#define NV_PPWR_FIFO_PUT(i) (4 * (i) + 0x04a0) +#define NV_PPWR_FIFO_GET(i) (4 * (i) + 0x04b0) +#define NV_PPWR_FIFO_INTR 0x04c0 +#define NV_PPWR_FIFO_INTR_EN 0x04c4 +#define NV_PPWR_RFIFO_PUT 0x04c8 +#define NV_PPWR_RFIFO_GET 0x04cc +#define NV_PPWR_H2D 0x04d0 +#define NV_PPWR_D2H 0x04dc +#if NVKM_PPWR_CHIPSET < GK208 +#define NV_PPWR_DSCRATCH(i) (4 * (i) + 0x05d0) +#endif +#define NV_PPWR_SUBINTR 0x0688 +#define NV_PPWR_SUBINTR_FIFO 0x00000002 +#define NV_PPWR_MMIO_ADDR 0x07a0 +#define NV_PPWR_MMIO_DATA 0x07a4 +#define NV_PPWR_MMIO_CTRL 0x07ac +#define NV_PPWR_MMIO_CTRL_TRIGGER 0x00010000 +#define NV_PPWR_MMIO_CTRL_STATUS 0x00007000 +#define NV_PPWR_MMIO_CTRL_STATUS_IDLE 0x00000000 +#define NV_PPWR_MMIO_CTRL_MASK 0x000000f0 +#define NV_PPWR_MMIO_CTRL_MASK_B32_0 0x000000f0 +#define NV_PPWR_MMIO_CTRL_OP 0x00000003 +#define NV_PPWR_MMIO_CTRL_OP_RD 0x00000001 +#define NV_PPWR_MMIO_CTRL_OP_WR 0x00000002 +#define NV_PPWR_OUTPUT 0x07c0 +#define NV_PPWR_OUTPUT_FB_PAUSE 0x00000004 +#if NVKM_PPWR_CHIPSET < GF119 +#define NV_PPWR_OUTPUT_I2C_3_SCL 0x00000100 +#define NV_PPWR_OUTPUT_I2C_3_SDA 0x00000200 +#define NV_PPWR_OUTPUT_I2C_0_SCL 0x00001000 +#define NV_PPWR_OUTPUT_I2C_0_SDA 0x00002000 +#define NV_PPWR_OUTPUT_I2C_1_SCL 0x00004000 +#define NV_PPWR_OUTPUT_I2C_1_SDA 0x00008000 +#define NV_PPWR_OUTPUT_I2C_2_SCL 0x00010000 +#define NV_PPWR_OUTPUT_I2C_2_SDA 0x00020000 +#define NV_PPWR_OUTPUT_I2C_4_SCL 0x00040000 +#define NV_PPWR_OUTPUT_I2C_4_SDA 0x00080000 +#define NV_PPWR_OUTPUT_I2C_5_SCL 0x00100000 +#define NV_PPWR_OUTPUT_I2C_5_SDA 0x00200000 +#define NV_PPWR_OUTPUT_I2C_6_SCL 0x00400000 +#define NV_PPWR_OUTPUT_I2C_6_SDA 0x00800000 +#define NV_PPWR_OUTPUT_I2C_7_SCL 0x01000000 +#define NV_PPWR_OUTPUT_I2C_7_SDA 0x02000000 +#define NV_PPWR_OUTPUT_I2C_8_SCL 0x04000000 +#define NV_PPWR_OUTPUT_I2C_8_SDA 0x08000000 +#define NV_PPWR_OUTPUT_I2C_9_SCL 0x10000000 +#define NV_PPWR_OUTPUT_I2C_9_SDA 0x20000000 +#else +#define NV_PPWR_OUTPUT_I2C_0_SCL 0x00000400 +#define NV_PPWR_OUTPUT_I2C_1_SCL 0x00000800 +#define NV_PPWR_OUTPUT_I2C_2_SCL 0x00001000 +#define NV_PPWR_OUTPUT_I2C_3_SCL 0x00002000 +#define NV_PPWR_OUTPUT_I2C_4_SCL 0x00004000 +#define NV_PPWR_OUTPUT_I2C_5_SCL 0x00008000 +#define NV_PPWR_OUTPUT_I2C_6_SCL 0x00010000 +#define NV_PPWR_OUTPUT_I2C_7_SCL 0x00020000 +#define NV_PPWR_OUTPUT_I2C_8_SCL 0x00040000 +#define NV_PPWR_OUTPUT_I2C_9_SCL 0x00080000 +#define NV_PPWR_OUTPUT_I2C_0_SDA 0x00100000 +#define NV_PPWR_OUTPUT_I2C_1_SDA 0x00200000 +#define NV_PPWR_OUTPUT_I2C_2_SDA 0x00400000 +#define NV_PPWR_OUTPUT_I2C_3_SDA 0x00800000 +#define NV_PPWR_OUTPUT_I2C_4_SDA 0x01000000 +#define NV_PPWR_OUTPUT_I2C_5_SDA 0x02000000 +#define NV_PPWR_OUTPUT_I2C_6_SDA 0x04000000 +#define NV_PPWR_OUTPUT_I2C_7_SDA 0x08000000 +#define NV_PPWR_OUTPUT_I2C_8_SDA 0x10000000 +#define NV_PPWR_OUTPUT_I2C_9_SDA 0x20000000 +#endif +#define NV_PPWR_INPUT 0x07c4 +#define NV_PPWR_OUTPUT_SET 0x07e0 +#define NV_PPWR_OUTPUT_SET_FB_PAUSE 0x00000004 +#define NV_PPWR_OUTPUT_CLR 0x07e4 +#define NV_PPWR_OUTPUT_CLR_FB_PAUSE 0x00000004 + +// Inter-process message format +.equ #msg_process 0x00 /* send() target, recv() sender */ +.equ #msg_message 0x04 +.equ #msg_data0 0x08 +.equ #msg_data1 0x0c + +// Kernel message IDs +#define KMSG_FIFO 0x00000000 +#define KMSG_ALARM 0x00000001 + +// Process message queue description +.equ #proc_qlen 4 // log2(size of queue entry in bytes) +.equ #proc_qnum 2 // log2(max number of entries in queue) +.equ #proc_qmaskb (1 << #proc_qnum) // max number of entries in queue +.equ #proc_qmaskp (#proc_qmaskb - 1) +.equ #proc_qmaskf ((#proc_qmaskb << 1) - 1) +.equ #proc_qsize (1 << (#proc_qlen + #proc_qnum)) + +// Process table entry +.equ #proc_id 0x00 +.equ #proc_init 0x04 +.equ #proc_recv 0x08 +.equ #proc_time 0x0c +.equ #proc_qput 0x10 +.equ #proc_qget 0x14 +.equ #proc_queue 0x18 +.equ #proc_size (0x18 + #proc_qsize) + +#define process(id,init,recv) /* +*/ .b32 id /* +*/ .b32 init /* +*/ .b32 recv /* +*/ .b32 0 /* +*/ .b32 0 /* +*/ .b32 0 /* +*/ .skip 64 + +#if NV_PPWR_CHIPSET < GK208 +#define imm32(reg,val) /* +*/ movw reg ((val) & 0x0000ffff) /* +*/ sethi reg ((val) & 0xffff0000) +#else +#define imm32(reg,val) /* +*/ mov reg (val) +#endif + +#ifndef NVKM_FALCON_UNSHIFTED_IO +#define nv_iord(reg,ior) /* +*/ mov reg ior /* +*/ shl b32 reg 6 /* +*/ iord reg I[reg + 0x000] +#else +#define nv_iord(reg,ior) /* +*/ mov reg ior /* +*/ iord reg I[reg + 0x000] +#endif + +#ifndef NVKM_FALCON_UNSHIFTED_IO +#define nv_iowr(ior,reg) /* +*/ mov $r0 ior /* +*/ shl b32 $r0 6 /* +*/ iowr I[$r0 + 0x000] reg /* +*/ clear b32 $r0 +#else +#define nv_iowr(ior,reg) /* +*/ mov $r0 ior /* +*/ iowr I[$r0 + 0x000] reg /* +*/ clear b32 $r0 +#endif + +#ifndef NVKM_FALCON_UNSHIFTED_IO +#define nv_iowrs(ior,reg) /* +*/ mov $r0 ior /* +*/ shl b32 $r0 6 /* +*/ iowrs I[$r0 + 0x000] reg /* +*/ clear b32 $r0 +#else +#define nv_iowrs(ior,reg) /* +*/ mov $r0 ior /* +*/ iowrs I[$r0 + 0x000] reg /* +*/ clear b32 $r0 +#endif + +#define hash # +#define fn(a) a +#ifndef NVKM_FALCON_PC24 +#define call(a) call fn(hash)a +#else +#define call(a) lcall fn(hash)a +#endif + +#ifndef NVKM_FALCON_MMIO_UAS +#define nv_rd32(reg,addr) /* +*/ mov b32 $r14 addr /* +*/ call(rd32) /* +*/ mov b32 reg $r13 +#else +#define nv_rd32(reg,addr) /* +*/ sethi $r0 0x14000000 /* +*/ or $r0 addr /* +*/ ld b32 reg D[$r0] /* +*/ clear b32 $r0 +#endif + +#if !defined(NVKM_FALCON_MMIO_UAS) || defined(NVKM_FALCON_MMIO_TRAP) +#define nv_wr32(addr,reg) /* +*/ push addr /* +*/ push reg /* +*/ pop $r13 /* +*/ pop $r14 /* +*/ call(wr32) /* +#else +#define nv_wr32(addr,reg) /* +*/ sethi $r0 0x14000000 /* +*/ or $r0 addr /* +*/ st b32 D[$r0] reg /* +*/ clear b32 $r0 +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc new file mode 100644 index 00000000000..d43741eccb1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc @@ -0,0 +1,219 @@ +/* + * 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 + */ + +#ifdef INCLUDE_PROC +process(PROC_MEMX, #memx_init, #memx_recv) +#endif + +/****************************************************************************** + * MEMX data segment + *****************************************************************************/ +#ifdef INCLUDE_DATA +.equ #memx_opcode 0 +.equ #memx_header 2 +.equ #memx_length 4 +.equ #memx_func 8 + +#define handler(cmd,hdr,len,func) /* +*/ .b16 MEMX_##cmd /* +*/ .b16 hdr /* +*/ .b16 len /* +*/ .b16 0 /* +*/ .b32 func + +memx_func_head: +handler(ENTER , 0x0001, 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) +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_data_head: +.skip 0x0800 +memx_data_tail: +#endif + +/****************************************************************************** + * MEMX code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE +// description +// +// $r15 - current (memx) +// $r4 - packet length +// +00: bitmask of heads to wait for vblank on +// $r3 - opcode desciption +// $r0 - zero +memx_func_enter: + 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 + ret + +// description +// +// $r15 - current (memx) +// $r4 - packet length +// $r3 - opcode desciption +// $r0 - zero +memx_func_leave: + 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 + ret + +// description +// +// $r15 - current (memx) +// $r4 - packet length +// +00*n: addr +// +04*n: data +// $r3 - opcode desciption +// $r0 - zero +memx_func_wr32: + ld b32 $r6 D[$r1 + 0x00] + ld b32 $r5 D[$r1 + 0x04] + add b32 $r1 0x08 + nv_wr32($r6, $r5) + sub b32 $r4 0x02 + bra nz #memx_func_wr32 + ret + +// description +// +// $r15 - current (memx) +// $r4 - packet length +// +00: addr +// +04: mask +// +08: data +// +0c: timeout (ns) +// $r3 - opcode desciption +// $r0 - zero +memx_func_wait: + nv_iord($r8, NV_PPWR_TIMER_LOW) + ld b32 $r14 D[$r1 + 0x00] + ld b32 $r13 D[$r1 + 0x04] + ld b32 $r12 D[$r1 + 0x08] + ld b32 $r11 D[$r1 + 0x0c] + add b32 $r1 0x10 + call(wait) + ret + +// description +// +// $r15 - current (memx) +// $r4 - packet length +// +00: time (ns) +// $r3 - opcode desciption +// $r0 - zero +memx_func_delay: + ld b32 $r14 D[$r1 + 0x00] + add b32 $r1 0x04 + call(nsec) + ret + +// description +// +// $r15 - current (memx) +// $r14 - sender process name +// $r13 - message (exec) +// $r12 - head of script +// $r11 - tail of script +// $r0 - zero +memx_exec: + push $r14 + push $r13 + mov b32 $r1 $r12 + mov b32 $r2 $r11 + memx_exec_next: + // fetch the packet header, and locate opcode info + ld b32 $r3 D[$r1] + add b32 $r1 4 + shr b32 $r4 $r3 16 + mulu $r3 #memx_func_size + + // execute the opcode handler + ld b32 $r5 D[$r3 + #memx_func_head + #memx_func] + call $r5 + + // keep going, if we haven't reached the end + cmp b32 $r1 $r2 + bra l #memx_exec_next + + // send completion reply + pop $r13 + pop $r14 + call(send) + ret + +// description +// +// $r15 - current (memx) +// $r14 - sender process name +// $r13 - message +// $r12 - data0 +// $r11 - data1 +// $r0 - zero +memx_info: + mov $r12 #memx_data_head + mov $r11 #memx_data_tail - #memx_data_head + call(send) + ret + +// description +// +// $r15 - current (memx) +// $r14 - sender process name +// $r13 - message +// $r12 - data0 +// $r11 - data1 +// $r0 - zero +memx_recv: + cmp b32 $r13 MEMX_MSG_EXEC + bra e #memx_exec + cmp b32 $r13 MEMX_MSG_INFO + bra e #memx_info + ret + +// description +// +// $r15 - current (memx) +// $r0 - zero +memx_init: + ret +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc new file mode 100644 index 00000000000..17a8a383d91 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#define NVKM_PPWR_CHIPSET GK208 + +#define NVKM_FALCON_PC24 +#define NVKM_FALCON_UNSHIFTED_IO +//#define NVKM_FALCON_MMIO_UAS +//#define NVKM_FALCON_MMIO_TRAP + +#include "macros.fuc" + +.section #nv108_pwr_data +#define INCLUDE_PROC +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_PROC + +#define INCLUDE_DATA +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_DATA +.align 256 + +.section #nv108_pwr_code +#define INCLUDE_CODE +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_CODE +.align 256 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 new file mode 100644 index 00000000000..39a5dc150a0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h @@ -0,0 +1,1460 @@ +uint32_t nv108_pwr_data[] = { +/* 0x0000: proc_kern */ + 0x52544e49, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0058: proc_list_head */ + 0x54534f48, + 0x00000379, + 0x0000032a, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x584d454d, + 0x0000046f, + 0x00000461, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x46524550, + 0x00000473, + 0x00000471, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5f433249, + 0x00000877, + 0x0000071e, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x54534554, + 0x00000898, + 0x00000879, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x454c4449, + 0x000008a3, + 0x000008a1, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0268: proc_list_tail */ +/* 0x0268: time_prev */ + 0x00000000, +/* 0x026c: time_next */ + 0x00000000, +/* 0x0270: fifo_queue */ + 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, +/* 0x02f0: rfifo_queue */ + 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, +/* 0x0370: memx_func_head */ + 0x00010000, + 0x00000000, + 0x000003a9, +/* 0x037c: memx_func_next */ + 0x00000001, + 0x00000000, + 0x000003c7, + 0x00000002, + 0x00000002, + 0x000003df, + 0x00040003, + 0x00000000, + 0x00000407, + 0x00010004, + 0x00000000, + 0x00000421, +/* 0x03ac: memx_func_tail */ +/* 0x03ac: memx_data_head */ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, +/* 0x0bac: memx_data_tail */ +/* 0x0bac: i2c_scl_map */ + 0x00000400, + 0x00000800, + 0x00001000, + 0x00002000, + 0x00004000, + 0x00008000, + 0x00010000, + 0x00020000, + 0x00040000, + 0x00080000, +/* 0x0bd4: i2c_sda_map */ + 0x00100000, + 0x00200000, + 0x00400000, + 0x00800000, + 0x01000000, + 0x02000000, + 0x04000000, + 0x08000000, + 0x10000000, + 0x20000000, + 0x00000000, +}; + +uint32_t nv108_pwr_code[] = { + 0x02910ef5, +/* 0x0004: rd32 */ + 0xf607a040, + 0x04bd000e, + 0xd3f0010d, + 0x07ac4001, + 0xbd000df6, +/* 0x0019: rd32_wait */ + 0x07ac4d04, + 0xf100ddcf, + 0xf47000d4, + 0xa44df61b, + 0x00ddcf07, +/* 0x002e: wr32 */ + 0xa04000f8, + 0x000ef607, + 0xa44004bd, + 0x000df607, + 0x020d04bd, + 0xf0f0d5f0, + 0xac4001d3, + 0x000df607, +/* 0x004e: wr32_wait */ + 0xac4d04bd, + 0x00ddcf07, + 0x7000d4f1, + 0xf8f61bf4, +/* 0x005d: nsec */ + 0xcf2c0800, +/* 0x0062: nsec_loop */ + 0x2c090088, + 0xbb0099cf, + 0x9ea60298, + 0xf8f61ef4, +/* 0x0071: wait */ + 0xcf2c0800, +/* 0x0076: wait_loop */ + 0xeeb20088, + 0x0000047e, + 0xadfddab2, + 0xf4aca604, + 0x2c09100b, + 0xbb0099cf, + 0x9ba60298, +/* 0x0093: wait_done */ + 0xf8e61ef4, +/* 0x0095: intr_watchdog */ + 0x03e99800, + 0xf40096b0, + 0x0a98280b, + 0x029abb9a, + 0x0d0e1cf4, + 0x01de7e01, + 0xf494bd00, +/* 0x00b2: intr_watchdog_next_time */ + 0x0a98140e, + 0x00a6b09b, + 0xa6080bf4, + 0x061cf49a, +/* 0x00c0: intr_watchdog_next_time_set */ +/* 0x00c3: intr_watchdog_next_proc */ + 0xb59b09b5, + 0xe0b603e9, + 0x68e6b158, + 0xc81bf402, +/* 0x00d2: intr */ + 0x00f900f8, + 0x80f904bd, + 0xa0f990f9, + 0xc0f9b0f9, + 0xe0f9d0f9, + 0x000ff0f9, + 0xf90188fe, + 0x04504880, + 0xb60088cf, + 0x50400180, + 0x0008f604, + 0x080804bd, + 0xc40088cf, + 0x0bf40289, + 0x9b00b51f, + 0x957e580e, + 0x09980000, + 0x0096b09b, + 0x000d0bf4, + 0x0009f634, + 0x09b504bd, +/* 0x0125: intr_skip_watchdog */ + 0x0089e49a, + 0x360bf408, + 0xcf068849, + 0x9ac40099, + 0x220bf402, + 0xcf04c04c, + 0xc0f900cc, + 0xf14f484e, + 0x0d5453e3, + 0x023f7e00, + 0x40c0fc00, + 0x0cf604c0, +/* 0x0157: intr_subintr_skip_fifo */ + 0x4004bd00, + 0x09f60688, +/* 0x015f: intr_skip_subintr */ + 0xc404bd00, + 0x0bf42089, + 0xbfa4f107, +/* 0x0169: intr_skip_pause */ + 0x4089c4ff, + 0xf1070bf4, +/* 0x0173: intr_skip_user0 */ + 0x00ffbfa4, + 0x0008f604, + 0x80fc04bd, + 0xfc0088fe, + 0xfce0fcf0, + 0xfcc0fcd0, + 0xfca0fcb0, + 0xfc80fc90, + 0x0032f400, +/* 0x0196: timer */ + 0x32f401f8, + 0x03f89810, + 0xf40086b0, + 0xfeb53a1c, + 0xf6380003, + 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, + 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, + 0x4104bd00, + 0x14b60080, + 0xf015f110, + 0x04dc4002, + 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, + 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, + 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, + 0x00005d7e, + 0x8f7e0103, + 0x884e0004, + 0x005d7e13, +/* 0x057b: i2c_bitw */ + 0x7e00f800, + 0x4e00048f, + 0x5d7e03e8, + 0x76bb0000, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, + 0xb60004d1, + 0x11f40464, + 0x13884e17, + 0x00005d7e, + 0x757e0003, + 0x884e0004, + 0x005d7e13, +/* 0x05b9: i2c_bitw_out */ +/* 0x05bb: i2c_bitr */ + 0x0300f800, + 0x048f7e01, + 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, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x0005bb7e, + 0xf40464b6, + 0x53fd2a11, + 0x0142b605, + 0x03d81bf4, + 0x0076bb01, + 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, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x05bb7e50, + 0x0464b600, + 0xbb0f11f4, + 0x36b00076, + 0x061bf401, +/* 0x06a7: i2c_put_byte_done */ + 0xf80132f4, +/* 0x06a9: i2c_addr */ + 0x0076bb00, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0xf47e50fc, + 0x64b60004, + 0x2911f404, + 0x012ec3e7, + 0xfd0134b6, + 0x76bb0553, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, + 0xb600064f, +/* 0x06ee: i2c_addr_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, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x064f7e50, + 0x0464b600, + 0x00a911f5, + 0x76bb0105, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, + 0xb60006a9, + 0x11f50464, + 0x76bb0087, + 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, + 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, + 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 new file mode 100644 index 00000000000..6744fcc0615 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#define NVKM_PPWR_CHIPSET GT215 + +//#define NVKM_FALCON_PC24 +//#define NVKM_FALCON_UNSHIFTED_IO +//#define NVKM_FALCON_MMIO_UAS +//#define NVKM_FALCON_MMIO_TRAP + +#include "macros.fuc" + +.section #nva3_pwr_data +#define INCLUDE_PROC +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_PROC + +#define INCLUDE_DATA +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_DATA +.align 256 + +.section #nva3_pwr_code +#define INCLUDE_CODE +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_CODE +.align 256 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 new file mode 100644 index 00000000000..254205cd516 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h @@ -0,0 +1,1589 @@ +uint32_t nva3_pwr_data[] = { +/* 0x0000: proc_kern */ + 0x52544e49, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0058: proc_list_head */ + 0x54534f48, + 0x00000430, + 0x000003cd, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x584d454d, + 0x0000054e, + 0x00000540, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x46524550, + 0x00000552, + 0x00000550, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5f433249, + 0x00000982, + 0x00000825, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x54534554, + 0x000009ab, + 0x00000984, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x454c4449, + 0x000009b7, + 0x000009b5, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0268: proc_list_tail */ +/* 0x0268: time_prev */ + 0x00000000, +/* 0x026c: time_next */ + 0x00000000, +/* 0x0270: fifo_queue */ + 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, +/* 0x02f0: rfifo_queue */ + 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, +/* 0x0370: memx_func_head */ + 0x00010000, + 0x00000000, + 0x0000046f, +/* 0x037c: memx_func_next */ + 0x00000001, + 0x00000000, + 0x00000496, + 0x00000002, + 0x00000002, + 0x000004b7, + 0x00040003, + 0x00000000, + 0x000004df, + 0x00010004, + 0x00000000, + 0x000004fc, +/* 0x03ac: memx_func_tail */ +/* 0x03ac: memx_data_head */ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, +/* 0x0bac: memx_data_tail */ +/* 0x0bac: i2c_scl_map */ + 0x00001000, + 0x00004000, + 0x00010000, + 0x00000100, + 0x00040000, + 0x00100000, + 0x00400000, + 0x01000000, + 0x04000000, + 0x10000000, +/* 0x0bd4: i2c_sda_map */ + 0x00002000, + 0x00008000, + 0x00020000, + 0x00000200, + 0x00080000, + 0x00200000, + 0x00800000, + 0x02000000, + 0x08000000, + 0x20000000, +/* 0x0bfc: i2c_ctrl */ + 0x0000e138, + 0x0000e150, + 0x0000e168, + 0x0000e180, + 0x0000e254, + 0x0000e274, + 0x0000e764, + 0x0000e780, + 0x0000e79c, + 0x0000e7b8, + 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 nva3_pwr_code[] = { + 0x030d0ef5, +/* 0x0004: rd32 */ + 0x07a007f1, + 0xd00604b6, + 0x04bd000e, + 0xf001d7f0, + 0x07f101d3, + 0x04b607ac, + 0x000dd006, +/* 0x0022: rd32_wait */ + 0xd7f104bd, + 0xd4b607ac, + 0x00ddcf06, + 0x7000d4f1, + 0xf1f21bf4, + 0xb607a4d7, + 0xddcf06d4, +/* 0x003f: wr32 */ + 0xf100f800, + 0xb607a007, + 0x0ed00604, + 0xf104bd00, + 0xb607a407, + 0x0dd00604, + 0xf004bd00, + 0xd5f002d7, + 0x01d3f0f0, + 0x07ac07f1, + 0xd00604b6, + 0x04bd000d, +/* 0x006c: wr32_wait */ + 0x07acd7f1, + 0xcf06d4b6, + 0xd4f100dd, + 0x1bf47000, +/* 0x007f: nsec */ + 0xf000f8f2, + 0x84b62c87, + 0x0088cf06, +/* 0x0088: nsec_loop */ + 0xb62c97f0, + 0x99cf0694, + 0x0298bb00, + 0xf4069eb8, + 0x00f8f11e, +/* 0x009c: wait */ + 0xb62c87f0, + 0x88cf0684, +/* 0x00a5: wait_loop */ + 0x02eeb900, + 0xb90421f4, + 0xadfd02da, + 0x06acb804, + 0xf0150bf4, + 0x94b62c97, + 0x0099cf06, + 0xb80298bb, + 0x1ef4069b, +/* 0x00c9: wait_done */ +/* 0x00cb: intr_watchdog */ + 0x9800f8df, + 0x96b003e9, + 0x2a0bf400, + 0xbb9a0a98, + 0x1cf4029a, + 0x01d7f00f, + 0x025421f5, + 0x0ef494bd, +/* 0x00e9: intr_watchdog_next_time */ + 0x9b0a9815, + 0xf400a6b0, + 0x9ab8090b, + 0x061cf406, +/* 0x00f8: intr_watchdog_next_time_set */ +/* 0x00fb: intr_watchdog_next_proc */ + 0x809b0980, + 0xe0b603e9, + 0x68e6b158, + 0xc61bf402, +/* 0x010a: intr */ + 0x00f900f8, + 0x80f904bd, + 0xa0f990f9, + 0xc0f9b0f9, + 0xe0f9d0f9, + 0xf7f0f0f9, + 0x0188fe00, + 0x87f180f9, + 0x84b605d0, + 0x0088cf06, + 0xf10180b6, + 0xb605d007, + 0x08d00604, + 0xf004bd00, + 0x84b60887, + 0x0088cf06, + 0xf40289c4, + 0x0080230b, + 0x58e7f09b, + 0x98cb21f4, + 0x96b09b09, + 0x110bf400, + 0xb63407f0, + 0x09d00604, + 0x8004bd00, +/* 0x016e: intr_skip_watchdog */ + 0x89e49a09, + 0x0bf40800, + 0x8897f148, + 0x0694b606, + 0xc40099cf, + 0x0bf4029a, + 0xc0c7f12c, + 0x06c4b604, + 0xf900cccf, + 0x48e7f1c0, + 0x53e3f14f, + 0x00d7f054, + 0x02b921f5, + 0x07f1c0fc, + 0x04b604c0, + 0x000cd006, +/* 0x01ae: intr_subintr_skip_fifo */ + 0x07f104bd, + 0x04b60688, + 0x0009d006, +/* 0x01ba: intr_skip_subintr */ + 0x89c404bd, + 0x070bf420, + 0xffbfa4f1, +/* 0x01c4: intr_skip_pause */ + 0xf44089c4, + 0xa4f1070b, +/* 0x01ce: intr_skip_user0 */ + 0x07f0ffbf, + 0x0604b604, + 0xbd0008d0, + 0xfe80fc04, + 0xf0fc0088, + 0xd0fce0fc, + 0xb0fcc0fc, + 0x90fca0fc, + 0x00fc80fc, + 0xf80032f4, +/* 0x01f5: timer */ + 0x1032f401, + 0xb003f898, + 0x1cf40086, + 0x03fe8051, + 0xb63807f0, + 0x08d00604, + 0xf004bd00, + 0x84b60887, + 0x0088cf06, + 0xf40284f0, + 0x87f0261b, + 0x0684b634, + 0xb80088cf, + 0x0bf406e0, + 0x06e8b809, +/* 0x0233: timer_reset */ + 0xf01f1ef4, + 0x04b63407, + 0x000ed006, + 0x0e8004bd, +/* 0x0241: timer_enable */ + 0x0187f09a, + 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, + 0xd00604b6, + 0x04bd0002, + 0xf04027f0, + 0x04b60007, + 0x0002d006, + 0x00f804bd, +/* 0x0430: host_init */ + 0x008017f1, + 0xf11014b6, + 0xf1027015, + 0xb604d007, + 0x01d00604, + 0xf104bd00, + 0xb6008017, + 0x15f11014, + 0x07f102f0, + 0x04b604dc, + 0x0001d006, + 0x17f004bd, + 0xc407f101, + 0x0604b604, + 0xbd0001d0, +/* 0x046f: memx_func_enter */ + 0xf000f804, + 0x07f10467, + 0x04b607e0, + 0x0006d006, +/* 0x047e: memx_func_enter_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, + 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 */ + 0xf87f21f4, +/* 0x0649: i2c_stop */ + 0x0037f000, + 0x055421f5, + 0xf50037f0, + 0xf1057621, + 0xf403e8e7, + 0x37f07f21, + 0x5421f501, + 0x88e7f105, + 0x7f21f413, + 0xf50137f0, + 0xf1057621, + 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, + 0x7f21f413, + 0xf4013cf0, +/* 0x0702: i2c_bitr_done */ + 0x00f80131, +/* 0x0704: i2c_get_byte */ + 0xf00057f0, +/* 0x070a: i2c_get_byte_next */ + 0x54b60847, + 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, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xbd21f550, + 0x0464b606, + 0xbb0f11f4, + 0x36b00076, + 0x061bf401, +/* 0x07af: i2c_put_byte_done */ + 0xf80132f4, +/* 0x07b1: i2c_addr */ + 0x0076bb00, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b605ed, + 0x2911f404, + 0x012ec3e7, + 0xfd0134b6, + 0x76bb0553, + 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, + 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, + 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 */ + 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, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc new file mode 100644 index 00000000000..48f79434a44 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#define NVKM_PPWR_CHIPSET GF100 + +//#define NVKM_FALCON_PC24 +//#define NVKM_FALCON_UNSHIFTED_IO +//#define NVKM_FALCON_MMIO_UAS +//#define NVKM_FALCON_MMIO_TRAP + +#include "macros.fuc" + +.section #nvc0_pwr_data +#define INCLUDE_PROC +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_PROC + +#define INCLUDE_DATA +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_DATA +.align 256 + +.section #nvc0_pwr_code +#define INCLUDE_CODE +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_CODE +.align 256 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 new file mode 100644 index 00000000000..7ac87405d01 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h @@ -0,0 +1,1589 @@ +uint32_t nvc0_pwr_data[] = { +/* 0x0000: proc_kern */ + 0x52544e49, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0058: proc_list_head */ + 0x54534f48, + 0x00000430, + 0x000003cd, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x584d454d, + 0x0000054e, + 0x00000540, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x46524550, + 0x00000552, + 0x00000550, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5f433249, + 0x00000982, + 0x00000825, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x54534554, + 0x000009ab, + 0x00000984, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x454c4449, + 0x000009b7, + 0x000009b5, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0268: proc_list_tail */ +/* 0x0268: time_prev */ + 0x00000000, +/* 0x026c: time_next */ + 0x00000000, +/* 0x0270: fifo_queue */ + 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, +/* 0x02f0: rfifo_queue */ + 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, +/* 0x0370: memx_func_head */ + 0x00010000, + 0x00000000, + 0x0000046f, +/* 0x037c: memx_func_next */ + 0x00000001, + 0x00000000, + 0x00000496, + 0x00000002, + 0x00000002, + 0x000004b7, + 0x00040003, + 0x00000000, + 0x000004df, + 0x00010004, + 0x00000000, + 0x000004fc, +/* 0x03ac: memx_func_tail */ +/* 0x03ac: memx_data_head */ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, +/* 0x0bac: memx_data_tail */ +/* 0x0bac: i2c_scl_map */ + 0x00001000, + 0x00004000, + 0x00010000, + 0x00000100, + 0x00040000, + 0x00100000, + 0x00400000, + 0x01000000, + 0x04000000, + 0x10000000, +/* 0x0bd4: i2c_sda_map */ + 0x00002000, + 0x00008000, + 0x00020000, + 0x00000200, + 0x00080000, + 0x00200000, + 0x00800000, + 0x02000000, + 0x08000000, + 0x20000000, +/* 0x0bfc: i2c_ctrl */ + 0x0000e138, + 0x0000e150, + 0x0000e168, + 0x0000e180, + 0x0000e254, + 0x0000e274, + 0x0000e764, + 0x0000e780, + 0x0000e79c, + 0x0000e7b8, + 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 nvc0_pwr_code[] = { + 0x030d0ef5, +/* 0x0004: rd32 */ + 0x07a007f1, + 0xd00604b6, + 0x04bd000e, + 0xf001d7f0, + 0x07f101d3, + 0x04b607ac, + 0x000dd006, +/* 0x0022: rd32_wait */ + 0xd7f104bd, + 0xd4b607ac, + 0x00ddcf06, + 0x7000d4f1, + 0xf1f21bf4, + 0xb607a4d7, + 0xddcf06d4, +/* 0x003f: wr32 */ + 0xf100f800, + 0xb607a007, + 0x0ed00604, + 0xf104bd00, + 0xb607a407, + 0x0dd00604, + 0xf004bd00, + 0xd5f002d7, + 0x01d3f0f0, + 0x07ac07f1, + 0xd00604b6, + 0x04bd000d, +/* 0x006c: wr32_wait */ + 0x07acd7f1, + 0xcf06d4b6, + 0xd4f100dd, + 0x1bf47000, +/* 0x007f: nsec */ + 0xf000f8f2, + 0x84b62c87, + 0x0088cf06, +/* 0x0088: nsec_loop */ + 0xb62c97f0, + 0x99cf0694, + 0x0298bb00, + 0xf4069eb8, + 0x00f8f11e, +/* 0x009c: wait */ + 0xb62c87f0, + 0x88cf0684, +/* 0x00a5: wait_loop */ + 0x02eeb900, + 0xb90421f4, + 0xadfd02da, + 0x06acb804, + 0xf0150bf4, + 0x94b62c97, + 0x0099cf06, + 0xb80298bb, + 0x1ef4069b, +/* 0x00c9: wait_done */ +/* 0x00cb: intr_watchdog */ + 0x9800f8df, + 0x96b003e9, + 0x2a0bf400, + 0xbb9a0a98, + 0x1cf4029a, + 0x01d7f00f, + 0x025421f5, + 0x0ef494bd, +/* 0x00e9: intr_watchdog_next_time */ + 0x9b0a9815, + 0xf400a6b0, + 0x9ab8090b, + 0x061cf406, +/* 0x00f8: intr_watchdog_next_time_set */ +/* 0x00fb: intr_watchdog_next_proc */ + 0x809b0980, + 0xe0b603e9, + 0x68e6b158, + 0xc61bf402, +/* 0x010a: intr */ + 0x00f900f8, + 0x80f904bd, + 0xa0f990f9, + 0xc0f9b0f9, + 0xe0f9d0f9, + 0xf7f0f0f9, + 0x0188fe00, + 0x87f180f9, + 0x84b605d0, + 0x0088cf06, + 0xf10180b6, + 0xb605d007, + 0x08d00604, + 0xf004bd00, + 0x84b60887, + 0x0088cf06, + 0xf40289c4, + 0x0080230b, + 0x58e7f09b, + 0x98cb21f4, + 0x96b09b09, + 0x110bf400, + 0xb63407f0, + 0x09d00604, + 0x8004bd00, +/* 0x016e: intr_skip_watchdog */ + 0x89e49a09, + 0x0bf40800, + 0x8897f148, + 0x0694b606, + 0xc40099cf, + 0x0bf4029a, + 0xc0c7f12c, + 0x06c4b604, + 0xf900cccf, + 0x48e7f1c0, + 0x53e3f14f, + 0x00d7f054, + 0x02b921f5, + 0x07f1c0fc, + 0x04b604c0, + 0x000cd006, +/* 0x01ae: intr_subintr_skip_fifo */ + 0x07f104bd, + 0x04b60688, + 0x0009d006, +/* 0x01ba: intr_skip_subintr */ + 0x89c404bd, + 0x070bf420, + 0xffbfa4f1, +/* 0x01c4: intr_skip_pause */ + 0xf44089c4, + 0xa4f1070b, +/* 0x01ce: intr_skip_user0 */ + 0x07f0ffbf, + 0x0604b604, + 0xbd0008d0, + 0xfe80fc04, + 0xf0fc0088, + 0xd0fce0fc, + 0xb0fcc0fc, + 0x90fca0fc, + 0x00fc80fc, + 0xf80032f4, +/* 0x01f5: timer */ + 0x1032f401, + 0xb003f898, + 0x1cf40086, + 0x03fe8051, + 0xb63807f0, + 0x08d00604, + 0xf004bd00, + 0x84b60887, + 0x0088cf06, + 0xf40284f0, + 0x87f0261b, + 0x0684b634, + 0xb80088cf, + 0x0bf406e0, + 0x06e8b809, +/* 0x0233: timer_reset */ + 0xf01f1ef4, + 0x04b63407, + 0x000ed006, + 0x0e8004bd, +/* 0x0241: timer_enable */ + 0x0187f09a, + 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, + 0xd00604b6, + 0x04bd0002, + 0xf04027f0, + 0x04b60007, + 0x0002d006, + 0x00f804bd, +/* 0x0430: host_init */ + 0x008017f1, + 0xf11014b6, + 0xf1027015, + 0xb604d007, + 0x01d00604, + 0xf104bd00, + 0xb6008017, + 0x15f11014, + 0x07f102f0, + 0x04b604dc, + 0x0001d006, + 0x17f004bd, + 0xc407f101, + 0x0604b604, + 0xbd0001d0, +/* 0x046f: memx_func_enter */ + 0xf000f804, + 0x07f10467, + 0x04b607e0, + 0x0006d006, +/* 0x047e: memx_func_enter_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, + 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 */ + 0xf87f21f4, +/* 0x0649: i2c_stop */ + 0x0037f000, + 0x055421f5, + 0xf50037f0, + 0xf1057621, + 0xf403e8e7, + 0x37f07f21, + 0x5421f501, + 0x88e7f105, + 0x7f21f413, + 0xf50137f0, + 0xf1057621, + 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, + 0x7f21f413, + 0xf4013cf0, +/* 0x0702: i2c_bitr_done */ + 0x00f80131, +/* 0x0704: i2c_get_byte */ + 0xf00057f0, +/* 0x070a: i2c_get_byte_next */ + 0x54b60847, + 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, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xbd21f550, + 0x0464b606, + 0xbb0f11f4, + 0x36b00076, + 0x061bf401, +/* 0x07af: i2c_put_byte_done */ + 0xf80132f4, +/* 0x07b1: i2c_addr */ + 0x0076bb00, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b605ed, + 0x2911f404, + 0x012ec3e7, + 0xfd0134b6, + 0x76bb0553, + 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, + 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, + 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 */ + 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, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc new file mode 100644 index 00000000000..8a89dfe41ce --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#define NVKM_PPWR_CHIPSET GF119 + +//#define NVKM_FALCON_PC24 +#define NVKM_FALCON_UNSHIFTED_IO +//#define NVKM_FALCON_MMIO_UAS +//#define NVKM_FALCON_MMIO_TRAP + +#include "macros.fuc" + +.section #nvd0_pwr_data +#define INCLUDE_PROC +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_PROC + +#define INCLUDE_DATA +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_DATA +.align 256 + +.section #nvd0_pwr_code +#define INCLUDE_CODE +#include "kernel.fuc" +#include "host.fuc" +#include "memx.fuc" +#include "perf.fuc" +#include "i2c_.fuc" +#include "test.fuc" +#include "idle.fuc" +#undef INCLUDE_CODE +.align 256 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 new file mode 100644 index 00000000000..cd9ff1a7328 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h @@ -0,0 +1,1524 @@ +uint32_t nvd0_pwr_data[] = { +/* 0x0000: proc_kern */ + 0x52544e49, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0058: proc_list_head */ + 0x54534f48, + 0x000003be, + 0x00000367, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x584d454d, + 0x000004c4, + 0x000004b6, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x46524550, + 0x000004c8, + 0x000004c6, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5f433249, + 0x000008e3, + 0x00000786, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x54534554, + 0x00000906, + 0x000008e5, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x454c4449, + 0x00000912, + 0x00000910, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0268: proc_list_tail */ +/* 0x0268: time_prev */ + 0x00000000, +/* 0x026c: time_next */ + 0x00000000, +/* 0x0270: fifo_queue */ + 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, +/* 0x02f0: rfifo_queue */ + 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, +/* 0x0370: memx_func_head */ + 0x00010000, + 0x00000000, + 0x000003f4, +/* 0x037c: memx_func_next */ + 0x00000001, + 0x00000000, + 0x00000415, + 0x00000002, + 0x00000002, + 0x00000430, + 0x00040003, + 0x00000000, + 0x00000458, + 0x00010004, + 0x00000000, + 0x00000472, +/* 0x03ac: memx_func_tail */ +/* 0x03ac: memx_data_head */ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, +/* 0x0bac: memx_data_tail */ +/* 0x0bac: i2c_scl_map */ + 0x00000400, + 0x00000800, + 0x00001000, + 0x00002000, + 0x00004000, + 0x00008000, + 0x00010000, + 0x00020000, + 0x00040000, + 0x00080000, +/* 0x0bd4: i2c_sda_map */ + 0x00100000, + 0x00200000, + 0x00400000, + 0x00800000, + 0x01000000, + 0x02000000, + 0x04000000, + 0x08000000, + 0x10000000, + 0x20000000, + 0x00000000, +}; + +uint32_t nvd0_pwr_code[] = { + 0x02bf0ef5, +/* 0x0004: rd32 */ + 0x07a007f1, + 0xbd000ed0, + 0x01d7f004, + 0xf101d3f0, + 0xd007ac07, + 0x04bd000d, +/* 0x001c: rd32_wait */ + 0x07acd7f1, + 0xf100ddcf, + 0xf47000d4, + 0xd7f1f51b, + 0xddcf07a4, +/* 0x0033: wr32 */ + 0xf100f800, + 0xd007a007, + 0x04bd000e, + 0x07a407f1, + 0xbd000dd0, + 0x02d7f004, + 0xf0f0d5f0, + 0x07f101d3, + 0x0dd007ac, +/* 0x0057: wr32_wait */ + 0xf104bd00, + 0xcf07acd7, + 0xd4f100dd, + 0x1bf47000, +/* 0x0067: nsec */ + 0xf000f8f5, + 0x88cf2c87, +/* 0x006d: nsec_loop */ + 0x2c97f000, + 0xbb0099cf, + 0x9eb80298, + 0xf41ef406, +/* 0x007e: wait */ + 0x87f000f8, + 0x0088cf2c, +/* 0x0084: wait_loop */ + 0xf402eeb9, + 0xdab90421, + 0x04adfd02, + 0xf406acb8, + 0x97f0120b, + 0x0099cf2c, + 0xb80298bb, + 0x1ef4069b, +/* 0x00a5: wait_done */ +/* 0x00a7: intr_watchdog */ + 0x9800f8e2, + 0x96b003e9, + 0x2a0bf400, + 0xbb9a0a98, + 0x1cf4029a, + 0x01d7f00f, + 0x020621f5, + 0x0ef494bd, +/* 0x00c5: intr_watchdog_next_time */ + 0x9b0a9815, + 0xf400a6b0, + 0x9ab8090b, + 0x061cf406, +/* 0x00d4: intr_watchdog_next_time_set */ +/* 0x00d7: intr_watchdog_next_proc */ + 0x809b0980, + 0xe0b603e9, + 0x68e6b158, + 0xc61bf402, +/* 0x00e6: intr */ + 0x00f900f8, + 0x80f904bd, + 0xa0f990f9, + 0xc0f9b0f9, + 0xe0f9d0f9, + 0xf7f0f0f9, + 0x0188fe00, + 0x87f180f9, + 0x88cf05d0, + 0x0180b600, + 0x05d007f1, + 0xbd0008d0, + 0x0887f004, + 0xc40088cf, + 0x0bf40289, + 0x9b008020, + 0xf458e7f0, + 0x0998a721, + 0x0096b09b, + 0xf00e0bf4, + 0x09d03407, + 0x8004bd00, +/* 0x013e: intr_skip_watchdog */ + 0x89e49a09, + 0x0bf40800, + 0x8897f13c, + 0x0099cf06, + 0xf4029ac4, + 0xc7f1260b, + 0xcccf04c0, + 0xf1c0f900, + 0xf14f48e7, + 0xf05453e3, + 0x21f500d7, + 0xc0fc026b, + 0x04c007f1, + 0xbd000cd0, +/* 0x0175: intr_subintr_skip_fifo */ + 0x8807f104, + 0x0009d006, +/* 0x017e: intr_skip_subintr */ + 0x89c404bd, + 0x070bf420, + 0xffbfa4f1, +/* 0x0188: intr_skip_pause */ + 0xf44089c4, + 0xa4f1070b, +/* 0x0192: intr_skip_user0 */ + 0x07f0ffbf, + 0x0008d004, + 0x80fc04bd, + 0xfc0088fe, + 0xfce0fcf0, + 0xfcc0fcd0, + 0xfca0fcb0, + 0xfc80fc90, + 0x0032f400, +/* 0x01b6: timer */ + 0x32f401f8, + 0x03f89810, + 0xf40086b0, + 0xfe80421c, + 0x3807f003, + 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, + 0x04e99805, + 0xb80486f0, + 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, + 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 */ + 0x17f100f8, + 0x14b60080, + 0x7015f110, + 0xd007f102, + 0x0001d004, + 0x17f104bd, + 0x14b60080, + 0xf015f110, + 0xdc07f102, + 0x0001d004, + 0x17f004bd, + 0xc407f101, + 0x0001d004, + 0x00f804bd, +/* 0x03f4: memx_func_enter */ + 0xf10467f0, + 0xd007e007, + 0x04bd0006, +/* 0x0400: memx_func_enter_wait */ + 0x07c067f1, + 0xf00066cf, + 0x0bf40464, + 0x001698f6, + 0xf80410b6, +/* 0x0415: memx_func_leave */ + 0x0467f000, + 0x07e407f1, + 0xbd0006d0, +/* 0x0421: memx_func_leave_wait */ + 0xc067f104, + 0x0066cf07, + 0xf40464f0, + 0x00f8f61b, +/* 0x0430: memx_func_wr32 */ + 0x98001698, + 0x10b60115, + 0xf960f908, + 0xfcd0fc50, + 0x3321f4e0, + 0x140003f1, + 0x800506fd, + 0x04bd0005, + 0xf40242b6, + 0x00f8dd1b, +/* 0x0458: memx_func_wait */ + 0xcf2c87f0, + 0x1e980088, + 0x011d9800, + 0x98021c98, + 0x10b6031b, + 0x7e21f410, +/* 0x0472: memx_func_delay */ + 0x1e9800f8, + 0x0410b600, + 0xf86721f4, +/* 0x047d: memx_exec */ + 0xf9e0f900, + 0x02c1b9d0, +/* 0x0487: memx_exec_next */ + 0x9802b2b9, + 0x10b60013, + 0x10349504, + 0x980c30f0, + 0x55f9de35, + 0xf40612b8, + 0xd0fcec1e, + 0x21f5e0fc, + 0x00f8026b, +/* 0x04a8: memx_info */ + 0x03acc7f1, + 0x0800b7f1, + 0x026b21f5, +/* 0x04b6: memx_recv */ + 0xd6b000f8, + 0xc40bf401, + 0xf400d6b0, + 0x00f8e90b, +/* 0x04c4: memx_init */ +/* 0x04c6: perf_recv */ + 0x00f800f8, +/* 0x04c8: perf_init */ +/* 0x04ca: i2c_drive_scl */ + 0x36b000f8, + 0x0e0bf400, + 0x07e007f1, + 0xbd0001d0, +/* 0x04db: i2c_drive_scl_lo */ + 0xf100f804, + 0xd007e407, + 0x04bd0001, +/* 0x04e6: i2c_drive_sda */ + 0x36b000f8, + 0x0e0bf400, + 0x07e007f1, + 0xbd0002d0, +/* 0x04f7: i2c_drive_sda_lo */ + 0xf100f804, + 0xd007e407, + 0x04bd0002, +/* 0x0502: i2c_sense_scl */ + 0x32f400f8, + 0xc437f101, + 0x0033cf07, + 0xf40431fd, + 0x31f4060b, +/* 0x0515: i2c_sense_scl_done */ +/* 0x0517: i2c_sense_sda */ + 0xf400f801, + 0x37f10132, + 0x33cf07c4, + 0x0432fd00, + 0xf4060bf4, +/* 0x052a: i2c_sense_sda_done */ + 0x00f80131, +/* 0x052c: i2c_raise_scl */ + 0x47f140f9, + 0x37f00898, + 0xca21f501, +/* 0x0539: i2c_raise_scl_wait */ + 0xe8e7f104, + 0x6721f403, + 0x050221f5, + 0xb60901f4, + 0x1bf40142, +/* 0x054d: i2c_raise_scl_done */ + 0xf840fcef, +/* 0x0551: i2c_start */ + 0x0221f500, + 0x0d11f405, + 0x051721f5, + 0xf40611f4, +/* 0x0562: i2c_start_rep */ + 0x37f0300e, + 0xca21f500, + 0x0137f004, + 0x04e621f5, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x2c21f550, + 0x0464b605, +/* 0x058f: i2c_start_send */ + 0xf01f11f4, + 0x21f50037, + 0xe7f104e6, + 0x21f41388, + 0x0037f067, + 0x04ca21f5, + 0x1388e7f1, +/* 0x05ab: i2c_start_out */ + 0xf86721f4, +/* 0x05ad: i2c_stop */ + 0x0037f000, + 0x04ca21f5, + 0xf50037f0, + 0xf104e621, + 0xf403e8e7, + 0x37f06721, + 0xca21f501, + 0x88e7f104, + 0x6721f413, + 0xf50137f0, + 0xf104e621, + 0xf41388e7, + 0x00f86721, +/* 0x05e0: i2c_bitw */ + 0x04e621f5, + 0x03e8e7f1, + 0xbb6721f4, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x052c21f5, + 0xf40464b6, + 0xe7f11811, + 0x21f41388, + 0x0037f067, + 0x04ca21f5, + 0x1388e7f1, +/* 0x061f: i2c_bitw_out */ + 0xf86721f4, +/* 0x0621: i2c_bitr */ + 0x0137f000, + 0x04e621f5, + 0x03e8e7f1, + 0xbb6721f4, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x052c21f5, + 0xf40464b6, + 0x21f51b11, + 0x37f00517, + 0xca21f500, + 0x88e7f104, + 0x6721f413, + 0xf4013cf0, +/* 0x0666: i2c_bitr_done */ + 0x00f80131, +/* 0x0668: i2c_get_byte */ + 0xf00057f0, +/* 0x066e: i2c_get_byte_next */ + 0x54b60847, + 0x0076bb01, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b60621, + 0x2b11f404, + 0xb60553fd, + 0x1bf40142, + 0x0137f0d8, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xe021f550, + 0x0464b605, +/* 0x06b8: i2c_get_byte_done */ +/* 0x06ba: i2c_put_byte */ + 0x47f000f8, +/* 0x06bd: i2c_put_byte_next */ + 0x0142b608, + 0xbb3854ff, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x05e021f5, + 0xf40464b6, + 0x46b03411, + 0xd81bf400, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x2121f550, + 0x0464b606, + 0xbb0f11f4, + 0x36b00076, + 0x061bf401, +/* 0x0713: i2c_put_byte_done */ + 0xf80132f4, +/* 0x0715: i2c_addr */ + 0x0076bb00, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b60551, + 0x2911f404, + 0x012ec3e7, + 0xfd0134b6, + 0x76bb0553, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb606ba21, +/* 0x075a: i2c_addr_done */ + 0x00f80464, +/* 0x075c: i2c_acquire_addr */ + 0xb6f8cec7, + 0xe0b705e4, + 0x00f8d014, +/* 0x0768: i2c_acquire */ + 0x075c21f5, + 0xf00421f4, + 0x21f403d9, +/* 0x0777: i2c_release */ + 0xf500f833, + 0xf4075c21, + 0xdaf00421, + 0x3321f403, +/* 0x0786: i2c_recv */ + 0x32f400f8, + 0xf8c1c701, + 0xb00214b6, + 0x1ff52816, + 0x13a0013a, + 0x32980bd4, + 0xac13a000, + 0x0031980b, + 0xf90231f4, + 0xf9e0f9d0, + 0x0067f1d0, + 0x0063f100, + 0x01679210, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x6821f550, + 0x0464b607, + 0xd6b0d0fc, + 0xb31bf500, + 0x0057f000, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x1521f550, + 0x0464b607, + 0x00d011f5, + 0xbbe0c5c7, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x06ba21f5, + 0xf50464b6, + 0xf000ad11, + 0x76bb0157, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb6071521, + 0x11f50464, + 0x76bb008a, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb6066821, + 0x11f40464, + 0xe05bcb6a, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xad21f550, + 0x0464b605, + 0xbd025bb9, + 0x430ef474, +/* 0x088c: i2c_recv_not_rd08 */ + 0xf401d6b0, + 0x57f03d1b, + 0x1521f500, + 0x3311f407, + 0xf5e0c5c7, + 0xf406ba21, + 0x57f02911, + 0x1521f500, + 0x1f11f407, + 0xf5e0b5c7, + 0xf406ba21, + 0x21f51511, + 0x74bd05ad, + 0xf408c5c7, + 0x32f4091b, + 0x030ef402, +/* 0x08cc: i2c_recv_not_wr08 */ +/* 0x08cc: i2c_recv_done */ + 0xf5f8cec7, + 0xfc077721, + 0xf4d0fce0, + 0x7cb90a12, + 0x6b21f502, +/* 0x08e1: i2c_recv_exit */ +/* 0x08e3: i2c_init */ + 0xf800f802, +/* 0x08e5: test_recv */ + 0xd817f100, + 0x0011cf05, + 0xf10110b6, + 0xd005d807, + 0x04bd0001, + 0xd900e7f1, + 0x134fe3f1, + 0x01b621f5, +/* 0x0906: test_init */ + 0xe7f100f8, + 0x21f50800, + 0x00f801b6, +/* 0x0910: idle_recv */ +/* 0x0912: idle */ + 0x31f400f8, + 0xd417f100, + 0x0011cf05, + 0xf10110b6, + 0xd005d407, + 0x04bd0001, +/* 0x0928: idle_loop */ + 0xf45817f0, +/* 0x092e: idle_proc */ +/* 0x092e: idle_proc_exec */ + 0x10f90232, + 0xf5021eb9, + 0xfc027421, + 0x0911f410, + 0xf40231f4, +/* 0x0942: idle_proc_next */ + 0x10b6ef0e, + 0x061fb858, + 0xf4e61bf4, + 0x28f4dd02, + 0xc10ef400, + 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, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h new file mode 100644 index 00000000000..574acfa44c8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h @@ -0,0 +1,46 @@ +#ifndef __NVKM_PWR_OS_H__ +#define __NVKM_PWR_OS_H__ + +/* Process names */ +#define PROC_KERN 0x52544e49 +#define PROC_IDLE 0x454c4449 +#define PROC_HOST 0x54534f48 +#define PROC_MEMX 0x584d454d +#define PROC_PERF 0x46524550 +#define PROC_I2C_ 0x5f433249 +#define PROC_TEST 0x54534554 + +/* KERN: message identifiers */ +#define KMSG_FIFO 0x00000000 +#define KMSG_ALARM 0x00000001 + +/* MEMX: message identifiers */ +#define MEMX_MSG_INFO 0 +#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 + +/* I2C_: message identifiers */ +#define I2C__MSG_RD08 0 +#define I2C__MSG_WR08 1 + +#define I2C__MSG_DATA0_PORT 24:31 +#define I2C__MSG_DATA0_ADDR 14:23 + +#define I2C__MSG_DATA0_RD08_PORT I2C__MSG_DATA0_PORT +#define I2C__MSG_DATA0_RD08_ADDR I2C__MSG_DATA0_ADDR +#define I2C__MSG_DATA0_RD08_REG 0:7 +#define I2C__MSG_DATA1_RD08_VAL 0:7 + +#define I2C__MSG_DATA0_WR08_PORT I2C__MSG_DATA0_PORT +#define I2C__MSG_DATA0_WR08_ADDR I2C__MSG_DATA0_ADDR +#define I2C__MSG_DATA0_WR08_SYNC 8:8 +#define I2C__MSG_DATA0_WR08_REG 0:7 +#define I2C__MSG_DATA1_WR08_VAL 0:7 + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc new file mode 100644 index 00000000000..38eadf705cb --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc @@ -0,0 +1,57 @@ +/* + * 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 + */ + +#ifdef INCLUDE_PROC +process(PROC_PERF, #perf_init, #perf_recv) +#endif + +/****************************************************************************** + * PERF data segment + *****************************************************************************/ +#ifdef INCLUDE_DATA +#endif + +/****************************************************************************** + * PERF code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE + +// description +// +// $r15 - current (perf) +// $r14 - sender process name +// $r13 - message +// $r12 - data0 +// $r11 - data1 +// $r0 - zero +perf_recv: + ret + +// description +// +// $r15 - current (perf) +// $r0 - zero +perf_init: + ret +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc new file mode 100644 index 00000000000..0c3a71bf545 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc @@ -0,0 +1,64 @@ +/* + * 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 + */ + +#ifdef INCLUDE_PROC +process(PROC_TEST, #test_init, #test_recv) +#endif + +/****************************************************************************** + * TEST data segment + *****************************************************************************/ +#ifdef INCLUDE_DATA +#endif + +/****************************************************************************** + * TEST code segment + *****************************************************************************/ +#ifdef INCLUDE_CODE +// description +// +// $r15 - current (test) +// $r14 - sender process name +// $r13 - message +// $r12 - data0 +// $r11 - data1 +// $r0 - zero +test_recv: + nv_iord($r1, NV_PPWR_DSCRATCH(2)) + add b32 $r1 1 + nv_iowr(NV_PPWR_DSCRATCH(2), $r1) + mov $r14 -0x2700 /* 0xd900, envyas grrr! */ + sethi $r14 0x134f0000 + call(timer) + ret + +// description +// +// $r15 - current (test) +// $r0 - zero +test_init: + mov $r14 0x800 + call(timer) + ret +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c new file mode 100644 index 00000000000..03de3107d29 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c @@ -0,0 +1,121 @@ +#ifndef __NVKM_PWR_MEMX_H__ +#define __NVKM_PWR_MEMX_H__ + +#include <subdev/pwr.h> +#include <subdev/pwr/fuc/os.h> + +struct nouveau_memx { + struct nouveau_pwr *ppwr; + u32 base; + u32 size; + struct { + u32 mthd; + u32 size; + u32 data[64]; + } c; +}; + +static void +memx_out(struct nouveau_memx *memx) +{ + struct nouveau_pwr *ppwr = memx->ppwr; + int i; + + if (memx->c.size) { + 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.size = 0; + } +} + +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_out(memx); + memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0])); + memx->c.size += size; + memx->c.mthd = mthd; +} + +int +nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx) +{ + struct nouveau_memx *memx; + u32 reply[2]; + int ret; + + ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO, 0, 0); + if (ret) + return ret; + + memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL); + if (!memx) + return -ENOMEM; + memx->ppwr = ppwr; + memx->base = reply[0]; + memx->size = reply[1]; + + /* acquire data segment access */ + do { + 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; +} + +int +nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec) +{ + struct nouveau_memx *memx = *pmemx; + struct nouveau_pwr *ppwr = memx->ppwr; + u32 finish, reply[2]; + + /* flush the cache... */ + 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); + + /* call MEMX process to execute the script, and wait for reply */ + if (exec) { + ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_EXEC, + memx->base, finish); + } + + kfree(memx); + return 0; +} + +void +nouveau_memx_wr32(struct nouveau_memx *memx, u32 addr, u32 data) +{ + nv_debug(memx->ppwr, "R[%06x] = 0x%08x\n", addr, data); + memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data }); +} + +void +nouveau_memx_wait(struct nouveau_memx *memx, + u32 addr, u32 mask, u32 data, u32 nsec) +{ + nv_debug(memx->ppwr, "R[%06x] & 0x%08x == 0x%08x, %d us\n", + addr, mask, data, nsec); + memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, ~mask, data, nsec }); + memx_out(memx); /* fuc can't handle multiple */ +} + +void +nouveau_memx_nsec(struct nouveau_memx *memx, u32 nsec) +{ + nv_debug(memx->ppwr, " DELAY = %d ns\n", nsec); + memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec }); + memx_out(memx); /* fuc can't handle multiple */ +} + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c new file mode 100644 index 00000000000..52c85414866 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c @@ -0,0 +1,62 @@ +/* + * 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/pwr.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, + .dtor = _nouveau_pwr_dtor, + .init = _nouveau_pwr_init, + .fini = _nouveau_pwr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c new file mode 100644 index 00000000000..c132b7ca974 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c @@ -0,0 +1,71 @@ +/* + * 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/pwr.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_oclass +nva3_pwr_oclass = { + .handle = NV_SUBDEV(PWR, 0xa3), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nva3_pwr_ctor, + .dtor = _nouveau_pwr_dtor, + .init = nva3_pwr_init, + .fini = _nouveau_pwr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c new file mode 100644 index 00000000000..495f6857428 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c @@ -0,0 +1,62 @@ +/* + * 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/pwr.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, + .dtor = _nouveau_pwr_dtor, + .init = _nouveau_pwr_init, + .fini = _nouveau_pwr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c new file mode 100644 index 00000000000..043aa142fe8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c @@ -0,0 +1,62 @@ +/* + * 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/pwr.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, + .dtor = _nouveau_pwr_dtor, + .init = _nouveau_pwr_init, + .fini = _nouveau_pwr_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c index f1de7a9c572..9ad01da6eac 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c @@ -92,10 +92,11 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) struct nouveau_timer *ptimer = nouveau_timer(therm); struct nouveau_therm_priv *priv = (void *)therm; unsigned long flags; - int duty; + bool immd = true; + bool poll = true; + int duty = -1; spin_lock_irqsave(&priv->lock, flags); - nv_debug(therm, "FAN speed check\n"); if (mode < 0) mode = priv->mode; priv->mode = mode; @@ -106,28 +107,51 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) duty = nouveau_therm_fan_get(therm); if (duty < 0) duty = 100; + poll = false; break; case NOUVEAU_THERM_CTRL_AUTO: - if (priv->fan->bios.nr_fan_trip) + switch(priv->fan->bios.fan_mode) { + case NVBIOS_THERM_FAN_TRIP: duty = nouveau_therm_update_trip(therm); - else + break; + case NVBIOS_THERM_FAN_LINEAR: duty = nouveau_therm_update_linear(therm); + break; + case NVBIOS_THERM_FAN_OTHER: + if (priv->cstate) + duty = priv->cstate; + poll = false; + break; + } + immd = false; break; case NOUVEAU_THERM_CTRL_NONE: default: ptimer->alarm_cancel(ptimer, &priv->alarm); - goto done; + poll = false; } - nv_debug(therm, "FAN target request: %d%%\n", duty); - nouveau_therm_fan_set(therm, (mode != NOUVEAU_THERM_CTRL_AUTO), duty); - -done: - if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO)) + if (list_empty(&priv->alarm.head) && poll) ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); - else if (!list_empty(&priv->alarm.head)) - nv_debug(therm, "therm fan alarm list is not empty\n"); spin_unlock_irqrestore(&priv->lock, flags); + + if (duty >= 0) { + nv_debug(therm, "FAN target request: %d%%\n", duty); + nouveau_therm_fan_set(therm, immd, duty); + } +} + +int +nouveau_therm_cstate(struct nouveau_therm *ptherm, int fan, int dir) +{ + struct nouveau_therm_priv *priv = (void *)ptherm; + if (!dir || (dir < 0 && fan < priv->cstate) || + (dir > 0 && fan > priv->cstate)) { + nv_debug(ptherm, "default fan speed -> %d%%\n", fan); + priv->cstate = fan; + nouveau_therm_update(ptherm, -1); + } + return 0; } static void @@ -149,14 +173,15 @@ nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode) "automatic" }; - /* The default PDAEMON ucode interferes with fan management */ + /* The default PPWR ucode on fermi interferes with fan management */ if ((mode >= ARRAY_SIZE(name)) || - (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0)) + (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0 && + !nouveau_subdev(device, NVDEV_SUBDEV_PWR))) return -EINVAL; /* do not allow automatic fan management if the thermal sensor is * not available */ - if (priv->mode == 2 && therm->temp_get(therm) < 0) + if (mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0) return -EINVAL; if (priv->mode == mode) @@ -335,7 +360,7 @@ nouveau_therm_preinit(struct nouveau_therm *therm) nouveau_therm_ic_ctor(therm); nouveau_therm_fan_ctor(therm); - nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_NONE); + nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO); nouveau_therm_sensor_preinit(therm); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index 39f47b950ad..016990a8252 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c @@ -54,8 +54,10 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) /* check that we're not already at the target duty cycle */ duty = fan->get(therm); - if (duty == target) - goto done; + if (duty == target) { + spin_unlock_irqrestore(&fan->lock, flags); + return 0; + } /* smooth out the fanspeed increase/decrease */ if (!immediate && duty >= 0) { @@ -73,8 +75,15 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) nv_debug(therm, "FAN update: %d\n", duty); ret = fan->set(therm, duty); - if (ret) - goto done; + if (ret) { + spin_unlock_irqrestore(&fan->lock, flags); + return ret; + } + + /* fan speed updated, drop the fan lock before grabbing the + * alarm-scheduling lock and risking a deadlock + */ + spin_unlock_irqrestore(&fan->lock, flags); /* schedule next fan update, if not at target speed already */ if (list_empty(&fan->alarm.head) && target != duty) { @@ -92,8 +101,6 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm); } -done: - spin_unlock_irqrestore(&fan->lock, flags); return ret; } @@ -232,7 +239,8 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) /* attempt to locate a drivable fan, and determine control method */ ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); if (ret == 0) { - if (func.log[0] & DCB_GPIO_LOG_DIR_IN) { + /* FIXME: is this really the place to perform such checks ? */ + if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) { nv_debug(therm, "GPIO_FAN is in input mode\n"); ret = -EINVAL; } else { diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c index 5f71db8e899..9a5c0734026 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c @@ -67,7 +67,7 @@ nouveau_fanpwm_set(struct nouveau_therm *therm, int percent) if (priv->base.bios.pwm_freq) { divs = 1; if (therm->pwm_clock) - divs = therm->pwm_clock(therm); + divs = therm->pwm_clock(therm, priv->func.line); divs /= priv->base.bios.pwm_freq; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c index e601773ee47..f69dab11f72 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c @@ -97,6 +97,13 @@ nouveau_fantog_create(struct nouveau_therm *therm, struct dcb_gpio_func *func) { struct nouveau_therm_priv *tpriv = (void *)therm; struct nouveau_fantog_priv *priv; + int ret; + + if (therm->pwm_ctrl) { + ret = therm->pwm_ctrl(therm, func->line, false); + if (ret) + return ret; + } priv = kzalloc(sizeof(*priv), GFP_KERNEL); tpriv->fan = &priv->base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c index 8b3adec5fbb..ca9ad9fd47b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c @@ -29,9 +29,9 @@ static bool probe_monitoring_device(struct nouveau_i2c_port *i2c, - struct i2c_board_info *info) + struct i2c_board_info *info, void *data) { - struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c); + struct nouveau_therm_priv *priv = data; struct nvbios_therm_sensor *sensor = &priv->bios_sensor; struct i2c_client *client; @@ -41,7 +41,8 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, if (!client) return false; - if (!client->driver || client->driver->detect(client, info)) { + if (!client->dev.driver || + to_i2c_driver(client->dev.driver)->detect(client, info)) { i2c_unregister_device(client); return false; } @@ -55,28 +56,28 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, return true; } -static struct i2c_board_info +static struct nouveau_i2c_board_info nv_board_infos[] = { - { I2C_BOARD_INFO("w83l785ts", 0x2d) }, - { I2C_BOARD_INFO("w83781d", 0x2d) }, - { I2C_BOARD_INFO("adt7473", 0x2e) }, - { I2C_BOARD_INFO("adt7473", 0x2d) }, - { I2C_BOARD_INFO("adt7473", 0x2c) }, - { I2C_BOARD_INFO("f75375", 0x2e) }, - { I2C_BOARD_INFO("lm99", 0x4c) }, - { I2C_BOARD_INFO("lm90", 0x4c) }, - { I2C_BOARD_INFO("lm90", 0x4d) }, - { I2C_BOARD_INFO("adm1021", 0x18) }, - { I2C_BOARD_INFO("adm1021", 0x19) }, - { I2C_BOARD_INFO("adm1021", 0x1a) }, - { I2C_BOARD_INFO("adm1021", 0x29) }, - { I2C_BOARD_INFO("adm1021", 0x2a) }, - { I2C_BOARD_INFO("adm1021", 0x2b) }, - { I2C_BOARD_INFO("adm1021", 0x4c) }, - { I2C_BOARD_INFO("adm1021", 0x4d) }, - { I2C_BOARD_INFO("adm1021", 0x4e) }, - { I2C_BOARD_INFO("lm63", 0x18) }, - { I2C_BOARD_INFO("lm63", 0x4e) }, + { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 }, + { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 }, + { { I2C_BOARD_INFO("adt7473", 0x2e) }, 40 }, + { { I2C_BOARD_INFO("adt7473", 0x2d) }, 40 }, + { { I2C_BOARD_INFO("adt7473", 0x2c) }, 40 }, + { { I2C_BOARD_INFO("f75375", 0x2e) }, 0 }, + { { I2C_BOARD_INFO("lm99", 0x4c) }, 0 }, + { { I2C_BOARD_INFO("lm90", 0x4c) }, 0 }, + { { I2C_BOARD_INFO("lm90", 0x4d) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x18) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x19) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x1a) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x29) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x2a) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x2b) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x4c) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x4d) }, 0 }, + { { I2C_BOARD_INFO("adm1021", 0x4e) }, 0 }, + { { I2C_BOARD_INFO("lm63", 0x18) }, 0 }, + { { I2C_BOARD_INFO("lm63", 0x4e) }, 0 }, { } }; @@ -89,25 +90,25 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) struct nvbios_extdev_func extdev_entry; if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { - struct i2c_board_info board[] = { - { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, - { } + struct nouveau_i2c_board_info board[] = { + { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0}, + { } }; i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - board, probe_monitoring_device); + board, probe_monitoring_device, therm); if (priv->ic) return; } if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { - struct i2c_board_info board[] = { - { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, - { } + struct nouveau_i2c_board_info board[] = { + { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 }, + { } }; i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - board, probe_monitoring_device); + board, probe_monitoring_device, therm); if (priv->ic) return; } @@ -116,5 +117,5 @@ nouveau_therm_ic_ctor(struct nouveau_therm *therm) device. Let's try our static list. */ i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - nv_board_infos, probe_monitoring_device); + nv_board_infos, probe_monitoring_device, therm); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c index 8cf7597a218..321db927d63 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c @@ -93,7 +93,7 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) } int -nv50_fan_pwm_clock(struct nouveau_therm *therm) +nv50_fan_pwm_clock(struct nouveau_therm *therm, int line) { int chipset = nv_device(therm)->chipset; int crystal = nv_device(therm)->crystal; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c index 42ba633ccff..1d15c52fad0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c @@ -126,7 +126,7 @@ nv84_therm_intr(struct nouveau_subdev *subdev) spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); - intr = nv_rd32(therm, 0x20100); + intr = nv_rd32(therm, 0x20100) & 0x3ff; /* THRS_4: downclock */ if (intr & 0x002) { @@ -209,6 +209,19 @@ nv84_therm_ctor(struct nouveau_object *parent, return nouveau_therm_preinit(&priv->base.base); } +int +nv84_therm_fini(struct nouveau_object *object, bool suspend) +{ + /* Disable PTherm IRQs */ + nv_wr32(object, 0x20000, 0x00000000); + + /* ACK all PTherm IRQs */ + nv_wr32(object, 0x20100, 0xffffffff); + nv_wr32(object, 0x1100, 0x10000); /* PBUS */ + + return _nouveau_therm_fini(object, suspend); +} + struct nouveau_oclass nv84_therm_oclass = { .handle = NV_SUBDEV(THERM, 0x84), @@ -216,6 +229,6 @@ nv84_therm_oclass = { .ctor = nv84_therm_ctor, .dtor = _nouveau_therm_dtor, .init = _nouveau_therm_init, - .fini = _nouveau_therm_fini, + .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 d11a7c40081..0478b2e3fb1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c @@ -36,7 +36,7 @@ nva3_therm_fan_sense(struct nouveau_therm *therm) u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff; u32 ctrl = nv_rd32(therm, 0x00e720); if (ctrl & 0x00000001) - return tach * 60; + return tach * 60 / 2; return -ENODEV; } @@ -94,6 +94,6 @@ nva3_therm_oclass = { .ctor = nva3_therm_ctor, .dtor = _nouveau_therm_dtor, .init = nva3_therm_init, - .fini = _nouveau_therm_fini, + .fini = nv84_therm_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c index 54c28bdc420..bbf117be572 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c @@ -32,12 +32,15 @@ static int pwm_info(struct nouveau_therm *therm, int line) { u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); + switch (gpio & 0x000000c0) { case 0x00000000: /* normal mode, possibly pwm forced off by us */ case 0x00000040: /* nvio special */ switch (gpio & 0x0000001f) { + case 0x00: return 2; case 0x19: return 1; case 0x1c: return 0; + case 0x1e: return 2; default: break; } @@ -56,8 +59,9 @@ nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) int indx = pwm_info(therm, line); if (indx < 0) return indx; - - nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); + else if (indx < 2) + nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); + /* nothing to do for indx == 2, it seems hardwired to PTHERM */ return 0; } @@ -67,10 +71,15 @@ nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) int indx = pwm_info(therm, line); if (indx < 0) return indx; - - if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { - *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); - *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); + else if (indx < 2) { + if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { + *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); + *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); + return 0; + } + } else if (indx == 2) { + *divs = nv_rd32(therm, 0x0200d8) & 0x1fff; + *duty = nv_rd32(therm, 0x0200dc) & 0x1fff; return 0; } @@ -83,16 +92,26 @@ nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) int indx = pwm_info(therm, line); if (indx < 0) return indx; - - nv_wr32(therm, 0x00e114 + (indx * 8), divs); - nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); + else if (indx < 2) { + nv_wr32(therm, 0x00e114 + (indx * 8), divs); + nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); + } else if (indx == 2) { + nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */ + nv_wr32(therm, 0x0200dc, duty | 0x40000000); + } return 0; } static int -nvd0_fan_pwm_clock(struct nouveau_therm *therm) +nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line) { - return (nv_device(therm)->crystal * 1000) / 20; + int indx = pwm_info(therm, line); + if (indx < 0) + return 0; + else if (indx < 2) + return (nv_device(therm)->crystal * 1000) / 20; + else + return nv_device(therm)->crystal * 1000 / 10; } static int @@ -148,6 +167,6 @@ nvd0_therm_oclass = { .ctor = nvd0_therm_ctor, .dtor = _nouveau_therm_dtor, .init = nvd0_therm_init, - .fini = _nouveau_therm_fini, + .fini = nv84_therm_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index dd38529262f..916fca5c781 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h @@ -76,6 +76,7 @@ struct nouveau_therm_priv { spinlock_t lock; struct nouveau_therm_trip_point *last_trip; int mode; + int cstate; int suspend; /* bios */ @@ -142,8 +143,9 @@ void nv40_therm_intr(struct nouveau_subdev *); int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool); 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 nv50_fan_pwm_clock(struct nouveau_therm *, int); int nv84_temp_get(struct nouveau_therm *therm); +int nv84_therm_fini(struct nouveau_object *object, bool suspend); int nva3_therm_fan_sense(struct nouveau_therm *); diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c index b80a33011b9..6212537b90c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c @@ -180,8 +180,6 @@ alarm_timer_callback(struct nouveau_alarm *alarm) spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); - nv_debug(therm, "polling the internal temperature\n"); - nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost, NOUVEAU_THERM_THRS_FANBOOST); @@ -194,11 +192,11 @@ alarm_timer_callback(struct nouveau_alarm *alarm) nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown, NOUVEAU_THERM_THRS_SHUTDOWN); + spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); + /* schedule the next poll in one second */ if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head)) - ptimer->alarm(ptimer, 1000 * 1000 * 1000, alarm); - - spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); + ptimer->alarm(ptimer, 1000000000ULL, alarm); } void diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c new file mode 100644 index 00000000000..37484db1f7f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c @@ -0,0 +1,57 @@ +/* + * 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" + +static int +gk20a_timer_init(struct nouveau_object *object) +{ + struct nv04_timer_priv *priv = (void *)object; + u32 hi = upper_32_bits(priv->suspend_time); + u32 lo = lower_32_bits(priv->suspend_time); + int ret; + + ret = nouveau_timer_init(&priv->base); + if (ret) + return ret; + + nv_debug(priv, "time low : 0x%08x\n", lo); + nv_debug(priv, "time high : 0x%08x\n", hi); + + /* restore the time before suspend */ + nv_wr32(priv, NV04_PTIMER_TIME_1, hi); + nv_wr32(priv, NV04_PTIMER_TIME_0, lo); + return 0; +} + +struct nouveau_oclass +gk20a_timer_oclass = { + .handle = NV_SUBDEV(TIMER, 0xff), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_timer_ctor, + .dtor = nv04_timer_dtor, + .init = gk20a_timer_init, + .fini = nv04_timer_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c index 57711ecb566..240ed0b983a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c @@ -22,22 +22,7 @@ * Authors: Ben Skeggs */ -#include <subdev/timer.h> - -#define NV04_PTIMER_INTR_0 0x009100 -#define NV04_PTIMER_INTR_EN_0 0x009140 -#define NV04_PTIMER_NUMERATOR 0x009200 -#define NV04_PTIMER_DENOMINATOR 0x009210 -#define NV04_PTIMER_TIME_0 0x009400 -#define NV04_PTIMER_TIME_1 0x009410 -#define NV04_PTIMER_ALARM_0 0x009420 - -struct nv04_timer_priv { - struct nouveau_timer base; - struct list_head alarms; - spinlock_t lock; - u64 suspend_time; -}; +#include "nv04.h" static u64 nv04_timer_read(struct nouveau_timer *ptimer) @@ -119,16 +104,8 @@ nv04_timer_alarm_cancel(struct nouveau_timer *ptimer, { struct nv04_timer_priv *priv = (void *)ptimer; unsigned long flags; - - /* avoid deleting an entry while the alarm intr is running */ spin_lock_irqsave(&priv->lock, flags); - - /* delete the alarm from the list */ - list_del(&alarm->head); - - /* reset the head so as list_empty returns 1 */ - INIT_LIST_HEAD(&alarm->head); - + list_del_init(&alarm->head); spin_unlock_irqrestore(&priv->lock, flags); } @@ -150,35 +127,14 @@ nv04_timer_intr(struct nouveau_subdev *subdev) } } -static int -nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv04_timer_priv *priv; - int ret; - - ret = nouveau_timer_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.base.intr = nv04_timer_intr; - priv->base.read = nv04_timer_read; - priv->base.alarm = nv04_timer_alarm; - priv->base.alarm_cancel = nv04_timer_alarm_cancel; - priv->suspend_time = 0; - - INIT_LIST_HEAD(&priv->alarms); - spin_lock_init(&priv->lock); - return 0; -} - -static void -nv04_timer_dtor(struct nouveau_object *object) +int +nv04_timer_fini(struct nouveau_object *object, bool suspend) { struct nv04_timer_priv *priv = (void *)object; - return nouveau_timer_destroy(&priv->base); + if (suspend) + priv->suspend_time = nv04_timer_read(&priv->base); + nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); + return nouveau_timer_fini(&priv->base, suspend); } static int @@ -265,14 +221,35 @@ nv04_timer_init(struct nouveau_object *object) return 0; } -static int -nv04_timer_fini(struct nouveau_object *object, bool suspend) +void +nv04_timer_dtor(struct nouveau_object *object) { struct nv04_timer_priv *priv = (void *)object; - if (suspend) - priv->suspend_time = nv04_timer_read(&priv->base); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); - return nouveau_timer_fini(&priv->base, suspend); + return nouveau_timer_destroy(&priv->base); +} + +int +nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_timer_priv *priv; + int ret; + + ret = nouveau_timer_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.base.intr = nv04_timer_intr; + priv->base.read = nv04_timer_read; + priv->base.alarm = nv04_timer_alarm; + priv->base.alarm_cancel = nv04_timer_alarm_cancel; + priv->suspend_time = 0; + + INIT_LIST_HEAD(&priv->alarms); + spin_lock_init(&priv->lock); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h new file mode 100644 index 00000000000..4bc152697c3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h @@ -0,0 +1,27 @@ +#ifndef __NVKM_TIMER_NV04_H__ +#define __NVKM_TIMER_NV04_H__ + +#include "priv.h" + +#define NV04_PTIMER_INTR_0 0x009100 +#define NV04_PTIMER_INTR_EN_0 0x009140 +#define NV04_PTIMER_NUMERATOR 0x009200 +#define NV04_PTIMER_DENOMINATOR 0x009210 +#define NV04_PTIMER_TIME_0 0x009400 +#define NV04_PTIMER_TIME_1 0x009410 +#define NV04_PTIMER_ALARM_0 0x009420 + +struct nv04_timer_priv { + struct nouveau_timer base; + struct list_head alarms; + spinlock_t lock; + u64 suspend_time; +}; + +int nv04_timer_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nv04_timer_dtor(struct nouveau_object *); +int nv04_timer_fini(struct nouveau_object *, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h new file mode 100644 index 00000000000..799dae3f230 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h @@ -0,0 +1,6 @@ +#ifndef __NVKM_TIMER_PRIV_H__ +#define __NVKM_TIMER_PRIV_H__ + +#include <subdev/timer.h> + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c index ef3133e7575..7dd680ff2f6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c @@ -72,13 +72,7 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node) vmm->flush(vm); } -void -nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node) -{ - nouveau_vm_map_at(vma, 0, node); -} - -void +static void nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length, struct nouveau_mem *mem) { @@ -136,7 +130,7 @@ finish: vmm->flush(vm); } -void +static void nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, struct nouveau_mem *mem) { @@ -175,6 +169,18 @@ nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, } void +nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node) +{ + if (node->sg) + nouveau_vm_map_sg_table(vma, 0, node->size << 12, node); + else + if (node->pages) + nouveau_vm_map_sg(vma, 0, node->size << 12, node); + else + nouveau_vm_map_at(vma, 0, node); +} + +void nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length) { struct nouveau_vm *vm = vma->vm; diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/base.c b/drivers/gpu/drm/nouveau/core/subdev/volt/base.c new file mode 100644 index 00000000000..32794a99910 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/volt/base.c @@ -0,0 +1,198 @@ +/* + * 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/volt.h> + +#include <subdev/bios.h> +#include <subdev/bios/vmap.h> +#include <subdev/bios/volt.h> + +static int +nouveau_volt_get(struct nouveau_volt *volt) +{ + if (volt->vid_get) { + int ret = volt->vid_get(volt), i; + if (ret >= 0) { + for (i = 0; i < volt->vid_nr; i++) { + if (volt->vid[i].vid == ret) + return volt->vid[i].uv; + } + ret = -EINVAL; + } + return ret; + } + return -ENODEV; +} + +static int +nouveau_volt_set(struct nouveau_volt *volt, u32 uv) +{ + if (volt->vid_set) { + int i, ret = -EINVAL; + for (i = 0; i < volt->vid_nr; i++) { + if (volt->vid[i].uv == uv) { + ret = volt->vid_set(volt, volt->vid[i].vid); + nv_debug(volt, "set %duv: %d\n", uv, ret); + break; + } + } + return ret; + } + return -ENODEV; +} + +static int +nouveau_volt_map(struct nouveau_volt *volt, u8 id) +{ + struct nouveau_bios *bios = nouveau_bios(volt); + struct nvbios_vmap_entry info; + u8 ver, len; + u16 vmap; + + vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info); + if (vmap) { + if (info.link != 0xff) { + int ret = nouveau_volt_map(volt, info.link); + if (ret < 0) + return ret; + info.min += ret; + } + return info.min; + } + + return id ? id * 10000 : -ENODEV; +} + +static int +nouveau_volt_set_id(struct nouveau_volt *volt, u8 id, int condition) +{ + int ret = nouveau_volt_map(volt, id); + if (ret >= 0) { + int prev = nouveau_volt_get(volt); + if (!condition || prev < 0 || + (condition < 0 && ret < prev) || + (condition > 0 && ret > prev)) { + ret = nouveau_volt_set(volt, ret); + } else { + ret = 0; + } + } + return ret; +} + +int +_nouveau_volt_init(struct nouveau_object *object) +{ + struct nouveau_volt *volt = (void *)object; + int ret; + + ret = nouveau_subdev_init(&volt->base); + if (ret) + return ret; + + ret = volt->get(volt); + if (ret < 0) { + if (ret != -ENODEV) + nv_debug(volt, "current voltage unknown\n"); + return 0; + } + + nv_info(volt, "GPU voltage: %duv\n", ret); + return 0; +} + +void +_nouveau_volt_dtor(struct nouveau_object *object) +{ + struct nouveau_volt *volt = (void *)object; + nouveau_subdev_destroy(&volt->base); +} + +int +nouveau_volt_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int length, void **pobject) +{ + struct nouveau_bios *bios = nouveau_bios(parent); + struct nouveau_volt *volt; + struct nvbios_volt_entry ivid; + struct nvbios_volt info; + u8 ver, hdr, cnt, len; + u16 data; + int ret, i; + + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT", + "voltage", length, pobject); + volt = *pobject; + if (ret) + return ret; + + volt->get = nouveau_volt_get; + volt->set = nouveau_volt_set; + volt->set_id = nouveau_volt_set_id; + + data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info); + if (data && info.vidmask && info.base && info.step) { + for (i = 0; i < info.vidmask + 1; i++) { + if (info.base >= info.min && + info.base <= info.max) { + volt->vid[volt->vid_nr].uv = info.base; + volt->vid[volt->vid_nr].vid = i; + volt->vid_nr++; + } + info.base += info.step; + } + volt->vid_mask = info.vidmask; + } else + if (data && info.vidmask) { + for (i = 0; i < cnt; i++) { + data = nvbios_volt_entry_parse(bios, i, &ver, &hdr, + &ivid); + if (data) { + volt->vid[volt->vid_nr].uv = ivid.voltage; + volt->vid[volt->vid_nr].vid = ivid.vid; + volt->vid_nr++; + } + } + volt->vid_mask = info.vidmask; + } + + if (volt->vid_nr) { + for (i = 0; i < volt->vid_nr; i++) { + nv_debug(volt, "VID %02x: %duv\n", + volt->vid[i].vid, volt->vid[i].uv); + } + + /*XXX: this is an assumption.. there probably exists boards + * out there with i2c-connected voltage controllers too.. + */ + ret = nouveau_voltgpio_init(volt); + if (ret == 0) { + volt->vid_get = nouveau_voltgpio_get; + volt->vid_set = nouveau_voltgpio_set; + } + } + + return ret; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c new file mode 100644 index 00000000000..755fa91bcd0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c @@ -0,0 +1,96 @@ +/* + * 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/volt.h> +#include <subdev/gpio.h> +#include <subdev/bios/gpio.h> + +static const u8 tags[] = { + DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3, + DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7, +}; + +int +nouveau_voltgpio_get(struct nouveau_volt *volt) +{ + struct nouveau_gpio *gpio = nouveau_gpio(volt); + u8 vid = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tags); i++) { + if (volt->vid_mask & (1 << i)) { + int ret = gpio->get(gpio, 0, tags[i], 0xff); + if (ret < 0) + return ret; + vid |= ret << i; + } + } + + return vid; +} + +int +nouveau_voltgpio_set(struct nouveau_volt *volt, u8 vid) +{ + struct nouveau_gpio *gpio = nouveau_gpio(volt); + int i; + + for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) { + if (volt->vid_mask & (1 << i)) { + int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int +nouveau_voltgpio_init(struct nouveau_volt *volt) +{ + struct nouveau_gpio *gpio = nouveau_gpio(volt); + struct dcb_gpio_func func; + int i; + + /* check we have gpio function info for each vid bit. on some + * boards (ie. nvs295) the vid mask has more bits than there + * are valid gpio functions... from traces, nvidia appear to + * just touch the existing ones, so let's mask off the invalid + * bits and continue with life + */ + for (i = 0; i < ARRAY_SIZE(tags); i++) { + if (volt->vid_mask & (1 << i)) { + int ret = gpio->find(gpio, 0, tags[i], 0xff, &func); + if (ret) { + if (ret != -ENOENT) + return ret; + nv_debug(volt, "VID bit %d has no GPIO\n", i); + volt->vid_mask &= ~(1 << i); + } + } + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c new file mode 100644 index 00000000000..87d5358376a --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c @@ -0,0 +1,56 @@ +/* + * 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/volt.h> + +struct nv40_volt_priv { + struct nouveau_volt base; +}; + +static int +nv40_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv40_volt_priv *priv; + int ret; + + ret = nouveau_volt_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass +nv40_volt_oclass = { + .handle = NV_SUBDEV(VOLT, 0x40), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_volt_ctor, + .dtor = _nouveau_volt_dtor, + .init = _nouveau_volt_init, + .fini = _nouveau_volt_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/dispnv04/Makefile b/drivers/gpu/drm/nouveau/dispnv04/Makefile index ea3f5b8a0f9..424a489d0f0 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/Makefile +++ b/drivers/gpu/drm/nouveau/dispnv04/Makefile @@ -5,6 +5,7 @@ nouveau-y += dispnv04/dac.o nouveau-y += dispnv04/dfp.o nouveau-y += dispnv04/disp.o nouveau-y += dispnv04/hw.o +nouveau-y += dispnv04/overlay.o nouveau-y += dispnv04/tvmodesnv17.o nouveau-y += dispnv04/tvnv04.o nouveau-y += dispnv04/tvnv17.o diff --git a/drivers/gpu/drm/nouveau/dispnv04/arb.c b/drivers/gpu/drm/nouveau/dispnv04/arb.c index 2e70462883e..2a15b98b4d2 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/arb.c +++ b/drivers/gpu/drm/nouveau/dispnv04/arb.c @@ -210,8 +210,8 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, sim_data.nvclk_khz = NVClk; sim_data.bpp = bpp; sim_data.two_heads = nv_two_heads(dev); - if ((dev->pci_device & 0xffff) == 0x01a0 /*CHIPSET_NFORCE*/ || - (dev->pci_device & 0xffff) == 0x01f0 /*CHIPSET_NFORCE2*/) { + if ((dev->pdev->device & 0xffff) == 0x01a0 /*CHIPSET_NFORCE*/ || + (dev->pdev->device & 0xffff) == 0x01f0 /*CHIPSET_NFORCE2*/) { uint32_t type; pci_read_config_dword(pci_get_bus_and_slot(0, 1), 0x7c, &type); @@ -256,8 +256,8 @@ nouveau_calc_arb(struct drm_device *dev, int vclk, int bpp, int *burst, int *lwm if (nv_device(drm->device)->card_type < NV_20) nv04_update_arb(dev, vclk, bpp, burst, lwm); - else if ((dev->pci_device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ || - (dev->pci_device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) { + else if ((dev->pdev->device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ || + (dev->pdev->device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) { *burst = 128; *lwm = 0x0480; } else diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index d4fbf11360f..41be3424c90 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -239,7 +239,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) struct drm_device *dev = crtc->dev; struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; /* Calculate our timings */ int horizDisplay = (mode->crtc_hdisplay >> 3) - 1; @@ -326,8 +326,6 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) regp->MiscOutReg = 0x23; /* +hsync +vsync */ } - regp->MiscOutReg |= (mode->clock_index & 0x03) << 2; - /* * Time Sequencer */ @@ -576,7 +574,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) regp->CRTC[NV_CIO_CRE_86] = 0x1; } - regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->fb->depth + 1) / 8; + regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->primary->fb->depth + 1) / 8; /* Enable slaved mode (called MODE_TV in nv4ref.h) */ if (lvds_output || tmds_output || tv_output) regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7); @@ -590,7 +588,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS | NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL | NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON; - if (crtc->fb->depth == 16) + if (crtc->primary->fb->depth == 16) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; if (nv_device(drm->device)->chipset >= 0x11) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG; @@ -611,7 +609,7 @@ static int nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { struct nv04_display *disp = nv04_display(crtc->dev); - struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); + struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); int ret; @@ -810,7 +808,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, * mark the lut values as dirty by setting depth==0, and it'll be * uploaded on the first mode_set_base() */ - if (!nv_crtc->base.fb) { + if (!nv_crtc->base.primary->fb) { nv_crtc->lut.depth = 0; return; } @@ -834,7 +832,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, NV_DEBUG(drm, "index %d\n", nv_crtc->index); /* no fb bound */ - if (!atomic && !crtc->fb) { + if (!atomic && !crtc->primary->fb) { NV_DEBUG(drm, "No FB bound\n"); return 0; } @@ -846,8 +844,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, drm_fb = passed_fb; fb = nouveau_framebuffer(passed_fb); } else { - drm_fb = crtc->fb; - fb = nouveau_framebuffer(crtc->fb); + drm_fb = crtc->primary->fb; + fb = nouveau_framebuffer(crtc->primary->fb); } nv_crtc->fb.offset = fb->nvbo->bo.offset; @@ -859,9 +857,9 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, /* Update the framebuffer format. */ regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3; - regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8; + regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->primary->fb->depth + 1) / 8; regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; - if (crtc->fb->depth == 16) + if (crtc->primary->fb->depth == 16) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX); NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL, @@ -1050,7 +1048,7 @@ nouveau_crtc_set_config(struct drm_mode_set *set) /* get a pm reference here */ ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return ret; ret = drm_crtc_helper_set_config(set); diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index 434b920f6bd..a96dda48718 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -414,7 +414,7 @@ static void nv04_dac_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), + nouveau_encoder_connector_get(nv_encoder)->base.name, nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 93dd23ff009..e57babb206d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -415,7 +415,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, /* Output property. */ if ((nv_connector->dithering_mode == DITHERING_MODE_ON) || (nv_connector->dithering_mode == DITHERING_MODE_AUTO && - encoder->crtc->fb->depth > connector->display_info.bpc * 3)) { + encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) { if (nv_device(drm->device)->chipset == 0x11) regp->dither = savep->dither | 0x00010000; else { @@ -477,7 +477,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), + nouveau_encoder_connector_get(nv_encoder)->base.name, nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } @@ -490,10 +490,10 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) /* BIOS scripts usually take care of the backlight, thanks * Apple for your consistency. */ - if (dev->pci_device == 0x0174 || dev->pci_device == 0x0179 || - dev->pci_device == 0x0189 || dev->pci_device == 0x0329) { + if (dev->pdev->device == 0x0174 || dev->pdev->device == 0x0179 || + dev->pdev->device == 0x0189 || dev->pdev->device == 0x0329) { if (mode == DRM_MODE_DPMS_ON) { - nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31); + nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 1 << 31); nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 1); } else { nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0); @@ -625,13 +625,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_i2c *i2c = nouveau_i2c(drm->device); struct nouveau_i2c_port *port = i2c->find(i2c, 2); - struct i2c_board_info info[] = { + struct nouveau_i2c_board_info info[] = { { - .type = "sil164", - .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), - .platform_data = &(struct sil164_encoder_params) { - SIL164_INPUT_EDGE_RISING - } + { + .type = "sil164", + .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), + .platform_data = &(struct sil164_encoder_params) { + SIL164_INPUT_EDGE_RISING + } + }, 0 }, { } }; @@ -641,12 +643,12 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) get_tmds_slave(encoder)) return; - type = i2c->identify(i2c, 2, "TMDS transmitter", info, NULL); + type = i2c->identify(i2c, 2, "TMDS transmitter", info, NULL, NULL); if (type < 0) return; drm_i2c_encoder_init(dev, to_encoder_slave(encoder), - &port->adapter, &info[type]); + &port->adapter, &info[type].dev); } static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index 4908d3fd048..4342fdaee70 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -77,11 +77,6 @@ nv04_display_create(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 1); - ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, 0xd1500000, - NV04_DISP_CLASS, NULL, 0, &disp->core); - if (ret) - return ret; - nv04_crtc_create(dev, 0); if (nv_two_heads(dev)) nv04_crtc_create(dev, 1); @@ -120,7 +115,7 @@ nv04_display_create(struct drm_device *dev) &dev->mode_config.connector_list, head) { if (!connector->encoder_ids[0]) { NV_WARN(drm, "%s has no encoders, removing\n", - drm_get_connector_name(connector)); + connector->name); connector->funcs->destroy(connector); } } @@ -140,6 +135,8 @@ nv04_display_create(struct drm_device *dev) func->save(encoder); } + nouveau_overlay_init(dev); + return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h index 9928187f0a7..4245fc3dab7 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h @@ -80,7 +80,6 @@ struct nv04_display { struct nv04_mode_state saved_reg; uint32_t saved_vga_font[4][16384]; uint32_t dac_users[4]; - struct nouveau_object *core; struct nouveau_bo *image[2]; }; @@ -123,11 +122,14 @@ int nv04_tv_create(struct drm_connector *, struct dcb_output *); /* nv17_tv.c */ int nv17_tv_create(struct drm_connector *, struct dcb_output *); +/* overlay.c */ +void nouveau_overlay_init(struct drm_device *dev); + static inline bool nv_two_heads(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - const int impl = dev->pci_device & 0x0ff0; + const int impl = dev->pdev->device & 0x0ff0; if (nv_device(drm->device)->card_type >= NV_10 && impl != 0x0100 && impl != 0x0150 && impl != 0x01a0 && impl != 0x0200) @@ -139,14 +141,14 @@ nv_two_heads(struct drm_device *dev) static inline bool nv_gf4_disp_arch(struct drm_device *dev) { - return nv_two_heads(dev) && (dev->pci_device & 0x0ff0) != 0x0110; + return nv_two_heads(dev) && (dev->pdev->device & 0x0ff0) != 0x0110; } static inline bool nv_two_reg_pll(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - const int impl = dev->pci_device & 0x0ff0; + const int impl = dev->pdev->device & 0x0ff0; if (impl == 0x0310 || impl == 0x0340 || nv_device(drm->device)->card_type >= NV_40) return true; diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c index 973056b8620..aca76af115b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.c +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c @@ -27,6 +27,7 @@ #include "hw.h" #include <subdev/bios/pll.h> +#include <subdev/fb.h> #include <subdev/clock.h> #include <subdev/timer.h> @@ -220,7 +221,7 @@ nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype) int ret; if (plltype == PLL_MEMORY && - (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) { + (dev->pdev->device & 0x0ff0) == CHIPSET_NFORCE) { uint32_t mpllP; pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP); @@ -230,7 +231,7 @@ nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype) return 400000 / mpllP; } else if (plltype == PLL_MEMORY && - (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) { + (dev->pdev->device & 0xff0) == CHIPSET_NFORCE2) { uint32_t clock; pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock); @@ -664,6 +665,7 @@ nv_load_state_ext(struct drm_device *dev, int head, 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 nv04_crtc_reg *regp = &state->crtc_reg[head]; uint32_t reg900; int i; @@ -680,10 +682,10 @@ nv_load_state_ext(struct drm_device *dev, int head, 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), 0); //drm->fb_available_size - 1); - nv_wr32(device, NV_PVIDEO_LIMIT(1), 0); //drm->fb_available_size - 1); - nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), 0); //drm->fb_available_size - 1); - nv_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), 0); //drm->fb_available_size - 1); + 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); NVWriteCRTC(dev, head, NV_PCRTC_CURSOR_CONFIG, regp->cursor_cfg); @@ -740,7 +742,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_10) { + if (nv_device(drm->device)->card_type < NV_20) { /* 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); diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c new file mode 100644 index 00000000000..ab03f7719d2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -0,0 +1,497 @@ +/* + * Copyright 2013 Ilia Mirkin + * + * 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 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. + * + * Implementation based on the pre-KMS implementation in xf86-video-nouveau, + * written by Arthur Huillet. + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> + +#include "nouveau_drm.h" + +#include "nouveau_bo.h" +#include "nouveau_connector.h" +#include "nouveau_display.h" +#include "nvreg.h" + + +struct nouveau_plane { + struct drm_plane base; + bool flip; + struct nouveau_bo *cur; + + struct { + struct drm_property *colorkey; + struct drm_property *contrast; + struct drm_property *brightness; + struct drm_property *hue; + struct drm_property *saturation; + struct drm_property *iturbt_709; + } props; + + int colorkey; + int contrast; + int brightness; + int hue; + int saturation; + int iturbt_709; + + void (*set_params)(struct nouveau_plane *); +}; + +static uint32_t formats[] = { + DRM_FORMAT_YUYV, + DRM_FORMAT_UYVY, + DRM_FORMAT_NV12, +}; + +/* Sine can be approximated with + * http://en.wikipedia.org/wiki/Bhaskara_I's_sine_approximation_formula + * sin(x degrees) ~= 4 x (180 - x) / (40500 - x (180 - x) ) + * Note that this only works for the range [0, 180]. + * Also note that sin(x) == -sin(x - 180) + */ +static inline int +sin_mul(int degrees, int factor) +{ + if (degrees > 180) { + degrees -= 180; + factor *= -1; + } + return factor * 4 * degrees * (180 - degrees) / + (40500 - degrees * (180 - degrees)); +} + +/* cos(x) = sin(x + 90) */ +static inline int +cos_mul(int degrees, int factor) +{ + return sin_mul((degrees + 90) % 360, factor); +} + +static int +nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + 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 nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct nouveau_bo *cur = nv_plane->cur; + bool flip = nv_plane->flip; + int soff = NV_PCRTC0_SIZE * nv_crtc->index; + int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index; + int format, ret; + + /* Source parameters given in 16.16 fixed point, ignore fractional. */ + src_x >>= 16; + src_y >>= 16; + src_w >>= 16; + src_h >>= 16; + + format = ALIGN(src_w * 4, 0x100); + + if (format > 0xffff) + return -ERANGE; + + if (dev->chipset >= 0x30) { + if (crtc_w < (src_w >> 1) || crtc_h < (src_h >> 1)) + return -ERANGE; + } else { + if (crtc_w < (src_w >> 3) || crtc_h < (src_h >> 3)) + return -ERANGE; + } + + ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM); + if (ret) + return ret; + + 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); + + 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); + + if (fb->pixel_format != DRM_FORMAT_UYVY) + format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8; + if (fb->pixel_format == DRM_FORMAT_NV12) + format |= NV_PVIDEO_FORMAT_PLANAR; + if (nv_plane->iturbt_709) + format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709; + if (nv_plane->colorkey & (1 << 24)) + 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), + nv_fb->nvbo->bo.offset + fb->offsets[1]); + } + nv_wr32(dev, NV_PVIDEO_FORMAT(flip), format); + nv_wr32(dev, NV_PVIDEO_STOP, 0); + /* TODO: wait for vblank? */ + nv_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1); + nv_plane->flip = !flip; + + if (cur) + nouveau_bo_unpin(cur); + + return 0; +} + +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; + + nv_wr32(dev, NV_PVIDEO_STOP, 1); + if (nv_plane->cur) { + nouveau_bo_unpin(nv_plane->cur); + nv_plane->cur = NULL; + } + + return 0; +} + +static void +nv_destroy_plane(struct drm_plane *plane) +{ + plane->funcs->disable_plane(plane); + drm_plane_cleanup(plane); + kfree(plane); +} + +static void +nv10_set_params(struct nouveau_plane *plane) +{ + struct nouveau_device *dev = nouveau_dev(plane->base.dev); + 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); + + 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), + NV_PVIDEO_FORMAT_MATRIX_ITURBT709 | + NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY, + format); + } +} + +static int +nv_set_property(struct drm_plane *plane, + struct drm_property *property, + uint64_t value) +{ + struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane; + + if (property == nv_plane->props.colorkey) + nv_plane->colorkey = value; + else if (property == nv_plane->props.contrast) + nv_plane->contrast = value; + else if (property == nv_plane->props.brightness) + nv_plane->brightness = value; + else if (property == nv_plane->props.hue) + nv_plane->hue = value; + else if (property == nv_plane->props.saturation) + nv_plane->saturation = value; + else if (property == nv_plane->props.iturbt_709) + nv_plane->iturbt_709 = value; + else + return -EINVAL; + + if (nv_plane->set_params) + nv_plane->set_params(nv_plane); + return 0; +} + +static const struct drm_plane_funcs nv10_plane_funcs = { + .update_plane = nv10_update_plane, + .disable_plane = nv10_disable_plane, + .set_property = nv_set_property, + .destroy = nv_destroy_plane, +}; + +static void +nv10_overlay_init(struct drm_device *device) +{ + struct nouveau_device *dev = nouveau_dev(device); + struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); + int num_formats = ARRAY_SIZE(formats); + int ret; + + if (!plane) + return; + + switch (dev->chipset) { + case 0x10: + case 0x11: + case 0x15: + case 0x1a: + case 0x20: + num_formats = 2; + break; + } + + ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */, + &nv10_plane_funcs, + formats, num_formats, false); + if (ret) + goto err; + + /* Set up the plane properties */ + plane->props.colorkey = drm_property_create_range( + device, 0, "colorkey", 0, 0x01ffffff); + plane->props.contrast = drm_property_create_range( + device, 0, "contrast", 0, 8192 - 1); + plane->props.brightness = drm_property_create_range( + device, 0, "brightness", 0, 1024); + plane->props.hue = drm_property_create_range( + device, 0, "hue", 0, 359); + plane->props.saturation = drm_property_create_range( + device, 0, "saturation", 0, 8192 - 1); + plane->props.iturbt_709 = drm_property_create_range( + device, 0, "iturbt_709", 0, 1); + if (!plane->props.colorkey || + !plane->props.contrast || + !plane->props.brightness || + !plane->props.hue || + !plane->props.saturation || + !plane->props.iturbt_709) + goto cleanup; + + plane->colorkey = 0; + drm_object_attach_property(&plane->base.base, + plane->props.colorkey, plane->colorkey); + + plane->contrast = 0x1000; + drm_object_attach_property(&plane->base.base, + plane->props.contrast, plane->contrast); + + plane->brightness = 512; + drm_object_attach_property(&plane->base.base, + plane->props.brightness, plane->brightness); + + plane->hue = 0; + drm_object_attach_property(&plane->base.base, + plane->props.hue, plane->hue); + + plane->saturation = 0x1000; + drm_object_attach_property(&plane->base.base, + plane->props.saturation, plane->saturation); + + plane->iturbt_709 = 0; + drm_object_attach_property(&plane->base.base, + plane->props.iturbt_709, plane->iturbt_709); + + plane->set_params = nv10_set_params; + nv10_set_params(plane); + nv10_disable_plane(&plane->base); + return; +cleanup: + drm_plane_cleanup(&plane->base); +err: + kfree(plane); + nv_error(dev, "Failed to create plane\n"); +} + +static int +nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + 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 nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); + struct nouveau_bo *cur = nv_plane->cur; + uint32_t overlay = 1; + int brightness = (nv_plane->brightness - 512) * 62 / 512; + int pitch, ret, i; + + /* Source parameters given in 16.16 fixed point, ignore fractional. */ + src_x >>= 16; + src_y >>= 16; + src_w >>= 16; + src_h >>= 16; + + pitch = ALIGN(src_w * 4, 0x100); + + if (pitch > 0xffff) + return -ERANGE; + + /* TODO: Compute an offset? Not sure how to do this for YUYV. */ + if (src_x != 0 || src_y != 0) + return -ERANGE; + + if (crtc_w < src_w || crtc_h < src_h) + return -ERANGE; + + ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM); + if (ret) + return ret; + + 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); + + for (i = 0; i < 2; i++) { + nv_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); + } + 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, + (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); + + 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) */ + + nv_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03); + nv_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38); + + nv_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); + + nv_wr32(dev, NV_PVIDEO_SU_STATE, nv_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16)); + + if (cur) + nouveau_bo_unpin(cur); + + return 0; +} + +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); + if (nv_plane->cur) { + nouveau_bo_unpin(nv_plane->cur); + nv_plane->cur = NULL; + } + + return 0; +} + +static const struct drm_plane_funcs nv04_plane_funcs = { + .update_plane = nv04_update_plane, + .disable_plane = nv04_disable_plane, + .set_property = nv_set_property, + .destroy = nv_destroy_plane, +}; + +static void +nv04_overlay_init(struct drm_device *device) +{ + struct nouveau_device *dev = nouveau_dev(device); + struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); + int ret; + + if (!plane) + return; + + ret = drm_plane_init(device, &plane->base, 1 /* single crtc */, + &nv04_plane_funcs, + formats, 2, false); + if (ret) + goto err; + + /* Set up the plane properties */ + plane->props.colorkey = drm_property_create_range( + device, 0, "colorkey", 0, 0x01ffffff); + plane->props.brightness = drm_property_create_range( + device, 0, "brightness", 0, 1024); + if (!plane->props.colorkey || + !plane->props.brightness) + goto cleanup; + + plane->colorkey = 0; + drm_object_attach_property(&plane->base.base, + plane->props.colorkey, plane->colorkey); + + plane->brightness = 512; + drm_object_attach_property(&plane->base.base, + plane->props.brightness, plane->brightness); + + nv04_disable_plane(&plane->base); + return; +cleanup: + drm_plane_cleanup(&plane->base); +err: + kfree(plane); + nv_error(dev, "Failed to create plane\n"); +} + +void +nouveau_overlay_init(struct drm_device *device) +{ + struct nouveau_device *dev = nouveau_dev(device); + if (dev->chipset < 0x10) + nv04_overlay_init(device); + else if (dev->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 bf13db4e863..8667620b703 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c @@ -37,15 +37,18 @@ #include <subdev/i2c.h> -static struct i2c_board_info nv04_tv_encoder_info[] = { +static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = { { - I2C_BOARD_INFO("ch7006", 0x75), - .platform_data = &(struct ch7006_encoder_params) { - CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, - 0, 0, 0, - CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, - CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC - } + { + I2C_BOARD_INFO("ch7006", 0x75), + .platform_data = &(struct ch7006_encoder_params) { + CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, + 0, 0, 0, + CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, + CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC + } + }, + 0 }, { } }; @@ -56,7 +59,7 @@ int nv04_tv_identify(struct drm_device *dev, int i2c_index) struct nouveau_i2c *i2c = nouveau_i2c(drm->device); return i2c->identify(i2c, i2c_index, "TV encoder", - nv04_tv_encoder_info, NULL); + nv04_tv_encoder_info, NULL, NULL); } @@ -168,7 +171,8 @@ static void nv04_tv_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); + nouveau_encoder_connector_get(nv_encoder)->base.name, + nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } static void nv04_tv_destroy(struct drm_encoder *encoder) @@ -229,7 +233,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) /* Run the slave-specific initialization */ ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), - &port->adapter, &nv04_tv_encoder_info[type]); + &port->adapter, + &nv04_tv_encoder_info[type].dev); if (ret < 0) goto fail_cleanup; diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index acef48f4a4e..195bd8e86c6 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -612,8 +612,7 @@ static void nv17_tv_commit(struct drm_encoder *encoder) helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name( - &nouveau_encoder_connector_get(nv_encoder)->base), + nouveau_encoder_connector_get(nv_encoder)->base.name, nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 8f467e7bfd1..b13f441c643 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -87,6 +87,7 @@ nouveau_abi16_swclass(struct nouveau_drm *drm) case NV_04: return 0x006e; case NV_10: + case NV_11: case NV_20: case NV_30: case NV_40: @@ -96,6 +97,7 @@ nouveau_abi16_swclass(struct nouveau_drm *drm) case NV_C0: case NV_D0: case NV_E0: + case GM100: return 0x906e; } @@ -130,7 +132,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, if (chan->ntfy) { nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma); nouveau_bo_unpin(chan->ntfy); - drm_gem_object_unreference_unlocked(chan->ntfy->gem); + drm_gem_object_unreference_unlocked(&chan->ntfy->gem); } if (chan->heap.block_size) @@ -138,7 +140,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, /* destroy channel object, all children will be killed too */ if (chan->chan) { - abi16->handles &= ~(1 << (chan->chan->handle & 0xffff)); + abi16->handles &= ~(1ULL << (chan->chan->handle & 0xffff)); nouveau_channel_del(&chan->chan); } @@ -178,12 +180,21 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = device->chipset; break; case NOUVEAU_GETPARAM_PCI_VENDOR: - getparam->value = dev->pci_vendor; + if (nv_device_is_pci(device)) + getparam->value = dev->pdev->vendor; + else + getparam->value = 0; break; case NOUVEAU_GETPARAM_PCI_DEVICE: - getparam->value = dev->pci_device; + if (nv_device_is_pci(device)) + getparam->value = dev->pdev->device; + else + getparam->value = 0; break; case NOUVEAU_GETPARAM_BUS_TYPE: + if (!nv_device_is_pci(device)) + getparam->value = 3; + else if (drm_pci_device_is_agp(dev)) getparam->value = 0; else @@ -269,8 +280,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) return nouveau_abi16_put(abi16, -EINVAL); /* allocate "abi16 channel" data and make up a handle for it */ - init->channel = ffsll(~abi16->handles); - if (!init->channel--) + init->channel = __ffs64(~abi16->handles); + if (~abi16->handles == 0) return nouveau_abi16_put(abi16, -ENOSPC); chan = kzalloc(sizeof(*chan), GFP_KERNEL); @@ -279,7 +290,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) INIT_LIST_HEAD(&chan->notifiers); list_add(&chan->head, &abi16->channels); - abi16->handles |= (1 << init->channel); + abi16->handles |= (1ULL << init->channel); /* create channel object and initialise dma and fence management */ ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN | @@ -297,7 +308,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) else init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; - if (device->card_type < NV_C0) { + if (device->card_type < NV_10) { init->subchan[0].handle = 0x00000000; init->subchan[0].grclass = 0x0000; init->subchan[1].handle = NvSw; @@ -320,7 +331,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) goto done; } - ret = drm_gem_handle_create(file_priv, chan->ntfy->gem, + ret = drm_gem_handle_create(file_priv, &chan->ntfy->gem, &init->notifier_handle); if (ret) goto done; @@ -446,6 +457,8 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; + info->offset = ntfy->node->offset; + done: if (ret) nouveau_abi16_ntfy_fini(chan, ntfy); diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index dd7d2e18271..279206997e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -1,15 +1,10 @@ #include <linux/pci.h> #include <linux/acpi.h> #include <linux/slab.h> -#include <acpi/acpi_drivers.h> -#include <acpi/acpi_bus.h> -#include <acpi/video.h> -#include <acpi/acpi.h> #include <linux/mxm-wmi.h> - #include <linux/vga_switcheroo.h> - #include <drm/drm_edid.h> +#include <acpi/video.h> #include "nouveau_drm.h" #include "nouveau_acpi.h" @@ -51,6 +46,7 @@ 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; @@ -65,6 +61,7 @@ bool nouveau_is_v1_dsm(void) { #define NOUVEAU_DSM_HAS_MUX 0x1 #define NOUVEAU_DSM_HAS_OPT 0x2 +#ifdef CONFIG_VGA_SWITCHEROO static const char nouveau_dsm_muid[] = { 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, @@ -77,124 +74,89 @@ static const char nouveau_op_dsm_muid[] = { static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) { - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_object_list input; - union acpi_object params[4]; + int i; union acpi_object *obj; - int i, err; char args_buff[4]; + union acpi_object argv4 = { + .buffer.type = ACPI_TYPE_BUFFER, + .buffer.length = 4, + .buffer.pointer = args_buff + }; - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(nouveau_op_dsm_muid); - params[0].buffer.pointer = (char *)nouveau_op_dsm_muid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 0x00000100; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_BUFFER; - params[3].buffer.length = 4; /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ for (i = 0; i < 4; i++) args_buff[i] = (arg >> i * 8) & 0xFF; - params[3].buffer.pointer = args_buff; - - err = acpi_evaluate_object(handle, "_DSM", &input, &output); - if (err) { - printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); - return err; - } - obj = (union acpi_object *)output.pointer; - - if (obj->type == ACPI_TYPE_INTEGER) - if (obj->integer.value == 0x80000002) { - return -ENODEV; - } - - if (obj->type == ACPI_TYPE_BUFFER) { - if (obj->buffer.length == 4 && result) { - *result = 0; + *result = 0; + obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100, + func, &argv4, ACPI_TYPE_BUFFER); + if (!obj) { + acpi_handle_info(handle, "failed to evaluate _DSM\n"); + return AE_ERROR; + } else { + if (obj->buffer.length == 4) { *result |= obj->buffer.pointer[0]; *result |= (obj->buffer.pointer[1] << 8); *result |= (obj->buffer.pointer[2] << 16); *result |= (obj->buffer.pointer[3] << 24); } + ACPI_FREE(obj); } - kfree(output.pointer); return 0; } -static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) +/* + * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special + * requirements on the fourth parameter, so a private implementation + * instead of using acpi_check_dsm(). + */ +static int nouveau_check_optimus_dsm(acpi_handle handle) { - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_object_list input; - union acpi_object params[4]; - union acpi_object *obj; - int err; - - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(nouveau_dsm_muid); - params[0].buffer.pointer = (char *)nouveau_dsm_muid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 0x00000102; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_INTEGER; - params[3].integer.value = arg; - - err = acpi_evaluate_object(handle, "_DSM", &input, &output); - if (err) { - printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); - return err; - } + int result; - obj = (union acpi_object *)output.pointer; - - if (obj->type == ACPI_TYPE_INTEGER) - if (obj->integer.value == 0x80000002) - return -ENODEV; - - if (obj->type == ACPI_TYPE_BUFFER) { - if (obj->buffer.length == 4 && result) { - *result = 0; - *result |= obj->buffer.pointer[0]; - *result |= (obj->buffer.pointer[1] << 8); - *result |= (obj->buffer.pointer[2] << 16); - *result |= (obj->buffer.pointer[3] << 24); - } - } + /* + * Function 0 returns a Buffer containing available functions. + * The args parameter is ignored for function 0, so just put 0 in it + */ + if (nouveau_optimus_dsm(handle, 0, 0, &result)) + return 0; - kfree(output.pointer); - return 0; + /* + * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. + * If the n-th bit is enabled, function n is supported + */ + return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS); } -/* Returns 1 if a DSM function is usable and 0 otherwise */ -static int nouveau_test_dsm(acpi_handle test_handle, - int (*dsm_func)(acpi_handle, int, int, uint32_t *), - int sfnc) +static int nouveau_dsm(acpi_handle handle, int func, int arg) { - u32 result = 0; - - /* Function 0 returns a Buffer containing available functions. The args - * parameter is ignored for function 0, so just put 0 in it */ - if (dsm_func(test_handle, 0, 0, &result)) - return 0; + int ret = 0; + union acpi_object *obj; + union acpi_object argv4 = { + .integer.type = ACPI_TYPE_INTEGER, + .integer.value = arg, + }; + + obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102, + func, &argv4, ACPI_TYPE_INTEGER); + if (!obj) { + acpi_handle_info(handle, "failed to evaluate _DSM\n"); + return AE_ERROR; + } else { + if (obj->integer.value == 0x80000002) + ret = -ENODEV; + ACPI_FREE(obj); + } - /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If - * the n-th bit is enabled, function n is supported */ - return result & 1 && result & (1 << sfnc); + return ret; } static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) { mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); - return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL); + return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id); } static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) @@ -204,7 +166,7 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero arg = NOUVEAU_DSM_POWER_SPEED; else arg = NOUVEAU_DSM_POWER_STAMINA; - nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL); + nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg); return 0; } @@ -253,24 +215,22 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = { static int nouveau_dsm_pci_probe(struct pci_dev *pdev) { - acpi_handle dhandle, nvidia_handle; - acpi_status status; + acpi_handle dhandle; int retval = 0; - dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); + dhandle = ACPI_HANDLE(&pdev->dev); if (!dhandle) return false; - status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(dhandle, "_DSM")) { + nouveau_dsm_priv.other_handle = dhandle; return false; } - - if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) + if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102, + 1 << NOUVEAU_DSM_POWER)) retval |= NOUVEAU_DSM_HAS_MUX; - if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, - NOUVEAU_DSM_OPTIMUS_CAPS)) + if (nouveau_check_optimus_dsm(dhandle)) retval |= NOUVEAU_DSM_HAS_OPT; if (retval & NOUVEAU_DSM_HAS_OPT) { @@ -317,6 +277,16 @@ static bool nouveau_dsm_detect(void) has_optimus = 1; } + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) { + vga_count++; + + retval = nouveau_dsm_pci_probe(pdev); + if (retval & NOUVEAU_DSM_HAS_MUX) + has_dsm |= 1; + if (retval & NOUVEAU_DSM_HAS_OPT) + has_optimus = 1; + } + /* find the optimus DSM or the old v1 DSM */ if (has_optimus == 1) { acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, @@ -331,6 +301,16 @@ 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; } @@ -369,6 +349,11 @@ void nouveau_unregister_dsm_handler(void) if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected) vga_switcheroo_unregister_handler(); } +#else +void nouveau_register_dsm_handler(void) {} +void nouveau_unregister_dsm_handler(void) {} +void nouveau_switcheroo_optimus_dsm(void) {} +#endif /* retrieve the ROM in 4k blocks */ static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, @@ -404,10 +389,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev) acpi_status status; acpi_handle dhandle, rom_handle; - if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected) - return false; - - dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); + dhandle = ACPI_HANDLE(&pdev->dev); if (!dhandle) return false; @@ -441,7 +423,7 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) return NULL; } - handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); + handle = ACPI_HANDLE(&dev->pdev->dev); if (!handle) return NULL; diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c index 6e7a55f93a8..51666daddb9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_agp.c +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c @@ -11,10 +11,28 @@ MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); static int nouveau_agpmode = -1; module_param_named(agpmode, nouveau_agpmode, int, 0400); +struct nouveau_agpmode_quirk { + u16 hostbridge_vendor; + u16 hostbridge_device; + u16 chip_vendor; + u16 chip_device; + int mode; +}; + +static struct nouveau_agpmode_quirk nouveau_agpmode_quirk_list[] = { + /* VIA Apollo PRO133x / GeForce FX 5600 Ultra, max agpmode 2, fdo #20341 */ + { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 }, + + {}, +}; + static unsigned long -get_agp_mode(struct nouveau_drm *drm, unsigned long mode) +get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) { struct nouveau_device *device = nv_device(drm->device); + struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list; + int agpmode = nouveau_agpmode; + unsigned long mode = info->mode; /* * FW seems to be broken on nv18, it makes the card lock up @@ -24,11 +42,27 @@ get_agp_mode(struct nouveau_drm *drm, unsigned long mode) mode &= ~PCI_AGP_COMMAND_FW; /* + * Go through the quirks list and adjust the agpmode accordingly. + */ + 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) { + agpmode = quirk->mode; + nv_info(device, "Forcing agp mode to %dX. Use agpmode to override.\n", + agpmode); + break; + } + ++quirk; + } + + /* * AGP mode set in the command line. */ - if (nouveau_agpmode > 0) { + if (agpmode > 0) { bool agpv3 = mode & 0x8; - int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode; + int rate = agpv3 ? agpmode / 4 : agpmode; mode = (mode & ~0x7) | (rate & 0x7); } @@ -41,7 +75,7 @@ nouveau_agp_enabled(struct nouveau_drm *drm) { struct drm_device *dev = drm->dev; - if (!drm_pci_device_is_agp(dev) || !dev->agp) + if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp) return false; if (drm->agp.stat == UNKNOWN) { @@ -90,7 +124,7 @@ nouveau_agp_reset(struct nouveau_drm *drm) if (ret) return; - mode.mode = get_agp_mode(drm, info.mode); + mode.mode = get_agp_mode(drm, &info); mode.mode &= ~PCI_AGP_COMMAND_FW; ret = drm_agp_enable(dev, mode); @@ -139,7 +173,7 @@ nouveau_agp_init(struct nouveau_drm *drm) } /* see agp.h for the AGPSTAT_* modes available */ - mode.mode = get_agp_mode(drm, info.mode); + mode.mode = get_agp_mode(drm, &info); ret = drm_agp_enable(dev, mode); if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 2ffad2176b7..2c1e4aad7da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -31,7 +31,6 @@ */ #include <linux/backlight.h> -#include <linux/acpi.h> #include "nouveau_drm.h" #include "nouveau_reg.h" @@ -82,7 +81,7 @@ nv40_backlight_init(struct drm_connector *connector) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = 31; - bd = backlight_device_register("nv_backlight", &connector->kdev, drm, + bd = backlight_device_register("nv_backlight", connector->kdev, drm, &nv40_bl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -204,7 +203,7 @@ nv50_backlight_init(struct drm_connector *connector) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = 100; - bd = backlight_device_register("nv_backlight", &connector->kdev, + bd = backlight_device_register("nv_backlight", connector->kdev, nv_encoder, ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -222,14 +221,6 @@ nouveau_backlight_init(struct drm_device *dev) struct nouveau_device *device = nv_device(drm->device); struct drm_connector *connector; -#ifdef CONFIG_ACPI - if (acpi_video_backlight_support()) { - NV_INFO(drm, "ACPI backlight interface available, " - "not registering our own\n"); - return 0; - } -#endif - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && connector->connector_type != DRM_MODE_CONNECTOR_eDP) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 3e7287675ec..8268a4ccac1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -127,8 +127,8 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_outp #ifdef __powerpc__ /* Powerbook specific quirks */ if (script == LVDS_RESET && - (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 || - dev->pci_device == 0x0329)) + (dev->pdev->device == 0x0179 || dev->pdev->device == 0x0189 || + dev->pdev->device == 0x0329)) nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); #endif @@ -1474,9 +1474,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, case 0: entry->dpconf.link_bw = 162000; break; - default: + case 1: entry->dpconf.link_bw = 270000; break; + default: + entry->dpconf.link_bw = 540000; + break; } switch ((conf & 0x0f000000) >> 24) { case 0xf: @@ -2069,6 +2072,10 @@ nouveau_bios_init(struct drm_device *dev) struct nvbios *bios = &drm->vbios; int ret; + /* only relevant for PCI devices */ + if (!dev->pdev) + return 0; + if (!NVInitVBIOS(dev)) return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 755c38d0627..b6dc85c614b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -98,12 +98,7 @@ nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile, if (tile) { spin_lock(&drm->tile.lock); - if (fence) { - /* Mark it as pending. */ - tile->fence = fence; - nouveau_fence_ref(fence); - } - + tile->fence = nouveau_fence_ref(fence); tile->used = false; spin_unlock(&drm->tile.lock); } @@ -146,7 +141,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) struct drm_device *dev = drm->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); - if (unlikely(nvbo->gem)) + if (unlikely(nvbo->gem.filp)) DRM_ERROR("bo %p still attached to GEM object\n", bo); WARN_ON(nvbo->pin_refcnt > 0); nv10_bo_put_tile_region(dev, nvbo->tile, NULL); @@ -269,7 +264,8 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type) struct nouveau_fb *pfb = nouveau_fb(drm->device); u32 vram_pages = pfb->ram->size >> PAGE_SHIFT; - if (nv_device(drm->device)->card_type == NV_10 && + if ((nv_device(drm->device)->card_type == NV_10 || + nv_device(drm->device)->card_type == NV_11) && nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && nvbo->bo.mem.num_pages < vram_pages / 4) { /* @@ -564,28 +560,6 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) } -/* GPU-assisted copy using NV_MEMORY_TO_MEMORY_FORMAT, can access - * TTM_PL_{VRAM,TT} directly. - */ - -static int -nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, - struct nouveau_bo *nvbo, bool evict, - bool no_wait_gpu, struct ttm_mem_reg *new_mem) -{ - struct nouveau_fence *fence = NULL; - int ret; - - ret = nouveau_fence_new(chan, false, &fence); - if (ret) - return ret; - - ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, evict, - no_wait_gpu, new_mem); - nouveau_fence_unref(&fence); - return ret; -} - static int nve0_bo_move_init(struct nouveau_channel *chan, u32 handle) { @@ -802,25 +776,25 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) { struct nouveau_mem *node = old_mem->mm_node; - struct nouveau_bo *nvbo = nouveau_bo(bo); u64 length = (new_mem->num_pages << PAGE_SHIFT); u64 src_offset = node->vma[0].offset; u64 dst_offset = node->vma[1].offset; + int src_tiled = !!node->memtype; + int dst_tiled = !!((struct nouveau_mem *)new_mem->mm_node)->memtype; int ret; while (length) { u32 amount, stride, height; + ret = RING_SPACE(chan, 18 + 6 * (src_tiled + dst_tiled)); + if (ret) + return ret; + amount = min(length, (u64)(4 * 1024 * 1024)); stride = 16 * 4; height = amount / stride; - if (old_mem->mem_type == TTM_PL_VRAM && - nouveau_bo_tile_layout(nvbo)) { - ret = RING_SPACE(chan, 8); - if (ret) - return ret; - + if (src_tiled) { BEGIN_NV04(chan, NvSubCopy, 0x0200, 7); OUT_RING (chan, 0); OUT_RING (chan, 0); @@ -830,19 +804,10 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, OUT_RING (chan, 0); OUT_RING (chan, 0); } else { - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_NV04(chan, NvSubCopy, 0x0200, 1); OUT_RING (chan, 1); } - if (new_mem->mem_type == TTM_PL_VRAM && - nouveau_bo_tile_layout(nvbo)) { - ret = RING_SPACE(chan, 8); - if (ret) - return ret; - + if (dst_tiled) { BEGIN_NV04(chan, NvSubCopy, 0x021c, 7); OUT_RING (chan, 0); OUT_RING (chan, 0); @@ -852,18 +817,10 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, OUT_RING (chan, 0); OUT_RING (chan, 0); } else { - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_NV04(chan, NvSubCopy, 0x021c, 1); OUT_RING (chan, 1); } - ret = RING_SPACE(chan, 14); - if (ret) - return ret; - BEGIN_NV04(chan, NvSubCopy, 0x0238, 2); OUT_RING (chan, upper_32_bits(src_offset)); OUT_RING (chan, upper_32_bits(dst_offset)); @@ -957,23 +914,28 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, } static int -nouveau_vma_getmap(struct nouveau_channel *chan, struct nouveau_bo *nvbo, - struct ttm_mem_reg *mem, struct nouveau_vma *vma) +nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem) { - struct nouveau_mem *node = mem->mm_node; + struct nouveau_mem *old_node = bo->mem.mm_node; + struct nouveau_mem *new_node = mem->mm_node; + u64 size = (u64)mem->num_pages << PAGE_SHIFT; int ret; - ret = nouveau_vm_get(nv_client(chan->cli)->vm, mem->num_pages << - PAGE_SHIFT, node->page_shift, - NV_MEM_ACCESS_RW, vma); + ret = nouveau_vm_get(nv_client(drm)->vm, size, old_node->page_shift, + NV_MEM_ACCESS_RW, &old_node->vma[0]); if (ret) return ret; - if (mem->mem_type == TTM_PL_VRAM) - nouveau_vm_map(vma, node); - else - nouveau_vm_map_sg(vma, 0, mem->num_pages << PAGE_SHIFT, node); + ret = nouveau_vm_get(nv_client(drm)->vm, size, new_node->page_shift, + NV_MEM_ACCESS_RW, &old_node->vma[1]); + if (ret) { + nouveau_vm_put(&old_node->vma[0]); + return ret; + } + nouveau_vm_map(&old_node->vma[0], old_node); + nouveau_vm_map(&old_node->vma[1], new_node); return 0; } @@ -982,36 +944,35 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); - struct nouveau_channel *chan = chan = drm->ttm.chan; - struct nouveau_bo *nvbo = nouveau_bo(bo); - struct ttm_mem_reg *old_mem = &bo->mem; + struct nouveau_channel *chan = drm->ttm.chan; + struct nouveau_fence *fence; int ret; - mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING); - /* create temporary vmas for the transfer and attach them to the * 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) { - struct nouveau_mem *node = old_mem->mm_node; - - ret = nouveau_vma_getmap(chan, nvbo, old_mem, &node->vma[0]); - if (ret) - goto out; - - ret = nouveau_vma_getmap(chan, nvbo, new_mem, &node->vma[1]); + ret = nouveau_bo_move_prep(drm, bo, new_mem); if (ret) - goto out; + return ret; } - ret = drm->ttm.move(chan, bo, &bo->mem, new_mem); + mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING); + ret = nouveau_fence_sync(bo->sync_obj, chan); if (ret == 0) { - ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict, - no_wait_gpu, new_mem); + 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, + evict, + no_wait_gpu, + new_mem); + nouveau_fence_unref(&fence); + } + } } - -out: mutex_unlock(&chan->cli->mutex); return ret; } @@ -1151,19 +1112,10 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem) return; list_for_each_entry(vma, &nvbo->vma_list, head) { - if (new_mem && new_mem->mem_type == TTM_PL_VRAM) { + if (new_mem && new_mem->mem_type != TTM_PL_SYSTEM && + (new_mem->mem_type == TTM_PL_VRAM || + nvbo->page_shift != vma->vm->vmm->lpg_shift)) { nouveau_vm_map(vma, new_mem->mm_node); - } else - if (new_mem && new_mem->mem_type == TTM_PL_TT && - nvbo->page_shift == vma->vm->vmm->spg_shift) { - if (((struct nouveau_mem *)new_mem->mm_node)->sg) - nouveau_vm_map_sg_table(vma, 0, new_mem-> - num_pages << PAGE_SHIFT, - new_mem->mm_node); - else - nouveau_vm_map_sg(vma, 0, new_mem-> - num_pages << PAGE_SHIFT, - new_mem->mm_node); } else { nouveau_vm_unmap(vma); } @@ -1228,28 +1180,27 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, goto out; } - /* CPU copy if we have no accelerated method available */ - if (!drm->ttm.move) { - ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); - goto out; - } - /* Hardware assisted copy. */ - if (new_mem->mem_type == TTM_PL_SYSTEM) - ret = nouveau_bo_move_flipd(bo, evict, intr, - no_wait_gpu, new_mem); - else if (old_mem->mem_type == TTM_PL_SYSTEM) - ret = nouveau_bo_move_flips(bo, evict, intr, - no_wait_gpu, new_mem); - else - ret = nouveau_bo_move_m2mf(bo, evict, intr, - no_wait_gpu, new_mem); - - if (!ret) - goto out; + if (drm->ttm.move) { + if (new_mem->mem_type == TTM_PL_SYSTEM) + ret = nouveau_bo_move_flipd(bo, evict, intr, + no_wait_gpu, new_mem); + else if (old_mem->mem_type == TTM_PL_SYSTEM) + ret = nouveau_bo_move_flips(bo, evict, intr, + no_wait_gpu, new_mem); + else + ret = nouveau_bo_move_m2mf(bo, evict, intr, + no_wait_gpu, new_mem); + if (!ret) + goto out; + } /* Fallback to software copy. */ - ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); + 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) { @@ -1267,7 +1218,7 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) { struct nouveau_bo *nvbo = nouveau_bo(bo); - return drm_vma_node_verify_access(&nvbo->gem->vma_node, filp); + return drm_vma_node_verify_access(&nvbo->gem.vma_node, filp); } static int @@ -1275,6 +1226,7 @@ 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; @@ -1297,14 +1249,16 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) mem->bus.is_iomem = !dev->agp->cant_use_aperture; } #endif - break; + if (nv_device(drm->device)->card_type < NV_50 || !node->memtype) + /* untiled */ + break; + /* fallthrough, tiled memory */ case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; - mem->bus.base = pci_resource_start(dev->pdev, 1); + mem->bus.base = nv_device_resource_start(nouveau_dev(dev), 1); mem->bus.is_iomem = true; if (nv_device(drm->device)->card_type >= NV_50) { struct nouveau_bar *bar = nouveau_bar(drm->device); - struct nouveau_mem *node = mem->mm_node; ret = bar->umap(bar, node, NV_MEM_ACCESS_RW, &node->bar_vma); @@ -1339,7 +1293,8 @@ 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 = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT; + u32 mappable = nv_device_resource_len(device, 1) >> PAGE_SHIFT; + int ret; /* as long as the bo isn't in vram, and isn't tiled, we've got * nothing to do here. @@ -1348,10 +1303,20 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) if (nv_device(drm->device)->card_type < NV_50 || !nouveau_bo_tile_layout(nvbo)) return 0; + + if (bo->mem.mem_type == TTM_PL_SYSTEM) { + nouveau_bo_placement_set(nvbo, TTM_PL_TT, 0); + + ret = nouveau_bo_validate(nvbo, false, false); + if (ret) + return ret; + } + return 0; } /* make sure bo is in mappable vram */ - if (bo->mem.start + bo->mem.num_pages < mappable) + if (nv_device(drm->device)->card_type >= NV_50 || + bo->mem.start + bo->mem.num_pages < mappable) return 0; @@ -1366,6 +1331,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) { struct ttm_dma_tt *ttm_dma = (void *)ttm; struct nouveau_drm *drm; + struct nouveau_device *device; struct drm_device *dev; unsigned i; int r; @@ -1383,6 +1349,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) } drm = nouveau_bdev(ttm->bdev); + device = nv_device(drm->device); dev = drm->dev; #if __OS_HAS_AGP @@ -1403,13 +1370,12 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) } for (i = 0; i < ttm->num_pages; i++) { - ttm_dma->dma_address[i] = pci_map_page(dev->pdev, ttm->pages[i], - 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, ttm_dma->dma_address[i])) { + ttm_dma->dma_address[i] = nv_device_map_page(device, + ttm->pages[i]); + if (!ttm_dma->dma_address[i]) { while (--i) { - pci_unmap_page(dev->pdev, ttm_dma->dma_address[i], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, + ttm_dma->dma_address[i]); ttm_dma->dma_address[i] = 0; } ttm_pool_unpopulate(ttm); @@ -1424,6 +1390,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) { struct ttm_dma_tt *ttm_dma = (void *)ttm; struct nouveau_drm *drm; + struct nouveau_device *device; struct drm_device *dev; unsigned i; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); @@ -1432,6 +1399,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) return; drm = nouveau_bdev(ttm->bdev); + device = nv_device(drm->device); dev = drm->dev; #if __OS_HAS_AGP @@ -1450,8 +1418,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) for (i = 0; i < ttm->num_pages; i++) { if (ttm_dma->dma_address[i]) { - pci_unmap_page(dev->pdev, ttm_dma->dma_address[i], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, ttm_dma->dma_address[i]); } } @@ -1461,14 +1428,12 @@ 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; - if (likely(fence)) - nouveau_fence_ref(fence); - spin_lock(&nvbo->bo.bdev->fence_lock); old_fence = nvbo->bo.sync_obj; - nvbo->bo.sync_obj = fence; + nvbo->bo.sync_obj = new_fence; spin_unlock(&nvbo->bo.bdev->fence_lock); nouveau_fence_unref(&old_fence); @@ -1541,7 +1506,6 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm, struct nouveau_vma *vma) { const u32 size = nvbo->bo.mem.num_pages << PAGE_SHIFT; - struct nouveau_mem *node = nvbo->bo.mem.mm_node; int ret; ret = nouveau_vm_get(vm, size, nvbo->page_shift, @@ -1549,14 +1513,10 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm, if (ret) return ret; - if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) + if ( nvbo->bo.mem.mem_type != TTM_PL_SYSTEM && + (nvbo->bo.mem.mem_type == TTM_PL_VRAM || + nvbo->page_shift != vma->vm->vmm->lpg_shift)) nouveau_vm_map(vma, nvbo->bo.mem.mm_node); - else if (nvbo->bo.mem.mem_type == TTM_PL_TT) { - if (node->sg) - nouveau_vm_map_sg_table(vma, 0, size, node); - else - nouveau_vm_map_sg(vma, 0, size, node); - } list_add_tail(&vma->head, &nvbo->vma_list); vma->refcount = 1; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 653dbbbd4fa..ff17c1f432f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -27,7 +27,10 @@ struct nouveau_bo { u32 tile_flags; struct nouveau_drm_tile *tile; - struct drm_gem_object *gem; + /* Only valid if allocated via nouveau_gem_new() and iff you hold a + * gem reference to it! For debugging, use gem.filp != NULL to test + * whether it is valid. */ + struct drm_gem_object gem; /* protect by the ttm reservation lock */ int pin_refcnt; diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index e84f4c32331..ccb6b452d6d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -154,7 +154,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, * nfi why this exists, it came from the -nv ddx. */ args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR; - args.start = pci_resource_start(device->pdev, 1); + args.start = nv_device_resource_start(device, 1); args.limit = args.start + limit; } else { args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR; @@ -346,22 +346,17 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) OUT_RING(chan, 0x00000000); - /* allocate software object class (used for fences on <= nv05, and - * to signal flip completion), bind it to a subchannel. - */ - if ((device->card_type < NV_E0) || gart /* nve0: want_nvsw */) { + /* 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, nouveau_abi16_swclass(chan->drm), - NULL, 0, &object); + NvSw, 0x006e, NULL, 0, &object); if (ret) return ret; swch = (void *)object->parent; swch->flip = nouveau_flip_complete; swch->flip_data = chan; - } - if (device->card_type < NV_C0) { ret = RING_SPACE(chan, 2); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c5b36f9e9a1..1fa222e8f00 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -44,6 +44,7 @@ #include <subdev/i2c.h> #include <subdev/gpio.h> +#include <engine/disp.h> MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); static int nouveau_tv_disable = 0; @@ -75,7 +76,8 @@ find_encoder(struct drm_connector *connector, int type) continue; nv_encoder = nouveau_encoder(obj_to_encoder(obj)); - if (type == DCB_OUTPUT_ANY || nv_encoder->dcb->type == type) + if (type == DCB_OUTPUT_ANY || + (nv_encoder->dcb && nv_encoder->dcb->type == type)) return nv_encoder; } @@ -100,21 +102,24 @@ static void nouveau_connector_destroy(struct drm_connector *connector) { struct nouveau_connector *nv_connector = nouveau_connector(connector); + nouveau_event_ref(NULL, &nv_connector->hpd); kfree(nv_connector->edid); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); + if (nv_connector->aux.transfer) + drm_dp_aux_unregister(&nv_connector->aux); kfree(connector); } -static struct nouveau_i2c_port * -nouveau_connector_ddc_detect(struct drm_connector *connector, - struct nouveau_encoder **pnv_encoder) +static struct nouveau_encoder * +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_i2c_port *port = NULL; + struct nouveau_encoder *nv_encoder; + struct drm_mode_object *obj; int i, panel = -ENODEV; /* eDP panels need powering on by us (if the VBIOS doesn't default it @@ -129,13 +134,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, } } - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - struct nouveau_encoder *nv_encoder; - struct drm_mode_object *obj; - int id; - - id = connector->encoder_ids[i]; - if (!id) + for (i = 0; nv_encoder = NULL, i < DRM_CONNECTOR_MAX_ENCODER; i++) { + int id = connector->encoder_ids[i]; + if (id == 0) break; obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); @@ -143,22 +144,24 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, continue; nv_encoder = nouveau_encoder(obj_to_encoder(obj)); - port = nv_encoder->i2c; - if (port && nv_probe_i2c(port, 0x50)) { - *pnv_encoder = nv_encoder; - break; + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { + int ret = nouveau_dp_detect(nv_encoder); + if (ret == 0) + break; + } else + if (nv_encoder->i2c) { + if (nv_probe_i2c(nv_encoder->i2c, 0x50)) + break; } - - port = NULL; } /* eDP panel not detected, restore panel power GPIO to previous * state to avoid confusing the SOR for other output types. */ - if (!port && panel == 0) + if (!nv_encoder && panel == 0) gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel); - return port; + return nv_encoder; } static struct nouveau_encoder * @@ -214,9 +217,10 @@ nouveau_connector_set_encoder(struct drm_connector *connector, } else { connector->doublescan_allowed = true; if (nv_device(drm->device)->card_type == NV_20 || - (nv_device(drm->device)->card_type == NV_10 && - (dev->pci_device & 0x0ff0) != 0x0100 && - (dev->pci_device & 0x0ff0) != 0x0150)) + ((nv_device(drm->device)->card_type == NV_10 || + nv_device(drm->device)->card_type == NV_11) && + (dev->pdev->device & 0x0ff0) != 0x0100 && + (dev->pdev->device & 0x0ff0) != 0x0150)) /* HW is broken */ connector->interlace_allowed = false; else @@ -253,28 +257,20 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) } ret = pm_runtime_get_sync(connector->dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return conn_status; - i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); - if (i2c) { + nv_encoder = nouveau_connector_ddc_detect(connector); + if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { nv_connector->edid = drm_get_edid(connector, &i2c->adapter); drm_mode_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { NV_ERROR(drm, "DDC responded, but no EDID for %s\n", - drm_get_connector_name(connector)); + connector->name); goto detect_analog; } - if (nv_encoder->dcb->type == DCB_OUTPUT_DP && - !nouveau_dp_detect(to_drm_encoder(nv_encoder))) { - NV_ERROR(drm, "Detected %s, but failed init\n", - drm_get_connector_name(connector)); - conn_status = connector_status_disconnected; - goto out; - } - /* Override encoder type for DVI-I based on whether EDID * says the display is digital or analog, both use the * same i2c channel so the value returned from ddc_detect @@ -435,7 +431,7 @@ nouveau_connector_force(struct drm_connector *connector) nv_encoder = find_encoder(connector, type); if (!nv_encoder) { NV_ERROR(drm, "can't find encoder to force %s on!\n", - drm_get_connector_name(connector)); + connector->name); connector->status = connector_status_disconnected; return; } @@ -910,34 +906,103 @@ nouveau_connector_funcs_lvds = { }; static void +nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) +{ + struct nouveau_encoder *nv_encoder = NULL; + + if (connector->encoder) + nv_encoder = nouveau_encoder(connector->encoder); + if (nv_encoder && nv_encoder->dcb && + nv_encoder->dcb->type == DCB_OUTPUT_DP) { + if (mode == DRM_MODE_DPMS_ON) { + u8 data = DP_SET_POWER_D0; + nv_wraux(nv_encoder->i2c, DP_SET_POWER, &data, 1); + usleep_range(1000, 2000); + } else { + u8 data = DP_SET_POWER_D3; + nv_wraux(nv_encoder->i2c, DP_SET_POWER, &data, 1); + } + } + + drm_helper_connector_dpms(connector, mode); +} + +static const struct drm_connector_funcs +nouveau_connector_funcs_dp = { + .dpms = nouveau_connector_dp_dpms, + .save = NULL, + .restore = NULL, + .detect = nouveau_connector_detect, + .destroy = nouveau_connector_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = nouveau_connector_set_property, + .force = nouveau_connector_force +}; + +static void nouveau_connector_hotplug_work(struct work_struct *work) { struct nouveau_connector *nv_connector = - container_of(work, struct nouveau_connector, hpd_work); + container_of(work, typeof(*nv_connector), work); struct drm_connector *connector = &nv_connector->base; - struct drm_device *dev = connector->dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); - bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff); + struct nouveau_drm *drm = nouveau_drm(connector->dev); + const char *name = connector->name; - NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", - drm_get_connector_name(connector)); + if (nv_connector->status & NVKM_HPD_IRQ) { + } else { + bool plugged = (nv_connector->status != NVKM_HPD_UNPLUG); - if (plugged) - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - else - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name); + + if (plugged) + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + else + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_helper_hpd_irq_event(connector->dev); + } - drm_helper_hpd_irq_event(dev); + nouveau_event_get(nv_connector->hpd); } static int -nouveau_connector_hotplug(struct nouveau_eventh *event, int index) +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; +} + +static ssize_t +nouveau_connector_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { struct nouveau_connector *nv_connector = - container_of(event, struct nouveau_connector, hpd_func); - schedule_work(&nv_connector->hpd_work); - return NVKM_EVENT_KEEP; + container_of(aux, typeof(*nv_connector), aux); + struct nouveau_encoder *nv_encoder; + struct nouveau_i2c_port *port; + int ret; + + nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); + if (!nv_encoder || !(port = nv_encoder->i2c)) + return -ENODEV; + if (WARN_ON(msg->size > 16)) + return -E2BIG; + if (msg->size == 0) + return msg->size; + + ret = nouveau_i2c(port)->acquire(port, 0); + if (ret) + return ret; + + ret = port->func->aux(port, false, msg->request, msg->address, + msg->buffer, msg->size); + nouveau_i2c(port)->release(port); + if (ret >= 0) { + msg->reply = ret; + return msg->size; + } + + return ret; } static int @@ -959,7 +1024,8 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb) case DCB_CONNECTOR_DP : return DRM_MODE_CONNECTOR_DisplayPort; case DCB_CONNECTOR_eDP : return DRM_MODE_CONNECTOR_eDP; case DCB_CONNECTOR_HDMI_0 : - case DCB_CONNECTOR_HDMI_1 : return DRM_MODE_CONNECTOR_HDMIA; + case DCB_CONNECTOR_HDMI_1 : + case DCB_CONNECTOR_HDMI_C : return DRM_MODE_CONNECTOR_HDMIA; default: break; } @@ -972,9 +1038,9 @@ nouveau_connector_create(struct drm_device *dev, int index) { const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); 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; @@ -990,27 +1056,15 @@ nouveau_connector_create(struct drm_device *dev, int index) return ERR_PTR(-ENOMEM); connector = &nv_connector->base; - INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work); nv_connector->index = index; /* attempt to parse vbios connector type and hotplug gpio */ nv_connector->dcb = olddcb_conn(dev, index); if (nv_connector->dcb) { - static const u8 hpd[16] = { - 0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60, - }; - u32 entry = ROM16(nv_connector->dcb[0]); if (olddcb_conntab(dev)[3] >= 4) entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; - ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)], - DCB_GPIO_UNUSED, &nv_connector->hpd); - nv_connector->hpd_func.func = nouveau_connector_hotplug; - if (ret) - nv_connector->hpd.func = DCB_GPIO_UNUSED; - nv_connector->type = nv_connector->dcb[0]; if (drm_conntype_from_dcb(nv_connector->type) == DRM_MODE_CONNECTOR_Unknown) { @@ -1032,7 +1086,6 @@ nouveau_connector_create(struct drm_device *dev, int index) } } else { nv_connector->type = DCB_CONNECTOR_NONE; - nv_connector->hpd.func = DCB_GPIO_UNUSED; } /* no vbios data, or an unknown dcb connector type - attempt to @@ -1072,8 +1125,8 @@ nouveau_connector_create(struct drm_device *dev, int index) } } - type = drm_conntype_from_dcb(nv_connector->type); - if (type == DRM_MODE_CONNECTOR_LVDS) { + switch ((type = drm_conntype_from_dcb(nv_connector->type))) { + case DRM_MODE_CONNECTOR_LVDS: ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy); if (ret) { NV_ERROR(drm, "Error parsing LVDS table, disabling\n"); @@ -1082,8 +1135,23 @@ nouveau_connector_create(struct drm_device *dev, int index) } funcs = &nouveau_connector_funcs_lvds; - } else { + break; + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_eDP: + nv_connector->aux.dev = dev->dev; + nv_connector->aux.transfer = nouveau_connector_aux_xfer; + ret = drm_dp_aux_register(&nv_connector->aux); + if (ret) { + NV_ERROR(drm, "failed to register aux channel\n"); + kfree(nv_connector); + return ERR_PTR(ret); + } + + funcs = &nouveau_connector_funcs_dp; + break; + default: funcs = &nouveau_connector_funcs; + break; } /* defaults, will get overridden in detect() */ @@ -1158,10 +1226,16 @@ nouveau_connector_create(struct drm_device *dev, int index) break; } - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - if (nv_connector->hpd.func != DCB_GPIO_UNUSED) + ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index, + nouveau_connector_hotplug, + nv_connector, &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); return connector; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 6e399aad491..8861b6c579a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -28,12 +28,12 @@ #define __NOUVEAU_CONNECTOR_H__ #include <drm/drm_edid.h> +#include <drm/drm_dp_helper.h> #include "nouveau_crtc.h" #include <core/event.h> #include <subdev/bios.h> -#include <subdev/bios/gpio.h> struct nouveau_i2c_port; @@ -67,9 +67,11 @@ struct nouveau_connector { u8 index; u8 *dcb; - struct dcb_gpio_func hpd; - struct work_struct hpd_work; - struct nouveau_eventh hpd_func; + struct nouveau_eventh *hpd; + u32 status; + struct work_struct work; + + struct drm_dp_aux aux; int dithering_mode; int dithering_depth; @@ -107,7 +109,4 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) struct drm_connector * nouveau_connector_create(struct drm_device *, int index); -int -nouveau_connector_bpp(struct drm_connector *); - #endif /* __NOUVEAU_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index d1e5890784d..a0534489d23 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -74,7 +74,7 @@ struct nouveau_crtc { static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc) { - return container_of(crtc, struct nouveau_crtc, base); + return crtc ? container_of(crtc, struct nouveau_crtc, base) : NULL; } static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 7848590f556..47ad74255bf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -26,7 +26,6 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> -#include <drm/ttm/ttm_execbuf_util.h> #include "nouveau_fbcon.h" #include "dispnv04/hw.h" @@ -38,19 +37,172 @@ #include "nouveau_fence.h" -#include <subdev/bios/gpio.h> -#include <subdev/gpio.h> #include <engine/disp.h> #include <core/class.h> +static int +nouveau_display_vblank_handler(void *data, u32 type, int head) +{ + struct nouveau_drm *drm = data; + drm_handle_vblank(drm->dev, head); + return NVKM_EVENT_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; + } + return -EIO; +} + +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]); +} + +static inline int +calc(int blanks, int blanke, int total, int line) +{ + if (blanke >= blanks) { + if (line >= blanks) + line -= total; + } else { + if (line >= blanks) + line -= total; + line -= blanke + 1; + } + return line; +} + +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 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)); + if (ret != 0) + return 0; + + if (args.vline) { + ret |= DRM_SCANOUTPOS_ACCURATE; + ret |= DRM_SCANOUTPOS_VALID; + break; + } + + 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]); + + if (*vpos < 0) + ret |= DRM_SCANOUTPOS_INVBL; + return ret; +} + +int +nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags, + int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (nouveau_crtc(crtc)->index == head) { + return nouveau_display_scanoutpos_head(crtc, vpos, hpos, + stime, etime); + } + } + + return 0; +} + +int +nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error, + struct timeval *time, unsigned flags) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (nouveau_crtc(crtc)->index == head) { + return drm_calc_vbltimestamp_from_scanoutpos(dev, + head, max_error, time, flags, crtc, + &crtc->hwmode); + } + } + + return -EINVAL; +} + +static void +nouveau_display_vblank_fini(struct drm_device *dev) +{ + struct nouveau_display *disp = nouveau_display(dev); + int i; + + 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; + } +} + +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; + + 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]); + if (ret) { + nouveau_display_vblank_fini(dev); + return ret; + } + } + + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (ret) { + nouveau_display_vblank_fini(dev); + return ret; + } + + return 0; +} + static void nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) { struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); if (fb->nvbo) - drm_gem_object_unreference_unlocked(fb->nvbo->gem); + drm_gem_object_unreference_unlocked(&fb->nvbo->gem); drm_framebuffer_cleanup(drm_fb); kfree(fb); @@ -63,7 +215,7 @@ nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb, { struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); - return drm_gem_handle_create(file_priv, fb->nvbo->gem, handle); + return drm_gem_handle_create(file_priv, &fb->nvbo->gem, handle); } static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { @@ -227,9 +379,7 @@ static struct nouveau_drm_prop_enum_list dither_depth[] = { int nouveau_display_init(struct drm_device *dev) { - struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); struct drm_connector *connector; int ret; @@ -243,10 +393,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 (gpio && conn->hpd.func != DCB_GPIO_UNUSED) { - nouveau_event_get(gpio->events, conn->hpd.line, - &conn->hpd_func); - } + if (conn->hpd) nouveau_event_get(conn->hpd); } return ret; @@ -255,18 +402,13 @@ nouveau_display_init(struct drm_device *dev) void nouveau_display_fini(struct drm_device *dev) { - struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_display *disp = nouveau_display(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); struct drm_connector *connector; /* disable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) { - nouveau_event_put(gpio->events, conn->hpd.line, - &conn->hpd_func); - } + if (conn->hpd) nouveau_event_put(conn->hpd); } drm_kms_helper_poll_disable(dev); @@ -277,6 +419,7 @@ int nouveau_display_create(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; @@ -317,7 +460,7 @@ nouveau_display_create(struct drm_device *dev) } dev->mode_config.funcs = &nouveau_mode_config_funcs; - dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); + dev->mode_config.fb_base = nv_device_resource_start(device, 1); dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; @@ -336,14 +479,41 @@ 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) + dev->mode_config.async_page_flip = false; + else + dev->mode_config.async_page_flip = true; + drm_kms_helper_poll_init(dev); drm_kms_helper_poll_disable(dev); if (drm->vbios.dcb.entries) { - if (nv_device(drm->device)->card_type < NV_50) - ret = nv04_display_create(dev); - else - ret = nv50_display_create(dev); + 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, + }; + 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); + } + + if (ret == 0) { + if (nv_mclass(disp->core) < NV50_DISP_CLASS) + ret = nv04_display_create(dev); + else + ret = nv50_display_create(dev); + } } else { ret = 0; } @@ -352,7 +522,7 @@ nouveau_display_create(struct drm_device *dev) goto disp_create_err; if (dev->mode_config.num_crtc) { - ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + ret = nouveau_display_vblank_init(dev); if (ret) goto vblank_err; } @@ -372,9 +542,10 @@ 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); - drm_vblank_cleanup(dev); + nouveau_display_vblank_fini(dev); drm_kms_helper_poll_fini(dev); drm_mode_config_cleanup(dev); @@ -382,6 +553,8 @@ nouveau_display_destroy(struct drm_device *dev) if (disp->dtor) disp->dtor(dev); + nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_DISPLAY); + nouveau_drm(dev)->display = NULL; kfree(disp); } @@ -394,11 +567,11 @@ nouveau_display_suspend(struct drm_device *dev) nouveau_display_fini(dev); - NV_SUSPEND(drm, "unpinning framebuffer(s)...\n"); + NV_INFO(drm, "unpinning framebuffer(s)...\n"); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; - nouveau_fb = nouveau_framebuffer(crtc->fb); + nouveau_fb = nouveau_framebuffer(crtc->primary->fb); if (!nouveau_fb || !nouveau_fb->nvbo) continue; @@ -425,7 +598,7 @@ nouveau_display_repin(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; - nouveau_fb = nouveau_framebuffer(crtc->fb); + nouveau_fb = nouveau_framebuffer(crtc->primary->fb); if (!nouveau_fb || !nouveau_fb->nvbo) continue; @@ -492,19 +665,15 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, goto fail; /* Emit the pageflip */ - ret = RING_SPACE(chan, 3); + ret = RING_SPACE(chan, 2); if (ret) goto fail; - if (nv_device(drm->device)->card_type < NV_C0) { + if (nv_device(drm->device)->card_type < NV_C0) BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); - OUT_RING (chan, 0x00000000); - OUT_RING (chan, 0x00000000); - } else { - BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1); - OUT_RING (chan, 0); - BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000); - } + else + BEGIN_NVC0(chan, FermiSw, NV_SW_PAGE_FLIP, 1); + OUT_RING (chan, 0x00000000); FIRE_RING (chan); ret = nouveau_fence_new(chan, false, pfence); @@ -521,22 +690,16 @@ fail: int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) + struct drm_pending_vblank_event *event, u32 flags) { + const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; + 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 = NULL; + struct nouveau_channel *chan = drm->channel; struct nouveau_fence *fence; - struct ttm_validate_buffer resv[2] = { - { .bo = &old_bo->bo }, - { .bo = &new_bo->bo }, - }; - struct ww_acquire_ctx ticket; - LIST_HEAD(res); int ret; if (!drm->channel) @@ -546,26 +709,24 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (!s) return -ENOMEM; - /* Choose the channel the flip will be handled in */ - spin_lock(&old_bo->bo.bdev->fence_lock); - fence = new_bo->bo.sync_obj; - if (fence) - chan = fence->channel; - if (!chan) - chan = drm->channel; - spin_unlock(&old_bo->bo.bdev->fence_lock); - if (new_bo != old_bo) { ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); if (ret) goto fail_free; - - list_add(&resv[1].head, &res); } - list_add(&resv[0].head, &res); mutex_lock(&chan->cli->mutex); - ret = ttm_eu_reserve_buffers(&ticket, &res); + + /* 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); + if (ret) + goto fail_unpin; + + ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); if (ret) goto fail_unpin; @@ -575,32 +736,54 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y, new_bo->bo.offset }; + /* Keep vblanks on during flip, for the target crtc of this flip */ + drm_vblank_get(dev, nouveau_crtc(crtc)->index); + /* Emit a page flip */ if (nv_device(drm->device)->card_type >= NV_50) { - ret = nv50_display_flip_next(crtc, fb, chan, 0); + ret = nv50_display_flip_next(crtc, fb, chan, swap_interval); if (ret) goto fail_unreserve; } else { struct nv04_display *dispnv04 = nv04_display(dev); - nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]); + int head = nouveau_crtc(crtc)->index; + + if (swap_interval) { + ret = RING_SPACE(chan, 8); + if (ret) + goto fail_unreserve; + + BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); + OUT_RING (chan, 0); + BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); + OUT_RING (chan, head); + BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); + OUT_RING (chan, 0); + BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); + OUT_RING (chan, 0); + } + + nouveau_bo_ref(new_bo, &dispnv04->image[head]); } ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); - mutex_unlock(&chan->cli->mutex); if (ret) goto fail_unreserve; + mutex_unlock(&chan->cli->mutex); /* Update the crtc struct and cleanup */ - crtc->fb = fb; + crtc->primary->fb = fb; - ttm_eu_fence_buffer_objects(&ticket, &res, fence); + nouveau_bo_fence(old_bo, fence); + ttm_bo_unreserve(&old_bo->bo); if (old_bo != new_bo) nouveau_bo_unpin(old_bo); nouveau_fence_unref(&fence); return 0; fail_unreserve: - ttm_eu_backoff_reservation(&ticket, &res); + drm_vblank_put(dev, nouveau_crtc(crtc)->index); + ttm_bo_unreserve(&old_bo->bo); fail_unpin: mutex_unlock(&chan->cli->mutex); if (old_bo != new_bo) @@ -619,6 +802,7 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, struct drm_device *dev = drm->dev; struct nouveau_page_flip_state *s; unsigned long flags; + int crtcid = -1; spin_lock_irqsave(&dev->event_lock, flags); @@ -629,8 +813,16 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, } s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); - if (s->event) - drm_send_vblank_event(dev, -1, s->event); + if (s->event) { + /* Vblank timestamps/counts are only correct on >= NV-50 */ + if (nv_device(drm->device)->card_type >= NV_50) + crtcid = s->crtc; + + drm_send_vblank_event(dev, crtcid, s->event); + } + + /* Give up ownership of vblank for page-flipped crtc */ + drm_vblank_put(dev, s->crtc); list_del(&s->head); if (ps) @@ -674,8 +866,8 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, if (ret) return ret; - ret = drm_gem_handle_create(file_priv, bo->gem, &args->handle); - drm_gem_object_unreference_unlocked(bo->gem); + ret = drm_gem_handle_create(file_priv, &bo->gem, &args->handle); + drm_gem_object_unreference_unlocked(&bo->gem); return ret; } @@ -688,7 +880,7 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv, gem = drm_gem_object_lookup(dev, file_priv, handle); if (gem) { - struct nouveau_bo *bo = gem->driver_private; + struct nouveau_bo *bo = nouveau_gem_object(gem); *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node); drm_gem_object_unreference_unlocked(gem); return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 025c66f8e0e..a71cf77e55b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -36,6 +36,9 @@ struct nouveau_display { int (*init)(struct drm_device *); void (*fini)(struct drm_device *); + struct nouveau_object *core; + struct nouveau_eventh **vblank; + struct drm_property *dithering_mode; struct drm_property *dithering_depth; struct drm_property *underscan_property; @@ -59,6 +62,12 @@ 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_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, + int *, int *, ktime_t *, ktime_t *); +int nouveau_display_vblstamp(struct drm_device *, int, int *, + struct timeval *, unsigned); int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 40f91e1e584..c177272152e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -100,7 +100,7 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo, chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max; - DRM_MEMORYBARRIER(); + mb(); /* Flush writes. */ nouveau_bo_rd32(pb, 0); diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 690d5930ce3..dc0e0c5cadb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -51,9 +51,11 @@ enum { NvSubCtxSurf2D = 0, NvSubSw = 1, NvSubImageBlit = 2, - NvSub2D = 3, NvSubGdiRect = 3, - NvSubCopy = 4, + + NvSub2D = 3, /* DO NOT CHANGE - hardcoded for kepler gr fifo */ + NvSubCopy = 4, /* DO NOT CHANGE - hardcoded for kepler gr fifo */ + FermiSw = 5, /* DO NOT CHANGE (well.. 6/7 will work...) */ }; /* Object handles. */ @@ -153,7 +155,7 @@ BEGIN_IMC0(struct nouveau_channel *chan, int subc, int mthd, u16 data) } #define WRITE_PUT(val) do { \ - DRM_MEMORYBARRIER(); \ + mb(); \ nouveau_bo_rd32(chan->push.buffer, 0); \ nv_wo32(chan->object, chan->user_put, ((val) << 2) + chan->push.vma.offset); \ } while (0) @@ -194,7 +196,6 @@ WIND_RING(struct nouveau_channel *chan) #define NV84_SUBCHAN_UEVENT 0x00000020 #define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 #define NV10_SUBCHAN_REF_CNT 0x00000050 -#define NVSW_SUBCHAN_PAGE_FLIP 0x00000054 #define NV11_SUBCHAN_DMA_SEMAPHORE 0x00000060 #define NV11_SUBCHAN_SEMAPHORE_OFFSET 0x00000064 #define NV11_SUBCHAN_SEMAPHORE_ACQUIRE 0x00000068 diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 36fd2250056..5675ffc175a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -55,11 +55,10 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch, } -bool -nouveau_dp_detect(struct drm_encoder *encoder) +int +nouveau_dp_detect(struct nouveau_encoder *nv_encoder) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; + struct drm_device *dev = nv_encoder->base.base.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_i2c_port *auxch; u8 *dpcd = nv_encoder->dp.dpcd; @@ -67,11 +66,11 @@ nouveau_dp_detect(struct drm_encoder *encoder) auxch = nv_encoder->i2c; if (!auxch) - return false; + return -ENODEV; ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8); if (ret) - return false; + return ret; nv_encoder->dp.link_bw = 27000 * dpcd[1]; nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; @@ -91,6 +90,5 @@ nouveau_dp_detect(struct drm_encoder *encoder) nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); nouveau_dp_probe_oui(dev, auxch, dpcd); - - return true; + return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index e893c536240..5425ffe3931 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -33,10 +33,12 @@ #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> @@ -46,7 +48,8 @@ #include "nouveau_gem.h" #include "nouveau_agp.h" #include "nouveau_vga.h" -#include "nouveau_pm.h" +#include "nouveau_sysfs.h" +#include "nouveau_hwmon.h" #include "nouveau_acpi.h" #include "nouveau_bios.h" #include "nouveau_ioctl.h" @@ -78,59 +81,39 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400); static struct drm_driver driver; -static int -nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head) -{ - struct nouveau_drm *drm = - container_of(event, struct nouveau_drm, vblank[head]); - drm_handle_vblank(drm->dev, head); - return NVKM_EVENT_KEEP; -} - -static int -nouveau_drm_vblank_enable(struct drm_device *dev, int head) +static u64 +nouveau_pci_name(struct pci_dev *pdev) { - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_disp *pdisp = nouveau_disp(drm->device); - - if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank))) - return -EIO; - WARN_ON_ONCE(drm->vblank[head].func); - drm->vblank[head].func = nouveau_drm_vblank_handler; - nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]); - return 0; + u64 name = (u64)pci_domain_nr(pdev->bus) << 32; + name |= pdev->bus->number << 16; + name |= PCI_SLOT(pdev->devfn) << 8; + return name | PCI_FUNC(pdev->devfn); } -static void -nouveau_drm_vblank_disable(struct drm_device *dev, int head) +static u64 +nouveau_platform_name(struct platform_device *platformdev) { - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_disp *pdisp = nouveau_disp(drm->device); - if (drm->vblank[head].func) - nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]); - else - WARN_ON_ONCE(1); - drm->vblank[head].func = NULL; + return platformdev->id; } static u64 -nouveau_name(struct pci_dev *pdev) +nouveau_name(struct drm_device *dev) { - u64 name = (u64)pci_domain_nr(pdev->bus) << 32; - name |= pdev->bus->number << 16; - name |= PCI_SLOT(pdev->devfn) << 8; - return name | PCI_FUNC(pdev->devfn); + if (dev->pdev) + return nouveau_pci_name(dev->pdev); + else + return nouveau_platform_name(dev->platformdev); } static int -nouveau_cli_create(struct pci_dev *pdev, const char *name, +nouveau_cli_create(u64 name, const char *sname, int size, void **pcli) { struct nouveau_cli *cli; int ret; *pcli = NULL; - ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, + ret = nouveau_client_create_(sname, name, nouveau_config, nouveau_debug, size, pcli); cli = *pcli; if (ret) { @@ -177,7 +160,8 @@ nouveau_accel_init(struct nouveau_drm *drm) /* initialise synchronisation routines */ if (device->card_type < NV_10) ret = nv04_fence_create(drm); - else if (device->chipset < 0x17) ret = nv10_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); @@ -224,6 +208,32 @@ nouveau_accel_init(struct nouveau_drm *drm) return; } + ret = nouveau_object_new(nv_object(drm), NVDRM_CHAN, NVDRM_NVSW, + nouveau_abi16_swclass(drm), NULL, 0, &object); + if (ret == 0) { + struct nouveau_software_chan *swch = (void *)object->parent; + ret = RING_SPACE(drm->channel, 2); + if (ret == 0) { + if (device->card_type < NV_C0) { + BEGIN_NV04(drm->channel, NvSubSw, 0, 1); + OUT_RING (drm->channel, NVDRM_NVSW); + } else + if (device->card_type < NV_E0) { + BEGIN_NVC0(drm->channel, FermiSw, 0, 1); + OUT_RING (drm->channel, 0x001f0000); + } + } + swch = (void *)object->parent; + swch->flip = nouveau_flip_complete; + swch->flip_data = drm->channel; + } + + if (ret) { + NV_ERROR(drm, "failed to allocate software object, %d\n", ret); + nouveau_accel_fini(drm); + return; + } + if (device->card_type < NV_C0) { ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0, &drm->notify); @@ -287,7 +297,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev, remove_conflicting_framebuffers(aper, "nouveaufb", boot); kfree(aper); - ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev), + ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI, + nouveau_pci_name(pdev), pci_name(pdev), nouveau_config, nouveau_debug, &device); if (ret) return ret; @@ -306,22 +317,27 @@ static int nouveau_drm_probe(struct pci_dev *pdev, #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 static void -nouveau_get_hdmi_dev(struct drm_device *dev) +nouveau_get_hdmi_dev(struct nouveau_drm *drm) { - struct nouveau_drm *drm = dev->dev_private; - struct pci_dev *pdev = dev->pdev; + struct pci_dev *pdev = drm->dev->pdev; + + if (!pdev) { + DRM_INFO("not a PCI device; no HDMI\n"); + drm->hdmi_device = NULL; + return; + } /* subfunction one is a hdmi audio device? */ drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(PCI_SLOT(pdev->devfn), 1)); if (!drm->hdmi_device) { - DRM_INFO("hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1); + NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1); return; } if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) { - DRM_INFO("possible hdmi device not audio %d\n", drm->hdmi_device->class); + NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class); pci_dev_put(drm->hdmi_device); drm->hdmi_device = NULL; return; @@ -336,22 +352,24 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) struct nouveau_drm *drm; int ret; - ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); + ret = nouveau_cli_create(nouveau_name(dev), "DRM", sizeof(*drm), + (void **)&drm); if (ret) return ret; dev->dev_private = drm; drm->dev = dev; + nouveau_client(drm)->debug = nouveau_dbgopt(nouveau_debug, "DRM"); INIT_LIST_HEAD(&drm->clients); spin_lock_init(&drm->tile.lock); - nouveau_get_hdmi_dev(dev); + nouveau_get_hdmi_dev(drm); /* make sure AGP controller is in a consistent state before we * (possibly) execute vbios init tables (see nouveau_agp.h) */ - if (drm_pci_device_is_agp(dev) && dev->agp) { + if (pdev && drm_pci_device_is_agp(dev) && dev->agp) { /* dummy device object, doesn't init anything, but allows * agp code access to registers */ @@ -382,6 +400,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto fail_device; + dev->irq_enabled = true; + /* workaround an odd issue on nvc1 by disabling the device's * nosnoop capability. hopefully won't cause issues until a * better fix is found - assuming there is one... @@ -418,8 +438,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) goto fail_dispinit; } - nouveau_pm_init(dev); - + nouveau_sysfs_init(dev); + nouveau_hwmon_init(dev); nouveau_accel_init(drm); nouveau_fbcon_init(dev); @@ -455,8 +475,8 @@ nouveau_drm_unload(struct drm_device *dev) pm_runtime_get_sync(dev->dev); nouveau_fbcon_fini(dev); nouveau_accel_fini(drm); - - nouveau_pm_fini(dev); + nouveau_hwmon_fini(dev); + nouveau_sysfs_fini(dev); if (dev->mode_config.num_crtc) nouveau_display_fini(dev); @@ -481,6 +501,7 @@ nouveau_drm_remove(struct pci_dev *pdev) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_object *device; + dev->irq_enabled = false; device = drm->client.base.device; drm_put_dev(dev); @@ -489,39 +510,41 @@ nouveau_drm_remove(struct pci_dev *pdev) } static int -nouveau_do_suspend(struct drm_device *dev) +nouveau_do_suspend(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; int ret; - if (dev->mode_config.num_crtc) { - NV_SUSPEND(drm, "suspending display...\n"); + if (dev->mode_config.num_crtc && !runtime) { + NV_INFO(drm, "suspending display...\n"); ret = nouveau_display_suspend(dev); if (ret) return ret; } - NV_SUSPEND(drm, "evicting buffers...\n"); + NV_INFO(drm, "evicting buffers...\n"); ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); - NV_SUSPEND(drm, "waiting for kernel channels to go idle...\n"); + NV_INFO(drm, "waiting for kernel channels to go idle...\n"); if (drm->cechan) { ret = nouveau_channel_idle(drm->cechan); if (ret) - return ret; + goto fail_display; } if (drm->channel) { ret = nouveau_channel_idle(drm->channel); if (ret) - return ret; + goto fail_display; } - NV_SUSPEND(drm, "suspending client object trees...\n"); + NV_INFO(drm, "suspending client object trees...\n"); if (drm->fence && nouveau_fence(drm)->suspend) { - if (!nouveau_fence(drm)->suspend(drm)) - return -ENOMEM; + if (!nouveau_fence(drm)->suspend(drm)) { + ret = -ENOMEM; + goto fail_display; + } } list_for_each_entry(cli, &drm->clients, head) { @@ -530,7 +553,7 @@ nouveau_do_suspend(struct drm_device *dev) goto fail_client; } - NV_SUSPEND(drm, "suspending kernel object tree...\n"); + NV_INFO(drm, "suspending kernel object tree...\n"); ret = nouveau_client_fini(&drm->client.base, true); if (ret) goto fail_client; @@ -543,8 +566,12 @@ fail_client: nouveau_client_init(&cli->base); } + if (drm->fence && nouveau_fence(drm)->resume) + nouveau_fence(drm)->resume(drm); + +fail_display: if (dev->mode_config.num_crtc) { - NV_SUSPEND(drm, "resuming display...\n"); + NV_INFO(drm, "resuming display...\n"); nouveau_display_resume(dev); } return ret; @@ -563,16 +590,13 @@ int nouveau_pmops_suspend(struct device *dev) if (drm_dev->mode_config.num_crtc) nouveau_fbcon_set_suspend(drm_dev, 1); - nv_suspend_set_printk_level(NV_DBG_INFO); - ret = nouveau_do_suspend(drm_dev); + ret = nouveau_do_suspend(drm_dev, false); if (ret) return ret; pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); - nv_suspend_set_printk_level(NV_DBG_DEBUG); - return 0; } @@ -582,15 +606,15 @@ nouveau_do_resume(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; - NV_SUSPEND(drm, "re-enabling device...\n"); + NV_INFO(drm, "re-enabling device...\n"); nouveau_agp_reset(drm); - NV_SUSPEND(drm, "resuming kernel object tree...\n"); + NV_INFO(drm, "resuming kernel object tree...\n"); nouveau_client_init(&drm->client.base); nouveau_agp_init(drm); - NV_SUSPEND(drm, "resuming client object trees...\n"); + NV_INFO(drm, "resuming client object trees...\n"); if (drm->fence && nouveau_fence(drm)->resume) nouveau_fence(drm)->resume(drm); @@ -599,10 +623,9 @@ nouveau_do_resume(struct drm_device *dev) } nouveau_run_vbios_init(dev); - nouveau_pm_resume(dev); if (dev->mode_config.num_crtc) { - NV_SUSPEND(drm, "resuming display...\n"); + NV_INFO(drm, "resuming display...\n"); nouveau_display_repin(dev); } @@ -626,19 +649,15 @@ int nouveau_pmops_resume(struct device *dev) return ret; pci_set_master(pdev); - nv_suspend_set_printk_level(NV_DBG_INFO); ret = nouveau_do_resume(drm_dev); - if (ret) { - nv_suspend_set_printk_level(NV_DBG_DEBUG); + if (ret) return ret; - } - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 0); - nouveau_fbcon_zfill_all(drm_dev); - if (drm_dev->mode_config.num_crtc) + if (drm_dev->mode_config.num_crtc) { nouveau_display_resume(drm_dev); - nv_suspend_set_printk_level(NV_DBG_DEBUG); + nouveau_fbcon_set_suspend(drm_dev, 0); + } + return 0; } @@ -648,12 +667,10 @@ static int nouveau_pmops_freeze(struct device *dev) struct drm_device *drm_dev = pci_get_drvdata(pdev); int ret; - nv_suspend_set_printk_level(NV_DBG_INFO); if (drm_dev->mode_config.num_crtc) nouveau_fbcon_set_suspend(drm_dev, 1); - ret = nouveau_do_suspend(drm_dev); - nv_suspend_set_printk_level(NV_DBG_DEBUG); + ret = nouveau_do_suspend(drm_dev, false); return ret; } @@ -663,18 +680,15 @@ static int nouveau_pmops_thaw(struct device *dev) struct drm_device *drm_dev = pci_get_drvdata(pdev); int ret; - nv_suspend_set_printk_level(NV_DBG_INFO); ret = nouveau_do_resume(drm_dev); - if (ret) { - nv_suspend_set_printk_level(NV_DBG_DEBUG); + if (ret) return ret; - } - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 0); - nouveau_fbcon_zfill_all(drm_dev); - if (drm_dev->mode_config.num_crtc) + + if (drm_dev->mode_config.num_crtc) { nouveau_display_resume(drm_dev); - nv_suspend_set_printk_level(NV_DBG_DEBUG); + nouveau_fbcon_set_suspend(drm_dev, 0); + } + return 0; } @@ -682,7 +696,6 @@ static int nouveau_pmops_thaw(struct device *dev) static int nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) { - struct pci_dev *pdev = dev->pdev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; char name[32], tmpname[TASK_COMM_LEN]; @@ -690,13 +703,15 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) /* need to bring up power immediately if opening device */ ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return ret; get_task_comm(tmpname, current); snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); - ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli); + ret = nouveau_cli_create(nouveau_name(dev), name, sizeof(*cli), + (void **)&cli); + if (ret) goto out_suspend; @@ -773,7 +788,7 @@ long nouveau_drm_ioctl(struct file *filp, dev = file_priv->minor->dev; ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return ret; ret = drm_ioctl(filp, cmd, arg); @@ -816,8 +831,10 @@ driver = { #endif .get_vblank_counter = drm_vblank_count, - .enable_vblank = nouveau_drm_vblank_enable, - .disable_vblank = nouveau_drm_vblank_disable, + .enable_vblank = nouveau_display_vblank_enable, + .disable_vblank = nouveau_display_vblank_disable, + .get_scanout_position = nouveau_display_scanoutpos, + .get_vblank_timestamp = nouveau_display_vblstamp, .ioctls = nouveau_ioctls, .num_ioctls = ARRAY_SIZE(nouveau_ioctls), @@ -834,7 +851,6 @@ driver = { .gem_prime_vmap = nouveau_gem_prime_vmap, .gem_prime_vunmap = nouveau_gem_prime_vunmap, - .gem_init_object = nouveau_gem_object_new, .gem_free_object = nouveau_gem_object_del, .gem_open_object = nouveau_gem_object_open, .gem_close_object = nouveau_gem_object_close, @@ -876,13 +892,23 @@ static int nouveau_pmops_runtime_suspend(struct device *dev) struct drm_device *drm_dev = pci_get_drvdata(pdev); int ret; - if (nouveau_runtime_pm == 0) - return -EINVAL; + if (nouveau_runtime_pm == 0) { + pm_runtime_forbid(dev); + return -EBUSY; + } + /* are we optimus enabled? */ + if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) { + DRM_DEBUG_DRIVER("failing to power off - not optimus\n"); + pm_runtime_forbid(dev); + return -EBUSY; + } + + nv_debug_level(SILENT); drm_kms_helper_poll_disable(drm_dev); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); nouveau_switcheroo_optimus_dsm(); - ret = nouveau_do_suspend(drm_dev); + ret = nouveau_do_suspend(drm_dev, true); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3cold); @@ -908,13 +934,12 @@ static int nouveau_pmops_runtime_resume(struct device *dev) pci_set_master(pdev); ret = nouveau_do_resume(drm_dev); - if (drm_dev->mode_config.num_crtc) - nouveau_display_resume(drm_dev); drm_kms_helper_poll_enable(drm_dev); /* do magic */ nv_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); return ret; } @@ -925,12 +950,15 @@ static int nouveau_pmops_runtime_idle(struct device *dev) struct nouveau_drm *drm = nouveau_drm(drm_dev); struct drm_crtc *crtc; - if (nouveau_runtime_pm == 0) + if (nouveau_runtime_pm == 0) { + pm_runtime_forbid(dev); return -EBUSY; + } /* are we optimus enabled? */ if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) { DRM_DEBUG_DRIVER("failing to power off - not optimus\n"); + pm_runtime_forbid(dev); return -EBUSY; } @@ -976,6 +1004,25 @@ nouveau_drm_pci_driver = { .driver.pm = &nouveau_pm_ops, }; +int nouveau_drm_platform_probe(struct platform_device *pdev) +{ + struct nouveau_device *device; + int ret; + + ret = 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; + } + + return ret; +} + static int __init nouveau_drm_init(void) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 994fd6ec373..7efbafaf7c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -51,10 +51,13 @@ struct nouveau_drm_tile { }; enum nouveau_drm_handle { - NVDRM_CLIENT = 0xffffffff, - NVDRM_DEVICE = 0xdddddddd, - NVDRM_PUSH = 0xbbbb0000, /* |= client chid */ - NVDRM_CHAN = 0xcccc0000, /* |= client chid */ + NVDRM_CLIENT = 0xffffffff, + NVDRM_DEVICE = 0xdddddddd, + NVDRM_CONTROL = 0xdddddddc, + NVDRM_DISPLAY = 0xd1500000, + NVDRM_PUSH = 0xbbbb0000, /* |= client chid */ + NVDRM_CHAN = 0xcccc0000, /* |= client chid */ + NVDRM_NVSW = 0x55550000, }; struct nouveau_cli { @@ -127,10 +130,10 @@ struct nouveau_drm { struct nvbios vbios; struct nouveau_display *display; struct backlight_device *backlight; - struct nouveau_eventh vblank[4]; /* power management */ - struct nouveau_pm *pm; + struct nouveau_hwmon *hwmon; + struct nouveau_sysfs *sysfs; /* display power reference */ bool have_disp_power_ref; @@ -154,15 +157,11 @@ nouveau_dev(struct drm_device *dev) int nouveau_pmops_suspend(struct device *); int nouveau_pmops_resume(struct device *); -#define NV_SUSPEND(cli, fmt, args...) nv_suspend((cli), fmt, ##args) #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...) do { \ - if (drm_debug & DRM_UT_DRIVER) \ - nv_info((cli), fmt, ##args); \ -} while (0) +#define NV_DEBUG(cli, fmt, args...) nv_debug((cli), fmt, ##args) extern int nouveau_modeset; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 24660c0f713..5f0e37fc284 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -46,6 +46,7 @@ struct nouveau_encoder { /* different to drm_encoder.crtc, this reflects what's * actually programmed on the hw, not the proposed crtc */ struct drm_crtc *crtc; + u32 ctrl; struct drm_display_mode mode; int last_dpms; @@ -84,9 +85,7 @@ get_slave_funcs(struct drm_encoder *enc) } /* nouveau_dp.c */ -bool nouveau_dp_detect(struct drm_encoder *); -void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate, - struct nouveau_object *); +int nouveau_dp_detect(struct nouveau_encoder *); struct nouveau_connector * nouveau_encoder_connector_get(struct nouveau_encoder *encoder); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index a86ecf65c16..191665ee7f5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -420,7 +420,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_vma_del(nouveau_fb->nvbo, &nouveau_fb->vma); nouveau_bo_unpin(nouveau_fb->nvbo); - drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); + drm_gem_object_unreference_unlocked(&nouveau_fb->nvbo->gem); nouveau_fb->nvbo = NULL; } drm_fb_helper_fini(&fbcon->helper); @@ -503,34 +503,38 @@ nouveau_fbcon_fini(struct drm_device *dev) drm->fbcon = NULL; } -void nouveau_fbcon_save_disable_accel(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - 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) +void +nouveau_fbcon_save_disable_accel(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; + if (drm->fbcon) { + drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; + drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; + } } -void nouveau_fbcon_set_suspend(struct drm_device *dev, int state) +void +nouveau_fbcon_restore_accel(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - console_lock(); - if (state == 0) - nouveau_fbcon_save_disable_accel(dev); - fb_set_suspend(drm->fbcon->helper.fbdev, state); - if (state == 1) - nouveau_fbcon_restore_accel(dev); - console_unlock(); + if (drm->fbcon) { + drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; + } } -void nouveau_fbcon_zfill_all(struct drm_device *dev) +void +nouveau_fbcon_set_suspend(struct drm_device *dev, int state) { struct nouveau_drm *drm = nouveau_drm(dev); - nouveau_fbcon_zfill(dev, drm->fbcon); + if (drm->fbcon) { + 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); + } + console_unlock(); + } } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index fdfc0c94fbc..fcff797d208 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -61,7 +61,6 @@ 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_zfill_all(struct drm_device *dev); void nouveau_fbcon_save_disable_accel(struct drm_device *dev); void nouveau_fbcon_restore_accel(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index be3149932c2..ab5ea3b0d66 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -143,7 +143,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) int ret; fence->channel = chan; - fence->timeout = jiffies + (15 * DRM_HZ); + fence->timeout = jiffies + (15 * HZ); fence->sequence = ++fctx->sequence; ret = fctx->emit(fence); @@ -165,17 +165,11 @@ nouveau_fence_done(struct nouveau_fence *fence) return !fence->channel; } -struct nouveau_fence_uevent { - struct nouveau_eventh handler; - struct nouveau_fence_priv *priv; -}; - static int -nouveau_fence_wait_uevent_handler(struct nouveau_eventh *event, int index) +nouveau_fence_wait_uevent_handler(void *data, u32 type, int index) { - struct nouveau_fence_uevent *uevent = - container_of(event, struct nouveau_fence_uevent, handler); - wake_up_all(&uevent->priv->waiting); + struct nouveau_fence_priv *priv = data; + wake_up_all(&priv->waiting); return NVKM_EVENT_KEEP; } @@ -186,13 +180,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) 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_fence_uevent uevent = { - .handler.func = nouveau_fence_wait_uevent_handler, - .priv = priv, - }; + struct nouveau_eventh *handler; int ret = 0; - nouveau_event_get(pfifo->uevent, 0, &uevent.handler); + ret = nouveau_event_new(pfifo->uevent, 1, 0, + nouveau_fence_wait_uevent_handler, + priv, &handler); + if (ret) + return ret; + + nouveau_event_get(handler); if (fence->timeout) { unsigned long timeout = fence->timeout - jiffies; @@ -224,7 +221,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) } } - nouveau_event_put(pfifo->uevent, 0, &uevent.handler); + nouveau_event_ref(NULL, &handler); if (unlikely(ret < 0)) return ret; @@ -309,7 +306,8 @@ nouveau_fence_unref(struct nouveau_fence **pfence) struct nouveau_fence * nouveau_fence_ref(struct nouveau_fence *fence) { - kref_get(&fence->kref); + if (fence) + kref_get(&fence->kref); return fence; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index f32b71238c0..c90c0dc0afe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -34,29 +34,20 @@ #include "nouveau_ttm.h" #include "nouveau_gem.h" -int -nouveau_gem_object_new(struct drm_gem_object *gem) -{ - return 0; -} - void nouveau_gem_object_del(struct drm_gem_object *gem) { - struct nouveau_bo *nvbo = gem->driver_private; + struct nouveau_bo *nvbo = nouveau_gem_object(gem); struct ttm_buffer_object *bo = &nvbo->bo; - if (!nvbo) - return; - nvbo->gem = NULL; - if (gem->import_attach) drm_prime_gem_destroy(gem, nvbo->bo.sg); - ttm_bo_unref(&bo); - drm_gem_object_release(gem); - kfree(gem); + + /* reset filp so nouveau_bo_del_ttm() can test for it */ + gem->filp = NULL; + ttm_bo_unref(&bo); } int @@ -115,8 +106,7 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma) if (mapped) { spin_lock(&nvbo->bo.bdev->fence_lock); - if (nvbo->bo.sync_obj) - fence = nouveau_fence_ref(nvbo->bo.sync_obj); + fence = nouveau_fence_ref(nvbo->bo.sync_obj); spin_unlock(&nvbo->bo.bdev->fence_lock); } @@ -186,14 +176,15 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain, if (nv_device(drm->device)->card_type >= NV_50) nvbo->valid_domains &= domain; - nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size); - if (!nvbo->gem) { + /* Initialize the embedded gem-object. We return a single gem-reference + * to the caller, instead of a normal nouveau_bo ttm reference. */ + ret = drm_gem_object_init(dev, &nvbo->gem, nvbo->bo.mem.size); + if (ret) { nouveau_bo_ref(NULL, pnvbo); return -ENOMEM; } - nvbo->bo.persistent_swap_storage = nvbo->gem->filp; - nvbo->gem->driver_private = nvbo; + nvbo->bo.persistent_swap_storage = nvbo->gem.filp; return 0; } @@ -237,8 +228,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, struct nouveau_bo *nvbo = NULL; int ret = 0; - drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping; - if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { NV_ERROR(cli, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; @@ -250,15 +239,15 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, if (ret) return ret; - ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle); + ret = drm_gem_handle_create(file_priv, &nvbo->gem, &req->info.handle); if (ret == 0) { - ret = nouveau_gem_info(file_priv, nvbo->gem, &req->info); + ret = nouveau_gem_info(file_priv, &nvbo->gem, &req->info); if (ret) drm_gem_handle_delete(file_priv, req->info.handle); } /* drop reference from allocate - handle holds it now */ - drm_gem_object_unreference_unlocked(nvbo->gem); + drm_gem_object_unreference_unlocked(&nvbo->gem); return ret; } @@ -266,7 +255,7 @@ static int nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, uint32_t write_domains, uint32_t valid_domains) { - struct nouveau_bo *nvbo = gem->driver_private; + struct nouveau_bo *nvbo = nouveau_gem_object(gem); struct ttm_buffer_object *bo = &nvbo->bo; uint32_t domains = valid_domains & nvbo->valid_domains & (write_domains ? write_domains : read_domains); @@ -317,7 +306,8 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence, list_for_each_safe(entry, tmp, list) { nvbo = list_entry(entry, struct nouveau_bo, entry); - nouveau_bo_fence(nvbo, fence); + if (likely(fence)) + nouveau_bo_fence(nvbo, fence); if (unlikely(nvbo->validate_mapped)) { ttm_bo_kunmap(&nvbo->kmap); @@ -327,7 +317,7 @@ 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); - drm_gem_object_unreference_unlocked(nvbo->gem); + drm_gem_object_unreference_unlocked(&nvbo->gem); } } @@ -376,7 +366,7 @@ retry: validate_fini(op, NULL); return -ENOENT; } - nvbo = gem->driver_private; + nvbo = nouveau_gem_object(gem); if (nvbo == res_bo) { res_bo = NULL; drm_gem_object_unreference_unlocked(gem); @@ -446,8 +436,7 @@ validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo) int ret = 0; spin_lock(&nvbo->bo.bdev->fence_lock); - if (nvbo->bo.sync_obj) - fence = nouveau_fence_ref(nvbo->bo.sync_obj); + fence = nouveau_fence_ref(nvbo->bo.sync_obj); spin_unlock(&nvbo->bo.bdev->fence_lock); if (fence) { @@ -472,13 +461,7 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, list_for_each_entry(nvbo, list, entry) { struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; - ret = validate_sync(chan, nvbo); - if (unlikely(ret)) { - NV_ERROR(cli, "fail pre-validate sync\n"); - return ret; - } - - ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains, + ret = nouveau_gem_set_domain(&nvbo->gem, b->read_domains, b->write_domains, b->valid_domains); if (unlikely(ret)) { @@ -515,7 +498,7 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, b->presumed.valid = 0; relocs++; - if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index].presumed, + if (copy_to_user(&upbbo[nvbo->pbbo_index].presumed, &b->presumed, sizeof(b->presumed))) return -EFAULT; } @@ -602,7 +585,7 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size) if (!mem) return ERR_PTR(-ENOMEM); - if (DRM_COPY_FROM_USER(mem, userptr, size)) { + if (copy_from_user(mem, userptr, size)) { u_free(mem); return ERR_PTR(-EFAULT); } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.h b/drivers/gpu/drm/nouveau/nouveau_gem.h index 502e4290aa8..7caca057bc3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.h +++ b/drivers/gpu/drm/nouveau/nouveau_gem.h @@ -12,14 +12,13 @@ static inline struct nouveau_bo * nouveau_gem_object(struct drm_gem_object *gem) { - return gem ? gem->driver_private : NULL; + return gem ? container_of(gem, struct nouveau_bo, gem) : NULL; } /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, int size, int align, uint32_t domain, uint32_t tile_mode, uint32_t tile_flags, struct nouveau_bo **); -extern int nouveau_gem_object_new(struct drm_gem_object *); extern void nouveau_gem_object_del(struct drm_gem_object *); extern int nouveau_gem_object_open(struct drm_gem_object *, struct drm_file *); extern void nouveau_gem_object_close(struct drm_gem_object *, diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 936b442a6ab..19fd767bab1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -32,369 +32,12 @@ #include <drm/drmP.h> #include "nouveau_drm.h" -#include "nouveau_pm.h" +#include "nouveau_hwmon.h" #include <subdev/gpio.h> #include <subdev/timer.h> #include <subdev/therm.h> -MODULE_PARM_DESC(perflvl, "Performance level (default: boot)"); -static char *nouveau_perflvl; -module_param_named(perflvl, nouveau_perflvl, charp, 0400); - -MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)"); -static int nouveau_perflvl_wr; -module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); - -static int -nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl, - struct nouveau_pm_level *a, struct nouveau_pm_level *b) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); - int ret; - - /*XXX: not on all boards, we should control based on temperature - * on recent boards.. or maybe on some other factor we don't - * know about? - */ - if (therm && therm->fan_set && - a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) { - ret = therm->fan_set(therm, perflvl->fanspeed); - if (ret && ret != -ENODEV) { - NV_ERROR(drm, "fanspeed set failed: %d\n", ret); - } - } - - if (pm->voltage.supported && pm->voltage_set) { - if (perflvl->volt_min && b->volt_min > a->volt_min) { - ret = pm->voltage_set(dev, perflvl->volt_min); - if (ret) { - NV_ERROR(drm, "voltage set failed: %d\n", ret); - return ret; - } - } - } - - return 0; -} - -static int -nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - void *state; - int ret; - - if (perflvl == pm->cur) - return 0; - - ret = nouveau_pm_perflvl_aux(dev, perflvl, pm->cur, perflvl); - if (ret) - return ret; - - state = pm->clocks_pre(dev, perflvl); - if (IS_ERR(state)) { - ret = PTR_ERR(state); - goto error; - } - ret = pm->clocks_set(dev, state); - if (ret) - goto error; - - ret = nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur); - if (ret) - return ret; - - pm->cur = perflvl; - return 0; - -error: - /* restore the fan speed and voltage before leaving */ - nouveau_pm_perflvl_aux(dev, perflvl, perflvl, pm->cur); - return ret; -} - -void -nouveau_pm_trigger(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_timer *ptimer = nouveau_timer(drm->device); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_profile *profile = NULL; - struct nouveau_pm_level *perflvl = NULL; - int ret; - - /* select power profile based on current power source */ - if (power_supply_is_system_supplied()) - profile = pm->profile_ac; - else - profile = pm->profile_dc; - - if (profile != pm->profile) { - pm->profile->func->fini(pm->profile); - pm->profile = profile; - pm->profile->func->init(pm->profile); - } - - /* select performance level based on profile */ - perflvl = profile->func->select(profile); - - /* change perflvl, if necessary */ - if (perflvl != pm->cur) { - u64 time0 = ptimer->read(ptimer); - - NV_INFO(drm, "setting performance level: %d", perflvl->id); - ret = nouveau_pm_perflvl_set(dev, perflvl); - if (ret) - NV_INFO(drm, "> reclocking failed: %d\n\n", ret); - - NV_INFO(drm, "> reclocking took %lluns\n\n", - ptimer->read(ptimer) - time0); - } -} - -static struct nouveau_pm_profile * -profile_find(struct drm_device *dev, const char *string) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_profile *profile; - - list_for_each_entry(profile, &pm->profiles, head) { - if (!strncmp(profile->name, string, sizeof(profile->name))) - return profile; - } - - return NULL; -} - -static int -nouveau_pm_profile_set(struct drm_device *dev, const char *profile) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_profile *ac = NULL, *dc = NULL; - char string[16], *cur = string, *ptr; - - /* safety precaution, for now */ - if (nouveau_perflvl_wr != 7777) - return -EPERM; - - strncpy(string, profile, sizeof(string)); - string[sizeof(string) - 1] = 0; - if ((ptr = strchr(string, '\n'))) - *ptr = '\0'; - - ptr = strsep(&cur, ","); - if (ptr) - ac = profile_find(dev, ptr); - - ptr = strsep(&cur, ","); - if (ptr) - dc = profile_find(dev, ptr); - else - dc = ac; - - if (ac == NULL || dc == NULL) - return -EINVAL; - - pm->profile_ac = ac; - pm->profile_dc = dc; - nouveau_pm_trigger(dev); - return 0; -} - -static void -nouveau_pm_static_dummy(struct nouveau_pm_profile *profile) -{ -} - -static struct nouveau_pm_level * -nouveau_pm_static_select(struct nouveau_pm_profile *profile) -{ - return container_of(profile, struct nouveau_pm_level, profile); -} - -const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = { - .destroy = nouveau_pm_static_dummy, - .init = nouveau_pm_static_dummy, - .fini = nouveau_pm_static_dummy, - .select = nouveau_pm_static_select, -}; - -static int -nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_therm *therm = nouveau_therm(drm->device); - int ret; - - memset(perflvl, 0, sizeof(*perflvl)); - - if (pm->clocks_get) { - ret = pm->clocks_get(dev, perflvl); - if (ret) - return ret; - } - - if (pm->voltage.supported && pm->voltage_get) { - ret = pm->voltage_get(dev); - if (ret > 0) { - perflvl->volt_min = ret; - perflvl->volt_max = ret; - } - } - - if (therm && therm->fan_get) { - ret = therm->fan_get(therm); - if (ret >= 0) - perflvl->fanspeed = ret; - } - - nouveau_mem_timing_read(dev, &perflvl->timing); - return 0; -} - -static void -nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) -{ - char c[16], s[16], v[32], f[16], m[16]; - - c[0] = '\0'; - if (perflvl->core) - snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000); - - s[0] = '\0'; - if (perflvl->shader) - snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); - - m[0] = '\0'; - if (perflvl->memory) - snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000); - - v[0] = '\0'; - if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) { - snprintf(v, sizeof(v), " voltage %dmV-%dmV", - perflvl->volt_min / 1000, perflvl->volt_max / 1000); - } else - if (perflvl->volt_min) { - snprintf(v, sizeof(v), " voltage %dmV", - perflvl->volt_min / 1000); - } - - f[0] = '\0'; - if (perflvl->fanspeed) - snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); - - snprintf(ptr, len, "%s%s%s%s%s\n", c, s, m, v, f); -} - -static ssize_t -nouveau_pm_get_perflvl_info(struct device *d, - struct device_attribute *a, char *buf) -{ - struct nouveau_pm_level *perflvl = - container_of(a, struct nouveau_pm_level, dev_attr); - char *ptr = buf; - int len = PAGE_SIZE; - - snprintf(ptr, len, "%d:", perflvl->id); - ptr += strlen(buf); - len -= strlen(buf); - - nouveau_pm_perflvl_info(perflvl, ptr, len); - return strlen(buf); -} - -static ssize_t -nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) -{ - struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_level cur; - int len = PAGE_SIZE, ret; - char *ptr = buf; - - snprintf(ptr, len, "profile: %s, %s\nc:", - pm->profile_ac->name, pm->profile_dc->name); - ptr += strlen(buf); - len -= strlen(buf); - - ret = nouveau_pm_perflvl_get(dev, &cur); - if (ret == 0) - nouveau_pm_perflvl_info(&cur, ptr, len); - return strlen(buf); -} - -static ssize_t -nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, - const char *buf, size_t count) -{ - struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); - int ret; - - ret = nouveau_pm_profile_set(dev, buf); - if (ret) - return ret; - return strlen(buf); -} - -static DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, - nouveau_pm_get_perflvl, nouveau_pm_set_perflvl); - -static int -nouveau_sysfs_init(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_pm *pm = nouveau_pm(dev); - struct device *d = &dev->pdev->dev; - int ret, i; - - ret = device_create_file(d, &dev_attr_performance_level); - if (ret) - return ret; - - for (i = 0; i < pm->nr_perflvl; i++) { - struct nouveau_pm_level *perflvl = &pm->perflvl[i]; - - perflvl->dev_attr.attr.name = perflvl->name; - perflvl->dev_attr.attr.mode = S_IRUGO; - perflvl->dev_attr.show = nouveau_pm_get_perflvl_info; - perflvl->dev_attr.store = NULL; - sysfs_attr_init(&perflvl->dev_attr.attr); - - ret = device_create_file(d, &perflvl->dev_attr); - if (ret) { - NV_ERROR(drm, "failed pervlvl %d sysfs: %d\n", - perflvl->id, i); - perflvl->dev_attr.attr.name = NULL; - nouveau_pm_fini(dev); - return ret; - } - } - - return 0; -} - -static void -nouveau_sysfs_fini(struct drm_device *dev) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - struct device *d = &dev->pdev->dev; - int i; - - device_remove_file(d, &dev_attr_performance_level); - for (i = 0; i < pm->nr_perflvl; i++) { - struct nouveau_pm_level *pl = &pm->perflvl[i]; - - if (!pl->dev_attr.attr.name) - break; - - device_remove_file(d, &pl->dev_attr); - } -} - #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) @@ -740,8 +383,9 @@ nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, long value; int ret; - if (strict_strtol(buf, 10, &value) == -EINVAL) - return -EINVAL; + ret = kstrtol(buf, 10, &value); + if (ret) + return ret; ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value); if (ret) @@ -778,9 +422,6 @@ nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a, int ret = -ENODEV; long value; - if (nouveau_perflvl_wr != 7777) - return -EPERM; - if (kstrtol(buf, 10, &value) == -EINVAL) return -EINVAL; @@ -919,17 +560,21 @@ static const struct attribute_group hwmon_pwm_fan_attrgroup = { }; #endif -static int +int nouveau_hwmon_init(struct drm_device *dev) { - struct nouveau_pm *pm = nouveau_pm(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_hwmon *hwmon; struct device *hwmon_dev; int ret = 0; + hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + hwmon->dev = dev; + if (!therm || !therm->temp_get || !therm->attr_get || !therm->attr_set) return -ENODEV; @@ -943,18 +588,14 @@ nouveau_hwmon_init(struct drm_device *dev) /* set the default attributes */ ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup); - if (ret) { - if (ret) - goto error; - } + if (ret) + goto error; /* if the card has a working thermal sensor */ if (therm->temp_get(therm) >= 0) { ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup); - if (ret) { - if (ret) - goto error; - } + if (ret) + goto error; } /* if the card has a pwm fan */ @@ -976,199 +617,36 @@ nouveau_hwmon_init(struct drm_device *dev) goto error; } - pm->hwmon = hwmon_dev; + hwmon->hwmon = hwmon_dev; return 0; error: NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret); hwmon_device_unregister(hwmon_dev); - pm->hwmon = NULL; + hwmon->hwmon = NULL; return ret; #else - pm->hwmon = NULL; return 0; #endif } -static void +void nouveau_hwmon_fini(struct drm_device *dev) { #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) - struct nouveau_pm *pm = nouveau_pm(dev); - - if (pm->hwmon) { - sysfs_remove_group(&pm->hwmon->kobj, &hwmon_default_attrgroup); - sysfs_remove_group(&pm->hwmon->kobj, &hwmon_temp_attrgroup); - sysfs_remove_group(&pm->hwmon->kobj, &hwmon_pwm_fan_attrgroup); - sysfs_remove_group(&pm->hwmon->kobj, &hwmon_fan_rpm_attrgroup); + struct nouveau_hwmon *hwmon = nouveau_hwmon(dev); - hwmon_device_unregister(pm->hwmon); - } -#endif -} - -#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) -static int -nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) -{ - struct nouveau_pm *pm = container_of(nb, struct nouveau_pm, acpi_nb); - struct nouveau_drm *drm = nouveau_drm(pm->dev); - struct acpi_bus_event *entry = (struct acpi_bus_event *)data; - - if (strcmp(entry->device_class, "ac_adapter") == 0) { - bool ac = power_supply_is_system_supplied(); - - NV_DEBUG(drm, "power supply changed: %s\n", ac ? "AC" : "DC"); - nouveau_pm_trigger(pm->dev); - } - - return NOTIFY_OK; -} -#endif - -int -nouveau_pm_init(struct drm_device *dev) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_pm *pm; - char info[256]; - int ret, i; - - pm = drm->pm = kzalloc(sizeof(*pm), GFP_KERNEL); - if (!pm) - return -ENOMEM; - - pm->dev = dev; - - if (device->card_type < NV_40) { - pm->clocks_get = nv04_pm_clocks_get; - pm->clocks_pre = nv04_pm_clocks_pre; - pm->clocks_set = nv04_pm_clocks_set; - if (nouveau_gpio(drm->device)) { - pm->voltage_get = nouveau_voltage_gpio_get; - pm->voltage_set = nouveau_voltage_gpio_set; - } - } else - if (device->card_type < NV_50) { - pm->clocks_get = nv40_pm_clocks_get; - pm->clocks_pre = nv40_pm_clocks_pre; - pm->clocks_set = nv40_pm_clocks_set; - pm->voltage_get = nouveau_voltage_gpio_get; - pm->voltage_set = nouveau_voltage_gpio_set; - } else - if (device->card_type < NV_C0) { - if (device->chipset < 0xa3 || - device->chipset == 0xaa || - device->chipset == 0xac) { - pm->clocks_get = nv50_pm_clocks_get; - pm->clocks_pre = nv50_pm_clocks_pre; - pm->clocks_set = nv50_pm_clocks_set; - } else { - pm->clocks_get = nva3_pm_clocks_get; - pm->clocks_pre = nva3_pm_clocks_pre; - pm->clocks_set = nva3_pm_clocks_set; - } - pm->voltage_get = nouveau_voltage_gpio_get; - pm->voltage_set = nouveau_voltage_gpio_set; - } else - if (device->card_type < NV_E0) { - pm->clocks_get = nvc0_pm_clocks_get; - pm->clocks_pre = nvc0_pm_clocks_pre; - pm->clocks_set = nvc0_pm_clocks_set; - pm->voltage_get = nouveau_voltage_gpio_get; - pm->voltage_set = nouveau_voltage_gpio_set; - } - - - /* parse aux tables from vbios */ - nouveau_volt_init(dev); - - INIT_LIST_HEAD(&pm->profiles); - - /* determine current ("boot") performance level */ - ret = nouveau_pm_perflvl_get(dev, &pm->boot); - if (ret) { - NV_ERROR(drm, "failed to determine boot perflvl\n"); - return ret; - } + if (hwmon->hwmon) { + sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_default_attrgroup); + sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_temp_attrgroup); + sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_pwm_fan_attrgroup); + sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_fan_rpm_attrgroup); - strncpy(pm->boot.name, "boot", 4); - strncpy(pm->boot.profile.name, "boot", 4); - pm->boot.profile.func = &nouveau_pm_static_profile_func; - - list_add(&pm->boot.profile.head, &pm->profiles); - - pm->profile_ac = &pm->boot.profile; - pm->profile_dc = &pm->boot.profile; - pm->profile = &pm->boot.profile; - pm->cur = &pm->boot; - - /* add performance levels from vbios */ - nouveau_perf_init(dev); - - /* display available performance levels */ - NV_INFO(drm, "%d available performance level(s)\n", pm->nr_perflvl); - for (i = 0; i < pm->nr_perflvl; i++) { - nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); - NV_INFO(drm, "%d:%s", pm->perflvl[i].id, info); + hwmon_device_unregister(hwmon->hwmon); } - nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); - NV_INFO(drm, "c:%s", info); - - /* switch performance levels now if requested */ - if (nouveau_perflvl != NULL) - nouveau_pm_profile_set(dev, nouveau_perflvl); - - nouveau_sysfs_init(dev); - nouveau_hwmon_init(dev); -#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) - pm->acpi_nb.notifier_call = nouveau_pm_acpi_event; - register_acpi_notifier(&pm->acpi_nb); + nouveau_drm(dev)->hwmon = NULL; + kfree(hwmon); #endif - - return 0; -} - -void -nouveau_pm_fini(struct drm_device *dev) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_profile *profile, *tmp; - - list_for_each_entry_safe(profile, tmp, &pm->profiles, head) { - list_del(&profile->head); - profile->func->destroy(profile); - } - - if (pm->cur != &pm->boot) - nouveau_pm_perflvl_set(dev, &pm->boot); - - nouveau_perf_fini(dev); - nouveau_volt_fini(dev); - -#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY) - unregister_acpi_notifier(&pm->acpi_nb); -#endif - nouveau_hwmon_fini(dev); - nouveau_sysfs_fini(dev); - - nouveau_drm(dev)->pm = NULL; - kfree(pm); -} - -void -nouveau_pm_resume(struct drm_device *dev) -{ - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_level *perflvl; - - if (!pm->cur || pm->cur == &pm->boot) - return; - - perflvl = pm->cur; - pm->cur = &pm->boot; - nouveau_pm_perflvl_set(dev, perflvl); } diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.h b/drivers/gpu/drm/nouveau/nouveau_hwmon.h new file mode 100644 index 00000000000..62ccbb39863 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.h @@ -0,0 +1,43 @@ +/* + * Copyright 2010 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 + */ + +#ifndef __NOUVEAU_PM_H__ +#define __NOUVEAU_PM_H__ + +struct nouveau_hwmon { + struct drm_device *dev; + struct device *hwmon; +}; + +static inline struct nouveau_hwmon * +nouveau_hwmon(struct drm_device *dev) +{ + return nouveau_drm(dev)->hwmon; +} + +/* nouveau_hwmon.c */ +int nouveau_hwmon_init(struct drm_device *dev); +void nouveau_hwmon_fini(struct drm_device *dev); + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_hwsq.h b/drivers/gpu/drm/nouveau/nouveau_hwsq.h deleted file mode 100644 index 697687593a8..00000000000 --- a/drivers/gpu/drm/nouveau/nouveau_hwsq.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2010 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 - */ - -#ifndef __NOUVEAU_HWSQ_H__ -#define __NOUVEAU_HWSQ_H__ - -struct hwsq_ucode { - u8 data[0x200]; - union { - u8 *u08; - u16 *u16; - u32 *u32; - } ptr; - u16 len; - - u32 reg; - u32 val; -}; - -static inline void -hwsq_init(struct hwsq_ucode *hwsq) -{ - hwsq->ptr.u08 = hwsq->data; - hwsq->reg = 0xffffffff; - hwsq->val = 0xffffffff; -} - -static inline void -hwsq_fini(struct hwsq_ucode *hwsq) -{ - do { - *hwsq->ptr.u08++ = 0x7f; - hwsq->len = hwsq->ptr.u08 - hwsq->data; - } while (hwsq->len & 3); - hwsq->ptr.u08 = hwsq->data; -} - -static inline void -hwsq_usec(struct hwsq_ucode *hwsq, u8 usec) -{ - u32 shift = 0; - while (usec & ~3) { - usec >>= 2; - shift++; - } - - *hwsq->ptr.u08++ = (shift << 2) | usec; -} - -static inline void -hwsq_setf(struct hwsq_ucode *hwsq, u8 flag, int val) -{ - flag += 0x80; - if (val >= 0) - flag += 0x20; - if (val >= 1) - flag += 0x20; - *hwsq->ptr.u08++ = flag; -} - -static inline void -hwsq_op5f(struct hwsq_ucode *hwsq, u8 v0, u8 v1) -{ - *hwsq->ptr.u08++ = 0x5f; - *hwsq->ptr.u08++ = v0; - *hwsq->ptr.u08++ = v1; -} - -static inline void -hwsq_wr32(struct hwsq_ucode *hwsq, u32 reg, u32 val) -{ - if (val != hwsq->val) { - if ((val & 0xffff0000) == (hwsq->val & 0xffff0000)) { - *hwsq->ptr.u08++ = 0x42; - *hwsq->ptr.u16++ = (val & 0x0000ffff); - } else { - *hwsq->ptr.u08++ = 0xe2; - *hwsq->ptr.u32++ = val; - } - - hwsq->val = val; - } - - if ((reg & 0xffff0000) == (hwsq->reg & 0xffff0000)) { - *hwsq->ptr.u08++ = 0x40; - *hwsq->ptr.u16++ = (reg & 0x0000ffff); - } else { - *hwsq->ptr.u08++ = 0xe0; - *hwsq->ptr.u32++ = reg; - } - hwsq->reg = reg; -} - -#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_ioc32.c b/drivers/gpu/drm/nouveau/nouveau_ioc32.c index c1a7e5a73a2..462679a8fec 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ioc32.c +++ b/drivers/gpu/drm/nouveau/nouveau_ioc32.c @@ -57,7 +57,7 @@ long nouveau_compat_ioctl(struct file *filp, unsigned int cmd, return drm_compat_ioctl(filp, cmd, arg); #if 0 - if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls)) + if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(mga_compat_ioctls)) fn = nouveau_compat_ioctls[nr - DRM_COMMAND_BASE]; #endif if (fn != NULL) diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c deleted file mode 100644 index 4f6a572f225..00000000000 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ /dev/null @@ -1,647 +0,0 @@ -/* - * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. - * Copyright 2005 Stephane Marchesin - * - * The Weather Channel (TM) funded Tungsten Graphics to develop the - * initial release of the Radeon 8500 driver under the XFree86 license. - * This notice must be preserved. - * - * 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 AND/OR THEIR SUPPLIERS 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> - * Roy Spliet <r.spliet@student.tudelft.nl> - */ - -#include "nouveau_drm.h" -#include "nouveau_pm.h" - -#include <subdev/fb.h> - -static int -nv40_mem_timing_calc(struct drm_device *dev, u32 freq, - struct nouveau_pm_tbl_entry *e, u8 len, - struct nouveau_pm_memtiming *boot, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC); - - /* XXX: I don't trust the -1's and +1's... they must come - * from somewhere! */ - t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 | - 1 << 16 | - (e->tWTR + 2 + (t->tCWL - 1)) << 8 | - (e->tCL + 2 - (t->tCWL - 1)); - - t->reg[2] = 0x20200000 | - ((t->tCWL - 1) << 24 | - e->tRRD << 16 | - e->tRCDWR << 8 | - e->tRCDRD); - - NV_DEBUG(drm, "Entry %d: 220: %08x %08x %08x\n", t->id, - t->reg[0], t->reg[1], t->reg[2]); - return 0; -} - -static int -nv50_mem_timing_calc(struct drm_device *dev, u32 freq, - struct nouveau_pm_tbl_entry *e, u8 len, - struct nouveau_pm_memtiming *boot, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_fb *pfb = nouveau_fb(device); - struct nouveau_drm *drm = nouveau_drm(dev); - struct bit_entry P; - uint8_t unk18 = 1, unk20 = 0, unk21 = 0, tmp7_3; - - if (bit_table(dev, 'P', &P)) - return -EINVAL; - - switch (min(len, (u8) 22)) { - case 22: - unk21 = e->tUNK_21; - case 21: - unk20 = e->tUNK_20; - case 20: - if (e->tCWL > 0) - t->tCWL = e->tCWL; - case 19: - unk18 = e->tUNK_18; - break; - } - - t->reg[0] = (e->tRP << 24 | e->tRAS << 16 | e->tRFC << 8 | e->tRC); - - t->reg[1] = (e->tWR + 2 + (t->tCWL - 1)) << 24 | - max(unk18, (u8) 1) << 16 | - (e->tWTR + 2 + (t->tCWL - 1)) << 8; - - t->reg[2] = ((t->tCWL - 1) << 24 | - e->tRRD << 16 | - e->tRCDWR << 8 | - e->tRCDRD); - - t->reg[4] = e->tUNK_13 << 8 | e->tUNK_13; - - t->reg[5] = (e->tRFC << 24 | max(e->tRCDRD, e->tRCDWR) << 16 | e->tRP); - - t->reg[8] = boot->reg[8] & 0xffffff00; - - if (P.version == 1) { - t->reg[1] |= (e->tCL + 2 - (t->tCWL - 1)); - - t->reg[3] = (0x14 + e->tCL) << 24 | - 0x16 << 16 | - (e->tCL - 1) << 8 | - (e->tCL - 1); - - t->reg[4] |= boot->reg[4] & 0xffff0000; - - t->reg[6] = (0x33 - t->tCWL) << 16 | - t->tCWL << 8 | - (0x2e + e->tCL - t->tCWL); - - t->reg[7] = 0x4000202 | (e->tCL - 1) << 16; - - /* XXX: P.version == 1 only has DDR2 and GDDR3? */ - if (pfb->ram->type == NV_MEM_TYPE_DDR2) { - t->reg[5] |= (e->tCL + 3) << 8; - t->reg[6] |= (t->tCWL - 2) << 8; - t->reg[8] |= (e->tCL - 4); - } else { - t->reg[5] |= (e->tCL + 2) << 8; - t->reg[6] |= t->tCWL << 8; - t->reg[8] |= (e->tCL - 2); - } - } else { - t->reg[1] |= (5 + e->tCL - (t->tCWL)); - - /* XXX: 0xb? 0x30? */ - t->reg[3] = (0x30 + e->tCL) << 24 | - (boot->reg[3] & 0x00ff0000)| - (0xb + e->tCL) << 8 | - (e->tCL - 1); - - t->reg[4] |= (unk20 << 24 | unk21 << 16); - - /* XXX: +6? */ - t->reg[5] |= (t->tCWL + 6) << 8; - - t->reg[6] = (0x5a + e->tCL) << 16 | - (6 - e->tCL + t->tCWL) << 8 | - (0x50 + e->tCL - t->tCWL); - - tmp7_3 = (boot->reg[7] & 0xff000000) >> 24; - t->reg[7] = (tmp7_3 << 24) | - ((tmp7_3 - 6 + e->tCL) << 16) | - 0x202; - } - - NV_DEBUG(drm, "Entry %d: 220: %08x %08x %08x %08x\n", t->id, - t->reg[0], t->reg[1], t->reg[2], t->reg[3]); - NV_DEBUG(drm, " 230: %08x %08x %08x %08x\n", - t->reg[4], t->reg[5], t->reg[6], t->reg[7]); - NV_DEBUG(drm, " 240: %08x\n", t->reg[8]); - return 0; -} - -static int -nvc0_mem_timing_calc(struct drm_device *dev, u32 freq, - struct nouveau_pm_tbl_entry *e, u8 len, - struct nouveau_pm_memtiming *boot, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - if (e->tCWL > 0) - t->tCWL = e->tCWL; - - t->reg[0] = (e->tRP << 24 | (e->tRAS & 0x7f) << 17 | - e->tRFC << 8 | e->tRC); - - t->reg[1] = (boot->reg[1] & 0xff000000) | - (e->tRCDWR & 0x0f) << 20 | - (e->tRCDRD & 0x0f) << 14 | - (t->tCWL << 7) | - (e->tCL & 0x0f); - - t->reg[2] = (boot->reg[2] & 0xff0000ff) | - e->tWR << 16 | e->tWTR << 8; - - t->reg[3] = (e->tUNK_20 & 0x1f) << 9 | - (e->tUNK_21 & 0xf) << 5 | - (e->tUNK_13 & 0x1f); - - t->reg[4] = (boot->reg[4] & 0xfff00fff) | - (e->tRRD&0x1f) << 15; - - NV_DEBUG(drm, "Entry %d: 290: %08x %08x %08x %08x\n", t->id, - t->reg[0], t->reg[1], t->reg[2], t->reg[3]); - NV_DEBUG(drm, " 2a0: %08x\n", t->reg[4]); - return 0; -} - -/** - * MR generation methods - */ - -static int -nouveau_mem_ddr2_mr(struct drm_device *dev, u32 freq, - struct nouveau_pm_tbl_entry *e, u8 len, - struct nouveau_pm_memtiming *boot, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - t->drive_strength = 0; - if (len < 15) { - t->odt = boot->odt; - } else { - t->odt = e->RAM_FT1 & 0x07; - } - - if (e->tCL >= NV_MEM_CL_DDR2_MAX) { - NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL); - return -ERANGE; - } - - if (e->tWR >= NV_MEM_WR_DDR2_MAX) { - NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR); - return -ERANGE; - } - - if (t->odt > 3) { - NV_WARN(drm, "(%u) Invalid odt value, assuming disabled: %x", - t->id, t->odt); - t->odt = 0; - } - - t->mr[0] = (boot->mr[0] & 0x100f) | - (e->tCL) << 4 | - (e->tWR - 1) << 9; - t->mr[1] = (boot->mr[1] & 0x101fbb) | - (t->odt & 0x1) << 2 | - (t->odt & 0x2) << 5; - - NV_DEBUG(drm, "(%u) MR: %08x", t->id, t->mr[0]); - return 0; -} - -static const uint8_t nv_mem_wr_lut_ddr3[NV_MEM_WR_DDR3_MAX] = { - 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0}; - -static int -nouveau_mem_ddr3_mr(struct drm_device *dev, u32 freq, - struct nouveau_pm_tbl_entry *e, u8 len, - struct nouveau_pm_memtiming *boot, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - u8 cl = e->tCL - 4; - - t->drive_strength = 0; - if (len < 15) { - t->odt = boot->odt; - } else { - t->odt = e->RAM_FT1 & 0x07; - } - - if (e->tCL >= NV_MEM_CL_DDR3_MAX || e->tCL < 4) { - NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL); - return -ERANGE; - } - - if (e->tWR >= NV_MEM_WR_DDR3_MAX || e->tWR < 4) { - NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR); - return -ERANGE; - } - - if (e->tCWL < 5) { - NV_WARN(drm, "(%u) Invalid tCWL: %u", t->id, e->tCWL); - return -ERANGE; - } - - t->mr[0] = (boot->mr[0] & 0x180b) | - /* CAS */ - (cl & 0x7) << 4 | - (cl & 0x8) >> 1 | - (nv_mem_wr_lut_ddr3[e->tWR]) << 9; - t->mr[1] = (boot->mr[1] & 0x101dbb) | - (t->odt & 0x1) << 2 | - (t->odt & 0x2) << 5 | - (t->odt & 0x4) << 7; - t->mr[2] = (boot->mr[2] & 0x20ffb7) | (e->tCWL - 5) << 3; - - NV_DEBUG(drm, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[2]); - return 0; -} - -static const uint8_t nv_mem_cl_lut_gddr3[NV_MEM_CL_GDDR3_MAX] = { - 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11}; -static const uint8_t nv_mem_wr_lut_gddr3[NV_MEM_WR_GDDR3_MAX] = { - 0, 0, 0, 0, 0, 2, 3, 8, 9, 10, 11, 0, 0, 1, 1, 0, 3}; - -static int -nouveau_mem_gddr3_mr(struct drm_device *dev, u32 freq, - struct nouveau_pm_tbl_entry *e, u8 len, - struct nouveau_pm_memtiming *boot, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - if (len < 15) { - t->drive_strength = boot->drive_strength; - t->odt = boot->odt; - } else { - t->drive_strength = (e->RAM_FT1 & 0x30) >> 4; - t->odt = e->RAM_FT1 & 0x07; - } - - if (e->tCL >= NV_MEM_CL_GDDR3_MAX) { - NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL); - return -ERANGE; - } - - if (e->tWR >= NV_MEM_WR_GDDR3_MAX) { - NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR); - return -ERANGE; - } - - if (t->odt > 3) { - NV_WARN(drm, "(%u) Invalid odt value, assuming autocal: %x", - t->id, t->odt); - t->odt = 0; - } - - t->mr[0] = (boot->mr[0] & 0xe0b) | - /* CAS */ - ((nv_mem_cl_lut_gddr3[e->tCL] & 0x7) << 4) | - ((nv_mem_cl_lut_gddr3[e->tCL] & 0x8) >> 2); - t->mr[1] = (boot->mr[1] & 0x100f40) | t->drive_strength | - (t->odt << 2) | - (nv_mem_wr_lut_gddr3[e->tWR] & 0xf) << 4; - t->mr[2] = boot->mr[2]; - - NV_DEBUG(drm, "(%u) MR: %08x %08x %08x", t->id, - t->mr[0], t->mr[1], t->mr[2]); - return 0; -} - -static int -nouveau_mem_gddr5_mr(struct drm_device *dev, u32 freq, - struct nouveau_pm_tbl_entry *e, u8 len, - struct nouveau_pm_memtiming *boot, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - - if (len < 15) { - t->drive_strength = boot->drive_strength; - t->odt = boot->odt; - } else { - t->drive_strength = (e->RAM_FT1 & 0x30) >> 4; - t->odt = e->RAM_FT1 & 0x03; - } - - if (e->tCL >= NV_MEM_CL_GDDR5_MAX) { - NV_WARN(drm, "(%u) Invalid tCL: %u", t->id, e->tCL); - return -ERANGE; - } - - if (e->tWR >= NV_MEM_WR_GDDR5_MAX) { - NV_WARN(drm, "(%u) Invalid tWR: %u", t->id, e->tWR); - return -ERANGE; - } - - if (t->odt > 3) { - NV_WARN(drm, "(%u) Invalid odt value, assuming autocal: %x", - t->id, t->odt); - t->odt = 0; - } - - t->mr[0] = (boot->mr[0] & 0x007) | - ((e->tCL - 5) << 3) | - ((e->tWR - 4) << 8); - t->mr[1] = (boot->mr[1] & 0x1007f0) | - t->drive_strength | - (t->odt << 2); - - NV_DEBUG(drm, "(%u) MR: %08x %08x", t->id, t->mr[0], t->mr[1]); - return 0; -} - -int -nouveau_mem_timing_calc(struct drm_device *dev, u32 freq, - struct nouveau_pm_memtiming *t) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_fb *pfb = nouveau_fb(device); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_memtiming *boot = &pm->boot.timing; - struct nouveau_pm_tbl_entry *e; - u8 ver, len, *ptr, *ramcfg; - int ret; - - ptr = nouveau_perf_timing(dev, freq, &ver, &len); - if (!ptr || ptr[0] == 0x00) { - *t = *boot; - return 0; - } - e = (struct nouveau_pm_tbl_entry *)ptr; - - t->tCWL = boot->tCWL; - - switch (device->card_type) { - case NV_40: - ret = nv40_mem_timing_calc(dev, freq, e, len, boot, t); - break; - case NV_50: - ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t); - break; - case NV_C0: - case NV_D0: - ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t); - break; - default: - ret = -ENODEV; - break; - } - - switch (pfb->ram->type * !ret) { - case NV_MEM_TYPE_GDDR3: - ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t); - break; - case NV_MEM_TYPE_GDDR5: - ret = nouveau_mem_gddr5_mr(dev, freq, e, len, boot, t); - break; - case NV_MEM_TYPE_DDR2: - ret = nouveau_mem_ddr2_mr(dev, freq, e, len, boot, t); - break; - case NV_MEM_TYPE_DDR3: - ret = nouveau_mem_ddr3_mr(dev, freq, e, len, boot, t); - break; - default: - ret = -EINVAL; - break; - } - - ramcfg = nouveau_perf_ramcfg(dev, freq, &ver, &len); - if (ramcfg) { - int dll_off; - - if (ver == 0x00) - dll_off = !!(ramcfg[3] & 0x04); - else - dll_off = !!(ramcfg[2] & 0x40); - - switch (pfb->ram->type) { - case NV_MEM_TYPE_GDDR3: - t->mr[1] &= ~0x00000040; - t->mr[1] |= 0x00000040 * dll_off; - break; - default: - t->mr[1] &= ~0x00000001; - t->mr[1] |= 0x00000001 * dll_off; - break; - } - } - - return ret; -} - -void -nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_fb *pfb = nouveau_fb(device); - u32 timing_base, timing_regs, mr_base; - int i; - - if (device->card_type >= 0xC0) { - timing_base = 0x10f290; - mr_base = 0x10f300; - } else { - timing_base = 0x100220; - mr_base = 0x1002c0; - } - - t->id = -1; - - switch (device->card_type) { - case NV_50: - timing_regs = 9; - break; - case NV_C0: - case NV_D0: - timing_regs = 5; - break; - case NV_30: - case NV_40: - timing_regs = 3; - break; - default: - timing_regs = 0; - return; - } - for(i = 0; i < timing_regs; i++) - t->reg[i] = nv_rd32(device, timing_base + (0x04 * i)); - - t->tCWL = 0; - if (device->card_type < NV_C0) { - t->tCWL = ((nv_rd32(device, 0x100228) & 0x0f000000) >> 24) + 1; - } else if (device->card_type <= NV_D0) { - t->tCWL = ((nv_rd32(device, 0x10f294) & 0x00000f80) >> 7); - } - - t->mr[0] = nv_rd32(device, mr_base); - t->mr[1] = nv_rd32(device, mr_base + 0x04); - t->mr[2] = nv_rd32(device, mr_base + 0x20); - t->mr[3] = nv_rd32(device, mr_base + 0x24); - - t->odt = 0; - t->drive_strength = 0; - - switch (pfb->ram->type) { - case NV_MEM_TYPE_DDR3: - t->odt |= (t->mr[1] & 0x200) >> 7; - case NV_MEM_TYPE_DDR2: - t->odt |= (t->mr[1] & 0x04) >> 2 | - (t->mr[1] & 0x40) >> 5; - break; - case NV_MEM_TYPE_GDDR3: - case NV_MEM_TYPE_GDDR5: - t->drive_strength = t->mr[1] & 0x03; - t->odt = (t->mr[1] & 0x0c) >> 2; - break; - default: - break; - } -} - -int -nouveau_mem_exec(struct nouveau_mem_exec_func *exec, - struct nouveau_pm_level *perflvl) -{ - struct nouveau_drm *drm = nouveau_drm(exec->dev); - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nouveau_fb *pfb = nouveau_fb(device); - struct nouveau_pm_memtiming *info = &perflvl->timing; - u32 tMRD = 1000, tCKSRE = 0, tCKSRX = 0, tXS = 0, tDLLK = 0; - u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] }; - u32 mr1_dlloff; - - switch (pfb->ram->type) { - case NV_MEM_TYPE_DDR2: - tDLLK = 2000; - mr1_dlloff = 0x00000001; - break; - case NV_MEM_TYPE_DDR3: - tDLLK = 12000; - tCKSRE = 2000; - tXS = 1000; - mr1_dlloff = 0x00000001; - break; - case NV_MEM_TYPE_GDDR3: - tDLLK = 40000; - mr1_dlloff = 0x00000040; - break; - default: - NV_ERROR(drm, "cannot reclock unsupported memtype\n"); - return -ENODEV; - } - - /* fetch current MRs */ - switch (pfb->ram->type) { - case NV_MEM_TYPE_GDDR3: - case NV_MEM_TYPE_DDR3: - mr[2] = exec->mrg(exec, 2); - default: - mr[1] = exec->mrg(exec, 1); - mr[0] = exec->mrg(exec, 0); - break; - } - - /* DLL 'on' -> DLL 'off' mode, disable before entering self-refresh */ - if (!(mr[1] & mr1_dlloff) && (info->mr[1] & mr1_dlloff)) { - exec->precharge(exec); - exec->mrs (exec, 1, mr[1] | mr1_dlloff); - exec->wait(exec, tMRD); - } - - /* enter self-refresh mode */ - exec->precharge(exec); - exec->refresh(exec); - exec->refresh(exec); - exec->refresh_auto(exec, false); - exec->refresh_self(exec, true); - exec->wait(exec, tCKSRE); - - /* modify input clock frequency */ - exec->clock_set(exec); - - /* exit self-refresh mode */ - exec->wait(exec, tCKSRX); - exec->precharge(exec); - exec->refresh_self(exec, false); - exec->refresh_auto(exec, true); - exec->wait(exec, tXS); - exec->wait(exec, tXS); - - /* update MRs */ - if (mr[2] != info->mr[2]) { - exec->mrs (exec, 2, info->mr[2]); - exec->wait(exec, tMRD); - } - - if (mr[1] != info->mr[1]) { - /* need to keep DLL off until later, at least on GDDR3 */ - exec->mrs (exec, 1, info->mr[1] | (mr[1] & mr1_dlloff)); - exec->wait(exec, tMRD); - } - - if (mr[0] != info->mr[0]) { - exec->mrs (exec, 0, info->mr[0]); - exec->wait(exec, tMRD); - } - - /* update PFB timing registers */ - exec->timing_set(exec); - - /* DLL (enable + ) reset */ - if (!(info->mr[1] & mr1_dlloff)) { - if (mr[1] & mr1_dlloff) { - exec->mrs (exec, 1, info->mr[1]); - exec->wait(exec, tMRD); - } - exec->mrs (exec, 0, info->mr[0] | 0x00000100); - exec->wait(exec, tMRD); - exec->mrs (exec, 0, info->mr[0] | 0x00000000); - exec->wait(exec, tMRD); - exec->wait(exec, tDLLK); - if (pfb->ram->type == NV_MEM_TYPE_GDDR3) - exec->precharge(exec); - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c deleted file mode 100644 index 4fe883c5491..00000000000 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright 2010 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 <drm/drmP.h> - -#include "nouveau_drm.h" -#include "nouveau_reg.h" -#include "nouveau_pm.h" - -static u8 * -nouveau_perf_table(struct drm_device *dev, u8 *ver) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvbios *bios = &drm->vbios; - struct bit_entry P; - - if (!bit_table(dev, 'P', &P) && P.version && P.version <= 2) { - u8 *perf = ROMPTR(dev, P.data[0]); - if (perf) { - *ver = perf[0]; - return perf; - } - } - - if (bios->type == NVBIOS_BMP) { - if (bios->data[bios->offset + 6] >= 0x25) { - u8 *perf = ROMPTR(dev, bios->data[bios->offset + 0x94]); - if (perf) { - *ver = perf[1]; - return perf; - } - } - } - - return NULL; -} - -static u8 * -nouveau_perf_entry(struct drm_device *dev, int idx, - u8 *ver, u8 *hdr, u8 *cnt, u8 *len) -{ - u8 *perf = nouveau_perf_table(dev, ver); - if (perf) { - if (*ver >= 0x12 && *ver < 0x20 && idx < perf[2]) { - *hdr = perf[3]; - *cnt = 0; - *len = 0; - return perf + perf[0] + idx * perf[3]; - } else - if (*ver >= 0x20 && *ver < 0x40 && idx < perf[2]) { - *hdr = perf[3]; - *cnt = perf[4]; - *len = perf[5]; - return perf + perf[1] + idx * (*hdr + (*cnt * *len)); - } else - if (*ver >= 0x40 && *ver < 0x41 && idx < perf[5]) { - *hdr = perf[2]; - *cnt = perf[4]; - *len = perf[3]; - return perf + perf[1] + idx * (*hdr + (*cnt * *len)); - } - } - return NULL; -} - -u8 * -nouveau_perf_rammap(struct drm_device *dev, u32 freq, - u8 *ver, u8 *hdr, u8 *cnt, u8 *len) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct bit_entry P; - u8 *perf, i = 0; - - if (!bit_table(dev, 'P', &P) && P.version == 2) { - u8 *rammap = ROMPTR(dev, P.data[4]); - if (rammap) { - u8 *ramcfg = rammap + rammap[1]; - - *ver = rammap[0]; - *hdr = rammap[2]; - *cnt = rammap[4]; - *len = rammap[3]; - - freq /= 1000; - for (i = 0; i < rammap[5]; i++) { - if (freq >= ROM16(ramcfg[0]) && - freq <= ROM16(ramcfg[2])) - return ramcfg; - - ramcfg += *hdr + (*cnt * *len); - } - } - - return NULL; - } - - if (nv_device(drm->device)->chipset == 0x49 || - nv_device(drm->device)->chipset == 0x4b) - freq /= 2; - - while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) { - if (*ver >= 0x20 && *ver < 0x25) { - if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000) - break; - } else - if (*ver >= 0x25 && *ver < 0x40) { - if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000) - break; - } - } - - if (perf) { - u8 *ramcfg = perf + *hdr; - *ver = 0x00; - *hdr = 0; - return ramcfg; - } - - return NULL; -} - -u8 * -nouveau_perf_ramcfg(struct drm_device *dev, u32 freq, u8 *ver, u8 *len) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvbios *bios = &drm->vbios; - u8 strap, hdr, cnt; - u8 *rammap; - - strap = (nv_rd32(device, 0x101000) & 0x0000003c) >> 2; - if (bios->ram_restrict_tbl_ptr) - strap = bios->data[bios->ram_restrict_tbl_ptr + strap]; - - rammap = nouveau_perf_rammap(dev, freq, ver, &hdr, &cnt, len); - if (rammap && strap < cnt) - return rammap + hdr + (strap * *len); - - return NULL; -} - -u8 * -nouveau_perf_timing(struct drm_device *dev, u32 freq, u8 *ver, u8 *len) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvbios *bios = &drm->vbios; - struct bit_entry P; - u8 *perf, *timing = NULL; - u8 i = 0, hdr, cnt; - - if (bios->type == NVBIOS_BMP) { - while ((perf = nouveau_perf_entry(dev, i++, ver, &hdr, &cnt, - len)) && *ver == 0x15) { - if (freq <= ROM32(perf[5]) * 20) { - *ver = 0x00; - *len = 14; - return perf + 41; - } - } - return NULL; - } - - if (!bit_table(dev, 'P', &P)) { - if (P.version == 1) - timing = ROMPTR(dev, P.data[4]); - else - if (P.version == 2) - timing = ROMPTR(dev, P.data[8]); - } - - if (timing && timing[0] == 0x10) { - u8 *ramcfg = nouveau_perf_ramcfg(dev, freq, ver, len); - if (ramcfg && ramcfg[1] < timing[2]) { - *ver = timing[0]; - *len = timing[3]; - return timing + timing[1] + (ramcfg[1] * timing[3]); - } - } - - return NULL; -} - -static void -legacy_perf_init(struct drm_device *dev) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvbios *bios = &drm->vbios; - struct nouveau_pm *pm = nouveau_pm(dev); - char *perf, *entry, *bmp = &bios->data[bios->offset]; - int headerlen, use_straps; - - if (bmp[5] < 0x5 || bmp[6] < 0x14) { - NV_DEBUG(drm, "BMP version too old for perf\n"); - return; - } - - perf = ROMPTR(dev, bmp[0x73]); - if (!perf) { - NV_DEBUG(drm, "No memclock table pointer found.\n"); - return; - } - - switch (perf[0]) { - case 0x12: - case 0x14: - case 0x18: - use_straps = 0; - headerlen = 1; - break; - case 0x01: - use_straps = perf[1] & 1; - headerlen = (use_straps ? 8 : 2); - break; - default: - NV_WARN(drm, "Unknown memclock table version %x.\n", perf[0]); - return; - } - - entry = perf + headerlen; - if (use_straps) - entry += (nv_rd32(device, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1; - - sprintf(pm->perflvl[0].name, "performance_level_0"); - pm->perflvl[0].memory = ROM16(entry[0]) * 20; - pm->nr_perflvl = 1; -} - -static void -nouveau_perf_voltage(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct bit_entry P; - u8 *vmap; - int id; - - id = perflvl->volt_min; - perflvl->volt_min = 0; - - /* boards using voltage table version <0x40 store the voltage - * level directly in the perflvl entry as a multiple of 10mV - */ - if (drm->pm->voltage.version < 0x40) { - perflvl->volt_min = id * 10000; - perflvl->volt_max = perflvl->volt_min; - return; - } - - /* on newer ones, the perflvl stores an index into yet another - * vbios table containing a min/max voltage value for the perflvl - */ - if (bit_table(dev, 'P', &P) || P.version != 2 || P.length < 34) { - NV_DEBUG(drm, "where's our volt map table ptr? %d %d\n", - P.version, P.length); - return; - } - - vmap = ROMPTR(dev, P.data[32]); - if (!vmap) { - NV_DEBUG(drm, "volt map table pointer invalid\n"); - return; - } - - if (id < vmap[3]) { - vmap += vmap[1] + (vmap[2] * id); - perflvl->volt_min = ROM32(vmap[0]); - perflvl->volt_max = ROM32(vmap[4]); - } -} - -void -nouveau_perf_init(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nvbios *bios = &drm->vbios; - u8 *perf, ver, hdr, cnt, len; - int ret, vid, i = -1; - - if (bios->type == NVBIOS_BMP && bios->data[bios->offset + 6] < 0x25) { - legacy_perf_init(dev); - return; - } - - perf = nouveau_perf_table(dev, &ver); - - while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) { - struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; - - if (perf[0] == 0xff) - continue; - - switch (ver) { - case 0x12: - case 0x13: - case 0x15: - perflvl->fanspeed = perf[55]; - if (hdr > 56) - perflvl->volt_min = perf[56]; - perflvl->core = ROM32(perf[1]) * 10; - perflvl->memory = ROM32(perf[5]) * 20; - break; - case 0x21: - case 0x23: - case 0x24: - perflvl->fanspeed = perf[4]; - perflvl->volt_min = perf[5]; - perflvl->shader = ROM16(perf[6]) * 1000; - perflvl->core = perflvl->shader; - perflvl->core += (signed char)perf[8] * 1000; - if (nv_device(drm->device)->chipset == 0x49 || - nv_device(drm->device)->chipset == 0x4b) - perflvl->memory = ROM16(perf[11]) * 1000; - else - perflvl->memory = ROM16(perf[11]) * 2000; - break; - case 0x25: - perflvl->fanspeed = perf[4]; - perflvl->volt_min = perf[5]; - perflvl->core = ROM16(perf[6]) * 1000; - perflvl->shader = ROM16(perf[10]) * 1000; - perflvl->memory = ROM16(perf[12]) * 1000; - break; - case 0x30: - perflvl->memscript = ROM16(perf[2]); - case 0x35: - perflvl->fanspeed = perf[6]; - perflvl->volt_min = perf[7]; - perflvl->core = ROM16(perf[8]) * 1000; - perflvl->shader = ROM16(perf[10]) * 1000; - perflvl->memory = ROM16(perf[12]) * 1000; - perflvl->vdec = ROM16(perf[16]) * 1000; - perflvl->dom6 = ROM16(perf[20]) * 1000; - break; - case 0x40: -#define subent(n) ((ROM16(perf[hdr + (n) * len]) & 0xfff) * 1000) - perflvl->fanspeed = 0; /*XXX*/ - perflvl->volt_min = perf[2]; - if (nv_device(drm->device)->card_type == NV_50) { - perflvl->core = subent(0); - perflvl->shader = subent(1); - perflvl->memory = subent(2); - perflvl->vdec = subent(3); - perflvl->unka0 = subent(4); - } else { - perflvl->hub06 = subent(0); - perflvl->hub01 = subent(1); - perflvl->copy = subent(2); - perflvl->shader = subent(3); - perflvl->rop = subent(4); - perflvl->memory = subent(5); - perflvl->vdec = subent(6); - perflvl->daemon = subent(10); - perflvl->hub07 = subent(11); - perflvl->core = perflvl->shader / 2; - } - break; - } - - /* make sure vid is valid */ - nouveau_perf_voltage(dev, perflvl); - if (pm->voltage.supported && perflvl->volt_min) { - vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min); - if (vid < 0) { - NV_DEBUG(drm, "perflvl %d, bad vid\n", i); - continue; - } - } - - /* get the corresponding memory timings */ - ret = nouveau_mem_timing_calc(dev, perflvl->memory, - &perflvl->timing); - if (ret) { - NV_DEBUG(drm, "perflvl %d, bad timing: %d\n", i, ret); - continue; - } - - snprintf(perflvl->name, sizeof(perflvl->name), - "performance_level_%d", i); - perflvl->id = i; - - snprintf(perflvl->profile.name, sizeof(perflvl->profile.name), - "%d", perflvl->id); - perflvl->profile.func = &nouveau_pm_static_profile_func; - list_add_tail(&perflvl->profile.head, &pm->profiles); - - - pm->nr_perflvl++; - } -} - -void -nouveau_perf_fini(struct drm_device *dev) -{ -} diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h deleted file mode 100644 index 73b789c230a..00000000000 --- a/drivers/gpu/drm/nouveau/nouveau_pm.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2010 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 - */ - -#ifndef __NOUVEAU_PM_H__ -#define __NOUVEAU_PM_H__ - -#include <subdev/bios/pll.h> -#include <subdev/clock.h> - -struct nouveau_pm_voltage_level { - u32 voltage; /* microvolts */ - u8 vid; -}; - -struct nouveau_pm_voltage { - bool supported; - u8 version; - u8 vid_mask; - - struct nouveau_pm_voltage_level *level; - int nr_level; -}; - -/* Exclusive upper limits */ -#define NV_MEM_CL_DDR2_MAX 8 -#define NV_MEM_WR_DDR2_MAX 9 -#define NV_MEM_CL_DDR3_MAX 17 -#define NV_MEM_WR_DDR3_MAX 17 -#define NV_MEM_CL_GDDR3_MAX 16 -#define NV_MEM_WR_GDDR3_MAX 18 -#define NV_MEM_CL_GDDR5_MAX 21 -#define NV_MEM_WR_GDDR5_MAX 20 - -struct nouveau_pm_memtiming { - int id; - - u32 reg[9]; - u32 mr[4]; - - u8 tCWL; - - u8 odt; - u8 drive_strength; -}; - -struct nouveau_pm_tbl_header { - u8 version; - u8 header_len; - u8 entry_cnt; - u8 entry_len; -}; - -struct nouveau_pm_tbl_entry { - u8 tWR; - u8 tWTR; - u8 tCL; - u8 tRC; - u8 empty_4; - u8 tRFC; /* Byte 5 */ - u8 empty_6; - u8 tRAS; /* Byte 7 */ - u8 empty_8; - u8 tRP; /* Byte 9 */ - u8 tRCDRD; - u8 tRCDWR; - u8 tRRD; - u8 tUNK_13; - u8 RAM_FT1; /* 14, a bitmask of random RAM features */ - u8 empty_15; - u8 tUNK_16; - u8 empty_17; - u8 tUNK_18; - u8 tCWL; - u8 tUNK_20, tUNK_21; -}; - -struct nouveau_pm_profile; -struct nouveau_pm_profile_func { - void (*destroy)(struct nouveau_pm_profile *); - void (*init)(struct nouveau_pm_profile *); - void (*fini)(struct nouveau_pm_profile *); - struct nouveau_pm_level *(*select)(struct nouveau_pm_profile *); -}; - -struct nouveau_pm_profile { - const struct nouveau_pm_profile_func *func; - struct list_head head; - char name[8]; -}; - -#define NOUVEAU_PM_MAX_LEVEL 8 -struct nouveau_pm_level { - struct nouveau_pm_profile profile; - struct device_attribute dev_attr; - char name[32]; - int id; - - struct nouveau_pm_memtiming timing; - u32 memory; - u16 memscript; - - u32 core; - u32 shader; - u32 rop; - u32 copy; - u32 daemon; - u32 vdec; - u32 dom6; - u32 unka0; /* nva3:nvc0 */ - u32 hub01; /* nvc0- */ - u32 hub06; /* nvc0- */ - u32 hub07; /* nvc0- */ - - u32 volt_min; /* microvolts */ - u32 volt_max; - u8 fanspeed; -}; - -struct nouveau_pm_temp_sensor_constants { - u16 offset_constant; - s16 offset_mult; - s16 offset_div; - s16 slope_mult; - s16 slope_div; -}; - -struct nouveau_pm_threshold_temp { - s16 critical; - s16 down_clock; -}; - -struct nouveau_pm { - struct drm_device *dev; - - struct nouveau_pm_voltage voltage; - struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL]; - int nr_perflvl; - struct nouveau_pm_temp_sensor_constants sensor_constants; - struct nouveau_pm_threshold_temp threshold_temp; - - struct nouveau_pm_profile *profile_ac; - struct nouveau_pm_profile *profile_dc; - struct nouveau_pm_profile *profile; - struct list_head profiles; - - struct nouveau_pm_level boot; - struct nouveau_pm_level *cur; - - struct device *hwmon; - struct notifier_block acpi_nb; - - int (*clocks_get)(struct drm_device *, struct nouveau_pm_level *); - void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *); - int (*clocks_set)(struct drm_device *, void *); - - int (*voltage_get)(struct drm_device *); - int (*voltage_set)(struct drm_device *, int voltage); -}; - -static inline struct nouveau_pm * -nouveau_pm(struct drm_device *dev) -{ - return nouveau_drm(dev)->pm; -} - -struct nouveau_mem_exec_func { - struct drm_device *dev; - void (*precharge)(struct nouveau_mem_exec_func *); - void (*refresh)(struct nouveau_mem_exec_func *); - void (*refresh_auto)(struct nouveau_mem_exec_func *, bool); - void (*refresh_self)(struct nouveau_mem_exec_func *, bool); - void (*wait)(struct nouveau_mem_exec_func *, u32 nsec); - u32 (*mrg)(struct nouveau_mem_exec_func *, int mr); - void (*mrs)(struct nouveau_mem_exec_func *, int mr, u32 data); - void (*clock_set)(struct nouveau_mem_exec_func *); - void (*timing_set)(struct nouveau_mem_exec_func *); - void *priv; -}; - -/* nouveau_mem.c */ -int nouveau_mem_exec(struct nouveau_mem_exec_func *, - struct nouveau_pm_level *); - -/* nouveau_pm.c */ -int nouveau_pm_init(struct drm_device *dev); -void nouveau_pm_fini(struct drm_device *dev); -void nouveau_pm_resume(struct drm_device *dev); -extern const struct nouveau_pm_profile_func nouveau_pm_static_profile_func; -void nouveau_pm_trigger(struct drm_device *dev); - -/* nouveau_volt.c */ -void nouveau_volt_init(struct drm_device *); -void nouveau_volt_fini(struct drm_device *); -int nouveau_volt_vid_lookup(struct drm_device *, int voltage); -int nouveau_volt_lvl_lookup(struct drm_device *, int vid); -int nouveau_voltage_gpio_get(struct drm_device *); -int nouveau_voltage_gpio_set(struct drm_device *, int voltage); - -/* nouveau_perf.c */ -void nouveau_perf_init(struct drm_device *); -void nouveau_perf_fini(struct drm_device *); -u8 *nouveau_perf_rammap(struct drm_device *, u32 freq, u8 *ver, - u8 *hdr, u8 *cnt, u8 *len); -u8 *nouveau_perf_ramcfg(struct drm_device *, u32 freq, u8 *ver, u8 *len); -u8 *nouveau_perf_timing(struct drm_device *, u32 freq, u8 *ver, u8 *len); - -/* nouveau_mem.c */ -void nouveau_mem_timing_init(struct drm_device *); -void nouveau_mem_timing_fini(struct drm_device *); - -/* nv04_pm.c */ -int nv04_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); -void *nv04_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); -int nv04_pm_clocks_set(struct drm_device *, void *); - -/* nv40_pm.c */ -int nv40_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); -void *nv40_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); -int nv40_pm_clocks_set(struct drm_device *, void *); -int nv40_pm_pwm_get(struct drm_device *, int, u32 *, u32 *); -int nv40_pm_pwm_set(struct drm_device *, int, u32, u32); - -/* nv50_pm.c */ -int nv50_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); -void *nv50_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); -int nv50_pm_clocks_set(struct drm_device *, void *); -int nv50_pm_pwm_get(struct drm_device *, int, u32 *, u32 *); -int nv50_pm_pwm_set(struct drm_device *, int, u32, u32); - -/* nva3_pm.c */ -int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); -void *nva3_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); -int nva3_pm_clocks_set(struct drm_device *, void *); - -/* nvc0_pm.c */ -int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); -void *nvc0_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); -int nvc0_pm_clocks_set(struct drm_device *, void *); - -/* nouveau_mem.c */ -int nouveau_mem_timing_calc(struct drm_device *, u32 freq, - struct nouveau_pm_memtiming *); -void nouveau_mem_timing_read(struct drm_device *, - struct nouveau_pm_memtiming *); - -static inline int -nva3_calc_pll(struct drm_device *dev, struct nvbios_pll *pll, u32 freq, - int *N, int *fN, int *M, int *P) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_clock *clk = nouveau_clock(device); - struct nouveau_pll_vals pv; - int ret; - - ret = clk->pll_calc(clk, pll, freq, &pv); - *N = pv.N1; - *M = pv.M1; - *P = pv.log2P; - return ret; -} - -#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index e90468d5e5c..51a2cb102b4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -71,14 +71,16 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, return ERR_PTR(ret); nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART; - nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size); - if (!nvbo->gem) { + + /* Initialize the embedded gem-object. We return a single gem-reference + * to the caller, instead of a normal nouveau_bo ttm reference. */ + ret = drm_gem_object_init(dev, &nvbo->gem, nvbo->bo.mem.size); + if (ret) { nouveau_bo_ref(NULL, &nvbo); return ERR_PTR(-ENOMEM); } - nvbo->gem->driver_private = nvbo; - return nvbo->gem; + return &nvbo->gem; } int nouveau_gem_prime_pin(struct drm_gem_object *obj) diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 0843ebc910d..a4d22e5eb17 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -31,16 +31,17 @@ nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem) { struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; struct nouveau_mem *node = mem->mm_node; - u64 size = mem->num_pages << 12; if (ttm->sg) { - node->sg = ttm->sg; - nouveau_vm_map_sg_table(&node->vma[0], 0, size, node); + node->sg = ttm->sg; + node->pages = NULL; } else { + node->sg = NULL; node->pages = nvbe->ttm.dma_address; - nouveau_vm_map_sg(&node->vma[0], 0, size, node); } + node->size = (mem->num_pages << PAGE_SHIFT) >> 12; + nouveau_vm_map(&node->vma[0], node); nvbe->node = node; return 0; } @@ -67,9 +68,13 @@ nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem) /* noop: bound in move_notify() */ if (ttm->sg) { - node->sg = ttm->sg; - } else + node->sg = ttm->sg; + node->pages = NULL; + } else { + node->sg = NULL; node->pages = nvbe->ttm.dma_address; + } + node->size = (mem->num_pages << PAGE_SHIFT) >> 12; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c new file mode 100644 index 00000000000..75dda2b0717 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c @@ -0,0 +1,164 @@ +/* + * 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 "nouveau_sysfs.h" + +#include <core/object.h> +#include <core/class.h> + +static inline struct drm_device * +drm_device(struct device *d) +{ + return dev_get_drvdata(d); +} + +#define snappendf(p,r,f,a...) do { \ + snprintf(p, r, f, ##a); \ + r -= strlen(p); \ + p += strlen(p); \ +} while(0) + +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; + size_t cnt = PAGE_SIZE; + char *buf = b; + int ret, i; + + ret = nv_exec(sysfs->ctrl, NV_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 = { + .state = state, + .index = 0, + }; + + ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR, + &attr, sizeof(attr)); + if (ret) + return ret; + + if (i < info.count) + snappendf(buf, cnt, "%02x:", attr.state); + else + snappendf(buf, cnt, "--:"); + + attr.index = 0; + do { + attr.state = state; + ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR, + &attr, sizeof(attr)); + if (ret) + return ret; + + snappendf(buf, cnt, " %s %d", attr.name, attr.min); + if (attr.min != attr.max) + snappendf(buf, cnt, "-%d", attr.max); + snappendf(buf, cnt, " %s", attr.unit); + } while (attr.index); + + if ((state >= 0 && info.pstate == state) || + (state < 0 && info.ustate < 0)) + snappendf(buf, cnt, " *"); + snappendf(buf, cnt, "\n"); + } + + return strlen(b); +} + +static ssize_t +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; + long value, ret; + char *tmp; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (!strcasecmp(buf, "none")) + args.state = NV_CONTROL_PSTATE_USER_STATE_UNKNOWN; + else + if (!strcasecmp(buf, "auto")) + args.state = NV_CONTROL_PSTATE_USER_STATE_PERFMON; + else { + ret = kstrtol(buf, 16, &value); + if (ret) + return ret; + args.state = value; + } + + ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_USER, &args, sizeof(args)); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(pstate, S_IRUGO | S_IWUSR, + nouveau_sysfs_pstate_get, nouveau_sysfs_pstate_set); + +void +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); + + if (sysfs->ctrl) { + device_remove_file(nv_device_base(device), &dev_attr_pstate); + nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL); + } + + drm->sysfs = NULL; + kfree(sysfs); +} + +int +nouveau_sysfs_init(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nv_device(drm->device); + struct nouveau_sysfs *sysfs; + int ret; + + 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); + if (ret == 0) + device_create_file(nv_device_base(device), &dev_attr_pstate); + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.h b/drivers/gpu/drm/nouveau/nouveau_sysfs.h new file mode 100644 index 00000000000..74b47f1e01e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.h @@ -0,0 +1,19 @@ +#ifndef __NOUVEAU_SYSFS_H__ +#define __NOUVEAU_SYSFS_H__ + +#include "nouveau_drm.h" + +struct nouveau_sysfs { + struct nouveau_object *ctrl; +}; + +static inline struct nouveau_sysfs * +nouveau_sysfs(struct drm_device *dev) +{ + return nouveau_drm(dev)->sysfs; +} + +int nouveau_sysfs_init(struct drm_device *); +void nouveau_sysfs_fini(struct drm_device *); + +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 19e3757291f..ab0228f640a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -171,6 +171,7 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man, node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) return -ENOMEM; + node->page_shift = 12; switch (nv_device(drm->device)->card_type) { @@ -353,21 +354,26 @@ 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 ( drm->agp.stat == ENABLED || - !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) - bits = 32; - - ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits)); - if (ret) - return ret; - - ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(bits)); - if (ret) - pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32)); + if (nv_device_is_pci(device)) { + if (drm->agp.stat == ENABLED || + !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) + bits = 32; + + ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits)); + if (ret) + return ret; + + ret = pci_set_consistent_dma_mask(dev->pdev, + DMA_BIT_MASK(bits)); + if (ret) + pci_set_consistent_dma_mask(dev->pdev, + DMA_BIT_MASK(32)); + } ret = nouveau_ttm_global_init(drm); if (ret) @@ -375,7 +381,9 @@ nouveau_ttm_init(struct nouveau_drm *drm) ret = ttm_bo_device_init(&drm->ttm.bdev, drm->ttm.bo_global_ref.ref.object, - &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET, + &nouveau_bo_driver, + dev->anon_inode->i_mapping, + DRM_FILE_PAGE_OFFSET, bits <= 32 ? true : false); if (ret) { NV_ERROR(drm, "error initialising bo driver, %d\n", ret); @@ -393,8 +401,8 @@ nouveau_ttm_init(struct nouveau_drm *drm) return ret; } - drm->ttm.mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 1), - pci_resource_len(dev->pdev, 1)); + drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(device, 1), + nv_device_resource_len(device, 1)); /* GART init */ if (drm->agp.stat != ENABLED) { diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 81638d7f2ef..4f4c3fec691 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -14,7 +14,9 @@ nouveau_vga_set_decode(void *priv, bool state) { struct nouveau_device *device = nouveau_dev(priv); - if (device->chipset >= 0x40) + if (device->card_type == NV_40 && device->chipset >= 0x4c) + nv_wr32(device, 0x088060, state); + else if (device->chipset >= 0x40) nv_wr32(device, 0x088054, state); else nv_wr32(device, 0x001854, state); @@ -62,12 +64,13 @@ static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - bool can_switch; - spin_lock(&dev->count_lock); - can_switch = (dev->open_count == 0); - spin_unlock(&dev->count_lock); - return can_switch; + /* + * FIXME: open_count is protected by drm_global_mutex but that would lead to + * locking inversion with the driver load path. And the access here is + * completely racy anyway. So don't bother with locking for now. + */ + return dev->open_count == 0; } static const struct vga_switcheroo_client_ops @@ -82,6 +85,11 @@ nouveau_vga_init(struct nouveau_drm *drm) { struct drm_device *dev = drm->dev; bool runtime = false; + + /* only relevant for PCI devices */ + if (!dev->pdev) + return; + vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); if (nouveau_runtime_pm == 1) diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c deleted file mode 100644 index 9976414cbe5..00000000000 --- a/drivers/gpu/drm/nouveau/nouveau_volt.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2010 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 <drm/drmP.h> - -#include "nouveau_drm.h" -#include "nouveau_pm.h" - -#include <subdev/bios/gpio.h> -#include <subdev/gpio.h> - -static const enum dcb_gpio_func_name vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; -static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); - -int -nouveau_voltage_gpio_get(struct drm_device *dev) -{ - struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage; - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_gpio *gpio = nouveau_gpio(device); - u8 vid = 0; - int i; - - for (i = 0; i < nr_vidtag; i++) { - if (!(volt->vid_mask & (1 << i))) - continue; - - vid |= gpio->get(gpio, 0, vidtag[i], 0xff) << i; - } - - return nouveau_volt_lvl_lookup(dev, vid); -} - -int -nouveau_voltage_gpio_set(struct drm_device *dev, int voltage) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_gpio *gpio = nouveau_gpio(device); - struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage; - int vid, i; - - vid = nouveau_volt_vid_lookup(dev, voltage); - if (vid < 0) - return vid; - - for (i = 0; i < nr_vidtag; i++) { - if (!(volt->vid_mask & (1 << i))) - continue; - - gpio->set(gpio, 0, vidtag[i], 0xff, !!(vid & (1 << i))); - } - - return 0; -} - -int -nouveau_volt_vid_lookup(struct drm_device *dev, int voltage) -{ - struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage; - int i; - - for (i = 0; i < volt->nr_level; i++) { - if (volt->level[i].voltage == voltage) - return volt->level[i].vid; - } - - return -ENOENT; -} - -int -nouveau_volt_lvl_lookup(struct drm_device *dev, int vid) -{ - struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage; - int i; - - for (i = 0; i < volt->nr_level; i++) { - if (volt->level[i].vid == vid) - return volt->level[i].voltage; - } - - return -ENOENT; -} - -void -nouveau_volt_init(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); - struct nouveau_pm *pm = nouveau_pm(dev); - struct nouveau_pm_voltage *voltage = &pm->voltage; - struct nvbios *bios = &drm->vbios; - struct dcb_gpio_func func; - struct bit_entry P; - u8 *volt = NULL, *entry; - int i, headerlen, recordlen, entries, vidmask, vidshift; - - if (bios->type == NVBIOS_BIT) { - if (bit_table(dev, 'P', &P)) - return; - - if (P.version == 1) - volt = ROMPTR(dev, P.data[16]); - else - if (P.version == 2) - volt = ROMPTR(dev, P.data[12]); - else { - NV_WARN(drm, "unknown volt for BIT P %d\n", P.version); - } - } else { - if (bios->data[bios->offset + 6] < 0x27) { - NV_DEBUG(drm, "BMP version too old for voltage\n"); - return; - } - - volt = ROMPTR(dev, bios->data[bios->offset + 0x98]); - } - - if (!volt) { - NV_DEBUG(drm, "voltage table pointer invalid\n"); - return; - } - - switch (volt[0]) { - case 0x10: - case 0x11: - case 0x12: - headerlen = 5; - recordlen = volt[1]; - entries = volt[2]; - vidshift = 0; - vidmask = volt[4]; - break; - case 0x20: - headerlen = volt[1]; - recordlen = volt[3]; - entries = volt[2]; - vidshift = 0; /* could be vidshift like 0x30? */ - vidmask = volt[5]; - break; - case 0x30: - headerlen = volt[1]; - recordlen = volt[2]; - entries = volt[3]; - vidmask = volt[4]; - /* no longer certain what volt[5] is, if it's related to - * the vid shift then it's definitely not a function of - * how many bits are set. - * - * after looking at a number of nva3+ vbios images, they - * all seem likely to have a static shift of 2.. lets - * go with that for now until proven otherwise. - */ - vidshift = 2; - break; - case 0x40: - headerlen = volt[1]; - recordlen = volt[2]; - entries = volt[3]; /* not a clue what the entries are for.. */ - vidmask = volt[11]; /* guess.. */ - vidshift = 0; - break; - default: - NV_WARN(drm, "voltage table 0x%02x unknown\n", volt[0]); - return; - } - - /* validate vid mask */ - voltage->vid_mask = vidmask; - if (!voltage->vid_mask) - return; - - i = 0; - while (vidmask) { - if (i > nr_vidtag) { - NV_DEBUG(drm, "vid bit %d unknown\n", i); - return; - } - - if (gpio && gpio->find(gpio, 0, vidtag[i], 0xff, &func)) { - NV_DEBUG(drm, "vid bit %d has no gpio tag\n", i); - return; - } - - vidmask >>= 1; - i++; - } - - /* parse vbios entries into common format */ - voltage->version = volt[0]; - if (voltage->version < 0x40) { - voltage->nr_level = entries; - voltage->level = - kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); - if (!voltage->level) - return; - - entry = volt + headerlen; - for (i = 0; i < entries; i++, entry += recordlen) { - voltage->level[i].voltage = entry[0] * 10000; - voltage->level[i].vid = entry[1] >> vidshift; - } - } else { - u32 volt_uv = ROM32(volt[4]); - s16 step_uv = ROM16(volt[8]); - u8 vid; - - voltage->nr_level = voltage->vid_mask + 1; - voltage->level = kcalloc(voltage->nr_level, - sizeof(*voltage->level), GFP_KERNEL); - if (!voltage->level) - return; - - for (vid = 0; vid <= voltage->vid_mask; vid++) { - voltage->level[vid].voltage = volt_uv; - voltage->level[vid].vid = vid; - volt_uv += step_uv; - } - } - - voltage->supported = true; -} - -void -nouveau_volt_fini(struct drm_device *dev) -{ - struct nouveau_pm_voltage *volt = &nouveau_pm(dev)->voltage; - - kfree(volt->level); -} diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 77dcc9c5077..8fe32bbed99 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -255,6 +255,12 @@ nv04_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, NvCtxSurf2D); BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1); OUT_RING(chan, 3); + if (device->chipset >= 0x11 /*XXX: oclass == 0x009f*/) { + BEGIN_NV04(chan, NvSubImageBlit, 0x0120, 3); + OUT_RING(chan, 0); + OUT_RING(chan, 1); + OUT_RING(chan, 2); + } BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1); OUT_RING(chan, NvGdiRect); diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c deleted file mode 100644 index 27afc0ea28b..00000000000 --- a/drivers/gpu/drm/nouveau/nv04_pm.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2010 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 <drm/drmP.h> -#include "nouveau_drm.h" -#include "nouveau_reg.h" -#include "dispnv04/hw.h" -#include "nouveau_pm.h" - -#include <subdev/bios/pll.h> -#include <subdev/clock.h> -#include <subdev/timer.h> - -int -nv04_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - int ret; - - ret = nouveau_hw_get_clock(dev, PLL_CORE); - if (ret < 0) - return ret; - perflvl->core = ret; - - ret = nouveau_hw_get_clock(dev, PLL_MEMORY); - if (ret < 0) - return ret; - perflvl->memory = ret; - - return 0; -} - -struct nv04_pm_clock { - struct nvbios_pll pll; - struct nouveau_pll_vals calc; -}; - -struct nv04_pm_state { - struct nv04_pm_clock core; - struct nv04_pm_clock memory; -}; - -static int -calc_pll(struct drm_device *dev, u32 id, int khz, struct nv04_pm_clock *clk) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_bios *bios = nouveau_bios(device); - struct nouveau_clock *pclk = nouveau_clock(device); - int ret; - - ret = nvbios_pll_parse(bios, id, &clk->pll); - if (ret) - return ret; - - ret = pclk->pll_calc(pclk, &clk->pll, khz, &clk->calc); - if (!ret) - return -EINVAL; - - return 0; -} - -void * -nv04_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nv04_pm_state *info; - int ret; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return ERR_PTR(-ENOMEM); - - ret = calc_pll(dev, PLL_CORE, perflvl->core, &info->core); - if (ret) - goto error; - - if (perflvl->memory) { - ret = calc_pll(dev, PLL_MEMORY, perflvl->memory, &info->memory); - if (ret) - goto error; - } - - return info; -error: - kfree(info); - return ERR_PTR(ret); -} - -static void -prog_pll(struct drm_device *dev, struct nv04_pm_clock *clk) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_clock *pclk = nouveau_clock(device); - u32 reg = clk->pll.reg; - - /* thank the insane nouveau_hw_setpll() interface for this */ - if (device->card_type >= NV_40) - reg += 4; - - pclk->pll_prog(pclk, reg, &clk->calc); -} - -int -nv04_pm_clocks_set(struct drm_device *dev, void *pre_state) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_timer *ptimer = nouveau_timer(device); - struct nv04_pm_state *state = pre_state; - - prog_pll(dev, &state->core); - - if (state->memory.pll.reg) { - prog_pll(dev, &state->memory); - if (device->card_type < NV_30) { - if (device->card_type == NV_20) - nv_mask(device, 0x1002c4, 0, 1 << 20); - - /* Reset the DLLs */ - nv_mask(device, 0x1002c0, 0, 1 << 8); - } - } - - nv_ofuncs(ptimer)->init(nv_object(ptimer)); - - kfree(state); - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c deleted file mode 100644 index 625f80d53dc..00000000000 --- a/drivers/gpu/drm/nouveau/nv40_pm.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright 2011 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 <drm/drmP.h> -#include "nouveau_drm.h" -#include "nouveau_bios.h" -#include "nouveau_pm.h" -#include "dispnv04/hw.h" - -#include <subdev/bios/pll.h> -#include <subdev/clock.h> -#include <subdev/timer.h> - -#include <engine/fifo.h> - -#define min2(a,b) ((a) < (b) ? (a) : (b)) - -static u32 -read_pll_1(struct drm_device *dev, u32 reg) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ctrl = nv_rd32(device, reg + 0x00); - int P = (ctrl & 0x00070000) >> 16; - int N = (ctrl & 0x0000ff00) >> 8; - int M = (ctrl & 0x000000ff) >> 0; - u32 ref = 27000, clk = 0; - - if (ctrl & 0x80000000) - clk = ref * N / M; - - return clk >> P; -} - -static u32 -read_pll_2(struct drm_device *dev, u32 reg) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ctrl = nv_rd32(device, reg + 0x00); - u32 coef = nv_rd32(device, reg + 0x04); - int N2 = (coef & 0xff000000) >> 24; - int M2 = (coef & 0x00ff0000) >> 16; - int N1 = (coef & 0x0000ff00) >> 8; - int M1 = (coef & 0x000000ff) >> 0; - int P = (ctrl & 0x00070000) >> 16; - u32 ref = 27000, clk = 0; - - if ((ctrl & 0x80000000) && M1) { - clk = ref * N1 / M1; - if ((ctrl & 0x40000100) == 0x40000000) { - if (M2) - clk = clk * N2 / M2; - else - clk = 0; - } - } - - return clk >> P; -} - -static u32 -read_clk(struct drm_device *dev, u32 src) -{ - switch (src) { - case 3: - return read_pll_2(dev, 0x004000); - case 2: - return read_pll_1(dev, 0x004008); - default: - break; - } - - return 0; -} - -int -nv40_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ctrl = nv_rd32(device, 0x00c040); - - perflvl->core = read_clk(dev, (ctrl & 0x00000003) >> 0); - perflvl->shader = read_clk(dev, (ctrl & 0x00000030) >> 4); - perflvl->memory = read_pll_2(dev, 0x4020); - return 0; -} - -struct nv40_pm_state { - u32 ctrl; - u32 npll_ctrl; - u32 npll_coef; - u32 spll; - u32 mpll_ctrl; - u32 mpll_coef; -}; - -static int -nv40_calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll, - u32 clk, int *N1, int *M1, int *N2, int *M2, int *log2P) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_bios *bios = nouveau_bios(device); - struct nouveau_clock *pclk = nouveau_clock(device); - struct nouveau_pll_vals coef; - int ret; - - ret = nvbios_pll_parse(bios, reg, pll); - if (ret) - return ret; - - if (clk < pll->vco1.max_freq) - pll->vco2.max_freq = 0; - - ret = pclk->pll_calc(pclk, pll, clk, &coef); - if (ret == 0) - return -ERANGE; - - *N1 = coef.N1; - *M1 = coef.M1; - if (N2 && M2) { - if (pll->vco2.max_freq) { - *N2 = coef.N2; - *M2 = coef.M2; - } else { - *N2 = 1; - *M2 = 1; - } - } - *log2P = coef.log2P; - return 0; -} - -void * -nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nv40_pm_state *info; - struct nvbios_pll pll; - int N1, N2, M1, M2, log2P; - int ret; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return ERR_PTR(-ENOMEM); - - /* core/geometric clock */ - ret = nv40_calc_pll(dev, 0x004000, &pll, perflvl->core, - &N1, &M1, &N2, &M2, &log2P); - if (ret < 0) - goto out; - - if (N2 == M2) { - info->npll_ctrl = 0x80000100 | (log2P << 16); - info->npll_coef = (N1 << 8) | M1; - } else { - info->npll_ctrl = 0xc0000000 | (log2P << 16); - info->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; - } - - /* use the second PLL for shader/rop clock, if it differs from core */ - if (perflvl->shader && perflvl->shader != perflvl->core) { - ret = nv40_calc_pll(dev, 0x004008, &pll, perflvl->shader, - &N1, &M1, NULL, NULL, &log2P); - if (ret < 0) - goto out; - - info->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; - info->ctrl = 0x00000223; - } else { - info->spll = 0x00000000; - info->ctrl = 0x00000333; - } - - /* memory clock */ - if (!perflvl->memory) { - info->mpll_ctrl = 0x00000000; - goto out; - } - - ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory, - &N1, &M1, &N2, &M2, &log2P); - if (ret < 0) - goto out; - - info->mpll_ctrl = 0x80000000 | (log2P << 16); - info->mpll_ctrl |= min2(pll.bias_p + log2P, pll.max_p) << 20; - if (N2 == M2) { - info->mpll_ctrl |= 0x00000100; - info->mpll_coef = (N1 << 8) | M1; - } else { - info->mpll_ctrl |= 0x40000000; - info->mpll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; - } - -out: - if (ret < 0) { - kfree(info); - info = ERR_PTR(ret); - } - return info; -} - -static bool -nv40_pm_gr_idle(void *data) -{ - struct drm_device *dev = data; - struct nouveau_device *device = nouveau_dev(dev); - - if ((nv_rd32(device, 0x400760) & 0x000000f0) >> 4 != - (nv_rd32(device, 0x400760) & 0x0000000f)) - return false; - - if (nv_rd32(device, 0x400700)) - return false; - - return true; -} - -int -nv40_pm_clocks_set(struct drm_device *dev, void *pre_state) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_fifo *pfifo = nouveau_fifo(device); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nv40_pm_state *info = pre_state; - unsigned long flags; - struct bit_entry M; - u32 crtc_mask = 0; - u8 sr1[2]; - int i, ret = -EAGAIN; - - /* determine which CRTCs are active, fetch VGA_SR1 for each */ - for (i = 0; i < 2; i++) { - u32 vbl = nv_rd32(device, 0x600808 + (i * 0x2000)); - u32 cnt = 0; - do { - if (vbl != nv_rd32(device, 0x600808 + (i * 0x2000))) { - nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); - sr1[i] = nv_rd08(device, 0x0c03c5 + (i * 0x2000)); - if (!(sr1[i] & 0x20)) - crtc_mask |= (1 << i); - break; - } - udelay(1); - } while (cnt++ < 32); - } - - /* halt and idle engines */ - pfifo->pause(pfifo, &flags); - - if (!nv_wait_cb(device, nv40_pm_gr_idle, dev)) - goto resume; - - ret = 0; - - /* set engine clocks */ - nv_mask(device, 0x00c040, 0x00000333, 0x00000000); - nv_wr32(device, 0x004004, info->npll_coef); - nv_mask(device, 0x004000, 0xc0070100, info->npll_ctrl); - nv_mask(device, 0x004008, 0xc007ffff, info->spll); - mdelay(5); - nv_mask(device, 0x00c040, 0x00000333, info->ctrl); - - if (!info->mpll_ctrl) - goto resume; - - /* wait for vblank start on active crtcs, disable memory access */ - for (i = 0; i < 2; i++) { - if (!(crtc_mask & (1 << i))) - continue; - nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); - nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); - } - - /* prepare ram for reclocking */ - nv_wr32(device, 0x1002d4, 0x00000001); /* precharge */ - nv_wr32(device, 0x1002d0, 0x00000001); /* refresh */ - nv_wr32(device, 0x1002d0, 0x00000001); /* refresh */ - nv_mask(device, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ - nv_wr32(device, 0x1002dc, 0x00000001); /* enable self-refresh */ - - /* change the PLL of each memory partition */ - nv_mask(device, 0x00c040, 0x0000c000, 0x00000000); - switch (nv_device(drm->device)->chipset) { - case 0x40: - case 0x45: - case 0x41: - case 0x42: - case 0x47: - nv_mask(device, 0x004044, 0xc0771100, info->mpll_ctrl); - nv_mask(device, 0x00402c, 0xc0771100, info->mpll_ctrl); - nv_wr32(device, 0x004048, info->mpll_coef); - nv_wr32(device, 0x004030, info->mpll_coef); - case 0x43: - case 0x49: - case 0x4b: - nv_mask(device, 0x004038, 0xc0771100, info->mpll_ctrl); - nv_wr32(device, 0x00403c, info->mpll_coef); - default: - nv_mask(device, 0x004020, 0xc0771100, info->mpll_ctrl); - nv_wr32(device, 0x004024, info->mpll_coef); - break; - } - udelay(100); - nv_mask(device, 0x00c040, 0x0000c000, 0x0000c000); - - /* re-enable normal operation of memory controller */ - nv_wr32(device, 0x1002dc, 0x00000000); - nv_mask(device, 0x100210, 0x80000000, 0x80000000); - udelay(100); - - /* execute memory reset script from vbios */ - if (!bit_table(dev, 'M', &M)) - nouveau_bios_run_init_table(dev, ROM16(M.data[0]), NULL, 0); - - /* make sure we're in vblank (hopefully the same one as before), and - * then re-enable crtc memory access - */ - for (i = 0; i < 2; i++) { - if (!(crtc_mask & (1 << i))) - continue; - nv_wait(device, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]); - } - - /* resume engines */ -resume: - pfifo->start(pfifo, &flags); - kfree(info); - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index f8e66c08b11..4c534b7b04d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1,4 +1,4 @@ - /* +/* * Copyright 2011 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_dp_helper.h> #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -651,7 +652,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) nv_connector = nouveau_crtc_connector_get(nv_crtc); connector = &nv_connector->base; if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) { - if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3) + if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3) mode = DITHERING_MODE_DYNAMIC2X2; } else { mode = nv_connector->dithering_mode; @@ -785,7 +786,8 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) if (update) { nv50_display_flip_stop(crtc); - nv50_display_flip_next(crtc, crtc->fb, NULL, 1); + nv50_display_flip_next(crtc, crtc->primary->fb, + NULL, 1); } } @@ -956,7 +958,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc) nv50_display_flip_stop(crtc); - push = evo_wait(mast, 2); + push = evo_wait(mast, 6); if (push) { if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) { evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); @@ -1028,20 +1030,21 @@ nv50_crtc_commit(struct drm_crtc *crtc) } nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true); - nv50_display_flip_next(crtc, crtc->fb, NULL, 1); + nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); } static bool nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); return true; } static int nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { - struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); + struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb); struct nv50_head *head = nv50_head(crtc); int ret; @@ -1138,7 +1141,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, nv50_crtc_set_dither(nv_crtc, false); nv50_crtc_set_scale(nv_crtc, false); nv50_crtc_set_color_vibrance(nv_crtc, false); - nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false); + nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false); return 0; } @@ -1150,7 +1153,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); int ret; - if (!crtc->fb) { + if (!crtc->primary->fb) { NV_DEBUG(drm, "No FB bound\n"); return 0; } @@ -1160,8 +1163,8 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return ret; nv50_display_flip_stop(crtc); - nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true); - nv50_display_flip_next(crtc, crtc->fb, NULL, 1); + nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true); + nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); return 0; } @@ -1205,6 +1208,7 @@ static void nv50_crtc_disable(struct drm_crtc *crtc) { struct nv50_head *head = nv50_head(crtc); + evo_sync(crtc->dev); if (head->image) nouveau_bo_unpin(head->image); nouveau_bo_ref(NULL, &head->image); @@ -1265,7 +1269,7 @@ nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, uint32_t size) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - u32 end = max(start + size, (u32)256); + u32 end = min_t(u32, start + size, 256); u32 i; for (i = start; i < end; i++) { @@ -1698,10 +1702,9 @@ nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) } static void -nv50_hdmi_disconnect(struct drm_encoder *encoder) +nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); struct nv50_disp *disp = nv50_disp(encoder->dev); const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; @@ -1720,7 +1723,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct nv50_disp *disp = nv50_disp(dev); struct drm_encoder *partner; - int or = nv_encoder->or; + u32 mthd; nv_encoder->last_dpms = mode; @@ -1738,7 +1741,18 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) } } - nv_call(disp->core, NV50_DISP_SOR_PWR + or, (mode == DRM_MODE_DPMS_ON)); + 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; + } else { + mthd |= NV50_DISP_SOR_PWR; + } + + nv_call(disp->core, mthd, (mode == DRM_MODE_DPMS_ON)); } static bool @@ -1762,33 +1776,36 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder, } static void -nv50_sor_disconnect(struct drm_encoder *encoder) +nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_mast *mast = nv50_mast(encoder->dev); - const int or = nv_encoder->or; - u32 *push; - - if (nv_encoder->crtc) { - nv50_crtc_prepare(nv_encoder->crtc); - - push = evo_wait(mast, 4); - if (push) { - if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { - evo_mthd(push, 0x0600 + (or * 0x40), 1); - evo_data(push, 0x00000000); - } else { - evo_mthd(push, 0x0200 + (or * 0x20), 1); - evo_data(push, 0x00000000); - } - evo_kick(push, mast); + 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) { + evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1); + evo_data(push, (nv_encoder->ctrl = temp)); + } else { + evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); + evo_data(push, (nv_encoder->ctrl = temp)); } - - nv50_hdmi_disconnect(encoder); + evo_kick(push, mast); } +} + +static void +nv50_sor_disconnect(struct drm_encoder *encoder) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; nv_encoder->crtc = NULL; + + if (nv_crtc) { + nv50_crtc_prepare(&nv_crtc->base); + nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0); + nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc); + } } static void @@ -1808,12 +1825,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct nouveau_connector *nv_connector; struct nvbios *bios = &drm->vbios; - u32 *push, lvds = 0; + u32 lvds = 0, mask, ctrl; u8 owner = 1 << nv_crtc->index; u8 proto = 0xf; u8 depth = 0x0; nv_connector = nouveau_encoder_connector_get(nv_encoder); + nv_encoder->crtc = encoder->crtc; + switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: if (nv_encoder->dcb->sorconf.link & 1) { @@ -1825,7 +1844,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, proto = 0x2; } - nv50_hdmi_mode_set(encoder, mode); + nv50_hdmi_mode_set(&nv_encoder->base.base, mode); break; case DCB_OUTPUT_LVDS: proto = 0x0; @@ -1881,19 +1900,11 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, break; } - nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); + nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON); - push = evo_wait(nv50_mast(dev), 8); - if (push) { - if (nv50_vers(mast) < NVD0_DISP_CLASS) { - u32 ctrl = (depth << 16) | (proto << 8) | owner; - if (mode->flags & DRM_MODE_FLAG_NHSYNC) - ctrl |= 0x00001000; - if (mode->flags & DRM_MODE_FLAG_NVSYNC) - ctrl |= 0x00002000; - evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1); - evo_data(push, ctrl); - } else { + if (nv50_vers(mast) >= NVD0_DISP_CLASS) { + u32 *push = evo_wait(mast, 3); + if (push) { u32 magic = 0x31ec6000 | (nv_crtc->index << 25); u32 syncs = 0x00000001; @@ -1908,14 +1919,21 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2); evo_data(push, syncs | (depth << 6)); evo_data(push, magic); - evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 1); - evo_data(push, owner | (proto << 8)); + evo_kick(push, mast); } - evo_kick(push, mast); + ctrl = proto << 8; + mask = 0x00000f00; + } else { + ctrl = (depth << 16) | (proto << 8); + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + ctrl |= 0x00001000; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + ctrl |= 0x00002000; + mask = 0x000f3f00; } - nv_encoder->crtc = encoder->crtc; + nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner); } static void @@ -2199,16 +2217,6 @@ nv50_display_destroy(struct drm_device *dev) int nv50_display_create(struct drm_device *dev) { - static const u16 oclass[] = { - NVF0_DISP_CLASS, - NVE0_DISP_CLASS, - NVD0_DISP_CLASS, - NVA3_DISP_CLASS, - NV94_DISP_CLASS, - NVA0_DISP_CLASS, - NV84_DISP_CLASS, - NV50_DISP_CLASS, - }; struct nouveau_device *device = nouveau_dev(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct dcb_table *dcb = &drm->vbios.dcb; @@ -2225,6 +2233,7 @@ nv50_display_create(struct drm_device *dev) nouveau_display(dev)->dtor = nv50_display_destroy; nouveau_display(dev)->init = nv50_display_init; nouveau_display(dev)->fini = nv50_display_fini; + disp->core = nouveau_display(dev)->core; /* small shared memory area we use for notifiers and semaphores */ ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, @@ -2243,17 +2252,6 @@ nv50_display_create(struct drm_device *dev) if (ret) goto out; - /* attempt to allocate a supported evo display class */ - ret = -ENODEV; - for (i = 0; ret && i < ARRAY_SIZE(oclass); i++) { - ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, - 0xd1500000, oclass[i], NULL, 0, - &disp->core); - } - - if (ret) - goto out; - /* allocate master evo channel */ ret = nv50_dmac_create(disp->core, NV50_DISP_MAST_CLASS, 0, &(struct nv50_display_mast_class) { @@ -2313,7 +2311,7 @@ nv50_display_create(struct drm_device *dev) continue; NV_WARN(drm, "%s has no encoders, removing\n", - drm_get_connector_name(connector)); + connector->name); connector->funcs->destroy(connector); } diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c deleted file mode 100644 index 4efc33fa73f..00000000000 --- a/drivers/gpu/drm/nouveau/nv50_pm.c +++ /dev/null @@ -1,855 +0,0 @@ -/* - * Copyright 2010 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 <drm/drmP.h> -#include "nouveau_drm.h" -#include "nouveau_bios.h" -#include "dispnv04/hw.h" -#include "nouveau_pm.h" -#include "nouveau_hwsq.h" - -#include "nv50_display.h" - -#include <subdev/bios/pll.h> -#include <subdev/clock.h> -#include <subdev/timer.h> -#include <subdev/fb.h> - -enum clk_src { - clk_src_crystal, - clk_src_href, - clk_src_hclk, - clk_src_hclkm3, - clk_src_hclkm3d2, - clk_src_host, - clk_src_nvclk, - clk_src_sclk, - clk_src_mclk, - clk_src_vdec, - clk_src_dom6 -}; - -static u32 read_clk(struct drm_device *, enum clk_src); - -static u32 -read_div(struct drm_device *dev) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - - switch (nv_device(drm->device)->chipset) { - case 0x50: /* it exists, but only has bit 31, not the dividers.. */ - case 0x84: - case 0x86: - case 0x98: - case 0xa0: - return nv_rd32(device, 0x004700); - case 0x92: - case 0x94: - case 0x96: - return nv_rd32(device, 0x004800); - default: - return 0x00000000; - } -} - -static u32 -read_pll_src(struct drm_device *dev, u32 base) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - u32 coef, ref = read_clk(dev, clk_src_crystal); - u32 rsel = nv_rd32(device, 0x00e18c); - int P, N, M, id; - - switch (nv_device(drm->device)->chipset) { - case 0x50: - case 0xa0: - switch (base) { - case 0x4020: - case 0x4028: id = !!(rsel & 0x00000004); break; - case 0x4008: id = !!(rsel & 0x00000008); break; - case 0x4030: id = 0; break; - default: - NV_ERROR(drm, "ref: bad pll 0x%06x\n", base); - return 0; - } - - coef = nv_rd32(device, 0x00e81c + (id * 0x0c)); - ref *= (coef & 0x01000000) ? 2 : 4; - P = (coef & 0x00070000) >> 16; - N = ((coef & 0x0000ff00) >> 8) + 1; - M = ((coef & 0x000000ff) >> 0) + 1; - break; - case 0x84: - case 0x86: - case 0x92: - coef = nv_rd32(device, 0x00e81c); - P = (coef & 0x00070000) >> 16; - N = (coef & 0x0000ff00) >> 8; - M = (coef & 0x000000ff) >> 0; - break; - case 0x94: - case 0x96: - case 0x98: - rsel = nv_rd32(device, 0x00c050); - switch (base) { - case 0x4020: rsel = (rsel & 0x00000003) >> 0; break; - case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break; - case 0x4028: rsel = (rsel & 0x00001800) >> 11; break; - case 0x4030: rsel = 3; break; - default: - NV_ERROR(drm, "ref: bad pll 0x%06x\n", base); - return 0; - } - - switch (rsel) { - case 0: id = 1; break; - case 1: return read_clk(dev, clk_src_crystal); - case 2: return read_clk(dev, clk_src_href); - case 3: id = 0; break; - } - - coef = nv_rd32(device, 0x00e81c + (id * 0x28)); - P = (nv_rd32(device, 0x00e824 + (id * 0x28)) >> 16) & 7; - P += (coef & 0x00070000) >> 16; - N = (coef & 0x0000ff00) >> 8; - M = (coef & 0x000000ff) >> 0; - break; - default: - BUG_ON(1); - } - - if (M) - return (ref * N / M) >> P; - return 0; -} - -static u32 -read_pll_ref(struct drm_device *dev, u32 base) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - u32 src, mast = nv_rd32(device, 0x00c040); - - switch (base) { - case 0x004028: - src = !!(mast & 0x00200000); - break; - case 0x004020: - src = !!(mast & 0x00400000); - break; - case 0x004008: - src = !!(mast & 0x00010000); - break; - case 0x004030: - src = !!(mast & 0x02000000); - break; - case 0x00e810: - return read_clk(dev, clk_src_crystal); - default: - NV_ERROR(drm, "bad pll 0x%06x\n", base); - return 0; - } - - if (src) - return read_clk(dev, clk_src_href); - return read_pll_src(dev, base); -} - -static u32 -read_pll(struct drm_device *dev, u32 base) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - u32 mast = nv_rd32(device, 0x00c040); - u32 ctrl = nv_rd32(device, base + 0); - u32 coef = nv_rd32(device, base + 4); - u32 ref = read_pll_ref(dev, base); - u32 clk = 0; - int N1, N2, M1, M2; - - if (base == 0x004028 && (mast & 0x00100000)) { - /* wtf, appears to only disable post-divider on nva0 */ - if (nv_device(drm->device)->chipset != 0xa0) - return read_clk(dev, clk_src_dom6); - } - - N2 = (coef & 0xff000000) >> 24; - M2 = (coef & 0x00ff0000) >> 16; - N1 = (coef & 0x0000ff00) >> 8; - M1 = (coef & 0x000000ff); - if ((ctrl & 0x80000000) && M1) { - clk = ref * N1 / M1; - if ((ctrl & 0x40000100) == 0x40000000) { - if (M2) - clk = clk * N2 / M2; - else - clk = 0; - } - } - - return clk; -} - -static u32 -read_clk(struct drm_device *dev, enum clk_src src) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - u32 mast = nv_rd32(device, 0x00c040); - u32 P = 0; - - switch (src) { - case clk_src_crystal: - return device->crystal; - case clk_src_href: - return 100000; /* PCIE reference clock */ - case clk_src_hclk: - return read_clk(dev, clk_src_href) * 27778 / 10000; - case clk_src_hclkm3: - return read_clk(dev, clk_src_hclk) * 3; - case clk_src_hclkm3d2: - return read_clk(dev, clk_src_hclk) * 3 / 2; - case clk_src_host: - switch (mast & 0x30000000) { - case 0x00000000: return read_clk(dev, clk_src_href); - case 0x10000000: break; - case 0x20000000: /* !0x50 */ - case 0x30000000: return read_clk(dev, clk_src_hclk); - } - break; - case clk_src_nvclk: - if (!(mast & 0x00100000)) - P = (nv_rd32(device, 0x004028) & 0x00070000) >> 16; - switch (mast & 0x00000003) { - case 0x00000000: return read_clk(dev, clk_src_crystal) >> P; - case 0x00000001: return read_clk(dev, clk_src_dom6); - case 0x00000002: return read_pll(dev, 0x004020) >> P; - case 0x00000003: return read_pll(dev, 0x004028) >> P; - } - break; - case clk_src_sclk: - P = (nv_rd32(device, 0x004020) & 0x00070000) >> 16; - switch (mast & 0x00000030) { - case 0x00000000: - if (mast & 0x00000080) - return read_clk(dev, clk_src_host) >> P; - return read_clk(dev, clk_src_crystal) >> P; - case 0x00000010: break; - case 0x00000020: return read_pll(dev, 0x004028) >> P; - case 0x00000030: return read_pll(dev, 0x004020) >> P; - } - break; - case clk_src_mclk: - P = (nv_rd32(device, 0x004008) & 0x00070000) >> 16; - if (nv_rd32(device, 0x004008) & 0x00000200) { - switch (mast & 0x0000c000) { - case 0x00000000: - return read_clk(dev, clk_src_crystal) >> P; - case 0x00008000: - case 0x0000c000: - return read_clk(dev, clk_src_href) >> P; - } - } else { - return read_pll(dev, 0x004008) >> P; - } - break; - case clk_src_vdec: - P = (read_div(dev) & 0x00000700) >> 8; - switch (nv_device(drm->device)->chipset) { - case 0x84: - case 0x86: - case 0x92: - case 0x94: - case 0x96: - case 0xa0: - switch (mast & 0x00000c00) { - case 0x00000000: - if (nv_device(drm->device)->chipset == 0xa0) /* wtf?? */ - return read_clk(dev, clk_src_nvclk) >> P; - return read_clk(dev, clk_src_crystal) >> P; - case 0x00000400: - return 0; - case 0x00000800: - if (mast & 0x01000000) - return read_pll(dev, 0x004028) >> P; - return read_pll(dev, 0x004030) >> P; - case 0x00000c00: - return read_clk(dev, clk_src_nvclk) >> P; - } - break; - case 0x98: - switch (mast & 0x00000c00) { - case 0x00000000: - return read_clk(dev, clk_src_nvclk) >> P; - case 0x00000400: - return 0; - case 0x00000800: - return read_clk(dev, clk_src_hclkm3d2) >> P; - case 0x00000c00: - return read_clk(dev, clk_src_mclk) >> P; - } - break; - } - break; - case clk_src_dom6: - switch (nv_device(drm->device)->chipset) { - case 0x50: - case 0xa0: - return read_pll(dev, 0x00e810) >> 2; - case 0x84: - case 0x86: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - P = (read_div(dev) & 0x00000007) >> 0; - switch (mast & 0x0c000000) { - case 0x00000000: return read_clk(dev, clk_src_href); - case 0x04000000: break; - case 0x08000000: return read_clk(dev, clk_src_hclk); - case 0x0c000000: - return read_clk(dev, clk_src_hclkm3) >> P; - } - break; - default: - break; - } - default: - break; - } - - NV_DEBUG(drm, "unknown clock source %d 0x%08x\n", src, mast); - return 0; -} - -int -nv50_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (nv_device(drm->device)->chipset == 0xaa || - nv_device(drm->device)->chipset == 0xac) - return 0; - - perflvl->core = read_clk(dev, clk_src_nvclk); - perflvl->shader = read_clk(dev, clk_src_sclk); - perflvl->memory = read_clk(dev, clk_src_mclk); - if (nv_device(drm->device)->chipset != 0x50) { - perflvl->vdec = read_clk(dev, clk_src_vdec); - perflvl->dom6 = read_clk(dev, clk_src_dom6); - } - - return 0; -} - -struct nv50_pm_state { - struct nouveau_pm_level *perflvl; - struct hwsq_ucode eclk_hwsq; - struct hwsq_ucode mclk_hwsq; - u32 mscript; - u32 mmast; - u32 mctrl; - u32 mcoef; -}; - -static u32 -calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll, - u32 clk, int *N1, int *M1, int *log2P) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_bios *bios = nouveau_bios(device); - struct nouveau_clock *pclk = nouveau_clock(device); - struct nouveau_pll_vals coef; - int ret; - - ret = nvbios_pll_parse(bios, reg, pll); - if (ret) - return 0; - - pll->vco2.max_freq = 0; - pll->refclk = read_pll_ref(dev, reg); - if (!pll->refclk) - return 0; - - ret = pclk->pll_calc(pclk, pll, clk, &coef); - if (ret == 0) - return 0; - - *N1 = coef.N1; - *M1 = coef.M1; - *log2P = coef.log2P; - return ret; -} - -static inline u32 -calc_div(u32 src, u32 target, int *div) -{ - u32 clk0 = src, clk1 = src; - for (*div = 0; *div <= 7; (*div)++) { - if (clk0 <= target) { - clk1 = clk0 << (*div ? 1 : 0); - break; - } - clk0 >>= 1; - } - - if (target - clk0 <= clk1 - target) - return clk0; - (*div)--; - return clk1; -} - -static inline u32 -clk_same(u32 a, u32 b) -{ - return ((a / 1000) == (b / 1000)); -} - -static void -mclk_precharge(struct nouveau_mem_exec_func *exec) -{ - struct nv50_pm_state *info = exec->priv; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - - hwsq_wr32(hwsq, 0x1002d4, 0x00000001); -} - -static void -mclk_refresh(struct nouveau_mem_exec_func *exec) -{ - struct nv50_pm_state *info = exec->priv; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - - hwsq_wr32(hwsq, 0x1002d0, 0x00000001); -} - -static void -mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable) -{ - struct nv50_pm_state *info = exec->priv; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - - hwsq_wr32(hwsq, 0x100210, enable ? 0x80000000 : 0x00000000); -} - -static void -mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable) -{ - struct nv50_pm_state *info = exec->priv; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - - hwsq_wr32(hwsq, 0x1002dc, enable ? 0x00000001 : 0x00000000); -} - -static void -mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec) -{ - struct nv50_pm_state *info = exec->priv; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - - if (nsec > 1000) - hwsq_usec(hwsq, (nsec + 500) / 1000); -} - -static u32 -mclk_mrg(struct nouveau_mem_exec_func *exec, int mr) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - if (mr <= 1) - return nv_rd32(device, 0x1002c0 + ((mr - 0) * 4)); - if (mr <= 3) - return nv_rd32(device, 0x1002e0 + ((mr - 2) * 4)); - return 0; -} - -static void -mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nouveau_fb *pfb = nouveau_fb(device); - struct nv50_pm_state *info = exec->priv; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - - if (mr <= 1) { - if (pfb->ram->ranks > 1) - hwsq_wr32(hwsq, 0x1002c8 + ((mr - 0) * 4), data); - hwsq_wr32(hwsq, 0x1002c0 + ((mr - 0) * 4), data); - } else - if (mr <= 3) { - if (pfb->ram->ranks > 1) - hwsq_wr32(hwsq, 0x1002e8 + ((mr - 2) * 4), data); - hwsq_wr32(hwsq, 0x1002e0 + ((mr - 2) * 4), data); - } -} - -static void -mclk_clock_set(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nv50_pm_state *info = exec->priv; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - u32 ctrl = nv_rd32(device, 0x004008); - - info->mmast = nv_rd32(device, 0x00c040); - info->mmast &= ~0xc0000000; /* get MCLK_2 from HREF */ - info->mmast |= 0x0000c000; /* use MCLK_2 as MPLL_BYPASS clock */ - - hwsq_wr32(hwsq, 0xc040, info->mmast); - hwsq_wr32(hwsq, 0x4008, ctrl | 0x00000200); /* bypass MPLL */ - if (info->mctrl & 0x80000000) - hwsq_wr32(hwsq, 0x400c, info->mcoef); - hwsq_wr32(hwsq, 0x4008, info->mctrl); -} - -static void -mclk_timing_set(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nv50_pm_state *info = exec->priv; - struct nouveau_pm_level *perflvl = info->perflvl; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - int i; - - for (i = 0; i < 9; i++) { - u32 reg = 0x100220 + (i * 4); - u32 val = nv_rd32(device, reg); - if (val != perflvl->timing.reg[i]) - hwsq_wr32(hwsq, reg, perflvl->timing.reg[i]); - } -} - -static int -calc_mclk(struct drm_device *dev, struct nouveau_pm_level *perflvl, - struct nv50_pm_state *info) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nouveau_dev(dev); - u32 crtc_mask = 0; /*XXX: nv50_display_active_crtcs(dev); */ - struct nouveau_mem_exec_func exec = { - .dev = dev, - .precharge = mclk_precharge, - .refresh = mclk_refresh, - .refresh_auto = mclk_refresh_auto, - .refresh_self = mclk_refresh_self, - .wait = mclk_wait, - .mrg = mclk_mrg, - .mrs = mclk_mrs, - .clock_set = mclk_clock_set, - .timing_set = mclk_timing_set, - .priv = info - }; - struct hwsq_ucode *hwsq = &info->mclk_hwsq; - struct nvbios_pll pll; - int N, M, P; - int ret; - - /* use pcie refclock if possible, otherwise use mpll */ - info->mctrl = nv_rd32(device, 0x004008); - info->mctrl &= ~0x81ff0200; - if (clk_same(perflvl->memory, read_clk(dev, clk_src_href))) { - info->mctrl |= 0x00000200 | (pll.bias_p << 19); - } else { - ret = calc_pll(dev, 0x4008, &pll, perflvl->memory, &N, &M, &P); - if (ret == 0) - return -EINVAL; - - info->mctrl |= 0x80000000 | (P << 22) | (P << 16); - info->mctrl |= pll.bias_p << 19; - info->mcoef = (N << 8) | M; - } - - /* build the ucode which will reclock the memory for us */ - hwsq_init(hwsq); - if (crtc_mask) { - hwsq_op5f(hwsq, crtc_mask, 0x00); /* wait for scanout */ - hwsq_op5f(hwsq, crtc_mask, 0x01); /* wait for vblank */ - } - if (nv_device(drm->device)->chipset >= 0x92) - hwsq_wr32(hwsq, 0x611200, 0x00003300); /* disable scanout */ - hwsq_setf(hwsq, 0x10, 0); /* disable bus access */ - hwsq_op5f(hwsq, 0x00, 0x01); /* no idea :s */ - - ret = nouveau_mem_exec(&exec, perflvl); - if (ret) - return ret; - - hwsq_setf(hwsq, 0x10, 1); /* enable bus access */ - hwsq_op5f(hwsq, 0x00, 0x00); /* no idea, reverse of 0x00, 0x01? */ - if (nv_device(drm->device)->chipset >= 0x92) - hwsq_wr32(hwsq, 0x611200, 0x00003330); /* enable scanout */ - hwsq_fini(hwsq); - return 0; -} - -void * -nv50_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nv50_pm_state *info; - struct hwsq_ucode *hwsq; - struct nvbios_pll pll; - u32 out, mast, divs, ctrl; - int clk, ret = -EINVAL; - int N, M, P1, P2; - - if (nv_device(drm->device)->chipset == 0xaa || - nv_device(drm->device)->chipset == 0xac) - return ERR_PTR(-ENODEV); - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return ERR_PTR(-ENOMEM); - info->perflvl = perflvl; - - /* memory: build hwsq ucode which we'll use to reclock memory. - * use pcie refclock if possible, otherwise use mpll */ - info->mclk_hwsq.len = 0; - if (perflvl->memory) { - ret = calc_mclk(dev, perflvl, info); - if (ret) - goto error; - info->mscript = perflvl->memscript; - } - - divs = read_div(dev); - mast = info->mmast; - - /* start building HWSQ script for engine reclocking */ - hwsq = &info->eclk_hwsq; - hwsq_init(hwsq); - hwsq_setf(hwsq, 0x10, 0); /* disable bus access */ - hwsq_op5f(hwsq, 0x00, 0x01); /* wait for access disabled? */ - - /* vdec/dom6: switch to "safe" clocks temporarily */ - if (perflvl->vdec) { - mast &= ~0x00000c00; - divs &= ~0x00000700; - } - - if (perflvl->dom6) { - mast &= ~0x0c000000; - divs &= ~0x00000007; - } - - hwsq_wr32(hwsq, 0x00c040, mast); - - /* vdec: avoid modifying xpll until we know exactly how the other - * clock domains work, i suspect at least some of them can also be - * tied to xpll... - */ - if (perflvl->vdec) { - /* see how close we can get using nvclk as a source */ - clk = calc_div(perflvl->core, perflvl->vdec, &P1); - - /* see how close we can get using xpll/hclk as a source */ - if (nv_device(drm->device)->chipset != 0x98) - out = read_pll(dev, 0x004030); - else - out = read_clk(dev, clk_src_hclkm3d2); - out = calc_div(out, perflvl->vdec, &P2); - - /* select whichever gets us closest */ - if (abs((int)perflvl->vdec - clk) <= - abs((int)perflvl->vdec - out)) { - if (nv_device(drm->device)->chipset != 0x98) - mast |= 0x00000c00; - divs |= P1 << 8; - } else { - mast |= 0x00000800; - divs |= P2 << 8; - } - } - - /* dom6: nfi what this is, but we're limited to various combinations - * of the host clock frequency - */ - if (perflvl->dom6) { - if (clk_same(perflvl->dom6, read_clk(dev, clk_src_href))) { - mast |= 0x00000000; - } else - if (clk_same(perflvl->dom6, read_clk(dev, clk_src_hclk))) { - mast |= 0x08000000; - } else { - clk = read_clk(dev, clk_src_hclk) * 3; - clk = calc_div(clk, perflvl->dom6, &P1); - - mast |= 0x0c000000; - divs |= P1; - } - } - - /* vdec/dom6: complete switch to new clocks */ - switch (nv_device(drm->device)->chipset) { - case 0x92: - case 0x94: - case 0x96: - hwsq_wr32(hwsq, 0x004800, divs); - break; - default: - hwsq_wr32(hwsq, 0x004700, divs); - break; - } - - hwsq_wr32(hwsq, 0x00c040, mast); - - /* core/shader: make sure sclk/nvclk are disconnected from their - * PLLs (nvclk to dom6, sclk to hclk) - */ - if (nv_device(drm->device)->chipset < 0x92) - mast = (mast & ~0x001000b0) | 0x00100080; - else - mast = (mast & ~0x000000b3) | 0x00000081; - - hwsq_wr32(hwsq, 0x00c040, mast); - - /* core: for the moment at least, always use nvpll */ - clk = calc_pll(dev, 0x4028, &pll, perflvl->core, &N, &M, &P1); - if (clk == 0) - goto error; - - ctrl = nv_rd32(device, 0x004028) & ~0xc03f0100; - mast &= ~0x00100000; - mast |= 3; - - hwsq_wr32(hwsq, 0x004028, 0x80000000 | (P1 << 19) | (P1 << 16) | ctrl); - hwsq_wr32(hwsq, 0x00402c, (N << 8) | M); - - /* shader: tie to nvclk if possible, otherwise use spll. have to be - * very careful that the shader clock is at least twice the core, or - * some chipsets will be very unhappy. i expect most or all of these - * cases will be handled by tying to nvclk, but it's possible there's - * corners - */ - ctrl = nv_rd32(device, 0x004020) & ~0xc03f0100; - - if (P1-- && perflvl->shader == (perflvl->core << 1)) { - hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl); - hwsq_wr32(hwsq, 0x00c040, 0x00000020 | mast); - } else { - clk = calc_pll(dev, 0x4020, &pll, perflvl->shader, &N, &M, &P1); - if (clk == 0) - goto error; - ctrl |= 0x80000000; - - hwsq_wr32(hwsq, 0x004020, (P1 << 19) | (P1 << 16) | ctrl); - hwsq_wr32(hwsq, 0x004024, (N << 8) | M); - hwsq_wr32(hwsq, 0x00c040, 0x00000030 | mast); - } - - hwsq_setf(hwsq, 0x10, 1); /* enable bus access */ - hwsq_op5f(hwsq, 0x00, 0x00); /* wait for access enabled? */ - hwsq_fini(hwsq); - - return info; -error: - kfree(info); - return ERR_PTR(ret); -} - -static int -prog_hwsq(struct drm_device *dev, struct hwsq_ucode *hwsq) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - u32 hwsq_data, hwsq_kick; - int i; - - if (nv_device(drm->device)->chipset < 0x94) { - hwsq_data = 0x001400; - hwsq_kick = 0x00000003; - } else { - hwsq_data = 0x080000; - hwsq_kick = 0x00000001; - } - /* upload hwsq ucode */ - nv_mask(device, 0x001098, 0x00000008, 0x00000000); - nv_wr32(device, 0x001304, 0x00000000); - if (nv_device(drm->device)->chipset >= 0x92) - nv_wr32(device, 0x001318, 0x00000000); - for (i = 0; i < hwsq->len / 4; i++) - nv_wr32(device, hwsq_data + (i * 4), hwsq->ptr.u32[i]); - nv_mask(device, 0x001098, 0x00000018, 0x00000018); - - /* launch, and wait for completion */ - nv_wr32(device, 0x00130c, hwsq_kick); - if (!nv_wait(device, 0x001308, 0x00000100, 0x00000000)) { - NV_ERROR(drm, "hwsq ucode exec timed out\n"); - NV_ERROR(drm, "0x001308: 0x%08x\n", nv_rd32(device, 0x001308)); - for (i = 0; i < hwsq->len / 4; i++) { - NV_ERROR(drm, "0x%06x: 0x%08x\n", 0x1400 + (i * 4), - nv_rd32(device, 0x001400 + (i * 4))); - } - - return -EIO; - } - - return 0; -} - -int -nv50_pm_clocks_set(struct drm_device *dev, void *data) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nv50_pm_state *info = data; - struct bit_entry M; - int ret = -EBUSY; - - /* halt and idle execution engines */ - nv_mask(device, 0x002504, 0x00000001, 0x00000001); - if (!nv_wait(device, 0x002504, 0x00000010, 0x00000010)) - goto resume; - if (!nv_wait(device, 0x00251c, 0x0000003f, 0x0000003f)) - goto resume; - - /* program memory clock, if necessary - must come before engine clock - * reprogramming due to how we construct the hwsq scripts in pre() - */ -#define nouveau_bios_init_exec(a,b) nouveau_bios_run_init_table((a), (b), NULL, 0) - if (info->mclk_hwsq.len) { - /* execute some scripts that do ??? from the vbios.. */ - if (!bit_table(dev, 'M', &M) && M.version == 1) { - if (M.length >= 6) - nouveau_bios_init_exec(dev, ROM16(M.data[5])); - if (M.length >= 8) - nouveau_bios_init_exec(dev, ROM16(M.data[7])); - if (M.length >= 10) - nouveau_bios_init_exec(dev, ROM16(M.data[9])); - nouveau_bios_init_exec(dev, info->mscript); - } - - ret = prog_hwsq(dev, &info->mclk_hwsq); - if (ret) - goto resume; - } - - /* program engine clocks */ - ret = prog_hwsq(dev, &info->eclk_hwsq); - -resume: - nv_mask(device, 0x002504, 0x00000001, 0x00000000); - kfree(info); - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c deleted file mode 100644 index 0d0ed597fea..00000000000 --- a/drivers/gpu/drm/nouveau/nva3_pm.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Copyright 2010 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 <drm/drmP.h> -#include "nouveau_drm.h" -#include "nouveau_bios.h" -#include "nouveau_pm.h" - -#include <subdev/bios/pll.h> -#include <subdev/bios.h> -#include <subdev/clock.h> -#include <subdev/timer.h> -#include <subdev/fb.h> - -static u32 read_clk(struct drm_device *, int, bool); -static u32 read_pll(struct drm_device *, int, u32); - -static u32 -read_vco(struct drm_device *dev, int clk) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 sctl = nv_rd32(device, 0x4120 + (clk * 4)); - if ((sctl & 0x00000030) != 0x00000030) - return read_pll(dev, 0x41, 0x00e820); - return read_pll(dev, 0x42, 0x00e8a0); -} - -static u32 -read_clk(struct drm_device *dev, int clk, bool ignore_en) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - u32 sctl, sdiv, sclk; - - /* refclk for the 0xe8xx plls is a fixed frequency */ - if (clk >= 0x40) { - if (nv_device(drm->device)->chipset == 0xaf) { - /* no joke.. seriously.. sigh.. */ - return nv_rd32(device, 0x00471c) * 1000; - } - - return device->crystal; - } - - sctl = nv_rd32(device, 0x4120 + (clk * 4)); - if (!ignore_en && !(sctl & 0x00000100)) - return 0; - - switch (sctl & 0x00003000) { - case 0x00000000: - return device->crystal; - case 0x00002000: - if (sctl & 0x00000040) - return 108000; - return 100000; - case 0x00003000: - sclk = read_vco(dev, clk); - sdiv = ((sctl & 0x003f0000) >> 16) + 2; - return (sclk * 2) / sdiv; - default: - return 0; - } -} - -static u32 -read_pll(struct drm_device *dev, int clk, u32 pll) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ctrl = nv_rd32(device, pll + 0); - u32 sclk = 0, P = 1, N = 1, M = 1; - - if (!(ctrl & 0x00000008)) { - if (ctrl & 0x00000001) { - u32 coef = nv_rd32(device, pll + 4); - M = (coef & 0x000000ff) >> 0; - N = (coef & 0x0000ff00) >> 8; - P = (coef & 0x003f0000) >> 16; - - /* no post-divider on these.. */ - if ((pll & 0x00ff00) == 0x00e800) - P = 1; - - sclk = read_clk(dev, 0x00 + clk, false); - } - } else { - sclk = read_clk(dev, 0x10 + clk, false); - } - - if (M * P) - return sclk * N / (M * P); - return 0; -} - -struct creg { - u32 clk; - u32 pll; -}; - -static int -calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_bios *bios = nouveau_bios(device); - struct nvbios_pll limits; - u32 oclk, sclk, sdiv; - int P, N, M, diff; - int ret; - - reg->pll = 0; - reg->clk = 0; - if (!khz) { - NV_DEBUG(drm, "no clock for 0x%04x/0x%02x\n", pll, clk); - return 0; - } - - switch (khz) { - case 27000: - reg->clk = 0x00000100; - return khz; - case 100000: - reg->clk = 0x00002100; - return khz; - case 108000: - reg->clk = 0x00002140; - return khz; - default: - sclk = read_vco(dev, 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 - * and the VBIOS on my NVA8 seem to prefer using the PLL - * for 810MHz - is there a good reason? - */ - if (sdiv > 4) { - oclk = (sclk * 2) / sdiv; - diff = khz - oclk; - if (!pll || (diff >= -2000 && diff < 3000)) { - reg->clk = (((sdiv - 2) << 16) | 0x00003100); - return oclk; - } - } - - if (!pll) { - NV_ERROR(drm, "bad freq %02x: %d %d\n", clk, khz, sclk); - return -ERANGE; - } - - break; - } - - ret = nvbios_pll_parse(bios, pll, &limits); - if (ret) - return ret; - - limits.refclk = read_clk(dev, clk - 0x10, true); - if (!limits.refclk) - return -EINVAL; - - ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); - if (ret >= 0) { - reg->clk = nv_rd32(device, 0x4120 + (clk * 4)); - reg->pll = (P << 16) | (N << 8) | M; - } - - return ret; -} - -static void -prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - const u32 src0 = 0x004120 + (clk * 4); - const u32 src1 = 0x004160 + (clk * 4); - const u32 ctrl = pll + 0; - const u32 coef = pll + 4; - - if (!reg->clk && !reg->pll) { - NV_DEBUG(drm, "no clock for %02x\n", clk); - return; - } - - if (reg->pll) { - nv_mask(device, src0, 0x00000101, 0x00000101); - nv_wr32(device, coef, reg->pll); - nv_mask(device, ctrl, 0x00000015, 0x00000015); - nv_mask(device, ctrl, 0x00000010, 0x00000000); - nv_wait(device, ctrl, 0x00020000, 0x00020000); - nv_mask(device, ctrl, 0x00000010, 0x00000010); - nv_mask(device, ctrl, 0x00000008, 0x00000000); - nv_mask(device, src1, 0x00000100, 0x00000000); - nv_mask(device, src1, 0x00000001, 0x00000000); - } else { - nv_mask(device, src1, 0x003f3141, 0x00000101 | reg->clk); - nv_mask(device, ctrl, 0x00000018, 0x00000018); - udelay(20); - nv_mask(device, ctrl, 0x00000001, 0x00000000); - nv_mask(device, src0, 0x00000100, 0x00000000); - nv_mask(device, src0, 0x00000001, 0x00000000); - } -} - -static void -prog_clk(struct drm_device *dev, int clk, struct creg *reg) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - - if (!reg->clk) { - NV_DEBUG(drm, "no clock for %02x\n", clk); - return; - } - - nv_mask(device, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk); -} - -int -nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - perflvl->core = read_pll(dev, 0x00, 0x4200); - perflvl->shader = read_pll(dev, 0x01, 0x4220); - perflvl->memory = read_pll(dev, 0x02, 0x4000); - perflvl->unka0 = read_clk(dev, 0x20, false); - perflvl->vdec = read_clk(dev, 0x21, false); - perflvl->daemon = read_clk(dev, 0x25, false); - perflvl->copy = perflvl->core; - return 0; -} - -struct nva3_pm_state { - struct nouveau_pm_level *perflvl; - - struct creg nclk; - struct creg sclk; - struct creg vdec; - struct creg unka0; - - struct creg mclk; - u8 *rammap; - u8 rammap_ver; - u8 rammap_len; - u8 *ramcfg; - u8 ramcfg_len; - u32 r004018; - u32 r100760; -}; - -void * -nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nva3_pm_state *info; - u8 ramcfg_cnt; - int ret; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return ERR_PTR(-ENOMEM); - - ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk); - if (ret < 0) - goto out; - - ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk); - if (ret < 0) - goto out; - - ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk); - if (ret < 0) - goto out; - - ret = calc_clk(dev, 0x20, 0x0000, perflvl->unka0, &info->unka0); - if (ret < 0) - goto out; - - ret = calc_clk(dev, 0x21, 0x0000, perflvl->vdec, &info->vdec); - if (ret < 0) - goto out; - - info->rammap = nouveau_perf_rammap(dev, perflvl->memory, - &info->rammap_ver, - &info->rammap_len, - &ramcfg_cnt, &info->ramcfg_len); - if (info->rammap_ver != 0x10 || info->rammap_len < 5) - info->rammap = NULL; - - info->ramcfg = nouveau_perf_ramcfg(dev, perflvl->memory, - &info->rammap_ver, - &info->ramcfg_len); - if (info->rammap_ver != 0x10) - info->ramcfg = NULL; - - info->perflvl = perflvl; -out: - if (ret < 0) { - kfree(info); - info = ERR_PTR(ret); - } - return info; -} - -static bool -nva3_pm_grcp_idle(void *data) -{ - struct drm_device *dev = data; - struct nouveau_device *device = nouveau_dev(dev); - - if (!(nv_rd32(device, 0x400304) & 0x00000001)) - return true; - if (nv_rd32(device, 0x400308) == 0x0050001c) - return true; - return false; -} - -static void -mclk_precharge(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - nv_wr32(device, 0x1002d4, 0x00000001); -} - -static void -mclk_refresh(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - nv_wr32(device, 0x1002d0, 0x00000001); -} - -static void -mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - nv_wr32(device, 0x100210, enable ? 0x80000000 : 0x00000000); -} - -static void -mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - nv_wr32(device, 0x1002dc, enable ? 0x00000001 : 0x00000000); -} - -static void -mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - volatile u32 post = nv_rd32(device, 0); (void)post; - udelay((nsec + 500) / 1000); -} - -static u32 -mclk_mrg(struct nouveau_mem_exec_func *exec, int mr) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - if (mr <= 1) - return nv_rd32(device, 0x1002c0 + ((mr - 0) * 4)); - if (mr <= 3) - return nv_rd32(device, 0x1002e0 + ((mr - 2) * 4)); - return 0; -} - -static void -mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nouveau_fb *pfb = nouveau_fb(device); - if (mr <= 1) { - if (pfb->ram->ranks > 1) - nv_wr32(device, 0x1002c8 + ((mr - 0) * 4), data); - nv_wr32(device, 0x1002c0 + ((mr - 0) * 4), data); - } else - if (mr <= 3) { - if (pfb->ram->ranks > 1) - nv_wr32(device, 0x1002e8 + ((mr - 2) * 4), data); - nv_wr32(device, 0x1002e0 + ((mr - 2) * 4), data); - } -} - -static void -mclk_clock_set(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nva3_pm_state *info = exec->priv; - u32 ctrl; - - ctrl = nv_rd32(device, 0x004000); - if (!(ctrl & 0x00000008) && info->mclk.pll) { - nv_wr32(device, 0x004000, (ctrl |= 0x00000008)); - nv_mask(device, 0x1110e0, 0x00088000, 0x00088000); - nv_wr32(device, 0x004018, 0x00001000); - nv_wr32(device, 0x004000, (ctrl &= ~0x00000001)); - nv_wr32(device, 0x004004, info->mclk.pll); - nv_wr32(device, 0x004000, (ctrl |= 0x00000001)); - udelay(64); - nv_wr32(device, 0x004018, 0x00005000 | info->r004018); - udelay(20); - } else - if (!info->mclk.pll) { - nv_mask(device, 0x004168, 0x003f3040, info->mclk.clk); - nv_wr32(device, 0x004000, (ctrl |= 0x00000008)); - nv_mask(device, 0x1110e0, 0x00088000, 0x00088000); - nv_wr32(device, 0x004018, 0x0000d000 | info->r004018); - } - - if (info->rammap) { - if (info->ramcfg && (info->rammap[4] & 0x08)) { - u32 unk5a0 = (ROM16(info->ramcfg[5]) << 8) | - info->ramcfg[5]; - u32 unk5a4 = ROM16(info->ramcfg[7]); - u32 unk804 = (info->ramcfg[9] & 0xf0) << 16 | - (info->ramcfg[3] & 0x0f) << 16 | - (info->ramcfg[9] & 0x0f) | - 0x80000000; - nv_wr32(device, 0x1005a0, unk5a0); - nv_wr32(device, 0x1005a4, unk5a4); - nv_wr32(device, 0x10f804, unk804); - nv_mask(device, 0x10053c, 0x00001000, 0x00000000); - } else { - nv_mask(device, 0x10053c, 0x00001000, 0x00001000); - nv_mask(device, 0x10f804, 0x80000000, 0x00000000); - nv_mask(device, 0x100760, 0x22222222, info->r100760); - nv_mask(device, 0x1007a0, 0x22222222, info->r100760); - nv_mask(device, 0x1007e0, 0x22222222, info->r100760); - } - } - - if (info->mclk.pll) { - nv_mask(device, 0x1110e0, 0x00088000, 0x00011000); - nv_wr32(device, 0x004000, (ctrl &= ~0x00000008)); - } -} - -static void -mclk_timing_set(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nva3_pm_state *info = exec->priv; - struct nouveau_pm_level *perflvl = info->perflvl; - int i; - - for (i = 0; i < 9; i++) - nv_wr32(device, 0x100220 + (i * 4), perflvl->timing.reg[i]); - - if (info->ramcfg) { - u32 data = (info->ramcfg[2] & 0x08) ? 0x00000000 : 0x00001000; - nv_mask(device, 0x100200, 0x00001000, data); - } - - if (info->ramcfg) { - u32 unk714 = nv_rd32(device, 0x100714) & ~0xf0000010; - u32 unk718 = nv_rd32(device, 0x100718) & ~0x00000100; - u32 unk71c = nv_rd32(device, 0x10071c) & ~0x00000100; - if ( (info->ramcfg[2] & 0x20)) - unk714 |= 0xf0000000; - if (!(info->ramcfg[2] & 0x04)) - unk714 |= 0x00000010; - nv_wr32(device, 0x100714, unk714); - - if (info->ramcfg[2] & 0x01) - unk71c |= 0x00000100; - nv_wr32(device, 0x10071c, unk71c); - - if (info->ramcfg[2] & 0x02) - unk718 |= 0x00000100; - nv_wr32(device, 0x100718, unk718); - - if (info->ramcfg[2] & 0x10) - nv_wr32(device, 0x111100, 0x48000000); /*XXX*/ - } -} - -static void -prog_mem(struct drm_device *dev, struct nva3_pm_state *info) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_mem_exec_func exec = { - .dev = dev, - .precharge = mclk_precharge, - .refresh = mclk_refresh, - .refresh_auto = mclk_refresh_auto, - .refresh_self = mclk_refresh_self, - .wait = mclk_wait, - .mrg = mclk_mrg, - .mrs = mclk_mrs, - .clock_set = mclk_clock_set, - .timing_set = mclk_timing_set, - .priv = info - }; - u32 ctrl; - - /* XXX: where the fuck does 750MHz come from? */ - if (info->perflvl->memory <= 750000) { - info->r004018 = 0x10000000; - info->r100760 = 0x22222222; - } - - ctrl = nv_rd32(device, 0x004000); - if (ctrl & 0x00000008) { - if (info->mclk.pll) { - nv_mask(device, 0x004128, 0x00000101, 0x00000101); - nv_wr32(device, 0x004004, info->mclk.pll); - nv_wr32(device, 0x004000, (ctrl |= 0x00000001)); - nv_wr32(device, 0x004000, (ctrl &= 0xffffffef)); - nv_wait(device, 0x004000, 0x00020000, 0x00020000); - nv_wr32(device, 0x004000, (ctrl |= 0x00000010)); - nv_wr32(device, 0x004018, 0x00005000 | info->r004018); - nv_wr32(device, 0x004000, (ctrl |= 0x00000004)); - } - } else { - u32 ssel = 0x00000101; - if (info->mclk.clk) - ssel |= info->mclk.clk; - else - ssel |= 0x00080000; /* 324MHz, shouldn't matter... */ - nv_mask(device, 0x004168, 0x003f3141, ctrl); - } - - if (info->ramcfg) { - if (info->ramcfg[2] & 0x10) { - nv_mask(device, 0x111104, 0x00000600, 0x00000000); - } else { - nv_mask(device, 0x111100, 0x40000000, 0x40000000); - nv_mask(device, 0x111104, 0x00000180, 0x00000000); - } - } - if (info->rammap && !(info->rammap[4] & 0x02)) - nv_mask(device, 0x100200, 0x00000800, 0x00000000); - nv_wr32(device, 0x611200, 0x00003300); - if (!(info->ramcfg[2] & 0x10)) - nv_wr32(device, 0x111100, 0x4c020000); /*XXX*/ - - nouveau_mem_exec(&exec, info->perflvl); - - nv_wr32(device, 0x611200, 0x00003330); - if (info->rammap && (info->rammap[4] & 0x02)) - nv_mask(device, 0x100200, 0x00000800, 0x00000800); - if (info->ramcfg) { - if (info->ramcfg[2] & 0x10) { - nv_mask(device, 0x111104, 0x00000180, 0x00000180); - nv_mask(device, 0x111100, 0x40000000, 0x00000000); - } else { - nv_mask(device, 0x111104, 0x00000600, 0x00000600); - } - } - - if (info->mclk.pll) { - nv_mask(device, 0x004168, 0x00000001, 0x00000000); - nv_mask(device, 0x004168, 0x00000100, 0x00000000); - } else { - nv_mask(device, 0x004000, 0x00000001, 0x00000000); - nv_mask(device, 0x004128, 0x00000001, 0x00000000); - nv_mask(device, 0x004128, 0x00000100, 0x00000000); - } -} - -int -nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nva3_pm_state *info = pre_state; - int ret = -EAGAIN; - - /* prevent any new grctx switches from starting */ - nv_wr32(device, 0x400324, 0x00000000); - nv_wr32(device, 0x400328, 0x0050001c); /* wait flag 0x1c */ - /* wait for any pending grctx switches to complete */ - if (!nv_wait_cb(device, nva3_pm_grcp_idle, dev)) { - NV_ERROR(drm, "pm: ctxprog didn't go idle\n"); - goto cleanup; - } - /* freeze PFIFO */ - nv_mask(device, 0x002504, 0x00000001, 0x00000001); - if (!nv_wait(device, 0x002504, 0x00000010, 0x00000010)) { - NV_ERROR(drm, "pm: fifo didn't go idle\n"); - goto cleanup; - } - - prog_pll(dev, 0x00, 0x004200, &info->nclk); - prog_pll(dev, 0x01, 0x004220, &info->sclk); - prog_clk(dev, 0x20, &info->unka0); - prog_clk(dev, 0x21, &info->vdec); - - if (info->mclk.clk || info->mclk.pll) - prog_mem(dev, info); - - ret = 0; - -cleanup: - /* unfreeze PFIFO */ - nv_mask(device, 0x002504, 0x00000001, 0x00000000); - /* restore ctxprog to normal */ - nv_wr32(device, 0x400324, 0x00000000); - nv_wr32(device, 0x400328, 0x0070009c); /* set flag 0x1c */ - /* unblock it if necessary */ - if (nv_rd32(device, 0x400308) == 0x0050001c) - nv_mask(device, 0x400824, 0x10000000, 0x10000000); - kfree(info); - return ret; -} diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c deleted file mode 100644 index 3b7041cb013..00000000000 --- a/drivers/gpu/drm/nouveau/nvc0_pm.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Copyright 2011 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 "nouveau_drm.h" -#include "nouveau_bios.h" -#include "nouveau_pm.h" - -#include <subdev/bios/pll.h> -#include <subdev/bios.h> -#include <subdev/clock.h> -#include <subdev/timer.h> -#include <subdev/fb.h> - -static u32 read_div(struct drm_device *, int, u32, u32); -static u32 read_pll(struct drm_device *, u32); - -static u32 -read_vco(struct drm_device *dev, u32 dsrc) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ssrc = nv_rd32(device, dsrc); - if (!(ssrc & 0x00000100)) - return read_pll(dev, 0x00e800); - return read_pll(dev, 0x00e820); -} - -static u32 -read_pll(struct drm_device *dev, u32 pll) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ctrl = nv_rd32(device, pll + 0); - u32 coef = nv_rd32(device, pll + 4); - u32 P = (coef & 0x003f0000) >> 16; - u32 N = (coef & 0x0000ff00) >> 8; - u32 M = (coef & 0x000000ff) >> 0; - u32 sclk, doff; - - if (!(ctrl & 0x00000001)) - return 0; - - switch (pll & 0xfff000) { - case 0x00e000: - sclk = 27000; - P = 1; - break; - case 0x137000: - doff = (pll - 0x137000) / 0x20; - sclk = read_div(dev, doff, 0x137120, 0x137140); - break; - case 0x132000: - switch (pll) { - case 0x132000: - sclk = read_pll(dev, 0x132020); - break; - case 0x132020: - sclk = read_div(dev, 0, 0x137320, 0x137330); - break; - default: - return 0; - } - break; - default: - return 0; - } - - return sclk * N / M / P; -} - -static u32 -read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ssrc = nv_rd32(device, dsrc + (doff * 4)); - u32 sctl = nv_rd32(device, dctl + (doff * 4)); - - switch (ssrc & 0x00000003) { - case 0: - if ((ssrc & 0x00030000) != 0x00030000) - return 27000; - return 108000; - case 2: - return 100000; - case 3: - if (sctl & 0x80000000) { - u32 sclk = read_vco(dev, dsrc + (doff * 4)); - u32 sdiv = (sctl & 0x0000003f) + 2; - return (sclk * 2) / sdiv; - } - - return read_vco(dev, dsrc + (doff * 4)); - default: - return 0; - } -} - -static u32 -read_mem(struct drm_device *dev) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 ssel = nv_rd32(device, 0x1373f0); - if (ssel & 0x00000001) - return read_div(dev, 0, 0x137300, 0x137310); - return read_pll(dev, 0x132000); -} - -static u32 -read_clk(struct drm_device *dev, int clk) -{ - struct nouveau_device *device = nouveau_dev(dev); - u32 sctl = nv_rd32(device, 0x137250 + (clk * 4)); - u32 ssel = nv_rd32(device, 0x137100); - u32 sclk, sdiv; - - if (ssel & (1 << clk)) { - if (clk < 7) - sclk = read_pll(dev, 0x137000 + (clk * 0x20)); - else - sclk = read_pll(dev, 0x1370e0); - sdiv = ((sctl & 0x00003f00) >> 8) + 2; - } else { - sclk = read_div(dev, clk, 0x137160, 0x1371d0); - sdiv = ((sctl & 0x0000003f) >> 0) + 2; - } - - if (sctl & 0x80000000) - return (sclk * 2) / sdiv; - return sclk; -} - -int -nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - perflvl->shader = read_clk(dev, 0x00); - perflvl->core = perflvl->shader / 2; - perflvl->memory = read_mem(dev); - perflvl->rop = read_clk(dev, 0x01); - perflvl->hub07 = read_clk(dev, 0x02); - perflvl->hub06 = read_clk(dev, 0x07); - perflvl->hub01 = read_clk(dev, 0x08); - perflvl->copy = read_clk(dev, 0x09); - perflvl->daemon = read_clk(dev, 0x0c); - perflvl->vdec = read_clk(dev, 0x0e); - return 0; -} - -struct nvc0_pm_clock { - u32 freq; - u32 ssel; - u32 mdiv; - u32 dsrc; - u32 ddiv; - u32 coef; -}; - -struct nvc0_pm_state { - struct nouveau_pm_level *perflvl; - struct nvc0_pm_clock eng[16]; - struct nvc0_pm_clock mem; -}; - -static u32 -calc_div(struct drm_device *dev, int clk, u32 ref, u32 freq, u32 *ddiv) -{ - u32 div = min((ref * 2) / freq, (u32)65); - if (div < 2) - div = 2; - - *ddiv = div - 2; - return (ref * 2) / div; -} - -static u32 -calc_src(struct drm_device *dev, int clk, u32 freq, u32 *dsrc, u32 *ddiv) -{ - u32 sclk; - - /* use one of the fixed frequencies if possible */ - *ddiv = 0x00000000; - switch (freq) { - case 27000: - case 108000: - *dsrc = 0x00000000; - if (freq == 108000) - *dsrc |= 0x00030000; - return freq; - case 100000: - *dsrc = 0x00000002; - return freq; - default: - *dsrc = 0x00000003; - break; - } - - /* otherwise, calculate the closest divider */ - sclk = read_vco(dev, clk); - if (clk < 7) - sclk = calc_div(dev, clk, sclk, freq, ddiv); - return sclk; -} - -static u32 -calc_pll(struct drm_device *dev, int clk, u32 freq, u32 *coef) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_bios *bios = nouveau_bios(device); - struct nvbios_pll limits; - int N, M, P, ret; - - ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); - if (ret) - return 0; - - limits.refclk = read_div(dev, clk, 0x137120, 0x137140); - if (!limits.refclk) - return 0; - - ret = nva3_calc_pll(dev, &limits, freq, &N, NULL, &M, &P); - if (ret <= 0) - return 0; - - *coef = (P << 16) | (N << 8) | M; - return ret; -} - -/* A (likely rather simplified and incomplete) view of the clock tree - * - * Key: - * - * S: source select - * D: divider - * P: pll - * F: switch - * - * Engine clocks: - * - * 137250(D) ---- 137100(F0) ---- 137160(S)/1371d0(D) ------------------- ref - * (F1) ---- 1370X0(P) ---- 137120(S)/137140(D) ---- ref - * - * Not all registers exist for all clocks. For example: clocks >= 8 don't - * have their own PLL (all tied to clock 7's PLL when in PLL mode), nor do - * they have the divider at 1371d0, though the source selection at 137160 - * still exists. You must use the divider at 137250 for these instead. - * - * Memory clock: - * - * TBD, read_mem() above is likely very wrong... - * - */ - -static int -calc_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info, u32 freq) -{ - u32 src0, div0, div1D, div1P = 0; - u32 clk0, clk1 = 0; - - /* invalid clock domain */ - if (!freq) - return 0; - - /* first possible path, using only dividers */ - clk0 = calc_src(dev, clk, freq, &src0, &div0); - clk0 = calc_div(dev, clk, clk0, freq, &div1D); - - /* see if we can get any closer using PLLs */ - if (clk0 != freq && (0x00004387 & (1 << clk))) { - if (clk < 7) - clk1 = calc_pll(dev, clk, freq, &info->coef); - else - clk1 = read_pll(dev, 0x1370e0); - clk1 = calc_div(dev, clk, clk1, freq, &div1P); - } - - /* select the method which gets closest to target freq */ - if (abs((int)freq - clk0) <= abs((int)freq - clk1)) { - info->dsrc = src0; - if (div0) { - info->ddiv |= 0x80000000; - info->ddiv |= div0 << 8; - info->ddiv |= div0; - } - if (div1D) { - info->mdiv |= 0x80000000; - info->mdiv |= div1D; - } - info->ssel = 0; - info->freq = clk0; - } else { - if (div1P) { - info->mdiv |= 0x80000000; - info->mdiv |= div1P << 8; - } - info->ssel = (1 << clk); - info->freq = clk1; - } - - return 0; -} - -static int -calc_mem(struct drm_device *dev, struct nvc0_pm_clock *info, u32 freq) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_bios *bios = nouveau_bios(device); - struct nvbios_pll pll; - int N, M, P, ret; - u32 ctrl; - - /* mclk pll input freq comes from another pll, make sure it's on */ - ctrl = nv_rd32(device, 0x132020); - if (!(ctrl & 0x00000001)) { - /* if not, program it to 567MHz. nfi where this value comes - * from - it looks like it's in the pll limits table for - * 132000 but the binary driver ignores all my attempts to - * change this value. - */ - nv_wr32(device, 0x137320, 0x00000103); - nv_wr32(device, 0x137330, 0x81200606); - nv_wait(device, 0x132020, 0x00010000, 0x00010000); - nv_wr32(device, 0x132024, 0x0001150f); - nv_mask(device, 0x132020, 0x00000001, 0x00000001); - nv_wait(device, 0x137390, 0x00020000, 0x00020000); - nv_mask(device, 0x132020, 0x00000004, 0x00000004); - } - - /* for the moment, until the clock tree is better understood, use - * pll mode for all clock frequencies - */ - ret = nvbios_pll_parse(bios, 0x132000, &pll); - if (ret == 0) { - pll.refclk = read_pll(dev, 0x132020); - if (pll.refclk) { - ret = nva3_calc_pll(dev, &pll, freq, &N, NULL, &M, &P); - if (ret > 0) { - info->coef = (P << 16) | (N << 8) | M; - return 0; - } - } - } - - return -EINVAL; -} - -void * -nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nvc0_pm_state *info; - int ret; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return ERR_PTR(-ENOMEM); - - /* NFI why this is still in the performance table, the ROPCs appear - * to get their clock from clock 2 ("hub07", actually hub05 on this - * chip, but, anyway...) as well. nvatiming confirms hub05 and ROP - * are always the same freq with the binary driver even when the - * performance table says they should differ. - */ - if (device->chipset == 0xd9) - perflvl->rop = 0; - - if ((ret = calc_clk(dev, 0x00, &info->eng[0x00], perflvl->shader)) || - (ret = calc_clk(dev, 0x01, &info->eng[0x01], perflvl->rop)) || - (ret = calc_clk(dev, 0x02, &info->eng[0x02], perflvl->hub07)) || - (ret = calc_clk(dev, 0x07, &info->eng[0x07], perflvl->hub06)) || - (ret = calc_clk(dev, 0x08, &info->eng[0x08], perflvl->hub01)) || - (ret = calc_clk(dev, 0x09, &info->eng[0x09], perflvl->copy)) || - (ret = calc_clk(dev, 0x0c, &info->eng[0x0c], perflvl->daemon)) || - (ret = calc_clk(dev, 0x0e, &info->eng[0x0e], perflvl->vdec))) { - kfree(info); - return ERR_PTR(ret); - } - - if (perflvl->memory) { - ret = calc_mem(dev, &info->mem, perflvl->memory); - if (ret) { - kfree(info); - return ERR_PTR(ret); - } - } - - info->perflvl = perflvl; - return info; -} - -static void -prog_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info) -{ - struct nouveau_device *device = nouveau_dev(dev); - - /* program dividers at 137160/1371d0 first */ - if (clk < 7 && !info->ssel) { - nv_mask(device, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); - nv_wr32(device, 0x137160 + (clk * 0x04), info->dsrc); - } - - /* switch clock to non-pll mode */ - nv_mask(device, 0x137100, (1 << clk), 0x00000000); - nv_wait(device, 0x137100, (1 << clk), 0x00000000); - - /* reprogram pll */ - if (clk < 7) { - /* make sure it's disabled first... */ - u32 base = 0x137000 + (clk * 0x20); - u32 ctrl = nv_rd32(device, base + 0x00); - if (ctrl & 0x00000001) { - nv_mask(device, base + 0x00, 0x00000004, 0x00000000); - nv_mask(device, base + 0x00, 0x00000001, 0x00000000); - } - /* program it to new values, if necessary */ - if (info->ssel) { - nv_wr32(device, base + 0x04, info->coef); - nv_mask(device, base + 0x00, 0x00000001, 0x00000001); - nv_wait(device, base + 0x00, 0x00020000, 0x00020000); - nv_mask(device, base + 0x00, 0x00020004, 0x00000004); - } - } - - /* select pll/non-pll mode, and program final clock divider */ - nv_mask(device, 0x137100, (1 << clk), info->ssel); - nv_wait(device, 0x137100, (1 << clk), info->ssel); - nv_mask(device, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); -} - -static void -mclk_precharge(struct nouveau_mem_exec_func *exec) -{ -} - -static void -mclk_refresh(struct nouveau_mem_exec_func *exec) -{ -} - -static void -mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - nv_wr32(device, 0x10f210, enable ? 0x80000000 : 0x00000000); -} - -static void -mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable) -{ -} - -static void -mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec) -{ - udelay((nsec + 500) / 1000); -} - -static u32 -mclk_mrg(struct nouveau_mem_exec_func *exec, int mr) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nouveau_fb *pfb = nouveau_fb(device); - if (pfb->ram->type != NV_MEM_TYPE_GDDR5) { - if (mr <= 1) - return nv_rd32(device, 0x10f300 + ((mr - 0) * 4)); - return nv_rd32(device, 0x10f320 + ((mr - 2) * 4)); - } else { - if (mr == 0) - return nv_rd32(device, 0x10f300 + (mr * 4)); - else - if (mr <= 7) - return nv_rd32(device, 0x10f32c + (mr * 4)); - return nv_rd32(device, 0x10f34c); - } -} - -static void -mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nouveau_fb *pfb = nouveau_fb(device); - if (pfb->ram->type != NV_MEM_TYPE_GDDR5) { - if (mr <= 1) { - nv_wr32(device, 0x10f300 + ((mr - 0) * 4), data); - if (pfb->ram->ranks > 1) - nv_wr32(device, 0x10f308 + ((mr - 0) * 4), data); - } else - if (mr <= 3) { - nv_wr32(device, 0x10f320 + ((mr - 2) * 4), data); - if (pfb->ram->ranks > 1) - nv_wr32(device, 0x10f328 + ((mr - 2) * 4), data); - } - } else { - if (mr == 0) nv_wr32(device, 0x10f300 + (mr * 4), data); - else if (mr <= 7) nv_wr32(device, 0x10f32c + (mr * 4), data); - else if (mr == 15) nv_wr32(device, 0x10f34c, data); - } -} - -static void -mclk_clock_set(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nvc0_pm_state *info = exec->priv; - u32 ctrl = nv_rd32(device, 0x132000); - - nv_wr32(device, 0x137360, 0x00000001); - nv_wr32(device, 0x137370, 0x00000000); - nv_wr32(device, 0x137380, 0x00000000); - if (ctrl & 0x00000001) - nv_wr32(device, 0x132000, (ctrl &= ~0x00000001)); - - nv_wr32(device, 0x132004, info->mem.coef); - nv_wr32(device, 0x132000, (ctrl |= 0x00000001)); - nv_wait(device, 0x137390, 0x00000002, 0x00000002); - nv_wr32(device, 0x132018, 0x00005000); - - nv_wr32(device, 0x137370, 0x00000001); - nv_wr32(device, 0x137380, 0x00000001); - nv_wr32(device, 0x137360, 0x00000000); -} - -static void -mclk_timing_set(struct nouveau_mem_exec_func *exec) -{ - struct nouveau_device *device = nouveau_dev(exec->dev); - struct nvc0_pm_state *info = exec->priv; - struct nouveau_pm_level *perflvl = info->perflvl; - int i; - - for (i = 0; i < 5; i++) - nv_wr32(device, 0x10f290 + (i * 4), perflvl->timing.reg[i]); -} - -static void -prog_mem(struct drm_device *dev, struct nvc0_pm_state *info) -{ - struct nouveau_device *device = nouveau_dev(dev); - struct nouveau_mem_exec_func exec = { - .dev = dev, - .precharge = mclk_precharge, - .refresh = mclk_refresh, - .refresh_auto = mclk_refresh_auto, - .refresh_self = mclk_refresh_self, - .wait = mclk_wait, - .mrg = mclk_mrg, - .mrs = mclk_mrs, - .clock_set = mclk_clock_set, - .timing_set = mclk_timing_set, - .priv = info - }; - - if (device->chipset < 0xd0) - nv_wr32(device, 0x611200, 0x00003300); - else - nv_wr32(device, 0x62c000, 0x03030000); - - nouveau_mem_exec(&exec, info->perflvl); - - if (device->chipset < 0xd0) - nv_wr32(device, 0x611200, 0x00003330); - else - nv_wr32(device, 0x62c000, 0x03030300); -} -int -nvc0_pm_clocks_set(struct drm_device *dev, void *data) -{ - struct nvc0_pm_state *info = data; - int i; - - if (info->mem.coef) - prog_mem(dev, info); - - for (i = 0; i < 16; i++) { - if (!info->eng[i].freq) - continue; - prog_clk(dev, i, &info->eng[i]); - } - - kfree(info); - return 0; -} |
