Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,70 @@
config DRM_NOUVEAU
tristate "Nouveau (NVIDIA) cards"
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
select FB_CFB_IMAGEBLIT
select FB
select FRAMEBUFFER_CONSOLE if !EXPERT
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
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
select POWER_SUPPLY
# 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 INPUT if ACPI && X86
select THERMAL if ACPI && X86
select ACPI_VIDEO if ACPI && X86
help
Choose this option for open-source NVIDIA support.
config NOUVEAU_PLATFORM_DRIVER
tristate "Nouveau (NVIDIA) SoC GPUs"
depends on DRM_NOUVEAU && ARCH_TEGRA
default y
help
Support for Nouveau platform driver, used for SoC GPUs as found
on NVIDIA Tegra K1.
config NOUVEAU_DEBUG
int "Maximum debug level"
depends on DRM_NOUVEAU
range 0 7
default 5
help
Selects the maximum debug level to compile support for.
0 - fatal
1 - error
2 - warning
3 - info
4 - debug
5 - trace (recommended)
6 - paranoia
7 - spam
The paranoia and spam levels will add a lot of extra checks which
may potentially slow down driver operation.
config NOUVEAU_DEBUG_DEFAULT
int "Default debug level"
depends on DRM_NOUVEAU
range 0 7
default 3
help
Selects the default debug level
config DRM_NOUVEAU_BACKLIGHT
bool "Support for backlight control"
depends on DRM_NOUVEAU
default y
help
Say Y here if you want to control the backlight of your display
(e.g. a laptop panel).

View file

@ -0,0 +1,382 @@
#
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm
ccflags-y += -I$(src)/core/include
ccflags-y += -I$(src)/core
ccflags-y += -I$(src)
nouveau-y := core/core/client.o
nouveau-y += core/core/engctx.o
nouveau-y += core/core/engine.o
nouveau-y += core/core/enum.o
nouveau-y += core/core/event.o
nouveau-y += core/core/gpuobj.o
nouveau-y += core/core/handle.o
nouveau-y += core/core/ioctl.o
nouveau-y += core/core/mm.o
nouveau-y += core/core/namedb.o
nouveau-y += core/core/notify.o
nouveau-y += core/core/object.o
nouveau-y += core/core/option.o
nouveau-y += core/core/parent.o
nouveau-y += core/core/printk.o
nouveau-y += core/core/ramht.o
nouveau-y += core/core/subdev.o
nouveau-y += core/subdev/bar/base.o
nouveau-y += core/subdev/bar/nv50.o
nouveau-y += core/subdev/bar/nvc0.o
nouveau-y += core/subdev/bar/gk20a.o
nouveau-y += core/subdev/bios/base.o
nouveau-y += core/subdev/bios/bit.o
nouveau-y += core/subdev/bios/boost.o
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
nouveau-y += core/subdev/bios/extdev.o
nouveau-y += core/subdev/bios/fan.o
nouveau-y += core/subdev/bios/gpio.o
nouveau-y += core/subdev/bios/i2c.o
nouveau-y += core/subdev/bios/init.o
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/M0205.o
nouveau-y += core/subdev/bios/M0209.o
nouveau-y += core/subdev/bios/P0260.o
nouveau-y += core/subdev/bus/hwsq.o
nouveau-y += core/subdev/bus/nv04.o
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/gk20a.o
nouveau-y += core/subdev/clock/pllnv04.o
nouveau-y += core/subdev/clock/pllnva3.o
nouveau-y += core/subdev/devinit/base.o
nouveau-y += core/subdev/devinit/nv04.o
nouveau-y += core/subdev/devinit/nv05.o
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
nouveau-y += core/subdev/fb/nv1a.o
nouveau-y += core/subdev/fb/nv20.o
nouveau-y += core/subdev/fb/nv25.o
nouveau-y += core/subdev/fb/nv30.o
nouveau-y += core/subdev/fb/nv35.o
nouveau-y += core/subdev/fb/nv36.o
nouveau-y += core/subdev/fb/nv40.o
nouveau-y += core/subdev/fb/nv41.o
nouveau-y += core/subdev/fb/nv44.o
nouveau-y += core/subdev/fb/nv46.o
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
nouveau-y += core/subdev/fb/ramnv20.o
nouveau-y += core/subdev/fb/ramnv40.o
nouveau-y += core/subdev/fb/ramnv41.o
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/sddr2.o
nouveau-y += core/subdev/fb/sddr3.o
nouveau-y += core/subdev/fb/gddr5.o
nouveau-y += core/subdev/fuse/base.o
nouveau-y += core/subdev/fuse/g80.o
nouveau-y += core/subdev/fuse/gf100.o
nouveau-y += core/subdev/fuse/gm107.o
nouveau-y += core/subdev/gpio/base.o
nouveau-y += core/subdev/gpio/nv10.o
nouveau-y += core/subdev/gpio/nv50.o
nouveau-y += core/subdev/gpio/nv94.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/ltc/base.o
nouveau-y += core/subdev/ltc/gf100.o
nouveau-y += core/subdev/ltc/gk104.o
nouveau-y += core/subdev/ltc/gm107.o
nouveau-y += core/subdev/mc/base.o
nouveau-y += core/subdev/mc/nv04.o
nouveau-y += core/subdev/mc/nv40.o
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/mc/gk20a.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/gk104.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
nouveau-y += core/subdev/therm/fanpwm.o
nouveau-y += core/subdev/therm/fantog.o
nouveau-y += core/subdev/therm/ic.o
nouveau-y += core/subdev/therm/temp.o
nouveau-y += core/subdev/therm/nv40.o
nouveau-y += core/subdev/therm/nv50.o
nouveau-y += core/subdev/therm/nv84.o
nouveau-y += core/subdev/therm/nva3.o
nouveau-y += core/subdev/therm/nvd0.o
nouveau-y += core/subdev/therm/gm107.o
nouveau-y += core/subdev/timer/base.o
nouveau-y += core/subdev/timer/nv04.o
nouveau-y += core/subdev/timer/gk20a.o
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
nouveau-y += core/engine/dmaobj/base.o
nouveau-y += core/engine/dmaobj/nv04.o
nouveau-y += core/engine/dmaobj/nv50.o
nouveau-y += core/engine/dmaobj/nvc0.o
nouveau-y += core/engine/dmaobj/nvd0.o
nouveau-y += core/engine/bsp/nv84.o
nouveau-y += core/engine/bsp/nv98.o
nouveau-y += core/engine/bsp/nvc0.o
nouveau-y += core/engine/bsp/nve0.o
nouveau-y += core/engine/copy/nva3.o
nouveau-y += core/engine/copy/nvc0.o
nouveau-y += core/engine/copy/nve0.o
nouveau-y += core/engine/crypt/nv84.o
nouveau-y += core/engine/crypt/nv98.o
nouveau-y += core/engine/device/acpi.o
nouveau-y += core/engine/device/base.o
nouveau-y += core/engine/device/ctrl.o
nouveau-y += core/engine/device/nv04.o
nouveau-y += core/engine/device/nv10.o
nouveau-y += core/engine/device/nv20.o
nouveau-y += core/engine/device/nv30.o
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
nouveau-y += core/engine/disp/nv94.o
nouveau-y += core/engine/disp/nva0.o
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
nouveau-y += core/engine/disp/hdanvd0.o
nouveau-y += core/engine/disp/hdminv84.o
nouveau-y += core/engine/disp/hdminva3.o
nouveau-y += core/engine/disp/hdminvd0.o
nouveau-y += core/engine/disp/hdminve0.o
nouveau-y += core/engine/disp/piornv50.o
nouveau-y += core/engine/disp/sornv50.o
nouveau-y += core/engine/disp/sornv94.o
nouveau-y += core/engine/disp/sornvd0.o
nouveau-y += core/engine/disp/vga.o
nouveau-y += core/engine/fifo/base.o
nouveau-y += core/engine/fifo/nv04.o
nouveau-y += core/engine/fifo/nv10.o
nouveau-y += core/engine/fifo/nv17.o
nouveau-y += core/engine/fifo/nv40.o
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/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/ctxgk110b.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
nouveau-y += core/engine/graph/nv25.o
nouveau-y += core/engine/graph/nv2a.o
nouveau-y += core/engine/graph/nv30.o
nouveau-y += core/engine/graph/nv34.o
nouveau-y += core/engine/graph/nv35.o
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/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/gk110b.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
nouveau-y += core/engine/software/nv10.o
nouveau-y += core/engine/software/nv50.o
nouveau-y += core/engine/software/nvc0.o
nouveau-y += core/engine/vp/nv84.o
nouveau-y += core/engine/vp/nv98.o
nouveau-y += core/engine/vp/nvc0.o
nouveau-y += core/engine/vp/nve0.o
# nvif
nouveau-y += nvif/object.o
nouveau-y += nvif/client.o
nouveau-y += nvif/device.o
nouveau-y += nvif/notify.o
# drm/core
nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
nouveau-y += nouveau_vga.o nouveau_agp.o
nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
nouveau-y += nouveau_prime.o nouveau_abi16.o
nouveau-y += nouveau_nvif.o nouveau_usif.o
nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o
# drm/kms
nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
nouveau-y += nouveau_connector.o nouveau_dp.o
nouveau-y += nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o
# drm/kms/nv04:nv50
include $(src)/dispnv04/Makefile
# drm/kms/nv50-
nouveau-y += nv50_display.o
# drm/pm
nouveau-y += nouveau_hwmon.o nouveau_sysfs.o
# other random bits
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
ifdef CONFIG_X86
nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
endif
nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
# platform driver
obj-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o

View file

@ -0,0 +1,271 @@
/*
* 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/object.h>
#include <core/client.h>
#include <core/handle.h>
#include <core/option.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <nvif/unpack.h>
#include <nvif/event.h>
#include <engine/device.h>
struct nvkm_client_notify {
struct nouveau_client *client;
struct nvkm_notify n;
u8 version;
u8 size;
union {
struct nvif_notify_rep_v0 v0;
} rep;
};
static int
nvkm_client_notify(struct nvkm_notify *n)
{
struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
struct nouveau_client *client = notify->client;
return client->ntfy(&notify->rep, notify->size, n->data, n->size);
}
int
nvkm_client_notify_put(struct nouveau_client *client, int index)
{
if (index < ARRAY_SIZE(client->notify)) {
if (client->notify[index]) {
nvkm_notify_put(&client->notify[index]->n);
return 0;
}
}
return -ENOENT;
}
int
nvkm_client_notify_get(struct nouveau_client *client, int index)
{
if (index < ARRAY_SIZE(client->notify)) {
if (client->notify[index]) {
nvkm_notify_get(&client->notify[index]->n);
return 0;
}
}
return -ENOENT;
}
int
nvkm_client_notify_del(struct nouveau_client *client, int index)
{
if (index < ARRAY_SIZE(client->notify)) {
if (client->notify[index]) {
nvkm_notify_fini(&client->notify[index]->n);
kfree(client->notify[index]);
client->notify[index] = NULL;
return 0;
}
}
return -ENOENT;
}
int
nvkm_client_notify_new(struct nouveau_object *object,
struct nvkm_event *event, void *data, u32 size)
{
struct nouveau_client *client = nouveau_client(object);
struct nvkm_client_notify *notify;
union {
struct nvif_notify_req_v0 v0;
} *req = data;
u8 index, reply;
int ret;
for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
if (!client->notify[index])
break;
}
if (index == ARRAY_SIZE(client->notify))
return -ENOSPC;
notify = kzalloc(sizeof(*notify), GFP_KERNEL);
if (!notify)
return -ENOMEM;
nv_ioctl(client, "notify new size %d\n", size);
if (nvif_unpack(req->v0, 0, 0, true)) {
nv_ioctl(client, "notify new vers %d reply %d route %02x "
"token %llx\n", req->v0.version,
req->v0.reply, req->v0.route, req->v0.token);
notify->version = req->v0.version;
notify->size = sizeof(notify->rep.v0);
notify->rep.v0.version = req->v0.version;
notify->rep.v0.route = req->v0.route;
notify->rep.v0.token = req->v0.token;
reply = req->v0.reply;
}
if (ret == 0) {
ret = nvkm_notify_init(object, event, nvkm_client_notify,
false, data, size, reply, &notify->n);
if (ret == 0) {
client->notify[index] = notify;
notify->client = client;
return index;
}
}
kfree(notify);
return ret;
}
static int
nouveau_client_devlist(struct nouveau_object *object, void *data, u32 size)
{
union {
struct nv_client_devlist_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "client devlist size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "client devlist vers %d count %d\n",
args->v0.version, args->v0.count);
if (size == sizeof(args->v0.device[0]) * args->v0.count) {
ret = nouveau_device_list(args->v0.device,
args->v0.count);
if (ret >= 0) {
args->v0.count = ret;
ret = 0;
}
} else {
ret = -EINVAL;
}
}
return ret;
}
static int
nouveau_client_mthd(struct nouveau_object *object, u32 mthd,
void *data, u32 size)
{
switch (mthd) {
case NV_CLIENT_DEVLIST:
return nouveau_client_devlist(object, data, size);
default:
break;
}
return -EINVAL;
}
static void
nouveau_client_dtor(struct nouveau_object *object)
{
struct nouveau_client *client = (void *)object;
int i;
for (i = 0; i < ARRAY_SIZE(client->notify); i++)
nvkm_client_notify_del(client, i);
nouveau_object_ref(NULL, &client->device);
nouveau_handle_destroy(client->root);
nouveau_namedb_destroy(&client->base);
}
static struct nouveau_oclass
nouveau_client_oclass = {
.ofuncs = &(struct nouveau_ofuncs) {
.dtor = nouveau_client_dtor,
.mthd = nouveau_client_mthd,
},
};
int
nouveau_client_create_(const char *name, u64 devname, const char *cfg,
const char *dbg, int length, void **pobject)
{
struct nouveau_object *device;
struct nouveau_client *client;
int ret;
device = (void *)nouveau_device_find(devname);
if (!device)
return -ENODEV;
ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass,
NV_CLIENT_CLASS, NULL,
(1ULL << NVDEV_ENGINE_DEVICE),
length, pobject);
client = *pobject;
if (ret)
return ret;
ret = nouveau_handle_create(nv_object(client), ~0, ~0,
nv_object(client), &client->root);
if (ret)
return ret;
/* prevent init/fini being called, os in in charge of this */
atomic_set(&nv_object(client)->usecount, 2);
nouveau_object_ref(device, &client->device);
snprintf(client->name, sizeof(client->name), "%s", name);
client->debug = nouveau_dbgopt(dbg, "CLIENT");
return 0;
}
int
nouveau_client_init(struct nouveau_client *client)
{
int ret;
nv_debug(client, "init running\n");
ret = nouveau_handle_init(client->root);
nv_debug(client, "init completed with %d\n", ret);
return ret;
}
int
nouveau_client_fini(struct nouveau_client *client, bool suspend)
{
const char *name[2] = { "fini", "suspend" };
int ret, i;
nv_debug(client, "%s running\n", name[suspend]);
nv_debug(client, "%s notify\n", name[suspend]);
for (i = 0; i < ARRAY_SIZE(client->notify); i++)
nvkm_client_notify_put(client, i);
nv_debug(client, "%s object\n", name[suspend]);
ret = nouveau_handle_fini(client->root, suspend);
nv_debug(client, "%s completed with %d\n", name[suspend], ret);
return ret;
}
const char *
nouveau_client_name(void *obj)
{
const char *client_name = "unknown";
struct nouveau_client *client = nouveau_client(obj);
if (client)
client_name = client->name;
return client_name;
}

View file

@ -0,0 +1,251 @@
/*
* 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/object.h>
#include <core/namedb.h>
#include <core/handle.h>
#include <core/client.h>
#include <core/engctx.h>
#include <subdev/vm.h>
static inline int
nouveau_engctx_exists(struct nouveau_object *parent,
struct nouveau_engine *engine, void **pobject)
{
struct nouveau_engctx *engctx;
struct nouveau_object *parctx;
list_for_each_entry(engctx, &engine->contexts, head) {
parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS);
if (parctx == parent) {
atomic_inc(&nv_object(engctx)->refcount);
*pobject = engctx;
return 1;
}
}
return 0;
}
int
nouveau_engctx_create_(struct nouveau_object *parent,
struct nouveau_object *engobj,
struct nouveau_oclass *oclass,
struct nouveau_object *pargpu,
u32 size, u32 align, u32 flags,
int length, void **pobject)
{
struct nouveau_client *client = nouveau_client(parent);
struct nouveau_engine *engine = nv_engine(engobj);
struct nouveau_object *engctx;
unsigned long save;
int ret;
/* check if this engine already has a context for the parent object,
* and reference it instead of creating a new one
*/
spin_lock_irqsave(&engine->lock, save);
ret = nouveau_engctx_exists(parent, engine, pobject);
spin_unlock_irqrestore(&engine->lock, save);
if (ret)
return ret;
/* create the new context, supports creating both raw objects and
* objects backed by instance memory
*/
if (size) {
ret = nouveau_gpuobj_create_(parent, engobj, oclass,
NV_ENGCTX_CLASS,
pargpu, size, align, flags,
length, pobject);
} else {
ret = nouveau_object_create_(parent, engobj, oclass,
NV_ENGCTX_CLASS, length, pobject);
}
engctx = *pobject;
if (ret)
return ret;
/* must take the lock again and re-check a context doesn't already
* exist (in case of a race) - the lock had to be dropped before as
* it's not possible to allocate the object with it held.
*/
spin_lock_irqsave(&engine->lock, save);
ret = nouveau_engctx_exists(parent, engine, pobject);
if (ret) {
spin_unlock_irqrestore(&engine->lock, save);
nouveau_object_ref(NULL, &engctx);
return ret;
}
if (client->vm)
atomic_inc(&client->vm->engref[nv_engidx(engobj)]);
list_add(&nv_engctx(engctx)->head, &engine->contexts);
nv_engctx(engctx)->addr = ~0ULL;
spin_unlock_irqrestore(&engine->lock, save);
return 0;
}
void
nouveau_engctx_destroy(struct nouveau_engctx *engctx)
{
struct nouveau_object *engobj = nv_object(engctx)->engine;
struct nouveau_engine *engine = nv_engine(engobj);
struct nouveau_client *client = nouveau_client(engctx);
unsigned long save;
nouveau_gpuobj_unmap(&engctx->vma);
spin_lock_irqsave(&engine->lock, save);
list_del(&engctx->head);
spin_unlock_irqrestore(&engine->lock, save);
if (client->vm)
atomic_dec(&client->vm->engref[nv_engidx(engobj)]);
if (engctx->base.size)
nouveau_gpuobj_destroy(&engctx->base);
else
nouveau_object_destroy(&engctx->base.base);
}
int
nouveau_engctx_init(struct nouveau_engctx *engctx)
{
struct nouveau_object *object = nv_object(engctx);
struct nouveau_subdev *subdev = nv_subdev(object->engine);
struct nouveau_object *parent;
struct nouveau_subdev *pardev;
int ret;
ret = nouveau_gpuobj_init(&engctx->base);
if (ret)
return ret;
parent = nv_pclass(object->parent, NV_PARENT_CLASS);
pardev = nv_subdev(parent->engine);
if (nv_parent(parent)->context_attach) {
mutex_lock(&pardev->mutex);
ret = nv_parent(parent)->context_attach(parent, object);
mutex_unlock(&pardev->mutex);
}
if (ret) {
nv_error(parent, "failed to attach %s context, %d\n",
subdev->name, ret);
return ret;
}
nv_debug(parent, "attached %s context\n", subdev->name);
return 0;
}
int
nouveau_engctx_fini(struct nouveau_engctx *engctx, bool suspend)
{
struct nouveau_object *object = nv_object(engctx);
struct nouveau_subdev *subdev = nv_subdev(object->engine);
struct nouveau_object *parent;
struct nouveau_subdev *pardev;
int ret = 0;
parent = nv_pclass(object->parent, NV_PARENT_CLASS);
pardev = nv_subdev(parent->engine);
if (nv_parent(parent)->context_detach) {
mutex_lock(&pardev->mutex);
ret = nv_parent(parent)->context_detach(parent, suspend, object);
mutex_unlock(&pardev->mutex);
}
if (ret) {
nv_error(parent, "failed to detach %s context, %d\n",
subdev->name, ret);
return ret;
}
nv_debug(parent, "detached %s context\n", subdev->name);
return nouveau_gpuobj_fini(&engctx->base, suspend);
}
int
_nouveau_engctx_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_engctx *engctx;
int ret;
ret = nouveau_engctx_create(parent, engine, oclass, NULL, 256, 256,
NVOBJ_FLAG_ZERO_ALLOC, &engctx);
*pobject = nv_object(engctx);
return ret;
}
void
_nouveau_engctx_dtor(struct nouveau_object *object)
{
nouveau_engctx_destroy(nv_engctx(object));
}
int
_nouveau_engctx_init(struct nouveau_object *object)
{
return nouveau_engctx_init(nv_engctx(object));
}
int
_nouveau_engctx_fini(struct nouveau_object *object, bool suspend)
{
return nouveau_engctx_fini(nv_engctx(object), suspend);
}
struct nouveau_object *
nouveau_engctx_get(struct nouveau_engine *engine, u64 addr)
{
struct nouveau_engctx *engctx;
unsigned long flags;
spin_lock_irqsave(&engine->lock, flags);
list_for_each_entry(engctx, &engine->contexts, head) {
if (engctx->addr == addr) {
engctx->save = flags;
return nv_object(engctx);
}
}
spin_unlock_irqrestore(&engine->lock, flags);
return NULL;
}
void
nouveau_engctx_put(struct nouveau_object *object)
{
if (object) {
struct nouveau_engine *engine = nv_engine(object->engine);
struct nouveau_engctx *engctx = nv_engctx(object);
spin_unlock_irqrestore(&engine->lock, engctx->save);
}
}

View file

@ -0,0 +1,68 @@
/*
* 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/device.h>
#include <core/engine.h>
#include <core/option.h>
int
nouveau_engine_create_(struct nouveau_object *parent,
struct nouveau_object *engobj,
struct nouveau_oclass *oclass, bool enable,
const char *iname, const char *fname,
int length, void **pobject)
{
struct nouveau_engine *engine;
int ret;
ret = nouveau_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
iname, fname, length, pobject);
engine = *pobject;
if (ret)
return ret;
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);
spin_lock_init(&engine->lock);
return 0;
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2010 Nouveau Project
*
* 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 (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 COPYRIGHT OWNER(S) AND/OR ITS 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.
*
*/
#include <core/os.h>
#include <core/enum.h>
const struct nouveau_enum *
nouveau_enum_find(const struct nouveau_enum *en, u32 value)
{
while (en->name) {
if (en->value == value)
return en;
en++;
}
return NULL;
}
const struct nouveau_enum *
nouveau_enum_print(const struct nouveau_enum *en, u32 value)
{
en = nouveau_enum_find(en, value);
if (en)
pr_cont("%s", en->name);
else
pr_cont("(unknown enum 0x%08x)", value);
return en;
}
void
nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
{
while (bf->name) {
if (value & bf->mask) {
pr_cont(" %s", bf->name);
value &= ~bf->mask;
}
bf++;
}
if (value)
pr_cont(" (unknown bits 0x%08x)", value);
}

View file

@ -0,0 +1,100 @@
/*
* Copyright 2013-2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* 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.
*/
#include <core/object.h>
#include <core/event.h>
void
nvkm_event_put(struct nvkm_event *event, u32 types, int index)
{
assert_spin_locked(&event->refs_lock);
while (types) {
int type = __ffs(types); types &= ~(1 << type);
if (--event->refs[index * event->types_nr + type] == 0) {
if (event->func->fini)
event->func->fini(event, 1 << type, index);
}
}
}
void
nvkm_event_get(struct nvkm_event *event, u32 types, int index)
{
assert_spin_locked(&event->refs_lock);
while (types) {
int type = __ffs(types); types &= ~(1 << type);
if (++event->refs[index * event->types_nr + type] == 1) {
if (event->func->init)
event->func->init(event, 1 << type, index);
}
}
}
void
nvkm_event_send(struct nvkm_event *event, u32 types, int index,
void *data, u32 size)
{
struct nvkm_notify *notify;
unsigned long flags;
if (!event->refs || WARN_ON(index >= event->index_nr))
return;
spin_lock_irqsave(&event->list_lock, flags);
list_for_each_entry(notify, &event->list, head) {
if (notify->index == index && (notify->types & types)) {
if (event->func->send) {
event->func->send(data, size, notify);
continue;
}
nvkm_notify_send(notify, data, size);
}
}
spin_unlock_irqrestore(&event->list_lock, flags);
}
void
nvkm_event_fini(struct nvkm_event *event)
{
if (event->refs) {
kfree(event->refs);
event->refs = NULL;
}
}
int
nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
struct nvkm_event *event)
{
event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
GFP_KERNEL);
if (!event->refs)
return -ENOMEM;
event->func = func;
event->types_nr = types_nr;
event->index_nr = index_nr;
spin_lock_init(&event->refs_lock);
spin_lock_init(&event->list_lock);
INIT_LIST_HEAD(&event->list);
return 0;
}

View file

@ -0,0 +1,323 @@
/*
* 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/object.h>
#include <core/gpuobj.h>
#include <subdev/instmem.h>
#include <subdev/bar.h>
#include <subdev/vm.h>
void
nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj)
{
int i;
if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
for (i = 0; i < gpuobj->size; i += 4)
nv_wo32(gpuobj, i, 0x00000000);
}
if (gpuobj->node) {
nouveau_mm_free(&nv_gpuobj(gpuobj->parent)->heap,
&gpuobj->node);
}
if (gpuobj->heap.block_size)
nouveau_mm_fini(&gpuobj->heap);
nouveau_object_destroy(&gpuobj->base);
}
int
nouveau_gpuobj_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, u32 pclass,
struct nouveau_object *pargpu,
u32 size, u32 align, u32 flags,
int length, void **pobject)
{
struct nouveau_instmem *imem = nouveau_instmem(parent);
struct nouveau_bar *bar = nouveau_bar(parent);
struct nouveau_gpuobj *gpuobj;
struct nouveau_mm *heap = NULL;
int ret, i;
u64 addr;
*pobject = NULL;
if (pargpu) {
while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
if (nv_gpuobj(pargpu)->heap.block_size)
break;
pargpu = pargpu->parent;
}
if (unlikely(pargpu == NULL)) {
nv_error(parent, "no gpuobj heap\n");
return -EINVAL;
}
addr = nv_gpuobj(pargpu)->addr;
heap = &nv_gpuobj(pargpu)->heap;
atomic_inc(&parent->refcount);
} else {
ret = imem->alloc(imem, parent, size, align, &parent);
pargpu = parent;
if (ret)
return ret;
addr = nv_memobj(pargpu)->addr;
size = nv_memobj(pargpu)->size;
if (bar && bar->alloc) {
struct nouveau_instobj *iobj = (void *)parent;
struct nouveau_mem **mem = (void *)(iobj + 1);
struct nouveau_mem *node = *mem;
if (!bar->alloc(bar, parent, node, &pargpu)) {
nouveau_object_ref(NULL, &parent);
parent = pargpu;
}
}
}
ret = nouveau_object_create_(parent, engine, oclass, pclass |
NV_GPUOBJ_CLASS, length, pobject);
nouveau_object_ref(NULL, &parent);
gpuobj = *pobject;
if (ret)
return ret;
gpuobj->parent = pargpu;
gpuobj->flags = flags;
gpuobj->addr = addr;
gpuobj->size = size;
if (heap) {
ret = nouveau_mm_head(heap, 0, 1, size, size,
max(align, (u32)1), &gpuobj->node);
if (ret)
return ret;
gpuobj->addr += gpuobj->node->offset;
}
if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
ret = nouveau_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
if (ret)
return ret;
}
if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
for (i = 0; i < gpuobj->size; i += 4)
nv_wo32(gpuobj, i, 0x00000000);
}
return ret;
}
struct nouveau_gpuobj_class {
struct nouveau_object *pargpu;
u64 size;
u32 align;
u32 flags;
};
static int
_nouveau_gpuobj_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_gpuobj_class *args = data;
struct nouveau_gpuobj *object;
int ret;
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
args->size, args->align, args->flags,
&object);
*pobject = nv_object(object);
if (ret)
return ret;
return 0;
}
void
_nouveau_gpuobj_dtor(struct nouveau_object *object)
{
nouveau_gpuobj_destroy(nv_gpuobj(object));
}
int
_nouveau_gpuobj_init(struct nouveau_object *object)
{
return nouveau_gpuobj_init(nv_gpuobj(object));
}
int
_nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend)
{
return nouveau_gpuobj_fini(nv_gpuobj(object), suspend);
}
u32
_nouveau_gpuobj_rd32(struct nouveau_object *object, u64 addr)
{
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
if (gpuobj->node)
addr += gpuobj->node->offset;
return pfuncs->rd32(gpuobj->parent, addr);
}
void
_nouveau_gpuobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
{
struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
if (gpuobj->node)
addr += gpuobj->node->offset;
pfuncs->wr32(gpuobj->parent, addr, data);
}
static struct nouveau_oclass
_nouveau_gpuobj_oclass = {
.handle = 0x00000000,
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_gpuobj_ctor,
.dtor = _nouveau_gpuobj_dtor,
.init = _nouveau_gpuobj_init,
.fini = _nouveau_gpuobj_fini,
.rd32 = _nouveau_gpuobj_rd32,
.wr32 = _nouveau_gpuobj_wr32,
},
};
int
nouveau_gpuobj_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
u32 size, u32 align, u32 flags,
struct nouveau_gpuobj **pgpuobj)
{
struct nouveau_object *engine = parent;
struct nouveau_gpuobj_class args = {
.pargpu = pargpu,
.size = size,
.align = align,
.flags = flags,
};
if (!nv_iclass(engine, NV_SUBDEV_CLASS))
engine = engine->engine;
BUG_ON(engine == NULL);
return nouveau_object_ctor(parent, engine, &_nouveau_gpuobj_oclass,
&args, sizeof(args),
(struct nouveau_object **)pgpuobj);
}
int
nouveau_gpuobj_map(struct nouveau_gpuobj *gpuobj, u32 access,
struct nouveau_vma *vma)
{
struct nouveau_bar *bar = nouveau_bar(gpuobj);
int ret = -EINVAL;
if (bar && bar->umap) {
struct nouveau_instobj *iobj = (void *)
nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
struct nouveau_mem **mem = (void *)(iobj + 1);
ret = bar->umap(bar, *mem, access, vma);
}
return ret;
}
int
nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm,
u32 access, struct nouveau_vma *vma)
{
struct nouveau_instobj *iobj = (void *)
nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
struct nouveau_mem **mem = (void *)(iobj + 1);
int ret;
ret = nouveau_vm_get(vm, gpuobj->size, 12, access, vma);
if (ret)
return ret;
nouveau_vm_map(vma, *mem);
return 0;
}
void
nouveau_gpuobj_unmap(struct nouveau_vma *vma)
{
if (vma->node) {
nouveau_vm_unmap(vma);
nouveau_vm_put(vma);
}
}
/* the below is basically only here to support sharing the paged dma object
* for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
* anywhere else.
*/
static void
nouveau_gpudup_dtor(struct nouveau_object *object)
{
struct nouveau_gpuobj *gpuobj = (void *)object;
nouveau_object_ref(NULL, &gpuobj->parent);
nouveau_object_destroy(&gpuobj->base);
}
static struct nouveau_oclass
nouveau_gpudup_oclass = {
.handle = NV_GPUOBJ_CLASS,
.ofuncs = &(struct nouveau_ofuncs) {
.dtor = nouveau_gpudup_dtor,
.init = nouveau_object_init,
.fini = nouveau_object_fini,
},
};
int
nouveau_gpuobj_dup(struct nouveau_object *parent, struct nouveau_gpuobj *base,
struct nouveau_gpuobj **pgpuobj)
{
struct nouveau_gpuobj *gpuobj;
int ret;
ret = nouveau_object_create(parent, parent->engine,
&nouveau_gpudup_oclass, 0, &gpuobj);
*pgpuobj = gpuobj;
if (ret)
return ret;
nouveau_object_ref(nv_object(base), &gpuobj->parent);
gpuobj->addr = base->addr;
gpuobj->size = base->size;
return 0;
}

View file

@ -0,0 +1,337 @@
/*
* 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/object.h>
#include <core/handle.h>
#include <core/client.h>
#define hprintk(h,l,f,a...) do { \
struct nouveau_client *c = nouveau_client((h)->object); \
struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \
nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \
} while(0)
int
nouveau_handle_init(struct nouveau_handle *handle)
{
struct nouveau_handle *item;
int ret;
hprintk(handle, TRACE, "init running\n");
ret = nouveau_object_inc(handle->object);
if (ret)
return ret;
hprintk(handle, TRACE, "init children\n");
list_for_each_entry(item, &handle->tree, head) {
ret = nouveau_handle_init(item);
if (ret)
goto fail;
}
hprintk(handle, TRACE, "init completed\n");
return 0;
fail:
hprintk(handle, ERROR, "init failed with %d\n", ret);
list_for_each_entry_continue_reverse(item, &handle->tree, head) {
nouveau_handle_fini(item, false);
}
nouveau_object_dec(handle->object, false);
return ret;
}
int
nouveau_handle_fini(struct nouveau_handle *handle, bool suspend)
{
static char *name[2] = { "fini", "suspend" };
struct nouveau_handle *item;
int ret;
hprintk(handle, TRACE, "%s children\n", name[suspend]);
list_for_each_entry(item, &handle->tree, head) {
ret = nouveau_handle_fini(item, suspend);
if (ret && suspend)
goto fail;
}
hprintk(handle, TRACE, "%s running\n", name[suspend]);
if (handle->object) {
ret = nouveau_object_dec(handle->object, suspend);
if (ret && suspend)
goto fail;
}
hprintk(handle, TRACE, "%s completed\n", name[suspend]);
return 0;
fail:
hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
list_for_each_entry_continue_reverse(item, &handle->tree, head) {
int rret = nouveau_handle_init(item);
if (rret)
hprintk(handle, FATAL, "failed to restart, %d\n", rret);
}
return ret;
}
int
nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
struct nouveau_object *object,
struct nouveau_handle **phandle)
{
struct nouveau_object *namedb;
struct nouveau_handle *handle;
int ret;
namedb = parent;
while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
namedb = namedb->parent;
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
INIT_LIST_HEAD(&handle->head);
INIT_LIST_HEAD(&handle->tree);
handle->name = _handle;
handle->priv = ~0;
ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);
if (ret) {
kfree(handle);
return ret;
}
if (nv_parent(parent)->object_attach) {
ret = nv_parent(parent)->object_attach(parent, object, _handle);
if (ret < 0) {
nouveau_handle_destroy(handle);
return ret;
}
handle->priv = ret;
}
if (object != namedb) {
while (!nv_iclass(namedb, NV_CLIENT_CLASS))
namedb = namedb->parent;
handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);
if (handle->parent) {
list_add(&handle->head, &handle->parent->tree);
nouveau_namedb_put(handle->parent);
}
}
hprintk(handle, TRACE, "created\n");
*phandle = handle;
return 0;
}
void
nouveau_handle_destroy(struct nouveau_handle *handle)
{
struct nouveau_handle *item, *temp;
hprintk(handle, TRACE, "destroy running\n");
list_for_each_entry_safe(item, temp, &handle->tree, head) {
nouveau_handle_destroy(item);
}
list_del(&handle->head);
if (handle->priv != ~0) {
struct nouveau_object *parent = handle->parent->object;
nv_parent(parent)->object_detach(parent, handle->priv);
}
hprintk(handle, TRACE, "destroy completed\n");
nouveau_namedb_remove(handle);
kfree(handle);
}
struct nouveau_object *
nouveau_handle_ref(struct nouveau_object *parent, u32 name)
{
struct nouveau_object *object = NULL;
struct nouveau_handle *handle;
while (!nv_iclass(parent, NV_NAMEDB_CLASS))
parent = parent->parent;
handle = nouveau_namedb_get(nv_namedb(parent), name);
if (handle) {
nouveau_object_ref(handle->object, &object);
nouveau_namedb_put(handle);
}
return object;
}
struct nouveau_handle *
nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass)
{
struct nouveau_namedb *namedb;
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
return nouveau_namedb_get_class(namedb, oclass);
return NULL;
}
struct nouveau_handle *
nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst)
{
struct nouveau_namedb *namedb;
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
return nouveau_namedb_get_vinst(namedb, vinst);
return NULL;
}
struct nouveau_handle *
nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst)
{
struct nouveau_namedb *namedb;
if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
return nouveau_namedb_get_cinst(namedb, cinst);
return NULL;
}
void
nouveau_handle_put(struct nouveau_handle *handle)
{
if (handle)
nouveau_namedb_put(handle);
}
int
nouveau_handle_new(struct nouveau_object *client, u32 _parent, u32 _handle,
u16 _oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_object *parent = NULL;
struct nouveau_object *engctx = NULL;
struct nouveau_object *object = NULL;
struct nouveau_object *engine;
struct nouveau_oclass *oclass;
struct nouveau_handle *handle;
int ret;
/* lookup parent object and ensure it *is* a parent */
parent = nouveau_handle_ref(client, _parent);
if (!parent) {
nv_error(client, "parent 0x%08x not found\n", _parent);
return -ENOENT;
}
if (!nv_iclass(parent, NV_PARENT_CLASS)) {
nv_error(parent, "cannot have children\n");
ret = -EINVAL;
goto fail_class;
}
/* check that parent supports the requested subclass */
ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
if (ret) {
nv_debug(parent, "illegal class 0x%04x\n", _oclass);
goto fail_class;
}
/* make sure engine init has been completed *before* any objects
* it controls are created - the constructors may depend on
* state calculated at init (ie. default context construction)
*/
if (engine) {
ret = nouveau_object_inc(engine);
if (ret)
goto fail_class;
}
/* if engine requires it, create a context object to insert
* between the parent and its children (eg. PGRAPH context)
*/
if (engine && nv_engine(engine)->cclass) {
ret = nouveau_object_ctor(parent, engine,
nv_engine(engine)->cclass,
data, size, &engctx);
if (ret)
goto fail_engctx;
} else {
nouveau_object_ref(parent, &engctx);
}
/* finally, create new object and bind it to its handle */
ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
*pobject = object;
if (ret)
goto fail_ctor;
ret = nouveau_object_inc(object);
if (ret)
goto fail_init;
ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
if (ret)
goto fail_handle;
ret = nouveau_handle_init(handle);
if (ret)
nouveau_handle_destroy(handle);
fail_handle:
nouveau_object_dec(object, false);
fail_init:
nouveau_object_ref(NULL, &object);
fail_ctor:
nouveau_object_ref(NULL, &engctx);
fail_engctx:
if (engine)
nouveau_object_dec(engine, false);
fail_class:
nouveau_object_ref(NULL, &parent);
return ret;
}
int
nouveau_handle_del(struct nouveau_object *client, u32 _parent, u32 _handle)
{
struct nouveau_object *parent = NULL;
struct nouveau_object *namedb = NULL;
struct nouveau_handle *handle = NULL;
parent = nouveau_handle_ref(client, _parent);
if (!parent)
return -ENOENT;
namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
if (namedb) {
handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
if (handle) {
nouveau_namedb_put(handle);
nouveau_handle_fini(handle, false);
nouveau_handle_destroy(handle);
}
}
nouveau_object_ref(NULL, &parent);
return handle ? 0 : -EINVAL;
}

View file

@ -0,0 +1,530 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include <core/object.h>
#include <core/parent.h>
#include <core/handle.h>
#include <core/namedb.h>
#include <core/client.h>
#include <core/device.h>
#include <core/ioctl.h>
#include <core/event.h>
#include <nvif/unpack.h>
#include <nvif/ioctl.h>
static int
nvkm_ioctl_nop(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
union {
struct nvif_ioctl_nop none;
} *args = data;
int ret;
nv_ioctl(object, "nop size %d\n", size);
if (nvif_unvers(args->none)) {
nv_ioctl(object, "nop\n");
}
return ret;
}
static int
nvkm_ioctl_sclass(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
union {
struct nvif_ioctl_sclass_v0 v0;
} *args = data;
int ret;
if (!nv_iclass(object, NV_PARENT_CLASS)) {
nv_debug(object, "cannot have children (sclass)\n");
return -ENODEV;
}
nv_ioctl(object, "sclass size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "sclass vers %d count %d\n",
args->v0.version, args->v0.count);
if (size == args->v0.count * sizeof(args->v0.oclass[0])) {
ret = nouveau_parent_lclass(object, args->v0.oclass,
args->v0.count);
if (ret >= 0) {
args->v0.count = ret;
ret = 0;
}
} else {
ret = -EINVAL;
}
}
return ret;
}
static int
nvkm_ioctl_new(struct nouveau_handle *parent, void *data, u32 size)
{
union {
struct nvif_ioctl_new_v0 v0;
} *args = data;
struct nouveau_client *client = nouveau_client(parent->object);
struct nouveau_object *engctx = NULL;
struct nouveau_object *object = NULL;
struct nouveau_object *engine;
struct nouveau_oclass *oclass;
struct nouveau_handle *handle;
u32 _handle, _oclass;
int ret;
nv_ioctl(client, "new size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
_handle = args->v0.handle;
_oclass = args->v0.oclass;
} else
return ret;
nv_ioctl(client, "new vers %d handle %08x class %08x "
"route %02x token %llx\n",
args->v0.version, _handle, _oclass,
args->v0.route, args->v0.token);
if (!nv_iclass(parent->object, NV_PARENT_CLASS)) {
nv_debug(parent->object, "cannot have children (ctor)\n");
ret = -ENODEV;
goto fail_class;
}
/* check that parent supports the requested subclass */
ret = nouveau_parent_sclass(parent->object, _oclass, &engine, &oclass);
if (ret) {
nv_debug(parent->object, "illegal class 0x%04x\n", _oclass);
goto fail_class;
}
/* make sure engine init has been completed *before* any objects
* it controls are created - the constructors may depend on
* state calculated at init (ie. default context construction)
*/
if (engine) {
ret = nouveau_object_inc(engine);
if (ret)
goto fail_class;
}
/* if engine requires it, create a context object to insert
* between the parent and its children (eg. PGRAPH context)
*/
if (engine && nv_engine(engine)->cclass) {
ret = nouveau_object_ctor(parent->object, engine,
nv_engine(engine)->cclass,
data, size, &engctx);
if (ret)
goto fail_engctx;
} else {
nouveau_object_ref(parent->object, &engctx);
}
/* finally, create new object and bind it to its handle */
ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
client->data = object;
if (ret)
goto fail_ctor;
ret = nouveau_object_inc(object);
if (ret)
goto fail_init;
ret = nouveau_handle_create(parent->object, parent->name,
_handle, object, &handle);
if (ret)
goto fail_handle;
ret = nouveau_handle_init(handle);
handle->route = args->v0.route;
handle->token = args->v0.token;
if (ret)
nouveau_handle_destroy(handle);
fail_handle:
nouveau_object_dec(object, false);
fail_init:
nouveau_object_ref(NULL, &object);
fail_ctor:
nouveau_object_ref(NULL, &engctx);
fail_engctx:
if (engine)
nouveau_object_dec(engine, false);
fail_class:
return ret;
}
static int
nvkm_ioctl_del(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
union {
struct nvif_ioctl_del none;
} *args = data;
int ret;
nv_ioctl(object, "delete size %d\n", size);
if (nvif_unvers(args->none)) {
nv_ioctl(object, "delete\n");
nouveau_handle_fini(handle, false);
nouveau_handle_destroy(handle);
}
return ret;
}
static int
nvkm_ioctl_mthd(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
union {
struct nvif_ioctl_mthd_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "mthd size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "mthd vers %d mthd %02x\n",
args->v0.version, args->v0.method);
if (ret = -ENODEV, ofuncs->mthd)
ret = ofuncs->mthd(object, args->v0.method, data, size);
}
return ret;
}
static int
nvkm_ioctl_rd(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
union {
struct nvif_ioctl_rd_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "rd size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "rd vers %d size %d addr %016llx\n",
args->v0.version, args->v0.size, args->v0.addr);
switch (args->v0.size) {
case 1:
if (ret = -ENODEV, ofuncs->rd08) {
args->v0.data = nv_ro08(object, args->v0.addr);
ret = 0;
}
break;
case 2:
if (ret = -ENODEV, ofuncs->rd16) {
args->v0.data = nv_ro16(object, args->v0.addr);
ret = 0;
}
break;
case 4:
if (ret = -ENODEV, ofuncs->rd32) {
args->v0.data = nv_ro32(object, args->v0.addr);
ret = 0;
}
break;
default:
ret = -EINVAL;
break;
}
}
return ret;
}
static int
nvkm_ioctl_wr(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
union {
struct nvif_ioctl_wr_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "wr size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n",
args->v0.version, args->v0.size, args->v0.addr,
args->v0.data);
switch (args->v0.size) {
case 1:
if (ret = -ENODEV, ofuncs->wr08) {
nv_wo08(object, args->v0.addr, args->v0.data);
ret = 0;
}
break;
case 2:
if (ret = -ENODEV, ofuncs->wr16) {
nv_wo16(object, args->v0.addr, args->v0.data);
ret = 0;
}
break;
case 4:
if (ret = -ENODEV, ofuncs->wr32) {
nv_wo32(object, args->v0.addr, args->v0.data);
ret = 0;
}
break;
default:
ret = -EINVAL;
break;
}
}
return ret;
}
static int
nvkm_ioctl_map(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
union {
struct nvif_ioctl_map_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "map size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "map vers %d\n", args->v0.version);
if (ret = -ENODEV, ofuncs->map) {
ret = ofuncs->map(object, &args->v0.handle,
&args->v0.length);
}
}
return ret;
}
static int
nvkm_ioctl_unmap(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
union {
struct nvif_ioctl_unmap none;
} *args = data;
int ret;
nv_ioctl(object, "unmap size %d\n", size);
if (nvif_unvers(args->none)) {
nv_ioctl(object, "unmap\n");
}
return ret;
}
static int
nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_object *object = handle->object;
struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
union {
struct nvif_ioctl_ntfy_new_v0 v0;
} *args = data;
struct nvkm_event *event;
int ret;
nv_ioctl(object, "ntfy new size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "ntfy new vers %d event %02x\n",
args->v0.version, args->v0.event);
if (ret = -ENODEV, ofuncs->ntfy)
ret = ofuncs->ntfy(object, args->v0.event, &event);
if (ret == 0) {
ret = nvkm_client_notify_new(object, event, data, size);
if (ret >= 0) {
args->v0.index = ret;
ret = 0;
}
}
}
return ret;
}
static int
nvkm_ioctl_ntfy_del(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_client *client = nouveau_client(handle->object);
struct nouveau_object *object = handle->object;
union {
struct nvif_ioctl_ntfy_del_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "ntfy del size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "ntfy del vers %d index %d\n",
args->v0.version, args->v0.index);
ret = nvkm_client_notify_del(client, args->v0.index);
}
return ret;
}
static int
nvkm_ioctl_ntfy_get(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_client *client = nouveau_client(handle->object);
struct nouveau_object *object = handle->object;
union {
struct nvif_ioctl_ntfy_get_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "ntfy get size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "ntfy get vers %d index %d\n",
args->v0.version, args->v0.index);
ret = nvkm_client_notify_get(client, args->v0.index);
}
return ret;
}
static int
nvkm_ioctl_ntfy_put(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_client *client = nouveau_client(handle->object);
struct nouveau_object *object = handle->object;
union {
struct nvif_ioctl_ntfy_put_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "ntfy put size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "ntfy put vers %d index %d\n",
args->v0.version, args->v0.index);
ret = nvkm_client_notify_put(client, args->v0.index);
}
return ret;
}
static struct {
int version;
int (*func)(struct nouveau_handle *, void *, u32);
}
nvkm_ioctl_v0[] = {
{ 0x00, nvkm_ioctl_nop },
{ 0x00, nvkm_ioctl_sclass },
{ 0x00, nvkm_ioctl_new },
{ 0x00, nvkm_ioctl_del },
{ 0x00, nvkm_ioctl_mthd },
{ 0x00, nvkm_ioctl_rd },
{ 0x00, nvkm_ioctl_wr },
{ 0x00, nvkm_ioctl_map },
{ 0x00, nvkm_ioctl_unmap },
{ 0x00, nvkm_ioctl_ntfy_new },
{ 0x00, nvkm_ioctl_ntfy_del },
{ 0x00, nvkm_ioctl_ntfy_get },
{ 0x00, nvkm_ioctl_ntfy_put },
};
static int
nvkm_ioctl_path(struct nouveau_handle *parent, u32 type, u32 nr,
u32 *path, void *data, u32 size,
u8 owner, u8 *route, u64 *token)
{
struct nouveau_handle *handle = parent;
struct nouveau_namedb *namedb;
struct nouveau_object *object;
int ret;
while ((object = parent->object), nr--) {
nv_ioctl(object, "path 0x%08x\n", path[nr]);
if (!nv_iclass(object, NV_PARENT_CLASS)) {
nv_debug(object, "cannot have children (path)\n");
return -EINVAL;
}
if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||
!(handle = nouveau_namedb_get(namedb, path[nr]))) {
nv_debug(object, "handle 0x%08x not found\n", path[nr]);
return -ENOENT;
}
nouveau_namedb_put(handle);
parent = handle;
}
if (owner != NVIF_IOCTL_V0_OWNER_ANY &&
owner != handle->route) {
nv_ioctl(object, "object route != owner\n");
return -EACCES;
}
*route = handle->route;
*token = handle->token;
if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
if (nvkm_ioctl_v0[type].version == 0) {
ret = nvkm_ioctl_v0[type].func(handle, data, size);
}
}
return ret;
}
int
nvkm_ioctl(struct nouveau_client *client, bool supervisor,
void *data, u32 size, void **hack)
{
union {
struct nvif_ioctl_v0 v0;
} *args = data;
int ret;
client->super = supervisor;
nv_ioctl(client, "size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",
args->v0.version, args->v0.type, args->v0.path_nr,
args->v0.owner);
ret = nvkm_ioctl_path(client->root, args->v0.type,
args->v0.path_nr, args->v0.path,
data, size, args->v0.owner,
&args->v0.route, &args->v0.token);
}
nv_ioctl(client, "return %d\n", ret);
if (hack) {
*hack = client->data;
client->data = NULL;
}
client->super = false;
return ret;
}

View file

@ -0,0 +1,303 @@
/*
* 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/mm.h"
#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
static void
nouveau_mm_dump(struct nouveau_mm *mm, const char *header)
{
struct nouveau_mm_node *node;
printk(KERN_ERR "nouveau: %s\n", header);
printk(KERN_ERR "nouveau: node list:\n");
list_for_each_entry(node, &mm->nodes, nl_entry) {
printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
node->offset, node->length, node->type);
}
printk(KERN_ERR "nouveau: free list:\n");
list_for_each_entry(node, &mm->free, fl_entry) {
printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
node->offset, node->length, node->type);
}
}
void
nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
{
struct nouveau_mm_node *this = *pthis;
if (this) {
struct nouveau_mm_node *prev = node(this, prev);
struct nouveau_mm_node *next = node(this, next);
if (prev && prev->type == NVKM_MM_TYPE_NONE) {
prev->length += this->length;
list_del(&this->nl_entry);
kfree(this); this = prev;
}
if (next && next->type == NVKM_MM_TYPE_NONE) {
next->offset = this->offset;
next->length += this->length;
if (this->type == NVKM_MM_TYPE_NONE)
list_del(&this->fl_entry);
list_del(&this->nl_entry);
kfree(this); this = NULL;
}
if (this && this->type != NVKM_MM_TYPE_NONE) {
list_for_each_entry(prev, &mm->free, fl_entry) {
if (this->offset < prev->offset)
break;
}
list_add_tail(&this->fl_entry, &prev->fl_entry);
this->type = NVKM_MM_TYPE_NONE;
}
}
*pthis = NULL;
}
static struct nouveau_mm_node *
region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
{
struct nouveau_mm_node *b;
if (a->length == size)
return a;
b = kmalloc(sizeof(*b), GFP_KERNEL);
if (unlikely(b == NULL))
return NULL;
b->offset = a->offset;
b->length = size;
b->heap = a->heap;
b->type = a->type;
a->offset += size;
a->length -= size;
list_add_tail(&b->nl_entry, &a->nl_entry);
if (b->type == NVKM_MM_TYPE_NONE)
list_add_tail(&b->fl_entry, &a->fl_entry);
return b;
}
int
nouveau_mm_head(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
u32 size_min, u32 align, struct nouveau_mm_node **pnode)
{
struct nouveau_mm_node *prev, *this, *next;
u32 mask = align - 1;
u32 splitoff;
u32 s, e;
BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
list_for_each_entry(this, &mm->free, fl_entry) {
if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
if (this->heap != heap)
continue;
}
e = this->offset + this->length;
s = this->offset;
prev = node(this, prev);
if (prev && prev->type != type)
s = roundup(s, mm->block_size);
next = node(this, next);
if (next && next->type != type)
e = rounddown(e, mm->block_size);
s = (s + mask) & ~mask;
e &= ~mask;
if (s > e || e - s < size_min)
continue;
splitoff = s - this->offset;
if (splitoff && !region_head(mm, this, splitoff))
return -ENOMEM;
this = region_head(mm, this, min(size_max, e - s));
if (!this)
return -ENOMEM;
this->type = type;
list_del(&this->fl_entry);
*pnode = this;
return 0;
}
return -ENOSPC;
}
static struct nouveau_mm_node *
region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
{
struct nouveau_mm_node *b;
if (a->length == size)
return a;
b = kmalloc(sizeof(*b), GFP_KERNEL);
if (unlikely(b == NULL))
return NULL;
a->length -= size;
b->offset = a->offset + a->length;
b->length = size;
b->heap = a->heap;
b->type = a->type;
list_add(&b->nl_entry, &a->nl_entry);
if (b->type == NVKM_MM_TYPE_NONE)
list_add(&b->fl_entry, &a->fl_entry);
return b;
}
int
nouveau_mm_tail(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
u32 size_min, u32 align, struct nouveau_mm_node **pnode)
{
struct nouveau_mm_node *prev, *this, *next;
u32 mask = align - 1;
BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
list_for_each_entry_reverse(this, &mm->free, fl_entry) {
u32 e = this->offset + this->length;
u32 s = this->offset;
u32 c = 0, a;
if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
if (this->heap != heap)
continue;
}
prev = node(this, prev);
if (prev && prev->type != type)
s = roundup(s, mm->block_size);
next = node(this, next);
if (next && next->type != type) {
e = rounddown(e, mm->block_size);
c = next->offset - e;
}
s = (s + mask) & ~mask;
a = e - s;
if (s > e || a < size_min)
continue;
a = min(a, size_max);
s = (e - a) & ~mask;
c += (e - s) - a;
if (c && !region_tail(mm, this, c))
return -ENOMEM;
this = region_tail(mm, this, a);
if (!this)
return -ENOMEM;
this->type = type;
list_del(&this->fl_entry);
*pnode = this;
return 0;
}
return -ENOSPC;
}
int
nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
{
struct nouveau_mm_node *node, *prev;
u32 next;
if (nouveau_mm_initialised(mm)) {
prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
next = prev->offset + prev->length;
if (next != offset) {
BUG_ON(next > offset);
if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
return -ENOMEM;
node->type = NVKM_MM_TYPE_HOLE;
node->offset = next;
node->length = offset - next;
list_add_tail(&node->nl_entry, &mm->nodes);
}
BUG_ON(block != mm->block_size);
} else {
INIT_LIST_HEAD(&mm->nodes);
INIT_LIST_HEAD(&mm->free);
mm->block_size = block;
mm->heap_nodes = 0;
}
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
return -ENOMEM;
if (length) {
node->offset = roundup(offset, mm->block_size);
node->length = rounddown(offset + length, mm->block_size);
node->length -= node->offset;
}
list_add_tail(&node->nl_entry, &mm->nodes);
list_add_tail(&node->fl_entry, &mm->free);
node->heap = ++mm->heap_nodes;
return 0;
}
int
nouveau_mm_fini(struct nouveau_mm *mm)
{
struct nouveau_mm_node *node, *temp;
int nodes = 0;
if (!nouveau_mm_initialised(mm))
return 0;
list_for_each_entry(node, &mm->nodes, nl_entry) {
if (node->type != NVKM_MM_TYPE_HOLE) {
if (++nodes > mm->heap_nodes) {
nouveau_mm_dump(mm, "mm not clean!");
return -EBUSY;
}
}
}
list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
list_del(&node->nl_entry);
kfree(node);
}
mm->heap_nodes = 0;
return 0;
}

View file

@ -0,0 +1,203 @@
/*
* 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/object.h>
#include <core/namedb.h>
#include <core/handle.h>
#include <core/gpuobj.h>
static struct nouveau_handle *
nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name)
{
struct nouveau_handle *handle;
list_for_each_entry(handle, &namedb->list, node) {
if (handle->name == name)
return handle;
}
return NULL;
}
static struct nouveau_handle *
nouveau_namedb_lookup_class(struct nouveau_namedb *namedb, u16 oclass)
{
struct nouveau_handle *handle;
list_for_each_entry(handle, &namedb->list, node) {
if (nv_mclass(handle->object) == oclass)
return handle;
}
return NULL;
}
static struct nouveau_handle *
nouveau_namedb_lookup_vinst(struct nouveau_namedb *namedb, u64 vinst)
{
struct nouveau_handle *handle;
list_for_each_entry(handle, &namedb->list, node) {
if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
if (nv_gpuobj(handle->object)->addr == vinst)
return handle;
}
}
return NULL;
}
static struct nouveau_handle *
nouveau_namedb_lookup_cinst(struct nouveau_namedb *namedb, u32 cinst)
{
struct nouveau_handle *handle;
list_for_each_entry(handle, &namedb->list, node) {
if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
if (nv_gpuobj(handle->object)->node &&
nv_gpuobj(handle->object)->node->offset == cinst)
return handle;
}
}
return NULL;
}
int
nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name,
struct nouveau_object *object,
struct nouveau_handle *handle)
{
int ret = -EEXIST;
write_lock_irq(&namedb->lock);
if (!nouveau_namedb_lookup(namedb, name)) {
nouveau_object_ref(object, &handle->object);
handle->namedb = namedb;
list_add(&handle->node, &namedb->list);
ret = 0;
}
write_unlock_irq(&namedb->lock);
return ret;
}
void
nouveau_namedb_remove(struct nouveau_handle *handle)
{
struct nouveau_namedb *namedb = handle->namedb;
struct nouveau_object *object = handle->object;
write_lock_irq(&namedb->lock);
list_del(&handle->node);
write_unlock_irq(&namedb->lock);
nouveau_object_ref(NULL, &object);
}
struct nouveau_handle *
nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name)
{
struct nouveau_handle *handle;
read_lock(&namedb->lock);
handle = nouveau_namedb_lookup(namedb, name);
if (handle == NULL)
read_unlock(&namedb->lock);
return handle;
}
struct nouveau_handle *
nouveau_namedb_get_class(struct nouveau_namedb *namedb, u16 oclass)
{
struct nouveau_handle *handle;
read_lock(&namedb->lock);
handle = nouveau_namedb_lookup_class(namedb, oclass);
if (handle == NULL)
read_unlock(&namedb->lock);
return handle;
}
struct nouveau_handle *
nouveau_namedb_get_vinst(struct nouveau_namedb *namedb, u64 vinst)
{
struct nouveau_handle *handle;
read_lock(&namedb->lock);
handle = nouveau_namedb_lookup_vinst(namedb, vinst);
if (handle == NULL)
read_unlock(&namedb->lock);
return handle;
}
struct nouveau_handle *
nouveau_namedb_get_cinst(struct nouveau_namedb *namedb, u32 cinst)
{
struct nouveau_handle *handle;
read_lock(&namedb->lock);
handle = nouveau_namedb_lookup_cinst(namedb, cinst);
if (handle == NULL)
read_unlock(&namedb->lock);
return handle;
}
void
nouveau_namedb_put(struct nouveau_handle *handle)
{
if (handle)
read_unlock(&handle->namedb->lock);
}
int
nouveau_namedb_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, u32 pclass,
struct nouveau_oclass *sclass, u64 engcls,
int length, void **pobject)
{
struct nouveau_namedb *namedb;
int ret;
ret = nouveau_parent_create_(parent, engine, oclass, pclass |
NV_NAMEDB_CLASS, sclass, engcls,
length, pobject);
namedb = *pobject;
if (ret)
return ret;
rwlock_init(&namedb->lock);
INIT_LIST_HEAD(&namedb->list);
return 0;
}
int
_nouveau_namedb_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_namedb *object;
int ret;
ret = nouveau_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
*pobject = nv_object(object);
if (ret)
return ret;
return 0;
}

View file

@ -0,0 +1,168 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include <core/client.h>
#include <core/event.h>
#include <core/notify.h>
#include <nvif/unpack.h>
#include <nvif/event.h>
static inline void
nvkm_notify_put_locked(struct nvkm_notify *notify)
{
if (notify->block++ == 0)
nvkm_event_put(notify->event, notify->types, notify->index);
}
void
nvkm_notify_put(struct nvkm_notify *notify)
{
struct nvkm_event *event = notify->event;
unsigned long flags;
if (likely(event) &&
test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
nvkm_notify_put_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
flush_work(&notify->work);
}
}
static inline void
nvkm_notify_get_locked(struct nvkm_notify *notify)
{
if (--notify->block == 0)
nvkm_event_get(notify->event, notify->types, notify->index);
}
void
nvkm_notify_get(struct nvkm_notify *notify)
{
struct nvkm_event *event = notify->event;
unsigned long flags;
if (likely(event) &&
!test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
nvkm_notify_get_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
}
}
static inline void
nvkm_notify_func(struct nvkm_notify *notify)
{
struct nvkm_event *event = notify->event;
int ret = notify->func(notify);
unsigned long flags;
if ((ret == NVKM_NOTIFY_KEEP) ||
!test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
nvkm_notify_get_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
}
}
static void
nvkm_notify_work(struct work_struct *work)
{
struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
nvkm_notify_func(notify);
}
void
nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
{
struct nvkm_event *event = notify->event;
unsigned long flags;
assert_spin_locked(&event->list_lock);
BUG_ON(size != notify->size);
spin_lock_irqsave(&event->refs_lock, flags);
if (notify->block) {
spin_unlock_irqrestore(&event->refs_lock, flags);
return;
}
nvkm_notify_put_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
memcpy((void *)notify->data, data, size);
schedule_work(&notify->work);
} else {
notify->data = data;
nvkm_notify_func(notify);
notify->data = NULL;
}
}
void
nvkm_notify_fini(struct nvkm_notify *notify)
{
unsigned long flags;
if (notify->event) {
nvkm_notify_put(notify);
spin_lock_irqsave(&notify->event->list_lock, flags);
list_del(&notify->head);
spin_unlock_irqrestore(&notify->event->list_lock, flags);
kfree((void *)notify->data);
notify->event = NULL;
}
}
int
nvkm_notify_init(struct nouveau_object *object, struct nvkm_event *event,
int (*func)(struct nvkm_notify *), bool work,
void *data, u32 size, u32 reply,
struct nvkm_notify *notify)
{
unsigned long flags;
int ret = -ENODEV;
if ((notify->event = event), event->refs) {
ret = event->func->ctor(object, data, size, notify);
if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
notify->flags = 0;
notify->block = 1;
notify->func = func;
notify->data = NULL;
if (ret = 0, work) {
INIT_WORK(&notify->work, nvkm_notify_work);
set_bit(NVKM_NOTIFY_WORK, &notify->flags);
notify->data = kmalloc(reply, GFP_KERNEL);
if (!notify->data)
ret = -ENOMEM;
}
}
if (ret == 0) {
spin_lock_irqsave(&event->list_lock, flags);
list_add_tail(&notify->head, &event->list);
spin_unlock_irqrestore(&event->list_lock, flags);
}
}
if (ret)
notify->event = NULL;
return ret;
}

View file

@ -0,0 +1,334 @@
/*
* 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/object.h>
#include <core/engine.h>
#ifdef NOUVEAU_OBJECT_MAGIC
static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
static DEFINE_SPINLOCK(_objlist_lock);
#endif
int
nouveau_object_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, u32 pclass,
int size, void **pobject)
{
struct nouveau_object *object;
object = *pobject = kzalloc(size, GFP_KERNEL);
if (!object)
return -ENOMEM;
nouveau_object_ref(parent, &object->parent);
nouveau_object_ref(engine, &object->engine);
object->oclass = oclass;
object->oclass->handle |= pclass;
atomic_set(&object->refcount, 1);
atomic_set(&object->usecount, 0);
#ifdef NOUVEAU_OBJECT_MAGIC
object->_magic = NOUVEAU_OBJECT_MAGIC;
spin_lock(&_objlist_lock);
list_add(&object->list, &_objlist);
spin_unlock(&_objlist_lock);
#endif
return 0;
}
int
_nouveau_object_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
if (size != 0)
return -ENOSYS;
return nouveau_object_create(parent, engine, oclass, 0, pobject);
}
void
nouveau_object_destroy(struct nouveau_object *object)
{
#ifdef NOUVEAU_OBJECT_MAGIC
spin_lock(&_objlist_lock);
list_del(&object->list);
spin_unlock(&_objlist_lock);
#endif
nouveau_object_ref(NULL, &object->engine);
nouveau_object_ref(NULL, &object->parent);
kfree(object);
}
int
nouveau_object_init(struct nouveau_object *object)
{
return 0;
}
int
nouveau_object_fini(struct nouveau_object *object, bool suspend)
{
return 0;
}
struct nouveau_ofuncs
nouveau_object_ofuncs = {
.ctor = _nouveau_object_ctor,
.dtor = nouveau_object_destroy,
.init = nouveau_object_init,
.fini = nouveau_object_fini,
};
int
nouveau_object_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
struct nouveau_object *object = NULL;
int ret;
ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
*pobject = object;
if (ret < 0) {
if (ret != -ENODEV) {
nv_error(parent, "failed to create 0x%08x, %d\n",
oclass->handle, ret);
}
if (object) {
ofuncs->dtor(object);
*pobject = NULL;
}
return ret;
}
if (ret == 0) {
nv_trace(object, "created\n");
atomic_set(&object->refcount, 1);
}
return 0;
}
static void
nouveau_object_dtor(struct nouveau_object *object)
{
nv_trace(object, "destroying\n");
nv_ofuncs(object)->dtor(object);
}
void
nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
{
if (obj) {
atomic_inc(&obj->refcount);
nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
}
if (*ref) {
int dead = atomic_dec_and_test(&(*ref)->refcount);
nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
if (dead)
nouveau_object_dtor(*ref);
}
*ref = obj;
}
int
nouveau_object_inc(struct nouveau_object *object)
{
int ref = atomic_add_return(1, &object->usecount);
int ret;
nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
if (ref != 1)
return 0;
nv_trace(object, "initialising...\n");
if (object->parent) {
ret = nouveau_object_inc(object->parent);
if (ret) {
nv_error(object, "parent failed, %d\n", ret);
goto fail_parent;
}
}
if (object->engine) {
mutex_lock(&nv_subdev(object->engine)->mutex);
ret = nouveau_object_inc(object->engine);
mutex_unlock(&nv_subdev(object->engine)->mutex);
if (ret) {
nv_error(object, "engine failed, %d\n", ret);
goto fail_engine;
}
}
ret = nv_ofuncs(object)->init(object);
atomic_set(&object->usecount, 1);
if (ret) {
nv_error(object, "init failed, %d\n", ret);
goto fail_self;
}
nv_trace(object, "initialised\n");
return 0;
fail_self:
if (object->engine) {
mutex_lock(&nv_subdev(object->engine)->mutex);
nouveau_object_dec(object->engine, false);
mutex_unlock(&nv_subdev(object->engine)->mutex);
}
fail_engine:
if (object->parent)
nouveau_object_dec(object->parent, false);
fail_parent:
atomic_dec(&object->usecount);
return ret;
}
static int
nouveau_object_decf(struct nouveau_object *object)
{
int ret;
nv_trace(object, "stopping...\n");
ret = nv_ofuncs(object)->fini(object, false);
atomic_set(&object->usecount, 0);
if (ret)
nv_warn(object, "failed fini, %d\n", ret);
if (object->engine) {
mutex_lock(&nv_subdev(object->engine)->mutex);
nouveau_object_dec(object->engine, false);
mutex_unlock(&nv_subdev(object->engine)->mutex);
}
if (object->parent)
nouveau_object_dec(object->parent, false);
nv_trace(object, "stopped\n");
return 0;
}
static int
nouveau_object_decs(struct nouveau_object *object)
{
int ret, rret;
nv_trace(object, "suspending...\n");
ret = nv_ofuncs(object)->fini(object, true);
atomic_set(&object->usecount, 0);
if (ret) {
nv_error(object, "failed suspend, %d\n", ret);
return ret;
}
if (object->engine) {
mutex_lock(&nv_subdev(object->engine)->mutex);
ret = nouveau_object_dec(object->engine, true);
mutex_unlock(&nv_subdev(object->engine)->mutex);
if (ret) {
nv_warn(object, "engine failed suspend, %d\n", ret);
goto fail_engine;
}
}
if (object->parent) {
ret = nouveau_object_dec(object->parent, true);
if (ret) {
nv_warn(object, "parent failed suspend, %d\n", ret);
goto fail_parent;
}
}
nv_trace(object, "suspended\n");
return 0;
fail_parent:
if (object->engine) {
mutex_lock(&nv_subdev(object->engine)->mutex);
rret = nouveau_object_inc(object->engine);
mutex_unlock(&nv_subdev(object->engine)->mutex);
if (rret)
nv_fatal(object, "engine failed to reinit, %d\n", rret);
}
fail_engine:
rret = nv_ofuncs(object)->init(object);
if (rret)
nv_fatal(object, "failed to reinit, %d\n", rret);
return ret;
}
int
nouveau_object_dec(struct nouveau_object *object, bool suspend)
{
int ref = atomic_add_return(-1, &object->usecount);
int ret;
nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
if (ref == 0) {
if (suspend)
ret = nouveau_object_decs(object);
else
ret = nouveau_object_decf(object);
if (ret) {
atomic_inc(&object->usecount);
return ret;
}
}
return 0;
}
void
nouveau_object_debug(void)
{
#ifdef NOUVEAU_OBJECT_MAGIC
struct nouveau_object *object;
if (!list_empty(&_objlist)) {
nv_fatal(NULL, "*******************************************\n");
nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
nv_fatal(NULL, "*******************************************\n");
list_for_each_entry(object, &_objlist, list) {
nv_fatal(object, "%p/%p/%d/%d\n",
object->parent, object->engine,
atomic_read(&object->refcount),
atomic_read(&object->usecount));
}
}
#endif
}

View file

@ -0,0 +1,122 @@
/*
* 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/option.h>
#include <core/debug.h>
const char *
nouveau_stropt(const char *optstr, const char *opt, int *arglen)
{
while (optstr && *optstr != '\0') {
int len = strcspn(optstr, ",=");
switch (optstr[len]) {
case '=':
if (!strncasecmpz(optstr, opt, len)) {
optstr += len + 1;
*arglen = strcspn(optstr, ",=");
return *arglen ? optstr : NULL;
}
optstr++;
break;
case ',':
optstr++;
break;
default:
break;
}
optstr += len;
}
return NULL;
}
bool
nouveau_boolopt(const char *optstr, const char *opt, bool value)
{
int arglen;
optstr = nouveau_stropt(optstr, opt, &arglen);
if (optstr) {
if (!strncasecmpz(optstr, "0", arglen) ||
!strncasecmpz(optstr, "no", arglen) ||
!strncasecmpz(optstr, "off", arglen) ||
!strncasecmpz(optstr, "false", arglen))
value = false;
else
if (!strncasecmpz(optstr, "1", arglen) ||
!strncasecmpz(optstr, "yes", arglen) ||
!strncasecmpz(optstr, "on", arglen) ||
!strncasecmpz(optstr, "true", arglen))
value = true;
}
return value;
}
int
nouveau_dbgopt(const char *optstr, const char *sub)
{
int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT;
while (optstr) {
int len = strcspn(optstr, ",=");
switch (optstr[len]) {
case '=':
if (strncasecmpz(optstr, sub, len))
mode = 0;
optstr++;
break;
default:
if (mode) {
if (!strncasecmpz(optstr, "fatal", len))
level = NV_DBG_FATAL;
else if (!strncasecmpz(optstr, "error", len))
level = NV_DBG_ERROR;
else if (!strncasecmpz(optstr, "warn", len))
level = NV_DBG_WARN;
else if (!strncasecmpz(optstr, "info", len))
level = NV_DBG_INFO_NORMAL;
else if (!strncasecmpz(optstr, "debug", len))
level = NV_DBG_DEBUG;
else if (!strncasecmpz(optstr, "trace", len))
level = NV_DBG_TRACE;
else if (!strncasecmpz(optstr, "paranoia", len))
level = NV_DBG_PARANOIA;
else if (!strncasecmpz(optstr, "spam", len))
level = NV_DBG_SPAM;
}
if (optstr[len] != '\0') {
optstr++;
mode = 1;
break;
}
return level;
}
optstr += len;
}
return level;
}

View file

@ -0,0 +1,161 @@
/*
* 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/object.h>
#include <core/parent.h>
#include <core/client.h>
int
nouveau_parent_sclass(struct nouveau_object *parent, u16 handle,
struct nouveau_object **pengine,
struct nouveau_oclass **poclass)
{
struct nouveau_sclass *sclass;
struct nouveau_engine *engine;
struct nouveau_oclass *oclass;
u64 mask;
sclass = nv_parent(parent)->sclass;
while (sclass) {
if ((sclass->oclass->handle & 0xffff) == handle) {
*pengine = parent->engine;
*poclass = sclass->oclass;
return 0;
}
sclass = sclass->sclass;
}
mask = nv_parent(parent)->engine;
while (mask) {
int i = __ffs64(mask);
if (nv_iclass(parent, NV_CLIENT_CLASS))
engine = nv_engine(nv_client(parent)->device);
else
engine = nouveau_engine(parent, i);
if (engine) {
oclass = engine->sclass;
while (oclass->ofuncs) {
if ((oclass->handle & 0xffff) == handle) {
*pengine = nv_object(engine);
*poclass = oclass;
return 0;
}
oclass++;
}
}
mask &= ~(1ULL << i);
}
return -EINVAL;
}
int
nouveau_parent_lclass(struct nouveau_object *parent, u32 *lclass, int size)
{
struct nouveau_sclass *sclass;
struct nouveau_engine *engine;
struct nouveau_oclass *oclass;
int nr = -1, i;
u64 mask;
sclass = nv_parent(parent)->sclass;
while (sclass) {
if (++nr < size)
lclass[nr] = sclass->oclass->handle & 0xffff;
sclass = sclass->sclass;
}
mask = nv_parent(parent)->engine;
while (i = __ffs64(mask), mask) {
engine = nouveau_engine(parent, i);
if (engine && (oclass = engine->sclass)) {
while (oclass->ofuncs) {
if (++nr < size)
lclass[nr] = oclass->handle & 0xffff;
oclass++;
}
}
mask &= ~(1ULL << i);
}
return nr + 1;
}
int
nouveau_parent_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, u32 pclass,
struct nouveau_oclass *sclass, u64 engcls,
int size, void **pobject)
{
struct nouveau_parent *object;
struct nouveau_sclass *nclass;
int ret;
ret = nouveau_object_create_(parent, engine, oclass, pclass |
NV_PARENT_CLASS, size, pobject);
object = *pobject;
if (ret)
return ret;
while (sclass && sclass->ofuncs) {
nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);
if (!nclass)
return -ENOMEM;
nclass->sclass = object->sclass;
object->sclass = nclass;
nclass->engine = engine ? nv_engine(engine) : NULL;
nclass->oclass = sclass;
sclass++;
}
object->engine = engcls;
return 0;
}
void
nouveau_parent_destroy(struct nouveau_parent *parent)
{
struct nouveau_sclass *sclass;
while ((sclass = parent->sclass)) {
parent->sclass = sclass->sclass;
kfree(sclass);
}
nouveau_object_destroy(&parent->base);
}
void
_nouveau_parent_dtor(struct nouveau_object *object)
{
nouveau_parent_destroy(nv_parent(object));
}

View file

@ -0,0 +1,98 @@
/*
* 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/object.h>
#include <core/client.h>
#include <core/subdev.h>
#include <core/printk.h>
int nv_info_debug_level = NV_DBG_INFO_NORMAL;
void
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;
char obuf[64], *ofmt = "";
if (object->engine) {
snprintf(obuf, sizeof(obuf), "[0x%08x][%p]",
nv_hclass(object), object);
ofmt = obuf;
subdev = object->engine;
device = object->engine;
}
if (subdev->parent)
device = subdev->parent;
if (level > nv_subdev(subdev)->debug)
return;
snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx,
name[level], nv_subdev(subdev)->name,
nv_device(device)->name, ofmt, fmt);
} else
if (object && nv_iclass(object, NV_CLIENT_CLASS)) {
if (level > nv_client(object)->debug)
return;
snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx,
name[level], nv_client(object)->name, fmt);
} else {
snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt);
}
va_start(args, fmt);
vprintk(mfmt, args);
va_end(args);
}

View file

@ -0,0 +1,108 @@
/*
* 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.
*/
#include <core/object.h>
#include <core/ramht.h>
#include <subdev/bar.h>
static u32
nouveau_ramht_hash(struct nouveau_ramht *ramht, int chid, u32 handle)
{
u32 hash = 0;
while (handle) {
hash ^= (handle & ((1 << ramht->bits) - 1));
handle >>= ramht->bits;
}
hash ^= chid << (ramht->bits - 4);
hash = hash << 3;
return hash;
}
int
nouveau_ramht_insert(struct nouveau_ramht *ramht, int chid,
u32 handle, u32 context)
{
struct nouveau_bar *bar = nouveau_bar(ramht);
u32 co, ho;
co = ho = nouveau_ramht_hash(ramht, chid, handle);
do {
if (!nv_ro32(ramht, co + 4)) {
nv_wo32(ramht, co + 0, handle);
nv_wo32(ramht, co + 4, context);
if (bar)
bar->flush(bar);
return co;
}
co += 8;
if (co >= nv_gpuobj(ramht)->size)
co = 0;
} while (co != ho);
return -ENOMEM;
}
void
nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie)
{
struct nouveau_bar *bar = nouveau_bar(ramht);
nv_wo32(ramht, cookie + 0, 0x00000000);
nv_wo32(ramht, cookie + 4, 0x00000000);
if (bar)
bar->flush(bar);
}
static struct nouveau_oclass
nouveau_ramht_oclass = {
.handle = 0x0000abcd,
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = NULL,
.dtor = _nouveau_gpuobj_dtor,
.init = _nouveau_gpuobj_init,
.fini = _nouveau_gpuobj_fini,
.rd32 = _nouveau_gpuobj_rd32,
.wr32 = _nouveau_gpuobj_wr32,
},
};
int
nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
u32 size, u32 align, struct nouveau_ramht **pramht)
{
struct nouveau_ramht *ramht;
int ret;
ret = nouveau_gpuobj_create(parent, parent->engine ?
parent->engine : parent, /* <nv50 ramht */
&nouveau_ramht_oclass, 0, pargpu, size,
align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
*pramht = ramht;
if (ret)
return ret;
ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
return 0;
}

View file

@ -0,0 +1,112 @@
/*
* 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/object.h>
#include <core/subdev.h>
#include <core/device.h>
#include <core/option.h>
void
nouveau_subdev_reset(struct nouveau_object *subdev)
{
nv_trace(subdev, "resetting...\n");
nv_ofuncs(subdev)->fini(subdev, false);
nv_debug(subdev, "reset\n");
}
int
nouveau_subdev_init(struct nouveau_subdev *subdev)
{
int ret = nouveau_object_init(&subdev->base);
if (ret)
return ret;
nouveau_subdev_reset(&subdev->base);
return 0;
}
int
_nouveau_subdev_init(struct nouveau_object *object)
{
return nouveau_subdev_init(nv_subdev(object));
}
int
nouveau_subdev_fini(struct nouveau_subdev *subdev, bool suspend)
{
if (subdev->unit) {
nv_mask(subdev, 0x000200, subdev->unit, 0x00000000);
nv_mask(subdev, 0x000200, subdev->unit, subdev->unit);
}
return nouveau_object_fini(&subdev->base, suspend);
}
int
_nouveau_subdev_fini(struct nouveau_object *object, bool suspend)
{
return nouveau_subdev_fini(nv_subdev(object), suspend);
}
void
nouveau_subdev_destroy(struct nouveau_subdev *subdev)
{
int subidx = nv_hclass(subdev) & 0xff;
nv_device(subdev)->subdev[subidx] = NULL;
nouveau_object_destroy(&subdev->base);
}
void
_nouveau_subdev_dtor(struct nouveau_object *object)
{
nouveau_subdev_destroy(nv_subdev(object));
}
int
nouveau_subdev_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, u32 pclass,
const char *subname, const char *sysname,
int size, void **pobject)
{
struct nouveau_subdev *subdev;
int ret;
ret = nouveau_object_create_(parent, engine, oclass, pclass |
NV_SUBDEV_CLASS, size, pobject);
subdev = *pobject;
if (ret)
return ret;
__mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
subdev->name = subname;
if (parent) {
struct nouveau_device *device = nv_device(parent);
subdev->debug = nouveau_dbgopt(device->dbgopt, subname);
subdev->mmio = nv_subdev(device)->mmio;
}
return 0;
}

View file

@ -0,0 +1,92 @@
/*
* 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, Ilia Mirkin
*/
#include <engine/xtensa.h>
#include <engine/bsp.h>
/*******************************************************************************
* BSP object classes
******************************************************************************/
static struct nouveau_oclass
nv84_bsp_sclass[] = {
{ 0x74b0, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* BSP context
******************************************************************************/
static struct nouveau_oclass
nv84_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_xtensa_engctx_ctor,
.dtor = _nouveau_engctx_dtor,
.init = _nouveau_engctx_init,
.fini = _nouveau_engctx_fini,
.rd32 = _nouveau_engctx_rd32,
.wr32 = _nouveau_engctx_wr32,
},
};
/*******************************************************************************
* BSP engine/subdev functions
******************************************************************************/
static int
nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_xtensa *priv;
int ret;
ret = nouveau_xtensa_create(parent, engine, oclass, 0x103000, true,
"PBSP", "bsp", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x04008000;
nv_engine(priv)->cclass = &nv84_bsp_cclass;
nv_engine(priv)->sclass = nv84_bsp_sclass;
priv->fifo_val = 0x1111;
priv->unkd28 = 0x90044;
return 0;
}
struct nouveau_oclass
nv84_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_bsp_ctor,
.dtor = _nouveau_xtensa_dtor,
.init = _nouveau_xtensa_init,
.fini = _nouveau_xtensa_fini,
.rd32 = _nouveau_xtensa_rd32,
.wr32 = _nouveau_xtensa_wr32,
},
};

View file

@ -0,0 +1,111 @@
/*
* 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, Maarten Lankhorst, Ilia Mirkin
*/
#include <engine/falcon.h>
#include <engine/bsp.h>
struct nv98_bsp_priv {
struct nouveau_falcon base;
};
/*******************************************************************************
* BSP object classes
******************************************************************************/
static struct nouveau_oclass
nv98_bsp_sclass[] = {
{ 0x88b1, &nouveau_object_ofuncs },
{ 0x85b1, &nouveau_object_ofuncs },
{ 0x86b1, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PBSP context
******************************************************************************/
static struct nouveau_oclass
nv98_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_falcon_context_init,
.fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_falcon_context_wr32,
},
};
/*******************************************************************************
* PBSP engine/subdev functions
******************************************************************************/
static int
nv98_bsp_init(struct nouveau_object *object)
{
struct nv98_bsp_priv *priv = (void *)object;
int ret;
ret = nouveau_falcon_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x084010, 0x0000ffd2);
nv_wr32(priv, 0x08401c, 0x0000fff2);
return 0;
}
static int
nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv98_bsp_priv *priv;
int ret;
ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
"PBSP", "bsp", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x04008000;
nv_engine(priv)->cclass = &nv98_bsp_cclass;
nv_engine(priv)->sclass = nv98_bsp_sclass;
return 0;
}
struct nouveau_oclass
nv98_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_bsp_ctor,
.dtor = _nouveau_falcon_dtor,
.init = nv98_bsp_init,
.fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
},
};

View file

@ -0,0 +1,110 @@
/*
* Copyright 2012 Maarten Lankhorst
*
* 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: Maarten Lankhorst
*/
#include <engine/falcon.h>
#include <engine/bsp.h>
struct nvc0_bsp_priv {
struct nouveau_falcon base;
};
/*******************************************************************************
* BSP object classes
******************************************************************************/
static struct nouveau_oclass
nvc0_bsp_sclass[] = {
{ 0x90b1, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PBSP context
******************************************************************************/
static struct nouveau_oclass
nvc0_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_falcon_context_init,
.fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_falcon_context_wr32,
},
};
/*******************************************************************************
* PBSP engine/subdev functions
******************************************************************************/
static int
nvc0_bsp_init(struct nouveau_object *object)
{
struct nvc0_bsp_priv *priv = (void *)object;
int ret;
ret = nouveau_falcon_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x084010, 0x0000fff2);
nv_wr32(priv, 0x08401c, 0x0000fff2);
return 0;
}
static int
nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_bsp_priv *priv;
int ret;
ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
"PBSP", "bsp", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00008000;
nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nvc0_bsp_cclass;
nv_engine(priv)->sclass = nvc0_bsp_sclass;
return 0;
}
struct nouveau_oclass
nvc0_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_bsp_ctor,
.dtor = _nouveau_falcon_dtor,
.init = nvc0_bsp_init,
.fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
},
};

View file

@ -0,0 +1,110 @@
/*
* 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/falcon.h>
#include <engine/bsp.h>
struct nve0_bsp_priv {
struct nouveau_falcon base;
};
/*******************************************************************************
* BSP object classes
******************************************************************************/
static struct nouveau_oclass
nve0_bsp_sclass[] = {
{ 0x95b1, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PBSP context
******************************************************************************/
static struct nouveau_oclass
nve0_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_falcon_context_init,
.fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_falcon_context_wr32,
},
};
/*******************************************************************************
* PBSP engine/subdev functions
******************************************************************************/
static int
nve0_bsp_init(struct nouveau_object *object)
{
struct nve0_bsp_priv *priv = (void *)object;
int ret;
ret = nouveau_falcon_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x084010, 0x0000fff2);
nv_wr32(priv, 0x08401c, 0x0000fff2);
return 0;
}
static int
nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nve0_bsp_priv *priv;
int ret;
ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
"PBSP", "bsp", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00008000;
nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nve0_bsp_cclass;
nv_engine(priv)->sclass = nve0_bsp_sclass;
return 0;
}
struct nouveau_oclass
nve0_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_bsp_ctor,
.dtor = _nouveau_falcon_dtor,
.init = nve0_bsp_init,
.fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
},
};

View file

@ -0,0 +1,872 @@
/* fuc microcode for copy engine on nva3- chipsets
*
* 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
*/
/* To build for nva3:nvc0
* m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
*
* To build for nvc0-
* m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
*/
ifdef(`NVA3',
.section #nva3_pcopy_data
,
.section #nvc0_pcopy_data
)
ctx_object: .b32 0
ifdef(`NVA3',
ctx_dma:
ctx_dma_query: .b32 0
ctx_dma_src: .b32 0
ctx_dma_dst: .b32 0
,)
.equ #ctx_dma_count 3
ctx_query_address_high: .b32 0
ctx_query_address_low: .b32 0
ctx_query_counter: .b32 0
ctx_src_address_high: .b32 0
ctx_src_address_low: .b32 0
ctx_src_pitch: .b32 0
ctx_src_tile_mode: .b32 0
ctx_src_xsize: .b32 0
ctx_src_ysize: .b32 0
ctx_src_zsize: .b32 0
ctx_src_zoff: .b32 0
ctx_src_xoff: .b32 0
ctx_src_yoff: .b32 0
ctx_src_cpp: .b32 0
ctx_dst_address_high: .b32 0
ctx_dst_address_low: .b32 0
ctx_dst_pitch: .b32 0
ctx_dst_tile_mode: .b32 0
ctx_dst_xsize: .b32 0
ctx_dst_ysize: .b32 0
ctx_dst_zsize: .b32 0
ctx_dst_zoff: .b32 0
ctx_dst_xoff: .b32 0
ctx_dst_yoff: .b32 0
ctx_dst_cpp: .b32 0
ctx_format: .b32 0
ctx_swz_const0: .b32 0
ctx_swz_const1: .b32 0
ctx_xcnt: .b32 0
ctx_ycnt: .b32 0
.align 256
dispatch_table:
// mthd 0x0000, NAME
.b16 0x000 1
.b32 #ctx_object ~0xffffffff
// mthd 0x0100, NOP
.b16 0x040 1
.b32 0x00010000 + #cmd_nop ~0xffffffff
// mthd 0x0140, PM_TRIGGER
.b16 0x050 1
.b32 0x00010000 + #cmd_pm_trigger ~0xffffffff
ifdef(`NVA3', `
// mthd 0x0180-0x018c, DMA_
.b16 0x060 #ctx_dma_count
dispatch_dma:
.b32 0x00010000 + #cmd_dma ~0xffffffff
.b32 0x00010000 + #cmd_dma ~0xffffffff
.b32 0x00010000 + #cmd_dma ~0xffffffff
',)
// mthd 0x0200-0x0218, SRC_TILE
.b16 0x80 7
.b32 #ctx_src_tile_mode ~0x00000fff
.b32 #ctx_src_xsize ~0x0007ffff
.b32 #ctx_src_ysize ~0x00001fff
.b32 #ctx_src_zsize ~0x000007ff
.b32 #ctx_src_zoff ~0x00000fff
.b32 #ctx_src_xoff ~0x0007ffff
.b32 #ctx_src_yoff ~0x00001fff
// mthd 0x0220-0x0238, DST_TILE
.b16 0x88 7
.b32 #ctx_dst_tile_mode ~0x00000fff
.b32 #ctx_dst_xsize ~0x0007ffff
.b32 #ctx_dst_ysize ~0x00001fff
.b32 #ctx_dst_zsize ~0x000007ff
.b32 #ctx_dst_zoff ~0x00000fff
.b32 #ctx_dst_xoff ~0x0007ffff
.b32 #ctx_dst_yoff ~0x00001fff
// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
.b16 0xc0 2
.b32 0x00010000 + #cmd_exec ~0xffffffff
.b32 0x00010000 + #cmd_wrcache_flush ~0xffffffff
// mthd 0x030c-0x0340, various stuff
.b16 0xc3 14
.b32 #ctx_src_address_high ~0x000000ff
.b32 #ctx_src_address_low ~0xffffffff
.b32 #ctx_dst_address_high ~0x000000ff
.b32 #ctx_dst_address_low ~0xffffffff
.b32 #ctx_src_pitch ~0x0007ffff
.b32 #ctx_dst_pitch ~0x0007ffff
.b32 #ctx_xcnt ~0x0000ffff
.b32 #ctx_ycnt ~0x00001fff
.b32 #ctx_format ~0x0333ffff
.b32 #ctx_swz_const0 ~0xffffffff
.b32 #ctx_swz_const1 ~0xffffffff
.b32 #ctx_query_address_high ~0x000000ff
.b32 #ctx_query_address_low ~0xffffffff
.b32 #ctx_query_counter ~0xffffffff
.b16 0x800 0
ifdef(`NVA3',
.section #nva3_pcopy_code
,
.section #nvc0_pcopy_code
)
main:
clear b32 $r0
mov $sp $r0
// setup i0 handler and route fifo and ctxswitch to it
mov $r1 #ih
mov $iv0 $r1
mov $r1 0x400
movw $r2 0xfff3
sethi $r2 0
iowr I[$r1 + 0x300] $r2
// enable interrupts
or $r2 0xc
iowr I[$r1] $r2
bset $flags ie0
// enable fifo access and context switching
mov $r1 0x1200
mov $r2 3
iowr I[$r1] $r2
// sleep forever, waking for interrupts
bset $flags $p0
spin:
sleep $p0
bra #spin
// i0 handler
ih:
iord $r1 I[$r0 + 0x200]
and $r2 $r1 0x00000008
bra e #ih_no_chsw
call #chsw
ih_no_chsw:
and $r2 $r1 0x00000004
bra e #ih_no_cmd
call #dispatch
ih_no_cmd:
and $r1 $r1 0x0000000c
iowr I[$r0 + 0x100] $r1
iret
// $p1 direction (0 = unload, 1 = load)
// $r3 channel
swctx:
mov $r4 0x7700
mov $xtargets $r4
ifdef(`NVA3', `
// target 7 hardcoded to ctx dma object
mov $xdbase $r0
', ` // NVC0
// read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
mov $r4 0x2100
iord $r4 I[$r4 + 0]
and $r4 1
shl b32 $r4 4
add b32 $r4 0x30
// channel is in vram
mov $r15 0x61c
shl b32 $r15 6
mov $r5 0x114
iowrs I[$r15] $r5
// read 16-byte PCOPYn info, containing context pointer, from channel
shl b32 $r5 $r3 4
add b32 $r5 2
mov $xdbase $r5
mov $r5 $sp
// get a chunk of stack space, aligned to 256 byte boundary
sub b32 $r5 0x100
mov $r6 0xff
not b32 $r6
and $r5 $r6
sethi $r5 0x00020000
xdld $r4 $r5
xdwait
sethi $r5 0
// set context pointer, from within channel VM
mov $r14 0
iowrs I[$r15] $r14
ld b32 $r4 D[$r5 + 0]
shr b32 $r4 8
ld b32 $r6 D[$r5 + 4]
shl b32 $r6 24
or $r4 $r6
mov $xdbase $r4
')
// 256-byte context, at start of data segment
mov b32 $r4 $r0
sethi $r4 0x60000
// swap!
bra $p1 #swctx_load
xdst $r0 $r4
bra #swctx_done
swctx_load:
xdld $r0 $r4
swctx_done:
xdwait
ret
chsw:
// read current channel
mov $r2 0x1400
iord $r3 I[$r2]
// if it's active, unload it and return
xbit $r15 $r3 0x1e
bra e #chsw_no_unload
bclr $flags $p1
call #swctx
bclr $r3 0x1e
iowr I[$r2] $r3
mov $r4 1
iowr I[$r2 + 0x200] $r4
ret
// read next channel
chsw_no_unload:
iord $r3 I[$r2 + 0x100]
// is there a channel waiting to be loaded?
xbit $r13 $r3 0x1e
bra e #chsw_finish_load
bset $flags $p1
call #swctx
ifdef(`NVA3',
// load dma objects back into TARGET regs
mov $r5 #ctx_dma
mov $r6 #ctx_dma_count
chsw_load_ctx_dma:
ld b32 $r7 D[$r5 + $r6 * 4]
add b32 $r8 $r6 0x180
shl b32 $r8 8
iowr I[$r8] $r7
sub b32 $r6 1
bra nc #chsw_load_ctx_dma
,)
chsw_finish_load:
mov $r3 2
iowr I[$r2 + 0x200] $r3
ret
dispatch:
// read incoming fifo command
mov $r3 0x1900
iord $r2 I[$r3 + 0x100]
iord $r3 I[$r3 + 0x000]
and $r4 $r2 0x7ff
// $r2 will be used to store exception data
shl b32 $r2 0x10
// lookup method in the dispatch table, ILLEGAL_MTHD if not found
mov $r5 #dispatch_table
clear b32 $r6
clear b32 $r7
dispatch_loop:
ld b16 $r6 D[$r5 + 0]
ld b16 $r7 D[$r5 + 2]
add b32 $r5 4
cmpu b32 $r4 $r6
bra c #dispatch_illegal_mthd
add b32 $r7 $r6
cmpu b32 $r4 $r7
bra c #dispatch_valid_mthd
sub b32 $r7 $r6
shl b32 $r7 3
add b32 $r5 $r7
bra #dispatch_loop
// ensure no bits set in reserved fields, INVALID_BITFIELD
dispatch_valid_mthd:
sub b32 $r4 $r6
shl b32 $r4 3
add b32 $r4 $r5
ld b32 $r5 D[$r4 + 4]
and $r5 $r3
cmpu b32 $r5 0
bra ne #dispatch_invalid_bitfield
// depending on dispatch flags: execute method, or save data as state
ld b16 $r5 D[$r4 + 0]
ld b16 $r6 D[$r4 + 2]
cmpu b32 $r6 0
bra ne #dispatch_cmd
st b32 D[$r5] $r3
bra #dispatch_done
dispatch_cmd:
bclr $flags $p1
call $r5
bra $p1 #dispatch_error
bra #dispatch_done
dispatch_invalid_bitfield:
or $r2 2
dispatch_illegal_mthd:
or $r2 1
// store exception data in SCRATCH0/SCRATCH1, signal hostirq
dispatch_error:
mov $r4 0x1000
iowr I[$r4 + 0x000] $r2
iowr I[$r4 + 0x100] $r3
mov $r2 0x40
iowr I[$r0] $r2
hostirq_wait:
iord $r2 I[$r0 + 0x200]
and $r2 0x40
cmpu b32 $r2 0
bra ne #hostirq_wait
dispatch_done:
mov $r2 0x1d00
mov $r3 1
iowr I[$r2] $r3
ret
// No-operation
//
// Inputs:
// $r1: irqh state
// $r2: hostirq state
// $r3: data
// $r4: dispatch table entry
// Outputs:
// $r1: irqh state
// $p1: set on error
// $r2: hostirq state
// $r3: data
cmd_nop:
ret
// PM_TRIGGER
//
// Inputs:
// $r1: irqh state
// $r2: hostirq state
// $r3: data
// $r4: dispatch table entry
// Outputs:
// $r1: irqh state
// $p1: set on error
// $r2: hostirq state
// $r3: data
cmd_pm_trigger:
mov $r2 0x2200
clear b32 $r3
sethi $r3 0x20000
iowr I[$r2] $r3
ret
ifdef(`NVA3',
// SET_DMA_* method handler
//
// Inputs:
// $r1: irqh state
// $r2: hostirq state
// $r3: data
// $r4: dispatch table entry
// Outputs:
// $r1: irqh state
// $p1: set on error
// $r2: hostirq state
// $r3: data
cmd_dma:
sub b32 $r4 #dispatch_dma
shr b32 $r4 1
bset $r3 0x1e
st b32 D[$r4 + #ctx_dma] $r3
add b32 $r4 0x600
shl b32 $r4 6
iowr I[$r4] $r3
ret
,)
// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
//
cmd_exec_set_format:
// zero out a chunk of the stack to store the swizzle into
add $sp -0x10
st b32 D[$sp + 0x00] $r0
st b32 D[$sp + 0x04] $r0
st b32 D[$sp + 0x08] $r0
st b32 D[$sp + 0x0c] $r0
// extract cpp, src_ncomp and dst_ncomp from FORMAT
ld b32 $r4 D[$r0 + #ctx_format]
extr $r5 $r4 16:17
add b32 $r5 1
extr $r6 $r4 20:21
add b32 $r6 1
extr $r7 $r4 24:25
add b32 $r7 1
// convert FORMAT swizzle mask to hw swizzle mask
bclr $flags $p2
clear b32 $r8
clear b32 $r9
ncomp_loop:
and $r10 $r4 0xf
shr b32 $r4 4
clear b32 $r11
bpc_loop:
cmpu b8 $r10 4
bra nc #cmp_c0
mulu $r12 $r10 $r5
add b32 $r12 $r11
bset $flags $p2
bra #bpc_next
cmp_c0:
bra ne #cmp_c1
mov $r12 0x10
add b32 $r12 $r11
bra #bpc_next
cmp_c1:
cmpu b8 $r10 6
bra nc #cmp_zero
mov $r12 0x14
add b32 $r12 $r11
bra #bpc_next
cmp_zero:
mov $r12 0x80
bpc_next:
st b8 D[$sp + $r8] $r12
add b32 $r8 1
add b32 $r11 1
cmpu b32 $r11 $r5
bra c #bpc_loop
add b32 $r9 1
cmpu b32 $r9 $r7
bra c #ncomp_loop
// SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
mulu $r6 $r5
st b32 D[$r0 + #ctx_src_cpp] $r6
ld b32 $r8 D[$r0 + #ctx_xcnt]
mulu $r6 $r8
bra $p2 #dst_xcnt
clear b32 $r6
dst_xcnt:
mulu $r7 $r5
st b32 D[$r0 + #ctx_dst_cpp] $r7
mulu $r7 $r8
mov $r5 0x810
shl b32 $r5 6
iowr I[$r5 + 0x000] $r6
iowr I[$r5 + 0x100] $r7
add b32 $r5 0x800
ld b32 $r6 D[$r0 + #ctx_dst_cpp]
sub b32 $r6 1
shl b32 $r6 8
ld b32 $r7 D[$r0 + #ctx_src_cpp]
sub b32 $r7 1
or $r6 $r7
iowr I[$r5 + 0x000] $r6
add b32 $r5 0x100
ld b32 $r6 D[$sp + 0x00]
iowr I[$r5 + 0x000] $r6
ld b32 $r6 D[$sp + 0x04]
iowr I[$r5 + 0x100] $r6
ld b32 $r6 D[$sp + 0x08]
iowr I[$r5 + 0x200] $r6
ld b32 $r6 D[$sp + 0x0c]
iowr I[$r5 + 0x300] $r6
add b32 $r5 0x400
ld b32 $r6 D[$r0 + #ctx_swz_const0]
iowr I[$r5 + 0x000] $r6
ld b32 $r6 D[$r0 + #ctx_swz_const1]
iowr I[$r5 + 0x100] $r6
add $sp 0x10
ret
// Setup to handle a tiled surface
//
// Calculates a number of parameters the hardware requires in order
// to correctly handle tiling.
//
// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
// nTx = round_up(w * cpp, 1 << Tp) >> Tp
// nTy = round_up(h, 1 << Th) >> Th
// Txo = (x * cpp) & ((1 << Tp) - 1)
// Tx = (x * cpp) >> Tp
// Tyo = y & ((1 << Th) - 1)
// Ty = y >> Th
// Tzo = z & ((1 << Td) - 1)
// Tz = z >> Td
//
// off = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
// off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
//
// Inputs:
// $r4: hw command (0x104800)
// $r5: ctx offset adjustment for src/dst selection
// $p2: set if dst surface
//
cmd_exec_set_surface_tiled:
// translate TILE_MODE into Tp, Th, Td shift values
ld b32 $r7 D[$r5 + #ctx_src_tile_mode]
extr $r9 $r7 8:11
extr $r8 $r7 4:7
ifdef(`NVA3',
add b32 $r8 2
,
add b32 $r8 3
)
extr $r7 $r7 0:3
cmp b32 $r7 0xe
bra ne #xtile64
mov $r7 4
bra #xtileok
xtile64:
xbit $r7 $flags $p2
add b32 $r7 17
bset $r4 $r7
mov $r7 6
xtileok:
// Op = (x * cpp) & ((1 << Tp) - 1)
// Tx = (x * cpp) >> Tp
ld b32 $r10 D[$r5 + #ctx_src_xoff]
ld b32 $r11 D[$r5 + #ctx_src_cpp]
mulu $r10 $r11
mov $r11 1
shl b32 $r11 $r7
sub b32 $r11 1
and $r12 $r10 $r11
shr b32 $r10 $r7
// Tyo = y & ((1 << Th) - 1)
// Ty = y >> Th
ld b32 $r13 D[$r5 + #ctx_src_yoff]
mov $r14 1
shl b32 $r14 $r8
sub b32 $r14 1
and $r11 $r13 $r14
shr b32 $r13 $r8
// YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
add b32 $r14 1
shl b32 $r15 $r14 12
sub b32 $r14 $r11
or $r15 $r14
xbit $r6 $flags $p2
add b32 $r6 0x208
shl b32 $r6 8
iowr I[$r6 + 0x000] $r15
// Op += Tyo << Tp
shl b32 $r11 $r7
add b32 $r12 $r11
// nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
ld b32 $r15 D[$r5 + #ctx_src_xsize]
ld b32 $r11 D[$r5 + #ctx_src_cpp]
mulu $r15 $r11
mov $r11 1
shl b32 $r11 $r7
sub b32 $r11 1
add b32 $r15 $r11
shr b32 $r15 $r7
push $r15
// nTy = (h + ((1 << Th) - 1)) >> Th
ld b32 $r15 D[$r5 + #ctx_src_ysize]
mov $r11 1
shl b32 $r11 $r8
sub b32 $r11 1
add b32 $r15 $r11
shr b32 $r15 $r8
push $r15
// Tys = Tp + Th
// CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
add b32 $r7 $r8
sub b32 $r8 2
mov $r11 1
shl b32 $r11 $r8
shl b32 $r11 $r9
// Tzo = z & ((1 << Td) - 1)
// Tz = z >> Td
// Op += Tzo << Tys
// Ts = Tys + Td
ld b32 $r8 D[$r5 + #ctx_src_zoff]
mov $r14 1
shl b32 $r14 $r9
sub b32 $r14 1
and $r15 $r8 $r14
shl b32 $r15 $r7
add b32 $r12 $r15
add b32 $r7 $r9
shr b32 $r8 $r9
// Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
pop $r15
pop $r9
mulu $r13 $r9
add b32 $r10 $r13
mulu $r8 $r9
mulu $r8 $r15
add b32 $r10 $r8
shl b32 $r10 $r7
// PITCH = (nTx - 1) << Ts
sub b32 $r9 1
shl b32 $r9 $r7
iowr I[$r6 + 0x200] $r9
// SRC_ADDRESS_LOW = (Ot + Op) & 0xffffffff
// CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
ld b32 $r7 D[$r5 + #ctx_src_address_low]
ld b32 $r8 D[$r5 + #ctx_src_address_high]
add b32 $r10 $r12
add b32 $r7 $r10
adc b32 $r8 0
shl b32 $r8 16
or $r8 $r11
sub b32 $r6 0x600
iowr I[$r6 + 0x000] $r7
add b32 $r6 0x400
iowr I[$r6 + 0x000] $r8
ret
// Setup to handle a linear surface
//
// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
//
cmd_exec_set_surface_linear:
xbit $r6 $flags $p2
add b32 $r6 0x202
shl b32 $r6 8
ld b32 $r7 D[$r5 + #ctx_src_address_low]
iowr I[$r6 + 0x000] $r7
add b32 $r6 0x400
ld b32 $r7 D[$r5 + #ctx_src_address_high]
shl b32 $r7 16
iowr I[$r6 + 0x000] $r7
add b32 $r6 0x400
ld b32 $r7 D[$r5 + #ctx_src_pitch]
iowr I[$r6 + 0x000] $r7
ret
// wait for regs to be available for use
cmd_exec_wait:
push $r0
push $r1
mov $r0 0x800
shl b32 $r0 6
loop:
iord $r1 I[$r0]
and $r1 1
bra ne #loop
pop $r1
pop $r0
ret
cmd_exec_query:
// if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
xbit $r4 $r3 13
bra ne #query_counter
call #cmd_exec_wait
mov $r4 0x80c
shl b32 $r4 6
ld b32 $r5 D[$r0 + #ctx_query_address_low]
add b32 $r5 4
iowr I[$r4 + 0x000] $r5
iowr I[$r4 + 0x100] $r0
mov $r5 0xc
iowr I[$r4 + 0x200] $r5
add b32 $r4 0x400
ld b32 $r5 D[$r0 + #ctx_query_address_high]
shl b32 $r5 16
iowr I[$r4 + 0x000] $r5
add b32 $r4 0x500
mov $r5 0x00000b00
sethi $r5 0x00010000
iowr I[$r4 + 0x000] $r5
mov $r5 0x00004040
shl b32 $r5 1
sethi $r5 0x80800000
iowr I[$r4 + 0x100] $r5
mov $r5 0x00001110
sethi $r5 0x13120000
iowr I[$r4 + 0x200] $r5
mov $r5 0x00001514
sethi $r5 0x17160000
iowr I[$r4 + 0x300] $r5
mov $r5 0x00002601
sethi $r5 0x00010000
mov $r4 0x800
shl b32 $r4 6
iowr I[$r4 + 0x000] $r5
// write COUNTER
query_counter:
call #cmd_exec_wait
mov $r4 0x80c
shl b32 $r4 6
ld b32 $r5 D[$r0 + #ctx_query_address_low]
iowr I[$r4 + 0x000] $r5
iowr I[$r4 + 0x100] $r0
mov $r5 0x4
iowr I[$r4 + 0x200] $r5
add b32 $r4 0x400
ld b32 $r5 D[$r0 + #ctx_query_address_high]
shl b32 $r5 16
iowr I[$r4 + 0x000] $r5
add b32 $r4 0x500
mov $r5 0x00000300
iowr I[$r4 + 0x000] $r5
mov $r5 0x00001110
sethi $r5 0x13120000
iowr I[$r4 + 0x100] $r5
ld b32 $r5 D[$r0 + #ctx_query_counter]
add b32 $r4 0x500
iowr I[$r4 + 0x000] $r5
mov $r5 0x00002601
sethi $r5 0x00010000
mov $r4 0x800
shl b32 $r4 6
iowr I[$r4 + 0x000] $r5
ret
// Execute a copy operation
//
// Inputs:
// $r1: irqh state
// $r2: hostirq state
// $r3: data
// 000002000 QUERY_SHORT
// 000001000 QUERY
// 000000100 DST_LINEAR
// 000000010 SRC_LINEAR
// 000000001 FORMAT
// $r4: dispatch table entry
// Outputs:
// $r1: irqh state
// $p1: set on error
// $r2: hostirq state
// $r3: data
cmd_exec:
call #cmd_exec_wait
// if format requested, call function to calculate it, otherwise
// fill in cpp/xcnt for both surfaces as if (cpp == 1)
xbit $r15 $r3 0
bra e #cmd_exec_no_format
call #cmd_exec_set_format
mov $r4 0x200
bra #cmd_exec_init_src_surface
cmd_exec_no_format:
mov $r6 0x810
shl b32 $r6 6
mov $r7 1
st b32 D[$r0 + #ctx_src_cpp] $r7
st b32 D[$r0 + #ctx_dst_cpp] $r7
ld b32 $r7 D[$r0 + #ctx_xcnt]
iowr I[$r6 + 0x000] $r7
iowr I[$r6 + 0x100] $r7
clear b32 $r4
cmd_exec_init_src_surface:
bclr $flags $p2
clear b32 $r5
xbit $r15 $r3 4
bra e #src_tiled
call #cmd_exec_set_surface_linear
bra #cmd_exec_init_dst_surface
src_tiled:
call #cmd_exec_set_surface_tiled
bset $r4 7
cmd_exec_init_dst_surface:
bset $flags $p2
mov $r5 #ctx_dst_address_high - #ctx_src_address_high
xbit $r15 $r3 8
bra e #dst_tiled
call #cmd_exec_set_surface_linear
bra #cmd_exec_kick
dst_tiled:
call #cmd_exec_set_surface_tiled
bset $r4 8
cmd_exec_kick:
mov $r5 0x800
shl b32 $r5 6
ld b32 $r6 D[$r0 + #ctx_ycnt]
iowr I[$r5 + 0x100] $r6
mov $r6 0x0041
// SRC_TARGET = 1, DST_TARGET = 2
sethi $r6 0x44000000
or $r4 $r6
iowr I[$r5] $r4
// if requested, queue up a QUERY write after the copy has completed
xbit $r15 $r3 12
bra e #cmd_exec_done
call #cmd_exec_query
cmd_exec_done:
ret
// Flush write cache
//
// Inputs:
// $r1: irqh state
// $r2: hostirq state
// $r3: data
// $r4: dispatch table entry
// Outputs:
// $r1: irqh state
// $p1: set on error
// $r2: hostirq state
// $r3: data
cmd_wrcache_flush:
mov $r2 0x2200
clear b32 $r3
sethi $r3 0x10000
iowr I[$r2] $r3
ret
.align 0x100

View file

@ -0,0 +1,620 @@
uint32_t nva3_pcopy_data[] = {
/* 0x0000: ctx_object */
0x00000000,
/* 0x0004: ctx_dma */
/* 0x0004: ctx_dma_query */
0x00000000,
/* 0x0008: ctx_dma_src */
0x00000000,
/* 0x000c: ctx_dma_dst */
0x00000000,
/* 0x0010: ctx_query_address_high */
0x00000000,
/* 0x0014: ctx_query_address_low */
0x00000000,
/* 0x0018: ctx_query_counter */
0x00000000,
/* 0x001c: ctx_src_address_high */
0x00000000,
/* 0x0020: ctx_src_address_low */
0x00000000,
/* 0x0024: ctx_src_pitch */
0x00000000,
/* 0x0028: ctx_src_tile_mode */
0x00000000,
/* 0x002c: ctx_src_xsize */
0x00000000,
/* 0x0030: ctx_src_ysize */
0x00000000,
/* 0x0034: ctx_src_zsize */
0x00000000,
/* 0x0038: ctx_src_zoff */
0x00000000,
/* 0x003c: ctx_src_xoff */
0x00000000,
/* 0x0040: ctx_src_yoff */
0x00000000,
/* 0x0044: ctx_src_cpp */
0x00000000,
/* 0x0048: ctx_dst_address_high */
0x00000000,
/* 0x004c: ctx_dst_address_low */
0x00000000,
/* 0x0050: ctx_dst_pitch */
0x00000000,
/* 0x0054: ctx_dst_tile_mode */
0x00000000,
/* 0x0058: ctx_dst_xsize */
0x00000000,
/* 0x005c: ctx_dst_ysize */
0x00000000,
/* 0x0060: ctx_dst_zsize */
0x00000000,
/* 0x0064: ctx_dst_zoff */
0x00000000,
/* 0x0068: ctx_dst_xoff */
0x00000000,
/* 0x006c: ctx_dst_yoff */
0x00000000,
/* 0x0070: ctx_dst_cpp */
0x00000000,
/* 0x0074: ctx_format */
0x00000000,
/* 0x0078: ctx_swz_const0 */
0x00000000,
/* 0x007c: ctx_swz_const1 */
0x00000000,
/* 0x0080: ctx_xcnt */
0x00000000,
/* 0x0084: ctx_ycnt */
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
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: dispatch_table */
0x00010000,
0x00000000,
0x00000000,
0x00010040,
0x00010160,
0x00000000,
0x00010050,
0x00010162,
0x00000000,
0x00030060,
/* 0x0128: dispatch_dma */
0x00010170,
0x00000000,
0x00010170,
0x00000000,
0x00010170,
0x00000000,
0x00070080,
0x00000028,
0xfffff000,
0x0000002c,
0xfff80000,
0x00000030,
0xffffe000,
0x00000034,
0xfffff800,
0x00000038,
0xfffff000,
0x0000003c,
0xfff80000,
0x00000040,
0xffffe000,
0x00070088,
0x00000054,
0xfffff000,
0x00000058,
0xfff80000,
0x0000005c,
0xffffe000,
0x00000060,
0xfffff800,
0x00000064,
0xfffff000,
0x00000068,
0xfff80000,
0x0000006c,
0xffffe000,
0x000200c0,
0x00010492,
0x00000000,
0x0001051b,
0x00000000,
0x000e00c3,
0x0000001c,
0xffffff00,
0x00000020,
0x00000000,
0x00000048,
0xffffff00,
0x0000004c,
0x00000000,
0x00000024,
0xfff80000,
0x00000050,
0xfff80000,
0x00000080,
0xffff0000,
0x00000084,
0xffffe000,
0x00000074,
0xfccc0000,
0x00000078,
0x00000000,
0x0000007c,
0x00000000,
0x00000010,
0xffffff00,
0x00000014,
0x00000000,
0x00000018,
0x00000000,
0x00000800,
};
uint32_t nva3_pcopy_code[] = {
/* 0x0000: main */
0x04fe04bd,
0x3517f000,
0xf10010fe,
0xf1040017,
0xf0fff327,
0x12d00023,
0x0c25f0c0,
0xf40012d0,
0x17f11031,
0x27f01200,
0x0012d003,
/* 0x002f: spin */
0xf40031f4,
0x0ef40028,
/* 0x0035: ih */
0x8001cffd,
0xf40812c4,
0x21f4060b,
/* 0x0041: ih_no_chsw */
0x0412c472,
0xf4060bf4,
/* 0x004a: ih_no_cmd */
0x11c4c321,
0x4001d00c,
/* 0x0052: swctx */
0x47f101f8,
0x4bfe7700,
0x0007fe00,
0xf00204b9,
0x01f40643,
0x0604fa09,
/* 0x006b: swctx_load */
0xfa060ef4,
/* 0x006e: swctx_done */
0x03f80504,
/* 0x0072: chsw */
0x27f100f8,
0x23cf1400,
0x1e3fc800,
0xf4170bf4,
0x21f40132,
0x1e3af052,
0xf00023d0,
0x24d00147,
/* 0x0093: chsw_no_unload */
0xcf00f880,
0x3dc84023,
0x220bf41e,
0xf40131f4,
0x57f05221,
0x0367f004,
/* 0x00a8: chsw_load_ctx_dma */
0xa07856bc,
0xb6018068,
0x87d00884,
0x0162b600,
/* 0x00bb: chsw_finish_load */
0xf0f018f4,
0x23d00237,
/* 0x00c3: dispatch */
0xf100f880,
0xcf190037,
0x33cf4032,
0xff24e400,
0x1024b607,
0x010057f1,
0x74bd64bd,
/* 0x00dc: dispatch_loop */
0x58005658,
0x50b60157,
0x0446b804,
0xbb4d08f4,
0x47b80076,
0x0f08f404,
0xb60276bb,
0x57bb0374,
0xdf0ef400,
/* 0x0100: dispatch_valid_mthd */
0xb60246bb,
0x45bb0344,
0x01459800,
0xb00453fd,
0x1bf40054,
0x00455820,
0xb0014658,
0x1bf40064,
0x00538009,
/* 0x0127: dispatch_cmd */
0xf4300ef4,
0x55f90132,
0xf40c01f4,
/* 0x0132: dispatch_invalid_bitfield */
0x25f0250e,
/* 0x0135: dispatch_illegal_mthd */
0x0125f002,
/* 0x0138: dispatch_error */
0x100047f1,
0xd00042d0,
0x27f04043,
0x0002d040,
/* 0x0148: hostirq_wait */
0xf08002cf,
0x24b04024,
0xf71bf400,
/* 0x0154: dispatch_done */
0x1d0027f1,
0xd00137f0,
0x00f80023,
/* 0x0160: cmd_nop */
/* 0x0162: cmd_pm_trigger */
0x27f100f8,
0x34bd2200,
0xd00233f0,
0x00f80023,
/* 0x0170: cmd_dma */
0x012842b7,
0xf00145b6,
0x43801e39,
0x0040b701,
0x0644b606,
0xf80043d0,
/* 0x0189: cmd_exec_set_format */
0xf030f400,
0xb00001b0,
0x01b00101,
0x0301b002,
0xc71d0498,
0x50b63045,
0x3446c701,
0xc70160b6,
0x70b63847,
0x0232f401,
0x94bd84bd,
/* 0x01b4: ncomp_loop */
0xb60f4ac4,
0xb4bd0445,
/* 0x01bc: bpc_loop */
0xf404a430,
0xa5ff0f18,
0x00cbbbc0,
0xf40231f4,
/* 0x01ce: cmp_c0 */
0x1bf4220e,
0x10c7f00c,
0xf400cbbb,
/* 0x01da: cmp_c1 */
0xa430160e,
0x0c18f406,
0xbb14c7f0,
0x0ef400cb,
/* 0x01e9: cmp_zero */
0x80c7f107,
/* 0x01ed: bpc_next */
0x01c83800,
0xb60180b6,
0xb5b801b0,
0xc308f404,
0xb80190b6,
0x08f40497,
0x0065fdb2,
0x98110680,
0x68fd2008,
0x0502f400,
/* 0x0216: dst_xcnt */
0x75fd64bd,
0x1c078000,
0xf10078fd,
0xb6081057,
0x56d00654,
0x4057d000,
0x080050b7,
0xb61c0698,
0x64b60162,
0x11079808,
0xfd0172b6,
0x56d00567,
0x0050b700,
0x0060b401,
0xb40056d0,
0x56d00160,
0x0260b440,
0xb48056d0,
0x56d00360,
0x0050b7c0,
0x1e069804,
0x980056d0,
0x56d01f06,
0x1030f440,
/* 0x0276: cmd_exec_set_surface_tiled */
0x579800f8,
0x6879c70a,
0xb66478c7,
0x77c70280,
0x0e76b060,
0xf0091bf4,
0x0ef40477,
/* 0x0291: xtile64 */
0x027cf00f,
0xfd1170b6,
0x77f00947,
/* 0x029d: xtileok */
0x0f5a9806,
0xfd115b98,
0xb7f000ab,
0x04b7bb01,
0xff01b2b6,
0xa7bbc4ab,
0x105d9805,
0xbb01e7f0,
0xe2b604e8,
0xb4deff01,
0xb605d8bb,
0xef9401e0,
0x02ebbb0c,
0xf005fefd,
0x60b7026c,
0x64b60208,
0x006fd008,
0xbb04b7bb,
0x5f9800cb,
0x115b980b,
0xf000fbfd,
0xb7bb01b7,
0x01b2b604,
0xbb00fbbb,
0xf0f905f7,
0xf00c5f98,
0xb8bb01b7,
0x01b2b604,
0xbb00fbbb,
0xf0f905f8,
0xb60078bb,
0xb7f00282,
0x04b8bb01,
0x9804b9bb,
0xe7f00e58,
0x04e9bb01,
0xff01e2b6,
0xf7bbf48e,
0x00cfbb04,
0xbb0079bb,
0xf0fc0589,
0xd9fd90fc,
0x00adbb00,
0xfd0089fd,
0xa8bb008f,
0x04a7bb00,
0xbb0192b6,
0x69d00497,
0x08579880,
0xbb075898,
0x7abb00ac,
0x0081b600,
0xfd1084b6,
0x62b7058b,
0x67d00600,
0x0060b700,
0x0068d004,
/* 0x0382: cmd_exec_set_surface_linear */
0x6cf000f8,
0x0260b702,
0x0864b602,
0xd0085798,
0x60b70067,
0x57980400,
0x1074b607,
0xb70067d0,
0x98040060,
0x67d00957,
/* 0x03ab: cmd_exec_wait */
0xf900f800,
0xf110f900,
0xb6080007,
/* 0x03b6: loop */
0x01cf0604,
0x0114f000,
0xfcfa1bf4,
0xf800fc10,
/* 0x03c5: cmd_exec_query */
0x0d34c800,
0xf5701bf4,
0xf103ab21,
0xb6080c47,
0x05980644,
0x0450b605,
0xd00045d0,
0x57f04040,
0x8045d00c,
0x040040b7,
0xb6040598,
0x45d01054,
0x0040b700,
0x0057f105,
0x0153f00b,
0xf10045d0,
0xb6404057,
0x53f10154,
0x45d08080,
0x1057f140,
0x1253f111,
0x8045d013,
0x151457f1,
0x171653f1,
0xf1c045d0,
0xf0260157,
0x47f10153,
0x44b60800,
0x0045d006,
/* 0x0438: query_counter */
0x03ab21f5,
0x080c47f1,
0x980644b6,
0x45d00505,
0x4040d000,
0xd00457f0,
0x40b78045,
0x05980400,
0x1054b604,
0xb70045d0,
0xf1050040,
0xd0030057,
0x57f10045,
0x53f11110,
0x45d01312,
0x06059840,
0x050040b7,
0xf10045d0,
0xf0260157,
0x47f10153,
0x44b60800,
0x0045d006,
/* 0x0492: cmd_exec */
0x21f500f8,
0x3fc803ab,
0x0e0bf400,
0x018921f5,
0x020047f1,
/* 0x04a7: cmd_exec_no_format */
0xf11e0ef4,
0xb6081067,
0x77f00664,
0x11078001,
0x981c0780,
0x67d02007,
0x4067d000,
/* 0x04c2: cmd_exec_init_src_surface */
0x32f444bd,
0xc854bd02,
0x0bf4043f,
0x8221f50a,
0x0a0ef403,
/* 0x04d4: src_tiled */
0x027621f5,
/* 0x04db: cmd_exec_init_dst_surface */
0xf40749f0,
0x57f00231,
0x083fc82c,
0xf50a0bf4,
0xf4038221,
/* 0x04ee: dst_tiled */
0x21f50a0e,
0x49f00276,
/* 0x04f5: cmd_exec_kick */
0x0057f108,
0x0654b608,
0xd0210698,
0x67f04056,
0x0063f141,
0x0546fd44,
0xc80054d0,
0x0bf40c3f,
0xc521f507,
/* 0x0519: cmd_exec_done */
/* 0x051b: cmd_wrcache_flush */
0xf100f803,
0xbd220027,
0x0133f034,
0xf80023d0,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};

View file

@ -0,0 +1,606 @@
uint32_t nvc0_pcopy_data[] = {
/* 0x0000: ctx_object */
0x00000000,
/* 0x0004: ctx_query_address_high */
0x00000000,
/* 0x0008: ctx_query_address_low */
0x00000000,
/* 0x000c: ctx_query_counter */
0x00000000,
/* 0x0010: ctx_src_address_high */
0x00000000,
/* 0x0014: ctx_src_address_low */
0x00000000,
/* 0x0018: ctx_src_pitch */
0x00000000,
/* 0x001c: ctx_src_tile_mode */
0x00000000,
/* 0x0020: ctx_src_xsize */
0x00000000,
/* 0x0024: ctx_src_ysize */
0x00000000,
/* 0x0028: ctx_src_zsize */
0x00000000,
/* 0x002c: ctx_src_zoff */
0x00000000,
/* 0x0030: ctx_src_xoff */
0x00000000,
/* 0x0034: ctx_src_yoff */
0x00000000,
/* 0x0038: ctx_src_cpp */
0x00000000,
/* 0x003c: ctx_dst_address_high */
0x00000000,
/* 0x0040: ctx_dst_address_low */
0x00000000,
/* 0x0044: ctx_dst_pitch */
0x00000000,
/* 0x0048: ctx_dst_tile_mode */
0x00000000,
/* 0x004c: ctx_dst_xsize */
0x00000000,
/* 0x0050: ctx_dst_ysize */
0x00000000,
/* 0x0054: ctx_dst_zsize */
0x00000000,
/* 0x0058: ctx_dst_zoff */
0x00000000,
/* 0x005c: ctx_dst_xoff */
0x00000000,
/* 0x0060: ctx_dst_yoff */
0x00000000,
/* 0x0064: ctx_dst_cpp */
0x00000000,
/* 0x0068: ctx_format */
0x00000000,
/* 0x006c: ctx_swz_const0 */
0x00000000,
/* 0x0070: ctx_swz_const1 */
0x00000000,
/* 0x0074: ctx_xcnt */
0x00000000,
/* 0x0078: ctx_ycnt */
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
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: dispatch_table */
0x00010000,
0x00000000,
0x00000000,
0x00010040,
0x0001019f,
0x00000000,
0x00010050,
0x000101a1,
0x00000000,
0x00070080,
0x0000001c,
0xfffff000,
0x00000020,
0xfff80000,
0x00000024,
0xffffe000,
0x00000028,
0xfffff800,
0x0000002c,
0xfffff000,
0x00000030,
0xfff80000,
0x00000034,
0xffffe000,
0x00070088,
0x00000048,
0xfffff000,
0x0000004c,
0xfff80000,
0x00000050,
0xffffe000,
0x00000054,
0xfffff800,
0x00000058,
0xfffff000,
0x0000005c,
0xfff80000,
0x00000060,
0xffffe000,
0x000200c0,
0x000104b8,
0x00000000,
0x00010541,
0x00000000,
0x000e00c3,
0x00000010,
0xffffff00,
0x00000014,
0x00000000,
0x0000003c,
0xffffff00,
0x00000040,
0x00000000,
0x00000018,
0xfff80000,
0x00000044,
0xfff80000,
0x00000074,
0xffff0000,
0x00000078,
0xffffe000,
0x00000068,
0xfccc0000,
0x0000006c,
0x00000000,
0x00000070,
0x00000000,
0x00000004,
0xffffff00,
0x00000008,
0x00000000,
0x0000000c,
0x00000000,
0x00000800,
};
uint32_t nvc0_pcopy_code[] = {
/* 0x0000: main */
0x04fe04bd,
0x3517f000,
0xf10010fe,
0xf1040017,
0xf0fff327,
0x12d00023,
0x0c25f0c0,
0xf40012d0,
0x17f11031,
0x27f01200,
0x0012d003,
/* 0x002f: spin */
0xf40031f4,
0x0ef40028,
/* 0x0035: ih */
0x8001cffd,
0xf40812c4,
0x21f4060b,
/* 0x0041: ih_no_chsw */
0x0412c4ca,
0xf5070bf4,
/* 0x004b: ih_no_cmd */
0xc4010221,
0x01d00c11,
/* 0x0053: swctx */
0xf101f840,
0xfe770047,
0x47f1004b,
0x44cf2100,
0x0144f000,
0xb60444b6,
0xf7f13040,
0xf4b6061c,
0x1457f106,
0x00f5d101,
0xb6043594,
0x57fe0250,
0x0145fe00,
0x010052b7,
0x00ff67f1,
0x56fd60bd,
0x0253f004,
0xf80545fa,
0x0053f003,
0xd100e7f0,
0x549800fe,
0x0845b600,
0xb6015698,
0x46fd1864,
0x0047fe05,
0xf00204b9,
0x01f40643,
0x0604fa09,
/* 0x00c3: swctx_load */
0xfa060ef4,
/* 0x00c6: swctx_done */
0x03f80504,
/* 0x00ca: chsw */
0x27f100f8,
0x23cf1400,
0x1e3fc800,
0xf4170bf4,
0x21f40132,
0x1e3af053,
0xf00023d0,
0x24d00147,
/* 0x00eb: chsw_no_unload */
0xcf00f880,
0x3dc84023,
0x090bf41e,
0xf40131f4,
/* 0x00fa: chsw_finish_load */
0x37f05321,
0x8023d002,
/* 0x0102: dispatch */
0x37f100f8,
0x32cf1900,
0x0033cf40,
0x07ff24e4,
0xf11024b6,
0xbd010057,
/* 0x011b: dispatch_loop */
0x5874bd64,
0x57580056,
0x0450b601,
0xf40446b8,
0x76bb4d08,
0x0447b800,
0xbb0f08f4,
0x74b60276,
0x0057bb03,
/* 0x013f: dispatch_valid_mthd */
0xbbdf0ef4,
0x44b60246,
0x0045bb03,
0xfd014598,
0x54b00453,
0x201bf400,
0x58004558,
0x64b00146,
0x091bf400,
0xf4005380,
/* 0x0166: dispatch_cmd */
0x32f4300e,
0xf455f901,
0x0ef40c01,
/* 0x0171: dispatch_invalid_bitfield */
0x0225f025,
/* 0x0174: dispatch_illegal_mthd */
/* 0x0177: dispatch_error */
0xf10125f0,
0xd0100047,
0x43d00042,
0x4027f040,
/* 0x0187: hostirq_wait */
0xcf0002d0,
0x24f08002,
0x0024b040,
/* 0x0193: dispatch_done */
0xf1f71bf4,
0xf01d0027,
0x23d00137,
/* 0x019f: cmd_nop */
0xf800f800,
/* 0x01a1: cmd_pm_trigger */
0x0027f100,
0xf034bd22,
0x23d00233,
/* 0x01af: cmd_exec_set_format */
0xf400f800,
0x01b0f030,
0x0101b000,
0xb00201b0,
0x04980301,
0x3045c71a,
0xc70150b6,
0x60b63446,
0x3847c701,
0xf40170b6,
0x84bd0232,
/* 0x01da: ncomp_loop */
0x4ac494bd,
0x0445b60f,
/* 0x01e2: bpc_loop */
0xa430b4bd,
0x0f18f404,
0xbbc0a5ff,
0x31f400cb,
0x220ef402,
/* 0x01f4: cmp_c0 */
0xf00c1bf4,
0xcbbb10c7,
0x160ef400,
/* 0x0200: cmp_c1 */
0xf406a430,
0xc7f00c18,
0x00cbbb14,
/* 0x020f: cmp_zero */
0xf1070ef4,
/* 0x0213: bpc_next */
0x380080c7,
0x80b601c8,
0x01b0b601,
0xf404b5b8,
0x90b6c308,
0x0497b801,
0xfdb208f4,
0x06800065,
0x1d08980e,
0xf40068fd,
0x64bd0502,
/* 0x023c: dst_xcnt */
0x800075fd,
0x78fd1907,
0x1057f100,
0x0654b608,
0xd00056d0,
0x50b74057,
0x06980800,
0x0162b619,
0x980864b6,
0x72b60e07,
0x0567fd01,
0xb70056d0,
0xb4010050,
0x56d00060,
0x0160b400,
0xb44056d0,
0x56d00260,
0x0360b480,
0xb7c056d0,
0x98040050,
0x56d01b06,
0x1c069800,
0xf44056d0,
0x00f81030,
/* 0x029c: cmd_exec_set_surface_tiled */
0xc7075798,
0x78c76879,
0x0380b664,
0xb06077c7,
0x1bf40e76,
0x0477f009,
/* 0x02b7: xtile64 */
0xf00f0ef4,
0x70b6027c,
0x0947fd11,
/* 0x02c3: xtileok */
0x980677f0,
0x5b980c5a,
0x00abfd0e,
0xbb01b7f0,
0xb2b604b7,
0xc4abff01,
0x9805a7bb,
0xe7f00d5d,
0x04e8bb01,
0xff01e2b6,
0xd8bbb4de,
0x01e0b605,
0xbb0cef94,
0xfefd02eb,
0x026cf005,
0x020860b7,
0xd00864b6,
0xb7bb006f,
0x00cbbb04,
0x98085f98,
0xfbfd0e5b,
0x01b7f000,
0xb604b7bb,
0xfbbb01b2,
0x05f7bb00,
0x5f98f0f9,
0x01b7f009,
0xb604b8bb,
0xfbbb01b2,
0x05f8bb00,
0x78bbf0f9,
0x0282b600,
0xbb01b7f0,
0xb9bb04b8,
0x0b589804,
0xbb01e7f0,
0xe2b604e9,
0xf48eff01,
0xbb04f7bb,
0x79bb00cf,
0x0589bb00,
0x90fcf0fc,
0xbb00d9fd,
0x89fd00ad,
0x008ffd00,
0xbb00a8bb,
0x92b604a7,
0x0497bb01,
0x988069d0,
0x58980557,
0x00acbb04,
0xb6007abb,
0x84b60081,
0x058bfd10,
0x060062b7,
0xb70067d0,
0xd0040060,
0x00f80068,
/* 0x03a8: cmd_exec_set_surface_linear */
0xb7026cf0,
0xb6020260,
0x57980864,
0x0067d005,
0x040060b7,
0xb6045798,
0x67d01074,
0x0060b700,
0x06579804,
0xf80067d0,
/* 0x03d1: cmd_exec_wait */
0xf900f900,
0x0007f110,
0x0604b608,
/* 0x03dc: loop */
0xf00001cf,
0x1bf40114,
0xfc10fcfa,
/* 0x03eb: cmd_exec_query */
0xc800f800,
0x1bf40d34,
0xd121f570,
0x0c47f103,
0x0644b608,
0xb6020598,
0x45d00450,
0x4040d000,
0xd00c57f0,
0x40b78045,
0x05980400,
0x1054b601,
0xb70045d0,
0xf1050040,
0xf00b0057,
0x45d00153,
0x4057f100,
0x0154b640,
0x808053f1,
0xf14045d0,
0xf1111057,
0xd0131253,
0x57f18045,
0x53f11514,
0x45d01716,
0x0157f1c0,
0x0153f026,
0x080047f1,
0xd00644b6,
/* 0x045e: query_counter */
0x21f50045,
0x47f103d1,
0x44b6080c,
0x02059806,
0xd00045d0,
0x57f04040,
0x8045d004,
0x040040b7,
0xb6010598,
0x45d01054,
0x0040b700,
0x0057f105,
0x0045d003,
0x111057f1,
0x131253f1,
0x984045d0,
0x40b70305,
0x45d00500,
0x0157f100,
0x0153f026,
0x080047f1,
0xd00644b6,
0x00f80045,
/* 0x04b8: cmd_exec */
0x03d121f5,
0xf4003fc8,
0x21f50e0b,
0x47f101af,
0x0ef40200,
/* 0x04cd: cmd_exec_no_format */
0x1067f11e,
0x0664b608,
0x800177f0,
0x07800e07,
0x1d079819,
0xd00067d0,
0x44bd4067,
/* 0x04e8: cmd_exec_init_src_surface */
0xbd0232f4,
0x043fc854,
0xf50a0bf4,
0xf403a821,
/* 0x04fa: src_tiled */
0x21f50a0e,
0x49f0029c,
/* 0x0501: cmd_exec_init_dst_surface */
0x0231f407,
0xc82c57f0,
0x0bf4083f,
0xa821f50a,
0x0a0ef403,
/* 0x0514: dst_tiled */
0x029c21f5,
/* 0x051b: cmd_exec_kick */
0xf10849f0,
0xb6080057,
0x06980654,
0x4056d01e,
0xf14167f0,
0xfd440063,
0x54d00546,
0x0c3fc800,
0xf5070bf4,
/* 0x053f: cmd_exec_done */
0xf803eb21,
/* 0x0541: cmd_wrcache_flush */
0x0027f100,
0xf034bd22,
0x23d00133,
0x0000f800,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};

View file

@ -0,0 +1,156 @@
/*
* 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/falcon.h>
#include <engine/fifo.h>
#include <engine/copy.h>
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <core/client.h>
#include <core/enum.h>
#include "fuc/nva3.fuc.h"
struct nva3_copy_priv {
struct nouveau_falcon base;
};
/*******************************************************************************
* Copy object classes
******************************************************************************/
static struct nouveau_oclass
nva3_copy_sclass[] = {
{ 0x85b5, &nouveau_object_ofuncs },
{}
};
/*******************************************************************************
* PCOPY context
******************************************************************************/
static struct nouveau_oclass
nva3_copy_cclass = {
.handle = NV_ENGCTX(COPY0, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_falcon_context_init,
.fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_falcon_context_wr32,
},
};
/*******************************************************************************
* PCOPY engine/subdev functions
******************************************************************************/
static const struct nouveau_enum nva3_copy_isr_error_name[] = {
{ 0x0001, "ILLEGAL_MTHD" },
{ 0x0002, "INVALID_ENUM" },
{ 0x0003, "INVALID_BITFIELD" },
{}
};
void
nva3_copy_intr(struct nouveau_subdev *subdev)
{
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
struct nouveau_engine *engine = nv_engine(subdev);
struct nouveau_falcon *falcon = (void *)subdev;
struct nouveau_object *engctx;
u32 dispatch = nv_ro32(falcon, 0x01c);
u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff;
u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff;
u32 addr = nv_ro32(falcon, 0x040) >> 16;
u32 mthd = (addr & 0x07ff) << 2;
u32 subc = (addr & 0x3800) >> 11;
u32 data = nv_ro32(falcon, 0x044);
int chid;
engctx = nouveau_engctx_get(engine, inst);
chid = pfifo->chid(pfifo, engctx);
if (stat & 0x00000040) {
nv_error(falcon, "DISPATCH_ERROR [");
nouveau_enum_print(nva3_copy_isr_error_name, ssta);
pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
chid, inst << 12, nouveau_client_name(engctx), subc,
mthd, data);
nv_wo32(falcon, 0x004, 0x00000040);
stat &= ~0x00000040;
}
if (stat) {
nv_error(falcon, "unhandled intr 0x%08x\n", stat);
nv_wo32(falcon, 0x004, stat);
}
nouveau_engctx_put(engctx);
}
static int
nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
bool enable = (nv_device(parent)->chipset != 0xaf);
struct nva3_copy_priv *priv;
int ret;
ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, enable,
"PCE0", "copy0", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00802000;
nv_subdev(priv)->intr = nva3_copy_intr;
nv_engine(priv)->cclass = &nva3_copy_cclass;
nv_engine(priv)->sclass = nva3_copy_sclass;
nv_falcon(priv)->code.data = nva3_pcopy_code;
nv_falcon(priv)->code.size = sizeof(nva3_pcopy_code);
nv_falcon(priv)->data.data = nva3_pcopy_data;
nv_falcon(priv)->data.size = sizeof(nva3_pcopy_data);
return 0;
}
struct nouveau_oclass
nva3_copy_oclass = {
.handle = NV_ENGINE(COPY0, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nva3_copy_ctor,
.dtor = _nouveau_falcon_dtor,
.init = _nouveau_falcon_init,
.fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
},
};

View file

@ -0,0 +1,172 @@
/*
* 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/falcon.h>
#include <engine/fifo.h>
#include <engine/copy.h>
#include <core/enum.h>
#include <core/enum.h>
#include "fuc/nvc0.fuc.h"
struct nvc0_copy_priv {
struct nouveau_falcon base;
};
/*******************************************************************************
* Copy object classes
******************************************************************************/
static struct nouveau_oclass
nvc0_copy0_sclass[] = {
{ 0x90b5, &nouveau_object_ofuncs },
{},
};
static struct nouveau_oclass
nvc0_copy1_sclass[] = {
{ 0x90b8, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PCOPY context
******************************************************************************/
static struct nouveau_ofuncs
nvc0_copy_context_ofuncs = {
.ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_falcon_context_init,
.fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_falcon_context_wr32,
};
static struct nouveau_oclass
nvc0_copy0_cclass = {
.handle = NV_ENGCTX(COPY0, 0xc0),
.ofuncs = &nvc0_copy_context_ofuncs,
};
static struct nouveau_oclass
nvc0_copy1_cclass = {
.handle = NV_ENGCTX(COPY1, 0xc0),
.ofuncs = &nvc0_copy_context_ofuncs,
};
/*******************************************************************************
* PCOPY engine/subdev functions
******************************************************************************/
static int
nvc0_copy_init(struct nouveau_object *object)
{
struct nvc0_copy_priv *priv = (void *)object;
int ret;
ret = nouveau_falcon_init(&priv->base);
if (ret)
return ret;
nv_wo32(priv, 0x084, nv_engidx(object) - NVDEV_ENGINE_COPY0);
return 0;
}
static int
nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_copy_priv *priv;
int ret;
ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, true,
"PCE0", "copy0", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000040;
nv_subdev(priv)->intr = nva3_copy_intr;
nv_engine(priv)->cclass = &nvc0_copy0_cclass;
nv_engine(priv)->sclass = nvc0_copy0_sclass;
nv_falcon(priv)->code.data = nvc0_pcopy_code;
nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
nv_falcon(priv)->data.data = nvc0_pcopy_data;
nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
return 0;
}
static int
nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_copy_priv *priv;
int ret;
ret = nouveau_falcon_create(parent, engine, oclass, 0x105000, true,
"PCE1", "copy1", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000080;
nv_subdev(priv)->intr = nva3_copy_intr;
nv_engine(priv)->cclass = &nvc0_copy1_cclass;
nv_engine(priv)->sclass = nvc0_copy1_sclass;
nv_falcon(priv)->code.data = nvc0_pcopy_code;
nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
nv_falcon(priv)->data.data = nvc0_pcopy_data;
nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
return 0;
}
struct nouveau_oclass
nvc0_copy0_oclass = {
.handle = NV_ENGINE(COPY0, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_copy0_ctor,
.dtor = _nouveau_falcon_dtor,
.init = nvc0_copy_init,
.fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
},
};
struct nouveau_oclass
nvc0_copy1_oclass = {
.handle = NV_ENGINE(COPY1, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_copy1_ctor,
.dtor = _nouveau_falcon_dtor,
.init = nvc0_copy_init,
.fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
},
};

View file

@ -0,0 +1,176 @@
/*
* 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/enum.h>
#include <core/engctx.h>
#include <engine/copy.h>
struct nve0_copy_priv {
struct nouveau_engine base;
};
/*******************************************************************************
* Copy object classes
******************************************************************************/
static struct nouveau_oclass
nve0_copy_sclass[] = {
{ 0xa0b5, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PCOPY context
******************************************************************************/
static struct nouveau_ofuncs
nve0_copy_context_ofuncs = {
.ctor = _nouveau_engctx_ctor,
.dtor = _nouveau_engctx_dtor,
.init = _nouveau_engctx_init,
.fini = _nouveau_engctx_fini,
.rd32 = _nouveau_engctx_rd32,
.wr32 = _nouveau_engctx_wr32,
};
static struct nouveau_oclass
nve0_copy_cclass = {
.handle = NV_ENGCTX(COPY0, 0xc0),
.ofuncs = &nve0_copy_context_ofuncs,
};
/*******************************************************************************
* PCOPY engine/subdev functions
******************************************************************************/
static void
nve0_copy_intr(struct nouveau_subdev *subdev)
{
const int ce = nv_subidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
struct nve0_copy_priv *priv = (void *)subdev;
u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
if (stat) {
nv_warn(priv, "unhandled intr 0x%08x\n", stat);
nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
}
}
static int
nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nve0_copy_priv *priv;
int ret;
ret = nouveau_engine_create(parent, engine, oclass, true,
"PCE0", "copy0", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000040;
nv_subdev(priv)->intr = nve0_copy_intr;
nv_engine(priv)->cclass = &nve0_copy_cclass;
nv_engine(priv)->sclass = nve0_copy_sclass;
return 0;
}
static int
nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nve0_copy_priv *priv;
int ret;
ret = nouveau_engine_create(parent, engine, oclass, true,
"PCE1", "copy1", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000080;
nv_subdev(priv)->intr = nve0_copy_intr;
nv_engine(priv)->cclass = &nve0_copy_cclass;
nv_engine(priv)->sclass = nve0_copy_sclass;
return 0;
}
static int
nve0_copy2_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nve0_copy_priv *priv;
int ret;
ret = nouveau_engine_create(parent, engine, oclass, true,
"PCE2", "copy2", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00200000;
nv_subdev(priv)->intr = nve0_copy_intr;
nv_engine(priv)->cclass = &nve0_copy_cclass;
nv_engine(priv)->sclass = nve0_copy_sclass;
return 0;
}
struct nouveau_oclass
nve0_copy0_oclass = {
.handle = NV_ENGINE(COPY0, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_copy0_ctor,
.dtor = _nouveau_engine_dtor,
.init = _nouveau_engine_init,
.fini = _nouveau_engine_fini,
},
};
struct nouveau_oclass
nve0_copy1_oclass = {
.handle = NV_ENGINE(COPY1, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_copy1_ctor,
.dtor = _nouveau_engine_dtor,
.init = _nouveau_engine_init,
.fini = _nouveau_engine_fini,
},
};
struct nouveau_oclass
nve0_copy2_oclass = {
.handle = NV_ENGINE(COPY2, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_copy2_ctor,
.dtor = _nouveau_engine_dtor,
.init = _nouveau_engine_init,
.fini = _nouveau_engine_fini,
},
};

View file

@ -0,0 +1,698 @@
/*
* fuc microcode for nv98 pcrypt engine
* Copyright (C) 2010 Marcin Kościelnicki
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
.section #nv98_pcrypt_data
ctx_dma:
ctx_dma_query: .b32 0
ctx_dma_src: .b32 0
ctx_dma_dst: .b32 0
.equ #dma_count 3
ctx_query_address_high: .b32 0
ctx_query_address_low: .b32 0
ctx_query_counter: .b32 0
ctx_cond_address_high: .b32 0
ctx_cond_address_low: .b32 0
ctx_cond_off: .b32 0
ctx_src_address_high: .b32 0
ctx_src_address_low: .b32 0
ctx_dst_address_high: .b32 0
ctx_dst_address_low: .b32 0
ctx_mode: .b32 0
.align 16
ctx_key: .skip 16
ctx_iv: .skip 16
.align 0x80
swap:
.skip 32
.align 8
common_cmd_dtable:
.b32 #ctx_query_address_high + 0x20000 ~0xff
.b32 #ctx_query_address_low + 0x20000 ~0xfffffff0
.b32 #ctx_query_counter + 0x20000 ~0xffffffff
.b32 #cmd_query_get + 0x00000 ~1
.b32 #ctx_cond_address_high + 0x20000 ~0xff
.b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0
.b32 #cmd_cond_mode + 0x00000 ~7
.b32 #cmd_wrcache_flush + 0x00000 ~0
.equ #common_cmd_max 0x88
.align 8
engine_cmd_dtable:
.b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff
.b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff
.b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff
.b32 #ctx_key + 0xc + 0x20000 ~0xffffffff
.b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff
.b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff
.b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff
.b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff
.b32 #ctx_src_address_high + 0x20000 ~0xff
.b32 #ctx_src_address_low + 0x20000 ~0xfffffff0
.b32 #ctx_dst_address_high + 0x20000 ~0xff
.b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0
.b32 #crypt_cmd_mode + 0x00000 ~0xf
.b32 #crypt_cmd_length + 0x10000 ~0x0ffffff0
.equ #engine_cmd_max 0xce
.align 4
crypt_dtable:
.b16 #crypt_copy_prep #crypt_do_inout
.b16 #crypt_store_prep #crypt_do_out
.b16 #crypt_ecb_e_prep #crypt_do_inout
.b16 #crypt_ecb_d_prep #crypt_do_inout
.b16 #crypt_cbc_e_prep #crypt_do_inout
.b16 #crypt_cbc_d_prep #crypt_do_inout
.b16 #crypt_pcbc_e_prep #crypt_do_inout
.b16 #crypt_pcbc_d_prep #crypt_do_inout
.b16 #crypt_cfb_e_prep #crypt_do_inout
.b16 #crypt_cfb_d_prep #crypt_do_inout
.b16 #crypt_ofb_prep #crypt_do_inout
.b16 #crypt_ctr_prep #crypt_do_inout
.b16 #crypt_cbc_mac_prep #crypt_do_in
.b16 #crypt_cmac_finish_complete_prep #crypt_do_in
.b16 #crypt_cmac_finish_partial_prep #crypt_do_in
.align 0x100
.section #nv98_pcrypt_code
// $r0 is always set to 0 in our code - this allows some space savings.
clear b32 $r0
// set up the interrupt handler
mov $r1 #ih
mov $iv0 $r1
// init stack pointer
mov $sp $r0
// set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host
movw $r1 0xfff0
sethi $r1 0
mov $r2 0x400
iowr I[$r2 + 0x300] $r1
// enable the interrupts
or $r1 0xc
iowr I[$r2] $r1
// enable fifo access and context switching
mov $r1 3
mov $r2 0x1200
iowr I[$r2] $r1
// enable i0 delivery
bset $flags ie0
// sleep forver, waking only for interrupts.
bset $flags $p0
spin:
sleep $p0
bra #spin
// i0 handler
ih:
// see which interrupts we got
iord $r1 I[$r0 + 0x200]
and $r2 $r1 0x8
cmpu b32 $r2 0
bra e #noctx
// context switch... prepare the regs for xfer
mov $r2 0x7700
mov $xtargets $r2
mov $xdbase $r0
// 128-byte context.
mov $r2 0
sethi $r2 0x50000
// read current channel
mov $r3 0x1400
iord $r4 I[$r3]
// if bit 30 set, it's active, so we have to unload it first.
shl b32 $r5 $r4 1
cmps b32 $r5 0
bra nc #ctxload
// unload the current channel - save the context
xdst $r0 $r2
xdwait
// and clear bit 30, then write back
bclr $r4 0x1e
iowr I[$r3] $r4
// tell PFIFO we unloaded
mov $r4 1
iowr I[$r3 + 0x200] $r4
bra #noctx
ctxload:
// no channel loaded - perhaps we're requested to load one
iord $r4 I[$r3 + 0x100]
shl b32 $r15 $r4 1
cmps b32 $r15 0
// if bit 30 of next channel not set, probably PFIFO is just
// killing a context. do a faux load, without the active bit.
bra nc #dummyload
// ok, do a real context load.
xdld $r0 $r2
xdwait
mov $r5 #ctx_dma
mov $r6 #dma_count - 1
ctxload_dma_loop:
ld b32 $r7 D[$r5 + $r6 * 4]
add b32 $r8 $r6 0x180
shl b32 $r8 8
iowr I[$r8] $r7
sub b32 $r6 1
bra nc #ctxload_dma_loop
dummyload:
// tell PFIFO we're done
mov $r5 2
iowr I[$r3 + 0x200] $r5
noctx:
and $r2 $r1 0x4
cmpu b32 $r2 0
bra e #nocmd
// incoming fifo command.
mov $r3 0x1900
iord $r2 I[$r3 + 0x100]
iord $r3 I[$r3]
// extract the method
and $r4 $r2 0x7ff
// shift the addr to proper position if we need to interrupt later
shl b32 $r2 0x10
// mthd 0 and 0x100 [NAME, NOP]: ignore
and $r5 $r4 0x7bf
cmpu b32 $r5 0
bra e #cmddone
mov $r5 #engine_cmd_dtable - 0xc0 * 8
mov $r6 #engine_cmd_max
cmpu b32 $r4 0xc0
bra nc #dtable_cmd
mov $r5 #common_cmd_dtable - 0x80 * 8
mov $r6 #common_cmd_max
cmpu b32 $r4 0x80
bra nc #dtable_cmd
cmpu b32 $r4 0x60
bra nc #dma_cmd
cmpu b32 $r4 0x50
bra ne #illegal_mthd
// mthd 0x140: PM_TRIGGER
mov $r2 0x2200
clear b32 $r3
sethi $r3 0x20000
iowr I[$r2] $r3
bra #cmddone
dma_cmd:
// mthd 0x180...: DMA_*
cmpu b32 $r4 0x60+#dma_count
bra nc #illegal_mthd
shl b32 $r5 $r4 2
add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
bset $r3 0x1e
st b32 D[$r5] $r3
add b32 $r4 0x180 - 0x60
shl b32 $r4 8
iowr I[$r4] $r3
bra #cmddone
dtable_cmd:
cmpu b32 $r4 $r6
bra nc #illegal_mthd
shl b32 $r4 3
add b32 $r4 $r5
ld b32 $r5 D[$r4 + 4]
and $r5 $r3
cmpu b32 $r5 0
bra ne #invalid_bitfield
ld b16 $r5 D[$r4]
ld b16 $r6 D[$r4 + 2]
cmpu b32 $r6 2
bra e #cmd_setctx
ld b32 $r7 D[$r0 + #ctx_cond_off]
and $r6 $r7
cmpu b32 $r6 1
bra e #cmddone
call $r5
bra $p1 #dispatch_error
bra #cmddone
cmd_setctx:
st b32 D[$r5] $r3
bra #cmddone
invalid_bitfield:
or $r2 1
dispatch_error:
illegal_mthd:
mov $r4 0x1000
iowr I[$r4] $r2
iowr I[$r4 + 0x100] $r3
mov $r4 0x40
iowr I[$r0] $r4
im_loop:
iord $r4 I[$r0 + 0x200]
and $r4 0x40
cmpu b32 $r4 0
bra ne #im_loop
cmddone:
// remove the command from FIFO
mov $r3 0x1d00
mov $r4 1
iowr I[$r3] $r4
nocmd:
// ack the processed interrupts
and $r1 $r1 0xc
iowr I[$r0 + 0x100] $r1
iret
cmd_query_get:
// if bit 0 of param set, trigger interrupt afterwards.
setp $p1 $r3
or $r2 3
// read PTIMER, beware of races...
mov $r4 0xb00
ptimer_retry:
iord $r6 I[$r4 + 0x100]
iord $r5 I[$r4]
iord $r7 I[$r4 + 0x100]
cmpu b32 $r6 $r7
bra ne #ptimer_retry
// prepare the query structure
ld b32 $r4 D[$r0 + #ctx_query_counter]
st b32 D[$r0 + #swap + 0x0] $r4
st b32 D[$r0 + #swap + 0x4] $r0
st b32 D[$r0 + #swap + 0x8] $r5
st b32 D[$r0 + #swap + 0xc] $r6
// will use target 0, DMA_QUERY.
mov $xtargets $r0
ld b32 $r4 D[$r0 + #ctx_query_address_high]
shl b32 $r4 0x18
mov $xdbase $r4
ld b32 $r4 D[$r0 + #ctx_query_address_low]
mov $r5 #swap
sethi $r5 0x20000
xdst $r4 $r5
xdwait
ret
cmd_cond_mode:
// if >= 5, INVALID_ENUM
bset $flags $p1
or $r2 2
cmpu b32 $r3 5
bra nc #return
// otherwise, no error.
bclr $flags $p1
// if < 2, no QUERY object is involved
cmpu b32 $r3 2
bra nc #cmd_cond_mode_queryful
xor $r3 1
st b32 D[$r0 + #ctx_cond_off] $r3
return:
ret
cmd_cond_mode_queryful:
// ok, will need to pull a QUERY object, prepare offsets
ld b32 $r4 D[$r0 + #ctx_cond_address_high]
ld b32 $r5 D[$r0 + #ctx_cond_address_low]
and $r6 $r5 0xff
shr b32 $r5 8
shl b32 $r4 0x18
or $r4 $r5
mov $xdbase $r4
mov $xtargets $r0
// pull the first one
mov $r5 #swap
sethi $r5 0x20000
xdld $r6 $r5
// if == 2, only a single QUERY is involved...
cmpu b32 $r3 2
bra ne #cmd_cond_mode_double
xdwait
ld b32 $r4 D[$r0 + #swap + 4]
cmpu b32 $r4 0
xbit $r4 $flags z
st b32 D[$r0 + #ctx_cond_off] $r4
ret
// ok, we'll need to pull second one too
cmd_cond_mode_double:
add b32 $r6 0x10
add b32 $r5 0x10
xdld $r6 $r5
xdwait
// compare COUNTERs
ld b32 $r5 D[$r0 + #swap + 0x00]
ld b32 $r6 D[$r0 + #swap + 0x10]
cmpu b32 $r5 $r6
xbit $r4 $flags z
// compare RESen
ld b32 $r5 D[$r0 + #swap + 0x04]
ld b32 $r6 D[$r0 + #swap + 0x14]
cmpu b32 $r5 $r6
xbit $r5 $flags z
and $r4 $r5
// and negate or not, depending on mode
cmpu b32 $r3 3
xbit $r5 $flags z
xor $r4 $r5
st b32 D[$r0 + #ctx_cond_off] $r4
ret
cmd_wrcache_flush:
bclr $flags $p1
mov $r2 0x2200
clear b32 $r3
sethi $r3 0x10000
iowr I[$r2] $r3
ret
crypt_cmd_mode:
// if >= 0xf, INVALID_ENUM
bset $flags $p1
or $r2 2
cmpu b32 $r3 0xf
bra nc #crypt_cmd_mode_return
bclr $flags $p1
st b32 D[$r0 + #ctx_mode] $r3
crypt_cmd_mode_return:
ret
crypt_cmd_length:
// nop if length == 0
cmpu b32 $r3 0
bra e #crypt_cmd_mode_return
// init key, IV
cxset 3
mov $r4 #ctx_key
sethi $r4 0x70000
xdst $r0 $r4
mov $r4 #ctx_iv
sethi $r4 0x60000
xdst $r0 $r4
xdwait
ckeyreg $c7
// prepare the targets
mov $r4 0x2100
mov $xtargets $r4
// prepare src address
ld b32 $r4 D[$r0 + #ctx_src_address_high]
ld b32 $r5 D[$r0 + #ctx_src_address_low]
shr b32 $r8 $r5 8
shl b32 $r4 0x18
or $r4 $r8
and $r5 $r5 0xff
// prepare dst address
ld b32 $r6 D[$r0 + #ctx_dst_address_high]
ld b32 $r7 D[$r0 + #ctx_dst_address_low]
shr b32 $r8 $r7 8
shl b32 $r6 0x18
or $r6 $r8
and $r7 $r7 0xff
// find the proper prep & do functions
ld b32 $r8 D[$r0 + #ctx_mode]
shl b32 $r8 2
// run prep
ld b16 $r9 D[$r8 + #crypt_dtable]
call $r9
// do it
ld b16 $r9 D[$r8 + #crypt_dtable + 2]
call $r9
cxset 1
xdwait
cxset 0x61
xdwait
xdwait
// update src address
shr b32 $r8 $r4 0x18
shl b32 $r9 $r4 8
add b32 $r9 $r5
adc b32 $r8 0
st b32 D[$r0 + #ctx_src_address_high] $r8
st b32 D[$r0 + #ctx_src_address_low] $r9
// update dst address
shr b32 $r8 $r6 0x18
shl b32 $r9 $r6 8
add b32 $r9 $r7
adc b32 $r8 0
st b32 D[$r0 + #ctx_dst_address_high] $r8
st b32 D[$r0 + #ctx_dst_address_low] $r9
// pull updated IV
cxset 2
mov $r4 #ctx_iv
sethi $r4 0x60000
xdld $r0 $r4
xdwait
ret
crypt_copy_prep:
cs0begin 2
cxsin $c0
cxsout $c0
ret
crypt_store_prep:
cs0begin 1
cxsout $c6
ret
crypt_ecb_e_prep:
cs0begin 3
cxsin $c0
cenc $c0 $c0
cxsout $c0
ret
crypt_ecb_d_prep:
ckexp $c7 $c7
cs0begin 3
cxsin $c0
cdec $c0 $c0
cxsout $c0
ret
crypt_cbc_e_prep:
cs0begin 4
cxsin $c0
cxor $c6 $c0
cenc $c6 $c6
cxsout $c6
ret
crypt_cbc_d_prep:
ckexp $c7 $c7
cs0begin 5
cmov $c2 $c6
cxsin $c6
cdec $c0 $c6
cxor $c0 $c2
cxsout $c0
ret
crypt_pcbc_e_prep:
cs0begin 5
cxsin $c0
cxor $c6 $c0
cenc $c6 $c6
cxsout $c6
cxor $c6 $c0
ret
crypt_pcbc_d_prep:
ckexp $c7 $c7
cs0begin 5
cxsin $c0
cdec $c1 $c0
cxor $c6 $c1
cxsout $c6
cxor $c6 $c0
ret
crypt_cfb_e_prep:
cs0begin 4
cenc $c6 $c6
cxsin $c0
cxor $c6 $c0
cxsout $c6
ret
crypt_cfb_d_prep:
cs0begin 4
cenc $c0 $c6
cxsin $c6
cxor $c0 $c6
cxsout $c0
ret
crypt_ofb_prep:
cs0begin 4
cenc $c6 $c6
cxsin $c0
cxor $c0 $c6
cxsout $c0
ret
crypt_ctr_prep:
cs0begin 5
cenc $c1 $c6
cadd $c6 1
cxsin $c0
cxor $c0 $c1
cxsout $c0
ret
crypt_cbc_mac_prep:
cs0begin 3
cxsin $c0
cxor $c6 $c0
cenc $c6 $c6
ret
crypt_cmac_finish_complete_prep:
cs0begin 7
cxsin $c0
cxor $c6 $c0
cxor $c0 $c0
cenc $c0 $c0
cprecmac $c0 $c0
cxor $c6 $c0
cenc $c6 $c6
ret
crypt_cmac_finish_partial_prep:
cs0begin 8
cxsin $c0
cxor $c6 $c0
cxor $c0 $c0
cenc $c0 $c0
cprecmac $c0 $c0
cprecmac $c0 $c0
cxor $c6 $c0
cenc $c6 $c6
ret
// TODO
crypt_do_in:
add b32 $r3 $r5
mov $xdbase $r4
mov $r9 #swap
sethi $r9 0x20000
crypt_do_in_loop:
xdld $r5 $r9
xdwait
cxset 0x22
xdst $r0 $r9
cs0exec 1
xdwait
add b32 $r5 0x10
cmpu b32 $r5 $r3
bra ne #crypt_do_in_loop
cxset 1
xdwait
ret
crypt_do_out:
add b32 $r3 $r7
mov $xdbase $r6
mov $r9 #swap
sethi $r9 0x20000
crypt_do_out_loop:
cs0exec 1
cxset 0x61
xdld $r7 $r9
xdst $r7 $r9
cxset 1
xdwait
add b32 $r7 0x10
cmpu b32 $r7 $r3
bra ne #crypt_do_out_loop
ret
crypt_do_inout:
add b32 $r3 $r5
mov $r9 #swap
sethi $r9 0x20000
crypt_do_inout_loop:
mov $xdbase $r4
xdld $r5 $r9
xdwait
cxset 0x21
xdst $r0 $r9
cs0exec 1
cxset 0x61
mov $xdbase $r6
xdld $r7 $r9
xdst $r7 $r9
cxset 1
xdwait
add b32 $r5 0x10
add b32 $r7 0x10
cmpu b32 $r5 $r3
bra ne #crypt_do_inout_loop
ret
.align 0x100

View file

@ -0,0 +1,584 @@
uint32_t nv98_pcrypt_data[] = {
/* 0x0000: ctx_dma */
/* 0x0000: ctx_dma_query */
0x00000000,
/* 0x0004: ctx_dma_src */
0x00000000,
/* 0x0008: ctx_dma_dst */
0x00000000,
/* 0x000c: ctx_query_address_high */
0x00000000,
/* 0x0010: ctx_query_address_low */
0x00000000,
/* 0x0014: ctx_query_counter */
0x00000000,
/* 0x0018: ctx_cond_address_high */
0x00000000,
/* 0x001c: ctx_cond_address_low */
0x00000000,
/* 0x0020: ctx_cond_off */
0x00000000,
/* 0x0024: ctx_src_address_high */
0x00000000,
/* 0x0028: ctx_src_address_low */
0x00000000,
/* 0x002c: ctx_dst_address_high */
0x00000000,
/* 0x0030: ctx_dst_address_low */
0x00000000,
/* 0x0034: ctx_mode */
0x00000000,
0x00000000,
0x00000000,
/* 0x0040: ctx_key */
0x00000000,
0x00000000,
0x00000000,
0x00000000,
/* 0x0050: ctx_iv */
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
/* 0x0080: swap */
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
/* 0x00a0: common_cmd_dtable */
0x0002000c,
0xffffff00,
0x00020010,
0x0000000f,
0x00020014,
0x00000000,
0x00000192,
0xfffffffe,
0x00020018,
0xffffff00,
0x0002001c,
0x0000000f,
0x000001d7,
0xfffffff8,
0x00000260,
0xffffffff,
/* 0x00e0: engine_cmd_dtable */
0x00020040,
0x00000000,
0x00020044,
0x00000000,
0x00020048,
0x00000000,
0x0002004c,
0x00000000,
0x00020050,
0x00000000,
0x00020054,
0x00000000,
0x00020058,
0x00000000,
0x0002005c,
0x00000000,
0x00020024,
0xffffff00,
0x00020028,
0x0000000f,
0x0002002c,
0xffffff00,
0x00020030,
0x0000000f,
0x00000271,
0xfffffff0,
0x00010285,
0xf000000f,
/* 0x0150: crypt_dtable */
0x04db0321,
0x04b1032f,
0x04db0339,
0x04db034b,
0x04db0361,
0x04db0377,
0x04db0395,
0x04db03af,
0x04db03cd,
0x04db03e3,
0x04db03f9,
0x04db040f,
0x04830429,
0x0483043b,
0x0483045d,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
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 nv98_pcrypt_code[] = {
0x17f004bd,
0x0010fe35,
0xf10004fe,
0xf0fff017,
0x27f10013,
0x21d00400,
0x0c15f0c0,
0xf00021d0,
0x27f10317,
0x21d01200,
0x1031f400,
/* 0x002f: spin */
0xf40031f4,
0x0ef40028,
/* 0x0035: ih */
0x8001cffd,
0xb00812c4,
0x0bf40024,
0x0027f167,
0x002bfe77,
0xf00007fe,
0x23f00027,
0x0037f105,
0x0034cf14,
0xb0014594,
0x18f40055,
0x0602fa17,
0x4af003f8,
0x0034d01e,
0xd00147f0,
0x0ef48034,
/* 0x0075: ctxload */
0x4034cf33,
0xb0014f94,
0x18f400f5,
0x0502fa21,
0x57f003f8,
0x0267f000,
/* 0x008c: ctxload_dma_loop */
0xa07856bc,
0xb6018068,
0x87d00884,
0x0162b600,
/* 0x009f: dummyload */
0xf0f018f4,
0x35d00257,
/* 0x00a5: noctx */
0x0412c480,
0xf50024b0,
0xf100df0b,
0xcf190037,
0x33cf4032,
0xff24e400,
0x1024b607,
0x07bf45e4,
0xf50054b0,
0xf100b90b,
0xf1fae057,
0xb000ce67,
0x18f4c044,
0xa057f14d,
0x8867f1fc,
0x8044b000,
0xb03f18f4,
0x18f46044,
0x5044b019,
0xf1741bf4,
0xbd220027,
0x0233f034,
0xf50023d0,
/* 0x0103: dma_cmd */
0xb000810e,
0x18f46344,
0x0245945e,
0xfe8050b7,
0x801e39f0,
0x40b70053,
0x44b60120,
0x0043d008,
/* 0x0123: dtable_cmd */
0xb8600ef4,
0x18f40446,
0x0344b63e,
0x980045bb,
0x53fd0145,
0x0054b004,
0x58291bf4,
0x46580045,
0x0264b001,
0x98170bf4,
0x67fd0807,
0x0164b004,
0xf9300bf4,
0x0f01f455,
/* 0x015b: cmd_setctx */
0x80280ef4,
0x0ef40053,
/* 0x0161: invalid_bitfield */
0x0125f022,
/* 0x0164: dispatch_error */
/* 0x0164: illegal_mthd */
0x100047f1,
0xd00042d0,
0x47f04043,
0x0004d040,
/* 0x0174: im_loop */
0xf08004cf,
0x44b04044,
0xf71bf400,
/* 0x0180: cmddone */
0x1d0037f1,
0xd00147f0,
/* 0x018a: nocmd */
0x11c40034,
0x4001d00c,
/* 0x0192: cmd_query_get */
0x38f201f8,
0x0325f001,
0x0b0047f1,
/* 0x019c: ptimer_retry */
0xcf4046cf,
0x47cf0045,
0x0467b840,
0x98f41bf4,
0x04800504,
0x21008020,
0x80220580,
0x0bfe2306,
0x03049800,
0xfe1844b6,
0x04980047,
0x8057f104,
0x0253f000,
0xf80645fa,
/* 0x01d7: cmd_cond_mode */
0xf400f803,
0x25f00131,
0x0534b002,
0xf41218f4,
0x34b00132,
0x0b18f402,
0x800136f0,
/* 0x01f2: return */
0x00f80803,
/* 0x01f4: cmd_cond_mode_queryful */
0x98060498,
0x56c40705,
0x0855b6ff,
0xfd1844b6,
0x47fe0545,
0x000bfe00,
0x008057f1,
0xfa0253f0,
0x34b00565,
0x131bf402,
0x049803f8,
0x0044b021,
0x800b4cf0,
0x00f80804,
/* 0x022c: cmd_cond_mode_double */
0xb61060b6,
0x65fa1050,
0x9803f805,
0x06982005,
0x0456b824,
0x980b4cf0,
0x06982105,
0x0456b825,
0xfd0b5cf0,
0x34b00445,
0x0b5cf003,
0x800645fd,
0x00f80804,
/* 0x0260: cmd_wrcache_flush */
0xf10132f4,
0xbd220027,
0x0133f034,
0xf80023d0,
/* 0x0271: crypt_cmd_mode */
0x0131f400,
0xb00225f0,
0x18f40f34,
0x0132f409,
/* 0x0283: crypt_cmd_mode_return */
0xf80d0380,
/* 0x0285: crypt_cmd_length */
0x0034b000,
0xf4fb0bf4,
0x47f0033c,
0x0743f040,
0xf00604fa,
0x43f05047,
0x0604fa06,
0x3cf503f8,
0x47f1c407,
0x4bfe2100,
0x09049800,
0x950a0598,
0x44b60858,
0x0548fd18,
0x98ff55c4,
0x07980b06,
0x0878950c,
0xfd1864b6,
0x77c40568,
0x0d0898ff,
0x580284b6,
0x95f9a889,
0xf9a98958,
0x013cf495,
0x3cf403f8,
0xf803f861,
0x18489503,
0xbb084994,
0x81b60095,
0x09088000,
0x950a0980,
0x69941868,
0x0097bb08,
0x800081b6,
0x09800b08,
0x023cf40c,
0xf05047f0,
0x04fa0643,
0xf803f805,
/* 0x0321: crypt_copy_prep */
0x203cf500,
0x003cf594,
0x003cf588,
/* 0x032f: crypt_store_prep */
0xf500f88c,
0xf594103c,
0xf88c063c,
/* 0x0339: crypt_ecb_e_prep */
0x303cf500,
0x003cf594,
0x003cf588,
0x003cf5d0,
/* 0x034b: crypt_ecb_d_prep */
0xf500f88c,
0xf5c8773c,
0xf594303c,
0xf588003c,
0xf5d4003c,
0xf88c003c,
/* 0x0361: crypt_cbc_e_prep */
0x403cf500,
0x003cf594,
0x063cf588,
0x663cf5ac,
0x063cf5d0,
/* 0x0377: crypt_cbc_d_prep */
0xf500f88c,
0xf5c8773c,
0xf594503c,
0xf584623c,
0xf588063c,
0xf5d4603c,
0xf5ac203c,
0xf88c003c,
/* 0x0395: crypt_pcbc_e_prep */
0x503cf500,
0x003cf594,
0x063cf588,
0x663cf5ac,
0x063cf5d0,
0x063cf58c,
/* 0x03af: crypt_pcbc_d_prep */
0xf500f8ac,
0xf5c8773c,
0xf594503c,
0xf588003c,
0xf5d4013c,
0xf5ac163c,
0xf58c063c,
0xf8ac063c,
/* 0x03cd: crypt_cfb_e_prep */
0x403cf500,
0x663cf594,
0x003cf5d0,
0x063cf588,
0x063cf5ac,
/* 0x03e3: crypt_cfb_d_prep */
0xf500f88c,
0xf594403c,
0xf5d0603c,
0xf588063c,
0xf5ac603c,
0xf88c003c,
/* 0x03f9: crypt_ofb_prep */
0x403cf500,
0x663cf594,
0x003cf5d0,
0x603cf588,
0x003cf5ac,
/* 0x040f: crypt_ctr_prep */
0xf500f88c,
0xf594503c,
0xf5d0613c,
0xf5b0163c,
0xf588003c,
0xf5ac103c,
0xf88c003c,
/* 0x0429: crypt_cbc_mac_prep */
0x303cf500,
0x003cf594,
0x063cf588,
0x663cf5ac,
/* 0x043b: crypt_cmac_finish_complete_prep */
0xf500f8d0,
0xf594703c,
0xf588003c,
0xf5ac063c,
0xf5ac003c,
0xf5d0003c,
0xf5bc003c,
0xf5ac063c,
0xf8d0663c,
/* 0x045d: crypt_cmac_finish_partial_prep */
0x803cf500,
0x003cf594,
0x063cf588,
0x003cf5ac,
0x003cf5ac,
0x003cf5d0,
0x003cf5bc,
0x063cf5bc,
0x663cf5ac,
/* 0x0483: crypt_do_in */
0xbb00f8d0,
0x47fe0035,
0x8097f100,
0x0293f000,
/* 0x0490: crypt_do_in_loop */
0xf80559fa,
0x223cf403,
0xf50609fa,
0xf898103c,
0x1050b603,
0xf40453b8,
0x3cf4e91b,
0xf803f801,
/* 0x04b1: crypt_do_out */
0x0037bb00,
0xf10067fe,
0xf0008097,
/* 0x04be: crypt_do_out_loop */
0x3cf50293,
0x3cf49810,
0x0579fa61,
0xf40679fa,
0x03f8013c,
0xb81070b6,
0x1bf40473,
/* 0x04db: crypt_do_inout */
0xbb00f8e8,
0x97f10035,
0x93f00080,
/* 0x04e5: crypt_do_inout_loop */
0x0047fe02,
0xf80559fa,
0x213cf403,
0xf50609fa,
0xf498103c,
0x67fe613c,
0x0579fa00,
0xf40679fa,
0x03f8013c,
0xb61050b6,
0x53b81070,
0xd41bf404,
0x000000f8,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};

View file

@ -0,0 +1,188 @@
/*
* 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/client.h>
#include <core/os.h>
#include <core/enum.h>
#include <core/engctx.h>
#include <core/gpuobj.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include <engine/crypt.h>
struct nv84_crypt_priv {
struct nouveau_engine base;
};
/*******************************************************************************
* Crypt object classes
******************************************************************************/
static int
nv84_crypt_object_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_gpuobj *obj;
int ret;
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
16, 16, 0, &obj);
*pobject = nv_object(obj);
if (ret)
return ret;
nv_wo32(obj, 0x00, nv_mclass(obj));
nv_wo32(obj, 0x04, 0x00000000);
nv_wo32(obj, 0x08, 0x00000000);
nv_wo32(obj, 0x0c, 0x00000000);
return 0;
}
static struct nouveau_ofuncs
nv84_crypt_ofuncs = {
.ctor = nv84_crypt_object_ctor,
.dtor = _nouveau_gpuobj_dtor,
.init = _nouveau_gpuobj_init,
.fini = _nouveau_gpuobj_fini,
.rd32 = _nouveau_gpuobj_rd32,
.wr32 = _nouveau_gpuobj_wr32,
};
static struct nouveau_oclass
nv84_crypt_sclass[] = {
{ 0x74c1, &nv84_crypt_ofuncs },
{}
};
/*******************************************************************************
* PCRYPT context
******************************************************************************/
static struct nouveau_oclass
nv84_crypt_cclass = {
.handle = NV_ENGCTX(CRYPT, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_engctx_ctor,
.dtor = _nouveau_engctx_dtor,
.init = _nouveau_engctx_init,
.fini = _nouveau_engctx_fini,
.rd32 = _nouveau_engctx_rd32,
.wr32 = _nouveau_engctx_wr32,
},
};
/*******************************************************************************
* PCRYPT engine/subdev functions
******************************************************************************/
static const struct nouveau_bitfield nv84_crypt_intr_mask[] = {
{ 0x00000001, "INVALID_STATE" },
{ 0x00000002, "ILLEGAL_MTHD" },
{ 0x00000004, "ILLEGAL_CLASS" },
{ 0x00000080, "QUERY" },
{ 0x00000100, "FAULT" },
{}
};
static void
nv84_crypt_intr(struct nouveau_subdev *subdev)
{
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
struct nouveau_engine *engine = nv_engine(subdev);
struct nouveau_object *engctx;
struct nv84_crypt_priv *priv = (void *)subdev;
u32 stat = nv_rd32(priv, 0x102130);
u32 mthd = nv_rd32(priv, 0x102190);
u32 data = nv_rd32(priv, 0x102194);
u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
int chid;
engctx = nouveau_engctx_get(engine, inst);
chid = pfifo->chid(pfifo, engctx);
if (stat) {
nv_error(priv, "%s", "");
nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n",
chid, (u64)inst << 12, nouveau_client_name(engctx),
mthd, data);
}
nv_wr32(priv, 0x102130, stat);
nv_wr32(priv, 0x10200c, 0x10);
nouveau_engctx_put(engctx);
}
static int
nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv84_crypt_priv *priv;
int ret;
ret = nouveau_engine_create(parent, engine, oclass, true,
"PCRYPT", "crypt", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00004000;
nv_subdev(priv)->intr = nv84_crypt_intr;
nv_engine(priv)->cclass = &nv84_crypt_cclass;
nv_engine(priv)->sclass = nv84_crypt_sclass;
return 0;
}
static int
nv84_crypt_init(struct nouveau_object *object)
{
struct nv84_crypt_priv *priv = (void *)object;
int ret;
ret = nouveau_engine_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x102130, 0xffffffff);
nv_wr32(priv, 0x102140, 0xffffffbf);
nv_wr32(priv, 0x10200c, 0x00000010);
return 0;
}
struct nouveau_oclass
nv84_crypt_oclass = {
.handle = NV_ENGINE(CRYPT, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_crypt_ctor,
.dtor = _nouveau_engine_dtor,
.init = nv84_crypt_init,
.fini = _nouveau_engine_fini,
},
};

View file

@ -0,0 +1,156 @@
/*
* 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/client.h>
#include <core/os.h>
#include <core/enum.h>
#include <core/engctx.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/falcon.h>
#include <engine/fifo.h>
#include <engine/crypt.h>
#include "fuc/nv98.fuc.h"
struct nv98_crypt_priv {
struct nouveau_falcon base;
};
/*******************************************************************************
* Crypt object classes
******************************************************************************/
static struct nouveau_oclass
nv98_crypt_sclass[] = {
{ 0x88b4, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PCRYPT context
******************************************************************************/
static struct nouveau_oclass
nv98_crypt_cclass = {
.handle = NV_ENGCTX(CRYPT, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_falcon_context_init,
.fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_falcon_context_wr32,
},
};
/*******************************************************************************
* PCRYPT engine/subdev functions
******************************************************************************/
static const struct nouveau_enum nv98_crypt_isr_error_name[] = {
{ 0x0000, "ILLEGAL_MTHD" },
{ 0x0001, "INVALID_BITFIELD" },
{ 0x0002, "INVALID_ENUM" },
{ 0x0003, "QUERY" },
{}
};
static void
nv98_crypt_intr(struct nouveau_subdev *subdev)
{
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
struct nouveau_engine *engine = nv_engine(subdev);
struct nouveau_object *engctx;
struct nv98_crypt_priv *priv = (void *)subdev;
u32 disp = nv_rd32(priv, 0x08701c);
u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
u32 addr = nv_rd32(priv, 0x087040) >> 16;
u32 mthd = (addr & 0x07ff) << 2;
u32 subc = (addr & 0x3800) >> 11;
u32 data = nv_rd32(priv, 0x087044);
int chid;
engctx = nouveau_engctx_get(engine, inst);
chid = pfifo->chid(pfifo, engctx);
if (stat & 0x00000040) {
nv_error(priv, "DISPATCH_ERROR [");
nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
chid, (u64)inst << 12, nouveau_client_name(engctx),
subc, mthd, data);
nv_wr32(priv, 0x087004, 0x00000040);
stat &= ~0x00000040;
}
if (stat) {
nv_error(priv, "unhandled intr 0x%08x\n", stat);
nv_wr32(priv, 0x087004, stat);
}
nouveau_engctx_put(engctx);
}
static int
nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv98_crypt_priv *priv;
int ret;
ret = nouveau_falcon_create(parent, engine, oclass, 0x087000, true,
"PCRYPT", "crypt", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00004000;
nv_subdev(priv)->intr = nv98_crypt_intr;
nv_engine(priv)->cclass = &nv98_crypt_cclass;
nv_engine(priv)->sclass = nv98_crypt_sclass;
nv_falcon(priv)->code.data = nv98_pcrypt_code;
nv_falcon(priv)->code.size = sizeof(nv98_pcrypt_code);
nv_falcon(priv)->data.data = nv98_pcrypt_data;
nv_falcon(priv)->data.size = sizeof(nv98_pcrypt_data);
return 0;
}
struct nouveau_oclass
nv98_crypt_oclass = {
.handle = NV_ENGINE(CRYPT, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_crypt_ctor,
.dtor = _nouveau_falcon_dtor,
.init = _nouveau_falcon_init,
.fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
},
};

View file

@ -0,0 +1,59 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "acpi.h"
#ifdef CONFIG_ACPI
static int
nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
{
struct nouveau_device *device =
container_of(nb, typeof(*device), acpi.nb);
struct acpi_bus_event *info = data;
if (!strcmp(info->device_class, "ac_adapter"))
nvkm_event_send(&device->event, 1, 0, NULL, 0);
return NOTIFY_DONE;
}
#endif
int
nvkm_acpi_fini(struct nouveau_device *device, bool suspend)
{
#ifdef CONFIG_ACPI
unregister_acpi_notifier(&device->acpi.nb);
#endif
return 0;
}
int
nvkm_acpi_init(struct nouveau_device *device)
{
#ifdef CONFIG_ACPI
device->acpi.nb.notifier_call = nvkm_acpi_ntfy;
register_acpi_notifier(&device->acpi.nb);
#endif
return 0;
}

View file

@ -0,0 +1,9 @@
#ifndef __NVKM_DEVICE_ACPI_H__
#define __NVKM_DEVICE_ACPI_H__
#include <engine/device.h>
int nvkm_acpi_init(struct nouveau_device *);
int nvkm_acpi_fini(struct nouveau_device *, bool);
#endif

View file

@ -0,0 +1,705 @@
/*
* 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/object.h>
#include <core/device.h>
#include <core/client.h>
#include <core/option.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
#include "priv.h"
#include "acpi.h"
static DEFINE_MUTEX(nv_devices_mutex);
static LIST_HEAD(nv_devices);
struct nouveau_device *
nouveau_device_find(u64 name)
{
struct nouveau_device *device, *match = NULL;
mutex_lock(&nv_devices_mutex);
list_for_each_entry(device, &nv_devices, head) {
if (device->handle == name) {
match = device;
break;
}
}
mutex_unlock(&nv_devices_mutex);
return match;
}
int
nouveau_device_list(u64 *name, int size)
{
struct nouveau_device *device;
int nr = 0;
mutex_lock(&nv_devices_mutex);
list_for_each_entry(device, &nv_devices, head) {
if (nr++ < size)
name[nr - 1] = device->handle;
}
mutex_unlock(&nv_devices_mutex);
return nr;
}
/******************************************************************************
* nouveau_devobj (0x0080): class implementation
*****************************************************************************/
struct nouveau_devobj {
struct nouveau_parent base;
struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
};
static int
nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size)
{
struct nouveau_device *device = nv_device(object);
struct nouveau_fb *pfb = nouveau_fb(device);
struct nouveau_instmem *imem = nouveau_instmem(device);
union {
struct nv_device_info_v0 v0;
} *args = data;
int ret;
nv_ioctl(object, "device info size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "device info vers %d\n", args->v0.version);
} else
return ret;
switch (device->chipset) {
case 0x01a:
case 0x01f:
case 0x04c:
case 0x04e:
case 0x063:
case 0x067:
case 0x068:
case 0x0aa:
case 0x0ac:
case 0x0af:
args->v0.platform = NV_DEVICE_INFO_V0_IGP;
break;
default:
if (device->pdev) {
if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
args->v0.platform = NV_DEVICE_INFO_V0_AGP;
else
if (pci_is_pcie(device->pdev))
args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
else
args->v0.platform = NV_DEVICE_INFO_V0_PCI;
} else {
args->v0.platform = NV_DEVICE_INFO_V0_SOC;
}
break;
}
switch (device->card_type) {
case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
case NV_10:
case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
default:
args->v0.family = 0;
break;
}
args->v0.chipset = device->chipset;
args->v0.revision = device->chipset >= 0x10 ? nv_rd32(device, 0) : 0x00;
if (pfb) args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
else args->v0.ram_size = args->v0.ram_user = 0;
if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
return 0;
}
static int
nouveau_devobj_mthd(struct nouveau_object *object, u32 mthd,
void *data, u32 size)
{
switch (mthd) {
case NV_DEVICE_V0_INFO:
return nouveau_devobj_info(object, data, size);
default:
break;
}
return -EINVAL;
}
static u8
nouveau_devobj_rd08(struct nouveau_object *object, u64 addr)
{
return nv_rd08(object->engine, addr);
}
static u16
nouveau_devobj_rd16(struct nouveau_object *object, u64 addr)
{
return nv_rd16(object->engine, addr);
}
static u32
nouveau_devobj_rd32(struct nouveau_object *object, u64 addr)
{
return nv_rd32(object->engine, addr);
}
static void
nouveau_devobj_wr08(struct nouveau_object *object, u64 addr, u8 data)
{
nv_wr08(object->engine, addr, data);
}
static void
nouveau_devobj_wr16(struct nouveau_object *object, u64 addr, u16 data)
{
nv_wr16(object->engine, addr, data);
}
static void
nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
{
nv_wr32(object->engine, addr, data);
}
static int
nouveau_devobj_map(struct nouveau_object *object, u64 *addr, u32 *size)
{
struct nouveau_device *device = nv_device(object);
*addr = nv_device_resource_start(device, 0);
*size = nv_device_resource_len(device, 0);
return 0;
}
static const u64 disable_map[] = {
[NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS,
[NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_CLOCK] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_LTC] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_VM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO,
[NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO,
[NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GRAPH,
[NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG,
[NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME,
[NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP,
[NVDEV_ENGINE_CRYPT] = NV_DEVICE_V0_DISABLE_CRYPT,
[NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP,
[NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP,
[NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0,
[NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1,
[NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC,
[NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC,
[NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP,
[NVDEV_SUBDEV_NR] = 0,
};
static void
nouveau_devobj_dtor(struct nouveau_object *object)
{
struct nouveau_devobj *devobj = (void *)object;
int i;
for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
nouveau_object_ref(NULL, &devobj->subdev[i]);
nouveau_parent_destroy(&devobj->base);
}
static struct nouveau_oclass
nouveau_devobj_oclass_super = {
.handle = NV_DEVICE,
.ofuncs = &(struct nouveau_ofuncs) {
.dtor = nouveau_devobj_dtor,
.init = _nouveau_parent_init,
.fini = _nouveau_parent_fini,
.mthd = nouveau_devobj_mthd,
.map = nouveau_devobj_map,
.rd08 = nouveau_devobj_rd08,
.rd16 = nouveau_devobj_rd16,
.rd32 = nouveau_devobj_rd32,
.wr08 = nouveau_devobj_wr08,
.wr16 = nouveau_devobj_wr16,
.wr32 = nouveau_devobj_wr32,
}
};
static int
nouveau_devobj_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv_device_v0 v0;
} *args = data;
struct nouveau_client *client = nv_client(parent);
struct nouveau_device *device;
struct nouveau_devobj *devobj;
u32 boot0, strap;
u64 disable, mmio_base, mmio_size;
void __iomem *map;
int ret, i, c;
nv_ioctl(parent, "create device size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create device v%d device %016llx "
"disable %016llx debug0 %016llx\n",
args->v0.version, args->v0.device,
args->v0.disable, args->v0.debug0);
} else
return ret;
/* give priviledged clients register access */
if (client->super)
oclass = &nouveau_devobj_oclass_super;
/* find the device subdev that matches what the client requested */
device = nv_device(client->device);
if (args->v0.device != ~0) {
device = nouveau_device_find(args->v0.device);
if (!device)
return -ENODEV;
}
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) |
(1ULL << NVDEV_ENGINE_PERFMON), &devobj);
*pobject = nv_object(devobj);
if (ret)
return ret;
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->v0.debug0;
for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
if (args->v0.disable & disable_map[i])
disable |= (1ULL << i);
}
/* identify the chipset, and determine classes of subdev/engines */
if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) &&
!device->card_type) {
map = ioremap(mmio_base, 0x102000);
if (map == NULL)
return -ENOMEM;
/* switch mmio to cpu's native endianness */
#ifndef __BIG_ENDIAN
if (ioread32_native(map + 0x000004) != 0x00000000)
#else
if (ioread32_native(map + 0x000004) == 0x00000000)
#endif
iowrite32_native(0x01000001, map + 0x000004);
/* read boot0 and strapping information */
boot0 = ioread32_native(map + 0x000000);
strap = ioread32_native(map + 0x101000);
iounmap(map);
/* determine chipset and derive architecture from it */
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:
case 0x0d0: device->card_type = NV_C0; break;
case 0x0e0:
case 0x0f0:
case 0x100: device->card_type = NV_E0; break;
case 0x110: device->card_type = GM100; break;
default:
break;
}
} else
if ((boot0 & 0xff00fff0) == 0x20004000) {
if (boot0 & 0x00f00000)
device->chipset = 0x05;
else
device->chipset = 0x04;
device->card_type = NV_04;
}
switch (device->card_type) {
case NV_04: ret = nv04_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;
case NV_50: ret = nv50_identify(device); break;
case NV_C0: ret = nvc0_identify(device); break;
case NV_E0: ret = nve0_identify(device); break;
case GM100: ret = gm100_identify(device); break;
default:
ret = -EINVAL;
break;
}
if (ret) {
nv_error(device, "unknown chipset, 0x%08x\n", boot0);
return ret;
}
nv_info(device, "BOOT0 : 0x%08x\n", boot0);
nv_info(device, "Chipset: %s (NV%02X)\n",
device->cname, device->chipset);
nv_info(device, "Family : NV%02X\n", device->card_type);
/* determine frequency of timing crystal */
if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
(device->chipset >= 0x20 && device->chipset < 0x25))
strap &= 0x00000040;
else
strap &= 0x00400040;
switch (strap) {
case 0x00000000: device->crystal = 13500; break;
case 0x00000040: device->crystal = 14318; break;
case 0x00400000: device->crystal = 27000; break;
case 0x00400040: device->crystal = 25000; break;
}
nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
}
if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
!nv_subdev(device)->mmio) {
nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size);
if (!nv_subdev(device)->mmio) {
nv_error(device, "unable to map device registers\n");
return -ENOMEM;
}
}
/* ensure requested subsystems are available for use */
for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
continue;
if (device->subdev[i]) {
nouveau_object_ref(device->subdev[i],
&devobj->subdev[i]);
continue;
}
ret = nouveau_object_ctor(nv_object(device), NULL,
oclass, NULL, i,
&devobj->subdev[i]);
if (ret == -ENODEV)
continue;
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
* dependencies have been created.
*
* this code delays init of any subdev until all of devinit's
* dependencies have been created, and then initialises each
* subdev in turn as they're created.
*/
while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
struct nouveau_object *subdev = devobj->subdev[c++];
if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
ret = nouveau_object_inc(subdev);
if (ret)
return ret;
atomic_dec(&nv_object(device)->usecount);
} else
if (subdev) {
nouveau_subdev_reset(subdev);
}
}
}
return 0;
}
static struct nouveau_ofuncs
nouveau_devobj_ofuncs = {
.ctor = nouveau_devobj_ctor,
.dtor = nouveau_devobj_dtor,
.init = _nouveau_parent_init,
.fini = _nouveau_parent_fini,
.mthd = nouveau_devobj_mthd,
};
/******************************************************************************
* nouveau_device: engine functions
*****************************************************************************/
static struct nouveau_oclass
nouveau_device_sclass[] = {
{ 0x0080, &nouveau_devobj_ofuncs },
{}
};
static int
nouveau_device_event_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
if (!WARN_ON(size != 0)) {
notify->size = 0;
notify->types = 1;
notify->index = 0;
return 0;
}
return -EINVAL;
}
static const struct nvkm_event_func
nouveau_device_event_func = {
.ctor = nouveau_device_event_ctor,
};
static int
nouveau_device_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_device *device = (void *)object;
struct nouveau_object *subdev;
int ret, i;
for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
if ((subdev = device->subdev[i])) {
if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
ret = nouveau_object_dec(subdev, suspend);
if (ret && suspend)
goto fail;
}
}
}
ret = nvkm_acpi_fini(device, suspend);
fail:
for (; ret && i < NVDEV_SUBDEV_NR; i++) {
if ((subdev = device->subdev[i])) {
if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
ret = nouveau_object_inc(subdev);
if (ret) {
/* XXX */
}
}
}
}
return ret;
}
static int
nouveau_device_init(struct nouveau_object *object)
{
struct nouveau_device *device = (void *)object;
struct nouveau_object *subdev;
int ret, i = 0;
ret = nvkm_acpi_init(device);
if (ret)
goto fail;
for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
if ((subdev = device->subdev[i])) {
if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
ret = nouveau_object_inc(subdev);
if (ret)
goto fail;
} else {
nouveau_subdev_reset(subdev);
}
}
}
ret = 0;
fail:
for (--i; ret && i >= 0; i--) {
if ((subdev = device->subdev[i])) {
if (!nv_iclass(subdev, NV_ENGINE_CLASS))
nouveau_object_dec(subdev, false);
}
}
if (ret)
nvkm_acpi_fini(device, false);
return ret;
}
static void
nouveau_device_dtor(struct nouveau_object *object)
{
struct nouveau_device *device = (void *)object;
nvkm_event_fini(&device->event);
mutex_lock(&nv_devices_mutex);
list_del(&device->head);
mutex_unlock(&nv_devices_mutex);
if (nv_subdev(device)->mmio)
iounmap(nv_subdev(device)->mmio);
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);
}
}
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),
.ofuncs = &(struct nouveau_ofuncs) {
.dtor = nouveau_device_dtor,
.init = nouveau_device_init,
.fini = nouveau_device_fini,
},
};
int
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;
int ret = -EEXIST;
mutex_lock(&nv_devices_mutex);
list_for_each_entry(device, &nv_devices, head) {
if (device->handle == name)
goto done;
}
ret = nouveau_engine_create_(NULL, NULL, &nouveau_device_oclass, true,
"DEVICE", "device", length, pobject);
device = *pobject;
if (ret)
goto done;
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;
device->name = sname;
nv_subdev(device)->debug = nouveau_dbgopt(device->dbgopt, "DEVICE");
nv_engine(device)->sclass = nouveau_device_sclass;
list_add(&device->head, &nv_devices);
ret = nvkm_event_init(&nouveau_device_event_func, 1, 1,
&device->event);
done:
mutex_unlock(&nv_devices_mutex);
return ret;
}

View file

@ -0,0 +1,205 @@
/*
* 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/client.h>
#include <core/object.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <nvif/ioctl.h>
#include <subdev/clock.h>
#include "priv.h"
static int
nouveau_control_mthd_pstate_info(struct nouveau_object *object,
void *data, u32 size)
{
union {
struct nvif_control_pstate_info_v0 v0;
} *args = data;
struct nouveau_clock *clk = nouveau_clock(object);
int ret;
nv_ioctl(object, "control pstate info size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "control pstate info vers %d\n",
args->v0.version);
} else
return ret;
if (clk) {
args->v0.count = clk->state_nr;
args->v0.ustate_ac = clk->ustate_ac;
args->v0.ustate_dc = clk->ustate_dc;
args->v0.pwrsrc = clk->pwrsrc;
args->v0.pstate = clk->pstate;
} else {
args->v0.count = 0;
args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
args->v0.pwrsrc = -ENOSYS;
args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;
}
return 0;
}
static int
nouveau_control_mthd_pstate_attr(struct nouveau_object *object,
void *data, u32 size)
{
union {
struct nvif_control_pstate_attr_v0 v0;
} *args = data;
struct nouveau_clock *clk = nouveau_clock(object);
struct nouveau_clocks *domain;
struct nouveau_pstate *pstate;
struct nouveau_cstate *cstate;
int i = 0, j = -1;
u32 lo, hi;
int ret;
nv_ioctl(object, "control pstate attr size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "control pstate attr vers %d state %d "
"index %d\n",
args->v0.version, args->v0.state, args->v0.index);
if (!clk)
return -ENODEV;
if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT)
return -EINVAL;
if (args->v0.state >= clk->state_nr)
return -EINVAL;
} else
return ret;
domain = clk->domains;
while (domain->name != nv_clk_src_max) {
if (domain->mname && ++j == args->v0.index)
break;
domain++;
}
if (domain->name == nv_clk_src_max)
return -EINVAL;
if (args->v0.state != NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) {
list_for_each_entry(pstate, &clk->states, head) {
if (i++ == args->v0.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->v0.state = pstate->pstate;
} else {
lo = max(clk->read(clk, domain->name), 0);
hi = lo;
}
snprintf(args->v0.name, sizeof(args->v0.name), "%s", domain->mname);
snprintf(args->v0.unit, sizeof(args->v0.unit), "MHz");
args->v0.min = lo / domain->mdiv;
args->v0.max = hi / domain->mdiv;
args->v0.index = 0;
while ((++domain)->name != nv_clk_src_max) {
if (domain->mname) {
args->v0.index = ++j;
break;
}
}
return 0;
}
static int
nouveau_control_mthd_pstate_user(struct nouveau_object *object,
void *data, u32 size)
{
union {
struct nvif_control_pstate_user_v0 v0;
} *args = data;
struct nouveau_clock *clk = nouveau_clock(object);
int ret;
nv_ioctl(object, "control pstate user size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "control pstate user vers %d ustate %d "
"pwrsrc %d\n", args->v0.version,
args->v0.ustate, args->v0.pwrsrc);
if (!clk)
return -ENODEV;
} else
return ret;
if (args->v0.pwrsrc >= 0) {
ret |= nouveau_clock_ustate(clk, args->v0.ustate, args->v0.pwrsrc);
} else {
ret |= nouveau_clock_ustate(clk, args->v0.ustate, 0);
ret |= nouveau_clock_ustate(clk, args->v0.ustate, 1);
}
return ret;
}
static int
nouveau_control_mthd(struct nouveau_object *object, u32 mthd,
void *data, u32 size)
{
switch (mthd) {
case NVIF_CONTROL_PSTATE_INFO:
return nouveau_control_mthd_pstate_info(object, data, size);
case NVIF_CONTROL_PSTATE_ATTR:
return nouveau_control_mthd_pstate_attr(object, data, size);
case NVIF_CONTROL_PSTATE_USER:
return nouveau_control_mthd_pstate_user(object, data, size);
default:
break;
}
return -EINVAL;
}
static struct nouveau_ofuncs
nouveau_control_ofuncs = {
.ctor = _nouveau_object_ctor,
.dtor = nouveau_object_destroy,
.init = nouveau_object_init,
.fini = nouveau_object_fini,
.mthd = nouveau_control_mthd,
};
struct nouveau_oclass
nouveau_control_oclass[] = {
{ .handle = NVIF_IOCTL_NEW_V0_CONTROL,
.ofuncs = &nouveau_control_ofuncs
},
{}
};

View file

@ -0,0 +1,107 @@
/*
* 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/fuse.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/ltc.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_FUSE ] = &gm107_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
#if 0
device->oclass[NVDEV_SUBDEV_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;
}

View file

@ -0,0 +1,89 @@
/*
* 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/i2c.h>
#include <subdev/clock.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
#include <subdev/vm.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>
int
nv04_identify(struct nouveau_device *device)
{
switch (device->chipset) {
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_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_TIMER ] = &nv04_timer_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_GR ] = &nv04_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv04_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown RIVA chipset\n");
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,204 @@
/*
* 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/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
#include <subdev/vm.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>
int
nv10_identify(struct nouveau_device *device)
{
switch (device->chipset) {
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_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_TIMER ] = &nv04_timer_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;
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_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_TIMER ] = &nv04_timer_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_GR ] = &nv10_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv10_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv10_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv10_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv10_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv10_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown Celsius chipset\n");
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,131 @@
/*
* 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/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
#include <subdev/vm.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>
int
nv20_identify(struct nouveau_device *device)
{
switch (device->chipset) {
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_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_TIMER ] = &nv04_timer_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_GR ] = &nv20_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv25_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv25_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv2a_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown Kelvin chipset\n");
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,153 @@
/*
* 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/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
#include <subdev/vm.h>
#include <engine/device.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/mpeg.h>
#include <engine/disp.h>
int
nv30_identify(struct nouveau_device *device)
{
switch (device->chipset) {
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_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_TIMER ] = &nv04_timer_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_GR ] = &nv30_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv35_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv30_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv35_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv34_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown Rankine chipset\n");
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,427 @@
/*
* 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/vm.h>
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
#include <subdev/vm.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/mpeg.h>
#include <engine/disp.h>
#include <engine/perfmon.h>
int
nv40_identify(struct nouveau_device *device)
{
switch (device->chipset) {
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_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 ] = 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_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_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_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_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 ] = 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_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_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_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_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 ] = 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_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_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_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_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 ] = 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_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_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_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_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 ] = 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_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv40_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv40_graph_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_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_TIMER ] = &nv04_timer_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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_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 ] = 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_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_GR ] = &nv40_graph_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");
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,475 @@
/*
* 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/fuse.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/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/mpeg.h>
#include <engine/vp.h>
#include <engine/crypt.h>
#include <engine/bsp.h>
#include <engine/ppp.h>
#include <engine/copy.h>
#include <engine/disp.h>
#include <engine/perfmon.h>
int
nv50_identify(struct nouveau_device *device)
{
switch (device->chipset) {
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_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_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_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_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_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_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_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_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_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nv84_perfmon_oclass;
break;
case 0x94:
device->cname = "G94";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nv84_perfmon_oclass;
break;
case 0x96:
device->cname = "G96";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nv84_perfmon_oclass;
break;
case 0x98:
device->cname = "G98";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nv84_perfmon_oclass;
break;
case 0xa0:
device->cname = "G200";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nv84_perfmon_oclass;
break;
case 0xaa:
device->cname = "MCP77/MCP78";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nv84_perfmon_oclass;
break;
case 0xac:
device->cname = "MCP79/MCP7A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nv84_perfmon_oclass;
break;
case 0xa3:
device->cname = "GT215";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nva3_perfmon_oclass;
break;
case 0xa5:
device->cname = "GT216";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nva3_perfmon_oclass;
break;
case 0xa8:
device->cname = "GT218";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nva3_perfmon_oclass;
break;
case 0xaf:
device->cname = "MCP89";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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 ] = 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_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_PERFMON] = nva3_perfmon_oclass;
break;
default:
nv_fatal(device, "unknown Tesla chipset\n");
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,357 @@
/*
* 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/fuse.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/ltc.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/vp.h>
#include <engine/bsp.h>
#include <engine/ppp.h>
#include <engine/copy.h>
#include <engine/disp.h>
#include <engine/perfmon.h>
int
nvc0_identify(struct nouveau_device *device)
{
switch (device->chipset) {
case 0xc0:
device->cname = "GF100";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = 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_PERFMON] = &nvc0_perfmon_oclass;
break;
case 0xc4:
device->cname = "GF104";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = 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_PERFMON] = &nvc0_perfmon_oclass;
break;
case 0xc3:
device->cname = "GF106";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = 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_PERFMON] = &nvc0_perfmon_oclass;
break;
case 0xce:
device->cname = "GF114";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = 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_PERFMON] = &nvc0_perfmon_oclass;
break;
case 0xcf:
device->cname = "GF116";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = 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_PERFMON] = &nvc0_perfmon_oclass;
break;
case 0xc1:
device->cname = "GF108";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = 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_PERFMON] = &nvc0_perfmon_oclass;
break;
case 0xc8:
device->cname = "GF110";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = 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_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_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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_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_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 ] = gf117_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
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_LTC ] = gf100_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_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_PERFMON] = &nvc0_perfmon_oclass;
break;
default:
nv_fatal(device, "unknown Fermi chipset\n");
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,290 @@
/*
* 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/fuse.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/ltc.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
nve0_identify(struct nouveau_device *device)
{
switch (device->chipset) {
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 ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = gk104_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 ] = nve4_graph_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 ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = nve4_graph_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 ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = gk104_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 ] = nve4_graph_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_CLOCK ] = &gk20a_clock_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass;
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 ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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 ] = gk110b_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
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_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
device->oclass[NVDEV_SUBDEV_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;
device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
break;
default:
nv_fatal(device, "unknown Kepler chipset\n");
return -EINVAL;
}
return 0;
}

View file

@ -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

View file

@ -0,0 +1,242 @@
/*
* 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/os.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <nvif/event.h>
#include "priv.h"
#include "outp.h"
#include "conn.h"
int
nouveau_disp_vblank_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nouveau_disp *disp =
container_of(notify->event, typeof(*disp), vblank);
union {
struct nvif_notify_head_req_v0 v0;
} *req = data;
int ret;
if (nvif_unpack(req->v0, 0, 0, false)) {
notify->size = sizeof(struct nvif_notify_head_rep_v0);
if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
notify->types = 1;
notify->index = req->v0.head;
return 0;
}
}
return ret;
}
void
nouveau_disp_vblank(struct nouveau_disp *disp, int head)
{
struct nvif_notify_head_rep_v0 rep = {};
nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
}
static int
nouveau_disp_hpd_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nouveau_disp *disp =
container_of(notify->event, typeof(*disp), hpd);
union {
struct nvif_notify_conn_req_v0 v0;
} *req = data;
struct nvkm_output *outp;
int ret;
if (nvif_unpack(req->v0, 0, 0, false)) {
notify->size = sizeof(struct nvif_notify_conn_rep_v0);
list_for_each_entry(outp, &disp->outp, head) {
if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
if (ret = -ENODEV, outp->conn->hpd.event) {
notify->types = req->v0.mask;
notify->index = req->v0.conn;
ret = 0;
}
break;
}
}
}
return ret;
}
static const struct nvkm_event_func
nouveau_disp_hpd_func = {
.ctor = nouveau_disp_hpd_ctor
};
int
nouveau_disp_ntfy(struct nouveau_object *object, u32 type,
struct nvkm_event **event)
{
struct nouveau_disp *disp = (void *)object->engine;
switch (type) {
case NV04_DISP_NTFY_VBLANK:
*event = &disp->vblank;
return 0;
case NV04_DISP_NTFY_CONN:
*event = &disp->hpd;
return 0;
default:
break;
}
return -EINVAL;
}
int
_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;
nvkm_event_fini(&disp->vblank);
nvkm_event_fini(&disp->hpd);
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);
}
int
nouveau_disp_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, int heads,
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;
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);
disp = *pobject;
if (ret)
return ret;
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 = nvkm_event_init(&nouveau_disp_hpd_func, 3, hpd, &disp->hpd);
if (ret)
return ret;
ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
if (ret)
return ret;
return 0;
}

View file

@ -0,0 +1,175 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <core/os.h>
#include <nvif/event.h>
#include <subdev/gpio.h>
#include "conn.h"
#include "outp.h"
static int
nvkm_connector_hpd(struct nvkm_notify *notify)
{
struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
struct nouveau_disp *disp = nouveau_disp(conn);
struct nouveau_gpio *gpio = nouveau_gpio(conn);
const struct nvkm_gpio_ntfy_rep *line = notify->data;
struct nvif_notify_conn_rep_v0 rep;
int index = conn->index;
DBG("HPD: %d\n", line->mask);
if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
else
rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
rep.version = 0;
nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
return NVKM_NOTIFY_KEEP;
}
int
_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
{
struct nvkm_connector *conn = (void *)object;
nvkm_notify_put(&conn->hpd);
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)
nvkm_notify_get(&conn->hpd);
return ret;
}
void
_nvkm_connector_dtor(struct nouveau_object *object)
{
struct nvkm_connector *conn = (void *)object;
nvkm_notify_fini(&conn->hpd);
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);
return 0;
}
info->hpd = hpd[info->hpd];
ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
if (ret) {
ERR("func %02x lookup failed, %d\n", info->hpd, ret);
return 0;
}
ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
true, &(struct nvkm_gpio_ntfy_req) {
.mask = NVKM_GPIO_TOGGLED,
.line = func.line,
},
sizeof(struct nvkm_gpio_ntfy_req),
sizeof(struct nvkm_gpio_ntfy_rep),
&conn->hpd);
if (ret) {
ERR("func %02x failed, %d\n", info->hpd, ret);
} else {
DBG("func %02x (HPD)\n", info->hpd);
}
}
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;

View file

@ -0,0 +1,56 @@
#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 nvkm_notify 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

View file

@ -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 <core/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/timer.h>
#include "nv50.h"
int
nv50_dac_power(NV50_DISP_MTHD_V1)
{
const u32 doff = outp->or * 0x800;
union {
struct nv50_disp_dac_pwr_v0 v0;
} *args = data;
u32 stat;
int ret;
nv_ioctl(object, "disp dac pwr size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp dac pwr vers %d state %d data %d "
"vsync %d hsync %d\n",
args->v0.version, args->v0.state, args->v0.data,
args->v0.vsync, args->v0.hsync);
stat = 0x00000040 * !args->v0.state;
stat |= 0x00000010 * !args->v0.data;
stat |= 0x00000004 * !args->v0.vsync;
stat |= 0x00000001 * !args->v0.hsync;
} else
return ret;
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
return 0;
}
int
nv50_dac_sense(NV50_DISP_MTHD_V1)
{
union {
struct nv50_disp_dac_load_v0 v0;
} *args = data;
const u32 doff = outp->or * 0x800;
u32 loadval;
int ret;
nv_ioctl(object, "disp dac load size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp dac load vers %d data %08x\n",
args->v0.version, args->v0.data);
if (args->v0.data & 0xfff00000)
return -EINVAL;
loadval = args->v0.data;
} else
return ret;
nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
mdelay(9);
udelay(500);
loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000);
nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval);
if (!(loadval & 0x80000000))
return -ETIMEDOUT;
args->v0.load = (loadval & 0x38000000) >> 27;
return 0;
}

View file

@ -0,0 +1,399 @@
/*
* 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/dcb.h>
#include <subdev/bios/dp.h>
#include <subdev/bios/init.h>
#include <subdev/i2c.h>
#include <engine/disp.h>
#include <nvif/class.h>
#include "dport.h"
#include "outpdp.h"
/******************************************************************************
* link training
*****************************************************************************/
struct dp_state {
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 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(disp),
.bios = bios,
.offset = 0x0000,
.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 source */
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);
} else {
while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp))
lnkcmp += 3;
init.offset = nv_ro16(bios, lnkcmp + 1);
}
nvbios_exec(&init);
}
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);
impl->pattern(outp, pattern);
nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
sink_tp |= pattern;
nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
}
static int
dp_link_train_commit(struct dp_state *dp, bool pc)
{
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;
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;
if (pc) {
ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2);
if (ret)
return ret;
}
return 0;
}
static int
dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
{
struct nvkm_output_dp *outp = dp->outp;
int ret;
if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
else
udelay(delay);
ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6);
if (ret)
return ret;
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;
}
static int
dp_link_train_cr(struct dp_state *dp)
{
bool cr_done = false, abort = false;
int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
int tries = 0, i;
dp_set_training_pattern(dp, 1);
do {
if (dp_link_train_commit(dp, false) ||
dp_link_train_update(dp, false, 100))
break;
cr_done = true;
for (i = 0; i < dp->link_nr; i++) {
u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
cr_done = false;
if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
abort = true;
break;
}
}
if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
tries = 0;
}
} while (!cr_done && !abort && ++tries < 5);
return cr_done ? 0 : -1;
}
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;
if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
dp_set_training_pattern(dp, 3);
else
dp_set_training_pattern(dp, 2);
do {
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);
for (i = 0; i < dp->link_nr && eq_done; i++) {
u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
if (!(lane & DPCD_LS02_LANE0_CR_DONE))
cr_done = false;
if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
!(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
eq_done = false;
}
} while (!eq_done && cr_done && ++tries <= 5);
return eq_done ? 0 : -1;
}
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(disp),
.bios = bios,
.outp = &outp->base.info,
.crtc = -1,
.execute = 1,
};
/* set desired spread */
if (spread)
init.offset = outp->info.script[2];
else
init.offset = outp->info.script[3];
nvbios_exec(&init);
/* pre-train script */
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(disp),
.bios = bios,
.outp = &outp->base.info,
.crtc = -1,
.execute = 1,
};
/* post-train script */
init.offset = outp->info.script[1],
nvbios_exec(&init);
}
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 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 = {
.outp = outp,
}, *dp = &_dp;
u32 datarate = 0;
int ret;
/* bring capabilities within encoder limits */
if (nv_mclass(disp) < GF110_DISP)
outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
}
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--;
/* disable link interrupt handling during link training */
nvkm_notify_put(&outp->irq);
/* enable down-spreading and execute pre-train script from vbios */
dp_link_train_init(dp, outp->dpcd[3] & 0x01);
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);
if (ret == 0) {
/* attempt to train the link at this configuration */
memset(dp->stat, 0x00, sizeof(dp->stat));
if (!dp_link_train_cr(dp) &&
!dp_link_train_eq(dp))
break;
} else
if (ret) {
/* dp_set_link_config() handled training, or
* we failed to communicate with the sink.
*/
break;
}
}
/* finish link training and execute post-train script from vbios */
dp_set_training_pattern(dp, 0);
if (ret < 0)
ERR("link training failed\n");
dp_link_train_fini(dp);
/* signal completion and enable link interrupt handling */
DBG("training complete\n");
atomic_set(&outp->lt.done, 1);
wake_up(&outp->lt.wait);
nvkm_notify_get(&outp->irq);
}

View file

@ -0,0 +1,75 @@
#ifndef __NVKM_DISP_DPORT_H__
#define __NVKM_DISP_DPORT_H__
/* DPCD Receiver Capabilities */
#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_LINK_BW_SET 0x00100
#define DPCD_LC01 0x00101
#define DPCD_LC01_ENHANCED_FRAME_EN 0x80
#define DPCD_LC01_LANE_COUNT_SET 0x1f
#define DPCD_LC02 0x00102
#define DPCD_LC02_TRAINING_PATTERN_SET 0x03
#define DPCD_LC03(l) ((l) + 0x00103)
#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20
#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
#define DPCD_LS02_LANE1_SYMBOL_LOCKED 0x40
#define DPCD_LS02_LANE1_CHANNEL_EQ_DONE 0x20
#define DPCD_LS02_LANE1_CR_DONE 0x10
#define DPCD_LS02_LANE0_SYMBOL_LOCKED 0x04
#define DPCD_LS02_LANE0_CHANNEL_EQ_DONE 0x02
#define DPCD_LS02_LANE0_CR_DONE 0x01
#define DPCD_LS03 0x00203
#define DPCD_LS03_LANE3_SYMBOL_LOCKED 0x40
#define DPCD_LS03_LANE3_CHANNEL_EQ_DONE 0x20
#define DPCD_LS03_LANE3_CR_DONE 0x10
#define DPCD_LS03_LANE2_SYMBOL_LOCKED 0x04
#define DPCD_LS03_LANE2_CHANNEL_EQ_DONE 0x02
#define DPCD_LS03_LANE2_CR_DONE 0x01
#define DPCD_LS04 0x00204
#define DPCD_LS04_LINK_STATUS_UPDATED 0x80
#define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED 0x40
#define DPCD_LS04_INTERLANE_ALIGN_DONE 0x01
#define DPCD_LS06 0x00206
#define DPCD_LS06_LANE1_PRE_EMPHASIS 0xc0
#define DPCD_LS06_LANE1_VOLTAGE_SWING 0x30
#define DPCD_LS06_LANE0_PRE_EMPHASIS 0x0c
#define DPCD_LS06_LANE0_VOLTAGE_SWING 0x03
#define DPCD_LS07 0x00207
#define DPCD_LS07_LANE3_PRE_EMPHASIS 0xc0
#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
void nouveau_dp_train(struct work_struct *);
#endif

View file

@ -0,0 +1,107 @@
/*
* 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 <nvif/class.h>
#include "nv50.h"
/*******************************************************************************
* Base display object
******************************************************************************/
static struct nouveau_oclass
gm107_disp_sclass[] = {
{ GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base },
{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base },
{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
gm107_disp_base_oclass[] = {
{ GM107_DISP, &nvd0_disp_base_ofuncs },
{}
};
/*******************************************************************************
* 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;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = gm107_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
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 = nve0_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.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos,
}.base.base;

View file

@ -0,0 +1,69 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/timer.h>
#include "nv50.h"
int
nva3_hda_eld(NV50_DISP_MTHD_V1)
{
union {
struct nv50_disp_sor_hda_eld_v0 v0;
} *args = data;
const u32 soff = outp->or * 0x800;
int ret, i;
nv_ioctl(object, "disp sor hda eld size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
if (size > 0x60)
return -E2BIG;
} else
return ret;
if (size && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
}
for (i = 0; i < size; i++)
nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
for (; i < 0x60; i++)
nv_wr32(priv, 0x61c440 + soff, (i << 8));
nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
} else {
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000);
nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
}
nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
}
return 0;
}

View file

@ -0,0 +1,71 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/timer.h>
#include "nv50.h"
int
nvd0_hda_eld(NV50_DISP_MTHD_V1)
{
union {
struct nv50_disp_sor_hda_eld_v0 v0;
} *args = data;
const u32 soff = outp->or * 0x030;
const u32 hoff = head * 0x800;
int ret, i;
nv_ioctl(object, "disp sor hda eld size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
if (size > 0x60)
return -E2BIG;
} else
return ret;
if (size && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001);
nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
}
nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
for (i = 0; i < size; i++)
nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
for (; i < 0x60; i++)
nv_wr32(priv, 0x10ec00 + soff, (i << 8));
nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
} else {
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000);
nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
}
nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
}
return 0;
}

View file

@ -0,0 +1,91 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include "nv50.h"
int
nv84_hdmi_ctrl(NV50_DISP_MTHD_V1)
{
const u32 hoff = (head * 0x800);
union {
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
int ret;
nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
args->v0.max_ac_packet, args->v0.rekey);
if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
return -EINVAL;
ctrl = 0x40000000 * !!args->v0.state;
ctrl |= args->v0.max_ac_packet << 16;
ctrl |= args->v0.rekey;
ctrl |= 0x1f000000; /* ??? */
} else
return ret;
if (!(ctrl & 0x40000000)) {
nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000);
nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
return 0;
}
/* AVI InfoFrame */
nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
nv_wr32(priv, 0x616528 + hoff, 0x000d0282);
nv_wr32(priv, 0x61652c + hoff, 0x0000006f);
nv_wr32(priv, 0x616530 + hoff, 0x00000000);
nv_wr32(priv, 0x616534 + hoff, 0x00000000);
nv_wr32(priv, 0x616538 + hoff, 0x00000000);
nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001);
/* Audio InfoFrame */
nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
nv_wr32(priv, 0x616508 + hoff, 0x000a0184);
nv_wr32(priv, 0x61650c + hoff, 0x00000071);
nv_wr32(priv, 0x616510 + hoff, 0x00000000);
nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001);
nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
/* ??? */
nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
/* HDMI_CTRL */
nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
return 0;
}

View file

@ -0,0 +1,91 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include "nv50.h"
int
nva3_hdmi_ctrl(NV50_DISP_MTHD_V1)
{
const u32 soff = outp->or * 0x800;
union {
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
int ret;
nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
args->v0.max_ac_packet, args->v0.rekey);
if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
return -EINVAL;
ctrl = 0x40000000 * !!args->v0.state;
ctrl |= args->v0.max_ac_packet << 16;
ctrl |= args->v0.rekey;
ctrl |= 0x1f000000; /* ??? */
} else
return ret;
if (!(ctrl & 0x40000000)) {
nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000);
nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
return 0;
}
/* AVI InfoFrame */
nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
nv_wr32(priv, 0x61c528 + soff, 0x000d0282);
nv_wr32(priv, 0x61c52c + soff, 0x0000006f);
nv_wr32(priv, 0x61c530 + soff, 0x00000000);
nv_wr32(priv, 0x61c534 + soff, 0x00000000);
nv_wr32(priv, 0x61c538 + soff, 0x00000000);
nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001);
/* Audio InfoFrame */
nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
nv_wr32(priv, 0x61c508 + soff, 0x000a0184);
nv_wr32(priv, 0x61c50c + soff, 0x00000071);
nv_wr32(priv, 0x61c510 + soff, 0x00000000);
nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
/* ??? */
nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
/* HDMI_CTRL */
nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
return 0;
}

View file

@ -0,0 +1,79 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include "nv50.h"
int
nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1)
{
const u32 hoff = (head * 0x800);
union {
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
int ret;
nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
args->v0.max_ac_packet, args->v0.rekey);
if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
return -EINVAL;
ctrl = 0x40000000 * !!args->v0.state;
ctrl |= args->v0.max_ac_packet << 16;
ctrl |= args->v0.rekey;
} else
return ret;
if (!(ctrl & 0x40000000)) {
nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
return 0;
}
/* AVI InfoFrame */
nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
nv_wr32(priv, 0x61671c + hoff, 0x000d0282);
nv_wr32(priv, 0x616720 + hoff, 0x0000006f);
nv_wr32(priv, 0x616724 + hoff, 0x00000000);
nv_wr32(priv, 0x616728 + hoff, 0x00000000);
nv_wr32(priv, 0x61672c + hoff, 0x00000000);
nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001);
/* ??? InfoFrame? */
nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
nv_wr32(priv, 0x6167ac + hoff, 0x00000010);
nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001);
/* HDMI_CTRL */
nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
return 0;
}

View file

@ -0,0 +1,83 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <core/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include "nv50.h"
int
nve0_hdmi_ctrl(NV50_DISP_MTHD_V1)
{
const u32 hoff = (head * 0x800);
const u32 hdmi = (head * 0x400);
union {
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
int ret;
nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
args->v0.max_ac_packet, args->v0.rekey);
if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
return -EINVAL;
ctrl = 0x40000000 * !!args->v0.state;
ctrl |= args->v0.max_ac_packet << 16;
ctrl |= args->v0.rekey;
} else
return ret;
if (!(ctrl & 0x40000000)) {
nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
return 0;
}
/* AVI InfoFrame */
nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
nv_wr32(priv, 0x690008 + hdmi, 0x000d0282);
nv_wr32(priv, 0x69000c + hdmi, 0x0000006f);
nv_wr32(priv, 0x690010 + hdmi, 0x00000000);
nv_wr32(priv, 0x690014 + hdmi, 0x00000000);
nv_wr32(priv, 0x690018 + hdmi, 0x00000000);
nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001);
/* ??? InfoFrame? */
nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nv_wr32(priv, 0x6900cc + hdmi, 0x00000010);
nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
/* ??? */
nv_wr32(priv, 0x690080 + hdmi, 0x82000000);
/* HDMI_CTRL */
nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
return 0;
}

View file

@ -0,0 +1,205 @@
/*
* 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"
#include <core/client.h>
#include <core/event.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
struct nv04_disp_priv {
struct nouveau_disp base;
};
static int
nv04_disp_scanoutpos(struct nouveau_object *object, struct nv04_disp_priv *priv,
void *data, u32 size, int head)
{
const u32 hoff = head * 0x2000;
union {
struct nv04_disp_scanoutpos_v0 v0;
} *args = data;
u32 line;
int ret;
nv_ioctl(object, "disp scanoutpos size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
args->v0.vblanke = args->v0.vtotal - 1;
args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
args->v0.hblanke = args->v0.htotal - 1;
/*
* If output is vga instead of digital then vtotal/htotal is
* invalid so we have to give up and trigger the timestamping
* fallback in the drm core.
*/
if (!args->v0.vtotal || !args->v0.htotal)
return -ENOTSUPP;
args->v0.time[0] = ktime_to_ns(ktime_get());
line = nv_rd32(priv, 0x600868 + hoff);
args->v0.time[1] = ktime_to_ns(ktime_get());
args->v0.hline = (line & 0xffff0000) >> 16;
args->v0.vline = (line & 0x0000ffff);
} else
return ret;
return 0;
}
static int
nv04_disp_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
{
union {
struct nv04_disp_mthd_v0 v0;
} *args = data;
struct nv04_disp_priv *priv = (void *)object->engine;
int head, ret;
nv_ioctl(object, "disp mthd size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
args->v0.version, args->v0.method, args->v0.head);
mthd = args->v0.method;
head = args->v0.head;
} else
return ret;
if (head < 0 || head >= 2)
return -ENXIO;
switch (mthd) {
case NV04_DISP_SCANOUTPOS:
return nv04_disp_scanoutpos(object, priv, data, size, head);
default:
break;
}
return -EINVAL;
}
static struct nouveau_ofuncs
nv04_disp_ofuncs = {
.ctor = _nouveau_object_ctor,
.dtor = nouveau_object_destroy,
.init = nouveau_object_init,
.fini = nouveau_object_fini,
.mthd = nv04_disp_mthd,
.ntfy = nouveau_disp_ntfy,
};
static struct nouveau_oclass
nv04_disp_sclass[] = {
{ NV04_DISP, &nv04_disp_ofuncs },
{},
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static void
nv04_disp_vblank_init(struct nvkm_event *event, int type, int head)
{
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001);
}
static void
nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head)
{
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000);
}
static const struct nvkm_event_func
nv04_disp_vblank_func = {
.ctor = nouveau_disp_vblank_ctor,
.init = nv04_disp_vblank_init,
.fini = nv04_disp_vblank_fini,
};
static void
nv04_disp_intr(struct nouveau_subdev *subdev)
{
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_disp_vblank(&priv->base, 0);
nv_wr32(priv, 0x600100, 0x00000001);
}
if (crtc1 & 0x00000001) {
nouveau_disp_vblank(&priv->base, 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
nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_disp_priv *priv;
int ret;
ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->sclass = nv04_disp_sclass;
nv_subdev(priv)->intr = nv04_disp_intr;
return 0;
}
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,
},
.vblank = &nv04_disp_vblank_func,
}.base;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,247 @@
#ifndef __NV50_DISP_H__
#define __NV50_DISP_H__
#include <core/parent.h>
#include <core/namedb.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <core/event.h>
#include <engine/dmaobj.h>
#include "dport.h"
#include "priv.h"
#include "outp.h"
#include "outpdp.h"
#define NV50_DISP_MTHD_ struct nouveau_object *object, \
struct nv50_disp_priv *priv, void *data, u32 size
#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp
struct nv50_disp_priv {
struct nouveau_disp base;
struct nouveau_oclass *sclass;
struct work_struct supervisor;
u32 super;
struct nvkm_event uevent;
struct {
int nr;
} head;
struct {
int nr;
int (*power)(NV50_DISP_MTHD_V1);
int (*sense)(NV50_DISP_MTHD_V1);
} dac;
struct {
int nr;
int (*power)(NV50_DISP_MTHD_V1);
int (*hda_eld)(NV50_DISP_MTHD_V1);
int (*hdmi)(NV50_DISP_MTHD_V1);
u32 lvdsconf;
} sor;
struct {
int nr;
int (*power)(NV50_DISP_MTHD_V1);
u8 type[3];
} pior;
};
struct nv50_disp_impl {
struct nouveau_disp_impl base;
struct {
const struct nv50_disp_mthd_chan *core;
const struct nv50_disp_mthd_chan *base;
const struct nv50_disp_mthd_chan *ovly;
int prev;
} mthd;
struct {
int (*scanoutpos)(NV50_DISP_MTHD_V0);
} head;
};
int nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);
int nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
int nv50_dac_power(NV50_DISP_MTHD_V1);
int nv50_dac_sense(NV50_DISP_MTHD_V1);
int nva3_hda_eld(NV50_DISP_MTHD_V1);
int nvd0_hda_eld(NV50_DISP_MTHD_V1);
int nv84_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nva3_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nve0_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nv50_sor_power(NV50_DISP_MTHD_V1);
int nv94_sor_dp_train_init(struct nv50_disp_priv *, int, int, int, u16, u16,
u32, struct dcb_output *);
int nv94_sor_dp_train_fini(struct nv50_disp_priv *, int, int, int, u16, u16,
u32, struct dcb_output *);
int nv94_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
struct dcb_output *);
int nv94_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
struct dcb_output *);
int nv94_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
struct dcb_output *);
int nvd0_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
struct dcb_output *);
int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
struct dcb_output *);
int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
struct dcb_output *);
int nv50_pior_power(NV50_DISP_MTHD_V1);
struct nv50_disp_base {
struct nouveau_parent base;
struct nouveau_ramht *ramht;
u32 chan;
};
struct nv50_disp_chan_impl {
struct nouveau_ofuncs base;
int chid;
int (*attach)(struct nouveau_object *, struct nouveau_object *, u32);
void (*detach)(struct nouveau_object *, int);
};
struct nv50_disp_chan {
struct nouveau_namedb base;
int chid;
};
int nv50_disp_chan_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
int nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *);
u32 nv50_disp_chan_rd32(struct nouveau_object *, u64);
void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
extern const struct nvkm_event_func nv50_disp_chan_uevent;
int nv50_disp_chan_uevent_ctor(struct nouveau_object *, void *, u32,
struct nvkm_notify *);
void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);
extern const struct nvkm_event_func nvd0_disp_chan_uevent;
#define nv50_disp_chan_init(a) \
nouveau_namedb_init(&(a)->base)
#define nv50_disp_chan_fini(a,b) \
nouveau_namedb_fini(&(a)->base, (b))
struct nv50_disp_dmac {
struct nv50_disp_chan base;
struct nouveau_dmaobj *pushdma;
u32 push;
};
void nv50_disp_dmac_dtor(struct nouveau_object *);
struct nv50_disp_pioc {
struct nv50_disp_chan base;
};
void nv50_disp_pioc_dtor(struct nouveau_object *);
struct nv50_disp_mthd_list {
u32 mthd;
u32 addr;
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 nv50_disp_chan_impl nv50_disp_mast_ofuncs;
int nv50_disp_mast_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_base;
extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_sor;
extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_pior;
extern struct nv50_disp_chan_impl nv50_disp_sync_ofuncs;
int nv50_disp_sync_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
extern const struct nv50_disp_mthd_list nv50_disp_sync_mthd_image;
extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs;
int nv50_disp_ovly_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs;
int nv50_disp_oimm_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs;
int nv50_disp_curs_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void nv50_disp_base_dtor(struct nouveau_object *);
extern struct nouveau_omthds nv50_disp_base_omthds[];
extern struct nouveau_oclass nv50_disp_cclass;
void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
const struct nv50_disp_mthd_chan *);
void nv50_disp_intr_supervisor(struct work_struct *);
void nv50_disp_intr(struct nouveau_subdev *);
extern const struct nvkm_event_func nv50_disp_vblank_func;
extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan;
extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head;
extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan;
extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan;
extern struct nv50_disp_chan_impl nvd0_disp_mast_ofuncs;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_base;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_dac;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_sor;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_pior;
extern struct nv50_disp_chan_impl nvd0_disp_sync_ofuncs;
extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan;
extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
extern struct nouveau_oclass nvd0_disp_cclass;
void nvd0_disp_intr_supervisor(struct work_struct *);
void nvd0_disp_intr(struct nouveau_subdev *);
extern const struct nvkm_event_func nvd0_disp_vblank_func;
extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan;
extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
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

View file

@ -0,0 +1,276 @@
/*
* 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 <nvif/class.h>
#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[] = {
{ G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
{ G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
{ G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
nv84_disp_base_oclass[] = {
{ G82_DISP, &nv50_disp_base_ofuncs },
{}
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static int
nv84_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 ret;
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nv84_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nv84_disp_sclass;
priv->head.nr = 2;
priv->dac.nr = 3;
priv->sor.nr = 2;
priv->pior.nr = 3;
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power;
return 0;
}
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.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base;

View file

@ -0,0 +1,142 @@
/*
* 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 <nvif/class.h>
#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[] = {
{ GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
nv94_disp_base_oclass[] = {
{ GT206_DISP, &nv50_disp_base_ofuncs },
{}
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static int
nv94_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 ret;
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nv94_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nv94_disp_sclass;
priv->head.nr = 2;
priv->dac.nr = 3;
priv->sor.nr = 4;
priv->pior.nr = 3;
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power;
return 0;
}
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.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base;

View file

@ -0,0 +1,152 @@
/*
* 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 <nvif/class.h>
#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[] = {
{ GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
nva0_disp_base_oclass[] = {
{ GT200_DISP, &nv50_disp_base_ofuncs },
{}
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static int
nva0_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 ret;
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nva0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nva0_disp_sclass;
priv->head.nr = 2;
priv->dac.nr = 3;
priv->sor.nr = 2;
priv->pior.nr = 3;
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power;
return 0;
}
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.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nva0_disp_ovly_mthd_chan,
.mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base;

View file

@ -0,0 +1,108 @@
/*
* 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 <nvif/class.h>
#include "nv50.h"
/*******************************************************************************
* Base display object
******************************************************************************/
static struct nouveau_oclass
nva3_disp_sclass[] = {
{ GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
{ GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
{ GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
nva3_disp_base_oclass[] = {
{ GT214_DISP, &nv50_disp_base_ofuncs },
{}
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static int
nva3_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 ret;
ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nva3_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nva3_disp_sclass;
priv->head.nr = 2;
priv->dac.nr = 3;
priv->sor.nr = 4;
priv->pior.nr = 3;
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nva3_hda_eld;
priv->sor.hdmi = nva3_hdmi_ctrl;
priv->pior.power = nv50_pior_power;
return 0;
}
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.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos,
}.base.base;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,272 @@
/*
* 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 <nvif/class.h>
#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[] = {
{ GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base },
{ GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base },
{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
nve0_disp_base_oclass[] = {
{ GK104_DISP, &nvd0_disp_base_ofuncs },
{}
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static int
nve0_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;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nve0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
priv->sclass = nve0_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 = nve0_hdmi_ctrl;
return 0;
}
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.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos,
}.base.base;

View file

@ -0,0 +1,107 @@
/*
* 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 <nvif/class.h>
#include "nv50.h"
/*******************************************************************************
* Base display object
******************************************************************************/
static struct nouveau_oclass
nvf0_disp_sclass[] = {
{ GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base },
{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base },
{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
nvf0_disp_base_oclass[] = {
{ GK110_DISP, &nvd0_disp_base_ofuncs },
{}
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static int
nvf0_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;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nvf0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
priv->sclass = nvf0_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 = nve0_hdmi_ctrl;
return 0;
}
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.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos,
}.base.base;

View file

@ -0,0 +1,138 @@
/*
* 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;
outp->or = ffs(outp->info.or) - 1;
DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
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;

View file

@ -0,0 +1,60 @@
#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;
int or;
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

View file

@ -0,0 +1,302 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <core/os.h>
#include <nvif/event.h>
#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 {
nvkm_notify_get(&outp->irq);
}
if (wait) {
if (!wait_event_timeout(outp->lt.wait,
atomic_read(&outp->lt.done),
msecs_to_jiffies(2000)))
ret = -ETIMEDOUT;
}
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 int
nvkm_output_dp_hpd(struct nvkm_notify *notify)
{
struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
struct nvkm_output_dp *outp;
struct nouveau_disp *disp = nouveau_disp(conn);
const struct nvkm_i2c_ntfy_rep *line = notify->data;
struct nvif_notify_conn_rep_v0 rep = {};
list_for_each_entry(outp, &disp->outp, base.head) {
if (outp->base.conn == conn &&
outp->info.type == DCB_OUTPUT_DP) {
DBG("HPD: %d\n", line->mask);
nvkm_output_dp_detect(outp);
if (line->mask & NVKM_I2C_UNPLUG)
rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
if (line->mask & NVKM_I2C_PLUG)
rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
nvkm_event_send(&disp->hpd, rep.mask, conn->index,
&rep, sizeof(rep));
return NVKM_NOTIFY_KEEP;
}
}
WARN_ON(1);
return NVKM_NOTIFY_DROP;
}
static int
nvkm_output_dp_irq(struct nvkm_notify *notify)
{
struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
struct nouveau_disp *disp = nouveau_disp(outp);
const struct nvkm_i2c_ntfy_rep *line = notify->data;
struct nvif_notify_conn_rep_v0 rep = {
.mask = NVIF_NOTIFY_CONN_V0_IRQ,
};
int index = outp->base.info.connector;
DBG("IRQ: %d\n", line->mask);
nvkm_output_dp_train(&outp->base, 0, true);
nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
return NVKM_NOTIFY_DROP;
}
int
_nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
{
struct nvkm_output_dp *outp = (void *)object;
nvkm_notify_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;
nvkm_notify_fini(&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;
nvkm_notify_fini(&outp->base.conn->hpd);
/* 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 = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
&(struct nvkm_i2c_ntfy_req) {
.mask = NVKM_I2C_IRQ,
.port = outp->base.edid->index,
},
sizeof(struct nvkm_i2c_ntfy_req),
sizeof(struct nvkm_i2c_ntfy_rep),
&outp->irq);
if (ret) {
ERR("error monitoring aux irq event: %d\n", ret);
return ret;
}
/* hotplug detect, replaces gpio-based mechanism with aux events */
ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
&(struct nvkm_i2c_ntfy_req) {
.mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
.port = outp->base.edid->index,
},
sizeof(struct nvkm_i2c_ntfy_req),
sizeof(struct nvkm_i2c_ntfy_rep),
&outp->base.conn->hpd);
if (ret) {
ERR("error monitoring aux hpd events: %d\n", ret);
return ret;
}
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;
}

View file

@ -0,0 +1,62 @@
#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 nvkm_notify irq;
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

View file

@ -0,0 +1,172 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/timer.h>
#include <subdev/i2c.h>
#include "nv50.h"
/******************************************************************************
* TMDS
*****************************************************************************/
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(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 nvkm_output_dp *outp, int pattern)
{
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_pwr(struct nvkm_output_dp *outp, int nr)
{
return 0;
}
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)
return port->func->lnk_ctl(port, nr, bw, ef);
return port ? 0 : -ENODEV;
}
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_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(parent);
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;
outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(
outp->base.info.extdev));
return 0;
}
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,
};
/******************************************************************************
* General PIOR handling
*****************************************************************************/
int
nv50_pior_power(NV50_DISP_MTHD_V1)
{
const u32 soff = outp->or * 0x800;
union {
struct nv50_disp_pior_pwr_v0 v0;
} *args = data;
u32 ctrl, type;
int ret;
nv_ioctl(object, "disp pior pwr size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
args->v0.version, args->v0.state, args->v0.type);
if (args->v0.type > 0x0f)
return -EINVAL;
ctrl = !!args->v0.state;
type = args->v0.type;
} else
return ret;
nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
priv->pior.type[outp->or] = type;
return 0;
}

View file

@ -0,0 +1,48 @@
#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;
const struct nvkm_event_func *vblank;
};
#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;
int nouveau_disp_vblank_ctor(struct nouveau_object *, void *data, u32 size,
struct nvkm_notify *);
void nouveau_disp_vblank(struct nouveau_disp *, int head);
int nouveau_disp_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
#endif

View file

@ -0,0 +1,58 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/timer.h>
#include "nv50.h"
int
nv50_sor_power(NV50_DISP_MTHD_V1)
{
union {
struct nv50_disp_sor_pwr_v0 v0;
} *args = data;
const u32 soff = outp->or * 0x800;
u32 stat;
int ret;
nv_ioctl(object, "disp sor pwr size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp sor pwr vers %d state %d\n",
args->v0.version, args->v0.state);
stat = !!args->v0.state;
} else
return ret;
nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000);
return 0;
}

View file

@ -0,0 +1,151 @@
/*
* 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 <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/dp.h>
#include <subdev/bios/init.h>
#include <subdev/timer.h>
#include "nv50.h"
#include "outpdp.h"
static inline u32
nv94_sor_soff(struct nvkm_output_dp *outp)
{
return (ffs(outp->base.info.or) - 1) * 0x800;
}
static inline u32
nv94_sor_loff(struct nvkm_output_dp *outp)
{
return nv94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
}
static inline u32
nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
{
static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
static const u8 nv94[] = { 16, 8, 0, 24 };
if (nv_device(priv)->chipset == 0xaf)
return nvaf[lane];
return nv94[lane];
}
static int
nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
{
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 nvkm_output_dp *outp, int nr, int bw, bool ef)
{
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;
dpctrl |= ((1 << nr) - 1) << 16;
if (ef)
dpctrl |= 0x00004000;
if (bw > 0x06)
clksor |= 0x00040000;
nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
return 0;
}
static int
nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
{
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, data[3];
u8 ver, hdr, cnt, len;
struct nvbios_dpout info;
struct nvbios_dpcfg ocfg;
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, vs, pe,
&ver, &hdr, &cnt, &len, &ocfg);
if (!addr)
return -EINVAL;
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;
}
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,
};

View file

@ -0,0 +1,131 @@
/*
* 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 <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/dp.h>
#include <subdev/bios/init.h>
#include <subdev/timer.h>
#include "nv50.h"
static inline u32
nvd0_sor_soff(struct nvkm_output_dp *outp)
{
return (ffs(outp->base.info.or) - 1) * 0x800;
}
static inline u32
nvd0_sor_loff(struct nvkm_output_dp *outp)
{
return nvd0_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
}
static inline u32
nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
{
static const u8 nvd0[] = { 16, 8, 0, 24 };
return nvd0[lane];
}
static int
nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
{
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 nvkm_output_dp *outp, int nr, int bw, bool ef)
{
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;
clksor |= bw << 18;
dpctrl |= ((1 << nr) - 1) << 16;
if (ef)
dpctrl |= 0x00004000;
nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
return 0;
}
static int
nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
{
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, data[4];
u8 ver, hdr, cnt, len;
struct nvbios_dpout info;
struct nvbios_dpcfg ocfg;
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, pc, vs, pe,
&ver, &hdr, &cnt, &len, &ocfg);
if (!addr)
return -EINVAL;
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;
}
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,
};

View file

@ -0,0 +1,220 @@
/*
* 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/subdev.h>
#include <core/device.h>
#include <subdev/vga.h>
u8
nv_rdport(void *obj, int head, u16 port)
{
struct nouveau_device *device = nv_device(obj);
if (device->card_type >= NV_50)
return nv_rd08(obj, 0x601000 + port);
if (port == 0x03c0 || port == 0x03c1 || /* AR */
port == 0x03c2 || port == 0x03da || /* INP0 */
port == 0x03d4 || port == 0x03d5) /* CR */
return nv_rd08(obj, 0x601000 + (head * 0x2000) + port);
if (port == 0x03c2 || port == 0x03cc || /* MISC */
port == 0x03c4 || port == 0x03c5 || /* SR */
port == 0x03ce || port == 0x03cf) { /* GR */
if (device->card_type < NV_40)
head = 0; /* CR44 selects head */
return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port);
}
nv_error(obj, "unknown vga port 0x%04x\n", port);
return 0x00;
}
void
nv_wrport(void *obj, int head, u16 port, u8 data)
{
struct nouveau_device *device = nv_device(obj);
if (device->card_type >= NV_50)
nv_wr08(obj, 0x601000 + port, data);
else
if (port == 0x03c0 || port == 0x03c1 || /* AR */
port == 0x03c2 || port == 0x03da || /* INP0 */
port == 0x03d4 || port == 0x03d5) /* CR */
nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data);
else
if (port == 0x03c2 || port == 0x03cc || /* MISC */
port == 0x03c4 || port == 0x03c5 || /* SR */
port == 0x03ce || port == 0x03cf) { /* GR */
if (device->card_type < NV_40)
head = 0; /* CR44 selects head */
nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data);
} else
nv_error(obj, "unknown vga port 0x%04x\n", port);
}
u8
nv_rdvgas(void *obj, int head, u8 index)
{
nv_wrport(obj, head, 0x03c4, index);
return nv_rdport(obj, head, 0x03c5);
}
void
nv_wrvgas(void *obj, int head, u8 index, u8 value)
{
nv_wrport(obj, head, 0x03c4, index);
nv_wrport(obj, head, 0x03c5, value);
}
u8
nv_rdvgag(void *obj, int head, u8 index)
{
nv_wrport(obj, head, 0x03ce, index);
return nv_rdport(obj, head, 0x03cf);
}
void
nv_wrvgag(void *obj, int head, u8 index, u8 value)
{
nv_wrport(obj, head, 0x03ce, index);
nv_wrport(obj, head, 0x03cf, value);
}
u8
nv_rdvgac(void *obj, int head, u8 index)
{
nv_wrport(obj, head, 0x03d4, index);
return nv_rdport(obj, head, 0x03d5);
}
void
nv_wrvgac(void *obj, int head, u8 index, u8 value)
{
nv_wrport(obj, head, 0x03d4, index);
nv_wrport(obj, head, 0x03d5, value);
}
u8
nv_rdvgai(void *obj, int head, u16 port, u8 index)
{
if (port == 0x03c4) return nv_rdvgas(obj, head, index);
if (port == 0x03ce) return nv_rdvgag(obj, head, index);
if (port == 0x03d4) return nv_rdvgac(obj, head, index);
nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
return 0x00;
}
void
nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
{
if (port == 0x03c4) nv_wrvgas(obj, head, index, value);
else if (port == 0x03ce) nv_wrvgag(obj, head, index, value);
else if (port == 0x03d4) nv_wrvgac(obj, head, index, value);
else nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
}
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;
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);
}
return locked;
}
/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
* it affects only the 8 bit vga io regs, which we access using mmio at
* 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
* in general, the set value of cr44 does not matter: reg access works as
* expected and values can be set for the appropriate head by using a 0x2000
* offset as required
* however:
* a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
* cr44 must be set to 0 or 3 for accessing values on the correct head
* through the common 0xc03c* addresses
* b) in tied mode (4) head B is programmed to the values set on head A, and
* access using the head B addresses can have strange results, ergo we leave
* tied mode in init once we know to what cr44 should be restored on exit
*
* the owner parameter is slightly abused:
* 0 and 1 are treated as head values and so the set value is (owner * 3)
* other values are treated as literal values to set
*/
u8
nv_rdvgaowner(void *obj)
{
if (nv_device(obj)->card_type < NV_50) {
if (nv_device(obj)->chipset == 0x11) {
u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
if (tied == 0) {
u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
if (slA && !tvA) return 0x00;
if (slB && !tvB) return 0x03;
if (slA) return 0x00;
if (slB) return 0x03;
return 0x00;
}
return 0x04;
}
return nv_rdvgac(obj, 0, 0x44);
}
nv_error(obj, "rdvgaowner after nv4x\n");
return 0x00;
}
void
nv_wrvgaowner(void *obj, u8 select)
{
if (nv_device(obj)->card_type < NV_50) {
u8 owner = (select == 1) ? 3 : select;
if (nv_device(obj)->chipset == 0x11) {
/* workaround hw lockup bug */
nv_rdvgac(obj, 0, 0x1f);
nv_rdvgac(obj, 1, 0x1f);
}
nv_wrvgac(obj, 0, 0x44, owner);
if (nv_device(obj)->chipset == 0x11) {
nv_wrvgac(obj, 0, 0x2e, owner);
nv_wrvgac(obj, 0, 0x2e, owner);
}
} else
nv_error(obj, "wrvgaowner after nv4x\n");
}

View file

@ -0,0 +1,165 @@
/*
* 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/object.h>
#include <core/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/fb.h>
#include <subdev/instmem.h>
#include "priv.h"
static int
nvkm_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent,
struct nouveau_gpuobj **pgpuobj)
{
const struct nvkm_dmaeng_impl *impl = (void *)
nv_oclass(nv_object(dmaobj)->engine);
int ret = 0;
if (nv_object(dmaobj) == parent) { /* ctor bind */
if (nv_mclass(parent->parent) == NV_DEVICE) {
/* delayed, or no, binding */
return 0;
}
ret = impl->bind(dmaobj, parent, pgpuobj);
if (ret == 0)
nouveau_object_ref(NULL, &parent);
return ret;
}
return impl->bind(dmaobj, parent, pgpuobj);
}
int
nvkm_dmaobj_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void **pdata, u32 *psize,
int length, void **pobject)
{
union {
struct nv_dma_v0 v0;
} *args = *pdata;
struct nouveau_instmem *instmem = nouveau_instmem(parent);
struct nouveau_client *client = nouveau_client(parent);
struct nouveau_device *device = nv_device(parent);
struct nouveau_fb *pfb = nouveau_fb(parent);
struct nouveau_dmaobj *dmaobj;
void *data = *pdata;
u32 size = *psize;
int ret;
ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
dmaobj = *pobject;
if (ret)
return ret;
nv_ioctl(parent, "create dma size %d\n", *psize);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(parent, "create dma vers %d target %d access %d "
"start %016llx limit %016llx\n",
args->v0.version, args->v0.target, args->v0.access,
args->v0.start, args->v0.limit);
dmaobj->target = args->v0.target;
dmaobj->access = args->v0.access;
dmaobj->start = args->v0.start;
dmaobj->limit = args->v0.limit;
} else
return ret;
*pdata = data;
*psize = size;
if (dmaobj->start > dmaobj->limit)
return -EINVAL;
switch (dmaobj->target) {
case NV_DMA_V0_TARGET_VM:
dmaobj->target = NV_MEM_TARGET_VM;
break;
case NV_DMA_V0_TARGET_VRAM:
if (!client->super) {
if (dmaobj->limit >= pfb->ram->size - instmem->reserved)
return -EACCES;
if (device->card_type >= NV_50)
return -EACCES;
}
dmaobj->target = NV_MEM_TARGET_VRAM;
break;
case NV_DMA_V0_TARGET_PCI:
if (!client->super)
return -EACCES;
dmaobj->target = NV_MEM_TARGET_PCI;
break;
case NV_DMA_V0_TARGET_PCI_US:
case NV_DMA_V0_TARGET_AGP:
if (!client->super)
return -EACCES;
dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP;
break;
default:
return -EINVAL;
}
switch (dmaobj->access) {
case NV_DMA_V0_ACCESS_VM:
dmaobj->access = NV_MEM_ACCESS_VM;
break;
case NV_DMA_V0_ACCESS_RD:
dmaobj->access = NV_MEM_ACCESS_RO;
break;
case NV_DMA_V0_ACCESS_WR:
dmaobj->access = NV_MEM_ACCESS_WO;
break;
case NV_DMA_V0_ACCESS_RDWR:
dmaobj->access = NV_MEM_ACCESS_RW;
break;
default:
return -EINVAL;
}
return ret;
}
int
_nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
const struct nvkm_dmaeng_impl *impl = (void *)oclass;
struct nouveau_dmaeng *dmaeng;
int ret;
ret = nouveau_engine_create(parent, engine, oclass, true, "DMAOBJ",
"dmaobj", &dmaeng);
*pobject = nv_object(dmaeng);
if (ret)
return ret;
nv_engine(dmaeng)->sclass = impl->sclass;
dmaeng->bind = nvkm_dmaobj_bind;
return 0;
}

View file

@ -0,0 +1,165 @@
/*
* 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/gpuobj.h>
#include <nvif/class.h>
#include <subdev/fb.h>
#include <subdev/vm/nv04.h>
#include "priv.h"
struct nv04_dmaobj_priv {
struct nouveau_dmaobj base;
bool clone;
u32 flags0;
u32 flags2;
};
static int
nv04_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent,
struct nouveau_gpuobj **pgpuobj)
{
struct nv04_dmaobj_priv *priv = (void *)dmaobj;
struct nouveau_gpuobj *gpuobj;
u64 offset = priv->base.start & 0xfffff000;
u64 adjust = priv->base.start & 0x00000fff;
u32 length = priv->base.limit - priv->base.start;
int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
switch (nv_mclass(parent->parent)) {
case NV03_CHANNEL_DMA:
case NV10_CHANNEL_DMA:
case NV17_CHANNEL_DMA:
case NV40_CHANNEL_DMA:
break;
default:
return -EINVAL;
}
}
if (priv->clone) {
struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaobj);
struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
if (!dmaobj->start)
return nouveau_gpuobj_dup(parent, pgt, pgpuobj);
offset = nv_ro32(pgt, 8 + (offset >> 10));
offset &= 0xfffff000;
}
ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
*pgpuobj = gpuobj;
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20));
nv_wo32(*pgpuobj, 0x04, length);
nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset);
nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset);
}
return ret;
}
static int
nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
struct nv04_vmmgr_priv *vmm = nv04_vmmgr(engine);
struct nv04_dmaobj_priv *priv;
int ret;
ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
*pobject = nv_object(priv);
if (ret || (ret = -ENOSYS, size))
return ret;
if (priv->base.target == NV_MEM_TARGET_VM) {
if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass)
priv->clone = true;
priv->base.target = NV_MEM_TARGET_PCI;
priv->base.access = NV_MEM_ACCESS_RW;
}
priv->flags0 = nv_mclass(priv);
switch (priv->base.target) {
case NV_MEM_TARGET_VRAM:
priv->flags0 |= 0x00003000;
break;
case NV_MEM_TARGET_PCI:
priv->flags0 |= 0x00023000;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
priv->flags0 |= 0x00033000;
break;
default:
return -EINVAL;
}
switch (priv->base.access) {
case NV_MEM_ACCESS_RO:
priv->flags0 |= 0x00004000;
break;
case NV_MEM_ACCESS_WO:
priv->flags0 |= 0x00008000;
case NV_MEM_ACCESS_RW:
priv->flags2 |= 0x00000002;
break;
default:
return -EINVAL;
}
return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}
static struct nouveau_ofuncs
nv04_dmaobj_ofuncs = {
.ctor = nv04_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nv04_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs },
{}
};
struct nouveau_oclass *
nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0x04),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nvkm_dmaeng_ctor,
.dtor = _nvkm_dmaeng_dtor,
.init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini,
},
.sclass = nv04_dmaeng_sclass,
.bind = nv04_dmaobj_bind,
}.base;

View file

@ -0,0 +1,197 @@
/*
* 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/client.h>
#include <core/gpuobj.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/fb.h>
#include "priv.h"
struct nv50_dmaobj_priv {
struct nouveau_dmaobj base;
u32 flags0;
u32 flags5;
};
static int
nv50_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent,
struct nouveau_gpuobj **pgpuobj)
{
struct nv50_dmaobj_priv *priv = (void *)dmaobj;
int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
switch (nv_mclass(parent->parent)) {
case NV40_CHANNEL_DMA:
case NV50_CHANNEL_GPFIFO:
case G82_CHANNEL_GPFIFO:
case NV50_DISP_CORE_CHANNEL_DMA:
case G82_DISP_CORE_CHANNEL_DMA:
case GT206_DISP_CORE_CHANNEL_DMA:
case GT200_DISP_CORE_CHANNEL_DMA:
case GT214_DISP_CORE_CHANNEL_DMA:
case NV50_DISP_BASE_CHANNEL_DMA:
case G82_DISP_BASE_CHANNEL_DMA:
case GT200_DISP_BASE_CHANNEL_DMA:
case GT214_DISP_BASE_CHANNEL_DMA:
case NV50_DISP_OVERLAY_CHANNEL_DMA:
case G82_DISP_OVERLAY_CHANNEL_DMA:
case GT200_DISP_OVERLAY_CHANNEL_DMA:
case GT214_DISP_OVERLAY_CHANNEL_DMA:
break;
default:
return -EINVAL;
}
}
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
upper_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, priv->flags5);
}
return ret;
}
static int
nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
union {
struct nv50_dma_v0 v0;
} *args;
struct nv50_dmaobj_priv *priv;
u32 user, part, comp, kind;
int ret;
ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
args = data;
nv_ioctl(parent, "create nv50 dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d "
"comp %d kind %02x\n", args->v0.version,
args->v0.priv, args->v0.part, args->v0.comp,
args->v0.kind);
user = args->v0.priv;
part = args->v0.part;
comp = args->v0.comp;
kind = args->v0.kind;
} else
if (size == 0) {
if (priv->base.target != NV_MEM_TARGET_VM) {
user = NV50_DMA_V0_PRIV_US;
part = NV50_DMA_V0_PART_256;
comp = NV50_DMA_V0_COMP_NONE;
kind = NV50_DMA_V0_KIND_PITCH;
} else {
user = NV50_DMA_V0_PRIV_VM;
part = NV50_DMA_V0_PART_VM;
comp = NV50_DMA_V0_COMP_VM;
kind = NV50_DMA_V0_KIND_VM;
}
} else
return ret;
if (user > 2 || part > 2 || comp > 3 || kind > 0x7f)
return -EINVAL;
priv->flags0 = (comp << 29) | (kind << 22) | (user << 20);
priv->flags5 = (part << 16);
switch (priv->base.target) {
case NV_MEM_TARGET_VM:
priv->flags0 |= 0x00000000;
break;
case NV_MEM_TARGET_VRAM:
priv->flags0 |= 0x00010000;
break;
case NV_MEM_TARGET_PCI:
priv->flags0 |= 0x00020000;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
priv->flags0 |= 0x00030000;
break;
default:
return -EINVAL;
}
switch (priv->base.access) {
case NV_MEM_ACCESS_VM:
break;
case NV_MEM_ACCESS_RO:
priv->flags0 |= 0x00040000;
break;
case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW:
priv->flags0 |= 0x00080000;
break;
default:
return -EINVAL;
}
return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}
static struct nouveau_ofuncs
nv50_dmaobj_ofuncs = {
.ctor = nv50_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nv50_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs },
{}
};
struct nouveau_oclass *
nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0x50),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nvkm_dmaeng_ctor,
.dtor = _nvkm_dmaeng_dtor,
.init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini,
},
.sclass = nv50_dmaeng_sclass,
.bind = nv50_dmaobj_bind,
}.base;

View file

@ -0,0 +1,179 @@
/*
* 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/client.h>
#include <core/device.h>
#include <core/gpuobj.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/fb.h>
#include "priv.h"
struct nvc0_dmaobj_priv {
struct nouveau_dmaobj base;
u32 flags0;
u32 flags5;
};
static int
nvc0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent,
struct nouveau_gpuobj **pgpuobj)
{
struct nvc0_dmaobj_priv *priv = (void *)dmaobj;
int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
switch (nv_mclass(parent->parent)) {
case GT214_DISP_CORE_CHANNEL_DMA:
case GT214_DISP_BASE_CHANNEL_DMA:
case GT214_DISP_OVERLAY_CHANNEL_DMA:
break;
default:
return -EINVAL;
}
} else
return 0;
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
upper_32_bits(priv->base.start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, priv->flags5);
}
return ret;
}
static int
nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
union {
struct gf100_dma_v0 v0;
} *args;
struct nvc0_dmaobj_priv *priv;
u32 kind, user, unkn;
int ret;
ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
args = data;
nv_ioctl(parent, "create gf100 dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n",
args->v0.version, args->v0.priv, args->v0.kind);
kind = args->v0.kind;
user = args->v0.priv;
unkn = 0;
} else
if (size == 0) {
if (priv->base.target != NV_MEM_TARGET_VM) {
kind = GF100_DMA_V0_KIND_PITCH;
user = GF100_DMA_V0_PRIV_US;
unkn = 2;
} else {
kind = GF100_DMA_V0_KIND_VM;
user = GF100_DMA_V0_PRIV_VM;
unkn = 0;
}
} else
return ret;
if (user > 2)
return -EINVAL;
priv->flags0 |= (kind << 22) | (user << 20);
priv->flags5 |= (unkn << 16);
switch (priv->base.target) {
case NV_MEM_TARGET_VM:
priv->flags0 |= 0x00000000;
break;
case NV_MEM_TARGET_VRAM:
priv->flags0 |= 0x00010000;
break;
case NV_MEM_TARGET_PCI:
priv->flags0 |= 0x00020000;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
priv->flags0 |= 0x00030000;
break;
default:
return -EINVAL;
}
switch (priv->base.access) {
case NV_MEM_ACCESS_VM:
break;
case NV_MEM_ACCESS_RO:
priv->flags0 |= 0x00040000;
break;
case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW:
priv->flags0 |= 0x00080000;
break;
}
return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}
static struct nouveau_ofuncs
nvc0_dmaobj_ofuncs = {
.ctor = nvc0_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nvc0_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY, &nvc0_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY, &nvc0_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY, &nvc0_dmaobj_ofuncs },
{}
};
struct nouveau_oclass *
nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0xc0),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nvkm_dmaeng_ctor,
.dtor = _nvkm_dmaeng_dtor,
.init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini,
},
.sclass = nvc0_dmaeng_sclass,
.bind = nvc0_dmaobj_bind,
}.base;

View file

@ -0,0 +1,167 @@
/*
* 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/client.h>
#include <core/device.h>
#include <core/gpuobj.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/fb.h>
#include "priv.h"
struct nvd0_dmaobj_priv {
struct nouveau_dmaobj base;
u32 flags0;
};
static int
nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
struct nouveau_object *parent,
struct nouveau_gpuobj **pgpuobj)
{
struct nvd0_dmaobj_priv *priv = (void *)dmaobj;
int ret;
if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
switch (nv_mclass(parent->parent)) {
case GF110_DISP_CORE_CHANNEL_DMA:
case GK104_DISP_CORE_CHANNEL_DMA:
case GK110_DISP_CORE_CHANNEL_DMA:
case GM107_DISP_CORE_CHANNEL_DMA:
case GF110_DISP_BASE_CHANNEL_DMA:
case GK104_DISP_BASE_CHANNEL_DMA:
case GK110_DISP_BASE_CHANNEL_DMA:
case GF110_DISP_OVERLAY_CONTROL_DMA:
case GK104_DISP_OVERLAY_CONTROL_DMA:
break;
default:
return -EINVAL;
}
} else
return 0;
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, priv->flags0);
nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8);
nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8);
nv_wo32(*pgpuobj, 0x0c, 0x00000000);
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, 0x00000000);
}
return ret;
}
static int
nvd0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
union {
struct gf110_dma_v0 v0;
} *args;
struct nvd0_dmaobj_priv *priv;
u32 kind, page;
int ret;
ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
args = data;
nv_ioctl(parent, "create gf110 dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n",
args->v0.version, args->v0.page, args->v0.kind);
kind = args->v0.kind;
page = args->v0.page;
} else
if (size == 0) {
if (priv->base.target != NV_MEM_TARGET_VM) {
kind = GF110_DMA_V0_KIND_PITCH;
page = GF110_DMA_V0_PAGE_SP;
} else {
kind = GF110_DMA_V0_KIND_VM;
page = GF110_DMA_V0_PAGE_LP;
}
} else
return ret;
if (page > 1)
return -EINVAL;
priv->flags0 = (kind << 20) | (page << 6);
switch (priv->base.target) {
case NV_MEM_TARGET_VRAM:
priv->flags0 |= 0x00000009;
break;
case NV_MEM_TARGET_VM:
case NV_MEM_TARGET_PCI:
case NV_MEM_TARGET_PCI_NOSNOOP:
/* XXX: don't currently know how to construct a real one
* of these. we only use them to represent pushbufs
* on these chipsets, and the classes that use them
* deal with the target themselves.
*/
break;
default:
return -EINVAL;
}
return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
}
static struct nouveau_ofuncs
nvd0_dmaobj_ofuncs = {
.ctor = nvd0_dmaobj_ctor,
.dtor = _nvkm_dmaobj_dtor,
.init = _nvkm_dmaobj_init,
.fini = _nvkm_dmaobj_fini,
};
static struct nouveau_oclass
nvd0_dmaeng_sclass[] = {
{ NV_DMA_FROM_MEMORY, &nvd0_dmaobj_ofuncs },
{ NV_DMA_TO_MEMORY, &nvd0_dmaobj_ofuncs },
{ NV_DMA_IN_MEMORY, &nvd0_dmaobj_ofuncs },
{}
};
struct nouveau_oclass *
nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
.base.handle = NV_ENGINE(DMAOBJ, 0xd0),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nvkm_dmaeng_ctor,
.dtor = _nvkm_dmaeng_dtor,
.init = _nvkm_dmaeng_init,
.fini = _nvkm_dmaeng_fini,
},
.sclass = nvd0_dmaeng_sclass,
.bind = nvd0_dmaobj_bind,
}.base;

View file

@ -0,0 +1,30 @@
#ifndef __NVKM_DMAOBJ_PRIV_H__
#define __NVKM_DMAOBJ_PRIV_H__
#include <engine/dmaobj.h>
#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \
nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d)
int nvkm_dmaobj_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void **, u32 *,
int, void **);
#define _nvkm_dmaobj_dtor nouveau_object_destroy
#define _nvkm_dmaobj_init nouveau_object_init
#define _nvkm_dmaobj_fini nouveau_object_fini
int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
#define _nvkm_dmaeng_dtor _nouveau_engine_dtor
#define _nvkm_dmaeng_init _nouveau_engine_init
#define _nvkm_dmaeng_fini _nouveau_engine_fini
struct nvkm_dmaeng_impl {
struct nouveau_oclass base;
struct nouveau_oclass *sclass;
int (*bind)(struct nouveau_dmaobj *, struct nouveau_object *,
struct nouveau_gpuobj **);
};
#endif

View file

@ -0,0 +1,278 @@
/*
* 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.
*/
#include <engine/falcon.h>
#include <subdev/timer.h>
void
nouveau_falcon_intr(struct nouveau_subdev *subdev)
{
struct nouveau_falcon *falcon = (void *)subdev;
u32 dispatch = nv_ro32(falcon, 0x01c);
u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
if (intr & 0x00000010) {
nv_debug(falcon, "ucode halted\n");
nv_wo32(falcon, 0x004, 0x00000010);
intr &= ~0x00000010;
}
if (intr) {
nv_error(falcon, "unhandled intr 0x%08x\n", intr);
nv_wo32(falcon, 0x004, intr);
}
}
u32
_nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
{
struct nouveau_falcon *falcon = (void *)object;
return nv_rd32(falcon, falcon->addr + addr);
}
void
_nouveau_falcon_wr32(struct nouveau_object *object, u64 addr, u32 data)
{
struct nouveau_falcon *falcon = (void *)object;
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)
{
struct nouveau_device *device = nv_device(object);
struct nouveau_falcon *falcon = (void *)object;
const struct firmware *fw;
char name[32] = "internal";
int ret, i;
u32 caps;
/* enable engine, and determine its capabilities */
ret = nouveau_engine_init(&falcon->base);
if (ret)
return ret;
if (device->chipset < 0xa3 ||
device->chipset == 0xaa || device->chipset == 0xac) {
falcon->version = 0;
falcon->secret = (falcon->addr == 0x087000) ? 1 : 0;
} else {
caps = nv_ro32(falcon, 0x12c);
falcon->version = (caps & 0x0000000f);
falcon->secret = (caps & 0x00000030) >> 4;
}
caps = nv_ro32(falcon, 0x108);
falcon->code.limit = (caps & 0x000001ff) << 8;
falcon->data.limit = (caps & 0x0003fe00) >> 1;
nv_debug(falcon, "falcon version: %d\n", falcon->version);
nv_debug(falcon, "secret level: %d\n", falcon->secret);
nv_debug(falcon, "code limit: %d\n", falcon->code.limit);
nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
/* wait for 'uc halted' to be signalled before continuing */
if (falcon->secret && falcon->version < 4) {
if (!falcon->version)
nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
else
nv_wait(falcon, 0x180, 0x80000000, 0);
nv_wo32(falcon, 0x004, 0x00000010);
}
/* disable all interrupts */
nv_wo32(falcon, 0x014, 0xffffffff);
/* no default ucode provided by the engine implementation, try and
* locate a "self-bootstrapping" firmware image for the engine
*/
if (!falcon->code.data) {
snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
device->chipset, falcon->addr >> 12);
ret = request_firmware(&fw, name, nv_device_base(device));
if (ret == 0) {
falcon->code.data = vmemdup(fw->data, fw->size);
falcon->code.size = fw->size;
falcon->data.data = NULL;
falcon->data.size = 0;
release_firmware(fw);
}
falcon->external = true;
}
/* next step is to try and load "static code/data segment" firmware
* images for the engine
*/
if (!falcon->code.data) {
snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
device->chipset, falcon->addr >> 12);
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 = vmemdup(fw->data, fw->size);
falcon->data.size = fw->size;
release_firmware(fw);
if (!falcon->data.data)
return -ENOMEM;
snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
device->chipset, falcon->addr >> 12);
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 = vmemdup(fw->data, fw->size);
falcon->code.size = fw->size;
release_firmware(fw);
if (!falcon->code.data)
return -ENOMEM;
}
nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ?
"static code/data segments" : "self-bootstrapping");
/* ensure any "self-bootstrapping" firmware image is in vram */
if (!falcon->data.data && !falcon->core) {
ret = nouveau_gpuobj_new(object->parent, NULL,
falcon->code.size, 256, 0,
&falcon->core);
if (ret) {
nv_error(falcon, "core allocation failed, %d\n", ret);
return ret;
}
for (i = 0; i < falcon->code.size; i += 4)
nv_wo32(falcon->core, i, falcon->code.data[i / 4]);
}
/* upload firmware bootloader (or the full code segments) */
if (falcon->core) {
if (device->card_type < NV_C0)
nv_wo32(falcon, 0x618, 0x04000000);
else
nv_wo32(falcon, 0x618, 0x00000114);
nv_wo32(falcon, 0x11c, 0);
nv_wo32(falcon, 0x110, falcon->core->addr >> 8);
nv_wo32(falcon, 0x114, 0);
nv_wo32(falcon, 0x118, 0x00006610);
} else {
if (falcon->code.size > falcon->code.limit ||
falcon->data.size > falcon->data.limit) {
nv_error(falcon, "ucode exceeds falcon limit(s)\n");
return -EINVAL;
}
if (falcon->version < 3) {
nv_wo32(falcon, 0xff8, 0x00100000);
for (i = 0; i < falcon->code.size / 4; i++)
nv_wo32(falcon, 0xff4, falcon->code.data[i]);
} else {
nv_wo32(falcon, 0x180, 0x01000000);
for (i = 0; i < falcon->code.size / 4; i++) {
if ((i & 0x3f) == 0)
nv_wo32(falcon, 0x188, i >> 6);
nv_wo32(falcon, 0x184, falcon->code.data[i]);
}
}
}
/* upload data segment (if necessary), zeroing the remainder */
if (falcon->version < 3) {
nv_wo32(falcon, 0xff8, 0x00000000);
for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
nv_wo32(falcon, 0xff4, falcon->data.data[i]);
for (; i < falcon->data.limit; i += 4)
nv_wo32(falcon, 0xff4, 0x00000000);
} else {
nv_wo32(falcon, 0x1c0, 0x01000000);
for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
nv_wo32(falcon, 0x1c4, falcon->data.data[i]);
for (; i < falcon->data.limit / 4; i++)
nv_wo32(falcon, 0x1c4, 0x00000000);
}
/* start it running */
nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */
nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */
nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */
nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */
return 0;
}
int
_nouveau_falcon_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_falcon *falcon = (void *)object;
if (!suspend) {
nouveau_gpuobj_ref(NULL, &falcon->core);
if (falcon->external) {
vfree(falcon->data.data);
vfree(falcon->code.data);
falcon->code.data = NULL;
}
}
nv_mo32(falcon, 0x048, 0x00000003, 0x00000000);
nv_wo32(falcon, 0x014, 0xffffffff);
return nouveau_engine_fini(&falcon->base, suspend);
}
int
nouveau_falcon_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, u32 addr, bool enable,
const char *iname, const char *fname,
int length, void **pobject)
{
struct nouveau_falcon *falcon;
int ret;
ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
fname, length, pobject);
falcon = *pobject;
if (ret)
return ret;
falcon->addr = addr;
return 0;
}

View file

@ -0,0 +1,283 @@
/*
* 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/client.h>
#include <core/object.h>
#include <core/handle.h>
#include <core/event.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <nvif/event.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
static int
nouveau_fifo_event_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
if (size == 0) {
notify->size = 0;
notify->types = 1;
notify->index = 0;
return 0;
}
return -ENOSYS;
}
static const struct nvkm_event_func
nouveau_fifo_event_func = {
.ctor = nouveau_fifo_event_ctor,
};
int
nouveau_fifo_channel_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
int bar, u32 addr, u32 size, u32 pushbuf,
u64 engmask, int len, void **ptr)
{
struct nouveau_device *device = nv_device(engine);
struct nouveau_fifo *priv = (void *)engine;
struct nouveau_fifo_chan *chan;
struct nouveau_dmaeng *dmaeng;
unsigned long flags;
int ret;
/* create base object class */
ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
engmask, len, ptr);
chan = *ptr;
if (ret)
return ret;
/* validate dma object representing push buffer */
chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
if (!chan->pushdma)
return -ENOENT;
dmaeng = (void *)chan->pushdma->base.engine;
switch (chan->pushdma->base.oclass->handle) {
case NV_DMA_FROM_MEMORY:
case NV_DMA_IN_MEMORY:
break;
default:
return -EINVAL;
}
ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu);
if (ret)
return ret;
/* find a free fifo channel */
spin_lock_irqsave(&priv->lock, flags);
for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
if (!priv->channel[chan->chid]) {
priv->channel[chan->chid] = nv_object(chan);
break;
}
}
spin_unlock_irqrestore(&priv->lock, flags);
if (chan->chid == priv->max) {
nv_error(priv, "no free channels\n");
return -ENOSPC;
}
chan->addr = nv_device_resource_start(device, bar) +
addr + size * chan->chid;
chan->size = size;
nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
return 0;
}
void
nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan)
{
struct nouveau_fifo *priv = (void *)nv_object(chan)->engine;
unsigned long flags;
if (chan->user)
iounmap(chan->user);
spin_lock_irqsave(&priv->lock, flags);
priv->channel[chan->chid] = NULL;
spin_unlock_irqrestore(&priv->lock, flags);
nouveau_gpuobj_ref(NULL, &chan->pushgpu);
nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma);
nouveau_namedb_destroy(&chan->base);
}
void
_nouveau_fifo_channel_dtor(struct nouveau_object *object)
{
struct nouveau_fifo_chan *chan = (void *)object;
nouveau_fifo_channel_destroy(chan);
}
int
_nouveau_fifo_channel_map(struct nouveau_object *object, u64 *addr, u32 *size)
{
struct nouveau_fifo_chan *chan = (void *)object;
*addr = chan->addr;
*size = chan->size;
return 0;
}
u32
_nouveau_fifo_channel_rd32(struct nouveau_object *object, u64 addr)
{
struct nouveau_fifo_chan *chan = (void *)object;
if (unlikely(!chan->user)) {
chan->user = ioremap(chan->addr, chan->size);
if (WARN_ON_ONCE(chan->user == NULL))
return 0;
}
return ioread32_native(chan->user + addr);
}
void
_nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data)
{
struct nouveau_fifo_chan *chan = (void *)object;
if (unlikely(!chan->user)) {
chan->user = ioremap(chan->addr, chan->size);
if (WARN_ON_ONCE(chan->user == NULL))
return;
}
iowrite32_native(data, chan->user + addr);
}
int
nouveau_fifo_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
union {
struct nvif_notify_uevent_req none;
} *req = data;
int ret;
if (nvif_unvers(req->none)) {
notify->size = sizeof(struct nvif_notify_uevent_rep);
notify->types = 1;
notify->index = 0;
}
return ret;
}
void
nouveau_fifo_uevent(struct nouveau_fifo *fifo)
{
struct nvif_notify_uevent_rep rep = {
};
nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
}
int
_nouveau_fifo_channel_ntfy(struct nouveau_object *object, u32 type,
struct nvkm_event **event)
{
struct nouveau_fifo *fifo = (void *)object->engine;
switch (type) {
case G82_CHANNEL_DMA_V0_NTFY_UEVENT:
if (nv_mclass(object) >= G82_CHANNEL_DMA) {
*event = &fifo->uevent;
return 0;
}
break;
default:
break;
}
return -EINVAL;
}
static int
nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object)
{
int engidx = nv_hclass(priv) & 0xff;
while (object && object->parent) {
if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
(nv_hclass(object->parent) & 0xff) == engidx)
return nouveau_fifo_chan(object)->chid;
object = object->parent;
}
return -1;
}
const char *
nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid)
{
struct nouveau_fifo_chan *chan = NULL;
unsigned long flags;
spin_lock_irqsave(&fifo->lock, flags);
if (chid >= fifo->min && chid <= fifo->max)
chan = (void *)fifo->channel[chid];
spin_unlock_irqrestore(&fifo->lock, flags);
return nouveau_client_name(chan);
}
void
nouveau_fifo_destroy(struct nouveau_fifo *priv)
{
kfree(priv->channel);
nvkm_event_fini(&priv->uevent);
nvkm_event_fini(&priv->cevent);
nouveau_engine_destroy(&priv->base);
}
int
nouveau_fifo_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
int min, int max, int length, void **pobject)
{
struct nouveau_fifo *priv;
int ret;
ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO",
"fifo", length, pobject);
priv = *pobject;
if (ret)
return ret;
priv->min = min;
priv->max = max;
priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
if (!priv->channel)
return -ENOMEM;
ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent);
if (ret)
return ret;
priv->chid = nouveau_fifo_chid;
spin_lock_init(&priv->lock);
return 0;
}

View file

@ -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;

View file

@ -0,0 +1,656 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <core/engctx.h>
#include <core/namedb.h>
#include <core/handle.h>
#include <core/ramht.h>
#include <core/event.h>
#include <subdev/instmem.h>
#include <subdev/instmem/nv04.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include "nv04.h"
static struct ramfc_desc
nv04_ramfc[] = {
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
{ 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
{ 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
{ 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE },
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE },
{ 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 },
{}
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
int
nv04_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
u32 context, chid = chan->base.chid;
int ret;
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->addr >> 4;
else
context = 0x00000004; /* just non-zero */
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW:
context |= 0x00000000;
break;
case NVDEV_ENGINE_GR:
context |= 0x00010000;
break;
case NVDEV_ENGINE_MPEG:
context |= 0x00020000;
break;
default:
return -EINVAL;
}
context |= 0x80000000; /* valid */
context |= chid << 24;
mutex_lock(&nv_subdev(priv)->mutex);
ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
mutex_unlock(&nv_subdev(priv)->mutex);
return ret;
}
void
nv04_fifo_object_detach(struct nouveau_object *parent, int cookie)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
mutex_lock(&nv_subdev(priv)->mutex);
nouveau_ramht_remove(priv->ramht, cookie);
mutex_unlock(&nv_subdev(priv)->mutex);
}
int
nv04_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
nv_engctx(object)->addr = nouveau_fifo_chan(parent)->chid;
return 0;
}
static int
nv04_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv03_channel_dma_v0 v0;
} *args = data;
struct nv04_fifo_priv *priv = (void *)engine;
struct nv04_fifo_chan *chan;
int ret;
nv_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
nv_parent(chan)->context_attach = nv04_fifo_context_attach;
chan->ramfc = chan->base.chid * 32;
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + 0x10,
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
return 0;
}
void
nv04_fifo_chan_dtor(struct nouveau_object *object)
{
struct nv04_fifo_priv *priv = (void *)object->engine;
struct nv04_fifo_chan *chan = (void *)object;
struct ramfc_desc *c = priv->ramfc_desc;
do {
nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
} while ((++c)->bits);
nouveau_fifo_channel_destroy(&chan->base);
}
int
nv04_fifo_chan_init(struct nouveau_object *object)
{
struct nv04_fifo_priv *priv = (void *)object->engine;
struct nv04_fifo_chan *chan = (void *)object;
u32 mask = 1 << chan->base.chid;
unsigned long flags;
int ret;
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
spin_lock_irqsave(&priv->base.lock, flags);
nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
spin_unlock_irqrestore(&priv->base.lock, flags);
return 0;
}
int
nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend)
{
struct nv04_fifo_priv *priv = (void *)object->engine;
struct nv04_fifo_chan *chan = (void *)object;
struct nouveau_gpuobj *fctx = priv->ramfc;
struct ramfc_desc *c;
unsigned long flags;
u32 data = chan->ramfc;
u32 chid;
/* prevent fifo context switches */
spin_lock_irqsave(&priv->base.lock, flags);
nv_wr32(priv, NV03_PFIFO_CACHES, 0);
/* if this channel is active, replace it with a null context */
chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
if (chid == chan->base.chid) {
nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
c = priv->ramfc_desc;
do {
u32 rm = ((1ULL << c->bits) - 1) << c->regs;
u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs;
u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
} while ((++c)->bits);
c = priv->ramfc_desc;
do {
nv_wr32(priv, c->regp, 0x00000000);
} while ((++c)->bits);
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
}
/* restore normal operation, after disabling dma mode */
nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
spin_unlock_irqrestore(&priv->base.lock, flags);
return nouveau_fifo_channel_fini(&chan->base, suspend);
}
static struct nouveau_ofuncs
nv04_fifo_ofuncs = {
.ctor = nv04_fifo_chan_ctor,
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_oclass
nv04_fifo_sclass[] = {
{ NV03_CHANNEL_DMA, &nv04_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
int
nv04_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
0x1000, NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
return ret;
return 0;
}
static struct nouveau_oclass
nv04_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_context_ctor,
.dtor = _nouveau_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
void
nv04_fifo_pause(struct nouveau_fifo *pfifo, unsigned long *pflags)
__acquires(priv->base.lock)
{
struct nv04_fifo_priv *priv = (void *)pfifo;
unsigned long flags;
spin_lock_irqsave(&priv->base.lock, flags);
*pflags = flags;
nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
/* in some cases the puller may be left in an inconsistent state
* if you try to stop it while it's busy translating handles.
* sometimes you get a CACHE_ERROR, sometimes it just fails
* silently; sending incorrect instance offsets to PGRAPH after
* it's started up again.
*
* to avoid this, we invalidate the most recently calculated
* instance.
*/
if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
nv_warn(priv, "timeout idling puller\n");
if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
}
void
nv04_fifo_start(struct nouveau_fifo *pfifo, unsigned long *pflags)
__releases(priv->base.lock)
{
struct nv04_fifo_priv *priv = (void *)pfifo;
unsigned long flags = *pflags;
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
spin_unlock_irqrestore(&priv->base.lock, flags);
}
static const char *
nv_dma_state_err(u32 state)
{
static const char * const desc[] = {
"NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
"INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK"
};
return desc[(state >> 29) & 0x7];
}
static bool
nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
{
struct nv04_fifo_chan *chan = NULL;
struct nouveau_handle *bind;
const int subc = (addr >> 13) & 0x7;
const int mthd = addr & 0x1ffc;
bool handled = false;
unsigned long flags;
u32 engine;
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;
switch (mthd) {
case 0x0000:
bind = nouveau_namedb_get(nv_namedb(chan), data);
if (unlikely(!bind))
break;
if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
engine = 0x0000000f << (subc * 4);
chan->subc[subc] = data;
handled = true;
nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
}
nouveau_namedb_put(bind);
break;
default:
engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
break;
bind = nouveau_namedb_get(nv_namedb(chan), chan->subc[subc]);
if (likely(bind)) {
if (!nv_call(bind->object, mthd, data))
handled = true;
nouveau_namedb_put(bind);
}
break;
}
out:
spin_unlock_irqrestore(&priv->base.lock, flags);
return handled;
}
static void
nv04_fifo_cache_error(struct nouveau_device *device,
struct nv04_fifo_priv *priv, u32 chid, u32 get)
{
u32 mthd, data;
int ptr;
/* NV_PFIFO_CACHE1_GET actually goes to 0xffc before wrapping on my
* G80 chips, but CACHE1 isn't big enough for this much data.. Tests
* show that it wraps around to the start at GET=0x800.. No clue as to
* why..
*/
ptr = (get & 0x7ff) >> 2;
if (device->card_type < NV_40) {
mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr));
data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr));
} else {
mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr));
data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr));
}
if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
const char *client_name =
nouveau_client_name_for_fifo_chid(&priv->base, chid);
nv_error(priv,
"CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc,
data);
}
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
}
static void
nv04_fifo_dma_pusher(struct nouveau_device *device, struct nv04_fifo_priv *priv,
u32 chid)
{
const char *client_name;
u32 dma_get = nv_rd32(priv, 0x003244);
u32 dma_put = nv_rd32(priv, 0x003240);
u32 push = nv_rd32(priv, 0x003220);
u32 state = nv_rd32(priv, 0x003228);
client_name = nouveau_client_name_for_fifo_chid(&priv->base, chid);
if (device->card_type == NV_50) {
u32 ho_get = nv_rd32(priv, 0x003328);
u32 ho_put = nv_rd32(priv, 0x003320);
u32 ib_get = nv_rd32(priv, 0x003334);
u32 ib_put = nv_rd32(priv, 0x003330);
nv_error(priv,
"DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
chid, client_name, ho_get, dma_get, ho_put, dma_put,
ib_get, ib_put, state, nv_dma_state_err(state), push);
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
nv_wr32(priv, 0x003364, 0x00000000);
if (dma_get != dma_put || ho_get != ho_put) {
nv_wr32(priv, 0x003244, dma_put);
nv_wr32(priv, 0x003328, ho_put);
} else
if (ib_get != ib_put)
nv_wr32(priv, 0x003334, ib_put);
} else {
nv_error(priv,
"DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
chid, client_name, dma_get, dma_put, state,
nv_dma_state_err(state), push);
if (dma_get != dma_put)
nv_wr32(priv, 0x003244, dma_put);
}
nv_wr32(priv, 0x003228, 0x00000000);
nv_wr32(priv, 0x003220, 0x00000001);
nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
}
void
nv04_fifo_intr(struct nouveau_subdev *subdev)
{
struct nouveau_device *device = nv_device(subdev);
struct nv04_fifo_priv *priv = (void *)subdev;
uint32_t status, reassign;
int cnt = 0;
reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
uint32_t chid, get;
nv_wr32(priv, NV03_PFIFO_CACHES, 0);
chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
if (status & NV_PFIFO_INTR_CACHE_ERROR) {
nv04_fifo_cache_error(device, priv, chid, get);
status &= ~NV_PFIFO_INTR_CACHE_ERROR;
}
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
nv04_fifo_dma_pusher(device, priv, chid);
status &= ~NV_PFIFO_INTR_DMA_PUSHER;
}
if (status & NV_PFIFO_INTR_SEMAPHORE) {
uint32_t sem;
status &= ~NV_PFIFO_INTR_SEMAPHORE;
nv_wr32(priv, NV03_PFIFO_INTR_0,
NV_PFIFO_INTR_SEMAPHORE);
sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
}
if (device->card_type == NV_50) {
if (status & 0x00000010) {
status &= ~0x00000010;
nv_wr32(priv, 0x002100, 0x00000010);
}
if (status & 0x40000000) {
nv_wr32(priv, 0x002100, 0x40000000);
nouveau_fifo_uevent(&priv->base);
status &= ~0x40000000;
}
}
if (status) {
nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
status, chid);
nv_wr32(priv, NV03_PFIFO_INTR_0, status);
status = 0;
}
nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
}
if (status) {
nv_error(priv, "still angry after %d spins, halt\n", cnt);
nv_wr32(priv, 0x002140, 0);
nv_wr32(priv, 0x000140, 0);
}
nv_wr32(priv, 0x000100, 0x00000100);
}
static int
nv04_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 15, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nouveau_ramht_ref(imem->ramht, &priv->ramht);
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv04_fifo_cclass;
nv_engine(priv)->sclass = nv04_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv04_ramfc;
return 0;
}
void
nv04_fifo_dtor(struct nouveau_object *object)
{
struct nv04_fifo_priv *priv = (void *)object;
nouveau_gpuobj_ref(NULL, &priv->ramfc);
nouveau_gpuobj_ref(NULL, &priv->ramro);
nouveau_ramht_ref(NULL, &priv->ramht);
nouveau_fifo_destroy(&priv->base);
}
int
nv04_fifo_init(struct nouveau_object *object)
{
struct nv04_fifo_priv *priv = (void *)object;
int ret;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((priv->ramht->bits - 9) << 16) |
(priv->ramht->base.addr >> 8));
nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
return 0;
}
struct nouveau_oclass *
nv04_fifo_oclass = &(struct nouveau_oclass) {
.handle = NV_ENGINE(FIFO, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv04_fifo_init,
.fini = _nouveau_fifo_fini,
},
};

View file

@ -0,0 +1,178 @@
#ifndef __NV04_FIFO_H__
#define __NV04_FIFO_H__
#include <engine/fifo.h>
#define NV04_PFIFO_DELAY_0 0x00002040
#define NV04_PFIFO_DMA_TIMESLICE 0x00002044
#define NV04_PFIFO_NEXT_CHANNEL 0x00002050
#define NV03_PFIFO_INTR_0 0x00002100
#define NV03_PFIFO_INTR_EN_0 0x00002140
# define NV_PFIFO_INTR_CACHE_ERROR (1<<0)
# define NV_PFIFO_INTR_RUNOUT (1<<4)
# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8)
# define NV_PFIFO_INTR_DMA_PUSHER (1<<12)
# define NV_PFIFO_INTR_DMA_PT (1<<16)
# define NV_PFIFO_INTR_SEMAPHORE (1<<20)
# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24)
#define NV03_PFIFO_RAMHT 0x00002210
#define NV03_PFIFO_RAMFC 0x00002214
#define NV03_PFIFO_RAMRO 0x00002218
#define NV40_PFIFO_RAMFC 0x00002220
#define NV03_PFIFO_CACHES 0x00002500
#define NV04_PFIFO_MODE 0x00002504
#define NV04_PFIFO_DMA 0x00002508
#define NV04_PFIFO_SIZE 0x0000250c
#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4)
#define NV50_PFIFO_CTX_TABLE__SIZE 128
#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31)
#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30)
#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF
#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF
#define NV03_PFIFO_CACHE0_PUSH0 0x00003000
#define NV03_PFIFO_CACHE0_PULL0 0x00003040
#define NV04_PFIFO_CACHE0_PULL0 0x00003050
#define NV04_PFIFO_CACHE0_PULL1 0x00003054
#define NV03_PFIFO_CACHE1_PUSH0 0x00003200
#define NV03_PFIFO_CACHE1_PUSH1 0x00003204
#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8)
#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16)
#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f
#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f
#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f
#define NV03_PFIFO_CACHE1_PUT 0x00003210
#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220
#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000
# define NV_PFIFO_CACHE1_ENDIAN 0x80000000
# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF
# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000
#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228
#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c
#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230
#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240
#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244
#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248
#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C
#define NV03_PFIFO_CACHE1_PULL0 0x00003240
#define NV04_PFIFO_CACHE1_PULL0 0x00003250
# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010
# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000
#define NV03_PFIFO_CACHE1_PULL1 0x00003250
#define NV04_PFIFO_CACHE1_PULL1 0x00003254
#define NV04_PFIFO_CACHE1_HASH 0x00003258
#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260
#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264
#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268
#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C
#define NV03_PFIFO_CACHE1_GET 0x00003270
#define NV04_PFIFO_CACHE1_ENGINE 0x00003280
#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0
#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0
#define NV40_PFIFO_UNK32E4 0x000032E4
#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8))
#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8))
#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8))
#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8))
struct ramfc_desc {
unsigned bits:6;
unsigned ctxs:5;
unsigned ctxp:8;
unsigned regs:5;
unsigned regp;
};
struct nv04_fifo_priv {
struct nouveau_fifo base;
struct ramfc_desc *ramfc_desc;
struct nouveau_ramht *ramht;
struct nouveau_gpuobj *ramro;
struct nouveau_gpuobj *ramfc;
};
struct nv04_fifo_base {
struct nouveau_fifo_base base;
};
struct nv04_fifo_chan {
struct nouveau_fifo_chan base;
u32 subc[8];
u32 ramfc;
};
int nv04_fifo_object_attach(struct nouveau_object *,
struct nouveau_object *, u32);
void nv04_fifo_object_detach(struct nouveau_object *, int);
void nv04_fifo_chan_dtor(struct nouveau_object *);
int nv04_fifo_chan_init(struct nouveau_object *);
int nv04_fifo_chan_fini(struct nouveau_object *, bool suspend);
int nv04_fifo_context_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void nv04_fifo_dtor(struct nouveau_object *);
int nv04_fifo_init(struct nouveau_object *);
void nv04_fifo_pause(struct nouveau_fifo *, unsigned long *);
void nv04_fifo_start(struct nouveau_fifo *, unsigned long *);
#endif

View file

@ -0,0 +1,183 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <subdev/instmem.h>
#include <subdev/instmem/nv04.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include "nv04.h"
static struct ramfc_desc
nv10_ramfc[] = {
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
{ 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
{ 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
{ 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
{ 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
{}
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv10_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv03_channel_dma_v0 v0;
} *args = data;
struct nv04_fifo_priv *priv = (void *)engine;
struct nv04_fifo_chan *chan;
int ret;
nv_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
nv_parent(chan)->context_attach = nv04_fifo_context_attach;
chan->ramfc = chan->base.chid * 32;
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + 0x14,
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
return 0;
}
static struct nouveau_ofuncs
nv10_fifo_ofuncs = {
.ctor = nv10_fifo_chan_ctor,
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_oclass
nv10_fifo_sclass[] = {
{ NV10_CHANNEL_DMA, &nv10_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static struct nouveau_oclass
nv10_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x10),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_context_ctor,
.dtor = _nouveau_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
static int
nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nouveau_ramht_ref(imem->ramht, &priv->ramht);
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv10_fifo_cclass;
nv_engine(priv)->sclass = nv10_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv10_ramfc;
return 0;
}
struct nouveau_oclass *
nv10_fifo_oclass = &(struct nouveau_oclass) {
.handle = NV_ENGINE(FIFO, 0x10),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv10_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv04_fifo_init,
.fini = _nouveau_fifo_fini,
},
};

View file

@ -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;

View file

@ -0,0 +1,220 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <subdev/instmem.h>
#include <subdev/instmem/nv04.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include "nv04.h"
static struct ramfc_desc
nv17_ramfc[] = {
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
{ 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
{ 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
{ 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
{ 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
{ 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
{ 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
{ 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
{ 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
{ 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
{}
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv17_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv03_channel_dma_v0 v0;
} *args = data;
struct nv04_fifo_priv *priv = (void *)engine;
struct nv04_fifo_chan *chan;
int ret;
nv_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR) |
(1ULL << NVDEV_ENGINE_MPEG), /* NV31- */
&chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
nv_parent(chan)->context_attach = nv04_fifo_context_attach;
chan->ramfc = chan->base.chid * 64;
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + 0x14,
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
return 0;
}
static struct nouveau_ofuncs
nv17_fifo_ofuncs = {
.ctor = nv17_fifo_chan_ctor,
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_oclass
nv17_fifo_sclass[] = {
{ NV17_CHANNEL_DMA, &nv17_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static struct nouveau_oclass
nv17_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x17),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_context_ctor,
.dtor = _nouveau_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
static int
nv17_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nouveau_ramht_ref(imem->ramht, &priv->ramht);
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv17_fifo_cclass;
nv_engine(priv)->sclass = nv17_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv17_ramfc;
return 0;
}
static int
nv17_fifo_init(struct nouveau_object *object)
{
struct nv04_fifo_priv *priv = (void *)object;
int ret;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((priv->ramht->bits - 9) << 16) |
(priv->ramht->base.addr >> 8));
nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
return 0;
}
struct nouveau_oclass *
nv17_fifo_oclass = &(struct nouveau_oclass) {
.handle = NV_ENGINE(FIFO, 0x17),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv17_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv17_fifo_init,
.fini = _nouveau_fifo_fini,
},
};

View file

@ -0,0 +1,361 @@
/*
* 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/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <subdev/instmem.h>
#include <subdev/instmem/nv04.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include "nv04.h"
static struct ramfc_desc
nv40_ramfc[] = {
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
{ 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
{ 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
{ 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE },
{ 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
{ 2, 28, 0x18, 28, 0x002058 },
{ 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE },
{ 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 },
{ 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
{ 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
{ 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
{ 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
{ 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
{ 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE },
{ 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE },
{ 32, 0, 0x40, 0, 0x0032e4 },
{ 32, 0, 0x44, 0, 0x0032e8 },
{ 32, 0, 0x4c, 0, 0x002088 },
{ 32, 0, 0x50, 0, 0x003300 },
{ 32, 0, 0x54, 0, 0x00330c },
{}
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv40_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
u32 context, chid = chan->base.chid;
int ret;
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->addr >> 4;
else
context = 0x00000004; /* just non-zero */
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW:
context |= 0x00000000;
break;
case NVDEV_ENGINE_GR:
context |= 0x00100000;
break;
case NVDEV_ENGINE_MPEG:
context |= 0x00200000;
break;
default:
return -EINVAL;
}
context |= chid << 23;
mutex_lock(&nv_subdev(priv)->mutex);
ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
mutex_unlock(&nv_subdev(priv)->mutex);
return ret;
}
static int
nv40_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *engctx)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
unsigned long flags;
u32 reg, ctx;
switch (nv_engidx(engctx->engine)) {
case NVDEV_ENGINE_SW:
return 0;
case NVDEV_ENGINE_GR:
reg = 0x32e0;
ctx = 0x38;
break;
case NVDEV_ENGINE_MPEG:
reg = 0x330c;
ctx = 0x54;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&priv->base.lock, flags);
nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4;
nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
nv_wr32(priv, reg, nv_engctx(engctx)->addr);
nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr);
nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&priv->base.lock, flags);
return 0;
}
static int
nv40_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *engctx)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
unsigned long flags;
u32 reg, ctx;
switch (nv_engidx(engctx->engine)) {
case NVDEV_ENGINE_SW:
return 0;
case NVDEV_ENGINE_GR:
reg = 0x32e0;
ctx = 0x38;
break;
case NVDEV_ENGINE_MPEG:
reg = 0x330c;
ctx = 0x54;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&priv->base.lock, flags);
nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
nv_wr32(priv, reg, 0x00000000);
nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&priv->base.lock, flags);
return 0;
}
static int
nv40_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv03_channel_dma_v0 v0;
} *args = data;
struct nv04_fifo_priv *priv = (void *)engine;
struct nv04_fifo_chan *chan;
int ret;
nv_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x1000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR) |
(1ULL << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
nv_parent(chan)->context_attach = nv40_fifo_context_attach;
nv_parent(chan)->context_detach = nv40_fifo_context_detach;
nv_parent(chan)->object_attach = nv40_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
chan->ramfc = chan->base.chid * 128;
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 |
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
return 0;
}
static struct nouveau_ofuncs
nv40_fifo_ofuncs = {
.ctor = nv40_fifo_chan_ctor,
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_oclass
nv40_fifo_sclass[] = {
{ NV40_CHANNEL_DMA, &nv40_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static struct nouveau_oclass
nv40_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_context_ctor,
.dtor = _nouveau_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
static int
nv40_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nouveau_ramht_ref(imem->ramht, &priv->ramht);
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv40_fifo_cclass;
nv_engine(priv)->sclass = nv40_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv40_ramfc;
return 0;
}
static int
nv40_fifo_init(struct nouveau_object *object)
{
struct nv04_fifo_priv *priv = (void *)object;
struct nouveau_fb *pfb = nouveau_fb(object);
int ret;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x002040, 0x000000ff);
nv_wr32(priv, 0x002044, 0x2101ffff);
nv_wr32(priv, 0x002058, 0x00000001);
nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((priv->ramht->bits - 9) << 16) |
(priv->ramht->base.addr >> 8));
nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
switch (nv_device(priv)->chipset) {
case 0x47:
case 0x49:
case 0x4b:
nv_wr32(priv, 0x002230, 0x00000001);
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x45:
case 0x48:
nv_wr32(priv, 0x002220, 0x00030002);
break;
default:
nv_wr32(priv, 0x002230, 0x00000000);
nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 +
priv->ramfc->addr) >> 16) |
0x00030000);
break;
}
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
return 0;
}
struct nouveau_oclass *
nv40_fifo_oclass = &(struct nouveau_oclass) {
.handle = NV_ENGINE(FIFO, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv40_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv40_fifo_init,
.fini = _nouveau_fifo_fini,
},
};

View file

@ -0,0 +1,541 @@
/*
* 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/client.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/timer.h>
#include <subdev/bar.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include "nv04.h"
#include "nv50.h"
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static void
nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv)
{
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_gpuobj *cur;
int i, p;
cur = priv->playlist[priv->cur_playlist];
priv->cur_playlist = !priv->cur_playlist;
for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
nv_wo32(cur, p++ * 4, i);
}
bar->flush(bar);
nv_wr32(priv, 0x0032f4, cur->addr >> 12);
nv_wr32(priv, 0x0032ec, p);
nv_wr32(priv, 0x002500, 0x00000101);
}
void
nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
{
mutex_lock(&nv_subdev(priv)->mutex);
nv50_fifo_playlist_update_locked(priv);
mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
nv50_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent->parent;
struct nouveau_gpuobj *ectx = (void *)object;
u64 limit = ectx->addr + ectx->size - 1;
u64 start = ectx->addr;
u32 addr;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0000; break;
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
default:
return -EINVAL;
}
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
nv_wo32(base->eng, addr + 0x00, 0x00190000);
nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
upper_32_bits(start));
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
return 0;
}
static int
nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_priv *priv = (void *)parent->engine;
struct nv50_fifo_base *base = (void *)parent->parent;
struct nv50_fifo_chan *chan = (void *)parent;
u32 addr, me;
int ret = 0;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0000; break;
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
default:
return -EINVAL;
}
/* HW bug workaround:
*
* PFIFO will hang forever if the connected engines don't report
* that they've processed the context switch request.
*
* In order for the kickoff to work, we need to ensure all the
* connected engines are in a state where they can answer.
*
* Newer chipsets don't seem to suffer from this issue, and well,
* there's also a "ignore these engines" bitmask reg we can use
* if we hit the issue there..
*/
me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
/* do the kickoff... */
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
nv_error(priv, "channel %d [%s] unload timeout\n",
chan->base.chid, nouveau_client_name(chan));
if (suspend)
ret = -EBUSY;
}
nv_wr32(priv, 0x00b860, me);
if (ret == 0) {
nv_wo32(base->eng, addr + 0x00, 0x00000000);
nv_wo32(base->eng, addr + 0x04, 0x00000000);
nv_wo32(base->eng, addr + 0x08, 0x00000000);
nv_wo32(base->eng, addr + 0x0c, 0x00000000);
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
}
return ret;
}
static int
nv50_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
struct nv50_fifo_chan *chan = (void *)parent;
u32 context;
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->node->offset >> 4;
else
context = 0x00000004; /* just non-zero */
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW : context |= 0x00000000; break;
case NVDEV_ENGINE_GR : context |= 0x00100000; break;
case NVDEV_ENGINE_MPEG : context |= 0x00200000; break;
default:
return -EINVAL;
}
return nouveau_ramht_insert(chan->ramht, 0, handle, context);
}
void
nv50_fifo_object_detach(struct nouveau_object *parent, int cookie)
{
struct nv50_fifo_chan *chan = (void *)parent;
nouveau_ramht_remove(chan->ramht, cookie);
}
static int
nv50_fifo_chan_ctor_dma(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv03_channel_dma_v0 v0;
} *args = data;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
int ret;
nv_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR) |
(1ULL << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
nv_parent(chan)->context_attach = nv50_fifo_context_attach;
nv_parent(chan)->context_detach = nv50_fifo_context_detach;
nv_parent(chan)->object_attach = nv50_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
&chan->ramht);
if (ret)
return ret;
nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x3c, 0x003f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff);
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
nv_wo32(base->ramfc, 0x4c, 0xffffffff);
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
nv_wo32(base->ramfc, 0x78, 0x00000000);
nv_wo32(base->ramfc, 0x7c, 0x30000001);
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->base.node->offset >> 4));
bar->flush(bar);
return 0;
}
static int
nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv50_channel_gpfifo_v0 v0;
} *args = data;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
u64 ioffset, ilength;
int ret;
nv_ioctl(parent, "create channel gpfifo size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
"ioffset %016llx ilength %08x\n",
args->v0.version, args->v0.pushbuf, args->v0.ioffset,
args->v0.ilength);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR) |
(1ULL << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
nv_parent(chan)->context_attach = nv50_fifo_context_attach;
nv_parent(chan)->context_detach = nv50_fifo_context_detach;
nv_parent(chan)->object_attach = nv50_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
&chan->ramht);
if (ret)
return ret;
ioffset = args->v0.ioffset;
ilength = order_base_2(args->v0.ilength / 8);
nv_wo32(base->ramfc, 0x3c, 0x403f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff);
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
nv_wo32(base->ramfc, 0x78, 0x00000000);
nv_wo32(base->ramfc, 0x7c, 0x30000001);
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->base.node->offset >> 4));
bar->flush(bar);
return 0;
}
void
nv50_fifo_chan_dtor(struct nouveau_object *object)
{
struct nv50_fifo_chan *chan = (void *)object;
nouveau_ramht_ref(NULL, &chan->ramht);
nouveau_fifo_channel_destroy(&chan->base);
}
static int
nv50_fifo_chan_init(struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = (void *)object->engine;
struct nv50_fifo_base *base = (void *)object->parent;
struct nv50_fifo_chan *chan = (void *)object;
struct nouveau_gpuobj *ramfc = base->ramfc;
u32 chid = chan->base.chid;
int ret;
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
nv50_fifo_playlist_update(priv);
return 0;
}
int
nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend)
{
struct nv50_fifo_priv *priv = (void *)object->engine;
struct nv50_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
/* remove channel from playlist, fifo will unload context */
nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
nv50_fifo_playlist_update(priv);
nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
return nouveau_fifo_channel_fini(&chan->base, suspend);
}
static struct nouveau_ofuncs
nv50_fifo_ofuncs_dma = {
.ctor = nv50_fifo_chan_ctor_dma,
.dtor = nv50_fifo_chan_dtor,
.init = nv50_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_ofuncs
nv50_fifo_ofuncs_ind = {
.ctor = nv50_fifo_chan_ctor_ind,
.dtor = nv50_fifo_chan_dtor,
.init = nv50_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_oclass
nv50_fifo_sclass[] = {
{ NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma },
{ NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static int
nv50_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
0x1000, NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200,
0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0,
NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0,
&base->pgd);
if (ret)
return ret;
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
if (ret)
return ret;
return 0;
}
void
nv50_fifo_context_dtor(struct nouveau_object *object)
{
struct nv50_fifo_base *base = (void *)object;
nouveau_vm_ref(NULL, &base->vm, base->pgd);
nouveau_gpuobj_ref(NULL, &base->pgd);
nouveau_gpuobj_ref(NULL, &base->eng);
nouveau_gpuobj_ref(NULL, &base->ramfc);
nouveau_gpuobj_ref(NULL, &base->cache);
nouveau_fifo_context_destroy(&base->base);
}
static struct nouveau_oclass
nv50_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_fifo_context_ctor,
.dtor = nv50_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
static int
nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
&priv->playlist[0]);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
&priv->playlist[1]);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
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;
}
void
nv50_fifo_dtor(struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = (void *)object;
nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
nouveau_fifo_destroy(&priv->base);
}
int
nv50_fifo_init(struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = (void *)object;
int ret, i;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
nv_wr32(priv, 0x00250c, 0x6f3cfc34);
nv_wr32(priv, 0x002044, 0x01003fff);
nv_wr32(priv, 0x002100, 0xffffffff);
nv_wr32(priv, 0x002140, 0xbfffffff);
for (i = 0; i < 128; i++)
nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
nv50_fifo_playlist_update_locked(priv);
nv_wr32(priv, 0x003200, 0x00000001);
nv_wr32(priv, 0x003250, 0x00000001);
nv_wr32(priv, 0x002500, 0x00000001);
return 0;
}
struct nouveau_oclass *
nv50_fifo_oclass = &(struct nouveau_oclass) {
.handle = NV_ENGINE(FIFO, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_fifo_ctor,
.dtor = nv50_fifo_dtor,
.init = nv50_fifo_init,
.fini = _nouveau_fifo_fini,
},
};

View file

@ -0,0 +1,36 @@
#ifndef __NV50_FIFO_H__
#define __NV50_FIFO_H__
struct nv50_fifo_priv {
struct nouveau_fifo base;
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
};
struct nv50_fifo_base {
struct nouveau_fifo_base base;
struct nouveau_gpuobj *ramfc;
struct nouveau_gpuobj *cache;
struct nouveau_gpuobj *eng;
struct nouveau_gpuobj *pgd;
struct nouveau_vm *vm;
};
struct nv50_fifo_chan {
struct nouveau_fifo_chan base;
u32 subc[8];
struct nouveau_ramht *ramht;
};
void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
void nv50_fifo_object_detach(struct nouveau_object *, int);
void nv50_fifo_chan_dtor(struct nouveau_object *);
int nv50_fifo_chan_fini(struct nouveau_object *, bool);
void nv50_fifo_context_dtor(struct nouveau_object *);
void nv50_fifo_dtor(struct nouveau_object *);
int nv50_fifo_init(struct nouveau_object *);
#endif

View file

@ -0,0 +1,481 @@
/*
* 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/client.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <core/event.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/timer.h>
#include <subdev/bar.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include "nv04.h"
#include "nv50.h"
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv84_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent->parent;
struct nouveau_gpuobj *ectx = (void *)object;
u64 limit = ectx->addr + ectx->size - 1;
u64 start = ectx->addr;
u32 addr;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0020; break;
case NVDEV_ENGINE_VP : addr = 0x0040; break;
case NVDEV_ENGINE_PPP :
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
case NVDEV_ENGINE_BSP : addr = 0x0080; break;
case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
default:
return -EINVAL;
}
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
nv_wo32(base->eng, addr + 0x00, 0x00190000);
nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
upper_32_bits(start));
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
return 0;
}
static int
nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_priv *priv = (void *)parent->engine;
struct nv50_fifo_base *base = (void *)parent->parent;
struct nv50_fifo_chan *chan = (void *)parent;
u32 addr, save, engn;
bool done;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break;
case NVDEV_ENGINE_VP : engn = 3; addr = 0x0040; break;
case NVDEV_ENGINE_PPP :
case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
case NVDEV_ENGINE_BSP : engn = 5; addr = 0x0080; break;
case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; break;
default:
return -EINVAL;
}
save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn);
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
nv_wr32(priv, 0x002520, save);
if (!done) {
nv_error(priv, "channel %d [%s] unload timeout\n",
chan->base.chid, nouveau_client_name(chan));
if (suspend)
return -EBUSY;
}
nv_wo32(base->eng, addr + 0x00, 0x00000000);
nv_wo32(base->eng, addr + 0x04, 0x00000000);
nv_wo32(base->eng, addr + 0x08, 0x00000000);
nv_wo32(base->eng, addr + 0x0c, 0x00000000);
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
return 0;
}
static int
nv84_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
struct nv50_fifo_chan *chan = (void *)parent;
u32 context;
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->node->offset >> 4;
else
context = 0x00000004; /* just non-zero */
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW : context |= 0x00000000; break;
case NVDEV_ENGINE_GR : context |= 0x00100000; break;
case NVDEV_ENGINE_MPEG :
case NVDEV_ENGINE_PPP : context |= 0x00200000; break;
case NVDEV_ENGINE_ME :
case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break;
case NVDEV_ENGINE_VP : context |= 0x00400000; break;
case NVDEV_ENGINE_CRYPT :
case NVDEV_ENGINE_VIC : context |= 0x00500000; break;
case NVDEV_ENGINE_BSP : context |= 0x00600000; break;
default:
return -EINVAL;
}
return nouveau_ramht_insert(chan->ramht, 0, handle, context);
}
static int
nv84_fifo_chan_ctor_dma(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv03_channel_dma_v0 v0;
} *args = data;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
int ret;
nv_ioctl(parent, "create channel dma size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
"offset %016llx\n", args->v0.version,
args->v0.pushbuf, args->v0.offset);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR) |
(1ULL << NVDEV_ENGINE_MPEG) |
(1ULL << NVDEV_ENGINE_ME) |
(1ULL << NVDEV_ENGINE_VP) |
(1ULL << NVDEV_ENGINE_CRYPT) |
(1ULL << NVDEV_ENGINE_BSP) |
(1ULL << NVDEV_ENGINE_PPP) |
(1ULL << NVDEV_ENGINE_COPY0) |
(1ULL << NVDEV_ENGINE_VIC), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
&chan->ramht);
if (ret)
return ret;
nv_parent(chan)->context_attach = nv84_fifo_context_attach;
nv_parent(chan)->context_detach = nv84_fifo_context_detach;
nv_parent(chan)->object_attach = nv84_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
nv_wo32(base->ramfc, 0x3c, 0x003f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff);
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
nv_wo32(base->ramfc, 0x4c, 0xffffffff);
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
nv_wo32(base->ramfc, 0x78, 0x00000000);
nv_wo32(base->ramfc, 0x7c, 0x30000001);
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->base.node->offset >> 4));
nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
bar->flush(bar);
return 0;
}
static int
nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv50_channel_gpfifo_v0 v0;
} *args = data;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
u64 ioffset, ilength;
int ret;
nv_ioctl(parent, "create channel gpfifo size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
"ioffset %016llx ilength %08x\n",
args->v0.version, args->v0.pushbuf, args->v0.ioffset,
args->v0.ilength);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_DMAOBJ) |
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR) |
(1ULL << NVDEV_ENGINE_MPEG) |
(1ULL << NVDEV_ENGINE_ME) |
(1ULL << NVDEV_ENGINE_VP) |
(1ULL << NVDEV_ENGINE_CRYPT) |
(1ULL << NVDEV_ENGINE_BSP) |
(1ULL << NVDEV_ENGINE_PPP) |
(1ULL << NVDEV_ENGINE_COPY0) |
(1ULL << NVDEV_ENGINE_VIC), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
&chan->ramht);
if (ret)
return ret;
nv_parent(chan)->context_attach = nv84_fifo_context_attach;
nv_parent(chan)->context_detach = nv84_fifo_context_detach;
nv_parent(chan)->object_attach = nv84_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
ioffset = args->v0.ioffset;
ilength = order_base_2(args->v0.ilength / 8);
nv_wo32(base->ramfc, 0x3c, 0x403f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff);
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
nv_wo32(base->ramfc, 0x78, 0x00000000);
nv_wo32(base->ramfc, 0x7c, 0x30000001);
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->base.node->offset >> 4));
nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
bar->flush(bar);
return 0;
}
static int
nv84_fifo_chan_init(struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = (void *)object->engine;
struct nv50_fifo_base *base = (void *)object->parent;
struct nv50_fifo_chan *chan = (void *)object;
struct nouveau_gpuobj *ramfc = base->ramfc;
u32 chid = chan->base.chid;
int ret;
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
nv50_fifo_playlist_update(priv);
return 0;
}
static struct nouveau_ofuncs
nv84_fifo_ofuncs_dma = {
.ctor = nv84_fifo_chan_ctor_dma,
.dtor = nv50_fifo_chan_dtor,
.init = nv84_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_ofuncs
nv84_fifo_ofuncs_ind = {
.ctor = nv84_fifo_chan_ctor_ind,
.dtor = nv50_fifo_chan_dtor,
.init = nv84_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_oclass
nv84_fifo_sclass[] = {
{ G82_CHANNEL_DMA, &nv84_fifo_ofuncs_dma },
{ G82_CHANNEL_GPFIFO, &nv84_fifo_ofuncs_ind },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static int
nv84_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
0x1000, NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0,
NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0,
0, &base->pgd);
if (ret)
return ret;
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1000,
0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0100,
0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
if (ret)
return ret;
return 0;
}
static struct nouveau_oclass
nv84_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_fifo_context_ctor,
.dtor = nv50_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
static void
nv84_fifo_uevent_init(struct nvkm_event *event, int type, int index)
{
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
}
static void
nv84_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x40000000, 0x00000000);
}
static const struct nvkm_event_func
nv84_fifo_uevent_func = {
.ctor = nouveau_fifo_uevent_ctor,
.init = nv84_fifo_uevent_init,
.fini = nv84_fifo_uevent_fini,
};
static int
nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
&priv->playlist[0]);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
&priv->playlist[1]);
if (ret)
return ret;
ret = nvkm_event_init(&nv84_fifo_uevent_func, 1, 1, &priv->base.uevent);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
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) {
.handle = NV_ENGINE(FIFO, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_fifo_ctor,
.dtor = nv50_fifo_dtor,
.init = nv50_fifo_init,
.fini = _nouveau_fifo_fini,
},
};

View file

@ -0,0 +1,975 @@
/*
* 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/client.h>
#include <core/handle.h>
#include <core/namedb.h>
#include <core/gpuobj.h>
#include <core/engctx.h>
#include <core/event.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <core/enum.h>
#include <subdev/timer.h>
#include <subdev/bar.h>
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
struct nvc0_fifo_priv {
struct nouveau_fifo base;
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;
} user;
int spoon_nr;
};
struct nvc0_fifo_base {
struct nouveau_fifo_base base;
struct nouveau_gpuobj *pgd;
struct nouveau_vm *vm;
};
struct nvc0_fifo_chan {
struct nouveau_fifo_chan base;
enum {
STOPPED,
RUNNING,
KILLED
} state;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static void
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->runlist.mem[priv->runlist.active];
priv->runlist.active = !priv->runlist.active;
for (i = 0, p = 0; i < 128; i++) {
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 (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);
}
static int
nvc0_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nvc0_fifo_base *base = (void *)parent->parent;
struct nouveau_engctx *ectx = (void *)object;
u32 addr;
int ret;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
case NVDEV_ENGINE_BSP : addr = 0x0270; break;
case NVDEV_ENGINE_VP : addr = 0x0250; break;
case NVDEV_ENGINE_PPP : addr = 0x0260; break;
default:
return -EINVAL;
}
if (!ectx->vma.node) {
ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
NV_MEM_ACCESS_RW, &ectx->vma);
if (ret)
return ret;
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
}
nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
bar->flush(bar);
return 0;
}
static int
nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nvc0_fifo_priv *priv = (void *)parent->engine;
struct nvc0_fifo_base *base = (void *)parent->parent;
struct nvc0_fifo_chan *chan = (void *)parent;
u32 addr;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
case NVDEV_ENGINE_BSP : addr = 0x0270; break;
case NVDEV_ENGINE_VP : addr = 0x0250; break;
case NVDEV_ENGINE_PPP : addr = 0x0260; break;
default:
return -EINVAL;
}
nv_wr32(priv, 0x002634, chan->base.chid);
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
nv_error(priv, "channel %d [%s] kick timeout\n",
chan->base.chid, nouveau_client_name(chan));
if (suspend)
return -EBUSY;
}
nv_wo32(base, addr + 0x00, 0x00000000);
nv_wo32(base, addr + 0x04, 0x00000000);
bar->flush(bar);
return 0;
}
static int
nvc0_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
union {
struct nv50_channel_gpfifo_v0 v0;
} *args = data;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nvc0_fifo_priv *priv = (void *)engine;
struct nvc0_fifo_base *base = (void *)parent;
struct nvc0_fifo_chan *chan;
u64 usermem, ioffset, ilength;
int ret, i;
nv_ioctl(parent, "create channel gpfifo size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
"ioffset %016llx ilength %08x\n",
args->v0.version, args->v0.pushbuf, args->v0.ioffset,
args->v0.ilength);
} else
return ret;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
priv->user.bar.offset, 0x1000,
args->v0.pushbuf,
(1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_GR) |
(1ULL << NVDEV_ENGINE_COPY0) |
(1ULL << NVDEV_ENGINE_COPY1) |
(1ULL << NVDEV_ENGINE_BSP) |
(1ULL << NVDEV_ENGINE_VP) |
(1ULL << NVDEV_ENGINE_PPP), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
args->v0.chid = chan->base.chid;
nv_parent(chan)->context_attach = nvc0_fifo_context_attach;
nv_parent(chan)->context_detach = nvc0_fifo_context_detach;
usermem = chan->base.chid * 0x1000;
ioffset = args->v0.ioffset;
ilength = order_base_2(args->v0.ilength / 8);
for (i = 0; i < 0x1000; i += 4)
nv_wo32(priv->user.mem, usermem + i, 0x00000000);
nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
nv_wo32(base, 0x10, 0x0000face);
nv_wo32(base, 0x30, 0xfffff902);
nv_wo32(base, 0x48, lower_32_bits(ioffset));
nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
nv_wo32(base, 0x54, 0x00000002);
nv_wo32(base, 0x84, 0x20400000);
nv_wo32(base, 0x94, 0x30000001);
nv_wo32(base, 0x9c, 0x00000100);
nv_wo32(base, 0xa4, 0x1f1f1f1f);
nv_wo32(base, 0xa8, 0x1f1f1f1f);
nv_wo32(base, 0xac, 0x0000001f);
nv_wo32(base, 0xb8, 0xf8000000);
nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
bar->flush(bar);
return 0;
}
static int
nvc0_fifo_chan_init(struct nouveau_object *object)
{
struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
struct nvc0_fifo_priv *priv = (void *)object->engine;
struct nvc0_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
int ret;
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
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;
if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
nvc0_fifo_runlist_update(priv);
}
nvc0_fifo_intr_engine(priv);
nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
return nouveau_fifo_channel_fini(&chan->base, suspend);
}
static struct nouveau_ofuncs
nvc0_fifo_ofuncs = {
.ctor = nvc0_fifo_chan_ctor,
.dtor = _nouveau_fifo_channel_dtor,
.init = nvc0_fifo_chan_init,
.fini = nvc0_fifo_chan_fini,
.map = _nouveau_fifo_channel_map,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
.ntfy = _nouveau_fifo_channel_ntfy
};
static struct nouveau_oclass
nvc0_fifo_sclass[] = {
{ FERMI_CHANNEL_GPFIFO, &nvc0_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - instmem heap and vm setup
******************************************************************************/
static int
nvc0_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
0x1000, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
&base->pgd);
if (ret)
return ret;
nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
nv_wo32(base, 0x0208, 0xffffffff);
nv_wo32(base, 0x020c, 0x000000ff);
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
if (ret)
return ret;
return 0;
}
static void
nvc0_fifo_context_dtor(struct nouveau_object *object)
{
struct nvc0_fifo_base *base = (void *)object;
nouveau_vm_ref(NULL, &base->vm, base->pgd);
nouveau_gpuobj_ref(NULL, &base->pgd);
nouveau_fifo_context_destroy(&base->base);
}
static struct nouveau_oclass
nvc0_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_fifo_context_ctor,
.dtor = nvc0_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
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", 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 },
{ 0x13, "PCOUNTER" },
{ 0x14, "PVP", NULL, NVDEV_ENGINE_VP },
{ 0x15, "PCOPY0", NULL, NVDEV_ENGINE_COPY0 },
{ 0x16, "PCOPY1", NULL, NVDEV_ENGINE_COPY1 },
{ 0x17, "PDAEMON" },
{}
};
static const struct nouveau_enum
nvc0_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
nvc0_fifo_fault_hubclient[] = {
{ 0x01, "PCOPY0" },
{ 0x02, "PCOPY1" },
{ 0x04, "DISPATCH" },
{ 0x05, "CTXCTL" },
{ 0x06, "PFIFO" },
{ 0x07, "BAR_READ" },
{ 0x08, "BAR_WRITE" },
{ 0x0b, "PVP" },
{ 0x0c, "PPPP" },
{ 0x0d, "PBSP" },
{ 0x11, "PCOUNTER" },
{ 0x12, "PDAEMON" },
{ 0x14, "CCACHE" },
{ 0x15, "CCACHE_POST" },
{}
};
static const struct nouveau_enum
nvc0_fifo_fault_gpcclient[] = {
{ 0x01, "TEX" },
{ 0x0c, "ESETUP" },
{ 0x0e, "CTXCTL" },
{ 0x0f, "PROP" },
{}
};
static void
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;
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);
}
if (hub) {
ec = nouveau_enum_find(nvc0_fifo_fault_hubclient, client);
} else {
ec = nouveau_enum_find(nvc0_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 FERMI_CHANNEL_GPFIFO:
nvc0_fifo_recover(priv, engine, (void *)object);
break;
}
object = object->parent;
}
nouveau_engctx_put(engctx);
}
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_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));
u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
u32 subc = (addr & 0x00070000) >> 16;
u32 mthd = (addr & 0x00003ffc);
u32 show = stat;
if (stat & 0x00800000) {
if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
show &= ~0x00800000;
}
if (show) {
nv_error(priv, "PBDMA%d:", unit);
nouveau_bitfield_print(nvc0_fifo_pbdma_intr, show);
pr_cont("\n");
nv_error(priv,
"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);
}
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
}
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;
nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) {
nouveau_fifo_uevent(&priv->base);
ints &= ~1;
}
if (ints) {
nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints);
nv_mask(priv, 0x002628, ints, 0);
}
}
}
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;
u32 mask = nv_rd32(priv, 0x002140);
u32 stat = nv_rd32(priv, 0x002100) & mask;
if (stat & 0x00000001) {
u32 intr = nv_rd32(priv, 0x00252c);
nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr);
nv_wr32(priv, 0x002100, 0x00000001);
stat &= ~0x00000001;
}
if (stat & 0x00000100) {
nvc0_fifo_intr_sched(priv);
nv_wr32(priv, 0x002100, 0x00000100);
stat &= ~0x00000100;
}
if (stat & 0x00010000) {
u32 intr = nv_rd32(priv, 0x00256c);
nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr);
nv_wr32(priv, 0x002100, 0x00010000);
stat &= ~0x00010000;
}
if (stat & 0x01000000) {
u32 intr = nv_rd32(priv, 0x00258c);
nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr);
nv_wr32(priv, 0x002100, 0x01000000);
stat &= ~0x01000000;
}
if (stat & 0x10000000) {
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);
}
stat &= ~0x10000000;
}
if (stat & 0x20000000) {
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);
}
stat &= ~0x20000000;
}
if (stat & 0x40000000) {
nvc0_fifo_intr_runlist(priv);
stat &= ~0x40000000;
}
if (stat & 0x80000000) {
nvc0_fifo_intr_engine(priv);
stat &= ~0x80000000;
}
if (stat) {
nv_error(priv, "INTR 0x%08x\n", stat);
nv_mask(priv, 0x002140, stat, 0x00000000);
nv_wr32(priv, 0x002100, stat);
}
}
static void
nvc0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
{
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
}
static void
nvc0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
}
static const struct nvkm_event_func
nvc0_fifo_uevent_func = {
.ctor = nouveau_fifo_uevent_ctor,
.init = nvc0_fifo_uevent_init,
.fini = nvc0_fifo_uevent_fini,
};
static int
nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
INIT_WORK(&priv->fault, nvc0_fifo_recover_work);
ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
&priv->runlist.mem[0]);
if (ret)
return ret;
ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
&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)
return ret;
ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
&priv->user.bar);
if (ret)
return ret;
ret = nvkm_event_init(&nvc0_fifo_uevent_func, 1, 1, &priv->base.uevent);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nvc0_fifo_intr;
nv_engine(priv)->cclass = &nvc0_fifo_cclass;
nv_engine(priv)->sclass = nvc0_fifo_sclass;
return 0;
}
static void
nvc0_fifo_dtor(struct nouveau_object *object)
{
struct nvc0_fifo_priv *priv = (void *)object;
nouveau_gpuobj_unmap(&priv->user.bar);
nouveau_gpuobj_ref(NULL, &priv->user.mem);
nouveau_gpuobj_ref(NULL, &priv->runlist.mem[0]);
nouveau_gpuobj_ref(NULL, &priv->runlist.mem[1]);
nouveau_fifo_destroy(&priv->base);
}
static int
nvc0_fifo_init(struct nouveau_object *object)
{
struct nvc0_fifo_priv *priv = (void *)object;
int ret, i;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x000204, 0xffffffff);
nv_wr32(priv, 0x002204, 0xffffffff);
priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
/* assign engines to PBDMAs */
if (priv->spoon_nr >= 3) {
nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */
nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */
nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
}
/* 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_mask(priv, 0x002200, 0x00000001, 0x00000001);
nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
nv_wr32(priv, 0x002100, 0xffffffff);
nv_wr32(priv, 0x002140, 0x7fffffff);
nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
return 0;
}
struct nouveau_oclass *
nvc0_fifo_oclass = &(struct nouveau_oclass) {
.handle = NV_ENGINE(FIFO, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_fifo_ctor,
.dtor = nvc0_fifo_dtor,
.init = nvc0_fifo_init,
.fini = _nouveau_fifo_fini,
},
};

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more