diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev')
56 files changed, 1092 insertions, 173 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild index 642d27dc99a3..3f5d38d74fba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild @@ -19,4 +19,5 @@ include $(src)/nvkm/subdev/pmu/Kbuild include $(src)/nvkm/subdev/secboot/Kbuild include $(src)/nvkm/subdev/therm/Kbuild include $(src)/nvkm/subdev/timer/Kbuild +include $(src)/nvkm/subdev/top/Kbuild include $(src)/nvkm/subdev/volt/Kbuild diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index a9433ad45b1e..c561d148cebc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -77,7 +77,7 @@ void nvkm_bar_ctor(const struct nvkm_bar_func *func, struct nvkm_device *device, int index, struct nvkm_bar *bar) { - nvkm_subdev_ctor(&nvkm_bar, device, index, 0, &bar->subdev); + nvkm_subdev_ctor(&nvkm_bar, device, index, &bar->subdev); bar->func = func; spin_lock_init(&bar->lock); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index 79536897efaa..e15b9627b07e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -105,7 +105,7 @@ nvkm_bios_new(struct nvkm_device *device, int index, struct nvkm_bios **pbios) if (!(bios = *pbios = kzalloc(sizeof(*bios), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_bios, device, index, 0, &bios->subdev); + nvkm_subdev_ctor(&nvkm_bios, device, index, &bios->subdev); ret = nvbios_shadow(bios); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index 125ec2ed6c2e..91a7dc56e406 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -81,9 +81,11 @@ static u16 pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_C; + u16 data = 0x0000; - if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) { - u16 data = nvbios_rd16(bios, bit_C.offset + 8); + if (!bit_entry(bios, 'C', &bit_C)) { + if (bit_C.version == 1 && bit_C.length >= 10) + data = nvbios_rd16(bios, bit_C.offset + 8); if (data) { *ver = nvbios_rd08(bios, data + 0); *hdr = nvbios_rd08(bios, data + 1); @@ -94,7 +96,7 @@ pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } if (bmp_version(bios) >= 0x0524) { - u16 data = nvbios_rd16(bios, bios->bmp_offset + 142); + data = nvbios_rd16(bios, bios->bmp_offset + 142); if (data) { *ver = nvbios_rd08(bios, data + 0); *hdr = 1; @@ -105,7 +107,7 @@ pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } *ver = 0x00; - return 0x0000; + return data; } static struct pll_mapping * @@ -156,7 +158,7 @@ pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) } map = pll_map(bios); - while (map->reg) { + while (map && map->reg) { if (map->reg == reg && *ver >= 0x20) { u16 addr = (data += hdr); *type = map->type; @@ -198,7 +200,7 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) } map = pll_map(bios); - while (map->reg) { + while (map && map->reg) { if (map->type == type && *ver >= 0x20) { u16 addr = (data += hdr); *reg = map->reg; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c index dc5a10f18bdb..52ad73bce5fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c @@ -58,7 +58,7 @@ nvkm_bus_new_(const struct nvkm_bus_func *func, struct nvkm_device *device, struct nvkm_bus *bus; if (!(bus = *pbus = kzalloc(sizeof(*bus), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_bus, device, index, 0, &bus->subdev); + nvkm_subdev_ctor(&nvkm_bus, device, index, &bus->subdev); bus->func = func; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 889cce2eb727..7102c25320fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -564,7 +564,7 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, int ret, idx, arglen; const char *mode; - nvkm_subdev_ctor(&nvkm_clk, device, index, 0, &clk->subdev); + nvkm_subdev_ctor(&nvkm_clk, device, index, &clk->subdev); clk->func = func; INIT_LIST_HEAD(&clk->states); clk->domains = func->domains; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index 5f25402f6b09..4756019ddf3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -83,6 +83,12 @@ nvkm_devinit_preinit(struct nvkm_subdev *subdev) if (init->func->preinit) init->func->preinit(init); + /* Override the post flag during the first call if NvForcePost is set */ + if (init->force_post) { + init->post = init->force_post; + init->force_post = false; + } + /* unlock the extended vga crtc regs */ nvkm_lockvgac(subdev->device, false); return 0; @@ -124,7 +130,7 @@ nvkm_devinit_ctor(const struct nvkm_devinit_func *func, struct nvkm_device *device, int index, struct nvkm_devinit *init) { - nvkm_subdev_ctor(&nvkm_devinit, device, index, 0, &init->subdev); + nvkm_subdev_ctor(&nvkm_devinit, device, index, &init->subdev); init->func = func; - init->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false); + init->force_post = nvkm_boolopt(device->cfgopt, "NvForcePost", false); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c index 2923598b5fe9..8b1b34c3ad26 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c @@ -97,9 +97,11 @@ gf100_devinit_preinit(struct nvkm_devinit *base) struct nvkm_subdev *subdev = &init->base.subdev; struct nvkm_device *device = subdev->device; - /* This bit is set by devinit, and flips back to 0 on suspend */ - if (!base->post) - base->post = ((nvkm_rd32(device, 0x2240c) & BIT(1)) == 0); + /* + * This bit is set by devinit, and flips back to 0 on suspend. We + * can use it as a reliable way to know whether we should run devinit. + */ + base->post = ((nvkm_rd32(device, 0x2240c) & BIT(1)) == 0); } static const struct nvkm_devinit_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild index 08105701af7e..842d5de96d73 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild @@ -23,6 +23,7 @@ nvkm-y += nvkm/subdev/fb/gf100.o nvkm-y += nvkm/subdev/fb/gk104.o nvkm-y += nvkm/subdev/fb/gk20a.o nvkm-y += nvkm/subdev/fb/gm107.o +nvkm-y += nvkm/subdev/fb/gm200.o nvkm-y += nvkm/subdev/fb/ram.o nvkm-y += nvkm/subdev/fb/ramnv04.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index a719b9becb73..ce90242b8cce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -24,6 +24,7 @@ #include "priv.h" #include "ram.h" +#include <core/memory.h> #include <subdev/bios.h> #include <subdev/bios/M0203.h> #include <engine/gr.h> @@ -98,6 +99,7 @@ static int nvkm_fb_oneinit(struct nvkm_subdev *subdev) { struct nvkm_fb *fb = nvkm_fb(subdev); + if (fb->func->ram_new) { int ret = fb->func->ram_new(fb, &fb->ram); if (ret) { @@ -105,6 +107,13 @@ nvkm_fb_oneinit(struct nvkm_subdev *subdev) return ret; } } + + if (fb->func->oneinit) { + int ret = fb->func->oneinit(fb); + if (ret) + return ret; + } + return 0; } @@ -134,6 +143,9 @@ nvkm_fb_dtor(struct nvkm_subdev *subdev) struct nvkm_fb *fb = nvkm_fb(subdev); int i; + nvkm_memory_del(&fb->mmu_wr); + nvkm_memory_del(&fb->mmu_rd); + for (i = 0; i < fb->tile.regions; i++) fb->func->tile.fini(fb, i, &fb->tile.region[i]); @@ -156,7 +168,7 @@ void nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device, int index, struct nvkm_fb *fb) { - nvkm_subdev_ctor(&nvkm_fb, device, index, 0, &fb->subdev); + nvkm_subdev_ctor(&nvkm_fb, device, index, &fb->subdev); fb->func = func; fb->tile.regions = fb->func->tile.regions; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index 008bb9849f3b..e649ead5ccfc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -24,6 +24,9 @@ #include "gf100.h" #include "ram.h" +#include <core/memory.h> +#include <core/option.h> + extern const u8 gf100_pte_storage_type_map[256]; bool @@ -46,6 +49,28 @@ gf100_fb_intr(struct nvkm_fb *base) nvkm_debug(subdev, "PBFB intr\n"); } +int +gf100_fb_oneinit(struct nvkm_fb *fb) +{ + struct nvkm_device *device = fb->subdev.device; + int ret, size = 0x1000; + + size = nvkm_longopt(device->cfgopt, "MmuDebugBufferSize", size); + size = min(size, 0x1000); + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, + false, &fb->mmu_rd); + if (ret) + return ret; + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, + false, &fb->mmu_wr); + if (ret) + return ret; + + return 0; +} + void gf100_fb_init(struct nvkm_fb *base) { @@ -98,6 +123,7 @@ gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, static const struct nvkm_fb_func gf100_fb = { .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, .init = gf100_fb_init, .intr = gf100_fb_intr, .ram_new = gf100_ram_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c index 0edb3c316f5c..b41f0f70038c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c @@ -27,6 +27,7 @@ static const struct nvkm_fb_func gk104_fb = { .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, .init = gf100_fb_init, .intr = gf100_fb_intr, .ram_new = gk104_ram_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index 81447eb4c948..7306f7dfc3b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -21,15 +21,20 @@ */ #include "priv.h" +#include <core/memory.h> + static void gk20a_fb_init(struct nvkm_fb *fb) { struct nvkm_device *device = fb->subdev.device; nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ + nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->mmu_wr) >> 8); + nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->mmu_rd) >> 8); } static const struct nvkm_fb_func gk20a_fb = { + .oneinit = gf100_fb_oneinit, .init = gk20a_fb_init, .memtype_valid = gf100_fb_memtype_valid, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c index 2a91df8655dd..4869fdb753c9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c @@ -27,6 +27,7 @@ static const struct nvkm_fb_func gm107_fb = { .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, .init = gf100_fb_init, .intr = gf100_fb_intr, .ram_new = gm107_ram_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c new file mode 100644 index 000000000000..44f5716f64d8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gf100.h" +#include "ram.h" + +#include <core/memory.h> + +static void +gm200_fb_init(struct nvkm_fb *base) +{ + struct gf100_fb *fb = gf100_fb(base); + struct nvkm_device *device = fb->base.subdev.device; + + if (fb->r100c10_page) + nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); + + nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ + + nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8); + nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8); + nvkm_mask(device, 0x100cc4, 0x00060000, + min(nvkm_memory_size(fb->base.mmu_rd) >> 16, (u64)2) << 17); +} + +static const struct nvkm_fb_func +gm200_fb = { + .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, + .init = gm200_fb_init, + .intr = gf100_fb_intr, + .ram_new = gm107_ram_new, + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gm200_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gm200_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index 62b9feb531dc..d97d640e60a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -6,6 +6,7 @@ struct nvkm_bios; struct nvkm_fb_func { void *(*dtor)(struct nvkm_fb *); + int (*oneinit)(struct nvkm_fb *); void (*init)(struct nvkm_fb *); void (*intr)(struct nvkm_fb *); @@ -58,5 +59,6 @@ void nv44_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *); +int gf100_fb_oneinit(struct nvkm_fb *); bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c index f4144979a79c..1c3c18ea8ced 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c @@ -47,7 +47,7 @@ nvkm_fuse_new_(const struct nvkm_fuse_func *func, struct nvkm_device *device, struct nvkm_fuse *fuse; if (!(fuse = *pfuse = kzalloc(sizeof(*fuse), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_fuse, device, index, 0, &fuse->subdev); + nvkm_subdev_ctor(&nvkm_fuse, device, index, &fuse->subdev); fuse->func = func; spin_lock_init(&fuse->lock); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index d45ec99f0e38..77c649723ad7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -216,7 +216,7 @@ nvkm_gpio_new_(const struct nvkm_gpio_func *func, struct nvkm_device *device, if (!(gpio = *pgpio = kzalloc(sizeof(*gpio), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_gpio, device, index, 0, &gpio->subdev); + nvkm_subdev_ctor(&nvkm_gpio, device, index, &gpio->subdev); gpio->func = func; return nvkm_event_init(&nvkm_gpio_intr_func, 2, func->lines, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 243a71ff0a0d..4f197b15acf6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -254,7 +254,7 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_i2c, device, index, 0, &i2c->subdev); + nvkm_subdev_ctor(&nvkm_i2c, device, index, &i2c->subdev); i2c->func = func; INIT_LIST_HEAD(&i2c->pad); INIT_LIST_HEAD(&i2c->bus); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c index 72d6330d243d..2c6b374f1420 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c @@ -117,6 +117,6 @@ gf100_ibus_new(struct nvkm_device *device, int index, struct nvkm_subdev *ibus; if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&gf100_ibus, device, index, 0, ibus); + nvkm_subdev_ctor(&gf100_ibus, device, index, ibus); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf117.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf117.c index f69f263c5906..3905a80da811 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf117.c @@ -46,6 +46,6 @@ gf117_ibus_new(struct nvkm_device *device, int index, struct nvkm_subdev *ibus; if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&gf117_ibus, device, index, 0, ibus); + nvkm_subdev_ctor(&gf117_ibus, device, index, ibus); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c index b5cee3f89aaa..c673853f3213 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c @@ -120,6 +120,6 @@ gk104_ibus_new(struct nvkm_device *device, int index, struct nvkm_subdev *ibus; if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&gk104_ibus, device, index, 0, ibus); + nvkm_subdev_ctor(&gk104_ibus, device, index, ibus); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c index 3484079e885a..b7159b338fac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c @@ -84,6 +84,6 @@ gk20a_ibus_new(struct nvkm_device *device, int index, struct nvkm_subdev *ibus; if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&gk20a_ibus, device, index, 0, ibus); + nvkm_subdev_ctor(&gk20a_ibus, device, index, ibus); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm200.c index ef0b7f3b1128..c63328152bfa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gm200.c @@ -35,6 +35,6 @@ gm200_ibus_new(struct nvkm_device *device, int index, struct nvkm_subdev *ibus; if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&gm200_ibus, device, index, 0, ibus); + nvkm_subdev_ctor(&gm200_ibus, device, index, ibus); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c index c44a85228074..323c79abe468 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c @@ -30,15 +30,14 @@ static bool nvkm_iccsense_validate_device(struct i2c_adapter *i2c, u8 addr, - enum nvbios_extdev_type type, u8 rail) + enum nvbios_extdev_type type) { switch (type) { case NVBIOS_EXTDEV_INA209: case NVBIOS_EXTDEV_INA219: - return rail == 0 && nv_rd16i2cr(i2c, addr, 0x0) >= 0; + return nv_rd16i2cr(i2c, addr, 0x0) >= 0; case NVBIOS_EXTDEV_INA3221: - return rail <= 3 && - nv_rd16i2cr(i2c, addr, 0xff) == 0x3220 && + return nv_rd16i2cr(i2c, addr, 0xff) == 0x3220 && nv_rd16i2cr(i2c, addr, 0xfe) == 0x5449; default: return false; @@ -67,8 +66,9 @@ nvkm_iccsense_ina2x9_read(struct nvkm_iccsense *iccsense, struct nvkm_iccsense_rail *rail, u8 shunt_reg, u8 bus_reg) { - return nvkm_iccsense_poll_lane(rail->i2c, rail->addr, shunt_reg, 0, - bus_reg, 3, rail->mohm, 10 * 4); + return nvkm_iccsense_poll_lane(rail->sensor->i2c, rail->sensor->addr, + shunt_reg, 0, bus_reg, 3, rail->mohm, + 10 * 4); } static int @@ -89,37 +89,87 @@ static int nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense, struct nvkm_iccsense_rail *rail) { - return nvkm_iccsense_poll_lane(rail->i2c, rail->addr, - 1 + (rail->rail * 2), 3, - 2 + (rail->rail * 2), 3, rail->mohm, + return nvkm_iccsense_poll_lane(rail->sensor->i2c, rail->sensor->addr, + 1 + (rail->idx * 2), 3, + 2 + (rail->idx * 2), 3, rail->mohm, 40 * 8); } -int -nvkm_iccsense_read(struct nvkm_iccsense *iccsense, u8 idx) +static void +nvkm_iccsense_ina209_config(struct nvkm_iccsense *iccsense, + struct nvkm_iccsense_sensor *sensor) { - struct nvkm_iccsense_rail *rail; - - if (!iccsense || idx >= iccsense->rail_count) - return -EINVAL; + struct nvkm_subdev *subdev = &iccsense->subdev; + /* configuration: + * 0x0007: 0x0007 shunt and bus continous + * 0x0078: 0x0078 128 samples shunt + * 0x0780: 0x0780 128 samples bus + * 0x1800: 0x0000 +-40 mV shunt range + * 0x2000: 0x0000 16V FSR + */ + u16 value = 0x07ff; + nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value); + nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value); +} - rail = &iccsense->rails[idx]; - if (!rail->read) - return -ENODEV; +static void +nvkm_iccsense_ina3221_config(struct nvkm_iccsense *iccsense, + struct nvkm_iccsense_sensor *sensor) +{ + struct nvkm_subdev *subdev = &iccsense->subdev; + /* configuration: + * 0x0007: 0x0007 shunt and bus continous + * 0x0031: 0x0000 140 us conversion time shunt + * 0x01c0: 0x0000 140 us conversion time bus + * 0x0f00: 0x0f00 1024 samples + * 0x7000: 0x?000 channels + */ + u16 value = 0x0e07; + if (sensor->rail_mask & 0x1) + value |= 0x1 << 14; + if (sensor->rail_mask & 0x2) + value |= 0x1 << 13; + if (sensor->rail_mask & 0x4) + value |= 0x1 << 12; + nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value); + nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value); +} - return rail->read(iccsense, rail); +static void +nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense, + struct nvkm_iccsense_sensor *sensor) +{ + switch (sensor->type) { + case NVBIOS_EXTDEV_INA209: + case NVBIOS_EXTDEV_INA219: + nvkm_iccsense_ina209_config(iccsense, sensor); + break; + case NVBIOS_EXTDEV_INA3221: + nvkm_iccsense_ina3221_config(iccsense, sensor); + break; + default: + break; + } } int nvkm_iccsense_read_all(struct nvkm_iccsense *iccsense) { - int result = 0, i; - for (i = 0; i < iccsense->rail_count; ++i) { - int res = nvkm_iccsense_read(iccsense, i); - if (res >= 0) - result += res; - else + int result = 0; + struct nvkm_iccsense_rail *rail; + + if (!iccsense) + return -EINVAL; + + list_for_each_entry(rail, &iccsense->rails, head) { + int res; + if (!rail->read) + return -ENODEV; + + res = rail->read(iccsense, rail); + if (res < 0) return res; + result += res; } return result; } @@ -128,89 +178,158 @@ static void * nvkm_iccsense_dtor(struct nvkm_subdev *subdev) { struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev); + struct nvkm_iccsense_sensor *sensor, *tmps; + struct nvkm_iccsense_rail *rail, *tmpr; - if (iccsense->rails) - kfree(iccsense->rails); + list_for_each_entry_safe(sensor, tmps, &iccsense->sensors, head) { + list_del(&sensor->head); + kfree(sensor); + } + list_for_each_entry_safe(rail, tmpr, &iccsense->rails, head) { + list_del(&rail->head); + kfree(rail); + } return iccsense; } +static struct nvkm_iccsense_sensor* +nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id) +{ + + struct nvkm_subdev *subdev = &iccsense->subdev; + struct nvkm_bios *bios = subdev->device->bios; + struct nvkm_i2c *i2c = subdev->device->i2c; + struct nvbios_extdev_func extdev; + struct nvkm_i2c_bus *i2c_bus; + struct nvkm_iccsense_sensor *sensor; + u8 addr; + + if (!i2c || !bios || nvbios_extdev_parse(bios, id, &extdev)) + return NULL; + + if (extdev.type == 0xff) + return NULL; + + if (extdev.type != NVBIOS_EXTDEV_INA209 && + extdev.type != NVBIOS_EXTDEV_INA219 && + extdev.type != NVBIOS_EXTDEV_INA3221) { + iccsense->data_valid = false; + nvkm_error(subdev, "Unknown sensor type %x, power reading " + "disabled\n", extdev.type); + return NULL; + } + + if (extdev.bus) + i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_SEC); + else + i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_PRI); + if (!i2c_bus) + return NULL; + + addr = extdev.addr >> 1; + if (!nvkm_iccsense_validate_device(&i2c_bus->i2c, addr, + extdev.type)) { + iccsense->data_valid = false; + nvkm_warn(subdev, "found invalid sensor id: %i, power reading" + "might be invalid\n", id); + return NULL; + } + + sensor = kmalloc(sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + + list_add_tail(&sensor->head, &iccsense->sensors); + sensor->id = id; + sensor->type = extdev.type; + sensor->i2c = &i2c_bus->i2c; + sensor->addr = addr; + sensor->rail_mask = 0x0; + return sensor; +} + +static struct nvkm_iccsense_sensor* +nvkm_iccsense_get_sensor(struct nvkm_iccsense *iccsense, u8 id) +{ + struct nvkm_iccsense_sensor *sensor; + list_for_each_entry(sensor, &iccsense->sensors, head) { + if (sensor->id == id) + return sensor; + } + return nvkm_iccsense_create_sensor(iccsense, id); +} + static int nvkm_iccsense_oneinit(struct nvkm_subdev *subdev) { struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev); struct nvkm_bios *bios = subdev->device->bios; - struct nvkm_i2c *i2c = subdev->device->i2c; struct nvbios_iccsense stbl; int i; - if (!i2c || !bios || nvbios_iccsense_parse(bios, &stbl) - || !stbl.nr_entry) + if (!bios || nvbios_iccsense_parse(bios, &stbl) || !stbl.nr_entry) return 0; - iccsense->rails = kmalloc(sizeof(*iccsense->rails) * stbl.nr_entry, - GFP_KERNEL); - if (!iccsense->rails) - return -ENOMEM; - iccsense->data_valid = true; for (i = 0; i < stbl.nr_entry; ++i) { struct pwr_rail_t *r = &stbl.rail[i]; - struct nvbios_extdev_func extdev; struct nvkm_iccsense_rail *rail; - struct nvkm_i2c_bus *i2c_bus; - u8 addr; + struct nvkm_iccsense_sensor *sensor; if (!r->mode || r->resistor_mohm == 0) continue; - if (nvbios_extdev_parse(bios, r->extdev_id, &extdev)) + sensor = nvkm_iccsense_get_sensor(iccsense, r->extdev_id); + if (!sensor) continue; - if (extdev.type == 0xff) - continue; + rail = kmalloc(sizeof(*rail), GFP_KERNEL); + if (!rail) + return -ENOMEM; - if (extdev.bus) - i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_SEC); - else - i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_PRI); - if (!i2c_bus) - continue; - - addr = extdev.addr >> 1; - if (!nvkm_iccsense_validate_device(&i2c_bus->i2c, addr, - extdev.type, r->rail)) { - iccsense->data_valid = false; - nvkm_warn(subdev, "found unknown or invalid rail entry" - " type 0x%x rail %i, power reading might be" - " invalid\n", extdev.type, r->rail); - continue; - } - - rail = &iccsense->rails[iccsense->rail_count]; - switch (extdev.type) { + switch (sensor->type) { case NVBIOS_EXTDEV_INA209: + if (r->rail != 0) + continue; rail->read = nvkm_iccsense_ina209_read; break; case NVBIOS_EXTDEV_INA219: + if (r->rail != 0) + continue; rail->read = nvkm_iccsense_ina219_read; break; case NVBIOS_EXTDEV_INA3221: + if (r->rail >= 3) + continue; rail->read = nvkm_iccsense_ina3221_read; break; + default: + continue; } - rail->addr = addr; - rail->rail = r->rail; + sensor->rail_mask |= 1 << r->rail; + rail->sensor = sensor; + rail->idx = r->rail; rail->mohm = r->resistor_mohm; - rail->i2c = &i2c_bus->i2c; - ++iccsense->rail_count; + list_add_tail(&rail->head, &iccsense->rails); } return 0; } +static int +nvkm_iccsense_init(struct nvkm_subdev *subdev) +{ + struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev); + struct nvkm_iccsense_sensor *sensor; + list_for_each_entry(sensor, &iccsense->sensors, head) + nvkm_iccsense_sensor_config(iccsense, sensor); + return 0; +} + struct nvkm_subdev_func iccsense_func = { .oneinit = nvkm_iccsense_oneinit, + .init = nvkm_iccsense_init, .dtor = nvkm_iccsense_dtor, }; @@ -218,7 +337,7 @@ void nvkm_iccsense_ctor(struct nvkm_device *device, int index, struct nvkm_iccsense *iccsense) { - nvkm_subdev_ctor(&iccsense_func, device, index, 0, &iccsense->subdev); + nvkm_subdev_ctor(&iccsense_func, device, index, &iccsense->subdev); } int @@ -227,6 +346,8 @@ nvkm_iccsense_new_(struct nvkm_device *device, int index, { if (!(*iccsense = kzalloc(sizeof(**iccsense), GFP_KERNEL))) return -ENOMEM; + INIT_LIST_HEAD(&(*iccsense)->sensors); + INIT_LIST_HEAD(&(*iccsense)->rails); nvkm_iccsense_ctor(device, index, *iccsense); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h index ed398b81e86e..b72c31d2f908 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h @@ -2,12 +2,22 @@ #define __NVKM_ICCSENSE_PRIV_H__ #define nvkm_iccsense(p) container_of((p), struct nvkm_iccsense, subdev) #include <subdev/iccsense.h> +#include <subdev/bios/extdev.h> -struct nvkm_iccsense_rail { - int (*read)(struct nvkm_iccsense *, struct nvkm_iccsense_rail *); +struct nvkm_iccsense_sensor { + struct list_head head; + int id; + enum nvbios_extdev_type type; struct i2c_adapter *i2c; u8 addr; - u8 rail; + u8 rail_mask; +}; + +struct nvkm_iccsense_rail { + struct list_head head; + int (*read)(struct nvkm_iccsense *, struct nvkm_iccsense_rail *); + struct nvkm_iccsense_sensor *sensor; + u8 idx; u8 mohm; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 1d7dd38292b3..8ed8f65ff664 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -311,7 +311,7 @@ nvkm_instmem_ctor(const struct nvkm_instmem_func *func, struct nvkm_device *device, int index, struct nvkm_instmem *imem) { - nvkm_subdev_ctor(&nvkm_instmem, device, index, 0, &imem->subdev); + nvkm_subdev_ctor(&nvkm_instmem, device, index, &imem->subdev); imem->func = func; spin_lock_init(&imem->lock); INIT_LIST_HEAD(&imem->list); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c index 85b1464c0194..39c2a38e54f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c @@ -138,7 +138,7 @@ nvkm_ltc_new_(const struct nvkm_ltc_func *func, struct nvkm_device *device, if (!(ltc = *pltc = kzalloc(sizeof(*ltc), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_ltc, device, index, 0, <c->subdev); + nvkm_subdev_ctor(&nvkm_ltc, device, index, <c->subdev); ltc->func = func; ltc->zbc_min = 1; /* reserve 0 for disabled */ ltc->zbc_max = min(func->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild index bef325dcb4d0..49695ac7be2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild @@ -1,7 +1,12 @@ nvkm-y += nvkm/subdev/mc/base.o nvkm-y += nvkm/subdev/mc/nv04.o +nvkm-y += nvkm/subdev/mc/nv11.o +nvkm-y += nvkm/subdev/mc/nv17.o nvkm-y += nvkm/subdev/mc/nv44.o nvkm-y += nvkm/subdev/mc/nv50.o +nvkm-y += nvkm/subdev/mc/g84.o nvkm-y += nvkm/subdev/mc/g98.o +nvkm-y += nvkm/subdev/mc/gt215.o nvkm-y += nvkm/subdev/mc/gf100.o +nvkm-y += nvkm/subdev/mc/gk104.o nvkm-y += nvkm/subdev/mc/gk20a.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 954fbbe56c4b..350a8caa84c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -24,6 +24,7 @@ #include "priv.h" #include <core/option.h> +#include <subdev/top.h> void nvkm_mc_unk260(struct nvkm_mc *mc, u32 data) @@ -58,10 +59,19 @@ nvkm_mc_intr(struct nvkm_mc *mc, bool *handled) { struct nvkm_device *device = mc->subdev.device; struct nvkm_subdev *subdev; - const struct nvkm_mc_intr *map = mc->func->intr; - u32 stat, intr; + const struct nvkm_mc_map *map = mc->func->intr; + u32 stat, intr = nvkm_mc_intr_mask(mc); + u64 subdevs; + + stat = nvkm_top_intr(device->top, intr, &subdevs); + while (subdevs) { + enum nvkm_devidx subidx = __ffs64(subdevs); + subdev = nvkm_device_subdev(device, subidx); + if (subdev) + nvkm_subdev_intr(subdev); + subdevs &= ~BIT_ULL(subidx); + } - stat = intr = nvkm_mc_intr_mask(mc); while (map->stat) { if (intr & map->stat) { subdev = nvkm_device_subdev(device, map->unit); @@ -77,6 +87,36 @@ nvkm_mc_intr(struct nvkm_mc *mc, bool *handled) *handled = intr != 0; } +static void +nvkm_mc_reset_(struct nvkm_mc *mc, enum nvkm_devidx devidx) +{ + struct nvkm_device *device = mc->subdev.device; + const struct nvkm_mc_map *map; + u64 pmc_enable; + + if (!(pmc_enable = nvkm_top_reset(device->top, devidx))) { + for (map = mc->func->reset; map && map->stat; map++) { + if (map->unit == devidx) { + pmc_enable = map->stat; + break; + } + } + } + + if (pmc_enable) { + nvkm_mask(device, 0x000200, pmc_enable, 0x00000000); + nvkm_mask(device, 0x000200, pmc_enable, pmc_enable); + nvkm_rd32(device, 0x000200); + } +} + +void +nvkm_mc_reset(struct nvkm_mc *mc, enum nvkm_devidx devidx) +{ + if (likely(mc)) + nvkm_mc_reset_(mc, devidx); +} + static int nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend) { @@ -117,7 +157,7 @@ nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_mc, device, index, 0, &mc->subdev); + nvkm_subdev_ctor(&nvkm_mc, device, index, &mc->subdev); mc->func = func; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c new file mode 100644 index 000000000000..5c85b47f071d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c @@ -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 "priv.h" + +static const struct nvkm_mc_map +g84_mc_reset[] = { + { 0x04008000, NVKM_ENGINE_BSP }, + { 0x02004000, NVKM_ENGINE_CIPHER }, + { 0x01020000, NVKM_ENGINE_VP }, + { 0x00400002, NVKM_ENGINE_MPEG }, + { 0x00201000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + {} +}; + +const struct nvkm_mc_map +g84_mc_intr[] = { + { 0x04000000, NVKM_ENGINE_DISP }, + { 0x00020000, NVKM_ENGINE_VP }, + { 0x00008000, NVKM_ENGINE_BSP }, + { 0x00004000, NVKM_ENGINE_CIPHER }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000001, NVKM_ENGINE_MPEG }, + { 0x0002d101, NVKM_SUBDEV_FB }, + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x00200000, NVKM_SUBDEV_GPIO }, + { 0x00200000, NVKM_SUBDEV_I2C }, + { 0x00100000, NVKM_SUBDEV_TIMER }, + {}, +}; + +static const struct nvkm_mc_func +g84_mc = { + .init = nv50_mc_init, + .intr = g84_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, + .reset = g84_mc_reset, +}; + +int +g84_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&g84_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index 7344ad659105..0280b43cc10c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -23,24 +23,31 @@ */ #include "priv.h" -static const struct nvkm_mc_intr -g98_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */ - { 0x00000001, NVKM_ENGINE_MSPPP }, +static const struct nvkm_mc_map +g98_mc_reset[] = { + { 0x04008000, NVKM_ENGINE_MSVLD }, + { 0x02004000, NVKM_ENGINE_SEC }, + { 0x01020000, NVKM_ENGINE_MSPDEC }, + { 0x00400002, NVKM_ENGINE_MSPPP }, + { 0x00201000, NVKM_ENGINE_GR }, { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00004000, NVKM_ENGINE_SEC }, /* NV84:NVA3 */ - { 0x00008000, NVKM_ENGINE_MSVLD }, + {} +}; + +static const struct nvkm_mc_map +g98_mc_intr[] = { + { 0x04000000, NVKM_ENGINE_DISP }, { 0x00020000, NVKM_ENGINE_MSPDEC }, - { 0x00040000, NVKM_SUBDEV_PMU }, /* NVA3:NVC0 */ - { 0x00080000, NVKM_SUBDEV_THERM }, /* NVA3:NVC0 */ - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x00200000, NVKM_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVKM_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x00400000, NVKM_ENGINE_CE0 }, /* NVA3- */ + { 0x00008000, NVKM_ENGINE_MSVLD }, + { 0x00004000, NVKM_ENGINE_SEC }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000001, NVKM_ENGINE_MSPPP }, + { 0x0002d101, NVKM_SUBDEV_FB }, { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x80000000, NVKM_ENGINE_SW }, - { 0x0042d101, NVKM_SUBDEV_FB }, + { 0x00200000, NVKM_SUBDEV_GPIO }, + { 0x00200000, NVKM_SUBDEV_I2C }, + { 0x00100000, NVKM_SUBDEV_TIMER }, {}, }; @@ -51,6 +58,7 @@ g98_mc = { .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, .intr_mask = nv04_mc_intr_mask, + .reset = g98_mc_reset, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 122fe69e83e4..8397e223bd43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -23,28 +23,38 @@ */ #include "priv.h" -const struct nvkm_mc_intr -gf100_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, /* DISP first, so pageflip timestamps work. */ - { 0x00000001, NVKM_ENGINE_MSPPP }, - { 0x00000020, NVKM_ENGINE_CE0 }, - { 0x00000040, NVKM_ENGINE_CE1 }, - { 0x00000080, NVKM_ENGINE_CE2 }, - { 0x00000100, NVKM_ENGINE_FIFO }, - { 0x00001000, NVKM_ENGINE_GR }, - { 0x00002000, NVKM_SUBDEV_FB }, +static const struct nvkm_mc_map +gf100_mc_reset[] = { + { 0x00020000, NVKM_ENGINE_MSPDEC }, { 0x00008000, NVKM_ENGINE_MSVLD }, - { 0x00040000, NVKM_SUBDEV_THERM }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000080, NVKM_ENGINE_CE1 }, + { 0x00000040, NVKM_ENGINE_CE0 }, + { 0x00000002, NVKM_ENGINE_MSPPP }, + {} +}; + +static const struct nvkm_mc_map +gf100_mc_intr[] = { + { 0x04000000, NVKM_ENGINE_DISP }, { 0x00020000, NVKM_ENGINE_MSPDEC }, - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x00200000, NVKM_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVKM_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x01000000, NVKM_SUBDEV_PMU }, - { 0x02000000, NVKM_SUBDEV_LTC }, - { 0x08000000, NVKM_SUBDEV_FB }, - { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x00008000, NVKM_ENGINE_MSVLD }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000040, NVKM_ENGINE_CE1 }, + { 0x00000020, NVKM_ENGINE_CE0 }, + { 0x00000001, NVKM_ENGINE_MSPPP }, { 0x40000000, NVKM_SUBDEV_IBUS }, - { 0x80000000, NVKM_ENGINE_SW }, + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x08000000, NVKM_SUBDEV_FB }, + { 0x02000000, NVKM_SUBDEV_LTC }, + { 0x01000000, NVKM_SUBDEV_PMU }, + { 0x00200000, NVKM_SUBDEV_GPIO }, + { 0x00200000, NVKM_SUBDEV_I2C }, + { 0x00100000, NVKM_SUBDEV_TIMER }, + { 0x00040000, NVKM_SUBDEV_THERM }, + { 0x00002000, NVKM_SUBDEV_FB }, {}, }; @@ -87,6 +97,7 @@ gf100_mc = { .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, .intr_mask = gf100_mc_intr_mask, + .reset = gf100_mc_reset, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c new file mode 100644 index 000000000000..317464212c7d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c @@ -0,0 +1,64 @@ +/* + * Copyright 2016 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" + +const struct nvkm_mc_map +gk104_mc_reset[] = { + { 0x00000100, NVKM_ENGINE_FIFO }, + {} +}; + +const struct nvkm_mc_map +gk104_mc_intr[] = { + { 0x04000000, NVKM_ENGINE_DISP }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x40000000, NVKM_SUBDEV_IBUS }, + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x08000000, NVKM_SUBDEV_FB }, + { 0x02000000, NVKM_SUBDEV_LTC }, + { 0x01000000, NVKM_SUBDEV_PMU }, + { 0x00200000, NVKM_SUBDEV_GPIO }, + { 0x00200000, NVKM_SUBDEV_I2C }, + { 0x00100000, NVKM_SUBDEV_TIMER }, + { 0x00040000, NVKM_SUBDEV_THERM }, + { 0x00002000, NVKM_SUBDEV_FB }, + {}, +}; + +static const struct nvkm_mc_func +gk104_mc = { + .init = nv50_mc_init, + .intr = gk104_mc_intr, + .intr_unarm = gf100_mc_intr_unarm, + .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, + .reset = gk104_mc_reset, + .unk260 = gf100_mc_unk260, +}; + +int +gk104_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&gk104_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index d92efb33bcc3..60b044f517ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -26,10 +26,11 @@ static const struct nvkm_mc_func gk20a_mc = { .init = nv50_mc_init, - .intr = gf100_mc_intr, + .intr = gk104_mc_intr, .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, .intr_mask = gf100_mc_intr_mask, + .reset = gk104_mc_reset, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c new file mode 100644 index 000000000000..aad0ba95bf18 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c @@ -0,0 +1,70 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" + +static const struct nvkm_mc_map +gt215_mc_reset[] = { + { 0x04008000, NVKM_ENGINE_MSVLD }, + { 0x01020000, NVKM_ENGINE_MSPDEC }, + { 0x00802000, NVKM_ENGINE_CE0 }, + { 0x00400002, NVKM_ENGINE_MSPPP }, + { 0x00201000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + {} +}; + +static const struct nvkm_mc_map +gt215_mc_intr[] = { + { 0x04000000, NVKM_ENGINE_DISP }, + { 0x00400000, NVKM_ENGINE_CE0 }, + { 0x00020000, NVKM_ENGINE_MSPDEC }, + { 0x00008000, NVKM_ENGINE_MSVLD }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000001, NVKM_ENGINE_MSPPP }, + { 0x00429101, NVKM_SUBDEV_FB }, + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x00200000, NVKM_SUBDEV_GPIO }, + { 0x00200000, NVKM_SUBDEV_I2C }, + { 0x00100000, NVKM_SUBDEV_TIMER }, + { 0x00080000, NVKM_SUBDEV_THERM }, + { 0x00040000, NVKM_SUBDEV_PMU }, + {}, +}; + +static const struct nvkm_mc_func +gt215_mc = { + .init = nv50_mc_init, + .intr = gt215_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, + .reset = gt215_mc_reset, +}; + +int +gt215_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(>215_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index d282ec1555f8..a062624e906b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -23,18 +23,20 @@ */ #include "priv.h" -const struct nvkm_mc_intr -nv04_mc_intr[] = { - { 0x00000001, NVKM_ENGINE_MPEG }, /* NV17- MPEG/ME */ +const struct nvkm_mc_map +nv04_mc_reset[] = { + { 0x00001000, NVKM_ENGINE_GR }, { 0x00000100, NVKM_ENGINE_FIFO }, + {} +}; + +static const struct nvkm_mc_map +nv04_mc_intr[] = { + { 0x01010000, NVKM_ENGINE_DISP }, { 0x00001000, NVKM_ENGINE_GR }, - { 0x00010000, NVKM_ENGINE_DISP }, - { 0x00020000, NVKM_ENGINE_VP }, /* NV40- */ - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x01000000, NVKM_ENGINE_DISP }, /* NV04- PCRTC0 */ - { 0x02000000, NVKM_ENGINE_DISP }, /* NV11- PCRTC1 */ + { 0x00000100, NVKM_ENGINE_FIFO }, { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x80000000, NVKM_ENGINE_SW }, + { 0x00100000, NVKM_SUBDEV_TIMER }, {} }; @@ -74,6 +76,7 @@ nv04_mc = { .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, .intr_mask = nv04_mc_intr_mask, + .reset = nv04_mc_reset, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c new file mode 100644 index 000000000000..55f0b9166b52 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#include "priv.h" + +static const struct nvkm_mc_map +nv11_mc_intr[] = { + { 0x03010000, NVKM_ENGINE_DISP }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x00100000, NVKM_SUBDEV_TIMER }, + {} +}; + +static const struct nvkm_mc_func +nv11_mc = { + .init = nv04_mc_init, + .intr = nv11_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, + .reset = nv04_mc_reset, +}; + +int +nv11_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv11_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c new file mode 100644 index 000000000000..c40fa67f79a5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#include "priv.h" + +const struct nvkm_mc_map +nv17_mc_reset[] = { + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000002, NVKM_ENGINE_MPEG }, + {} +}; + +const struct nvkm_mc_map +nv17_mc_intr[] = { + { 0x03010000, NVKM_ENGINE_DISP }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000001, NVKM_ENGINE_MPEG }, + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x00100000, NVKM_SUBDEV_TIMER }, + {} +}; + +static const struct nvkm_mc_func +nv17_mc = { + .init = nv04_mc_init, + .intr = nv17_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, + .reset = nv17_mc_reset, +}; + +int +nv17_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv17_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index 9a3ac9965be0..cc56271db564 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -40,10 +40,11 @@ nv44_mc_init(struct nvkm_mc *mc) static const struct nvkm_mc_func nv44_mc = { .init = nv44_mc_init, - .intr = nv04_mc_intr, + .intr = nv17_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, .intr_mask = nv04_mc_intr_mask, + .reset = nv17_mc_reset, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 5f27d7b8fddd..343b6078580d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -23,21 +23,17 @@ */ #include "priv.h" -const struct nvkm_mc_intr +static const struct nvkm_mc_map nv50_mc_intr[] = { - { 0x04000000, NVKM_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */ - { 0x00000001, NVKM_ENGINE_MPEG }, - { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x04000000, NVKM_ENGINE_DISP }, { 0x00001000, NVKM_ENGINE_GR }, - { 0x00004000, NVKM_ENGINE_CIPHER }, /* NV84- */ - { 0x00008000, NVKM_ENGINE_BSP }, /* NV84- */ - { 0x00020000, NVKM_ENGINE_VP }, /* NV84- */ - { 0x00100000, NVKM_SUBDEV_TIMER }, - { 0x00200000, NVKM_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVKM_SUBDEV_I2C }, /* PMGR->I2C/AUX */ + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00000001, NVKM_ENGINE_MPEG }, + { 0x00001101, NVKM_SUBDEV_FB }, { 0x10000000, NVKM_SUBDEV_BUS }, - { 0x80000000, NVKM_ENGINE_SW }, - { 0x0002d101, NVKM_SUBDEV_FB }, + { 0x00200000, NVKM_SUBDEV_GPIO }, + { 0x00200000, NVKM_SUBDEV_I2C }, + { 0x00100000, NVKM_SUBDEV_TIMER }, {}, }; @@ -55,6 +51,7 @@ nv50_mc = { .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, .intr_mask = nv04_mc_intr_mask, + .reset = nv17_mc_reset, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index 307f6c692287..a12038118512 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -6,37 +6,42 @@ int nvkm_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, int index, struct nvkm_mc **); -struct nvkm_mc_intr { +struct nvkm_mc_map { u32 stat; u32 unit; }; struct nvkm_mc_func { void (*init)(struct nvkm_mc *); - const struct nvkm_mc_intr *intr; + const struct nvkm_mc_map *intr; /* disable reporting of interrupts to host */ void (*intr_unarm)(struct nvkm_mc *); /* enable reporting of interrupts to host */ void (*intr_rearm)(struct nvkm_mc *); /* retrieve pending interrupt mask (NV_PMC_INTR) */ u32 (*intr_mask)(struct nvkm_mc *); + const struct nvkm_mc_map *reset; void (*unk260)(struct nvkm_mc *, u32); }; void nv04_mc_init(struct nvkm_mc *); -extern const struct nvkm_mc_intr nv04_mc_intr[]; void nv04_mc_intr_unarm(struct nvkm_mc *); void nv04_mc_intr_rearm(struct nvkm_mc *); u32 nv04_mc_intr_mask(struct nvkm_mc *); +extern const struct nvkm_mc_map nv04_mc_reset[]; + +extern const struct nvkm_mc_map nv17_mc_intr[]; +extern const struct nvkm_mc_map nv17_mc_reset[]; void nv44_mc_init(struct nvkm_mc *); void nv50_mc_init(struct nvkm_mc *); -extern const struct nvkm_mc_intr nv50_mc_intr[]; -extern const struct nvkm_mc_intr gf100_mc_intr[]; void gf100_mc_intr_unarm(struct nvkm_mc *); void gf100_mc_intr_rearm(struct nvkm_mc *); u32 gf100_mc_intr_mask(struct nvkm_mc *); void gf100_mc_unk260(struct nvkm_mc *, u32); + +extern const struct nvkm_mc_map gk104_mc_intr[]; +extern const struct nvkm_mc_map gk104_mc_reset[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index e04a2296ecd0..5df9669ea39c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -524,7 +524,7 @@ void nvkm_mmu_ctor(const struct nvkm_mmu_func *func, struct nvkm_device *device, int index, struct nvkm_mmu *mmu) { - nvkm_subdev_ctor(&nvkm_mmu, device, index, 0, &mmu->subdev); + nvkm_subdev_ctor(&nvkm_mmu, device, index, &mmu->subdev); mmu->func = func; mmu->limit = func->limit; mmu->dma_bits = func->dma_bits; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 9700a7625012..21b65ee254e4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -241,7 +241,7 @@ nvkm_mxm_new_(struct nvkm_device *device, int index, struct nvkm_mxm **pmxm) if (!(mxm = *pmxm = kzalloc(sizeof(*mxm), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_mxm, device, index, 0, &mxm->subdev); + nvkm_subdev_ctor(&nvkm_mxm, device, index, &mxm->subdev); data = mxm_table(bios, &ver, &len); if (!data || !(ver = nvbios_rd08(bios, data))) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index 65057c8310a2..6b0328bd7eed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -168,7 +168,7 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_pci_func, device, index, 0, &pci->subdev); + nvkm_subdev_ctor(&nvkm_pci_func, device, index, &pci->subdev); pci->func = func; pci->pdev = device->func->pci(device)->pdev; pci->irq = -1; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index d95eb8659d1b..8dd164d13043 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -40,21 +40,23 @@ nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], struct nvkm_device *device = subdev->device; u32 addr; + mutex_lock(&subdev->mutex); /* wait for a free slot in the fifo */ addr = nvkm_rd32(device, 0x10a4a0); if (nvkm_msec(device, 2000, u32 tmp = nvkm_rd32(device, 0x10a4b0); if (tmp != (addr ^ 8)) break; - ) < 0) + ) < 0) { + mutex_unlock(&subdev->mutex); return -EBUSY; + } /* we currently only support a single process at a time waiting * on a synchronous reply, take the PMU mutex and tell the * receive handler what we're waiting for */ if (reply) { - mutex_lock(&subdev->mutex); pmu->recv.message = message; pmu->recv.process = process; } @@ -81,9 +83,9 @@ nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], wait_event(pmu->recv.wait, (pmu->recv.process == 0)); reply[0] = pmu->recv.data[0]; reply[1] = pmu->recv.data[1]; - mutex_unlock(&subdev->mutex); } + mutex_unlock(&subdev->mutex); return 0; } @@ -272,7 +274,7 @@ nvkm_pmu_new_(const struct nvkm_pmu_func *func, struct nvkm_device *device, struct nvkm_pmu *pmu; if (!(pmu = *ppmu = kzalloc(sizeof(*pmu), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_pmu, device, index, 0, &pmu->subdev); + nvkm_subdev_ctor(&nvkm_pmu, device, index, &pmu->subdev); pmu->func = func; INIT_WORK(&pmu->recv.work, nvkm_pmu_recv); init_waitqueue_head(&pmu->recv.wait); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 6689d0290a7e..f996d90c9f0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -220,7 +220,7 @@ gk20a_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) pmu->base.func = &func; *ppmu = &pmu->base; - nvkm_subdev_ctor(&gk20a_pmu, device, index, 0, &pmu->base.subdev); + nvkm_subdev_ctor(&gk20a_pmu, device, index, &pmu->base.subdev); pmu->data = &gk20a_dvfs_data; nvkm_alarm_init(&pmu->alarm, gk20a_pmu_dvfs_work); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c index 520facf9bc07..213fdba6cfa0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c @@ -264,7 +264,7 @@ nvkm_secboot_ctor(const struct nvkm_secboot_func *func, { unsigned long fid; - nvkm_subdev_ctor(&nvkm_secboot, device, index, 0, &sb->subdev); + nvkm_subdev_ctor(&nvkm_secboot, device, index, &sb->subdev); sb->func = func; /* setup the performing falcon's base address and masks */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index 949dc6101a58..8894fee30cbc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -366,7 +366,7 @@ nvkm_therm_new_(const struct nvkm_therm_func *func, struct nvkm_device *device, if (!(therm = *ptherm = kzalloc(sizeof(*therm), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_therm, device, index, 0, &therm->subdev); + nvkm_subdev_ctor(&nvkm_therm, device, index, &therm->subdev); therm->func = func; nvkm_alarm_init(&therm->alarm, nvkm_therm_alarm); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index d4dae1f12d62..07dc82bfe346 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -143,7 +143,7 @@ nvkm_timer_new_(const struct nvkm_timer_func *func, struct nvkm_device *device, if (!(tmr = *ptmr = kzalloc(sizeof(*tmr), GFP_KERNEL))) return -ENOMEM; - nvkm_subdev_ctor(&nvkm_timer, device, index, 0, &tmr->subdev); + nvkm_subdev_ctor(&nvkm_timer, device, index, &tmr->subdev); tmr->func = func; INIT_LIST_HEAD(&tmr->alarms); spin_lock_init(&tmr->lock); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/top/Kbuild new file mode 100644 index 000000000000..1078401cdcea --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/Kbuild @@ -0,0 +1,2 @@ +nvkm-y += nvkm/subdev/top/base.o +nvkm-y += nvkm/subdev/top/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c new file mode 100644 index 000000000000..a1b264664aad --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c @@ -0,0 +1,148 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#include "priv.h" + +struct nvkm_top_device * +nvkm_top_device_new(struct nvkm_top *top) +{ + struct nvkm_top_device *info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info) { + info->index = NVKM_SUBDEV_NR; + info->addr = 0; + info->fault = -1; + info->engine = -1; + info->runlist = -1; + info->reset = -1; + info->intr = -1; + list_add_tail(&info->head, &top->device); + } + return info; +} + +u32 +nvkm_top_reset(struct nvkm_top *top, enum nvkm_devidx index) +{ + struct nvkm_top_device *info; + + if (top) { + list_for_each_entry(info, &top->device, head) { + if (info->index == index && info->reset >= 0) + return BIT(info->reset); + } + } + + return 0; +} + +u32 +nvkm_top_intr(struct nvkm_top *top, u32 intr, u64 *psubdevs) +{ + struct nvkm_top_device *info; + u64 subdevs = 0; + u32 handled = 0; + + if (top) { + list_for_each_entry(info, &top->device, head) { + if (info->index != NVKM_SUBDEV_NR && info->intr >= 0) { + if (intr & BIT(info->intr)) { + subdevs |= BIT_ULL(info->index); + handled |= BIT(info->intr); + } + } + } + } + + *psubdevs = subdevs; + return intr & ~handled; +} + +enum nvkm_devidx +nvkm_top_fault(struct nvkm_top *top, int fault) +{ + struct nvkm_top_device *info; + + list_for_each_entry(info, &top->device, head) { + if (info->fault == fault) + return info->index; + } + + return NVKM_SUBDEV_NR; +} + +enum nvkm_devidx +nvkm_top_engine(struct nvkm_top *top, int index, int *runl, int *engn) +{ + struct nvkm_top_device *info; + int n = 0; + + list_for_each_entry(info, &top->device, head) { + if (info->engine >= 0 && info->runlist >= 0 && n++ == index) { + *runl = info->runlist; + *engn = info->engine; + return info->index; + } + } + + return -ENODEV; +} + +static int +nvkm_top_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_top *top = nvkm_top(subdev); + return top->func->oneinit(top); +} + +static void * +nvkm_top_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_top *top = nvkm_top(subdev); + struct nvkm_top_device *info, *temp; + + list_for_each_entry_safe(info, temp, &top->device, head) { + list_del(&info->head); + kfree(info); + } + + return top; +} + +static const struct nvkm_subdev_func +nvkm_top = { + .dtor = nvkm_top_dtor, + .oneinit = nvkm_top_oneinit, +}; + +int +nvkm_top_new_(const struct nvkm_top_func *func, struct nvkm_device *device, + int index, struct nvkm_top **ptop) +{ + struct nvkm_top *top; + if (!(top = *ptop = kzalloc(sizeof(*top), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_top, device, index, &top->subdev); + top->func = func; + INIT_LIST_HEAD(&top->device); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c new file mode 100644 index 000000000000..e06acc340e99 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c @@ -0,0 +1,110 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#include "priv.h" + +static int +gk104_top_oneinit(struct nvkm_top *top) +{ + struct nvkm_subdev *subdev = &top->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_top_device *info = NULL; + u32 data, type; + int i; + + for (i = 0; i < 64; i++) { + if (!info) { + if (!(info = nvkm_top_device_new(top))) + return -ENOMEM; + type = ~0; + } + + data = nvkm_rd32(device, 0x022700 + (i * 0x04)); + nvkm_trace(subdev, "%02x: %08x\n", i, data); + switch (data & 0x00000003) { + case 0x00000000: /* NOT_VALID */ + continue; + case 0x00000001: /* DATA */ + info->addr = (data & 0x00fff000); + info->fault = (data & 0x000000f8) >> 3; + break; + case 0x00000002: /* ENUM */ + if (data & 0x00000020) + info->engine = (data & 0x3c000000) >> 26; + if (data & 0x00000010) + info->runlist = (data & 0x01e00000) >> 21; + if (data & 0x00000008) + info->intr = (data & 0x000f8000) >> 15; + if (data & 0x00000004) + info->reset = (data & 0x00003e00) >> 9; + break; + case 0x00000003: /* ENGINE_TYPE */ + type = (data & 0x7ffffffc) >> 2; + break; + } + + if (data & 0x80000000) + continue; + + /* Translate engine type to NVKM engine identifier. */ + switch (type) { + case 0x00000000: info->index = NVKM_ENGINE_GR; break; + case 0x00000001: info->index = NVKM_ENGINE_CE0; break; + case 0x00000002: info->index = NVKM_ENGINE_CE1; break; + case 0x00000003: info->index = NVKM_ENGINE_CE2; break; + case 0x00000008: info->index = NVKM_ENGINE_MSPDEC; break; + case 0x00000009: info->index = NVKM_ENGINE_MSPPP; break; + case 0x0000000a: info->index = NVKM_ENGINE_MSVLD; break; + case 0x0000000b: info->index = NVKM_ENGINE_MSENC; break; + case 0x0000000c: info->index = NVKM_ENGINE_VIC; break; + case 0x0000000d: info->index = NVKM_ENGINE_SEC; break; + case 0x0000000e: info->index = NVKM_ENGINE_NVENC0; break; + case 0x0000000f: info->index = NVKM_ENGINE_NVENC1; break; + case 0x00000010: info->index = NVKM_ENGINE_NVDEC; break; + break; + default: + break; + } + + nvkm_debug(subdev, "%02x (%8s): addr %06x fault %2d engine %2d " + "runlist %2d intr %2d reset %2d\n", type, + info->index == NVKM_SUBDEV_NR ? NULL : + nvkm_subdev_name[info->index], + info->addr, info->fault, info->engine, info->runlist, + info->intr, info->reset); + info = NULL; + } + + return 0; +} + +static const struct nvkm_top_func +gk104_top = { + .oneinit = gk104_top_oneinit, +}; + +int +gk104_top_new(struct nvkm_device *device, int index, struct nvkm_top **ptop) +{ + return nvkm_top_new_(&gk104_top, device, index, ptop); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h new file mode 100644 index 000000000000..adb3ed03d937 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/priv.h @@ -0,0 +1,25 @@ +#ifndef __NVKM_TOP_PRIV_H__ +#define __NVKM_TOP_PRIV_H__ +#define nvkm_top(p) container_of((p), struct nvkm_top, subdev) +#include <subdev/top.h> + +struct nvkm_top_func { + int (*oneinit)(struct nvkm_top *); +}; + +int nvkm_top_new_(const struct nvkm_top_func *, struct nvkm_device *, + int, struct nvkm_top **); + +struct nvkm_top_device { + enum nvkm_devidx index; + u32 addr; + int fault; + int engine; + int runlist; + int reset; + int intr; + struct list_head head; +}; + +struct nvkm_top_device *nvkm_top_device_new(struct nvkm_top *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 50b5649ad1a4..6b2d7531a7ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -177,7 +177,7 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, struct nvkm_bios *bios = device->bios; int i; - nvkm_subdev_ctor(&nvkm_volt, device, index, 0, &volt->subdev); + nvkm_subdev_ctor(&nvkm_volt, device, index, &volt->subdev); volt->func = func; /* Assuming the non-bios device should build the voltage table later */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c index b735173a18ff..420bd84d8483 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c @@ -56,7 +56,7 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv) /* the blob uses this crystal frequency, let's use it too. */ div = 27648000 / bios->pwm_freq; - duty = (uv - bios->base) * div / bios->pwm_range; + duty = DIV_ROUND_UP((uv - bios->base) * div, bios->pwm_range); nvkm_wr32(device, 0x20340, div); nvkm_wr32(device, 0x20344, 0x80000000 | duty); |