diff options
Diffstat (limited to 'kernel/drivers/gpu/drm/nouveau/nvkm/subdev')
294 files changed, 13670 insertions, 11923 deletions
diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild index a1bb3e487..ee2c38f50 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild @@ -13,6 +13,7 @@ include $(src)/nvkm/subdev/ltc/Kbuild include $(src)/nvkm/subdev/mc/Kbuild include $(src)/nvkm/subdev/mmu/Kbuild include $(src)/nvkm/subdev/mxm/Kbuild +include $(src)/nvkm/subdev/pci/Kbuild include $(src)/nvkm/subdev/pmu/Kbuild include $(src)/nvkm/subdev/therm/Kbuild include $(src)/nvkm/subdev/timer/Kbuild diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild index 1ab554a0b..1e138b337 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild @@ -1,4 +1,5 @@ nvkm-y += nvkm/subdev/bar/base.o nvkm-y += nvkm/subdev/bar/nv50.o +nvkm-y += nvkm/subdev/bar/g84.o nvkm-y += nvkm/subdev/bar/gf100.o nvkm-y += nvkm/subdev/bar/gk20a.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index 3502d0012..a9433ad45 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -23,122 +23,61 @@ */ #include "priv.h" -#include <core/device.h> -#include <subdev/fb.h> -#include <subdev/mmu.h> - -struct nvkm_barobj { - struct nvkm_object base; - struct nvkm_vma vma; - void __iomem *iomem; -}; - -static int -nvkm_barobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +void +nvkm_bar_flush(struct nvkm_bar *bar) { - struct nvkm_device *device = nv_device(parent); - struct nvkm_bar *bar = nvkm_bar(device); - struct nvkm_mem *mem = data; - struct nvkm_barobj *barobj; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &barobj); - *pobject = nv_object(barobj); - if (ret) - return ret; - - ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma); - if (ret) - return ret; - - barobj->iomem = ioremap(nv_device_resource_start(device, 3) + - (u32)barobj->vma.offset, mem->size << 12); - if (!barobj->iomem) { - nv_warn(bar, "PRAMIN ioremap failed\n"); - return -ENOMEM; - } - - return 0; + if (bar && bar->func->flush) + bar->func->flush(bar); } -static void -nvkm_barobj_dtor(struct nvkm_object *object) +struct nvkm_vm * +nvkm_bar_kmap(struct nvkm_bar *bar) { - struct nvkm_bar *bar = nvkm_bar(object); - struct nvkm_barobj *barobj = (void *)object; - if (barobj->vma.node) { - if (barobj->iomem) - iounmap(barobj->iomem); - bar->unmap(bar, &barobj->vma); - } - nvkm_object_destroy(&barobj->base); + /* disallow kmap() until after vm has been bootstrapped */ + if (bar && bar->func->kmap && bar->subdev.oneinit) + return bar->func->kmap(bar); + return NULL; } -static u32 -nvkm_barobj_rd32(struct nvkm_object *object, u64 addr) +int +nvkm_bar_umap(struct nvkm_bar *bar, u64 size, int type, struct nvkm_vma *vma) { - struct nvkm_barobj *barobj = (void *)object; - return ioread32_native(barobj->iomem + addr); + return bar->func->umap(bar, size, type, vma); } -static void -nvkm_barobj_wr32(struct nvkm_object *object, u64 addr, u32 data) +static int +nvkm_bar_oneinit(struct nvkm_subdev *subdev) { - struct nvkm_barobj *barobj = (void *)object; - iowrite32_native(data, barobj->iomem + addr); + struct nvkm_bar *bar = nvkm_bar(subdev); + return bar->func->oneinit(bar); } -static struct nvkm_oclass -nvkm_barobj_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nvkm_barobj_ctor, - .dtor = nvkm_barobj_dtor, - .init = nvkm_object_init, - .fini = nvkm_object_fini, - .rd32 = nvkm_barobj_rd32, - .wr32 = nvkm_barobj_wr32, - }, -}; - -int -nvkm_bar_alloc(struct nvkm_bar *bar, struct nvkm_object *parent, - struct nvkm_mem *mem, struct nvkm_object **pobject) +static int +nvkm_bar_init(struct nvkm_subdev *subdev) { - struct nvkm_object *gpuobj; - int ret = nvkm_object_ctor(parent, &parent->engine->subdev.object, - &nvkm_barobj_oclass, mem, 0, &gpuobj); - if (ret == 0) - *pobject = gpuobj; - return ret; + struct nvkm_bar *bar = nvkm_bar(subdev); + return bar->func->init(bar); } -int -nvkm_bar_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +static void * +nvkm_bar_dtor(struct nvkm_subdev *subdev) { - struct nvkm_bar *bar; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "BARCTL", - "bar", length, pobject); - bar = *pobject; - if (ret) - return ret; - - return 0; + struct nvkm_bar *bar = nvkm_bar(subdev); + return bar->func->dtor(bar); } -void -nvkm_bar_destroy(struct nvkm_bar *bar) -{ - nvkm_subdev_destroy(&bar->base); -} +static const struct nvkm_subdev_func +nvkm_bar = { + .dtor = nvkm_bar_dtor, + .oneinit = nvkm_bar_oneinit, + .init = nvkm_bar_init, +}; void -_nvkm_bar_dtor(struct nvkm_object *object) +nvkm_bar_ctor(const struct nvkm_bar_func *func, struct nvkm_device *device, + int index, struct nvkm_bar *bar) { - struct nvkm_bar *bar = (void *)object; - nvkm_bar_destroy(bar); + nvkm_subdev_ctor(&nvkm_bar, device, index, 0, &bar->subdev); + bar->func = func; + spin_lock_init(&bar->lock); } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c new file mode 100644 index 000000000..ef717136c --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c @@ -0,0 +1,56 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#include "nv50.h" + +#include <subdev/timer.h> + +void +g84_bar_flush(struct nvkm_bar *bar) +{ + struct nvkm_device *device = bar->subdev.device; + unsigned long flags; + spin_lock_irqsave(&bar->lock, flags); + nvkm_wr32(device, 0x070000, 0x00000001); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x070000) & 0x00000002)) + break; + ); + spin_unlock_irqrestore(&bar->lock, flags); +} + +static const struct nvkm_bar_func +g84_bar_func = { + .dtor = nv50_bar_dtor, + .oneinit = nv50_bar_oneinit, + .init = nv50_bar_init, + .kmap = nv50_bar_kmap, + .umap = nv50_bar_umap, + .flush = g84_bar_flush, +}; + +int +g84_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) +{ + return nv50_bar_new_(&g84_bar_func, device, index, 0x200, pbar); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 12a1aebd9..c794b2c2d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -21,101 +21,60 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "gf100.h" -#include <core/device.h> #include <core/gpuobj.h> #include <subdev/fb.h> #include <subdev/mmu.h> -struct gf100_bar_priv_vm { - struct nvkm_gpuobj *mem; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; - -struct gf100_bar_priv { - struct nvkm_bar base; - spinlock_t lock; - struct gf100_bar_priv_vm bar[2]; -}; - -static int -gf100_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) -{ - struct gf100_bar_priv *priv = (void *)bar; - int ret; - - ret = nvkm_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; -} - -static int -gf100_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) +static struct nvkm_vm * +gf100_bar_kmap(struct nvkm_bar *base) { - struct gf100_bar_priv *priv = (void *)bar; - int ret; - - ret = nvkm_vm_get(priv->bar[1].vm, mem->size << 12, - mem->page_shift, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; + return gf100_bar(base)->bar[0].vm; } -static void -gf100_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma) +int +gf100_bar_umap(struct nvkm_bar *base, u64 size, int type, struct nvkm_vma *vma) { - nvkm_vm_unmap(vma); - nvkm_vm_put(vma); + struct gf100_bar *bar = gf100_bar(base); + return nvkm_vm_get(bar->bar[1].vm, size, type, NV_MEM_ACCESS_RW, vma); } static int -gf100_bar_ctor_vm(struct gf100_bar_priv *priv, struct gf100_bar_priv_vm *bar_vm, - int bar_nr) +gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, + struct lock_class_key *key, int bar_nr) { - struct nvkm_device *device = nv_device(&priv->base); + struct nvkm_device *device = bar->base.subdev.device; struct nvkm_vm *vm; resource_size_t bar_len; int ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0, false, &bar_vm->mem); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0, - &bar_vm->pgd); + ret = nvkm_gpuobj_new(device, 0x8000, 0, false, NULL, &bar_vm->pgd); if (ret) return ret; - bar_len = nv_device_resource_len(device, bar_nr); + bar_len = device->func->resource_size(device, bar_nr); - ret = nvkm_vm_new(device, 0, bar_len, 0, &vm); + ret = nvkm_vm_new(device, 0, bar_len, 0, key, &vm); if (ret) return ret; - atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + atomic_inc(&vm->engref[NVKM_SUBDEV_BAR]); /* * Bootstrap page table lookup. */ if (bar_nr == 3) { - ret = nvkm_gpuobj_new(nv_object(priv), NULL, - (bar_len >> 12) * 8, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, - &vm->pgt[0].obj[0]); - vm->pgt[0].refcount[0] = 1; - if (ret) + ret = nvkm_vm_boot(vm, bar_len); + if (ret) { + nvkm_vm_ref(NULL, &vm, NULL); return ret; + } } ret = nvkm_vm_ref(vm, &bar_vm->vm, bar_vm->pgd); @@ -123,97 +82,101 @@ gf100_bar_ctor_vm(struct gf100_bar_priv *priv, struct gf100_bar_priv_vm *bar_vm, if (ret) return ret; - nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr)); - nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr)); - nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1)); - nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1)); + nvkm_kmap(bar_vm->mem); + nvkm_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr)); + nvkm_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr)); + nvkm_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1)); + nvkm_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1)); + nvkm_done(bar_vm->mem); return 0; } int -gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_bar_oneinit(struct nvkm_bar *base) { - struct nvkm_device *device = nv_device(parent); - struct gf100_bar_priv *priv; - bool has_bar3 = nv_device_resource_len(device, 3) != 0; + static struct lock_class_key bar1_lock; + static struct lock_class_key bar3_lock; + struct gf100_bar *bar = gf100_bar(base); int ret; - ret = nvkm_bar_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - /* BAR3 */ - if (has_bar3) { - ret = gf100_bar_ctor_vm(priv, &priv->bar[0], 3); + if (bar->base.func->kmap) { + ret = gf100_bar_ctor_vm(bar, &bar->bar[0], &bar3_lock, 3); if (ret) return ret; } /* BAR1 */ - ret = gf100_bar_ctor_vm(priv, &priv->bar[1], 1); + ret = gf100_bar_ctor_vm(bar, &bar->bar[1], &bar1_lock, 1); if (ret) return ret; - if (has_bar3) { - priv->base.alloc = nvkm_bar_alloc; - priv->base.kmap = gf100_bar_kmap; - } - priv->base.umap = gf100_bar_umap; - priv->base.unmap = gf100_bar_unmap; - priv->base.flush = g84_bar_flush; - spin_lock_init(&priv->lock); return 0; } -void -gf100_bar_dtor(struct nvkm_object *object) +int +gf100_bar_init(struct nvkm_bar *base) { - struct gf100_bar_priv *priv = (void *)object; + struct gf100_bar *bar = gf100_bar(base); + struct nvkm_device *device = bar->base.subdev.device; + u32 addr; + + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); - nvkm_vm_ref(NULL, &priv->bar[1].vm, priv->bar[1].pgd); - nvkm_gpuobj_ref(NULL, &priv->bar[1].pgd); - nvkm_gpuobj_ref(NULL, &priv->bar[1].mem); + addr = nvkm_memory_addr(bar->bar[1].mem) >> 12; + nvkm_wr32(device, 0x001704, 0x80000000 | addr); - if (priv->bar[0].vm) { - nvkm_gpuobj_ref(NULL, &priv->bar[0].vm->pgt[0].obj[0]); - nvkm_vm_ref(NULL, &priv->bar[0].vm, priv->bar[0].pgd); + if (bar->bar[0].mem) { + addr = nvkm_memory_addr(bar->bar[0].mem) >> 12; + nvkm_wr32(device, 0x001714, 0xc0000000 | addr); } - nvkm_gpuobj_ref(NULL, &priv->bar[0].pgd); - nvkm_gpuobj_ref(NULL, &priv->bar[0].mem); - nvkm_bar_destroy(&priv->base); + return 0; } -int -gf100_bar_init(struct nvkm_object *object) +void * +gf100_bar_dtor(struct nvkm_bar *base) { - struct gf100_bar_priv *priv = (void *)object; - int ret; + struct gf100_bar *bar = gf100_bar(base); - ret = nvkm_bar_init(&priv->base); - if (ret) - return ret; + nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd); + nvkm_gpuobj_del(&bar->bar[1].pgd); + nvkm_memory_del(&bar->bar[1].mem); - nv_mask(priv, 0x000200, 0x00000100, 0x00000000); - nv_mask(priv, 0x000200, 0x00000100, 0x00000100); + if (bar->bar[0].vm) { + nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]); + nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); + } + nvkm_gpuobj_del(&bar->bar[0].pgd); + nvkm_memory_del(&bar->bar[0].mem); + return bar; +} - nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12); - if (priv->bar[0].mem) - nv_wr32(priv, 0x001714, - 0xc0000000 | priv->bar[0].mem->addr >> 12); +int +gf100_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, + int index, struct nvkm_bar **pbar) +{ + struct gf100_bar *bar; + if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) + return -ENOMEM; + nvkm_bar_ctor(func, device, index, &bar->base); + *pbar = &bar->base; return 0; } -struct nvkm_oclass -gf100_bar_oclass = { - .handle = NV_SUBDEV(BAR, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_bar_ctor, - .dtor = gf100_bar_dtor, - .init = gf100_bar_init, - .fini = _nvkm_bar_fini, - }, +static const struct nvkm_bar_func +gf100_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .init = gf100_bar_init, + .kmap = gf100_bar_kmap, + .umap = gf100_bar_umap, + .flush = g84_bar_flush, }; + +int +gf100_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) +{ + return gf100_bar_new_(&gf100_bar_func, device, index, pbar); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h new file mode 100644 index 000000000..f7dea6964 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h @@ -0,0 +1,23 @@ +#ifndef __GF100_BAR_H__ +#define __GF100_BAR_H__ +#define gf100_bar(p) container_of((p), struct gf100_bar, base) +#include "priv.h" + +struct gf100_bar_vm { + struct nvkm_memory *mem; + struct nvkm_gpuobj *pgd; + struct nvkm_vm *vm; +}; + +struct gf100_bar { + struct nvkm_bar base; + struct gf100_bar_vm bar[2]; +}; + +int gf100_bar_new_(const struct nvkm_bar_func *, struct nvkm_device *, + int, struct nvkm_bar **); +void *gf100_bar_dtor(struct nvkm_bar *); +int gf100_bar_oneinit(struct nvkm_bar *); +int gf100_bar_init(struct nvkm_bar *); +int gf100_bar_umap(struct nvkm_bar *, u64, int, struct nvkm_vma *); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c index 148f739a2..9232fab42 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c @@ -19,32 +19,22 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "priv.h" +#include "gf100.h" + +static const struct nvkm_bar_func +gk20a_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .init = gf100_bar_init, + .umap = gf100_bar_umap, + .flush = g84_bar_flush, +}; int -gk20a_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gk20a_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) { - struct nvkm_bar *bar; - int ret; - - ret = gf100_bar_ctor(parent, engine, oclass, data, size, pobject); - if (ret) - return ret; - - bar = (struct nvkm_bar *)*pobject; - bar->iomap_uncached = true; - return 0; + int ret = gf100_bar_new_(&gk20a_bar_func, device, index, pbar); + if (ret == 0) + (*pbar)->iomap_uncached = true; + return ret; } - -struct nvkm_oclass -gk20a_bar_oclass = { - .handle = NV_SUBDEV(BAR, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_bar_ctor, - .dtor = gf100_bar_dtor, - .init = gf100_bar_init, - .fini = _nvkm_bar_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index 8548adb91..370dcd8ff 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -21,251 +21,196 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv50.h" -#include <core/device.h> #include <core/gpuobj.h> #include <subdev/fb.h> #include <subdev/mmu.h> #include <subdev/timer.h> -struct nv50_bar_priv { - struct nvkm_bar base; - spinlock_t lock; - struct nvkm_gpuobj *mem; - struct nvkm_gpuobj *pad; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *bar1_vm; - struct nvkm_gpuobj *bar1; - struct nvkm_vm *bar3_vm; - struct nvkm_gpuobj *bar3; -}; - -static int -nv50_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) -{ - struct nv50_bar_priv *priv = (void *)bar; - int ret; - - ret = nvkm_vm_get(priv->bar3_vm, mem->size << 12, 12, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; -} - -static int -nv50_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) +struct nvkm_vm * +nv50_bar_kmap(struct nvkm_bar *base) { - struct nv50_bar_priv *priv = (void *)bar; - int ret; - - ret = nvkm_vm_get(priv->bar1_vm, mem->size << 12, 12, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; + return nv50_bar(base)->bar3_vm; } -static void -nv50_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma) +int +nv50_bar_umap(struct nvkm_bar *base, u64 size, int type, struct nvkm_vma *vma) { - nvkm_vm_unmap(vma); - nvkm_vm_put(vma); + struct nv50_bar *bar = nv50_bar(base); + return nvkm_vm_get(bar->bar1_vm, size, type, NV_MEM_ACCESS_RW, vma); } static void -nv50_bar_flush(struct nvkm_bar *bar) -{ - struct nv50_bar_priv *priv = (void *)bar; - unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - nv_wr32(priv, 0x00330c, 0x00000001); - if (!nv_wait(priv, 0x00330c, 0x00000002, 0x00000000)) - nv_warn(priv, "flush timeout\n"); - spin_unlock_irqrestore(&priv->lock, flags); -} - -void -g84_bar_flush(struct nvkm_bar *bar) +nv50_bar_flush(struct nvkm_bar *base) { - struct nv50_bar_priv *priv = (void *)bar; + struct nv50_bar *bar = nv50_bar(base); + struct nvkm_device *device = bar->base.subdev.device; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - nv_wr32(bar, 0x070000, 0x00000001); - if (!nv_wait(priv, 0x070000, 0x00000002, 0x00000000)) - nv_warn(priv, "flush timeout\n"); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&bar->base.lock, flags); + nvkm_wr32(device, 0x00330c, 0x00000001); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x00330c) & 0x00000002)) + break; + ); + spin_unlock_irqrestore(&bar->base.lock, flags); } -static int -nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_bar_oneinit(struct nvkm_bar *base) { - struct nvkm_device *device = nv_device(parent); - struct nvkm_object *heap; + struct nv50_bar *bar = nv50_bar(base); + struct nvkm_device *device = bar->base.subdev.device; + static struct lock_class_key bar1_lock; + static struct lock_class_key bar3_lock; struct nvkm_vm *vm; - struct nv50_bar_priv *priv; u64 start, limit; int ret; - ret = nvkm_bar_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_gpuobj_new(device, 0x20000, 0, false, NULL, &bar->mem); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0, - NVOBJ_FLAG_HEAP, &priv->mem); - heap = nv_object(priv->mem); + ret = nvkm_gpuobj_new(device, bar->pgd_addr, 0, false, bar->mem, + &bar->pad); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), heap, - (device->chipset == 0x50) ? 0x1400 : 0x0200, - 0, 0, &priv->pad); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), heap, 0x4000, 0, 0, &priv->pgd); + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, bar->mem, &bar->pgd); if (ret) return ret; /* BAR3 */ start = 0x0100000000ULL; - limit = start + nv_device_resource_len(device, 3); + limit = start + device->func->resource_size(device, 3); - ret = nvkm_vm_new(device, start, limit, start, &vm); + ret = nvkm_vm_new(device, start, limit, start, &bar3_lock, &vm); if (ret) return ret; - atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + atomic_inc(&vm->engref[NVKM_SUBDEV_BAR]); - ret = nvkm_gpuobj_new(nv_object(priv), heap, - ((limit-- - start) >> 12) * 8, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); - vm->pgt[0].refcount[0] = 1; + ret = nvkm_vm_boot(vm, limit-- - start); if (ret) return ret; - ret = nvkm_vm_ref(vm, &priv->bar3_vm, priv->pgd); + ret = nvkm_vm_ref(vm, &bar->bar3_vm, bar->pgd); nvkm_vm_ref(NULL, &vm, NULL); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar3); + ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar3); if (ret) return ret; - nv_wo32(priv->bar3, 0x00, 0x7fc00000); - nv_wo32(priv->bar3, 0x04, lower_32_bits(limit)); - nv_wo32(priv->bar3, 0x08, lower_32_bits(start)); - nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(priv->bar3, 0x10, 0x00000000); - nv_wo32(priv->bar3, 0x14, 0x00000000); + nvkm_kmap(bar->bar3); + nvkm_wo32(bar->bar3, 0x00, 0x7fc00000); + nvkm_wo32(bar->bar3, 0x04, lower_32_bits(limit)); + nvkm_wo32(bar->bar3, 0x08, lower_32_bits(start)); + nvkm_wo32(bar->bar3, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(bar->bar3, 0x10, 0x00000000); + nvkm_wo32(bar->bar3, 0x14, 0x00000000); + nvkm_done(bar->bar3); /* BAR1 */ start = 0x0000000000ULL; - limit = start + nv_device_resource_len(device, 1); + limit = start + device->func->resource_size(device, 1); - ret = nvkm_vm_new(device, start, limit--, start, &vm); + ret = nvkm_vm_new(device, start, limit--, start, &bar1_lock, &vm); if (ret) return ret; - atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + atomic_inc(&vm->engref[NVKM_SUBDEV_BAR]); - ret = nvkm_vm_ref(vm, &priv->bar1_vm, priv->pgd); + ret = nvkm_vm_ref(vm, &bar->bar1_vm, bar->pgd); nvkm_vm_ref(NULL, &vm, NULL); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar1); + ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar1); if (ret) return ret; - nv_wo32(priv->bar1, 0x00, 0x7fc00000); - nv_wo32(priv->bar1, 0x04, lower_32_bits(limit)); - nv_wo32(priv->bar1, 0x08, lower_32_bits(start)); - nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(priv->bar1, 0x10, 0x00000000); - nv_wo32(priv->bar1, 0x14, 0x00000000); - - priv->base.alloc = nvkm_bar_alloc; - priv->base.kmap = nv50_bar_kmap; - priv->base.umap = nv50_bar_umap; - priv->base.unmap = nv50_bar_unmap; - if (device->chipset == 0x50) - priv->base.flush = nv50_bar_flush; - else - priv->base.flush = g84_bar_flush; - spin_lock_init(&priv->lock); + nvkm_kmap(bar->bar1); + nvkm_wo32(bar->bar1, 0x00, 0x7fc00000); + nvkm_wo32(bar->bar1, 0x04, lower_32_bits(limit)); + nvkm_wo32(bar->bar1, 0x08, lower_32_bits(start)); + nvkm_wo32(bar->bar1, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(bar->bar1, 0x10, 0x00000000); + nvkm_wo32(bar->bar1, 0x14, 0x00000000); + nvkm_done(bar->bar1); return 0; } -static void -nv50_bar_dtor(struct nvkm_object *object) +int +nv50_bar_init(struct nvkm_bar *base) { - struct nv50_bar_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->bar1); - nvkm_vm_ref(NULL, &priv->bar1_vm, priv->pgd); - nvkm_gpuobj_ref(NULL, &priv->bar3); - if (priv->bar3_vm) { - nvkm_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]); - nvkm_vm_ref(NULL, &priv->bar3_vm, priv->pgd); - } - nvkm_gpuobj_ref(NULL, &priv->pgd); - nvkm_gpuobj_ref(NULL, &priv->pad); - nvkm_gpuobj_ref(NULL, &priv->mem); - nvkm_bar_destroy(&priv->base); -} - -static int -nv50_bar_init(struct nvkm_object *object) -{ - struct nv50_bar_priv *priv = (void *)object; - int ret, i; - - ret = nvkm_bar_init(&priv->base); - if (ret) - return ret; - - nv_mask(priv, 0x000200, 0x00000100, 0x00000000); - nv_mask(priv, 0x000200, 0x00000100, 0x00000100); - nv_wr32(priv, 0x100c80, 0x00060001); - if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) { - nv_error(priv, "vm flush timeout\n"); + struct nv50_bar *bar = nv50_bar(base); + struct nvkm_device *device = bar->base.subdev.device; + int i; + + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); + nvkm_wr32(device, 0x100c80, 0x00060001); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) + break; + ) < 0) return -EBUSY; - } - nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12); - nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12); - nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4); - nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4); + nvkm_wr32(device, 0x001704, 0x00000000 | bar->mem->addr >> 12); + nvkm_wr32(device, 0x001704, 0x40000000 | bar->mem->addr >> 12); + nvkm_wr32(device, 0x001708, 0x80000000 | bar->bar1->node->offset >> 4); + nvkm_wr32(device, 0x00170c, 0x80000000 | bar->bar3->node->offset >> 4); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x001900 + (i * 4), 0x00000000); + nvkm_wr32(device, 0x001900 + (i * 4), 0x00000000); return 0; } -static int -nv50_bar_fini(struct nvkm_object *object, bool suspend) +void * +nv50_bar_dtor(struct nvkm_bar *base) { - struct nv50_bar_priv *priv = (void *)object; - return nvkm_bar_fini(&priv->base, suspend); + struct nv50_bar *bar = nv50_bar(base); + nvkm_gpuobj_del(&bar->bar1); + nvkm_vm_ref(NULL, &bar->bar1_vm, bar->pgd); + nvkm_gpuobj_del(&bar->bar3); + if (bar->bar3_vm) { + nvkm_memory_del(&bar->bar3_vm->pgt[0].mem[0]); + nvkm_vm_ref(NULL, &bar->bar3_vm, bar->pgd); + } + nvkm_gpuobj_del(&bar->pgd); + nvkm_gpuobj_del(&bar->pad); + nvkm_gpuobj_del(&bar->mem); + return bar; } -struct nvkm_oclass -nv50_bar_oclass = { - .handle = NV_SUBDEV(BAR, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_bar_ctor, - .dtor = nv50_bar_dtor, - .init = nv50_bar_init, - .fini = nv50_bar_fini, - }, +int +nv50_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, + int index, u32 pgd_addr, struct nvkm_bar **pbar) +{ + struct nv50_bar *bar; + if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) + return -ENOMEM; + nvkm_bar_ctor(func, device, index, &bar->base); + bar->pgd_addr = pgd_addr; + *pbar = &bar->base; + return 0; +} + +static const struct nvkm_bar_func +nv50_bar_func = { + .dtor = nv50_bar_dtor, + .oneinit = nv50_bar_oneinit, + .init = nv50_bar_init, + .kmap = nv50_bar_kmap, + .umap = nv50_bar_umap, + .flush = nv50_bar_flush, }; + +int +nv50_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) +{ + return nv50_bar_new_(&nv50_bar_func, device, index, 0x1400, pbar); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h new file mode 100644 index 000000000..1eb764f22 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h @@ -0,0 +1,26 @@ +#ifndef __NV50_BAR_H__ +#define __NV50_BAR_H__ +#define nv50_bar(p) container_of((p), struct nv50_bar, base) +#include "priv.h" + +struct nv50_bar { + struct nvkm_bar base; + u32 pgd_addr; + struct nvkm_gpuobj *mem; + struct nvkm_gpuobj *pad; + struct nvkm_gpuobj *pgd; + struct nvkm_vm *bar1_vm; + struct nvkm_gpuobj *bar1; + struct nvkm_vm *bar3_vm; + struct nvkm_gpuobj *bar3; +}; + +int nv50_bar_new_(const struct nvkm_bar_func *, struct nvkm_device *, + int, u32 pgd_addr, struct nvkm_bar **); +void *nv50_bar_dtor(struct nvkm_bar *); +int nv50_bar_oneinit(struct nvkm_bar *); +int nv50_bar_init(struct nvkm_bar *); +struct nvkm_vm *nv50_bar_kmap(struct nvkm_bar *); +int nv50_bar_umap(struct nvkm_bar *, u64, int, struct nvkm_vma *); +void nv50_bar_unmap(struct nvkm_bar *, struct nvkm_vma *); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h index aa85f61b4..d834ef20d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h @@ -1,30 +1,19 @@ #ifndef __NVKM_BAR_PRIV_H__ #define __NVKM_BAR_PRIV_H__ +#define nvkm_bar(p) container_of((p), struct nvkm_bar, subdev) #include <subdev/bar.h> -#define nvkm_bar_create(p,e,o,d) \ - nvkm_bar_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_bar_init(p) \ - nvkm_subdev_init(&(p)->base) -#define nvkm_bar_fini(p,s) \ - nvkm_subdev_fini(&(p)->base, (s)) +void nvkm_bar_ctor(const struct nvkm_bar_func *, struct nvkm_device *, + int, struct nvkm_bar *); -int nvkm_bar_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void nvkm_bar_destroy(struct nvkm_bar *); - -void _nvkm_bar_dtor(struct nvkm_object *); -#define _nvkm_bar_init _nvkm_subdev_init -#define _nvkm_bar_fini _nvkm_subdev_fini - -int nvkm_bar_alloc(struct nvkm_bar *, struct nvkm_object *, - struct nvkm_mem *, struct nvkm_object **); +struct nvkm_bar_func { + void *(*dtor)(struct nvkm_bar *); + int (*oneinit)(struct nvkm_bar *); + int (*init)(struct nvkm_bar *); + struct nvkm_vm *(*kmap)(struct nvkm_bar *); + int (*umap)(struct nvkm_bar *, u64 size, int type, struct nvkm_vma *); + void (*flush)(struct nvkm_bar *); +}; void g84_bar_flush(struct nvkm_bar *); - -int gf100_bar_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_bar_dtor(struct nvkm_object *); -int gf100_bar_init(struct nvkm_object *); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c index 08eb03fbc..43f0ba1fb 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c @@ -33,14 +33,14 @@ nvbios_M0203Te(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 2 && bit_M.length > 0x04) - data = nv_ro16(bios, bit_M.offset + 0x03); + data = nvbios_rd16(bios, bit_M.offset + 0x03); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); return data; default: break; @@ -59,8 +59,8 @@ nvbios_M0203Tp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->type = nv_ro08(bios, data + 0x04); - info->pointer = nv_ro16(bios, data + 0x05); + info->type = nvbios_rd08(bios, data + 0x04); + info->pointer = nvbios_rd16(bios, data + 0x05); break; default: break; @@ -89,9 +89,9 @@ nvbios_M0203Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->type = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0; - info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4; - info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0; + info->type = (nvbios_rd08(bios, data + 0x00) & 0x0f) >> 0; + info->strap = (nvbios_rd08(bios, data + 0x00) & 0xf0) >> 4; + info->group = (nvbios_rd08(bios, data + 0x01) & 0x0f) >> 0; return data; default: break; @@ -103,12 +103,13 @@ u32 nvbios_M0203Em(struct nvkm_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr, struct nvbios_M0203E *info) { + struct nvkm_subdev *subdev = &bios->subdev; struct nvbios_M0203T M0203T; u8 cnt, len, idx = 0xff; u32 data; if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) { - nv_warn(bios, "M0203T not found\n"); + nvkm_warn(subdev, "M0203T not found\n"); return 0x00000000; } @@ -119,7 +120,7 @@ nvbios_M0203Em(struct nvkm_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr, continue; return data; default: - nv_warn(bios, "M0203T type %02x\n", M0203T.type); + nvkm_warn(subdev, "M0203T type %02x\n", M0203T.type); return 0x00000000; } } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c index e1a8ad5f3..293a6af1b 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c @@ -34,16 +34,16 @@ nvbios_M0205Te(struct nvkm_bios *bios, if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 2 && bit_M.length > 0x08) - data = nv_ro32(bios, bit_M.offset + 0x05); + data = nvbios_rd32(bios, bit_M.offset + 0x05); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *ssz = nv_ro08(bios, data + 0x03); - *snr = nv_ro08(bios, data + 0x04); - *cnt = nv_ro08(bios, data + 0x05); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *ssz = nvbios_rd08(bios, data + 0x03); + *snr = nvbios_rd08(bios, data + 0x04); + *cnt = nvbios_rd08(bios, data + 0x05); return data; default: break; @@ -63,7 +63,7 @@ nvbios_M0205Tp(struct nvkm_bios *bios, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->freq = nv_ro16(bios, data + 0x06); + info->freq = nvbios_rd16(bios, data + 0x06); break; default: break; @@ -96,7 +96,7 @@ nvbios_M0205Ep(struct nvkm_bios *bios, int idx, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->type = nv_ro08(bios, data + 0x00) & 0x0f; + info->type = nvbios_rd08(bios, data + 0x00) & 0x0f; return data; default: break; @@ -126,7 +126,7 @@ nvbios_M0205Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->data = nv_ro08(bios, data + 0x00); + info->data = nvbios_rd08(bios, data + 0x00); return data; default: break; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c index 3026920c3..95d49a526 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c @@ -34,16 +34,16 @@ nvbios_M0209Te(struct nvkm_bios *bios, if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 2 && bit_M.length > 0x0c) - data = nv_ro32(bios, bit_M.offset + 0x09); + data = nvbios_rd32(bios, bit_M.offset + 0x09); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *ssz = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *ssz = nvbios_rd08(bios, data + 0x03); *snr = 1; - *cnt = nv_ro08(bios, data + 0x04); + *cnt = nvbios_rd08(bios, data + 0x04); return data; default: break; @@ -78,12 +78,12 @@ nvbios_M0209Ep(struct nvkm_bios *bios, int idx, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6; - info->bits = nv_ro08(bios, data + 0x00) & 0x3f; - info->modulo = nv_ro08(bios, data + 0x01); - info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; - info->v02_07 = nv_ro08(bios, data + 0x02) & 0x07; - info->v03 = nv_ro08(bios, data + 0x03); + info->v00_40 = (nvbios_rd08(bios, data + 0x00) & 0x40) >> 6; + info->bits = nvbios_rd08(bios, data + 0x00) & 0x3f; + info->modulo = nvbios_rd08(bios, data + 0x01); + info->v02_40 = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; + info->v02_07 = nvbios_rd08(bios, data + 0x02) & 0x07; + info->v03 = nvbios_rd08(bios, data + 0x03); return data; default: break; @@ -122,7 +122,7 @@ nvbios_M0209Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr, u32 mask = (1ULL << M0209E.bits) - 1; u16 off = bits / 8; u8 mod = bits % 8; - info->data[i] = nv_ro32(bios, data + off); + info->data[i] = nvbios_rd32(bios, data + off); info->data[i] = info->data[i] >> mod; info->data[i] = info->data[i] & mask; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c index b72edcf84..3f7db3eb3 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c @@ -34,15 +34,15 @@ nvbios_P0260Te(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2 && bit_P.length > 0x63) - data = nv_ro32(bios, bit_P.offset + 0x60); + data = nvbios_rd32(bios, bit_P.offset + 0x60); if (data) { - *ver = nv_ro08(bios, data + 0); + *ver = nvbios_rd08(bios, data + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 1); - *cnt = nv_ro08(bios, data + 2); + *hdr = nvbios_rd08(bios, data + 1); + *cnt = nvbios_rd08(bios, data + 2); *len = 4; - *xnr = nv_ro08(bios, data + 3); + *xnr = nvbios_rd08(bios, data + 3); *xsz = 4; return data; default: @@ -72,7 +72,7 @@ nvbios_P0260Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->data = nv_ro32(bios, data); + info->data = nvbios_rd32(bios, data); return data; default: break; @@ -98,7 +98,7 @@ nvbios_P0260Xp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->data = nv_ro32(bios, data); + info->data = nvbios_rd32(bios, data); return data; default: break; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index 8db204f92..79536897e 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -53,6 +53,20 @@ nvbios_findstr(const u8 *data, int size, const char *str, int len) } int +nvbios_memcmp(struct nvkm_bios *bios, u32 addr, const char *str, u32 len) +{ + unsigned char c1, c2; + + while (len--) { + c1 = nvbios_rd08(bios, addr++); + c2 = *(str++); + if (c1 != c2) + return c1 - c2; + } + return 0; +} + +int nvbios_extend(struct nvkm_bios *bios, u32 length) { if (bios->size < length) { @@ -69,62 +83,29 @@ nvbios_extend(struct nvkm_bios *bios, u32 length) return 0; } -static u8 -nvkm_bios_rd08(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - return bios->data[addr]; -} - -static u16 -nvkm_bios_rd16(struct nvkm_object *object, u64 addr) +static void * +nvkm_bios_dtor(struct nvkm_subdev *subdev) { - struct nvkm_bios *bios = (void *)object; - return get_unaligned_le16(&bios->data[addr]); -} - -static u32 -nvkm_bios_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - return get_unaligned_le32(&bios->data[addr]); -} - -static void -nvkm_bios_wr08(struct nvkm_object *object, u64 addr, u8 data) -{ - struct nvkm_bios *bios = (void *)object; - bios->data[addr] = data; -} - -static void -nvkm_bios_wr16(struct nvkm_object *object, u64 addr, u16 data) -{ - struct nvkm_bios *bios = (void *)object; - put_unaligned_le16(data, &bios->data[addr]); + struct nvkm_bios *bios = nvkm_bios(subdev); + kfree(bios->data); + return bios; } -static void -nvkm_bios_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_bios *bios = (void *)object; - put_unaligned_le32(data, &bios->data[addr]); -} +static const struct nvkm_subdev_func +nvkm_bios = { + .dtor = nvkm_bios_dtor, +}; -static int -nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nvkm_bios_new(struct nvkm_device *device, int index, struct nvkm_bios **pbios) { struct nvkm_bios *bios; struct bit_entry bit_i; int ret; - ret = nvkm_subdev_create(parent, engine, oclass, 0, - "VBIOS", "bios", &bios); - *pobject = nv_object(bios); - if (ret) - return ret; + if (!(bios = *pbios = kzalloc(sizeof(*bios), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_bios, device, index, 0, &bios->subdev); ret = nvbios_shadow(bios); if (ret) @@ -134,73 +115,33 @@ nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, bios->bmp_offset = nvbios_findstr(bios->data, bios->size, "\xff\x7f""NV\0", 5); if (bios->bmp_offset) { - nv_info(bios, "BMP version %x.%x\n", - bmp_version(bios) >> 8, - bmp_version(bios) & 0xff); + nvkm_debug(&bios->subdev, "BMP version %x.%x\n", + bmp_version(bios) >> 8, + bmp_version(bios) & 0xff); } bios->bit_offset = nvbios_findstr(bios->data, bios->size, "\xff\xb8""BIT", 5); if (bios->bit_offset) - nv_info(bios, "BIT signature found\n"); + nvkm_debug(&bios->subdev, "BIT signature found\n"); /* determine the vbios version number */ if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) { - bios->version.major = nv_ro08(bios, bit_i.offset + 3); - bios->version.chip = nv_ro08(bios, bit_i.offset + 2); - bios->version.minor = nv_ro08(bios, bit_i.offset + 1); - bios->version.micro = nv_ro08(bios, bit_i.offset + 0); - bios->version.patch = nv_ro08(bios, bit_i.offset + 4); + bios->version.major = nvbios_rd08(bios, bit_i.offset + 3); + bios->version.chip = nvbios_rd08(bios, bit_i.offset + 2); + bios->version.minor = nvbios_rd08(bios, bit_i.offset + 1); + bios->version.micro = nvbios_rd08(bios, bit_i.offset + 0); + bios->version.patch = nvbios_rd08(bios, bit_i.offset + 4); } else if (bmp_version(bios)) { - bios->version.major = nv_ro08(bios, bios->bmp_offset + 13); - bios->version.chip = nv_ro08(bios, bios->bmp_offset + 12); - bios->version.minor = nv_ro08(bios, bios->bmp_offset + 11); - bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10); + bios->version.major = nvbios_rd08(bios, bios->bmp_offset + 13); + bios->version.chip = nvbios_rd08(bios, bios->bmp_offset + 12); + bios->version.minor = nvbios_rd08(bios, bios->bmp_offset + 11); + bios->version.micro = nvbios_rd08(bios, bios->bmp_offset + 10); } - nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n", - bios->version.major, bios->version.chip, - bios->version.minor, bios->version.micro, bios->version.patch); - + nvkm_info(&bios->subdev, "version %02x.%02x.%02x.%02x.%02x\n", + bios->version.major, bios->version.chip, + bios->version.minor, bios->version.micro, bios->version.patch); return 0; } - -static void -nvkm_bios_dtor(struct nvkm_object *object) -{ - struct nvkm_bios *bios = (void *)object; - kfree(bios->data); - nvkm_subdev_destroy(&bios->base); -} - -static int -nvkm_bios_init(struct nvkm_object *object) -{ - struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_init(&bios->base); -} - -static int -nvkm_bios_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_fini(&bios->base, suspend); -} - -struct nvkm_oclass -nvkm_bios_oclass = { - .handle = NV_SUBDEV(VBIOS, 0x00), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nvkm_bios_ctor, - .dtor = nvkm_bios_dtor, - .init = nvkm_bios_init, - .fini = nvkm_bios_fini, - .rd08 = nvkm_bios_rd08, - .rd16 = nvkm_bios_rd16, - .rd32 = nvkm_bios_rd32, - .wr08 = nvkm_bios_wr08, - .wr16 = nvkm_bios_wr16, - .wr32 = nvkm_bios_wr32, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c index eab540496..070ff33f8 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c @@ -28,18 +28,18 @@ int bit_entry(struct nvkm_bios *bios, u8 id, struct bit_entry *bit) { if (likely(bios->bit_offset)) { - u8 entries = nv_ro08(bios, bios->bit_offset + 10); + u8 entries = nvbios_rd08(bios, bios->bit_offset + 10); u32 entry = bios->bit_offset + 12; while (entries--) { - if (nv_ro08(bios, entry + 0) == id) { - bit->id = nv_ro08(bios, entry + 0); - bit->version = nv_ro08(bios, entry + 1); - bit->length = nv_ro16(bios, entry + 2); - bit->offset = nv_ro16(bios, entry + 4); + if (nvbios_rd08(bios, entry + 0) == id) { + bit->id = nvbios_rd08(bios, entry + 0); + bit->version = nvbios_rd08(bios, entry + 1); + bit->length = nvbios_rd16(bios, entry + 2); + bit->offset = nvbios_rd16(bios, entry + 4); return 0; } - entry += nv_ro08(bios, bios->bit_offset + 9); + entry += nvbios_rd08(bios, bios->bit_offset + 9); } return -ENOENT; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c index 12e958533..3756ec91a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c @@ -34,17 +34,17 @@ nvbios_boostTe(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - boost = nv_ro16(bios, bit_P.offset + 0x30); + boost = nvbios_rd16(bios, bit_P.offset + 0x30); if (boost) { - *ver = nv_ro08(bios, boost + 0); + *ver = nvbios_rd08(bios, boost + 0); switch (*ver) { case 0x11: - *hdr = nv_ro08(bios, boost + 1); - *cnt = nv_ro08(bios, boost + 5); - *len = nv_ro08(bios, boost + 2); - *snr = nv_ro08(bios, boost + 4); - *ssz = nv_ro08(bios, boost + 3); + *hdr = nvbios_rd08(bios, boost + 1); + *cnt = nvbios_rd08(bios, boost + 5); + *len = nvbios_rd08(bios, boost + 2); + *snr = nvbios_rd08(bios, boost + 4); + *ssz = nvbios_rd08(bios, boost + 3); return boost; default: break; @@ -78,9 +78,9 @@ nvbios_boostEp(struct nvkm_bios *bios, int idx, u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data) { - info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5; - info->min = nv_ro16(bios, data + 0x02) * 1000; - info->max = nv_ro16(bios, data + 0x04) * 1000; + info->pstate = (nvbios_rd16(bios, data + 0x00) & 0x01e0) >> 5; + info->min = nvbios_rd16(bios, data + 0x02) * 1000; + info->max = nvbios_rd16(bios, data + 0x04) * 1000; } return data; } @@ -117,10 +117,10 @@ nvbios_boostSp(struct nvkm_bios *bios, int idx, data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data) { - info->domain = nv_ro08(bios, data + 0x00); - info->percent = nv_ro08(bios, data + 0x01); - info->min = nv_ro16(bios, data + 0x02) * 1000; - info->max = nv_ro16(bios, data + 0x04) * 1000; + info->domain = nvbios_rd08(bios, data + 0x00); + info->percent = nvbios_rd08(bios, data + 0x01); + info->min = nvbios_rd16(bios, data + 0x02) * 1000; + info->max = nvbios_rd16(bios, data + 0x04) * 1000; } return data; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c index 706a1650a..276823426 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c @@ -30,12 +30,12 @@ nvbios_connTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u32 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb && *ver >= 0x30 && *hdr >= 0x16) { - u32 data = nv_ro16(bios, dcb + 0x14); + u32 data = nvbios_rd16(bios, dcb + 0x14); if (data) { - *ver = nv_ro08(bios, data + 0); - *hdr = nv_ro08(bios, data + 1); - *cnt = nv_ro08(bios, data + 2); - *len = nv_ro08(bios, data + 3); + *ver = nvbios_rd08(bios, data + 0); + *hdr = nvbios_rd08(bios, data + 1); + *cnt = nvbios_rd08(bios, data + 2); + *len = nvbios_rd08(bios, data + 3); return data; } } @@ -77,18 +77,18 @@ nvbios_connEp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, switch (!!data * *ver) { case 0x30: case 0x40: - info->type = nv_ro08(bios, data + 0x00); - info->location = nv_ro08(bios, data + 0x01) & 0x0f; - info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4; - info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6; + info->type = nvbios_rd08(bios, data + 0x00); + info->location = nvbios_rd08(bios, data + 0x01) & 0x0f; + info->hpd = (nvbios_rd08(bios, data + 0x01) & 0x30) >> 4; + info->dp = (nvbios_rd08(bios, data + 0x01) & 0xc0) >> 6; if (*len < 4) return data; - info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2; - info->dp |= nv_ro08(bios, data + 0x02) & 0x0c; - info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4; - info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4; - info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3; - info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4; + info->hpd |= (nvbios_rd08(bios, data + 0x02) & 0x03) << 2; + info->dp |= nvbios_rd08(bios, data + 0x02) & 0x0c; + info->di = (nvbios_rd08(bios, data + 0x02) & 0xf0) >> 4; + info->hpd |= (nvbios_rd08(bios, data + 0x03) & 0x07) << 4; + info->sr = (nvbios_rd08(bios, data + 0x03) & 0x08) >> 3; + info->lcdid = (nvbios_rd08(bios, data + 0x03) & 0x70) >> 4; return data; default: break; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c index 16f7ad8a4..32e01624a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c @@ -34,17 +34,17 @@ nvbios_cstepTe(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - cstep = nv_ro16(bios, bit_P.offset + 0x34); + cstep = nvbios_rd16(bios, bit_P.offset + 0x34); if (cstep) { - *ver = nv_ro08(bios, cstep + 0); + *ver = nvbios_rd08(bios, cstep + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, cstep + 1); - *cnt = nv_ro08(bios, cstep + 3); - *len = nv_ro08(bios, cstep + 2); - *xnr = nv_ro08(bios, cstep + 5); - *xsz = nv_ro08(bios, cstep + 4); + *hdr = nvbios_rd08(bios, cstep + 1); + *cnt = nvbios_rd08(bios, cstep + 3); + *len = nvbios_rd08(bios, cstep + 2); + *xnr = nvbios_rd08(bios, cstep + 5); + *xsz = nvbios_rd08(bios, cstep + 4); return cstep; default: break; @@ -75,8 +75,8 @@ nvbios_cstepEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u16 data = nvbios_cstepEe(bios, idx, ver, hdr); memset(info, 0x00, sizeof(*info)); if (data) { - info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5; - info->index = nv_ro08(bios, data + 0x03); + info->pstate = (nvbios_rd16(bios, data + 0x00) & 0x01e0) >> 5; + info->index = nvbios_rd08(bios, data + 0x03); } return data; } @@ -113,10 +113,10 @@ nvbios_cstepXp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u16 data = nvbios_cstepXe(bios, idx, ver, hdr); memset(info, 0x00, sizeof(*info)); if (data) { - info->freq = nv_ro16(bios, data + 0x00) * 1000; - info->unkn[0] = nv_ro08(bios, data + 0x02); - info->unkn[1] = nv_ro08(bios, data + 0x03); - info->voltage = nv_ro08(bios, data + 0x04); + info->freq = nvbios_rd16(bios, data + 0x00) * 1000; + info->unkn[0] = nvbios_rd08(bios, data + 0x02); + info->unkn[1] = nvbios_rd08(bios, data + 0x03); + info->voltage = nvbios_rd08(bios, data + 0x04); } return data; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c index 8d78140f9..8304b806f 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c @@ -24,38 +24,37 @@ #include <subdev/bios.h> #include <subdev/bios/dcb.h> -#include <core/device.h> - u16 dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { - struct nvkm_device *device = nv_device(bios); + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; u16 dcb = 0x0000; if (device->card_type > NV_04) - dcb = nv_ro16(bios, 0x36); + dcb = nvbios_rd16(bios, 0x36); if (!dcb) { - nv_warn(bios, "DCB table not found\n"); + nvkm_warn(subdev, "DCB table not found\n"); return dcb; } - *ver = nv_ro08(bios, dcb); + *ver = nvbios_rd08(bios, dcb); if (*ver >= 0x42) { - nv_warn(bios, "DCB version 0x%02x unknown\n", *ver); + nvkm_warn(subdev, "DCB version 0x%02x unknown\n", *ver); return 0x0000; } else if (*ver >= 0x30) { - if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) { - *hdr = nv_ro08(bios, dcb + 1); - *cnt = nv_ro08(bios, dcb + 2); - *len = nv_ro08(bios, dcb + 3); + if (nvbios_rd32(bios, dcb + 6) == 0x4edcbdcb) { + *hdr = nvbios_rd08(bios, dcb + 1); + *cnt = nvbios_rd08(bios, dcb + 2); + *len = nvbios_rd08(bios, dcb + 3); return dcb; } } else if (*ver >= 0x20) { - if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) { - u16 i2c = nv_ro16(bios, dcb + 2); + if (nvbios_rd32(bios, dcb + 4) == 0x4edcbdcb) { + u16 i2c = nvbios_rd16(bios, dcb + 2); *hdr = 8; *cnt = (i2c - dcb) / 8; *len = 8; @@ -63,8 +62,8 @@ dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } } else if (*ver >= 0x15) { - if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) { - u16 i2c = nv_ro16(bios, dcb + 2); + if (!nvbios_memcmp(bios, dcb - 7, "DEV_REC", 7)) { + u16 i2c = nvbios_rd16(bios, dcb + 2); *hdr = 4; *cnt = (i2c - dcb) / 10; *len = 10; @@ -88,11 +87,11 @@ dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) * * v1.1 (NV5+, maybe some NV4) is entirely unhelpful */ - nv_warn(bios, "DCB contains no useful data\n"); + nvkm_debug(subdev, "DCB contains no useful data\n"); return 0x0000; } - nv_warn(bios, "DCB header validation failed\n"); + nvkm_warn(subdev, "DCB header validation failed\n"); return 0x0000; } @@ -126,7 +125,7 @@ dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, memset(outp, 0x00, sizeof(*outp)); if (dcb) { if (*ver >= 0x20) { - u32 conn = nv_ro32(bios, dcb + 0x00); + u32 conn = nvbios_rd32(bios, dcb + 0x00); outp->or = (conn & 0x0f000000) >> 24; outp->location = (conn & 0x00300000) >> 20; outp->bus = (conn & 0x000f0000) >> 16; @@ -140,7 +139,7 @@ dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, } if (*ver >= 0x40) { - u32 conf = nv_ro32(bios, dcb + 0x04); + u32 conf = nvbios_rd32(bios, dcb + 0x04); switch (outp->type) { case DCB_OUTPUT_DP: switch (conf & 0x00e00000) { @@ -156,20 +155,19 @@ dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, break; } - outp->dpconf.link_nr = (conf & 0x0f000000) >> 24; - if (*ver < 0x41) { - switch (outp->dpconf.link_nr) { - case 0x0f: - outp->dpconf.link_nr = 4; - break; - case 0x03: - outp->dpconf.link_nr = 2; - break; - case 0x01: - default: - outp->dpconf.link_nr = 1; - break; - } + switch ((conf & 0x0f000000) >> 24) { + case 0xf: + case 0x4: + outp->dpconf.link_nr = 4; + break; + case 0x3: + case 0x2: + outp->dpconf.link_nr = 2; + break; + case 0x1: + default: + outp->dpconf.link_nr = 1; + break; } /* fall-through... */ @@ -215,14 +213,14 @@ dcb_outp_foreach(struct nvkm_bios *bios, void *data, u16 outp; while ((outp = dcb_outp(bios, ++idx, &ver, &len))) { - if (nv_ro32(bios, outp) == 0x00000000) + if (nvbios_rd32(bios, outp) == 0x00000000) break; /* seen on an NV11 with DCB v1.5 */ - if (nv_ro32(bios, outp) == 0xffffffff) + if (nvbios_rd32(bios, outp) == 0xffffffff) break; /* seen on an NV17 with DCB v2.0 */ - if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED) + if (nvbios_rd08(bios, outp) == DCB_OUTPUT_UNUSED) continue; - if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL) + if (nvbios_rd08(bios, outp) == DCB_OUTPUT_EOL) break; ret = exec(bios, data, idx, outp); diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c index 262c410b7..a5e92135c 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c @@ -33,17 +33,17 @@ nvbios_disp_table(struct nvkm_bios *bios, if (!bit_entry(bios, 'U', &U)) { if (U.version == 1) { - u16 data = nv_ro16(bios, U.offset); + u16 data = nvbios_rd16(bios, U.offset); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x20: case 0x21: case 0x22: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); - *sub = nv_ro08(bios, data + 0x04); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); + *sub = nvbios_rd08(bios, data + 0x04); return data; default: break; @@ -72,7 +72,7 @@ nvbios_disp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, u8 *sub, { u16 data = nvbios_disp_entry(bios, idx, ver, len, sub); if (data && *len >= 2) { - info->data = nv_ro16(bios, data + 0); + info->data = nvbios_rd16(bios, data + 0); return data; } return 0x0000; @@ -85,7 +85,7 @@ nvbios_outp_entry(struct nvkm_bios *bios, u8 idx, struct nvbios_disp info; u16 data = nvbios_disp_parse(bios, idx, ver, len, hdr, &info); if (data) { - *cnt = nv_ro08(bios, info.data + 0x05); + *cnt = nvbios_rd08(bios, info.data + 0x05); *len = 0x06; data = info.data; } @@ -98,15 +98,15 @@ nvbios_outp_parse(struct nvkm_bios *bios, u8 idx, { u16 data = nvbios_outp_entry(bios, idx, ver, hdr, cnt, len); if (data && *hdr >= 0x0a) { - info->type = nv_ro16(bios, data + 0x00); - info->mask = nv_ro32(bios, data + 0x02); + info->type = nvbios_rd16(bios, data + 0x00); + info->mask = nvbios_rd32(bios, data + 0x02); if (*ver <= 0x20) /* match any link */ info->mask |= 0x00c0; - info->script[0] = nv_ro16(bios, data + 0x06); - info->script[1] = nv_ro16(bios, data + 0x08); + info->script[0] = nvbios_rd16(bios, data + 0x06); + info->script[1] = nvbios_rd16(bios, data + 0x08); info->script[2] = 0x0000; if (*hdr >= 0x0c) - info->script[2] = nv_ro16(bios, data + 0x0a); + info->script[2] = nvbios_rd16(bios, data + 0x0a); return data; } return 0x0000; @@ -141,9 +141,9 @@ nvbios_ocfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx, { u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len); if (data) { - info->match = nv_ro16(bios, data + 0x00); - info->clkcmp[0] = nv_ro16(bios, data + 0x02); - info->clkcmp[1] = nv_ro16(bios, data + 0x04); + info->match = nvbios_rd16(bios, data + 0x00); + info->clkcmp[0] = nvbios_rd16(bios, data + 0x02); + info->clkcmp[1] = nvbios_rd16(bios, data + 0x04); } return data; } @@ -164,8 +164,8 @@ u16 nvbios_oclk_match(struct nvkm_bios *bios, u16 cmp, u32 khz) { while (cmp) { - if (khz / 10 >= nv_ro16(bios, cmp + 0x00)) - return nv_ro16(bios, cmp + 0x02); + if (khz / 10 >= nvbios_rd16(bios, cmp + 0x00)) + return nvbios_rd16(bios, cmp + 0x02); cmp += 0x04; } return 0x0000; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c index 95970faae..053324763 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c @@ -32,17 +32,17 @@ nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'd', &d)) { if (d.version == 1 && d.length >= 2) { - u16 data = nv_ro16(bios, d.offset); + u16 data = nvbios_rd16(bios, d.offset); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x21: case 0x30: case 0x40: case 0x41: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); return data; default: break; @@ -60,17 +60,17 @@ nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx, { u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len); if (data && idx < *cnt) { - u16 outp = nv_ro16(bios, data + *hdr + idx * *len); + u16 outp = nvbios_rd16(bios, data + *hdr + idx * *len); switch (*ver * !!outp) { case 0x21: case 0x30: - *hdr = nv_ro08(bios, data + 0x04); - *len = nv_ro08(bios, data + 0x05); - *cnt = nv_ro08(bios, outp + 0x04); + *hdr = nvbios_rd08(bios, data + 0x04); + *len = nvbios_rd08(bios, data + 0x05); + *cnt = nvbios_rd08(bios, outp + 0x04); break; case 0x40: case 0x41: - *hdr = nv_ro08(bios, data + 0x04); + *hdr = nvbios_rd08(bios, data + 0x04); *cnt = 0; *len = 0; break; @@ -91,31 +91,31 @@ nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx, u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data && *ver) { - info->type = nv_ro16(bios, data + 0x00); - info->mask = nv_ro16(bios, data + 0x02); + info->type = nvbios_rd16(bios, data + 0x00); + info->mask = nvbios_rd16(bios, data + 0x02); switch (*ver) { case 0x21: case 0x30: - info->flags = nv_ro08(bios, data + 0x05); - info->script[0] = nv_ro16(bios, data + 0x06); - info->script[1] = nv_ro16(bios, data + 0x08); - info->lnkcmp = nv_ro16(bios, data + 0x0a); + info->flags = nvbios_rd08(bios, data + 0x05); + info->script[0] = nvbios_rd16(bios, data + 0x06); + info->script[1] = nvbios_rd16(bios, data + 0x08); + info->lnkcmp = nvbios_rd16(bios, data + 0x0a); if (*len >= 0x0f) { - info->script[2] = nv_ro16(bios, data + 0x0c); - info->script[3] = nv_ro16(bios, data + 0x0e); + info->script[2] = nvbios_rd16(bios, data + 0x0c); + info->script[3] = nvbios_rd16(bios, data + 0x0e); } if (*len >= 0x11) - info->script[4] = nv_ro16(bios, data + 0x10); + info->script[4] = nvbios_rd16(bios, data + 0x10); break; case 0x40: case 0x41: - info->flags = nv_ro08(bios, data + 0x04); - info->script[0] = nv_ro16(bios, data + 0x05); - info->script[1] = nv_ro16(bios, data + 0x07); - info->lnkcmp = nv_ro16(bios, data + 0x09); - info->script[2] = nv_ro16(bios, data + 0x0b); - info->script[3] = nv_ro16(bios, data + 0x0d); - info->script[4] = nv_ro16(bios, data + 0x0f); + info->flags = nvbios_rd08(bios, data + 0x04); + info->script[0] = nvbios_rd16(bios, data + 0x05); + info->script[1] = nvbios_rd16(bios, data + 0x07); + info->lnkcmp = nvbios_rd16(bios, data + 0x09); + info->script[2] = nvbios_rd16(bios, data + 0x0b); + info->script[3] = nvbios_rd16(bios, data + 0x0d); + info->script[4] = nvbios_rd16(bios, data + 0x0f); break; default: data = 0x0000; @@ -147,8 +147,9 @@ nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx, if (*ver >= 0x40) { outp = nvbios_dp_table(bios, ver, hdr, cnt, len); *hdr = *hdr + (*len * * cnt); - *len = nv_ro08(bios, outp + 0x06); - *cnt = nv_ro08(bios, outp + 0x07); + *len = nvbios_rd08(bios, outp + 0x06); + *cnt = nvbios_rd08(bios, outp + 0x07) * + nvbios_rd08(bios, outp + 0x05); } if (idx < *cnt) @@ -167,17 +168,17 @@ nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx, if (data) { switch (*ver) { case 0x21: - info->dc = nv_ro08(bios, data + 0x02); - info->pe = nv_ro08(bios, data + 0x03); - info->tx_pu = nv_ro08(bios, data + 0x04); + info->dc = nvbios_rd08(bios, data + 0x02); + info->pe = nvbios_rd08(bios, data + 0x03); + info->tx_pu = nvbios_rd08(bios, data + 0x04); break; case 0x30: case 0x40: case 0x41: - info->pc = nv_ro08(bios, data + 0x00); - info->dc = nv_ro08(bios, data + 0x01); - info->pe = nv_ro08(bios, data + 0x02); - info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f; + info->pc = nvbios_rd08(bios, data + 0x00); + info->dc = nvbios_rd08(bios, data + 0x01); + info->pe = nvbios_rd08(bios, data + 0x02); + info->tx_pu = nvbios_rd08(bios, data + 0x03); break; default: data = 0x0000; @@ -196,17 +197,15 @@ nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe, u16 data; if (*ver >= 0x30) { - /*XXX: there's a second set of these on at least 4.1, that - * i've witnessed nvidia using instead of the first - * on gm204. figure out what/why - */ const u8 vsoff[] = { 0, 4, 7, 9 }; idx = (pc * 10) + vsoff[vs] + pe; + if (*ver >= 0x40 && *hdr >= 0x12) + idx += nvbios_rd08(bios, outp + 0x11) * 40; } else { while ((data = nvbios_dpcfg_entry(bios, outp, ++idx, ver, hdr, cnt, len))) { - if (nv_ro08(bios, data + 0x00) == vs && - nv_ro08(bios, data + 0x01) == pe) + if (nvbios_rd08(bios, data + 0x00) == vs && + nvbios_rd08(bios, data + 0x01) == pe) break; } } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c index a8503a185..c9e6f6ff7 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c @@ -35,14 +35,14 @@ extdev_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40)) return 0x0000; - extdev = nv_ro16(bios, dcb + 18); + extdev = nvbios_rd16(bios, dcb + 18); if (!extdev) return 0x0000; - *ver = nv_ro08(bios, extdev + 0); - *hdr = nv_ro08(bios, extdev + 1); - *cnt = nv_ro08(bios, extdev + 2); - *len = nv_ro08(bios, extdev + 3); + *ver = nvbios_rd08(bios, extdev + 0); + *hdr = nvbios_rd08(bios, extdev + 1); + *cnt = nvbios_rd08(bios, extdev + 2); + *len = nvbios_rd08(bios, extdev + 3); return extdev + *hdr; } @@ -60,9 +60,9 @@ static void extdev_parse_entry(struct nvkm_bios *bios, u16 offset, struct nvbios_extdev_func *entry) { - entry->type = nv_ro08(bios, offset + 0); - entry->addr = nv_ro08(bios, offset + 1); - entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1; + entry->type = nvbios_rd08(bios, offset + 0); + entry->addr = nvbios_rd08(bios, offset + 1); + entry->bus = (nvbios_rd08(bios, offset + 2) >> 4) & 1; } int diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c index 8dba70d9d..80fed7e78 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c @@ -33,15 +33,15 @@ nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2 && bit_P.length >= 0x5a) - fan = nv_ro16(bios, bit_P.offset + 0x58); + fan = nvbios_rd16(bios, bit_P.offset + 0x58); if (fan) { - *ver = nv_ro08(bios, fan + 0); + *ver = nvbios_rd08(bios, fan + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, fan + 1); - *len = nv_ro08(bios, fan + 2); - *cnt = nv_ro08(bios, fan + 3); + *hdr = nvbios_rd08(bios, fan + 1); + *len = nvbios_rd08(bios, fan + 2); + *cnt = nvbios_rd08(bios, fan + 3); return fan; default: break; @@ -69,7 +69,7 @@ nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len); if (data) { - u8 type = nv_ro08(bios, data + 0x00); + u8 type = nvbios_rd08(bios, data + 0x00); switch (type) { case 0: fan->type = NVBIOS_THERM_FAN_TOGGLE; @@ -83,10 +83,11 @@ nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) fan->type = NVBIOS_THERM_FAN_UNK; } - fan->min_duty = nv_ro08(bios, data + 0x02); - fan->max_duty = nv_ro08(bios, data + 0x03); + fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; + fan->min_duty = nvbios_rd08(bios, data + 0x02); + fan->max_duty = nvbios_rd08(bios, data + 0x03); - fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff; + fan->pwm_freq = nvbios_rd32(bios, data + 0x0b) & 0xffffff; } return data; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c index 8ce154d88..2107b5584 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c @@ -33,22 +33,22 @@ dcb_gpio_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) u16 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb) { if (*ver >= 0x30 && *hdr >= 0x0c) - data = nv_ro16(bios, dcb + 0x0a); + data = nvbios_rd16(bios, dcb + 0x0a); else - if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) - data = nv_ro16(bios, dcb - 0x0f); + if (*ver >= 0x22 && nvbios_rd08(bios, dcb - 1) >= 0x13) + data = nvbios_rd16(bios, dcb - 0x0f); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); if (*ver < 0x30) { *hdr = 3; - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x01); } else if (*ver <= 0x41) { - *hdr = nv_ro08(bios, data + 0x01); - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x03); } else { data = 0x0000; } @@ -81,7 +81,7 @@ dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len, u16 data = dcb_gpio_entry(bios, idx, ent, ver, len); if (data) { if (*ver < 0x40) { - u16 info = nv_ro16(bios, data); + u16 info = nvbios_rd16(bios, data); *gpio = (struct dcb_gpio_func) { .line = (info & 0x001f) >> 0, .func = (info & 0x07e0) >> 5, @@ -91,7 +91,7 @@ dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len, }; } else if (*ver < 0x41) { - u32 info = nv_ro32(bios, data); + u32 info = nvbios_rd32(bios, data); *gpio = (struct dcb_gpio_func) { .line = (info & 0x0000001f) >> 0, .func = (info & 0x0000ff00) >> 8, @@ -100,8 +100,8 @@ dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len, .param = !!(info & 0x80000000), }; } else { - u32 info = nv_ro32(bios, data + 0); - u8 info1 = nv_ro32(bios, data + 4); + u32 info = nvbios_rd32(bios, data + 0); + u8 info1 = nvbios_rd32(bios, data + 4); *gpio = (struct dcb_gpio_func) { .line = (info & 0x0000003f) >> 0, .func = (info & 0x0000ff00) >> 8, @@ -131,8 +131,8 @@ dcb_gpio_match(struct nvkm_bios *bios, int idx, u8 func, u8 line, /* DCB 2.2, fixed TVDAC GPIO data */ if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) { if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) { - u8 conf = nv_ro08(bios, data - 5); - u8 addr = nv_ro08(bios, data - 4); + u8 conf = nvbios_rd08(bios, data - 5); + u8 addr = nvbios_rd08(bios, data - 4); if (conf & 0x01) { *gpio = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c index c4e1f085e..0fc60be32 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c @@ -32,21 +32,21 @@ dcb_i2c_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) u16 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb) { if (*ver >= 0x15) - i2c = nv_ro16(bios, dcb + 2); + i2c = nvbios_rd16(bios, dcb + 2); if (*ver >= 0x30) - i2c = nv_ro16(bios, dcb + 4); + i2c = nvbios_rd16(bios, dcb + 4); } if (i2c && *ver >= 0x42) { - nv_warn(bios, "ccb %02x not supported\n", *ver); + nvkm_warn(&bios->subdev, "ccb %02x not supported\n", *ver); return 0x0000; } if (i2c && *ver >= 0x30) { - *ver = nv_ro08(bios, i2c + 0); - *hdr = nv_ro08(bios, i2c + 1); - *cnt = nv_ro08(bios, i2c + 2); - *len = nv_ro08(bios, i2c + 3); + *ver = nvbios_rd08(bios, i2c + 0); + *hdr = nvbios_rd08(bios, i2c + 1); + *cnt = nvbios_rd08(bios, i2c + 2); + *len = nvbios_rd08(bios, i2c + 3); } else { *ver = *ver; /* use DCB version */ *hdr = 0; @@ -70,13 +70,14 @@ dcb_i2c_entry(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len) int dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) { + struct nvkm_subdev *subdev = &bios->subdev; u8 ver, len; u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); if (ent) { if (ver >= 0x41) { - u32 ent_value = nv_ro32(bios, ent); - u8 i2c_port = (ent_value >> 27) & 0x1f; - u8 dpaux_port = (ent_value >> 22) & 0x1f; + u32 ent_value = nvbios_rd32(bios, ent); + u8 i2c_port = (ent_value >> 0) & 0x1f; + u8 dpaux_port = (ent_value >> 5) & 0x1f; /* value 0x1f means unused according to DCB 4.x spec */ if (i2c_port == 0x1f && dpaux_port == 0x1f) info->type = DCB_I2C_UNUSED; @@ -84,9 +85,9 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) info->type = DCB_I2C_PMGR; } else if (ver >= 0x30) { - info->type = nv_ro08(bios, ent + 0x03); + info->type = nvbios_rd08(bios, ent + 0x03); } else { - info->type = nv_ro08(bios, ent + 0x03) & 0x07; + info->type = nvbios_rd08(bios, ent + 0x03) & 0x07; if (info->type == 0x07) info->type = DCB_I2C_UNUSED; } @@ -98,27 +99,27 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) switch (info->type) { case DCB_I2C_NV04_BIT: - info->drive = nv_ro08(bios, ent + 0); - info->sense = nv_ro08(bios, ent + 1); + info->drive = nvbios_rd08(bios, ent + 0); + info->sense = nvbios_rd08(bios, ent + 1); return 0; case DCB_I2C_NV4E_BIT: - info->drive = nv_ro08(bios, ent + 1); + info->drive = nvbios_rd08(bios, ent + 1); return 0; case DCB_I2C_NVIO_BIT: - info->drive = nv_ro08(bios, ent + 0) & 0x0f; - if (nv_ro08(bios, ent + 1) & 0x01) - info->share = nv_ro08(bios, ent + 1) >> 1; + info->drive = nvbios_rd08(bios, ent + 0) & 0x0f; + if (nvbios_rd08(bios, ent + 1) & 0x01) + info->share = nvbios_rd08(bios, ent + 1) >> 1; return 0; case DCB_I2C_NVIO_AUX: - info->auxch = nv_ro08(bios, ent + 0) & 0x0f; - if (nv_ro08(bios, ent + 1) & 0x01) + info->auxch = nvbios_rd08(bios, ent + 0) & 0x0f; + if (nvbios_rd08(bios, ent + 1) & 0x01) info->share = info->auxch; return 0; case DCB_I2C_PMGR: - info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0; + info->drive = (nvbios_rd16(bios, ent + 0) & 0x01f) >> 0; if (info->drive == 0x1f) info->drive = DCB_I2C_UNUSED; - info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5; + info->auxch = (nvbios_rd16(bios, ent + 0) & 0x3e0) >> 5; if (info->auxch == 0x1f) info->auxch = DCB_I2C_UNUSED; info->share = info->auxch; @@ -126,7 +127,7 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) case DCB_I2C_UNUSED: return 0; default: - nv_warn(bios, "unknown i2c type %d\n", info->type); + nvkm_warn(subdev, "unknown i2c type %d\n", info->type); info->type = DCB_I2C_UNUSED; return 0; } @@ -136,21 +137,21 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) /* BMP (from v4.0 has i2c info in the structure, it's in a * fixed location on earlier VBIOS */ - if (nv_ro08(bios, bios->bmp_offset + 5) < 4) + if (nvbios_rd08(bios, bios->bmp_offset + 5) < 4) ent = 0x0048; else ent = 0x0036 + bios->bmp_offset; if (idx == 0) { - info->drive = nv_ro08(bios, ent + 4); + info->drive = nvbios_rd08(bios, ent + 4); if (!info->drive) info->drive = 0x3f; - info->sense = nv_ro08(bios, ent + 5); + info->sense = nvbios_rd08(bios, ent + 5); if (!info->sense) info->sense = 0x3e; } else if (idx == 1) { - info->drive = nv_ro08(bios, ent + 6); + info->drive = nvbios_rd08(bios, ent + 6); if (!info->drive) info->drive = 0x37; - info->sense = nv_ro08(bios, ent + 7); + info->sense = nvbios_rd08(bios, ent + 7); if (!info->sense) info->sense = 0x36; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c index 1815540a0..74b14cf09 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c @@ -29,20 +29,21 @@ static bool nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image) { + struct nvkm_subdev *subdev = &bios->subdev; struct nvbios_pcirT pcir; struct nvbios_npdeT npde; u8 ver; u16 hdr; u32 data; - switch ((data = nv_ro16(bios, image->base + 0x00))) { + switch ((data = nvbios_rd16(bios, image->base + 0x00))) { case 0xaa55: case 0xbb77: case 0x4e56: /* NV */ break; default: - nv_debug(bios, "%08x: ROM signature (%04x) unknown\n", - image->base, data); + nvkm_debug(subdev, "%08x: ROM signature (%04x) unknown\n", + image->base, data); return false; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index f67cdae1e..a7d69ce7a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -31,18 +31,18 @@ #include <subdev/bios/init.h> #include <subdev/bios/ramcfg.h> -#include <core/device.h> #include <subdev/devinit.h> #include <subdev/gpio.h> #include <subdev/i2c.h> #include <subdev/vga.h> #define bioslog(lvl, fmt, args...) do { \ - nv_printk(init->bios, lvl, "0x%04x[%c]: "fmt, init->offset, \ - init_exec(init) ? '0' + (init->nested - 1) : ' ', ##args); \ + nvkm_printk(init->subdev, lvl, info, "0x%04x[%c]: "fmt, \ + init->offset, init_exec(init) ? \ + '0' + (init->nested - 1) : ' ', ##args); \ } while(0) #define cont(fmt, args...) do { \ - if (nv_subdev(init->bios)->debug >= NV_DBG_TRACE) \ + if (init->subdev->debug >= NV_DBG_TRACE) \ printk(fmt, ##args); \ } while(0) #define trace(fmt, args...) bioslog(TRACE, fmt, ##args) @@ -141,7 +141,7 @@ init_conn(struct nvbios_init *init) static inline u32 init_nvreg(struct nvbios_init *init, u32 reg) { - struct nvkm_devinit *devinit = nvkm_devinit(init->bios); + struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; /* C51 (at least) sometimes has the lower bits set which the VBIOS * interprets to mean that access needs to go through certain IO @@ -154,7 +154,7 @@ init_nvreg(struct nvbios_init *init, u32 reg) /* GF8+ display scripts need register addresses mangled a bit to * select a specific CRTC/OR */ - if (nv_device(init->bios)->card_type >= NV_50) { + if (init->bios->subdev.device->card_type >= NV_50) { if (reg & 0x80000000) { reg += init_crtc(init) * 0x800; reg &= ~0x80000000; @@ -173,35 +173,36 @@ init_nvreg(struct nvbios_init *init, u32 reg) if (reg & ~0x00fffffc) warn("unknown bits in register 0x%08x\n", reg); - if (devinit->mmio) - reg = devinit->mmio(devinit, reg); - return reg; + return nvkm_devinit_mmio(devinit, reg); } static u32 init_rd32(struct nvbios_init *init, u32 reg) { + struct nvkm_device *device = init->bios->subdev.device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) - return nv_rd32(init->subdev, reg); + return nvkm_rd32(device, reg); return 0x00000000; } static void init_wr32(struct nvbios_init *init, u32 reg, u32 val) { + struct nvkm_device *device = init->bios->subdev.device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) - nv_wr32(init->subdev, reg, val); + nvkm_wr32(device, reg, val); } static u32 init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val) { + struct nvkm_device *device = init->bios->subdev.device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) { - u32 tmp = nv_rd32(init->subdev, reg); - nv_wr32(init->subdev, reg, (tmp & ~mask) | val); + u32 tmp = nvkm_rd32(device, reg); + nvkm_wr32(device, reg, (tmp & ~mask) | val); return tmp; } return 0x00000000; @@ -211,7 +212,7 @@ static u8 init_rdport(struct nvbios_init *init, u16 port) { if (init_exec(init)) - return nv_rdport(init->subdev, init->crtc, port); + return nvkm_rdport(init->subdev->device, init->crtc, port); return 0x00; } @@ -219,7 +220,7 @@ static void init_wrport(struct nvbios_init *init, u16 port, u8 value) { if (init_exec(init)) - nv_wrport(init->subdev, init->crtc, port, value); + nvkm_wrport(init->subdev->device, init->crtc, port, value); } static u8 @@ -228,7 +229,7 @@ init_rdvgai(struct nvbios_init *init, u16 port, u8 index) struct nvkm_subdev *subdev = init->subdev; if (init_exec(init)) { int head = init->crtc < 0 ? 0 : init->crtc; - return nv_rdvgai(subdev, head, port, index); + return nvkm_rdvgai(subdev->device, head, port, index); } return 0x00; } @@ -236,80 +237,86 @@ init_rdvgai(struct nvbios_init *init, u16 port, u8 index) static void init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value) { + struct nvkm_device *device = init->subdev->device; + /* force head 0 for updates to cr44, it only exists on first head */ - if (nv_device(init->subdev)->card_type < NV_50) { + if (device->card_type < NV_50) { if (port == 0x03d4 && index == 0x44) init->crtc = 0; } if (init_exec(init)) { int head = init->crtc < 0 ? 0 : init->crtc; - nv_wrvgai(init->subdev, head, port, index, value); + nvkm_wrvgai(device, head, port, index, value); } /* select head 1 if cr44 write selected it */ - if (nv_device(init->subdev)->card_type < NV_50) { + if (device->card_type < NV_50) { if (port == 0x03d4 && index == 0x44 && value == 3) init->crtc = 1; } } -static struct nvkm_i2c_port * +static struct i2c_adapter * init_i2c(struct nvbios_init *init, int index) { - struct nvkm_i2c *i2c = nvkm_i2c(init->bios); + struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; + struct nvkm_i2c_bus *bus; if (index == 0xff) { - index = NV_I2C_DEFAULT(0); + index = NVKM_I2C_BUS_PRI; if (init->outp && init->outp->i2c_upper_default) - index = NV_I2C_DEFAULT(1); + index = NVKM_I2C_BUS_SEC; } else - if (index < 0) { - if (!init->outp) { - if (init_exec(init)) - error("script needs output for i2c\n"); - return NULL; - } - - if (index == -2 && init->outp->location) { - index = NV_I2C_TYPE_EXTAUX(init->outp->extdev); - return i2c->find_type(i2c, index); - } - - index = init->outp->i2c_index; - if (init->outp->type == DCB_OUTPUT_DP) - index += NV_I2C_AUX(0); + if (index == 0x80) { + index = NVKM_I2C_BUS_PRI; + } else + if (index == 0x81) { + index = NVKM_I2C_BUS_SEC; } - return i2c->find(i2c, index); + bus = nvkm_i2c_bus_find(i2c, index); + return bus ? &bus->i2c : NULL; } static int init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg) { - struct nvkm_i2c_port *port = init_i2c(init, index); - if (port && init_exec(init)) - return nv_rdi2cr(port, addr, reg); + struct i2c_adapter *adap = init_i2c(init, index); + if (adap && init_exec(init)) + return nvkm_rdi2cr(adap, addr, reg); return -ENODEV; } static int init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val) { - struct nvkm_i2c_port *port = init_i2c(init, index); - if (port && init_exec(init)) - return nv_wri2cr(port, addr, reg, val); + struct i2c_adapter *adap = init_i2c(init, index); + if (adap && init_exec(init)) + return nvkm_wri2cr(adap, addr, reg, val); return -ENODEV; } +static struct nvkm_i2c_aux * +init_aux(struct nvbios_init *init) +{ + struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; + if (!init->outp) { + if (init_exec(init)) + error("script needs output for aux\n"); + return NULL; + } + return nvkm_i2c_aux_find(i2c, init->outp->i2c_index); +} + static u8 init_rdauxr(struct nvbios_init *init, u32 addr) { - struct nvkm_i2c_port *port = init_i2c(init, -2); + struct nvkm_i2c_aux *aux = init_aux(init); u8 data; - if (port && init_exec(init)) { - int ret = nv_rdaux(port, addr, &data, 1); + if (aux && init_exec(init)) { + int ret = nvkm_rdaux(aux, addr, &data, 1); if (ret == 0) return data; trace("auxch read failed with %d\n", ret); @@ -321,9 +328,9 @@ init_rdauxr(struct nvbios_init *init, u32 addr) static int init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) { - struct nvkm_i2c_port *port = init_i2c(init, -2); - if (port && init_exec(init)) { - int ret = nv_wraux(port, addr, &data, 1); + struct nvkm_i2c_aux *aux = init_aux(init); + if (aux && init_exec(init)) { + int ret = nvkm_wraux(aux, addr, &data, 1); if (ret) trace("auxch write failed with %d\n", ret); return ret; @@ -334,9 +341,9 @@ init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) static void init_prog_pll(struct nvbios_init *init, u32 id, u32 freq) { - struct nvkm_devinit *devinit = nvkm_devinit(init->bios); - if (devinit->pll_set && init_exec(init)) { - int ret = devinit->pll_set(devinit, id, freq); + struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; + if (init_exec(init)) { + int ret = nvkm_devinit_pll_set(devinit, id, freq); if (ret) warn("failed to prog pll 0x%08x to %dkHz\n", id, freq); } @@ -371,7 +378,7 @@ init_table_(struct nvbios_init *init, u16 offset, const char *name) u16 len, data = init_table(bios, &len); if (data) { if (len >= offset + 2) { - data = nv_ro16(bios, data + offset); + data = nvbios_rd16(bios, data + offset); if (data) return data; @@ -407,12 +414,12 @@ init_script(struct nvkm_bios *bios, int index) return 0x0000; data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18); - return nv_ro16(bios, data + (index * 2)); + return nvbios_rd16(bios, data + (index * 2)); } data = init_script_table(&init); if (data) - return nv_ro16(bios, data + (index * 2)); + return nvbios_rd16(bios, data + (index * 2)); return 0x0000; } @@ -422,7 +429,7 @@ init_unknown_script(struct nvkm_bios *bios) { u16 len, data = init_table(bios, &len); if (data && len >= 16) - return nv_ro16(bios, data + 14); + return nvbios_rd16(bios, data + 14); return 0x0000; } @@ -454,9 +461,9 @@ init_xlat_(struct nvbios_init *init, u8 index, u8 offset) struct nvkm_bios *bios = init->bios; u16 table = init_xlat_table(init); if (table) { - u16 data = nv_ro16(bios, table + (index * 2)); + u16 data = nvbios_rd16(bios, table + (index * 2)); if (data) - return nv_ro08(bios, data + offset); + return nvbios_rd08(bios, data + offset); warn("xlat table pointer %d invalid\n", index); } return 0x00; @@ -472,9 +479,9 @@ init_condition_met(struct nvbios_init *init, u8 cond) struct nvkm_bios *bios = init->bios; u16 table = init_condition_table(init); if (table) { - u32 reg = nv_ro32(bios, table + (cond * 12) + 0); - u32 msk = nv_ro32(bios, table + (cond * 12) + 4); - u32 val = nv_ro32(bios, table + (cond * 12) + 8); + u32 reg = nvbios_rd32(bios, table + (cond * 12) + 0); + u32 msk = nvbios_rd32(bios, table + (cond * 12) + 4); + u32 val = nvbios_rd32(bios, table + (cond * 12) + 8); trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n", cond, reg, msk, val); return (init_rd32(init, reg) & msk) == val; @@ -488,10 +495,10 @@ init_io_condition_met(struct nvbios_init *init, u8 cond) struct nvkm_bios *bios = init->bios; u16 table = init_io_condition_table(init); if (table) { - u16 port = nv_ro16(bios, table + (cond * 5) + 0); - u8 index = nv_ro08(bios, table + (cond * 5) + 2); - u8 mask = nv_ro08(bios, table + (cond * 5) + 3); - u8 value = nv_ro08(bios, table + (cond * 5) + 4); + u16 port = nvbios_rd16(bios, table + (cond * 5) + 0); + u8 index = nvbios_rd08(bios, table + (cond * 5) + 2); + u8 mask = nvbios_rd08(bios, table + (cond * 5) + 3); + u8 value = nvbios_rd08(bios, table + (cond * 5) + 4); trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n", cond, port, index, mask, value); return (init_rdvgai(init, port, index) & mask) == value; @@ -505,15 +512,15 @@ init_io_flag_condition_met(struct nvbios_init *init, u8 cond) struct nvkm_bios *bios = init->bios; u16 table = init_io_flag_condition_table(init); if (table) { - u16 port = nv_ro16(bios, table + (cond * 9) + 0); - u8 index = nv_ro08(bios, table + (cond * 9) + 2); - u8 mask = nv_ro08(bios, table + (cond * 9) + 3); - u8 shift = nv_ro08(bios, table + (cond * 9) + 4); - u16 data = nv_ro16(bios, table + (cond * 9) + 5); - u8 dmask = nv_ro08(bios, table + (cond * 9) + 7); - u8 value = nv_ro08(bios, table + (cond * 9) + 8); + u16 port = nvbios_rd16(bios, table + (cond * 9) + 0); + u8 index = nvbios_rd08(bios, table + (cond * 9) + 2); + u8 mask = nvbios_rd08(bios, table + (cond * 9) + 3); + u8 shift = nvbios_rd08(bios, table + (cond * 9) + 4); + u16 data = nvbios_rd16(bios, table + (cond * 9) + 5); + u8 dmask = nvbios_rd08(bios, table + (cond * 9) + 7); + u8 value = nvbios_rd08(bios, table + (cond * 9) + 8); u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift; - return (nv_ro08(bios, data + ioval) & dmask) == value; + return (nvbios_rd08(bios, data + ioval) & dmask) == value; } return false; } @@ -573,7 +580,7 @@ init_tmds_reg(struct nvbios_init *init, u8 tmds) static void init_reserved(struct nvbios_init *init) { - u8 opcode = nv_ro08(init->bios, init->offset); + u8 opcode = nvbios_rd08(init->bios, init->offset); u8 length, i; switch (opcode) { @@ -587,7 +594,7 @@ init_reserved(struct nvbios_init *init) trace("RESERVED 0x%02x\t", opcode); for (i = 1; i < length; i++) - cont(" 0x%02x", nv_ro08(init->bios, init->offset + i)); + cont(" 0x%02x", nvbios_rd08(init->bios, init->offset + i)); cont("\n"); init->offset += length; } @@ -611,12 +618,12 @@ static void init_io_restrict_prog(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 shift = nv_ro08(bios, init->offset + 5); - u8 count = nv_ro08(bios, init->offset + 6); - u32 reg = nv_ro32(bios, init->offset + 7); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u8 count = nvbios_rd08(bios, init->offset + 6); + u32 reg = nvbios_rd32(bios, init->offset + 7); u8 conf, i; trace("IO_RESTRICT_PROG\tR[0x%06x] = " @@ -626,7 +633,7 @@ init_io_restrict_prog(struct nvbios_init *init) conf = (init_rdvgai(init, port, index) & mask) >> shift; for (i = 0; i < count; i++) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); if (i == conf) { trace("\t0x%08x *\n", data); @@ -648,7 +655,7 @@ static void init_repeat(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 count = nv_ro08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 1); u16 repeat = init->repeat; trace("REPEAT\t0x%02x\n", count); @@ -674,13 +681,13 @@ static void init_io_restrict_pll(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 shift = nv_ro08(bios, init->offset + 5); - s8 iofc = nv_ro08(bios, init->offset + 6); - u8 count = nv_ro08(bios, init->offset + 7); - u32 reg = nv_ro32(bios, init->offset + 8); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 shift = nvbios_rd08(bios, init->offset + 5); + s8 iofc = nvbios_rd08(bios, init->offset + 6); + u8 count = nvbios_rd08(bios, init->offset + 7); + u32 reg = nvbios_rd32(bios, init->offset + 8); u8 conf, i; trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= " @@ -690,7 +697,7 @@ init_io_restrict_pll(struct nvbios_init *init) conf = (init_rdvgai(init, port, index) & mask) >> shift; for (i = 0; i < count; i++) { - u32 freq = nv_ro16(bios, init->offset) * 10; + u32 freq = nvbios_rd16(bios, init->offset) * 10; if (i == conf) { trace("\t%dkHz *\n", freq); @@ -730,12 +737,12 @@ static void init_copy(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u8 shift = nv_ro08(bios, init->offset + 5); - u8 smask = nv_ro08(bios, init->offset + 6); - u16 port = nv_ro16(bios, init->offset + 7); - u8 index = nv_ro08(bios, init->offset + 9); - u8 mask = nv_ro08(bios, init->offset + 10); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u8 smask = nvbios_rd08(bios, init->offset + 6); + u16 port = nvbios_rd16(bios, init->offset + 7); + u8 index = nvbios_rd08(bios, init->offset + 9); + u8 mask = nvbios_rd08(bios, init->offset + 10); u8 data; trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= " @@ -769,7 +776,7 @@ static void init_io_flag_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); + u8 cond = nvbios_rd08(bios, init->offset + 1); trace("IO_FLAG_CONDITION\t0x%02x\n", cond); init->offset += 2; @@ -787,8 +794,8 @@ init_dp_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; struct nvbios_dpout info; - u8 cond = nv_ro08(bios, init->offset + 1); - u8 unkn = nv_ro08(bios, init->offset + 2); + u8 cond = nvbios_rd08(bios, init->offset + 1); + u8 unkn = nvbios_rd08(bios, init->offset + 2); u8 ver, hdr, cnt, len; u16 data; @@ -834,7 +841,7 @@ static void init_io_mask_or(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 1); u8 or = init_or(init); u8 data; @@ -853,7 +860,7 @@ static void init_io_or(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 1); u8 or = init_or(init); u8 data; @@ -872,8 +879,8 @@ static void init_andn_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask); init->offset += 9; @@ -889,8 +896,8 @@ static void init_or_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask); init->offset += 9; @@ -906,19 +913,19 @@ static void init_idx_addr_latched(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 creg = nv_ro32(bios, init->offset + 1); - u32 dreg = nv_ro32(bios, init->offset + 5); - u32 mask = nv_ro32(bios, init->offset + 9); - u32 data = nv_ro32(bios, init->offset + 13); - u8 count = nv_ro08(bios, init->offset + 17); + u32 creg = nvbios_rd32(bios, init->offset + 1); + u32 dreg = nvbios_rd32(bios, init->offset + 5); + u32 mask = nvbios_rd32(bios, init->offset + 9); + u32 data = nvbios_rd32(bios, init->offset + 13); + u8 count = nvbios_rd08(bios, init->offset + 17); trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg); trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data); init->offset += 18; while (count--) { - u8 iaddr = nv_ro08(bios, init->offset + 0); - u8 idata = nv_ro08(bios, init->offset + 1); + u8 iaddr = nvbios_rd08(bios, init->offset + 0); + u8 idata = nvbios_rd08(bios, init->offset + 1); trace("\t[0x%02x] = 0x%02x\n", iaddr, idata); init->offset += 2; @@ -936,12 +943,12 @@ static void init_io_restrict_pll2(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 shift = nv_ro08(bios, init->offset + 5); - u8 count = nv_ro08(bios, init->offset + 6); - u32 reg = nv_ro32(bios, init->offset + 7); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u8 count = nvbios_rd08(bios, init->offset + 6); + u32 reg = nvbios_rd32(bios, init->offset + 7); u8 conf, i; trace("IO_RESTRICT_PLL2\t" @@ -951,7 +958,7 @@ init_io_restrict_pll2(struct nvbios_init *init) conf = (init_rdvgai(init, port, index) & mask) >> shift; for (i = 0; i < count; i++) { - u32 freq = nv_ro32(bios, init->offset); + u32 freq = nvbios_rd32(bios, init->offset); if (i == conf) { trace("\t%dkHz *\n", freq); init_prog_pll(init, reg, freq); @@ -971,8 +978,8 @@ static void init_pll2(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 freq = nv_ro32(bios, init->offset + 5); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 freq = nvbios_rd32(bios, init->offset + 5); trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq); init->offset += 9; @@ -988,17 +995,17 @@ static void init_i2c_byte(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 count = nv_ro08(bios, init->offset + 3); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 count = nvbios_rd08(bios, init->offset + 3); trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr); init->offset += 4; while (count--) { - u8 reg = nv_ro08(bios, init->offset + 0); - u8 mask = nv_ro08(bios, init->offset + 1); - u8 data = nv_ro08(bios, init->offset + 2); + u8 reg = nvbios_rd08(bios, init->offset + 0); + u8 mask = nvbios_rd08(bios, init->offset + 1); + u8 data = nvbios_rd08(bios, init->offset + 2); int val; trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data); @@ -1019,16 +1026,16 @@ static void init_zm_i2c_byte(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 count = nv_ro08(bios, init->offset + 3); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 count = nvbios_rd08(bios, init->offset + 3); trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr); init->offset += 4; while (count--) { - u8 reg = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 reg = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\t[0x%02x] = 0x%02x\n", reg, data); init->offset += 2; @@ -1045,28 +1052,28 @@ static void init_zm_i2c(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 count = nv_ro08(bios, init->offset + 3); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 count = nvbios_rd08(bios, init->offset + 3); u8 data[256], i; trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr); init->offset += 4; for (i = 0; i < count; i++) { - data[i] = nv_ro08(bios, init->offset); + data[i] = nvbios_rd08(bios, init->offset); trace("\t0x%02x\n", data[i]); init->offset++; } if (init_exec(init)) { - struct nvkm_i2c_port *port = init_i2c(init, index); + struct i2c_adapter *adap = init_i2c(init, index); struct i2c_msg msg = { .addr = addr, .flags = 0, .len = count, .buf = data, }; int ret; - if (port && (ret = i2c_transfer(&port->adapter, &msg, 1)) != 1) + if (adap && (ret = i2c_transfer(adap, &msg, 1)) != 1) warn("i2c wr failed, %d\n", ret); } } @@ -1079,10 +1086,10 @@ static void init_tmds(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 tmds = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2); - u8 mask = nv_ro08(bios, init->offset + 3); - u8 data = nv_ro08(bios, init->offset + 4); + u8 tmds = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2); + u8 mask = nvbios_rd08(bios, init->offset + 3); + u8 data = nvbios_rd08(bios, init->offset + 4); u32 reg = init_tmds_reg(init, tmds); trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n", @@ -1105,16 +1112,16 @@ static void init_zm_tmds_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 tmds = nv_ro08(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 2); + u8 tmds = nvbios_rd08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 2); u32 reg = init_tmds_reg(init, tmds); trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds); init->offset += 3; while (count--) { - u8 addr = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\t[0x%02x] = 0x%02x\n", addr, data); init->offset += 2; @@ -1132,10 +1139,10 @@ static void init_cr_idx_adr_latch(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 addr0 = nv_ro08(bios, init->offset + 1); - u8 addr1 = nv_ro08(bios, init->offset + 2); - u8 base = nv_ro08(bios, init->offset + 3); - u8 count = nv_ro08(bios, init->offset + 4); + u8 addr0 = nvbios_rd08(bios, init->offset + 1); + u8 addr1 = nvbios_rd08(bios, init->offset + 2); + u8 base = nvbios_rd08(bios, init->offset + 3); + u8 count = nvbios_rd08(bios, init->offset + 4); u8 save0; trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1); @@ -1143,7 +1150,7 @@ init_cr_idx_adr_latch(struct nvbios_init *init) save0 = init_rdvgai(init, 0x03d4, addr0); while (count--) { - u8 data = nv_ro08(bios, init->offset); + u8 data = nvbios_rd08(bios, init->offset); trace("\t\t[0x%02x] = 0x%02x\n", base, data); init->offset += 1; @@ -1162,9 +1169,9 @@ static void init_cr(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 addr = nv_ro08(bios, init->offset + 1); - u8 mask = nv_ro08(bios, init->offset + 2); - u8 data = nv_ro08(bios, init->offset + 3); + u8 addr = nvbios_rd08(bios, init->offset + 1); + u8 mask = nvbios_rd08(bios, init->offset + 2); + u8 data = nvbios_rd08(bios, init->offset + 3); u8 val; trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data); @@ -1182,8 +1189,8 @@ static void init_zm_cr(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 addr = nv_ro08(bios, init->offset + 1); - u8 data = nv_ro08(bios, init->offset + 2); + u8 addr = nvbios_rd08(bios, init->offset + 1); + u8 data = nvbios_rd08(bios, init->offset + 2); trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr, data); init->offset += 3; @@ -1199,14 +1206,14 @@ static void init_zm_cr_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 count = nv_ro08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 1); trace("ZM_CR_GROUP\n"); init->offset += 2; while (count--) { - u8 addr = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\t\tC[0x%02x] = 0x%02x\n", addr, data); init->offset += 2; @@ -1223,8 +1230,8 @@ static void init_condition_time(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); - u8 retry = nv_ro08(bios, init->offset + 2); + u8 cond = nvbios_rd08(bios, init->offset + 1); + u8 retry = nvbios_rd08(bios, init->offset + 2); u8 wait = min((u16)retry * 50, 100); trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry); @@ -1250,7 +1257,7 @@ static void init_ltime(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 msec = nv_ro16(bios, init->offset + 1); + u16 msec = nvbios_rd16(bios, init->offset + 1); trace("LTIME\t0x%04x\n", msec); init->offset += 3; @@ -1267,14 +1274,14 @@ static void init_zm_reg_sequence(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 base = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 base = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("ZM_REG_SEQUENCE\t0x%02x\n", count); init->offset += 6; while (count--) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); trace("\t\tR[0x%06x] = 0x%08x\n", base, data); init->offset += 4; @@ -1285,6 +1292,44 @@ init_zm_reg_sequence(struct nvbios_init *init) } /** + * INIT_PLL_INDIRECT - opcode 0x59 + * + */ +static void +init_pll_indirect(struct nvbios_init *init) +{ + struct nvkm_bios *bios = init->bios; + u32 reg = nvbios_rd32(bios, init->offset + 1); + u16 addr = nvbios_rd16(bios, init->offset + 5); + u32 freq = (u32)nvbios_rd16(bios, addr) * 1000; + + trace("PLL_INDIRECT\tR[0x%06x] =PLL= VBIOS[%04x] = %dkHz\n", + reg, addr, freq); + init->offset += 7; + + init_prog_pll(init, reg, freq); +} + +/** + * INIT_ZM_REG_INDIRECT - opcode 0x5a + * + */ +static void +init_zm_reg_indirect(struct nvbios_init *init) +{ + struct nvkm_bios *bios = init->bios; + u32 reg = nvbios_rd32(bios, init->offset + 1); + u16 addr = nvbios_rd16(bios, init->offset + 5); + u32 data = nvbios_rd32(bios, addr); + + trace("ZM_REG_INDIRECT\tR[0x%06x] = VBIOS[0x%04x] = 0x%08x\n", + reg, addr, data); + init->offset += 7; + + init_wr32(init, addr, data); +} + +/** * INIT_SUB_DIRECT - opcode 0x5b * */ @@ -1292,7 +1337,7 @@ static void init_sub_direct(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 addr = nv_ro16(bios, init->offset + 1); + u16 addr = nvbios_rd16(bios, init->offset + 1); u16 save; trace("SUB_DIRECT\t0x%04x\n", addr); @@ -1318,7 +1363,7 @@ static void init_jump(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 offset = nv_ro16(bios, init->offset + 1); + u16 offset = nvbios_rd16(bios, init->offset + 1); trace("JUMP\t0x%04x\n", offset); @@ -1336,11 +1381,11 @@ static void init_i2c_if(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2); - u8 reg = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 data = nv_ro08(bios, init->offset + 5); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2); + u8 reg = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 data = nvbios_rd08(bios, init->offset + 5); u8 value; trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n", @@ -1363,12 +1408,12 @@ static void init_copy_nv_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 sreg = nv_ro32(bios, init->offset + 1); - u8 shift = nv_ro08(bios, init->offset + 5); - u32 smask = nv_ro32(bios, init->offset + 6); - u32 sxor = nv_ro32(bios, init->offset + 10); - u32 dreg = nv_ro32(bios, init->offset + 14); - u32 dmask = nv_ro32(bios, init->offset + 18); + u32 sreg = nvbios_rd32(bios, init->offset + 1); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u32 smask = nvbios_rd32(bios, init->offset + 6); + u32 sxor = nvbios_rd32(bios, init->offset + 10); + u32 dreg = nvbios_rd32(bios, init->offset + 14); + u32 dmask = nvbios_rd32(bios, init->offset + 18); u32 data; trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= " @@ -1389,9 +1434,9 @@ static void init_zm_index_io(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 data = nv_ro08(bios, init->offset + 4); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 data = nvbios_rd08(bios, init->offset + 4); trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data); init->offset += 5; @@ -1406,14 +1451,14 @@ init_zm_index_io(struct nvbios_init *init) static void init_compute_mem(struct nvbios_init *init) { - struct nvkm_devinit *devinit = nvkm_devinit(init->bios); + struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; trace("COMPUTE_MEM\n"); init->offset += 1; init_exec_force(init, true); - if (init_exec(init) && devinit->meminit) - devinit->meminit(devinit); + if (init_exec(init)) + nvkm_devinit_meminit(devinit); init_exec_force(init, false); } @@ -1425,9 +1470,9 @@ static void init_reset(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 data1 = nv_ro32(bios, init->offset + 5); - u32 data2 = nv_ro32(bios, init->offset + 9); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 data1 = nvbios_rd32(bios, init->offset + 5); + u32 data2 = nvbios_rd32(bios, init->offset + 9); u32 savepci19; trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2); @@ -1475,14 +1520,14 @@ init_configure_mem(struct nvbios_init *init) mdata = init_configure_mem_clk(init); sdata = bmp_sdr_seq_table(bios); - if (nv_ro08(bios, mdata) & 0x01) + if (nvbios_rd08(bios, mdata) & 0x01) sdata = bmp_ddr_seq_table(bios); mdata += 6; /* skip to data */ data = init_rdvgai(init, 0x03c4, 0x01); init_wrvgai(init, 0x03c4, 0x01, data | 0x20); - for (; (addr = nv_ro32(bios, sdata)) != 0xffffffff; sdata += 4) { + for (; (addr = nvbios_rd32(bios, sdata)) != 0xffffffff; sdata += 4) { switch (addr) { case 0x10021c: /* CKE_NORMAL */ case 0x1002d0: /* CMD_REFRESH */ @@ -1490,7 +1535,7 @@ init_configure_mem(struct nvbios_init *init) data = 0x00000001; break; default: - data = nv_ro32(bios, mdata); + data = nvbios_rd32(bios, mdata); mdata += 4; if (data == 0xffffffff) continue; @@ -1525,12 +1570,12 @@ init_configure_clk(struct nvbios_init *init) mdata = init_configure_mem_clk(init); /* NVPLL */ - clock = nv_ro16(bios, mdata + 4) * 10; + clock = nvbios_rd16(bios, mdata + 4) * 10; init_prog_pll(init, 0x680500, clock); /* MPLL */ - clock = nv_ro16(bios, mdata + 2) * 10; - if (nv_ro08(bios, mdata) & 0x01) + clock = nvbios_rd16(bios, mdata + 2) * 10; + if (nvbios_rd08(bios, mdata) & 0x01) clock *= 2; init_prog_pll(init, 0x680504, clock); @@ -1571,9 +1616,9 @@ static void init_io(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 mask = nv_ro16(bios, init->offset + 3); - u8 data = nv_ro16(bios, init->offset + 4); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 mask = nvbios_rd16(bios, init->offset + 3); + u8 data = nvbios_rd16(bios, init->offset + 4); u8 value; trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data); @@ -1583,7 +1628,7 @@ init_io(struct nvbios_init *init) * needed some day.. it's almost certainly wrong, but, it also * somehow makes things work... */ - if (nv_device(init->bios)->card_type >= NV_50 && + if (bios->subdev.device->card_type >= NV_50 && port == 0x03c3 && data == 0x01) { init_mask(init, 0x614100, 0xf0800000, 0x00800000); init_mask(init, 0x00e18c, 0x00020000, 0x00020000); @@ -1611,7 +1656,7 @@ static void init_sub(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 1); u16 addr, save; trace("SUB\t0x%02x\n", index); @@ -1638,8 +1683,8 @@ static void init_ram_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 mask = nv_ro08(bios, init->offset + 1); - u8 value = nv_ro08(bios, init->offset + 2); + u8 mask = nvbios_rd08(bios, init->offset + 1); + u8 value = nvbios_rd08(bios, init->offset + 2); trace("RAM_CONDITION\t" "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value); @@ -1657,9 +1702,9 @@ static void init_nv_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); - u32 data = nv_ro32(bios, init->offset + 9); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); + u32 data = nvbios_rd32(bios, init->offset + 9); trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data); init->offset += 13; @@ -1675,15 +1720,15 @@ static void init_macro(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 macro = nv_ro08(bios, init->offset + 1); + u8 macro = nvbios_rd08(bios, init->offset + 1); u16 table; trace("MACRO\t0x%02x\n", macro); table = init_macro_table(init); if (table) { - u32 addr = nv_ro32(bios, table + (macro * 8) + 0); - u32 data = nv_ro32(bios, table + (macro * 8) + 4); + u32 addr = nvbios_rd32(bios, table + (macro * 8) + 0); + u32 data = nvbios_rd32(bios, table + (macro * 8) + 4); trace("\t\tR[0x%06x] = 0x%08x\n", addr, data); init_wr32(init, addr, data); } @@ -1704,6 +1749,24 @@ init_resume(struct nvbios_init *init) } /** + * INIT_STRAP_CONDITION - opcode 0x73 + * + */ +static void +init_strap_condition(struct nvbios_init *init) +{ + struct nvkm_bios *bios = init->bios; + u32 mask = nvbios_rd32(bios, init->offset + 1); + u32 value = nvbios_rd32(bios, init->offset + 5); + + trace("STRAP_CONDITION\t(R[0x101000] & 0x%08x) == 0x%08x\n", mask, value); + init->offset += 9; + + if ((init_rd32(init, 0x101000) & mask) != value) + init_exec_set(init, false); +} + +/** * INIT_TIME - opcode 0x74 * */ @@ -1711,7 +1774,7 @@ static void init_time(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 usec = nv_ro16(bios, init->offset + 1); + u16 usec = nvbios_rd16(bios, init->offset + 1); trace("TIME\t0x%04x\n", usec); init->offset += 3; @@ -1732,7 +1795,7 @@ static void init_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); + u8 cond = nvbios_rd08(bios, init->offset + 1); trace("CONDITION\t0x%02x\n", cond); init->offset += 2; @@ -1749,7 +1812,7 @@ static void init_io_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); + u8 cond = nvbios_rd08(bios, init->offset + 1); trace("IO_CONDITION\t0x%02x\n", cond); init->offset += 2; @@ -1759,6 +1822,23 @@ init_io_condition(struct nvbios_init *init) } /** + * INIT_ZM_REG16 - opcode 0x77 + * + */ +static void +init_zm_reg16(struct nvbios_init *init) +{ + struct nvkm_bios *bios = init->bios; + u32 addr = nvbios_rd32(bios, init->offset + 1); + u16 data = nvbios_rd16(bios, init->offset + 5); + + trace("ZM_REG\tR[0x%06x] = 0x%04x\n", addr, data); + init->offset += 7; + + init_wr32(init, addr, data); +} + +/** * INIT_INDEX_IO - opcode 0x78 * */ @@ -1766,10 +1846,10 @@ static void init_index_io(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro16(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 data = nv_ro08(bios, init->offset + 5); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd16(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 data = nvbios_rd08(bios, init->offset + 5); u8 value; trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n", @@ -1788,8 +1868,8 @@ static void init_pll(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 freq = nv_ro16(bios, init->offset + 5) * 10; + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 freq = nvbios_rd16(bios, init->offset + 5) * 10; trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq); init->offset += 7; @@ -1805,8 +1885,8 @@ static void init_zm_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u32 data = nv_ro32(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u32 data = nvbios_rd32(bios, init->offset + 5); trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data); init->offset += 9; @@ -1825,7 +1905,7 @@ static void init_ram_restrict_pll(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 type = nv_ro08(bios, init->offset + 1); + u8 type = nvbios_rd08(bios, init->offset + 1); u8 count = init_ram_restrict_group_count(init); u8 strap = init_ram_restrict(init); u8 cconf; @@ -1834,7 +1914,7 @@ init_ram_restrict_pll(struct nvbios_init *init) init->offset += 2; for (cconf = 0; cconf < count; cconf++) { - u32 freq = nv_ro32(bios, init->offset); + u32 freq = nvbios_rd32(bios, init->offset); if (cconf == strap) { trace("%dkHz *\n", freq); @@ -1854,13 +1934,13 @@ init_ram_restrict_pll(struct nvbios_init *init) static void init_gpio(struct nvbios_init *init) { - struct nvkm_gpio *gpio = nvkm_gpio(init->bios); + struct nvkm_gpio *gpio = init->bios->subdev.device->gpio; trace("GPIO\n"); init->offset += 1; - if (init_exec(init) && gpio && gpio->reset) - gpio->reset(gpio, DCB_GPIO_UNUSED); + if (init_exec(init)) + nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED); } /** @@ -1871,9 +1951,9 @@ static void init_ram_restrict_zm_reg_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 incr = nv_ro08(bios, init->offset + 5); - u8 num = nv_ro08(bios, init->offset + 6); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 incr = nvbios_rd08(bios, init->offset + 5); + u8 num = nvbios_rd08(bios, init->offset + 6); u8 count = init_ram_restrict_group_count(init); u8 index = init_ram_restrict(init); u8 i, j; @@ -1885,7 +1965,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init) for (i = 0; i < num; i++) { trace("\tR[0x%06x] = {\n", addr); for (j = 0; j < count; j++) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); if (j == index) { trace("\t\t0x%08x *\n", data); @@ -1909,8 +1989,8 @@ static void init_copy_zm_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 sreg = nv_ro32(bios, init->offset + 1); - u32 dreg = nv_ro32(bios, init->offset + 5); + u32 sreg = nvbios_rd32(bios, init->offset + 1); + u32 dreg = nvbios_rd32(bios, init->offset + 5); trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg); init->offset += 9; @@ -1926,14 +2006,14 @@ static void init_zm_reg_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr); init->offset += 6; while (count--) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); trace("\t0x%08x\n", data); init_wr32(init, addr, data); init->offset += 4; @@ -1948,13 +2028,13 @@ static void init_xlat(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 saddr = nv_ro32(bios, init->offset + 1); - u8 sshift = nv_ro08(bios, init->offset + 5); - u8 smask = nv_ro08(bios, init->offset + 6); - u8 index = nv_ro08(bios, init->offset + 7); - u32 daddr = nv_ro32(bios, init->offset + 8); - u32 dmask = nv_ro32(bios, init->offset + 12); - u8 shift = nv_ro08(bios, init->offset + 16); + u32 saddr = nvbios_rd32(bios, init->offset + 1); + u8 sshift = nvbios_rd08(bios, init->offset + 5); + u8 smask = nvbios_rd08(bios, init->offset + 6); + u8 index = nvbios_rd08(bios, init->offset + 7); + u32 daddr = nvbios_rd32(bios, init->offset + 8); + u32 dmask = nvbios_rd32(bios, init->offset + 12); + u8 shift = nvbios_rd08(bios, init->offset + 16); u32 data; trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= " @@ -1976,9 +2056,9 @@ static void init_zm_mask_add(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); - u32 add = nv_ro32(bios, init->offset + 9); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); + u32 add = nvbios_rd32(bios, init->offset + 9); u32 data; trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add); @@ -1997,15 +2077,15 @@ static void init_auxch(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count); init->offset += 6; while (count--) { - u8 mask = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 mask = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data); mask = init_rdauxr(init, addr) & mask; init_wrauxr(init, addr, mask | data); @@ -2021,14 +2101,14 @@ static void init_zm_auxch(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count); init->offset += 6; while (count--) { - u8 data = nv_ro08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 0); trace("\tAUX[0x%08x] = 0x%02x\n", addr, data); init_wrauxr(init, addr, data); init->offset += 1; @@ -2043,21 +2123,21 @@ static void init_i2c_long_if(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 reglo = nv_ro08(bios, init->offset + 3); - u8 reghi = nv_ro08(bios, init->offset + 4); - u8 mask = nv_ro08(bios, init->offset + 5); - u8 data = nv_ro08(bios, init->offset + 6); - struct nvkm_i2c_port *port; + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 reglo = nvbios_rd08(bios, init->offset + 3); + u8 reghi = nvbios_rd08(bios, init->offset + 4); + u8 mask = nvbios_rd08(bios, init->offset + 5); + u8 data = nvbios_rd08(bios, init->offset + 6); + struct i2c_adapter *adap; trace("I2C_LONG_IF\t" "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n", index, addr, reglo, reghi, mask, data); init->offset += 7; - port = init_i2c(init, index); - if (port) { + adap = init_i2c(init, index); + if (adap) { u8 i[2] = { reghi, reglo }; u8 o[1] = {}; struct i2c_msg msg[] = { @@ -2066,7 +2146,7 @@ init_i2c_long_if(struct nvbios_init *init) }; int ret; - ret = i2c_transfer(&port->adapter, msg, 2); + ret = i2c_transfer(adap, msg, 2); if (ret == 2 && ((o[0] & mask) == data)) return; } @@ -2082,9 +2162,9 @@ static void init_gpio_ne(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - struct nvkm_gpio *gpio = nvkm_gpio(bios); + struct nvkm_gpio *gpio = bios->subdev.device->gpio; struct dcb_gpio_func func; - u8 count = nv_ro08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 1); u8 idx = 0, ver, len; u16 data, i; @@ -2092,21 +2172,21 @@ init_gpio_ne(struct nvbios_init *init) init->offset += 2; for (i = init->offset; i < init->offset + count; i++) - cont("0x%02x ", nv_ro08(bios, i)); + cont("0x%02x ", nvbios_rd08(bios, i)); cont("\n"); while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) { if (func.func != DCB_GPIO_UNUSED) { for (i = init->offset; i < init->offset + count; i++) { - if (func.func == nv_ro08(bios, i)) + if (func.func == nvbios_rd08(bios, i)) break; } trace("\tFUNC[0x%02x]", func.func); if (i == (init->offset + count)) { cont(" *"); - if (init_exec(init) && gpio && gpio->reset) - gpio->reset(gpio, func.func); + if (init_exec(init)) + nvkm_gpio_reset(gpio, func.func); } cont("\n"); } @@ -2145,6 +2225,8 @@ static struct nvbios_init_opcode { [0x56] = { init_condition_time }, [0x57] = { init_ltime }, [0x58] = { init_zm_reg_sequence }, + [0x59] = { init_pll_indirect }, + [0x5a] = { init_zm_reg_indirect }, [0x5b] = { init_sub_direct }, [0x5c] = { init_jump }, [0x5e] = { init_i2c_if }, @@ -2162,9 +2244,11 @@ static struct nvbios_init_opcode { [0x6f] = { init_macro }, [0x71] = { init_done }, [0x72] = { init_resume }, + [0x73] = { init_strap_condition }, [0x74] = { init_time }, [0x75] = { init_condition }, [0x76] = { init_io_condition }, + [0x77] = { init_zm_reg16 }, [0x78] = { init_index_io }, [0x79] = { init_pll }, [0x7a] = { init_zm_reg }, @@ -2192,7 +2276,7 @@ nvbios_exec(struct nvbios_init *init) { init->nested++; while (init->offset) { - u8 opcode = nv_ro08(init->bios, init->offset); + u8 opcode = nvbios_rd08(init->bios, init->offset); if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) { error("unknown opcode 0x%02x\n", opcode); return -EINVAL; @@ -2207,13 +2291,13 @@ nvbios_exec(struct nvbios_init *init) int nvbios_init(struct nvkm_subdev *subdev, bool execute) { - struct nvkm_bios *bios = nvkm_bios(subdev); + struct nvkm_bios *bios = subdev->device->bios; int ret = 0; int i = -1; u16 data; if (execute) - nv_info(bios, "running init tables\n"); + nvkm_debug(subdev, "running init tables\n"); while (!ret && (data = (init_script(bios, ++i)))) { struct nvbios_init init = { .subdev = subdev, diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c index c4087df4f..3ddf0939d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c @@ -28,17 +28,18 @@ u16 mxm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr) { + struct nvkm_subdev *subdev = &bios->subdev; struct bit_entry x; if (bit_entry(bios, 'x', &x)) { - nv_debug(bios, "BIT 'x' table not present\n"); + nvkm_debug(subdev, "BIT 'x' table not present\n"); return 0x0000; } *ver = x.version; *hdr = x.length; if (*ver != 1 || *hdr < 3) { - nv_warn(bios, "BIT 'x' table %d/%d unknown\n", *ver, *hdr); + nvkm_warn(subdev, "BIT 'x' table %d/%d unknown\n", *ver, *hdr); return 0x0000; } @@ -73,23 +74,24 @@ static u8 g98_sor_map[16] = { u8 mxm_sor_map(struct nvkm_bios *bios, u8 conn) { + struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 6) { - u16 map = nv_ro16(bios, mxm + 4); + u16 map = nvbios_rd16(bios, mxm + 4); if (map) { - ver = nv_ro08(bios, map); + ver = nvbios_rd08(bios, map); if (ver == 0x10) { - if (conn < nv_ro08(bios, map + 3)) { - map += nv_ro08(bios, map + 1); + if (conn < nvbios_rd08(bios, map + 3)) { + map += nvbios_rd08(bios, map + 1); map += conn; - return nv_ro08(bios, map); + return nvbios_rd08(bios, map); } return 0x00; } - nv_warn(bios, "unknown sor map v%02x\n", ver); + nvkm_warn(subdev, "unknown sor map v%02x\n", ver); } } @@ -102,30 +104,31 @@ mxm_sor_map(struct nvkm_bios *bios, u8 conn) if (bios->version.chip == 0x98) return g98_sor_map[conn]; - nv_warn(bios, "missing sor map\n"); + nvkm_warn(subdev, "missing sor map\n"); return 0x00; } u8 mxm_ddc_map(struct nvkm_bios *bios, u8 port) { + struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 8) { - u16 map = nv_ro16(bios, mxm + 6); + u16 map = nvbios_rd16(bios, mxm + 6); if (map) { - ver = nv_ro08(bios, map); + ver = nvbios_rd08(bios, map); if (ver == 0x10) { - if (port < nv_ro08(bios, map + 3)) { - map += nv_ro08(bios, map + 1); + if (port < nvbios_rd08(bios, map + 3)) { + map += nvbios_rd08(bios, map + 1); map += port; - return nv_ro08(bios, map); + return nvbios_rd08(bios, map); } return 0x00; } - nv_warn(bios, "unknown ddc map v%02x\n", ver); + nvkm_warn(subdev, "unknown ddc map v%02x\n", ver); } } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c index fd7dd718b..955df2963 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c @@ -32,12 +32,13 @@ nvbios_npdeTe(struct nvkm_bios *bios, u32 base) u8 ver; u16 hdr; u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir); if (data = (data + hdr + 0x0f) & ~0x0f, data) { - switch (nv_ro32(bios, data + 0x00)) { + switch (nvbios_rd32(bios, data + 0x00)) { case 0x4544504e: /* NPDE */ break; default: - nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n", - data, nv_ro32(bios, data + 0x00)); + nvkm_debug(&bios->subdev, + "%08x: NPDE signature (%08x) unknown\n", + data, nvbios_rd32(bios, data + 0x00)); data = 0; break; } @@ -51,8 +52,8 @@ nvbios_npdeTp(struct nvkm_bios *bios, u32 base, struct nvbios_npdeT *info) u32 data = nvbios_npdeTe(bios, base); memset(info, 0x00, sizeof(*info)); if (data) { - info->image_size = nv_ro16(bios, data + 0x08) * 512; - info->last = nv_ro08(bios, data + 0x0a) & 0x80; + info->image_size = nvbios_rd16(bios, data + 0x08) * 512; + info->last = nvbios_rd08(bios, data + 0x0a) & 0x80; } return data; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c index df5978753..67cb3aeb2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c @@ -27,19 +27,20 @@ u32 nvbios_pcirTe(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr) { - u32 data = nv_ro16(bios, base + 0x18); + u32 data = nvbios_rd16(bios, base + 0x18); if (data) { data += base; - switch (nv_ro32(bios, data + 0x00)) { + switch (nvbios_rd32(bios, data + 0x00)) { case 0x52494350: /* PCIR */ case 0x53494752: /* RGIS */ case 0x5344504e: /* NPDS */ - *hdr = nv_ro16(bios, data + 0x0a); - *ver = nv_ro08(bios, data + 0x0c); + *hdr = nvbios_rd16(bios, data + 0x0a); + *ver = nvbios_rd08(bios, data + 0x0c); break; default: - nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n", - data, nv_ro32(bios, data + 0x00)); + nvkm_debug(&bios->subdev, + "%08x: PCIR signature (%08x) unknown\n", + data, nvbios_rd32(bios, data + 0x00)); data = 0; break; } @@ -54,15 +55,15 @@ nvbios_pcirTp(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr, u32 data = nvbios_pcirTe(bios, base, ver, hdr); memset(info, 0x00, sizeof(*info)); if (data) { - info->vendor_id = nv_ro16(bios, data + 0x04); - info->device_id = nv_ro16(bios, data + 0x06); - info->class_code[0] = nv_ro08(bios, data + 0x0d); - info->class_code[1] = nv_ro08(bios, data + 0x0e); - info->class_code[2] = nv_ro08(bios, data + 0x0f); - info->image_size = nv_ro16(bios, data + 0x10) * 512; - info->image_rev = nv_ro16(bios, data + 0x12); - info->image_type = nv_ro08(bios, data + 0x14); - info->last = nv_ro08(bios, data + 0x15) & 0x80; + info->vendor_id = nvbios_rd16(bios, data + 0x04); + info->device_id = nvbios_rd16(bios, data + 0x06); + info->class_code[0] = nvbios_rd08(bios, data + 0x0d); + info->class_code[1] = nvbios_rd08(bios, data + 0x0e); + info->class_code[2] = nvbios_rd08(bios, data + 0x0f); + info->image_size = nvbios_rd16(bios, data + 0x10) * 512; + info->image_rev = nvbios_rd16(bios, data + 0x12); + info->image_type = nvbios_rd08(bios, data + 0x14); + info->last = nvbios_rd08(bios, data + 0x15) & 0x80; } return data; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c index 382ae9cdb..aa7e33b42 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c @@ -25,8 +25,6 @@ #include <subdev/bios/bit.h> #include <subdev/bios/perf.h> -#include <core/device.h> - u16 nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) @@ -36,22 +34,22 @@ nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version <= 2) { - perf = nv_ro16(bios, bit_P.offset + 0); + perf = nvbios_rd16(bios, bit_P.offset + 0); if (perf) { - *ver = nv_ro08(bios, perf + 0); - *hdr = nv_ro08(bios, perf + 1); + *ver = nvbios_rd08(bios, perf + 0); + *hdr = nvbios_rd08(bios, perf + 1); if (*ver >= 0x40 && *ver < 0x41) { - *cnt = nv_ro08(bios, perf + 5); - *len = nv_ro08(bios, perf + 2); - *snr = nv_ro08(bios, perf + 4); - *ssz = nv_ro08(bios, perf + 3); + *cnt = nvbios_rd08(bios, perf + 5); + *len = nvbios_rd08(bios, perf + 2); + *snr = nvbios_rd08(bios, perf + 4); + *ssz = nvbios_rd08(bios, perf + 3); return perf; } else if (*ver >= 0x20 && *ver < 0x40) { - *cnt = nv_ro08(bios, perf + 2); - *len = nv_ro08(bios, perf + 3); - *snr = nv_ro08(bios, perf + 4); - *ssz = nv_ro08(bios, perf + 5); + *cnt = nvbios_rd08(bios, perf + 2); + *len = nvbios_rd08(bios, perf + 3); + *snr = nvbios_rd08(bios, perf + 4); + *ssz = nvbios_rd08(bios, perf + 5); return perf; } } @@ -59,13 +57,13 @@ nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, } if (bios->bmp_offset) { - if (nv_ro08(bios, bios->bmp_offset + 6) >= 0x25) { - perf = nv_ro16(bios, bios->bmp_offset + 0x94); + if (nvbios_rd08(bios, bios->bmp_offset + 6) >= 0x25) { + perf = nvbios_rd16(bios, bios->bmp_offset + 0x94); if (perf) { - *hdr = nv_ro08(bios, perf + 0); - *ver = nv_ro08(bios, perf + 1); - *cnt = nv_ro08(bios, perf + 2); - *len = nv_ro08(bios, perf + 3); + *hdr = nvbios_rd08(bios, perf + 0); + *ver = nvbios_rd08(bios, perf + 1); + *cnt = nvbios_rd08(bios, perf + 2); + *len = nvbios_rd08(bios, perf + 3); *snr = 0; *ssz = 0; return perf; @@ -98,55 +96,55 @@ nvbios_perfEp(struct nvkm_bios *bios, int idx, { u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); - info->pstate = nv_ro08(bios, perf + 0x00); + info->pstate = nvbios_rd08(bios, perf + 0x00); switch (!!perf * *ver) { case 0x12: case 0x13: case 0x14: - info->core = nv_ro32(bios, perf + 0x01) * 10; - info->memory = nv_ro32(bios, perf + 0x05) * 20; - info->fanspeed = nv_ro08(bios, perf + 0x37); + info->core = nvbios_rd32(bios, perf + 0x01) * 10; + info->memory = nvbios_rd32(bios, perf + 0x05) * 20; + info->fanspeed = nvbios_rd08(bios, perf + 0x37); if (*hdr > 0x38) - info->voltage = nv_ro08(bios, perf + 0x38); + info->voltage = nvbios_rd08(bios, perf + 0x38); break; case 0x21: case 0x23: case 0x24: - info->fanspeed = nv_ro08(bios, perf + 0x04); - info->voltage = nv_ro08(bios, perf + 0x05); - info->shader = nv_ro16(bios, perf + 0x06) * 1000; + info->fanspeed = nvbios_rd08(bios, perf + 0x04); + info->voltage = nvbios_rd08(bios, perf + 0x05); + info->shader = nvbios_rd16(bios, perf + 0x06) * 1000; info->core = info->shader + (signed char) - nv_ro08(bios, perf + 0x08) * 1000; - switch (nv_device(bios)->chipset) { + nvbios_rd08(bios, perf + 0x08) * 1000; + switch (bios->subdev.device->chipset) { case 0x49: case 0x4b: - info->memory = nv_ro16(bios, perf + 0x0b) * 1000; + info->memory = nvbios_rd16(bios, perf + 0x0b) * 1000; break; default: - info->memory = nv_ro16(bios, perf + 0x0b) * 2000; + info->memory = nvbios_rd16(bios, perf + 0x0b) * 2000; break; } break; case 0x25: - info->fanspeed = nv_ro08(bios, perf + 0x04); - info->voltage = nv_ro08(bios, perf + 0x05); - info->core = nv_ro16(bios, perf + 0x06) * 1000; - info->shader = nv_ro16(bios, perf + 0x0a) * 1000; - info->memory = nv_ro16(bios, perf + 0x0c) * 1000; + info->fanspeed = nvbios_rd08(bios, perf + 0x04); + info->voltage = nvbios_rd08(bios, perf + 0x05); + info->core = nvbios_rd16(bios, perf + 0x06) * 1000; + info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000; + info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000; break; case 0x30: - info->script = nv_ro16(bios, perf + 0x02); + info->script = nvbios_rd16(bios, perf + 0x02); case 0x35: - info->fanspeed = nv_ro08(bios, perf + 0x06); - info->voltage = nv_ro08(bios, perf + 0x07); - info->core = nv_ro16(bios, perf + 0x08) * 1000; - info->shader = nv_ro16(bios, perf + 0x0a) * 1000; - info->memory = nv_ro16(bios, perf + 0x0c) * 1000; - info->vdec = nv_ro16(bios, perf + 0x10) * 1000; - info->disp = nv_ro16(bios, perf + 0x14) * 1000; + info->fanspeed = nvbios_rd08(bios, perf + 0x06); + info->voltage = nvbios_rd08(bios, perf + 0x07); + info->core = nvbios_rd16(bios, perf + 0x08) * 1000; + info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000; + info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000; + info->vdec = nvbios_rd16(bios, perf + 0x10) * 1000; + info->disp = nvbios_rd16(bios, perf + 0x14) * 1000; break; case 0x40: - info->voltage = nv_ro08(bios, perf + 0x02); + info->voltage = nvbios_rd08(bios, perf + 0x02); break; default: return 0x0000; @@ -175,7 +173,7 @@ nvbios_perfSp(struct nvkm_bios *bios, u32 perfE, int idx, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x40: - info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000; + info->v40.freq = (nvbios_rd16(bios, data + 0x00) & 0x3fff) * 1000; break; default: break; @@ -193,7 +191,7 @@ nvbios_perf_fan_parse(struct nvkm_bios *bios, return -ENODEV; if (ver >= 0x20 && ver < 0x40 && hdr > 6) - fan->pwm_divisor = nv_ro16(bios, perf + 6); + fan->pwm_divisor = nvbios_rd16(bios, perf + 6); else fan->pwm_divisor = 0; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index ebd402e19..125ec2ed6 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -27,7 +27,6 @@ #include <subdev/bios/pll.h> #include <subdev/vga.h> -#include <core/device.h> struct pll_mapping { u8 type; @@ -84,20 +83,20 @@ pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) struct bit_entry bit_C; if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) { - u16 data = nv_ro16(bios, bit_C.offset + 8); + u16 data = nvbios_rd16(bios, bit_C.offset + 8); if (data) { - *ver = nv_ro08(bios, data + 0); - *hdr = nv_ro08(bios, data + 1); - *len = nv_ro08(bios, data + 2); - *cnt = nv_ro08(bios, data + 3); + *ver = nvbios_rd08(bios, data + 0); + *hdr = nvbios_rd08(bios, data + 1); + *len = nvbios_rd08(bios, data + 2); + *cnt = nvbios_rd08(bios, data + 3); return data; } } if (bmp_version(bios) >= 0x0524) { - u16 data = nv_ro16(bios, bios->bmp_offset + 142); + u16 data = nvbios_rd16(bios, bios->bmp_offset + 142); if (data) { - *ver = nv_ro08(bios, data + 0); + *ver = nvbios_rd08(bios, data + 0); *hdr = 1; *cnt = 1; *len = 0x18; @@ -112,7 +111,8 @@ pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) static struct pll_mapping * pll_map(struct nvkm_bios *bios) { - switch (nv_device(bios)->card_type) { + struct nvkm_device *device = bios->subdev.device; + switch (device->card_type) { case NV_04: case NV_10: case NV_11: @@ -123,12 +123,12 @@ pll_map(struct nvkm_bios *bios) case NV_40: return nv40_pll_mapping; case NV_50: - if (nv_device(bios)->chipset == 0x50) + if (device->chipset == 0x50) return nv50_pll_mapping; else - if (nv_device(bios)->chipset < 0xa3 || - nv_device(bios)->chipset == 0xaa || - nv_device(bios)->chipset == 0xac) + if (device->chipset < 0xa3 || + device->chipset == 0xaa || + device->chipset == 0xac) return g84_pll_mapping; default: return NULL; @@ -146,8 +146,8 @@ pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) if (data && *ver >= 0x30) { data += hdr; while (cnt--) { - if (nv_ro32(bios, data + 3) == reg) { - *type = nv_ro08(bios, data + 0); + if (nvbios_rd32(bios, data + 3) == reg) { + *type = nvbios_rd08(bios, data + 0); return data; } data += *len; @@ -161,7 +161,7 @@ pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) u16 addr = (data += hdr); *type = map->type; while (cnt--) { - if (nv_ro32(bios, data) == map->reg) + if (nvbios_rd32(bios, data) == map->reg) return data; data += *len; } @@ -188,8 +188,8 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) if (data && *ver >= 0x30) { data += hdr; while (cnt--) { - if (nv_ro08(bios, data + 0) == type) { - *reg = nv_ro32(bios, data + 3); + if (nvbios_rd08(bios, data + 0) == type) { + *reg = nvbios_rd32(bios, data + 3); return data; } data += *len; @@ -203,7 +203,7 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) u16 addr = (data += hdr); *reg = map->reg; while (cnt--) { - if (nv_ro32(bios, data) == map->reg) + if (nvbios_rd32(bios, data) == map->reg) return data; data += *len; } @@ -222,6 +222,8 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) int nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) { + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; u8 ver, len; u32 reg = type; u16 data; @@ -245,12 +247,12 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) break; case 0x10: case 0x11: - info->vco1.min_freq = nv_ro32(bios, data + 0); - info->vco1.max_freq = nv_ro32(bios, data + 4); - info->vco2.min_freq = nv_ro32(bios, data + 8); - info->vco2.max_freq = nv_ro32(bios, data + 12); - info->vco1.min_inputfreq = nv_ro32(bios, data + 16); - info->vco2.min_inputfreq = nv_ro32(bios, data + 20); + info->vco1.min_freq = nvbios_rd32(bios, data + 0); + info->vco1.max_freq = nvbios_rd32(bios, data + 4); + info->vco2.min_freq = nvbios_rd32(bios, data + 8); + info->vco2.max_freq = nvbios_rd32(bios, data + 12); + info->vco1.min_inputfreq = nvbios_rd32(bios, data + 16); + info->vco2.min_inputfreq = nvbios_rd32(bios, data + 20); info->vco1.max_inputfreq = INT_MAX; info->vco2.max_inputfreq = INT_MAX; @@ -291,82 +293,82 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) break; case 0x20: case 0x21: - info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000; - info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000; - info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000; - info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000; - info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000; - info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000; - info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000; - info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000; - info->vco1.min_n = nv_ro08(bios, data + 20); - info->vco1.max_n = nv_ro08(bios, data + 21); - info->vco1.min_m = nv_ro08(bios, data + 22); - info->vco1.max_m = nv_ro08(bios, data + 23); - info->vco2.min_n = nv_ro08(bios, data + 24); - info->vco2.max_n = nv_ro08(bios, data + 25); - info->vco2.min_m = nv_ro08(bios, data + 26); - info->vco2.max_m = nv_ro08(bios, data + 27); - - info->max_p = nv_ro08(bios, data + 29); + info->vco1.min_freq = nvbios_rd16(bios, data + 4) * 1000; + info->vco1.max_freq = nvbios_rd16(bios, data + 6) * 1000; + info->vco2.min_freq = nvbios_rd16(bios, data + 8) * 1000; + info->vco2.max_freq = nvbios_rd16(bios, data + 10) * 1000; + info->vco1.min_inputfreq = nvbios_rd16(bios, data + 12) * 1000; + info->vco2.min_inputfreq = nvbios_rd16(bios, data + 14) * 1000; + info->vco1.max_inputfreq = nvbios_rd16(bios, data + 16) * 1000; + info->vco2.max_inputfreq = nvbios_rd16(bios, data + 18) * 1000; + info->vco1.min_n = nvbios_rd08(bios, data + 20); + info->vco1.max_n = nvbios_rd08(bios, data + 21); + info->vco1.min_m = nvbios_rd08(bios, data + 22); + info->vco1.max_m = nvbios_rd08(bios, data + 23); + info->vco2.min_n = nvbios_rd08(bios, data + 24); + info->vco2.max_n = nvbios_rd08(bios, data + 25); + info->vco2.min_m = nvbios_rd08(bios, data + 26); + info->vco2.max_m = nvbios_rd08(bios, data + 27); + + info->max_p = nvbios_rd08(bios, data + 29); info->max_p_usable = info->max_p; if (bios->version.chip < 0x60) info->max_p_usable = 0x6; - info->bias_p = nv_ro08(bios, data + 30); + info->bias_p = nvbios_rd08(bios, data + 30); if (len > 0x22) - info->refclk = nv_ro32(bios, data + 31); + info->refclk = nvbios_rd32(bios, data + 31); break; case 0x30: - data = nv_ro16(bios, data + 1); - - info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; - info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; - info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000; - info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000; - info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000; - info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000; - info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000; - info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000; - info->vco1.min_n = nv_ro08(bios, data + 16); - info->vco1.max_n = nv_ro08(bios, data + 17); - info->vco1.min_m = nv_ro08(bios, data + 18); - info->vco1.max_m = nv_ro08(bios, data + 19); - info->vco2.min_n = nv_ro08(bios, data + 20); - info->vco2.max_n = nv_ro08(bios, data + 21); - info->vco2.min_m = nv_ro08(bios, data + 22); - info->vco2.max_m = nv_ro08(bios, data + 23); - info->max_p_usable = info->max_p = nv_ro08(bios, data + 25); - info->bias_p = nv_ro08(bios, data + 27); - info->refclk = nv_ro32(bios, data + 28); + data = nvbios_rd16(bios, data + 1); + + info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; + info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; + info->vco2.min_freq = nvbios_rd16(bios, data + 4) * 1000; + info->vco2.max_freq = nvbios_rd16(bios, data + 6) * 1000; + info->vco1.min_inputfreq = nvbios_rd16(bios, data + 8) * 1000; + info->vco2.min_inputfreq = nvbios_rd16(bios, data + 10) * 1000; + info->vco1.max_inputfreq = nvbios_rd16(bios, data + 12) * 1000; + info->vco2.max_inputfreq = nvbios_rd16(bios, data + 14) * 1000; + info->vco1.min_n = nvbios_rd08(bios, data + 16); + info->vco1.max_n = nvbios_rd08(bios, data + 17); + info->vco1.min_m = nvbios_rd08(bios, data + 18); + info->vco1.max_m = nvbios_rd08(bios, data + 19); + info->vco2.min_n = nvbios_rd08(bios, data + 20); + info->vco2.max_n = nvbios_rd08(bios, data + 21); + info->vco2.min_m = nvbios_rd08(bios, data + 22); + info->vco2.max_m = nvbios_rd08(bios, data + 23); + info->max_p_usable = info->max_p = nvbios_rd08(bios, data + 25); + info->bias_p = nvbios_rd08(bios, data + 27); + info->refclk = nvbios_rd32(bios, data + 28); break; case 0x40: - info->refclk = nv_ro16(bios, data + 9) * 1000; - data = nv_ro16(bios, data + 1); - - info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; - info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; - info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000; - info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000; - info->vco1.min_m = nv_ro08(bios, data + 8); - info->vco1.max_m = nv_ro08(bios, data + 9); - info->vco1.min_n = nv_ro08(bios, data + 10); - info->vco1.max_n = nv_ro08(bios, data + 11); - info->min_p = nv_ro08(bios, data + 12); - info->max_p = nv_ro08(bios, data + 13); + info->refclk = nvbios_rd16(bios, data + 9) * 1000; + data = nvbios_rd16(bios, data + 1); + + info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; + info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; + info->vco1.min_inputfreq = nvbios_rd16(bios, data + 4) * 1000; + info->vco1.max_inputfreq = nvbios_rd16(bios, data + 6) * 1000; + info->vco1.min_m = nvbios_rd08(bios, data + 8); + info->vco1.max_m = nvbios_rd08(bios, data + 9); + info->vco1.min_n = nvbios_rd08(bios, data + 10); + info->vco1.max_n = nvbios_rd08(bios, data + 11); + info->min_p = nvbios_rd08(bios, data + 12); + info->max_p = nvbios_rd08(bios, data + 13); break; default: - nv_error(bios, "unknown pll limits version 0x%02x\n", ver); + nvkm_error(subdev, "unknown pll limits version 0x%02x\n", ver); return -EINVAL; } if (!info->refclk) { - info->refclk = nv_device(bios)->crystal; + info->refclk = device->crystal; if (bios->version.chip == 0x51) { - u32 sel_clk = nv_rd32(bios, 0x680524); + u32 sel_clk = nvkm_rd32(device, 0x680524); if ((info->reg == 0x680508 && sel_clk & 0x20) || (info->reg == 0x680520 && sel_clk & 0x80)) { - if (nv_rdvgac(bios, 0, 0x27) < 0xa3) + if (nvkm_rdvgac(device, 0, 0x27) < 0xa3) info->refclk = 200000; else info->refclk = 25000; @@ -380,8 +382,8 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) * with an empty limit table (seen on nv18) */ if (!info->vco1.max_freq) { - info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67); - info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71); + info->vco1.max_freq = nvbios_rd32(bios, bios->bmp_offset + 67); + info->vco1.min_freq = nvbios_rd32(bios, bios->bmp_offset + 71); if (bmp_version(bios) < 0x0506) { info->vco1.max_freq = 256000; info->vco1.min_freq = 128000; @@ -393,7 +395,7 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) info->vco1.max_n = 0xff; info->vco1.min_m = 0x1; - if (nv_device(bios)->crystal == 13500) { + if (device->crystal == 13500) { /* nv05 does this, nv11 doesn't, nv10 unknown */ if (bios->version.chip < 0x11) info->vco1.min_m = 0x7; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c index 20c5ce0cd..c268e5afe 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c @@ -49,12 +49,12 @@ nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'p', &bit_p)) { if (bit_p.version == 2 && bit_p.length >= 4) - data = nv_ro32(bios, bit_p.offset + 0x00); + data = nvbios_rd32(bios, bit_p.offset + 0x00); if ((data = weirdo_pointer(bios, data))) { - *ver = nv_ro08(bios, data + 0x00); /* maybe? */ - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); + *ver = nvbios_rd08(bios, data + 0x00); /* maybe? */ + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); } } @@ -62,19 +62,6 @@ nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } u32 -nvbios_pmuTp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, - struct nvbios_pmuT *info) -{ - u32 data = nvbios_pmuTe(bios, ver, hdr, cnt, len); - memset(info, 0x00, sizeof(*info)); - switch (!!data * *ver) { - default: - break; - } - return data; -} - -u32 nvbios_pmuEe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr) { u8 cnt, len; @@ -95,8 +82,8 @@ nvbios_pmuEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { default: - info->type = nv_ro08(bios, data + 0x00); - info->data = nv_ro32(bios, data + 0x02); + info->type = nvbios_rd08(bios, data + 0x00); + info->data = nvbios_rd32(bios, data + 0x02); break; } return data; @@ -112,21 +99,21 @@ nvbios_pmuRm(struct nvkm_bios *bios, u8 type, struct nvbios_pmuR *info) while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) { if ( pmuE.type == type && (data = weirdo_pointer(bios, pmuE.data))) { - info->init_addr_pmu = nv_ro32(bios, data + 0x08); - info->args_addr_pmu = nv_ro32(bios, data + 0x0c); + info->init_addr_pmu = nvbios_rd32(bios, data + 0x08); + info->args_addr_pmu = nvbios_rd32(bios, data + 0x0c); info->boot_addr = data + 0x30; - info->boot_addr_pmu = nv_ro32(bios, data + 0x10) + - nv_ro32(bios, data + 0x18); - info->boot_size = nv_ro32(bios, data + 0x1c) - - nv_ro32(bios, data + 0x18); + info->boot_addr_pmu = nvbios_rd32(bios, data + 0x10) + + nvbios_rd32(bios, data + 0x18); + info->boot_size = nvbios_rd32(bios, data + 0x1c) - + nvbios_rd32(bios, data + 0x18); info->code_addr = info->boot_addr + info->boot_size; info->code_addr_pmu = info->boot_addr_pmu + info->boot_size; - info->code_size = nv_ro32(bios, data + 0x20); + info->code_size = nvbios_rd32(bios, data + 0x20); info->data_addr = data + 0x30 + - nv_ro32(bios, data + 0x24); - info->data_addr_pmu = nv_ro32(bios, data + 0x28); - info->data_size = nv_ro32(bios, data + 0x2c); + nvbios_rd32(bios, data + 0x24); + info->data_addr_pmu = nvbios_rd32(bios, data + 0x28); + info->data_size = nvbios_rd32(bios, data + 0x2c); return true; } } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h index 95e4fa153..212800ecd 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h @@ -1,5 +1,6 @@ #ifndef __NVKM_BIOS_PRIV_H__ #define __NVKM_BIOS_PRIV_H__ +#define nvkm_bios(p) container_of((p), struct nvkm_bios, subdev) #include <subdev/bios.h> struct nvbios_source { @@ -7,7 +8,10 @@ struct nvbios_source { void *(*init)(struct nvkm_bios *, const char *); void (*fini)(void *); u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *); + u32 (*size)(void *); bool rw; + bool ignore_checksum; + bool no_pcir; }; int nvbios_extend(struct nvkm_bios *, u32 length); diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c index a17b22111..d5222af10 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c @@ -29,7 +29,7 @@ static u8 nvbios_ramcfg_strap(struct nvkm_subdev *subdev) { - return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2; + return (nvkm_rd32(subdev->device, 0x101000) & 0x0000003c) >> 2; } u8 @@ -39,9 +39,9 @@ nvbios_ramcfg_count(struct nvkm_bios *bios) if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 1 && bit_M.length >= 5) - return nv_ro08(bios, bit_M.offset + 2); + return nvbios_rd08(bios, bit_M.offset + 2); if (bit_M.version == 2 && bit_M.length >= 3) - return nv_ro08(bios, bit_M.offset + 0); + return nvbios_rd08(bios, bit_M.offset + 0); } return 0x00; @@ -50,7 +50,7 @@ nvbios_ramcfg_count(struct nvkm_bios *bios) u8 nvbios_ramcfg_index(struct nvkm_subdev *subdev) { - struct nvkm_bios *bios = nvkm_bios(subdev); + struct nvkm_bios *bios = subdev->device->bios; u8 strap = nvbios_ramcfg_strap(subdev); u32 xlat = 0x00000000; struct bit_entry bit_M; @@ -59,7 +59,7 @@ nvbios_ramcfg_index(struct nvkm_subdev *subdev) if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 1 && bit_M.length >= 5) - xlat = nv_ro16(bios, bit_M.offset + 3); + xlat = nvbios_rd16(bios, bit_M.offset + 3); if (bit_M.version == 2 && bit_M.length >= 3) { /*XXX: is M ever shorter than this? * if not - what is xlat used for now? @@ -68,11 +68,11 @@ nvbios_ramcfg_index(struct nvkm_subdev *subdev) if (bit_M.length >= 7 && nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E)) return M0203E.group; - xlat = nv_ro16(bios, bit_M.offset + 1); + xlat = nvbios_rd16(bios, bit_M.offset + 1); } } if (xlat) - strap = nv_ro08(bios, xlat + strap); + strap = nvbios_rd08(bios, xlat + strap); return strap; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index 8b17bb4b2..d0ae74547 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -34,18 +34,18 @@ nvbios_rammapTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - rammap = nv_ro16(bios, bit_P.offset + 4); + rammap = nvbios_rd16(bios, bit_P.offset + 4); if (rammap) { - *ver = nv_ro08(bios, rammap + 0); + *ver = nvbios_rd08(bios, rammap + 0); switch (*ver) { case 0x10: case 0x11: - *hdr = nv_ro08(bios, rammap + 1); - *cnt = nv_ro08(bios, rammap + 5); - *len = nv_ro08(bios, rammap + 2); - *snr = nv_ro08(bios, rammap + 4); - *ssz = nv_ro08(bios, rammap + 3); + *hdr = nvbios_rd08(bios, rammap + 1); + *cnt = nvbios_rd08(bios, rammap + 5); + *len = nvbios_rd08(bios, rammap + 2); + *snr = nvbios_rd08(bios, rammap + 4); + *ssz = nvbios_rd08(bios, rammap + 3); return rammap; default: break; @@ -72,6 +72,21 @@ nvbios_rammapEe(struct nvkm_bios *bios, int idx, return 0x0000; } +/* Pretend a performance mode is also a rammap entry, helps coalesce entries + * later on */ +u32 +nvbios_rammapEp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, + struct nvbios_ramcfg *p) +{ + memset(p, 0x00, sizeof(*p)); + + p->rammap_00_16_20 = (nvbios_rd08(bios, data + 0x16) & 0x20) >> 5; + p->rammap_00_16_40 = (nvbios_rd08(bios, data + 0x16) & 0x40) >> 6; + p->rammap_00_17_02 = (nvbios_rd08(bios, data + 0x17) & 0x02) >> 1; + + return data; +} + u32 nvbios_rammapEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p) @@ -82,18 +97,18 @@ nvbios_rammapEp(struct nvkm_bios *bios, int idx, p->rammap_hdr = *hdr; switch (!!data * *ver) { case 0x10: - p->rammap_min = nv_ro16(bios, data + 0x00); - p->rammap_max = nv_ro16(bios, data + 0x02); - p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1; - p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3; + p->rammap_min = nvbios_rd16(bios, data + 0x00); + p->rammap_max = nvbios_rd16(bios, data + 0x02); + p->rammap_10_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1; + p->rammap_10_04_08 = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3; break; case 0x11: - p->rammap_min = nv_ro16(bios, data + 0x00); - p->rammap_max = nv_ro16(bios, data + 0x02); - p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0; - p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2; - p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4; - temp = nv_ro32(bios, data + 0x09); + p->rammap_min = nvbios_rd16(bios, data + 0x00); + p->rammap_max = nvbios_rd16(bios, data + 0x02); + p->rammap_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0; + p->rammap_11_08_0c = (nvbios_rd08(bios, data + 0x08) & 0x0c) >> 2; + p->rammap_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4; + temp = nvbios_rd32(bios, data + 0x09); p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0; p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9; p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18; @@ -102,10 +117,10 @@ nvbios_rammapEp(struct nvkm_bios *bios, int idx, p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25; p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26; p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27; - p->rammap_11_0d = nv_ro08(bios, data + 0x0d); - p->rammap_11_0e = nv_ro08(bios, data + 0x0e); - p->rammap_11_0f = nv_ro08(bios, data + 0x0f); - p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2; + p->rammap_11_0d = nvbios_rd08(bios, data + 0x0d); + p->rammap_11_0e = nvbios_rd08(bios, data + 0x0e); + p->rammap_11_0f = nvbios_rd08(bios, data + 0x0f); + p->rammap_11_11_0c = (nvbios_rd08(bios, data + 0x11) & 0x0c) >> 2; break; default: data = 0; @@ -141,6 +156,37 @@ nvbios_rammapSe(struct nvkm_bios *bios, u32 data, } u32 +nvbios_rammapSp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, int idx, + struct nvbios_ramcfg *p) +{ + data += (idx * size); + + if (size < 11) + return 0x00000000; + + p->ramcfg_ver = 0; + p->ramcfg_timing = nvbios_rd08(bios, data + 0x01); + p->ramcfg_00_03_01 = (nvbios_rd08(bios, data + 0x03) & 0x01) >> 0; + p->ramcfg_00_03_02 = (nvbios_rd08(bios, data + 0x03) & 0x02) >> 1; + p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x03) & 0x04) >> 2; + p->ramcfg_00_03_08 = (nvbios_rd08(bios, data + 0x03) & 0x08) >> 3; + p->ramcfg_RON = (nvbios_rd08(bios, data + 0x03) & 0x10) >> 3; + p->ramcfg_FBVDDQ = (nvbios_rd08(bios, data + 0x03) & 0x80) >> 7; + p->ramcfg_00_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1; + p->ramcfg_00_04_04 = (nvbios_rd08(bios, data + 0x04) & 0x04) >> 2; + p->ramcfg_00_04_20 = (nvbios_rd08(bios, data + 0x04) & 0x20) >> 5; + p->ramcfg_00_05 = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0; + p->ramcfg_00_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_00_07 = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0; + p->ramcfg_00_08 = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0; + p->ramcfg_00_09 = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0; + p->ramcfg_00_0a_0f = (nvbios_rd08(bios, data + 0x0a) & 0x0f) >> 0; + p->ramcfg_00_0a_f0 = (nvbios_rd08(bios, data + 0x0a) & 0xf0) >> 4; + + return data; +} + +u32 nvbios_rammapSp(struct nvkm_bios *bios, u32 data, u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr, struct nvbios_ramcfg *p) @@ -150,58 +196,59 @@ nvbios_rammapSp(struct nvkm_bios *bios, u32 data, p->ramcfg_hdr = *hdr; switch (!!data * *ver) { case 0x10: - p->ramcfg_timing = nv_ro08(bios, data + 0x01); - p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0; - p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1; - p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2; - p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; - p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; - p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5; - p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; - p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; - p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0; - p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0; - p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; - p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0; - p->ramcfg_10_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0; - p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0; - p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4; + p->ramcfg_timing = nvbios_rd08(bios, data + 0x01); + p->ramcfg_10_02_01 = (nvbios_rd08(bios, data + 0x02) & 0x01) >> 0; + p->ramcfg_10_02_02 = (nvbios_rd08(bios, data + 0x02) & 0x02) >> 1; + p->ramcfg_10_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2; + p->ramcfg_10_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3; + p->ramcfg_10_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; + p->ramcfg_10_02_20 = (nvbios_rd08(bios, data + 0x02) & 0x20) >> 5; + p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; + p->ramcfg_10_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; + p->ramcfg_10_04_01 = (nvbios_rd08(bios, data + 0x04) & 0x01) >> 0; + p->ramcfg_FBVDDQ = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3; + p->ramcfg_10_05 = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0; + p->ramcfg_10_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_10_07 = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0; + p->ramcfg_10_08 = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0; + p->ramcfg_10_09_0f = (nvbios_rd08(bios, data + 0x09) & 0x0f) >> 0; + p->ramcfg_10_09_f0 = (nvbios_rd08(bios, data + 0x09) & 0xf0) >> 4; break; case 0x11: - p->ramcfg_timing = nv_ro08(bios, data + 0x00); - p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0; - p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1; - p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2; - p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3; - p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4; - p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5; - p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6; - p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7; - p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0; - p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2; - p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; - p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; - p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; - p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7; - p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; - p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4; - p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6; - p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4; - p->ramcfg_11_04 = (nv_ro08(bios, data + 0x04) & 0xff) >> 0; - p->ramcfg_11_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; - p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1; - p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2; - p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3; - p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4; - p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6; - p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7; - p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0; - p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1; - p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2; - p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3; - p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4; - p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5; - p->ramcfg_11_09 = (nv_ro08(bios, data + 0x09) & 0xff) >> 0; + p->ramcfg_timing = nvbios_rd08(bios, data + 0x00); + p->ramcfg_11_01_01 = (nvbios_rd08(bios, data + 0x01) & 0x01) >> 0; + p->ramcfg_11_01_02 = (nvbios_rd08(bios, data + 0x01) & 0x02) >> 1; + p->ramcfg_11_01_04 = (nvbios_rd08(bios, data + 0x01) & 0x04) >> 2; + p->ramcfg_11_01_08 = (nvbios_rd08(bios, data + 0x01) & 0x08) >> 3; + p->ramcfg_11_01_10 = (nvbios_rd08(bios, data + 0x01) & 0x10) >> 4; + p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x01) & 0x20) >> 5; + p->ramcfg_11_01_40 = (nvbios_rd08(bios, data + 0x01) & 0x40) >> 6; + p->ramcfg_11_01_80 = (nvbios_rd08(bios, data + 0x01) & 0x80) >> 7; + p->ramcfg_11_02_03 = (nvbios_rd08(bios, data + 0x02) & 0x03) >> 0; + p->ramcfg_11_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2; + p->ramcfg_11_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3; + p->ramcfg_11_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; + p->ramcfg_11_02_40 = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; + p->ramcfg_11_02_80 = (nvbios_rd08(bios, data + 0x02) & 0x80) >> 7; + p->ramcfg_11_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; + p->ramcfg_11_03_30 = (nvbios_rd08(bios, data + 0x03) & 0x30) >> 4; + p->ramcfg_11_03_c0 = (nvbios_rd08(bios, data + 0x03) & 0xc0) >> 6; + p->ramcfg_11_03_f0 = (nvbios_rd08(bios, data + 0x03) & 0xf0) >> 4; + p->ramcfg_11_04 = (nvbios_rd08(bios, data + 0x04) & 0xff) >> 0; + p->ramcfg_11_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_11_07_02 = (nvbios_rd08(bios, data + 0x07) & 0x02) >> 1; + p->ramcfg_11_07_04 = (nvbios_rd08(bios, data + 0x07) & 0x04) >> 2; + p->ramcfg_11_07_08 = (nvbios_rd08(bios, data + 0x07) & 0x08) >> 3; + p->ramcfg_11_07_10 = (nvbios_rd08(bios, data + 0x07) & 0x10) >> 4; + p->ramcfg_11_07_40 = (nvbios_rd08(bios, data + 0x07) & 0x40) >> 6; + p->ramcfg_11_07_80 = (nvbios_rd08(bios, data + 0x07) & 0x80) >> 7; + p->ramcfg_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0; + p->ramcfg_11_08_02 = (nvbios_rd08(bios, data + 0x08) & 0x02) >> 1; + p->ramcfg_11_08_04 = (nvbios_rd08(bios, data + 0x08) & 0x04) >> 2; + p->ramcfg_11_08_08 = (nvbios_rd08(bios, data + 0x08) & 0x08) >> 3; + p->ramcfg_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4; + p->ramcfg_11_08_20 = (nvbios_rd08(bios, data + 0x08) & 0x20) >> 5; + p->ramcfg_11_09 = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0; break; default: data = 0; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index 8c2b7cba5..b2557e87a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -23,13 +23,11 @@ */ #include "priv.h" -#include <core/device.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/image.h> struct shadow { - struct nvkm_oclass base; u32 skip; const struct nvbios_source *func; void *data; @@ -38,9 +36,8 @@ struct shadow { }; static bool -shadow_fetch(struct nvkm_bios *bios, u32 upto) +shadow_fetch(struct nvkm_bios *bios, struct shadow *mthd, u32 upto) { - struct shadow *mthd = (void *)nv_object(bios)->oclass; const u32 limit = (upto + 3) & ~3; const u32 start = bios->size; void *data = mthd->data; @@ -48,68 +45,47 @@ shadow_fetch(struct nvkm_bios *bios, u32 upto) u32 read = mthd->func->read(data, start, limit - start, bios); bios->size = start + read; } - return bios->size >= limit; + return bios->size >= upto; } -static u8 -shadow_rd08(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - if (shadow_fetch(bios, addr + 1)) - return bios->data[addr]; - return 0x00; -} - -static u16 -shadow_rd16(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - if (shadow_fetch(bios, addr + 2)) - return get_unaligned_le16(&bios->data[addr]); - return 0x0000; -} - -static u32 -shadow_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - if (shadow_fetch(bios, addr + 4)) - return get_unaligned_le32(&bios->data[addr]); - return 0x00000000; -} - -static struct nvkm_oclass -shadow_class = { - .handle = NV_SUBDEV(VBIOS, 0x00), - .ofuncs = &(struct nvkm_ofuncs) { - .rd08 = shadow_rd08, - .rd16 = shadow_rd16, - .rd32 = shadow_rd32, - }, -}; - static int -shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd) +shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) { + struct nvkm_subdev *subdev = &bios->subdev; struct nvbios_image image; int score = 1; - if (!nvbios_image(bios, idx, &image)) { - nv_debug(bios, "image %d invalid\n", idx); - return 0; + if (mthd->func->no_pcir) { + image.base = 0; + image.type = 0; + image.size = mthd->func->size(mthd->data); + image.last = 1; + } else { + if (!shadow_fetch(bios, mthd, offset + 0x1000)) { + nvkm_debug(subdev, "%08x: header fetch failed\n", + offset); + return 0; + } + + if (!nvbios_image(bios, idx, &image)) { + nvkm_debug(subdev, "image %d invalid\n", idx); + return 0; + } } - nv_debug(bios, "%08x: type %02x, %d bytes\n", - image.base, image.type, image.size); + nvkm_debug(subdev, "%08x: type %02x, %d bytes\n", + image.base, image.type, image.size); - if (!shadow_fetch(bios, image.size)) { - nv_debug(bios, "%08x: fetch failed\n", image.base); + if (!shadow_fetch(bios, mthd, image.size)) { + nvkm_debug(subdev, "%08x: fetch failed\n", image.base); return 0; } switch (image.type) { case 0x00: - if (nvbios_checksum(&bios->data[image.base], image.size)) { - nv_debug(bios, "%08x: checksum failed\n", image.base); + if (!mthd->func->ignore_checksum && + nvbios_checksum(&bios->data[image.base], image.size)) { + nvkm_debug(subdev, "%08x: checksum failed\n", + image.base); if (mthd->func->rw) score += 1; score += 1; @@ -123,28 +99,17 @@ shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd) } if (!image.last) - score += shadow_image(bios, idx + 1, mthd); + score += shadow_image(bios, idx + 1, offset + image.size, mthd); return score; } static int -shadow_score(struct nvkm_bios *bios, struct shadow *mthd) -{ - struct nvkm_oclass *oclass = nv_object(bios)->oclass; - int score; - nv_object(bios)->oclass = &mthd->base; - score = shadow_image(bios, 0, mthd); - nv_object(bios)->oclass = oclass; - return score; - -} - -static int shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name) { const struct nvbios_source *func = mthd->func; + struct nvkm_subdev *subdev = &bios->subdev; if (func->name) { - nv_debug(bios, "trying %s...\n", name ? name : func->name); + nvkm_debug(subdev, "trying %s...\n", name ? name : func->name); if (func->init) { mthd->data = func->init(bios, name); if (IS_ERR(mthd->data)) { @@ -152,10 +117,10 @@ shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name) return 0; } } - mthd->score = shadow_score(bios, mthd); + mthd->score = shadow_image(bios, 0, 0, mthd); if (func->fini) func->fini(mthd->data); - nv_debug(bios, "scored %d\n", mthd->score); + nvkm_debug(subdev, "scored %d\n", mthd->score); mthd->data = bios->data; mthd->size = bios->size; bios->data = NULL; @@ -178,7 +143,7 @@ shadow_fw_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * shadow_fw_init(struct nvkm_bios *bios, const char *name) { - struct device *dev = &nv_device(bios)->pdev->dev; + struct device *dev = bios->subdev.device->dev; const struct firmware *fw; int ret = request_firmware(&fw, name, dev); if (ret) @@ -198,22 +163,24 @@ shadow_fw = { int nvbios_shadow(struct nvkm_bios *bios) { + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; struct shadow mthds[] = { - { shadow_class, 0, &nvbios_of }, - { shadow_class, 0, &nvbios_ramin }, - { shadow_class, 0, &nvbios_rom }, - { shadow_class, 0, &nvbios_acpi_fast }, - { shadow_class, 4, &nvbios_acpi_slow }, - { shadow_class, 1, &nvbios_pcirom }, - { shadow_class, 1, &nvbios_platform }, - { shadow_class } - }, *mthd = mthds, *best = NULL; + { 0, &nvbios_of }, + { 0, &nvbios_ramin }, + { 0, &nvbios_rom }, + { 0, &nvbios_acpi_fast }, + { 4, &nvbios_acpi_slow }, + { 1, &nvbios_pcirom }, + { 1, &nvbios_platform }, + {} + }, *mthd, *best = NULL; const char *optarg; char *source; int optlen; /* handle user-specified bios source */ - optarg = nvkm_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen); + optarg = nvkm_stropt(device->cfgopt, "NvBios", &optlen); source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL; if (source) { /* try to match one of the built-in methods */ @@ -234,7 +201,7 @@ nvbios_shadow(struct nvkm_bios *bios) } if (!best->score) { - nv_error(bios, "%s invalid\n", source); + nvkm_error(subdev, "%s invalid\n", source); kfree(source); source = NULL; } @@ -259,12 +226,12 @@ nvbios_shadow(struct nvkm_bios *bios) } if (!best->score) { - nv_fatal(bios, "unable to locate usable image\n"); + nvkm_error(subdev, "unable to locate usable image\n"); return -EINVAL; } - nv_info(bios, "using image from %s\n", best->func ? - best->func->name : source); + nvkm_debug(subdev, "using image from %s\n", best->func ? + best->func->name : source); bios->data = best->data; bios->size = best->size; kfree(source); diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c index f9d0eb564..8fecb5ff2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c @@ -22,14 +22,12 @@ */ #include "priv.h" -#include <core/device.h> - #if defined(CONFIG_ACPI) && defined(CONFIG_X86) int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); -bool nouveau_acpi_rom_supported(struct pci_dev *pdev); +bool nouveau_acpi_rom_supported(struct device *); #else static inline bool -nouveau_acpi_rom_supported(struct pci_dev *pdev) +nouveau_acpi_rom_supported(struct device *dev) { return false; } @@ -90,7 +88,7 @@ acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * acpi_init(struct nvkm_bios *bios, const char *name) { - if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev)) + if (!nouveau_acpi_rom_supported(bios->subdev.device->dev)) return ERR_PTR(-ENODEV); return NULL; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c index 4c19a7dba..4bf486b57 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c @@ -22,7 +22,7 @@ */ #include "priv.h" -#include <core/device.h> +#include <core/pci.h> #if defined(__powerpc__) struct priv { @@ -34,17 +34,26 @@ static u32 of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { struct priv *priv = data; - if (offset + length <= priv->size) { + if (offset < priv->size) { + length = min_t(u32, length, priv->size - offset); memcpy_fromio(bios->data + offset, priv->data + offset, length); return length; } return 0; } +static u32 +of_size(void *data) +{ + struct priv *priv = data; + return priv->size; +} + static void * of_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = nv_device(bios)->pdev; + struct nvkm_device *device = bios->subdev.device; + struct pci_dev *pdev = device->func->pci(device)->pdev; struct device_node *dn; struct priv *priv; if (!(dn = pci_device_to_OF_node(pdev))) @@ -63,7 +72,10 @@ nvbios_of = { .init = of_init, .fini = (void(*)(void *))kfree, .read = of_read, + .size = of_size, .rw = false, + .ignore_checksum = true, + .no_pcir = true, }; #else const struct nvbios_source diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c index 1b045483d..9b91da09d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c @@ -22,7 +22,7 @@ */ #include "priv.h" -#include <core/device.h> +#include <core/pci.h> struct priv { struct pci_dev *pdev; @@ -53,10 +53,16 @@ pcirom_fini(void *data) static void * pcirom_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = nv_device(bios)->pdev; + struct nvkm_device *device = bios->subdev.device; struct priv *priv = NULL; + struct pci_dev *pdev; int ret; + if (device->func->pci) + pdev = device->func->pci(device)->pdev; + else + return ERR_PTR(-ENODEV); + if (!(ret = pci_enable_rom(pdev))) { if (ret = -ENOMEM, (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) { @@ -85,10 +91,16 @@ nvbios_pcirom = { static void * platform_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = nv_device(bios)->pdev; + struct nvkm_device *device = bios->subdev.device; + struct pci_dev *pdev; struct priv *priv; int ret = -ENOMEM; + if (device->func->pci) + pdev = device->func->pci(device)->pdev; + else + return ERR_PTR(-ENODEV); + if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) { if (ret = -ENODEV, (priv->rom = pci_platform_rom(pdev, &priv->size))) diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c index abe8ae4d3..0f537c228 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c @@ -22,8 +22,6 @@ */ #include "priv.h" -#include <core/device.h> - struct priv { struct nvkm_bios *bios; u32 bar0; @@ -32,10 +30,11 @@ struct priv { static u32 pramin_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { + struct nvkm_device *device = bios->subdev.device; u32 i; if (offset + length <= 0x00100000) { for (i = offset; i < offset + length; i += 4) - *(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i); + *(u32 *)&bios->data[i] = nvkm_rd32(device, 0x700000 + i); return length; } return 0; @@ -46,7 +45,8 @@ pramin_fini(void *data) { struct priv *priv = data; if (priv) { - nv_wr32(priv->bios, 0x001700, priv->bar0); + struct nvkm_device *device = priv->bios->subdev.device; + nvkm_wr32(device, 0x001700, priv->bar0); kfree(priv); } } @@ -54,21 +54,23 @@ pramin_fini(void *data) static void * pramin_init(struct nvkm_bios *bios, const char *name) { + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; struct priv *priv = NULL; u64 addr = 0; /* PRAMIN always potentially available prior to nv50 */ - if (nv_device(bios)->card_type < NV_50) + if (device->card_type < NV_50) return NULL; /* we can't get the bios image pointer without PDISP */ - if (nv_device(bios)->card_type >= GM100) - addr = nv_rd32(bios, 0x021c04); + if (device->card_type >= GM100) + addr = nvkm_rd32(device, 0x021c04); else - if (nv_device(bios)->card_type >= NV_C0) - addr = nv_rd32(bios, 0x022500); + if (device->card_type >= NV_C0) + addr = nvkm_rd32(device, 0x022500); if (addr & 0x00000001) { - nv_debug(bios, "... display disabled\n"); + nvkm_debug(subdev, "... display disabled\n"); return ERR_PTR(-ENODEV); } @@ -76,32 +78,32 @@ pramin_init(struct nvkm_bios *bios, const char *name) * important as we don't want to be touching vram on an * uninitialised board */ - addr = nv_rd32(bios, 0x619f04); + addr = nvkm_rd32(device, 0x619f04); if (!(addr & 0x00000008)) { - nv_debug(bios, "... not enabled\n"); + nvkm_debug(subdev, "... not enabled\n"); return ERR_PTR(-ENODEV); } if ( (addr & 0x00000003) != 1) { - nv_debug(bios, "... not in vram\n"); + nvkm_debug(subdev, "... not in vram\n"); return ERR_PTR(-ENODEV); } /* some alternate method inherited from xf86-video-nv... */ addr = (addr & 0xffffff00) << 8; if (!addr) { - addr = (u64)nv_rd32(bios, 0x001700) << 16; + addr = (u64)nvkm_rd32(device, 0x001700) << 16; addr += 0xf0000; } /* modify bar0 PRAMIN window to cover the bios image */ if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) { - nv_error(bios, "... out of memory\n"); + nvkm_error(subdev, "... out of memory\n"); return ERR_PTR(-ENOMEM); } priv->bios = bios; - priv->bar0 = nv_rd32(bios, 0x001700); - nv_wr32(bios, 0x001700, addr >> 16); + priv->bar0 = nvkm_rd32(device, 0x001700); + nvkm_wr32(device, 0x001700, addr >> 16); return priv; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c index 6ec3b2379..ffa4b3952 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c @@ -22,15 +22,16 @@ */ #include "priv.h" -#include <core/device.h> +#include <subdev/pci.h> static u32 prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { + struct nvkm_device *device = data; u32 i; if (offset + length <= 0x00100000) { for (i = offset; i < offset + length; i += 4) - *(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i); + *(u32 *)&bios->data[i] = nvkm_rd32(device, 0x300000 + i); return length; } return 0; @@ -39,25 +40,18 @@ prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void prom_fini(void *data) { - struct nvkm_bios *bios = data; - if (nv_device(bios)->card_type < NV_50) - nv_mask(bios, 0x001850, 0x00000001, 0x00000001); - else - nv_mask(bios, 0x088050, 0x00000001, 0x00000001); + struct nvkm_device *device = data; + nvkm_pci_rom_shadow(device->pci, true); } static void * prom_init(struct nvkm_bios *bios, const char *name) { - if (nv_device(bios)->card_type < NV_50) { - if (nv_device(bios)->card_type == NV_40 && - nv_device(bios)->chipset >= 0x4c) - return ERR_PTR(-ENODEV); - nv_mask(bios, 0x001850, 0x00000001, 0x00000000); - } else { - nv_mask(bios, 0x088050, 0x00000001, 0x00000000); - } - return bios; + struct nvkm_device *device = bios->subdev.device; + if (device->card_type == NV_40 && device->chipset >= 0x4c) + return ERR_PTR(-ENODEV); + nvkm_pci_rom_shadow(device->pci, false); + return device; } const struct nvbios_source diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c index 249ff6d58..a54cfec05 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c @@ -25,8 +25,6 @@ #include <subdev/bios/bit.h> #include <subdev/bios/therm.h> -#include <core/device.h> - static u16 therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) { @@ -35,24 +33,24 @@ therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 1) - therm = nv_ro16(bios, bit_P.offset + 12); + therm = nvbios_rd16(bios, bit_P.offset + 12); else if (bit_P.version == 2) - therm = nv_ro16(bios, bit_P.offset + 16); + therm = nvbios_rd16(bios, bit_P.offset + 16); else - nv_error(bios, - "unknown offset for thermal in BIT P %d\n", - bit_P.version); + nvkm_error(&bios->subdev, + "unknown offset for thermal in BIT P %d\n", + bit_P.version); } /* exit now if we haven't found the thermal table */ if (!therm) return 0x0000; - *ver = nv_ro08(bios, therm + 0); - *hdr = nv_ro08(bios, therm + 1); - *len = nv_ro08(bios, therm + 2); - *cnt = nv_ro08(bios, therm + 3); - return therm + nv_ro08(bios, therm + 1); + *ver = nvbios_rd08(bios, therm + 0); + *hdr = nvbios_rd08(bios, therm + 1); + *len = nvbios_rd08(bios, therm + 2); + *cnt = nvbios_rd08(bios, therm + 3); + return therm + nvbios_rd08(bios, therm + 1); } static u16 @@ -83,9 +81,9 @@ nvbios_therm_sensor_parse(struct nvkm_bios *bios, sensor_section = -1; i = 0; while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { - s16 value = nv_ro16(bios, entry + 1); + s16 value = nvbios_rd16(bios, entry + 1); - switch (nv_ro08(bios, entry + 0)) { + switch (nvbios_rd08(bios, entry + 0)) { case 0x0: thrs_section = value; if (value > 0) @@ -94,7 +92,7 @@ nvbios_therm_sensor_parse(struct nvkm_bios *bios, case 0x01: sensor_section++; if (sensor_section == 0) { - offset = ((s8) nv_ro08(bios, entry + 2)) / 2; + offset = ((s8) nvbios_rd08(bios, entry + 2)) / 2; sensor->offset_constant = offset; } break; @@ -165,9 +163,9 @@ nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) fan->nr_fan_trip = 0; fan->fan_mode = NVBIOS_THERM_FAN_OTHER; while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { - s16 value = nv_ro16(bios, entry + 1); + s16 value = nvbios_rd16(bios, entry + 1); - switch (nv_ro08(bios, entry + 0)) { + switch (nvbios_rd08(bios, entry + 0)) { case 0x22: fan->min_duty = value & 0xff; fan->max_duty = (value & 0xff00) >> 8; @@ -198,14 +196,14 @@ nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) case 0x46: if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR) fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; - fan->linear_min_temp = nv_ro08(bios, entry + 1); - fan->linear_max_temp = nv_ro08(bios, entry + 2); + fan->linear_min_temp = nvbios_rd08(bios, entry + 1); + fan->linear_max_temp = nvbios_rd08(bios, entry + 2); break; } } /* starting from fermi, fan management is always linear */ - if (nv_device(bios)->card_type >= NV_C0 && + if (bios->subdev.device->card_type >= NV_C0 && fan->fan_mode == NVBIOS_THERM_FAN_OTHER) { fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c index 763fd29a5..99f6432ac 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c @@ -34,27 +34,27 @@ nvbios_timingTe(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 1) - timing = nv_ro16(bios, bit_P.offset + 4); + timing = nvbios_rd16(bios, bit_P.offset + 4); else if (bit_P.version == 2) - timing = nv_ro16(bios, bit_P.offset + 8); + timing = nvbios_rd16(bios, bit_P.offset + 8); if (timing) { - *ver = nv_ro08(bios, timing + 0); + *ver = nvbios_rd08(bios, timing + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, timing + 1); - *cnt = nv_ro08(bios, timing + 2); - *len = nv_ro08(bios, timing + 3); + *hdr = nvbios_rd08(bios, timing + 1); + *cnt = nvbios_rd08(bios, timing + 2); + *len = nvbios_rd08(bios, timing + 3); *snr = 0; *ssz = 0; return timing; case 0x20: - *hdr = nv_ro08(bios, timing + 1); - *cnt = nv_ro08(bios, timing + 5); - *len = nv_ro08(bios, timing + 2); - *snr = nv_ro08(bios, timing + 4); - *ssz = nv_ro08(bios, timing + 3); + *hdr = nvbios_rd08(bios, timing + 1); + *cnt = nvbios_rd08(bios, timing + 5); + *len = nvbios_rd08(bios, timing + 2); + *snr = nvbios_rd08(bios, timing + 4); + *ssz = nvbios_rd08(bios, timing + 3); return timing; default: break; @@ -90,18 +90,20 @@ nvbios_timingEp(struct nvkm_bios *bios, int idx, p->timing_hdr = *hdr; switch (!!data * *ver) { case 0x10: - p->timing_10_WR = nv_ro08(bios, data + 0x00); - p->timing_10_WTR = nv_ro08(bios, data + 0x01); - p->timing_10_CL = nv_ro08(bios, data + 0x02); - p->timing_10_RC = nv_ro08(bios, data + 0x03); - p->timing_10_RFC = nv_ro08(bios, data + 0x05); - p->timing_10_RAS = nv_ro08(bios, data + 0x07); - p->timing_10_RP = nv_ro08(bios, data + 0x09); - p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a); - p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b); - p->timing_10_RRD = nv_ro08(bios, data + 0x0c); - p->timing_10_13 = nv_ro08(bios, data + 0x0d); - p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07; + p->timing_10_WR = nvbios_rd08(bios, data + 0x00); + p->timing_10_WTR = nvbios_rd08(bios, data + 0x01); + p->timing_10_CL = nvbios_rd08(bios, data + 0x02); + p->timing_10_RC = nvbios_rd08(bios, data + 0x03); + p->timing_10_RFC = nvbios_rd08(bios, data + 0x05); + p->timing_10_RAS = nvbios_rd08(bios, data + 0x07); + p->timing_10_RP = nvbios_rd08(bios, data + 0x09); + p->timing_10_RCDRD = nvbios_rd08(bios, data + 0x0a); + p->timing_10_RCDWR = nvbios_rd08(bios, data + 0x0b); + p->timing_10_RRD = nvbios_rd08(bios, data + 0x0c); + p->timing_10_13 = nvbios_rd08(bios, data + 0x0d); + p->timing_10_ODT = nvbios_rd08(bios, data + 0x0e) & 0x07; + if (p->ramcfg_ver >= 0x10) + p->ramcfg_RON = nvbios_rd08(bios, data + 0x0e) & 0x07; p->timing_10_24 = 0xff; p->timing_10_21 = 0; @@ -112,45 +114,45 @@ nvbios_timingEp(struct nvkm_bios *bios, int idx, switch (min_t(u8, *hdr, 25)) { case 25: - p->timing_10_24 = nv_ro08(bios, data + 0x18); + p->timing_10_24 = nvbios_rd08(bios, data + 0x18); case 24: case 23: case 22: - p->timing_10_21 = nv_ro08(bios, data + 0x15); + p->timing_10_21 = nvbios_rd08(bios, data + 0x15); case 21: - p->timing_10_20 = nv_ro08(bios, data + 0x14); + p->timing_10_20 = nvbios_rd08(bios, data + 0x14); case 20: - p->timing_10_CWL = nv_ro08(bios, data + 0x13); + p->timing_10_CWL = nvbios_rd08(bios, data + 0x13); case 19: - p->timing_10_18 = nv_ro08(bios, data + 0x12); + p->timing_10_18 = nvbios_rd08(bios, data + 0x12); case 18: case 17: - p->timing_10_16 = nv_ro08(bios, data + 0x10); + p->timing_10_16 = nvbios_rd08(bios, data + 0x10); } break; case 0x20: - p->timing[0] = nv_ro32(bios, data + 0x00); - p->timing[1] = nv_ro32(bios, data + 0x04); - p->timing[2] = nv_ro32(bios, data + 0x08); - p->timing[3] = nv_ro32(bios, data + 0x0c); - p->timing[4] = nv_ro32(bios, data + 0x10); - p->timing[5] = nv_ro32(bios, data + 0x14); - p->timing[6] = nv_ro32(bios, data + 0x18); - p->timing[7] = nv_ro32(bios, data + 0x1c); - p->timing[8] = nv_ro32(bios, data + 0x20); - p->timing[9] = nv_ro32(bios, data + 0x24); - p->timing[10] = nv_ro32(bios, data + 0x28); - p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0; - p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4; - p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6; - p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0; - temp = nv_ro16(bios, data + 0x2c); + p->timing[0] = nvbios_rd32(bios, data + 0x00); + p->timing[1] = nvbios_rd32(bios, data + 0x04); + p->timing[2] = nvbios_rd32(bios, data + 0x08); + p->timing[3] = nvbios_rd32(bios, data + 0x0c); + p->timing[4] = nvbios_rd32(bios, data + 0x10); + p->timing[5] = nvbios_rd32(bios, data + 0x14); + p->timing[6] = nvbios_rd32(bios, data + 0x18); + p->timing[7] = nvbios_rd32(bios, data + 0x1c); + p->timing[8] = nvbios_rd32(bios, data + 0x20); + p->timing[9] = nvbios_rd32(bios, data + 0x24); + p->timing[10] = nvbios_rd32(bios, data + 0x28); + p->timing_20_2e_03 = (nvbios_rd08(bios, data + 0x2e) & 0x03) >> 0; + p->timing_20_2e_30 = (nvbios_rd08(bios, data + 0x2e) & 0x30) >> 4; + p->timing_20_2e_c0 = (nvbios_rd08(bios, data + 0x2e) & 0xc0) >> 6; + p->timing_20_2f_03 = (nvbios_rd08(bios, data + 0x2f) & 0x03) >> 0; + temp = nvbios_rd16(bios, data + 0x2c); p->timing_20_2c_003f = (temp & 0x003f) >> 0; p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6; - p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0; - p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3; - temp = nv_ro16(bios, data + 0x31); + p->timing_20_30_07 = (nvbios_rd08(bios, data + 0x30) & 0x07) >> 0; + p->timing_20_30_f8 = (nvbios_rd08(bios, data + 0x30) & 0xf8) >> 3; + temp = nvbios_rd16(bios, data + 0x31); p->timing_20_31_0007 = (temp & 0x0007) >> 0; p->timing_20_31_0078 = (temp & 0x0078) >> 3; p->timing_20_31_0780 = (temp & 0x0780) >> 7; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c index e95b69faa..2f13db745 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c @@ -33,15 +33,15 @@ nvbios_vmap_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) { - vmap = nv_ro16(bios, bit_P.offset + 0x20); + vmap = nvbios_rd16(bios, bit_P.offset + 0x20); if (vmap) { - *ver = nv_ro08(bios, vmap + 0); + *ver = nvbios_rd08(bios, vmap + 0); switch (*ver) { case 0x10: case 0x20: - *hdr = nv_ro08(bios, vmap + 1); - *cnt = nv_ro08(bios, vmap + 3); - *len = nv_ro08(bios, vmap + 2); + *hdr = nvbios_rd08(bios, vmap + 1); + *cnt = nvbios_rd08(bios, vmap + 3); + *len = nvbios_rd08(bios, vmap + 2); return vmap; default: break; @@ -88,23 +88,23 @@ nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, switch (!!vmap * *ver) { case 0x10: info->link = 0xff; - info->min = nv_ro32(bios, vmap + 0x00); - info->max = nv_ro32(bios, vmap + 0x04); - info->arg[0] = nv_ro32(bios, vmap + 0x08); - info->arg[1] = nv_ro32(bios, vmap + 0x0c); - info->arg[2] = nv_ro32(bios, vmap + 0x10); + info->min = nvbios_rd32(bios, vmap + 0x00); + info->max = nvbios_rd32(bios, vmap + 0x04); + info->arg[0] = nvbios_rd32(bios, vmap + 0x08); + info->arg[1] = nvbios_rd32(bios, vmap + 0x0c); + info->arg[2] = nvbios_rd32(bios, vmap + 0x10); break; case 0x20: - info->unk0 = nv_ro08(bios, vmap + 0x00); - info->link = nv_ro08(bios, vmap + 0x01); - info->min = nv_ro32(bios, vmap + 0x02); - info->max = nv_ro32(bios, vmap + 0x06); - info->arg[0] = nv_ro32(bios, vmap + 0x0a); - info->arg[1] = nv_ro32(bios, vmap + 0x0e); - info->arg[2] = nv_ro32(bios, vmap + 0x12); - info->arg[3] = nv_ro32(bios, vmap + 0x16); - info->arg[4] = nv_ro32(bios, vmap + 0x1a); - info->arg[5] = nv_ro32(bios, vmap + 0x1e); + info->unk0 = nvbios_rd08(bios, vmap + 0x00); + info->link = nvbios_rd08(bios, vmap + 0x01); + info->min = nvbios_rd32(bios, vmap + 0x02); + info->max = nvbios_rd32(bios, vmap + 0x06); + info->arg[0] = nvbios_rd32(bios, vmap + 0x0a); + info->arg[1] = nvbios_rd32(bios, vmap + 0x0e); + info->arg[2] = nvbios_rd32(bios, vmap + 0x12); + info->arg[3] = nvbios_rd32(bios, vmap + 0x16); + info->arg[4] = nvbios_rd32(bios, vmap + 0x1a); + info->arg[5] = nvbios_rd32(bios, vmap + 0x1e); break; } return vmap; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c index 8454ab7c4..6e0a33648 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c @@ -33,30 +33,30 @@ nvbios_volt_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - volt = nv_ro16(bios, bit_P.offset + 0x0c); + volt = nvbios_rd16(bios, bit_P.offset + 0x0c); else if (bit_P.version == 1) - volt = nv_ro16(bios, bit_P.offset + 0x10); + volt = nvbios_rd16(bios, bit_P.offset + 0x10); if (volt) { - *ver = nv_ro08(bios, volt + 0); + *ver = nvbios_rd08(bios, volt + 0); switch (*ver) { case 0x12: *hdr = 5; - *cnt = nv_ro08(bios, volt + 2); - *len = nv_ro08(bios, volt + 1); + *cnt = nvbios_rd08(bios, volt + 2); + *len = nvbios_rd08(bios, volt + 1); return volt; case 0x20: - *hdr = nv_ro08(bios, volt + 1); - *cnt = nv_ro08(bios, volt + 2); - *len = nv_ro08(bios, volt + 3); + *hdr = nvbios_rd08(bios, volt + 1); + *cnt = nvbios_rd08(bios, volt + 2); + *len = nvbios_rd08(bios, volt + 3); return volt; case 0x30: case 0x40: case 0x50: - *hdr = nv_ro08(bios, volt + 1); - *cnt = nv_ro08(bios, volt + 3); - *len = nv_ro08(bios, volt + 2); + *hdr = nvbios_rd08(bios, volt + 1); + *cnt = nvbios_rd08(bios, volt + 3); + *len = nvbios_rd08(bios, volt + 2); return volt; } } @@ -73,28 +73,41 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, memset(info, 0x00, sizeof(*info)); switch (!!volt * *ver) { case 0x12: - info->vidmask = nv_ro08(bios, volt + 0x04); + info->type = NVBIOS_VOLT_GPIO; + info->vidmask = nvbios_rd08(bios, volt + 0x04); break; case 0x20: - info->vidmask = nv_ro08(bios, volt + 0x05); + info->type = NVBIOS_VOLT_GPIO; + info->vidmask = nvbios_rd08(bios, volt + 0x05); break; case 0x30: - info->vidmask = nv_ro08(bios, volt + 0x04); + info->type = NVBIOS_VOLT_GPIO; + info->vidmask = nvbios_rd08(bios, volt + 0x04); break; case 0x40: - info->base = nv_ro32(bios, volt + 0x04); - info->step = nv_ro16(bios, volt + 0x08); - info->vidmask = nv_ro08(bios, volt + 0x0b); + info->type = NVBIOS_VOLT_GPIO; + info->base = nvbios_rd32(bios, volt + 0x04); + info->step = nvbios_rd16(bios, volt + 0x08); + info->vidmask = nvbios_rd08(bios, volt + 0x0b); /*XXX*/ info->min = 0; info->max = info->base; break; case 0x50: - info->vidmask = nv_ro08(bios, volt + 0x06); - info->min = nv_ro32(bios, volt + 0x0a); - info->max = nv_ro32(bios, volt + 0x0e); - info->base = nv_ro32(bios, volt + 0x12) & 0x00ffffff; - info->step = nv_ro16(bios, volt + 0x16); + info->min = nvbios_rd32(bios, volt + 0x0a); + info->max = nvbios_rd32(bios, volt + 0x0e); + info->base = nvbios_rd32(bios, volt + 0x12) & 0x00ffffff; + + /* offset 4 seems to be a flag byte */ + if (nvbios_rd32(bios, volt + 0x4) & 1) { + info->type = NVBIOS_VOLT_PWM; + info->pwm_freq = nvbios_rd32(bios, volt + 0x5) / 1000; + info->pwm_range = nvbios_rd32(bios, volt + 0x16); + } else { + info->type = NVBIOS_VOLT_GPIO; + info->vidmask = nvbios_rd08(bios, volt + 0x06); + info->step = nvbios_rd16(bios, volt + 0x16); + } break; } return volt; @@ -121,12 +134,12 @@ nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, switch (!!volt * *ver) { case 0x12: case 0x20: - info->voltage = nv_ro08(bios, volt + 0x00) * 10000; - info->vid = nv_ro08(bios, volt + 0x01); + info->voltage = nvbios_rd08(bios, volt + 0x00) * 10000; + info->vid = nvbios_rd08(bios, volt + 0x01); break; case 0x30: - info->voltage = nv_ro08(bios, volt + 0x00) * 10000; - info->vid = nv_ro08(bios, volt + 0x01) >> 2; + info->voltage = nvbios_rd08(bios, volt + 0x00) * 10000; + info->vid = nvbios_rd08(bios, volt + 0x01) >> 2; break; case 0x40: case 0x50: diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c index 63a5e1b5c..250fc42d8 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c @@ -30,12 +30,12 @@ dcb_xpiod_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len); if (data && *ver >= 0x40 && *hdr >= 0x06) { - u16 xpio = nv_ro16(bios, data + 0x04); + u16 xpio = nvbios_rd16(bios, data + 0x04); if (xpio) { - *ver = nv_ro08(bios, data + 0x00); - *hdr = nv_ro08(bios, data + 0x01); - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x03); + *ver = nvbios_rd08(bios, data + 0x00); + *hdr = nvbios_rd08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x03); return xpio; } } @@ -48,12 +48,12 @@ dcb_xpio_table(struct nvkm_bios *bios, u8 idx, { u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len); if (data && idx < *cnt) { - u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len)); + u16 xpio = nvbios_rd16(bios, data + *hdr + (idx * *len)); if (xpio) { - *ver = nv_ro08(bios, data + 0x00); - *hdr = nv_ro08(bios, data + 0x01); - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x03); + *ver = nvbios_rd08(bios, data + 0x00); + *hdr = nvbios_rd08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x03); return xpio; } } @@ -66,9 +66,9 @@ dcb_xpio_parse(struct nvkm_bios *bios, u8 idx, { u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len); if (data && *len >= 6) { - info->type = nv_ro08(bios, data + 0x04); - info->addr = nv_ro08(bios, data + 0x05); - info->flags = nv_ro08(bios, data + 0x06); + info->type = nvbios_rd08(bios, data + 0x04); + info->addr = nvbios_rd08(bios, data + 0x05); + info->flags = nvbios_rd08(bios, data + 0x06); } return 0x0000; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild index 83d80b13f..5fa9e9183 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild @@ -1,3 +1,4 @@ +nvkm-y += nvkm/subdev/bus/base.o nvkm-y += nvkm/subdev/bus/hwsq.o nvkm-y += nvkm/subdev/bus/nv04.o nvkm-y += nvkm/subdev/bus/nv31.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c new file mode 100644 index 000000000..dc5a10f18 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c @@ -0,0 +1,64 @@ +/* + * Copyright 2015 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 void +nvkm_bus_intr(struct nvkm_subdev *subdev) +{ + struct nvkm_bus *bus = nvkm_bus(subdev); + bus->func->intr(bus); +} + +static int +nvkm_bus_init(struct nvkm_subdev *subdev) +{ + struct nvkm_bus *bus = nvkm_bus(subdev); + bus->func->init(bus); + return 0; +} + +static void * +nvkm_bus_dtor(struct nvkm_subdev *subdev) +{ + return nvkm_bus(subdev); +} + +static const struct nvkm_subdev_func +nvkm_bus = { + .dtor = nvkm_bus_dtor, + .init = nvkm_bus_init, + .intr = nvkm_bus_intr, +}; + +int +nvkm_bus_new_(const struct nvkm_bus_func *func, struct nvkm_device *device, + int index, struct nvkm_bus **pbus) +{ + struct nvkm_bus *bus; + if (!(bus = *pbus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_bus, device, index, 0, &bus->subdev); + bus->func = func; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c index cbe699e82..9700b5c01 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c @@ -22,37 +22,43 @@ * Authors: Martin Peres <martin.peres@labri.fr> * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" #include <subdev/timer.h> static int -g94_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size) +g94_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) { - struct nv50_bus_priv *priv = (void *)pbus; + struct nvkm_device *device = bus->subdev.device; int i; - nv_mask(pbus, 0x001098, 0x00000008, 0x00000000); - nv_wr32(pbus, 0x001304, 0x00000000); - nv_wr32(pbus, 0x001318, 0x00000000); + nvkm_mask(device, 0x001098, 0x00000008, 0x00000000); + nvkm_wr32(device, 0x001304, 0x00000000); + nvkm_wr32(device, 0x001318, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(priv, 0x080000 + (i * 4), data[i]); - nv_mask(pbus, 0x001098, 0x00000018, 0x00000018); - nv_wr32(pbus, 0x00130c, 0x00000001); + nvkm_wr32(device, 0x080000 + (i * 4), data[i]); + nvkm_mask(device, 0x001098, 0x00000018, 0x00000018); + nvkm_wr32(device, 0x00130c, 0x00000001); - return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x001308) & 0x00000100)) + break; + ) < 0) + return -ETIMEDOUT; + + return 0; } -struct nvkm_oclass * -g94_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv50_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +g94_bus = { + .init = nv50_bus_init, .intr = nv50_bus_intr, .hwsq_exec = g94_bus_hwsq_exec, .hwsq_size = 128, -}.base; +}; + +int +g94_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&g94_bus, device, index, pbus); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c index ebc63ba96..e0930d5fd 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c @@ -22,59 +22,54 @@ * Authors: Martin Peres <martin.peres@labri.fr> * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" static void -gf100_bus_intr(struct nvkm_subdev *subdev) +gf100_bus_intr(struct nvkm_bus *bus) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); + struct nvkm_subdev *subdev = &bus->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x0000000e) { - u32 addr = nv_rd32(pbus, 0x009084); - u32 data = nv_rd32(pbus, 0x009088); + u32 addr = nvkm_rd32(device, 0x009084); + u32 data = nvkm_rd32(device, 0x009088); - nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n", - (addr & 0x00000002) ? "write" : "read", data, - (addr & 0x00fffffc), - (stat & 0x00000002) ? "!ENGINE " : "", - (stat & 0x00000004) ? "IBUS " : "", - (stat & 0x00000008) ? "TIMEOUT " : ""); + nvkm_error(subdev, + "MMIO %s of %08x FAULT at %06x [ %s%s%s]\n", + (addr & 0x00000002) ? "write" : "read", data, + (addr & 0x00fffffc), + (stat & 0x00000002) ? "!ENGINE " : "", + (stat & 0x00000004) ? "IBUS " : "", + (stat & 0x00000008) ? "TIMEOUT " : ""); - nv_wr32(pbus, 0x009084, 0x00000000); - nv_wr32(pbus, 0x001100, (stat & 0x0000000e)); + nvkm_wr32(device, 0x009084, 0x00000000); + nvkm_wr32(device, 0x001100, (stat & 0x0000000e)); stat &= ~0x0000000e; } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0x00000000); + nvkm_error(subdev, "intr %08x\n", stat); + nvkm_mask(device, 0x001140, stat, 0x00000000); } } -static int -gf100_bus_init(struct nvkm_object *object) +static void +gf100_bus_init(struct nvkm_bus *bus) { - struct nv04_bus_priv *priv = (void *)object; - int ret; - - ret = nvkm_bus_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x0000000e); - return 0; + struct nvkm_device *device = bus->subdev.device; + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x0000000e); } -struct nvkm_oclass * -gf100_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = gf100_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +gf100_bus = { + .init = gf100_bus_init, .intr = gf100_bus_intr, -}.base; +}; + +int +gf100_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&gf100_bus, device, index, pbus); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c index 7622b4161..2a5668938 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include <subdev/bus.h> +#include "priv.h" struct nvkm_hwsq { - struct nvkm_bus *pbus; + struct nvkm_subdev *subdev; u32 addr; u32 data; struct { @@ -41,13 +41,13 @@ hwsq_cmd(struct nvkm_hwsq *hwsq, int size, u8 data[]) } int -nvkm_hwsq_init(struct nvkm_bus *pbus, struct nvkm_hwsq **phwsq) +nvkm_hwsq_init(struct nvkm_subdev *subdev, struct nvkm_hwsq **phwsq) { struct nvkm_hwsq *hwsq; hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL); if (hwsq) { - hwsq->pbus = pbus; + hwsq->subdev = subdev; hwsq->addr = ~0; hwsq->data = ~0; memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data)); @@ -63,21 +63,23 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) struct nvkm_hwsq *hwsq = *phwsq; int ret = 0, i; if (hwsq) { - struct nvkm_bus *pbus = hwsq->pbus; + struct nvkm_subdev *subdev = hwsq->subdev; + struct nvkm_bus *bus = subdev->device->bus; hwsq->c.size = (hwsq->c.size + 4) / 4; - if (hwsq->c.size <= pbus->hwsq_size) { + if (hwsq->c.size <= bus->func->hwsq_size) { if (exec) - ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data, - hwsq->c.size); + ret = bus->func->hwsq_exec(bus, + (u32 *)hwsq->c.data, + hwsq->c.size); if (ret) - nv_error(pbus, "hwsq exec failed: %d\n", ret); + nvkm_error(subdev, "hwsq exec failed: %d\n", ret); } else { - nv_error(pbus, "hwsq ucode too large\n"); + nvkm_error(subdev, "hwsq ucode too large\n"); ret = -ENOSPC; } for (i = 0; ret && i < hwsq->c.size; i++) - nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]); + nvkm_error(subdev, "\t%08x\n", ((u32 *)hwsq->c.data)[i]); *phwsq = NULL; kfree(hwsq); @@ -88,7 +90,7 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) void nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) { - nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data); + nvkm_debug(hwsq->subdev, "R[%06x] = %08x\n", addr, data); if (hwsq->data != data) { if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) { @@ -113,7 +115,7 @@ nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) void nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) { - nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data); + nvkm_debug(hwsq->subdev, " FLAG[%02x] = %d\n", flag, data); flag += 0x80; if (data >= 0) flag += 0x20; @@ -125,11 +127,43 @@ nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) void nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data) { - nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data); + nvkm_debug(hwsq->subdev, " WAIT[%02x] = %d\n", flag, data); hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data }); } void +nvkm_hwsq_wait_vblank(struct nvkm_hwsq *hwsq) +{ + struct nvkm_subdev *subdev = hwsq->subdev; + struct nvkm_device *device = subdev->device; + u32 heads, x, y, px = 0; + int i, head_sync; + + heads = nvkm_rd32(device, 0x610050); + for (i = 0; i < 2; i++) { + /* Heuristic: sync to head with biggest resolution */ + if (heads & (2 << (i << 3))) { + x = nvkm_rd32(device, 0x610b40 + (0x540 * i)); + y = (x & 0xffff0000) >> 16; + x &= 0x0000ffff; + if ((x * y) > px) { + px = (x * y); + head_sync = i; + } + } + } + + if (px == 0) { + nvkm_debug(subdev, "WAIT VBLANK !NO ACTIVE HEAD\n"); + return; + } + + nvkm_debug(subdev, "WAIT VBLANK HEAD%d\n", head_sync); + nvkm_hwsq_wait(hwsq, head_sync ? 0x3 : 0x1, 0x0); + nvkm_hwsq_wait(hwsq, head_sync ? 0x3 : 0x1, 0x1); +} + +void nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec) { u8 shift = 0, usec = nsec / 1000; @@ -138,6 +172,6 @@ nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec) shift++; } - nv_debug(hwsq->pbus, " DELAY = %d ns\n", nsec); + nvkm_debug(hwsq->subdev, " DELAY = %d ns\n", nsec); hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec }); } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h index ebf709c27..54ec3b131 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h @@ -59,10 +59,9 @@ hwsq_reg(u32 addr) static inline int hwsq_init(struct hwsq *ram, struct nvkm_subdev *subdev) { - struct nvkm_bus *pbus = nvkm_bus(subdev); int ret; - ret = nvkm_hwsq_init(pbus, &ram->hwsq); + ret = nvkm_hwsq_init(subdev, &ram->hwsq); if (ret) return ret; @@ -85,8 +84,9 @@ hwsq_exec(struct hwsq *ram, bool exec) static inline u32 hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg) { + struct nvkm_device *device = ram->subdev->device; if (reg->sequence != ram->sequence) - reg->data = nv_rd32(ram->subdev, reg->addr); + reg->data = nvkm_rd32(device, reg->addr); return reg->data; } @@ -134,6 +134,12 @@ hwsq_wait(struct hwsq *ram, u8 flag, u8 data) } static inline void +hwsq_wait_vblank(struct hwsq *ram) +{ + nvkm_hwsq_wait_vblank(ram->hwsq); +} + +static inline void hwsq_nsec(struct hwsq *ram, u32 nsec) { nvkm_hwsq_nsec(ram->hwsq, nsec); diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c index 19c8e50ee..c80b96789 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c @@ -22,73 +22,55 @@ * Authors: Martin Peres <martin.peres@labri.fr> * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" + +#include <subdev/gpio.h> + +#include <subdev/gpio.h> static void -nv04_bus_intr(struct nvkm_subdev *subdev) +nv04_bus_intr(struct nvkm_bus *bus) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); + struct nvkm_subdev *subdev = &bus->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x00000001) { - nv_error(pbus, "BUS ERROR\n"); + nvkm_error(subdev, "BUS ERROR\n"); stat &= ~0x00000001; - nv_wr32(pbus, 0x001100, 0x00000001); + nvkm_wr32(device, 0x001100, 0x00000001); } if (stat & 0x00000110) { - subdev = nvkm_subdev(subdev, NVDEV_SUBDEV_GPIO); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_gpio *gpio = device->gpio; + if (gpio) + nvkm_subdev_intr(&gpio->subdev); stat &= ~0x00000110; - nv_wr32(pbus, 0x001100, 0x00000110); + nvkm_wr32(device, 0x001100, 0x00000110); } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0x00000000); + nvkm_error(subdev, "intr %08x\n", stat); + nvkm_mask(device, 0x001140, stat, 0x00000000); } } -static int -nv04_bus_init(struct nvkm_object *object) +static void +nv04_bus_init(struct nvkm_bus *bus) { - struct nv04_bus_priv *priv = (void *)object; - - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x00000111); - - return nvkm_bus_init(&priv->base); + struct nvkm_device *device = bus->subdev.device; + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x00000111); } +static const struct nvkm_bus_func +nv04_bus = { + .init = nv04_bus_init, + .intr = nv04_bus_intr, +}; + int -nv04_bus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) { - struct nv04_bus_impl *impl = (void *)oclass; - struct nv04_bus_priv *priv; - int ret; - - ret = nvkm_bus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->intr = impl->intr; - priv->base.hwsq_exec = impl->hwsq_exec; - priv->base.hwsq_size = impl->hwsq_size; - return 0; + return nvkm_bus_new_(&nv04_bus, device, index, pbus); } - -struct nvkm_oclass * -nv04_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv04_bus_init, - .fini = _nvkm_bus_fini, - }, - .intr = nv04_bus_intr, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h deleted file mode 100644 index 3ddc8f91b..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __NVKM_BUS_NV04_H__ -#define __NVKM_BUS_NV04_H__ -#include <subdev/bus.h> - -struct nv04_bus_priv { - struct nvkm_bus base; -}; - -int nv04_bus_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -int nv50_bus_init(struct nvkm_object *); -void nv50_bus_intr(struct nvkm_subdev *); - -struct nv04_bus_impl { - struct nvkm_oclass base; - void (*intr)(struct nvkm_subdev *); - int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32); - u32 hwsq_size; -}; -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c index c5739bce8..5153d89e1 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c @@ -22,70 +22,67 @@ * Authors: Martin Peres <martin.peres@labri.fr> * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" + +#include <subdev/gpio.h> +#include <subdev/therm.h> static void -nv31_bus_intr(struct nvkm_subdev *subdev) +nv31_bus_intr(struct nvkm_bus *bus) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); - u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144); + struct nvkm_subdev *subdev = &bus->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); + u32 gpio = nvkm_rd32(device, 0x001104) & nvkm_rd32(device, 0x001144); if (gpio) { - subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_GPIO); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_gpio *gpio = device->gpio; + if (gpio) + nvkm_subdev_intr(&gpio->subdev); } if (stat & 0x00000008) { /* NV41- */ - u32 addr = nv_rd32(pbus, 0x009084); - u32 data = nv_rd32(pbus, 0x009088); + u32 addr = nvkm_rd32(device, 0x009084); + u32 data = nvkm_rd32(device, 0x009088); - nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", - (addr & 0x00000002) ? "write" : "read", data, - (addr & 0x00fffffc)); + nvkm_error(subdev, "MMIO %s of %08x FAULT at %06x\n", + (addr & 0x00000002) ? "write" : "read", data, + (addr & 0x00fffffc)); stat &= ~0x00000008; - nv_wr32(pbus, 0x001100, 0x00000008); + nvkm_wr32(device, 0x001100, 0x00000008); } if (stat & 0x00070000) { - subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_therm *therm = device->therm; + if (therm) + nvkm_subdev_intr(&therm->subdev); stat &= ~0x00070000; - nv_wr32(pbus, 0x001100, 0x00070000); + nvkm_wr32(device, 0x001100, 0x00070000); } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0x00000000); + nvkm_error(subdev, "intr %08x\n", stat); + nvkm_mask(device, 0x001140, stat, 0x00000000); } } -static int -nv31_bus_init(struct nvkm_object *object) +static void +nv31_bus_init(struct nvkm_bus *bus) { - struct nv04_bus_priv *priv = (void *)object; - int ret; - - ret = nvkm_bus_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x00070008); - return 0; + struct nvkm_device *device = bus->subdev.device; + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x00070008); } -struct nvkm_oclass * -nv31_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x31), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv31_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +nv31_bus = { + .init = nv31_bus_init, .intr = nv31_bus_intr, -}.base; +}; + +int +nv31_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&nv31_bus, device, index, pbus); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c index 1987863d7..19e10fdc9 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c @@ -22,83 +22,84 @@ * Authors: Martin Peres <martin.peres@labri.fr> * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" +#include <subdev/therm.h> #include <subdev/timer.h> static int -nv50_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size) +nv50_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) { - struct nv50_bus_priv *priv = (void *)pbus; + struct nvkm_device *device = bus->subdev.device; int i; - nv_mask(pbus, 0x001098, 0x00000008, 0x00000000); - nv_wr32(pbus, 0x001304, 0x00000000); + nvkm_mask(device, 0x001098, 0x00000008, 0x00000000); + nvkm_wr32(device, 0x001304, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(priv, 0x001400 + (i * 4), data[i]); - nv_mask(pbus, 0x001098, 0x00000018, 0x00000018); - nv_wr32(pbus, 0x00130c, 0x00000003); + nvkm_wr32(device, 0x001400 + (i * 4), data[i]); + nvkm_mask(device, 0x001098, 0x00000018, 0x00000018); + nvkm_wr32(device, 0x00130c, 0x00000003); - return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x001308) & 0x00000100)) + break; + ) < 0) + return -ETIMEDOUT; + + return 0; } void -nv50_bus_intr(struct nvkm_subdev *subdev) +nv50_bus_intr(struct nvkm_bus *bus) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); + struct nvkm_subdev *subdev = &bus->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x00000008) { - u32 addr = nv_rd32(pbus, 0x009084); - u32 data = nv_rd32(pbus, 0x009088); + u32 addr = nvkm_rd32(device, 0x009084); + u32 data = nvkm_rd32(device, 0x009088); - nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", - (addr & 0x00000002) ? "write" : "read", data, - (addr & 0x00fffffc)); + nvkm_error(subdev, "MMIO %s of %08x FAULT at %06x\n", + (addr & 0x00000002) ? "write" : "read", data, + (addr & 0x00fffffc)); stat &= ~0x00000008; - nv_wr32(pbus, 0x001100, 0x00000008); + nvkm_wr32(device, 0x001100, 0x00000008); } if (stat & 0x00010000) { - subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_therm *therm = device->therm; + if (therm) + nvkm_subdev_intr(&therm->subdev); stat &= ~0x00010000; - nv_wr32(pbus, 0x001100, 0x00010000); + nvkm_wr32(device, 0x001100, 0x00010000); } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0); + nvkm_error(subdev, "intr %08x\n", stat); + nvkm_mask(device, 0x001140, stat, 0); } } -int -nv50_bus_init(struct nvkm_object *object) +void +nv50_bus_init(struct nvkm_bus *bus) { - struct nv04_bus_priv *priv = (void *)object; - int ret; - - ret = nvkm_bus_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x00010008); - return 0; + struct nvkm_device *device = bus->subdev.device; + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x00010008); } -struct nvkm_oclass * -nv50_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv50_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +nv50_bus = { + .init = nv50_bus_init, .intr = nv50_bus_intr, .hwsq_exec = nv50_bus_hwsq_exec, .hwsq_size = 64, -}.base; +}; + +int +nv50_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&nv50_bus, device, index, pbus); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h new file mode 100644 index 000000000..a130f2c64 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_BUS_PRIV_H__ +#define __NVKM_BUS_PRIV_H__ +#define nvkm_bus(p) container_of((p), struct nvkm_bus, subdev) +#include <subdev/bus.h> + +struct nvkm_bus_func { + void (*init)(struct nvkm_bus *); + void (*intr)(struct nvkm_bus *); + int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32); + u32 hwsq_size; +}; + +int nvkm_bus_new_(const struct nvkm_bus_func *, struct nvkm_device *, int, + struct nvkm_bus **); + +void nv50_bus_init(struct nvkm_bus *); +void nv50_bus_intr(struct nvkm_bus *); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild index 9c2f688c9..ed7717bcc 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild @@ -8,5 +8,6 @@ nvkm-y += nvkm/subdev/clk/mcp77.o nvkm-y += nvkm/subdev/clk/gf100.o nvkm-y += nvkm/subdev/clk/gk104.o nvkm-y += nvkm/subdev/clk/gk20a.o + nvkm-y += nvkm/subdev/clk/pllnv04.o nvkm-y += nvkm/subdev/clk/pllgt215.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 39a83d82e..dc8682c91 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include <subdev/clk.h> +#include "priv.h" + #include <subdev/bios.h> #include <subdev/bios/boost.h> #include <subdev/bios/cstep.h> @@ -30,7 +31,6 @@ #include <subdev/therm.h> #include <subdev/volt.h> -#include <core/device.h> #include <core/option.h> /****************************************************************************** @@ -40,7 +40,7 @@ static u32 nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, u8 pstate, u8 domain, u32 input) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_bios *bios = clk->subdev.device->bios; struct nvbios_boostE boostE; u8 ver, hdr, cnt, len; u16 data; @@ -77,8 +77,10 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, static int nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) { - struct nvkm_therm *ptherm = nvkm_therm(clk); - struct nvkm_volt *volt = nvkm_volt(clk); + struct nvkm_subdev *subdev = &clk->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_therm *therm = device->therm; + struct nvkm_volt *volt = device->volt; struct nvkm_cstate *cstate; int ret; @@ -88,41 +90,41 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) cstate = &pstate->base; } - if (ptherm) { - ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, +1); + if (therm) { + ret = nvkm_therm_cstate(therm, pstate->fanspeed, +1); if (ret && ret != -ENODEV) { - nv_error(clk, "failed to raise fan speed: %d\n", ret); + nvkm_error(subdev, "failed to raise fan speed: %d\n", ret); return ret; } } if (volt) { - ret = volt->set_id(volt, cstate->voltage, +1); + ret = nvkm_volt_set_id(volt, cstate->voltage, +1); if (ret && ret != -ENODEV) { - nv_error(clk, "failed to raise voltage: %d\n", ret); + nvkm_error(subdev, "failed to raise voltage: %d\n", ret); return ret; } } - ret = clk->calc(clk, cstate); + ret = clk->func->calc(clk, cstate); if (ret == 0) { - ret = clk->prog(clk); - clk->tidy(clk); + ret = clk->func->prog(clk); + clk->func->tidy(clk); } if (volt) { - ret = volt->set_id(volt, cstate->voltage, -1); + ret = nvkm_volt_set_id(volt, cstate->voltage, -1); if (ret && ret != -ENODEV) - nv_error(clk, "failed to lower voltage: %d\n", ret); + nvkm_error(subdev, "failed to lower voltage: %d\n", ret); } - if (ptherm) { - ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, -1); + if (therm) { + ret = nvkm_therm_cstate(therm, pstate->fanspeed, -1); if (ret && ret != -ENODEV) - nv_error(clk, "failed to lower fan speed: %d\n", ret); + nvkm_error(subdev, "failed to lower fan speed: %d\n", ret); } - return 0; + return ret; } static void @@ -135,8 +137,8 @@ nvkm_cstate_del(struct nvkm_cstate *cstate) static int nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) { - struct nvkm_bios *bios = nvkm_bios(clk); - struct nvkm_domain *domain = clk->domains; + struct nvkm_bios *bios = clk->subdev.device->bios; + const struct nvkm_domain *domain = clk->domains; struct nvkm_cstate *cstate = NULL; struct nvbios_cstepX cstepX; u8 ver, hdr; @@ -172,7 +174,8 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) static int nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) { - struct nvkm_fb *pfb = nvkm_fb(clk); + struct nvkm_subdev *subdev = &clk->subdev; + struct nvkm_ram *ram = subdev->device->fb->ram; struct nvkm_pstate *pstate; int ret, idx = 0; @@ -181,17 +184,17 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) break; } - nv_debug(clk, "setting performance state %d\n", pstatei); + nvkm_debug(subdev, "setting performance state %d\n", pstatei); clk->pstate = pstatei; - if (pfb->ram && pfb->ram->calc) { + if (ram && ram->func->calc) { int khz = pstate->base.domain[nv_clk_src_mem]; do { - ret = pfb->ram->calc(pfb, khz); + ret = ram->func->calc(ram, khz); if (ret == 0) - ret = pfb->ram->prog(pfb); + ret = ram->func->prog(ram); } while (ret > 0); - pfb->ram->tidy(pfb); + ram->func->tidy(ram); } return nvkm_cstate_prog(clk, pstate, 0); @@ -201,31 +204,32 @@ static void nvkm_pstate_work(struct work_struct *work) { struct nvkm_clk *clk = container_of(work, typeof(*clk), work); + struct nvkm_subdev *subdev = &clk->subdev; int pstate; if (!atomic_xchg(&clk->waiting, 0)) return; clk->pwrsrc = power_supply_is_system_supplied(); - nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n", - clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, - clk->astate, clk->tstate, clk->dstate); + nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n", + clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, + clk->astate, clk->tstate, clk->dstate); pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; if (clk->state_nr && pstate != -1) { pstate = (pstate < 0) ? clk->astate : pstate; - pstate = min(pstate, clk->state_nr - 1 - clk->tstate); + pstate = min(pstate, clk->state_nr - 1 + clk->tstate); pstate = max(pstate, clk->dstate); } else { pstate = clk->pstate = -1; } - nv_trace(clk, "-> %d\n", pstate); + nvkm_trace(subdev, "-> %d\n", pstate); if (pstate != clk->pstate) { int ret = nvkm_pstate_prog(clk, pstate); if (ret) { - nv_error(clk, "error setting pstate %d: %d\n", - pstate, ret); + nvkm_error(subdev, "error setting pstate %d: %d\n", + pstate, ret); } } @@ -246,8 +250,9 @@ nvkm_pstate_calc(struct nvkm_clk *clk, bool wait) static void nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) { - struct nvkm_domain *clock = clk->domains - 1; + const struct nvkm_domain *clock = clk->domains - 1; struct nvkm_cstate *cstate; + struct nvkm_subdev *subdev = &clk->subdev; char info[3][32] = { "", "", "" }; char name[4] = "--"; int i = -1; @@ -261,12 +266,12 @@ nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) if (hi == 0) continue; - nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo); + nvkm_debug(subdev, "%02x: %10d KHz\n", clock->name, lo); list_for_each_entry(cstate, &pstate->list, head) { u32 freq = cstate->domain[clock->name]; lo = min(lo, freq); hi = max(hi, freq); - nv_debug(clk, "%10d KHz\n", freq); + nvkm_debug(subdev, "%10d KHz\n", freq); } if (clock->mname && ++i < ARRAY_SIZE(info)) { @@ -282,7 +287,7 @@ nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) } } - nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]); + nvkm_debug(subdev, "%s: %s %s %s\n", name, info[0], info[1], info[2]); } static void @@ -301,8 +306,8 @@ nvkm_pstate_del(struct nvkm_pstate *pstate) static int nvkm_pstate_new(struct nvkm_clk *clk, int idx) { - struct nvkm_bios *bios = nvkm_bios(clk); - struct nvkm_domain *domain = clk->domains - 1; + struct nvkm_bios *bios = clk->subdev.device->bios; + const struct nvkm_domain *domain = clk->domains - 1; struct nvkm_pstate *pstate; struct nvkm_cstate *cstate; struct nvbios_cstepE cstepE; @@ -471,32 +476,37 @@ nvkm_clk_pwrsrc(struct nvkm_notify *notify) *****************************************************************************/ int -_nvkm_clk_fini(struct nvkm_object *object, bool suspend) +nvkm_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +{ + return clk->func->read(clk, src); +} + +static int +nvkm_clk_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_clk *clk = (void *)object; + struct nvkm_clk *clk = nvkm_clk(subdev); nvkm_notify_put(&clk->pwrsrc_ntfy); - return nvkm_subdev_fini(&clk->base, suspend); + flush_work(&clk->work); + if (clk->func->fini) + clk->func->fini(clk); + return 0; } -int -_nvkm_clk_init(struct nvkm_object *object) +static int +nvkm_clk_init(struct nvkm_subdev *subdev) { - struct nvkm_clk *clk = (void *)object; - struct nvkm_domain *clock = clk->domains; + struct nvkm_clk *clk = nvkm_clk(subdev); + const struct nvkm_domain *clock = clk->domains; int ret; - ret = nvkm_subdev_init(&clk->base); - if (ret) - return ret; - memset(&clk->bstate, 0x00, sizeof(clk->bstate)); INIT_LIST_HEAD(&clk->bstate.list); clk->bstate.pstate = 0xff; while (clock->name != nv_clk_src_max) { - ret = clk->read(clk, clock->name); + ret = nvkm_clk_read(clk, clock->name); if (ret < 0) { - nv_error(clk, "%02x freq unknown\n", clock->name); + nvkm_error(subdev, "%02x freq unknown\n", clock->name); return ret; } clk->bstate.base.domain[clock->name] = ret; @@ -505,6 +515,9 @@ _nvkm_clk_init(struct nvkm_object *object) nvkm_pstate_info(clk, &clk->bstate); + if (clk->func->init) + return clk->func->init(clk); + clk->astate = clk->state_nr - 1; clk->tstate = 0; clk->dstate = 0; @@ -513,61 +526,63 @@ _nvkm_clk_init(struct nvkm_object *object) return 0; } -void -_nvkm_clk_dtor(struct nvkm_object *object) +static void * +nvkm_clk_dtor(struct nvkm_subdev *subdev) { - struct nvkm_clk *clk = (void *)object; + struct nvkm_clk *clk = nvkm_clk(subdev); struct nvkm_pstate *pstate, *temp; nvkm_notify_fini(&clk->pwrsrc_ntfy); + /* Early return if the pstates have been provided statically */ + if (clk->func->pstates) + return clk; + list_for_each_entry_safe(pstate, temp, &clk->states, head) { nvkm_pstate_del(pstate); } - nvkm_subdev_destroy(&clk->base); + return clk; } +static const struct nvkm_subdev_func +nvkm_clk = { + .dtor = nvkm_clk_dtor, + .init = nvkm_clk_init, + .fini = nvkm_clk_fini, +}; + int -nvkm_clk_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, struct nvkm_domain *clocks, - struct nvkm_pstate *pstates, int nb_pstates, - bool allow_reclock, int length, void **object) +nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, + int index, bool allow_reclock, struct nvkm_clk *clk) { - struct nvkm_device *device = nv_device(parent); - struct nvkm_clk *clk; int ret, idx, arglen; const char *mode; - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "CLK", - "clock", length, object); - clk = *object; - if (ret) - return ret; - + nvkm_subdev_ctor(&nvkm_clk, device, index, 0, &clk->subdev); + clk->func = func; INIT_LIST_HEAD(&clk->states); - clk->domains = clocks; + clk->domains = func->domains; clk->ustate_ac = -1; clk->ustate_dc = -1; + clk->allow_reclock = allow_reclock; INIT_WORK(&clk->work, nvkm_pstate_work); init_waitqueue_head(&clk->wait); atomic_set(&clk->waiting, 0); /* If no pstates are provided, try and fetch them from the BIOS */ - if (!pstates) { + if (!func->pstates) { idx = 0; do { ret = nvkm_pstate_new(clk, idx++); } while (ret == 0); } else { - for (idx = 0; idx < nb_pstates; idx++) - list_add_tail(&pstates[idx].head, &clk->states); - clk->state_nr = nb_pstates; + for (idx = 0; idx < func->nr_pstates; idx++) + list_add_tail(&func->pstates[idx].head, &clk->states); + clk->state_nr = func->nr_pstates; } - clk->allow_reclock = allow_reclock; - ret = nvkm_notify_init(NULL, &device->event, nvkm_clk_pwrsrc, true, NULL, 0, 0, &clk->pwrsrc_ntfy); if (ret) @@ -589,3 +604,12 @@ nvkm_clk_create_(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } + +int +nvkm_clk_new_(const struct nvkm_clk_func *func, struct nvkm_device *device, + int index, bool allow_reclock, struct nvkm_clk **pclk) +{ + if (!(*pclk = kzalloc(sizeof(**pclk), GFP_KERNEL))) + return -ENOMEM; + return nvkm_clk_ctor(func, device, index, allow_reclock, *pclk); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c index 4c90b9769..f97e3ec19 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c @@ -23,25 +23,26 @@ */ #include "nv50.h" -static struct nvkm_domain -g84_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0xff }, - { nv_clk_src_max } +static const struct nvkm_clk_func +g84_clk = { + .read = nv50_clk_read, + .calc = nv50_clk_calc, + .prog = nv50_clk_prog, + .tidy = nv50_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0xff }, + { nv_clk_src_max } + } }; -struct nvkm_oclass * -g84_clk_oclass = &(struct nv50_clk_oclass) { - .base.handle = NV_SUBDEV(CLK, 0x84), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, - .domains = g84_domains, -}.base; +int +g84_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) +{ + return nv50_clk_new_(&g84_clk, device, index, + (device->chipset >= 0x94), pclk); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index 3d7330d54..a52b7e7fc 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#include <subdev/clk.h> +#define gf100_clk(p) container_of((p), struct gf100_clk, base) +#include "priv.h" #include "pll.h" -#include <core/device.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> #include <subdev/timer.h> @@ -38,29 +38,29 @@ struct gf100_clk_info { u32 coef; }; -struct gf100_clk_priv { +struct gf100_clk { struct nvkm_clk base; struct gf100_clk_info eng[16]; }; -static u32 read_div(struct gf100_clk_priv *, int, u32, u32); +static u32 read_div(struct gf100_clk *, int, u32, u32); static u32 -read_vco(struct gf100_clk_priv *priv, u32 dsrc) +read_vco(struct gf100_clk *clk, u32 dsrc) { - struct nvkm_clk *clk = &priv->base; - u32 ssrc = nv_rd32(priv, dsrc); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc); if (!(ssrc & 0x00000100)) - return clk->read(clk, nv_clk_src_sppll0); - return clk->read(clk, nv_clk_src_sppll1); + return nvkm_clk_read(&clk->base, nv_clk_src_sppll0); + return nvkm_clk_read(&clk->base, nv_clk_src_sppll1); } static u32 -read_pll(struct gf100_clk_priv *priv, u32 pll) +read_pll(struct gf100_clk *clk, u32 pll) { - struct nvkm_clk *clk = &priv->base; - u32 ctrl = nv_rd32(priv, pll + 0x00); - u32 coef = nv_rd32(priv, pll + 0x04); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, pll + 0x00); + u32 coef = nvkm_rd32(device, pll + 0x04); u32 P = (coef & 0x003f0000) >> 16; u32 N = (coef & 0x0000ff00) >> 8; u32 M = (coef & 0x000000ff) >> 0; @@ -72,20 +72,20 @@ read_pll(struct gf100_clk_priv *priv, u32 pll) switch (pll) { case 0x00e800: case 0x00e820: - sclk = nv_device(priv)->crystal; + sclk = device->crystal; P = 1; break; case 0x132000: - sclk = clk->read(clk, nv_clk_src_mpllsrc); + sclk = nvkm_clk_read(&clk->base, nv_clk_src_mpllsrc); break; case 0x132020: - sclk = clk->read(clk, nv_clk_src_mpllsrcref); + sclk = nvkm_clk_read(&clk->base, nv_clk_src_mpllsrcref); break; case 0x137000: case 0x137020: case 0x137040: case 0x1370e0: - sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + sclk = read_div(clk, (pll & 0xff) / 0x20, 0x137120, 0x137140); break; default: return 0; @@ -95,46 +95,48 @@ read_pll(struct gf100_clk_priv *priv, u32 pll) } static u32 -read_div(struct gf100_clk_priv *priv, int doff, u32 dsrc, u32 dctl) +read_div(struct gf100_clk *clk, int doff, u32 dsrc, u32 dctl) { - u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); - u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc + (doff * 4)); + u32 sctl = nvkm_rd32(device, dctl + (doff * 4)); switch (ssrc & 0x00000003) { case 0: if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(priv)->crystal; + return device->crystal; return 108000; case 2: return 100000; case 3: if (sctl & 0x80000000) { - u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sclk = read_vco(clk, dsrc + (doff * 4)); u32 sdiv = (sctl & 0x0000003f) + 2; return (sclk * 2) / sdiv; } - return read_vco(priv, dsrc + (doff * 4)); + return read_vco(clk, dsrc + (doff * 4)); default: return 0; } } static u32 -read_clk(struct gf100_clk_priv *priv, int clk) +read_clk(struct gf100_clk *clk, int idx) { - u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); - u32 ssel = nv_rd32(priv, 0x137100); + struct nvkm_device *device = clk->base.subdev.device; + u32 sctl = nvkm_rd32(device, 0x137250 + (idx * 4)); + u32 ssel = nvkm_rd32(device, 0x137100); u32 sclk, sdiv; - if (ssel & (1 << clk)) { - if (clk < 7) - sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + if (ssel & (1 << idx)) { + if (idx < 7) + sclk = read_pll(clk, 0x137000 + (idx * 0x20)); else - sclk = read_pll(priv, 0x1370e0); + sclk = read_pll(clk, 0x1370e0); sdiv = ((sctl & 0x00003f00) >> 8) + 2; } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); sdiv = ((sctl & 0x0000003f) >> 0) + 2; } @@ -145,10 +147,11 @@ read_clk(struct gf100_clk_priv *priv, int clk) } static int -gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gf100_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct nvkm_device *device = nv_device(clk); - struct gf100_clk_priv *priv = (void *)clk; + struct gf100_clk *clk = gf100_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; switch (src) { case nv_clk_src_crystal: @@ -156,47 +159,47 @@ gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) case nv_clk_src_href: return 100000; case nv_clk_src_sppll0: - return read_pll(priv, 0x00e800); + return read_pll(clk, 0x00e800); case nv_clk_src_sppll1: - return read_pll(priv, 0x00e820); + return read_pll(clk, 0x00e820); case nv_clk_src_mpllsrcref: - return read_div(priv, 0, 0x137320, 0x137330); + return read_div(clk, 0, 0x137320, 0x137330); case nv_clk_src_mpllsrc: - return read_pll(priv, 0x132020); + return read_pll(clk, 0x132020); case nv_clk_src_mpll: - return read_pll(priv, 0x132000); + return read_pll(clk, 0x132000); case nv_clk_src_mdiv: - return read_div(priv, 0, 0x137300, 0x137310); + return read_div(clk, 0, 0x137300, 0x137310); case nv_clk_src_mem: - if (nv_rd32(priv, 0x1373f0) & 0x00000002) - return clk->read(clk, nv_clk_src_mpll); - return clk->read(clk, nv_clk_src_mdiv); + if (nvkm_rd32(device, 0x1373f0) & 0x00000002) + return nvkm_clk_read(&clk->base, nv_clk_src_mpll); + return nvkm_clk_read(&clk->base, nv_clk_src_mdiv); case nv_clk_src_gpc: - return read_clk(priv, 0x00); + return read_clk(clk, 0x00); case nv_clk_src_rop: - return read_clk(priv, 0x01); + return read_clk(clk, 0x01); case nv_clk_src_hubk07: - return read_clk(priv, 0x02); + return read_clk(clk, 0x02); case nv_clk_src_hubk06: - return read_clk(priv, 0x07); + return read_clk(clk, 0x07); case nv_clk_src_hubk01: - return read_clk(priv, 0x08); + return read_clk(clk, 0x08); case nv_clk_src_copy: - return read_clk(priv, 0x09); + return read_clk(clk, 0x09); case nv_clk_src_daemon: - return read_clk(priv, 0x0c); + return read_clk(clk, 0x0c); case nv_clk_src_vdec: - return read_clk(priv, 0x0e); + return read_clk(clk, 0x0e); default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } } static u32 -calc_div(struct gf100_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +calc_div(struct gf100_clk *clk, int idx, u32 ref, u32 freq, u32 *ddiv) { u32 div = min((ref * 2) / freq, (u32)65); if (div < 2) @@ -207,7 +210,7 @@ calc_div(struct gf100_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) } static u32 -calc_src(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +calc_src(struct gf100_clk *clk, int idx, u32 freq, u32 *dsrc, u32 *ddiv) { u32 sclk; @@ -229,28 +232,29 @@ calc_src(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) } /* otherwise, calculate the closest divider */ - sclk = read_vco(priv, 0x137160 + (clk * 4)); - if (clk < 7) - sclk = calc_div(priv, clk, sclk, freq, ddiv); + sclk = read_vco(clk, 0x137160 + (idx * 4)); + if (idx < 7) + sclk = calc_div(clk, idx, sclk, freq, ddiv); return sclk; } static u32 -calc_pll(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *coef) +calc_pll(struct gf100_clk *clk, int idx, u32 freq, u32 *coef) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pll limits; int N, M, P, ret; - ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + ret = nvbios_pll_parse(bios, 0x137000 + (idx * 0x20), &limits); if (ret) return 0; - limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + limits.refclk = read_div(clk, idx, 0x137120, 0x137140); if (!limits.refclk) return 0; - ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + ret = gt215_pll_calc(subdev, &limits, freq, &N, NULL, &M, &P); if (ret <= 0) return 0; @@ -259,10 +263,9 @@ calc_pll(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *coef) } static int -calc_clk(struct gf100_clk_priv *priv, - struct nvkm_cstate *cstate, int clk, int dom) +calc_clk(struct gf100_clk *clk, struct nvkm_cstate *cstate, int idx, int dom) { - struct gf100_clk_info *info = &priv->eng[clk]; + struct gf100_clk_info *info = &clk->eng[idx]; u32 freq = cstate->domain[dom]; u32 src0, div0, div1D, div1P = 0; u32 clk0, clk1 = 0; @@ -272,16 +275,16 @@ calc_clk(struct gf100_clk_priv *priv, return 0; /* first possible path, using only dividers */ - clk0 = calc_src(priv, clk, freq, &src0, &div0); - clk0 = calc_div(priv, clk, clk0, freq, &div1D); + clk0 = calc_src(clk, idx, freq, &src0, &div0); + clk0 = calc_div(clk, idx, clk0, freq, &div1D); /* see if we can get any closer using PLLs */ - if (clk0 != freq && (0x00004387 & (1 << clk))) { - if (clk <= 7) - clk1 = calc_pll(priv, clk, freq, &info->coef); + if (clk0 != freq && (0x00004387 & (1 << idx))) { + if (idx <= 7) + clk1 = calc_pll(clk, idx, freq, &info->coef); else clk1 = cstate->domain[nv_clk_src_hubk06]; - clk1 = calc_div(priv, clk, clk1, freq, &div1P); + clk1 = calc_div(clk, idx, clk1, freq, &div1P); } /* select the method which gets closest to target freq */ @@ -303,7 +306,7 @@ calc_clk(struct gf100_clk_priv *priv, info->mdiv |= 0x80000000; info->mdiv |= div1P << 8; } - info->ssel = (1 << clk); + info->ssel = (1 << idx); info->freq = clk1; } @@ -311,81 +314,96 @@ calc_clk(struct gf100_clk_priv *priv, } static int -gf100_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gf100_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gf100_clk_priv *priv = (void *)clk; + struct gf100_clk *clk = gf100_clk(base); int ret; - if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || - (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || - (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || - (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || - (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || - (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) || - (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || - (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + if ((ret = calc_clk(clk, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(clk, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(clk, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(clk, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(clk, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(clk, cstate, 0x09, nv_clk_src_copy)) || + (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(clk, cstate, 0x0e, nv_clk_src_vdec))) return ret; return 0; } static void -gf100_clk_prog_0(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_0(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; - if (clk < 7 && !info->ssel) { - nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); - nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + struct gf100_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; + if (idx < 7 && !info->ssel) { + nvkm_mask(device, 0x1371d0 + (idx * 0x04), 0x80003f3f, info->ddiv); + nvkm_wr32(device, 0x137160 + (idx * 0x04), info->dsrc); } } static void -gf100_clk_prog_1(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_1(struct gf100_clk *clk, int idx) { - nv_mask(priv, 0x137100, (1 << clk), 0x00000000); - nv_wait(priv, 0x137100, (1 << clk), 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137100, (1 << idx), 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x137100) & (1 << idx))) + break; + ); } static void -gf100_clk_prog_2(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_2(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; - const u32 addr = 0x137000 + (clk * 0x20); - if (clk <= 7) { - nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + struct gf100_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; + const u32 addr = 0x137000 + (idx * 0x20); + if (idx <= 7) { + nvkm_mask(device, addr + 0x00, 0x00000004, 0x00000000); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000000); if (info->coef) { - nv_wr32(priv, addr + 0x04, info->coef); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + nvkm_wr32(device, addr + 0x04, info->coef); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, addr + 0x00) & 0x00020000) + break; + ); + nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); } } } static void -gf100_clk_prog_3(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_3(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; + struct gf100_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { - nv_mask(priv, 0x137100, (1 << clk), info->ssel); - nv_wait(priv, 0x137100, (1 << clk), info->ssel); + nvkm_mask(device, 0x137100, (1 << idx), info->ssel); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x137100) & (1 << idx); + if (tmp == info->ssel) + break; + ); } } static void -gf100_clk_prog_4(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_4(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; - nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); + struct gf100_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137250 + (idx * 0x04), 0x00003f3f, info->mdiv); } static int -gf100_clk_prog(struct nvkm_clk *clk) +gf100_clk_prog(struct nvkm_clk *base) { - struct gf100_clk_priv *priv = (void *)clk; + struct gf100_clk *clk = gf100_clk(base); struct { - void (*exec)(struct gf100_clk_priv *, int); + void (*exec)(struct gf100_clk *, int); } stage[] = { { gf100_clk_prog_0 }, /* div programming */ { gf100_clk_prog_1 }, /* select div mode */ @@ -396,10 +414,10 @@ gf100_clk_prog(struct nvkm_clk *clk) int i, j; for (i = 0; i < ARRAY_SIZE(stage); i++) { - for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { - if (!priv->eng[j].freq) + for (j = 0; j < ARRAY_SIZE(clk->eng); j++) { + if (!clk->eng[j].freq) continue; - stage[i].exec(priv, j); + stage[i].exec(clk, j); } } @@ -407,56 +425,42 @@ gf100_clk_prog(struct nvkm_clk *clk) } static void -gf100_clk_tidy(struct nvkm_clk *clk) +gf100_clk_tidy(struct nvkm_clk *base) { - struct gf100_clk_priv *priv = (void *)clk; - memset(priv->eng, 0x00, sizeof(priv->eng)); + struct gf100_clk *clk = gf100_clk(base); + memset(clk->eng, 0x00, sizeof(clk->eng)); } -static struct nvkm_domain -gf100_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_hubk06 , 0x00 }, - { nv_clk_src_hubk01 , 0x01 }, - { nv_clk_src_copy , 0x02 }, - { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, - { nv_clk_src_rop , 0x04 }, - { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0x06 }, - { nv_clk_src_daemon , 0x0a }, - { nv_clk_src_hubk07 , 0x0b }, - { nv_clk_src_max } +static const struct nvkm_clk_func +gf100_clk = { + .read = gf100_clk_read, + .calc = gf100_clk_calc, + .prog = gf100_clk_prog, + .tidy = gf100_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_hubk06 , 0x00 }, + { nv_clk_src_hubk01 , 0x01 }, + { nv_clk_src_copy , 0x02 }, + { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, + { nv_clk_src_rop , 0x04 }, + { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x0a }, + { nv_clk_src_hubk07 , 0x0b }, + { nv_clk_src_max } + } }; -static int -gf100_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct gf100_clk_priv *priv; - int ret; + struct gf100_clk *clk; - ret = nvkm_clk_create(parent, engine, oclass, gf100_domain, - NULL, 0, false, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - priv->base.read = gf100_clk_read; - priv->base.calc = gf100_clk_calc; - priv->base.prog = gf100_clk_prog; - priv->base.tidy = gf100_clk_tidy; - return 0; + return nvkm_clk_ctor(&gf100_clk, device, index, false, &clk->base); } - -struct nvkm_oclass -gf100_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index e9b2310bd..396f7e4da 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#include <subdev/clk.h> +#define gk104_clk(p) container_of((p), struct gk104_clk, base) +#include "priv.h" #include "pll.h" -#include <core/device.h> #include <subdev/timer.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> @@ -38,28 +38,30 @@ struct gk104_clk_info { u32 coef; }; -struct gk104_clk_priv { +struct gk104_clk { struct nvkm_clk base; struct gk104_clk_info eng[16]; }; -static u32 read_div(struct gk104_clk_priv *, int, u32, u32); -static u32 read_pll(struct gk104_clk_priv *, u32); +static u32 read_div(struct gk104_clk *, int, u32, u32); +static u32 read_pll(struct gk104_clk *, u32); static u32 -read_vco(struct gk104_clk_priv *priv, u32 dsrc) +read_vco(struct gk104_clk *clk, u32 dsrc) { - u32 ssrc = nv_rd32(priv, dsrc); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc); if (!(ssrc & 0x00000100)) - return read_pll(priv, 0x00e800); - return read_pll(priv, 0x00e820); + return read_pll(clk, 0x00e800); + return read_pll(clk, 0x00e820); } static u32 -read_pll(struct gk104_clk_priv *priv, u32 pll) +read_pll(struct gk104_clk *clk, u32 pll) { - u32 ctrl = nv_rd32(priv, pll + 0x00); - u32 coef = nv_rd32(priv, pll + 0x04); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, pll + 0x00); + u32 coef = nvkm_rd32(device, pll + 0x04); u32 P = (coef & 0x003f0000) >> 16; u32 N = (coef & 0x0000ff00) >> 8; u32 M = (coef & 0x000000ff) >> 0; @@ -72,22 +74,22 @@ read_pll(struct gk104_clk_priv *priv, u32 pll) switch (pll) { case 0x00e800: case 0x00e820: - sclk = nv_device(priv)->crystal; + sclk = device->crystal; P = 1; break; case 0x132000: - sclk = read_pll(priv, 0x132020); + sclk = read_pll(clk, 0x132020); P = (coef & 0x10000000) ? 2 : 1; break; case 0x132020: - sclk = read_div(priv, 0, 0x137320, 0x137330); - fN = nv_rd32(priv, pll + 0x10) >> 16; + sclk = read_div(clk, 0, 0x137320, 0x137330); + fN = nvkm_rd32(device, pll + 0x10) >> 16; break; case 0x137000: case 0x137020: case 0x137040: case 0x1370e0: - sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + sclk = read_div(clk, (pll & 0xff) / 0x20, 0x137120, 0x137140); break; default: return 0; @@ -101,70 +103,73 @@ read_pll(struct gk104_clk_priv *priv, u32 pll) } static u32 -read_div(struct gk104_clk_priv *priv, int doff, u32 dsrc, u32 dctl) +read_div(struct gk104_clk *clk, int doff, u32 dsrc, u32 dctl) { - u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); - u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc + (doff * 4)); + u32 sctl = nvkm_rd32(device, dctl + (doff * 4)); switch (ssrc & 0x00000003) { case 0: if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(priv)->crystal; + return device->crystal; return 108000; case 2: return 100000; case 3: if (sctl & 0x80000000) { - u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sclk = read_vco(clk, dsrc + (doff * 4)); u32 sdiv = (sctl & 0x0000003f) + 2; return (sclk * 2) / sdiv; } - return read_vco(priv, dsrc + (doff * 4)); + return read_vco(clk, dsrc + (doff * 4)); default: return 0; } } static u32 -read_mem(struct gk104_clk_priv *priv) +read_mem(struct gk104_clk *clk) { - switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) { - case 1: return read_pll(priv, 0x132020); - case 2: return read_pll(priv, 0x132000); + struct nvkm_device *device = clk->base.subdev.device; + switch (nvkm_rd32(device, 0x1373f4) & 0x0000000f) { + case 1: return read_pll(clk, 0x132020); + case 2: return read_pll(clk, 0x132000); default: return 0; } } static u32 -read_clk(struct gk104_clk_priv *priv, int clk) +read_clk(struct gk104_clk *clk, int idx) { - u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 sctl = nvkm_rd32(device, 0x137250 + (idx * 4)); u32 sclk, sdiv; - if (clk < 7) { - u32 ssel = nv_rd32(priv, 0x137100); - if (ssel & (1 << clk)) { - sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + if (idx < 7) { + u32 ssel = nvkm_rd32(device, 0x137100); + if (ssel & (1 << idx)) { + sclk = read_pll(clk, 0x137000 + (idx * 0x20)); sdiv = 1; } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); sdiv = 0; } } else { - u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04)); + u32 ssrc = nvkm_rd32(device, 0x137160 + (idx * 0x04)); if ((ssrc & 0x00000003) == 0x00000003) { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); if (ssrc & 0x00000100) { if (ssrc & 0x40000000) - sclk = read_pll(priv, 0x1370e0); + sclk = read_pll(clk, 0x1370e0); sdiv = 1; } else { sdiv = 0; } } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); sdiv = 0; } } @@ -181,10 +186,11 @@ read_clk(struct gk104_clk_priv *priv, int clk) } static int -gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gk104_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct nvkm_device *device = nv_device(clk); - struct gk104_clk_priv *priv = (void *)clk; + struct gk104_clk *clk = gk104_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; switch (src) { case nv_clk_src_crystal: @@ -192,29 +198,29 @@ gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) case nv_clk_src_href: return 100000; case nv_clk_src_mem: - return read_mem(priv); + return read_mem(clk); case nv_clk_src_gpc: - return read_clk(priv, 0x00); + return read_clk(clk, 0x00); case nv_clk_src_rop: - return read_clk(priv, 0x01); + return read_clk(clk, 0x01); case nv_clk_src_hubk07: - return read_clk(priv, 0x02); + return read_clk(clk, 0x02); case nv_clk_src_hubk06: - return read_clk(priv, 0x07); + return read_clk(clk, 0x07); case nv_clk_src_hubk01: - return read_clk(priv, 0x08); + return read_clk(clk, 0x08); case nv_clk_src_daemon: - return read_clk(priv, 0x0c); + return read_clk(clk, 0x0c); case nv_clk_src_vdec: - return read_clk(priv, 0x0e); + return read_clk(clk, 0x0e); default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } } static u32 -calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +calc_div(struct gk104_clk *clk, int idx, u32 ref, u32 freq, u32 *ddiv) { u32 div = min((ref * 2) / freq, (u32)65); if (div < 2) @@ -225,7 +231,7 @@ calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) } static u32 -calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +calc_src(struct gk104_clk *clk, int idx, u32 freq, u32 *dsrc, u32 *ddiv) { u32 sclk; @@ -247,28 +253,29 @@ calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) } /* otherwise, calculate the closest divider */ - sclk = read_vco(priv, 0x137160 + (clk * 4)); - if (clk < 7) - sclk = calc_div(priv, clk, sclk, freq, ddiv); + sclk = read_vco(clk, 0x137160 + (idx * 4)); + if (idx < 7) + sclk = calc_div(clk, idx, sclk, freq, ddiv); return sclk; } static u32 -calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef) +calc_pll(struct gk104_clk *clk, int idx, u32 freq, u32 *coef) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pll limits; int N, M, P, ret; - ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + ret = nvbios_pll_parse(bios, 0x137000 + (idx * 0x20), &limits); if (ret) return 0; - limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + limits.refclk = read_div(clk, idx, 0x137120, 0x137140); if (!limits.refclk) return 0; - ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + ret = gt215_pll_calc(subdev, &limits, freq, &N, NULL, &M, &P); if (ret <= 0) return 0; @@ -277,10 +284,10 @@ calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef) } static int -calc_clk(struct gk104_clk_priv *priv, - struct nvkm_cstate *cstate, int clk, int dom) +calc_clk(struct gk104_clk *clk, + struct nvkm_cstate *cstate, int idx, int dom) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; u32 freq = cstate->domain[dom]; u32 src0, div0, div1D, div1P = 0; u32 clk0, clk1 = 0; @@ -290,16 +297,16 @@ calc_clk(struct gk104_clk_priv *priv, return 0; /* first possible path, using only dividers */ - clk0 = calc_src(priv, clk, freq, &src0, &div0); - clk0 = calc_div(priv, clk, clk0, freq, &div1D); + clk0 = calc_src(clk, idx, freq, &src0, &div0); + clk0 = calc_div(clk, idx, clk0, freq, &div1D); /* see if we can get any closer using PLLs */ - if (clk0 != freq && (0x0000ff87 & (1 << clk))) { - if (clk <= 7) - clk1 = calc_pll(priv, clk, freq, &info->coef); + if (clk0 != freq && (0x0000ff87 & (1 << idx))) { + if (idx <= 7) + clk1 = calc_pll(clk, idx, freq, &info->coef); else clk1 = cstate->domain[nv_clk_src_hubk06]; - clk1 = calc_div(priv, clk, clk1, freq, &div1P); + clk1 = calc_div(clk, idx, clk1, freq, &div1P); } /* select the method which gets closest to target freq */ @@ -320,7 +327,7 @@ calc_clk(struct gk104_clk_priv *priv, info->mdiv |= 0x80000000; info->mdiv |= div1P << 8; } - info->ssel = (1 << clk); + info->ssel = (1 << idx); info->dsrc = 0x40000100; info->freq = clk1; } @@ -329,98 +336,115 @@ calc_clk(struct gk104_clk_priv *priv, } static int -gk104_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gk104_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gk104_clk_priv *priv = (void *)clk; + struct gk104_clk *clk = gk104_clk(base); int ret; - if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || - (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || - (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || - (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || - (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || - (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || - (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + if ((ret = calc_clk(clk, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(clk, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(clk, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(clk, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(clk, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(clk, cstate, 0x0e, nv_clk_src_vdec))) return ret; return 0; } static void -gk104_clk_prog_0(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_0(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (!info->ssel) { - nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv); - nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + nvkm_mask(device, 0x1371d0 + (idx * 0x04), 0x8000003f, info->ddiv); + nvkm_wr32(device, 0x137160 + (idx * 0x04), info->dsrc); } } static void -gk104_clk_prog_1_0(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_1_0(struct gk104_clk *clk, int idx) { - nv_mask(priv, 0x137100, (1 << clk), 0x00000000); - nv_wait(priv, 0x137100, (1 << clk), 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137100, (1 << idx), 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x137100) & (1 << idx))) + break; + ); } static void -gk104_clk_prog_1_1(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_1_1(struct gk104_clk *clk, int idx) { - nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137160 + (idx * 0x04), 0x00000100, 0x00000000); } static void -gk104_clk_prog_2(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_2(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; - const u32 addr = 0x137000 + (clk * 0x20); - nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; + const u32 addr = 0x137000 + (idx * 0x20); + nvkm_mask(device, addr + 0x00, 0x00000004, 0x00000000); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000000); if (info->coef) { - nv_wr32(priv, addr + 0x04, info->coef); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + nvkm_wr32(device, addr + 0x04, info->coef); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, addr + 0x00) & 0x00020000) + break; + ); + nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); } } static void -gk104_clk_prog_3(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_3(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) - nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv); + nvkm_mask(device, 0x137250 + (idx * 0x04), 0x00003f00, info->mdiv); else - nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv); + nvkm_mask(device, 0x137250 + (idx * 0x04), 0x0000003f, info->mdiv); } static void -gk104_clk_prog_4_0(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_4_0(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { - nv_mask(priv, 0x137100, (1 << clk), info->ssel); - nv_wait(priv, 0x137100, (1 << clk), info->ssel); + nvkm_mask(device, 0x137100, (1 << idx), info->ssel); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x137100) & (1 << idx); + if (tmp == info->ssel) + break; + ); } } static void -gk104_clk_prog_4_1(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_4_1(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { - nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000); - nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100); + nvkm_mask(device, 0x137160 + (idx * 0x04), 0x40000000, 0x40000000); + nvkm_mask(device, 0x137160 + (idx * 0x04), 0x00000100, 0x00000100); } } static int -gk104_clk_prog(struct nvkm_clk *clk) +gk104_clk_prog(struct nvkm_clk *base) { - struct gk104_clk_priv *priv = (void *)clk; + struct gk104_clk *clk = gk104_clk(base); struct { u32 mask; - void (*exec)(struct gk104_clk_priv *, int); + void (*exec)(struct gk104_clk *, int); } stage[] = { { 0x007f, gk104_clk_prog_0 }, /* div programming */ { 0x007f, gk104_clk_prog_1_0 }, /* select div mode */ @@ -433,12 +457,12 @@ gk104_clk_prog(struct nvkm_clk *clk) int i, j; for (i = 0; i < ARRAY_SIZE(stage); i++) { - for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { + for (j = 0; j < ARRAY_SIZE(clk->eng); j++) { if (!(stage[i].mask & (1 << j))) continue; - if (!priv->eng[j].freq) + if (!clk->eng[j].freq) continue; - stage[i].exec(priv, j); + stage[i].exec(clk, j); } } @@ -446,55 +470,41 @@ gk104_clk_prog(struct nvkm_clk *clk) } static void -gk104_clk_tidy(struct nvkm_clk *clk) +gk104_clk_tidy(struct nvkm_clk *base) { - struct gk104_clk_priv *priv = (void *)clk; - memset(priv->eng, 0x00, sizeof(priv->eng)); + struct gk104_clk *clk = gk104_clk(base); + memset(clk->eng, 0x00, sizeof(clk->eng)); } -static struct nvkm_domain -gk104_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, - { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_mem , 0x03, 0, "memory", 500 }, - { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_hubk01 , 0x05 }, - { nv_clk_src_vdec , 0x06 }, - { nv_clk_src_daemon , 0x07 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +gk104_clk = { + .read = gk104_clk_read, + .calc = gk104_clk_calc, + .prog = gk104_clk_prog, + .tidy = gk104_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, + { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_mem , 0x03, 0, "memory", 500 }, + { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_hubk01 , 0x05 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x07 }, + { nv_clk_src_max } + } }; -static int -gk104_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct gk104_clk_priv *priv; - int ret; + struct gk104_clk *clk; - ret = nvkm_clk_create(parent, engine, oclass, gk104_domain, - NULL, 0, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - priv->base.read = gk104_clk_read; - priv->base.calc = gk104_clk_calc; - priv->base.prog = gk104_clk_prog; - priv->base.tidy = gk104_clk_tidy; - return 0; + return nvkm_clk_ctor(&gk104_clk, device, index, true, &clk->base); } - -struct nvkm_oclass -gk104_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 65c532742..254094ab7 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -22,14 +22,11 @@ * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c * */ -#include <subdev/clk.h> -#include <subdev/timer.h> - -#include <core/device.h> +#define gk20a_clk(p) container_of((p), struct gk20a_clk, base) +#include "priv.h" -#ifdef __KERNEL__ -#include <nouveau_platform.h> -#endif +#include <core/tegra.h> +#include <subdev/timer.h> #define MHZ (1000 * 1000) @@ -117,41 +114,42 @@ static const struct gk20a_clk_pllg_params gk20a_pllg_params = { .min_pl = 1, .max_pl = 32, }; -struct gk20a_clk_priv { +struct gk20a_clk { struct nvkm_clk base; const struct gk20a_clk_pllg_params *params; u32 m, n, pl; u32 parent_rate; }; -#define to_gk20a_clk(base) container_of(base, struct gk20a_clk_priv, base) static void -gk20a_pllg_read_mnp(struct gk20a_clk_priv *priv) +gk20a_pllg_read_mnp(struct gk20a_clk *clk) { + struct nvkm_device *device = clk->base.subdev.device; u32 val; - val = nv_rd32(priv, GPCPLL_COEFF); - priv->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); - priv->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH); - priv->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); + val = nvkm_rd32(device, GPCPLL_COEFF); + clk->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); + clk->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH); + clk->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); } static u32 -gk20a_pllg_calc_rate(struct gk20a_clk_priv *priv) +gk20a_pllg_calc_rate(struct gk20a_clk *clk) { u32 rate; u32 divider; - rate = priv->parent_rate * priv->n; - divider = priv->m * pl_to_div[priv->pl]; + rate = clk->parent_rate * clk->n; + divider = clk->m * pl_to_div[clk->pl]; do_div(rate, divider); return rate / 2; } static int -gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) +gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) { + struct nvkm_subdev *subdev = &clk->base.subdev; u32 target_clk_f, ref_clk_f, target_freq; u32 min_vco_f, max_vco_f; u32 low_pl, high_pl, best_pl; @@ -163,13 +161,13 @@ gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) u32 pl; target_clk_f = rate * 2 / MHZ; - ref_clk_f = priv->parent_rate / MHZ; + ref_clk_f = clk->parent_rate / MHZ; - max_vco_f = priv->params->max_vco; - min_vco_f = priv->params->min_vco; - best_m = priv->params->max_m; - best_n = priv->params->min_n; - best_pl = priv->params->min_pl; + max_vco_f = clk->params->max_vco; + min_vco_f = clk->params->min_vco; + best_m = clk->params->max_m; + best_n = clk->params->min_n; + best_pl = clk->params->min_pl; target_vco_f = target_clk_f + target_clk_f / 50; if (max_vco_f < target_vco_f) @@ -177,13 +175,13 @@ gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) /* min_pl <= high_pl <= max_pl */ high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f; - high_pl = min(high_pl, priv->params->max_pl); - high_pl = max(high_pl, priv->params->min_pl); + high_pl = min(high_pl, clk->params->max_pl); + high_pl = max(high_pl, clk->params->min_pl); /* min_pl <= low_pl <= max_pl */ low_pl = min_vco_f / target_vco_f; - low_pl = min(low_pl, priv->params->max_pl); - low_pl = max(low_pl, priv->params->min_pl); + low_pl = min(low_pl, clk->params->max_pl); + low_pl = max(low_pl, clk->params->min_pl); /* Find Indices of high_pl and low_pl */ for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) { @@ -199,30 +197,30 @@ gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) } } - nv_debug(priv, "low_PL %d(div%d), high_PL %d(div%d)", low_pl, - pl_to_div[low_pl], high_pl, pl_to_div[high_pl]); + nvkm_debug(subdev, "low_PL %d(div%d), high_PL %d(div%d)", low_pl, + pl_to_div[low_pl], high_pl, pl_to_div[high_pl]); /* Select lowest possible VCO */ for (pl = low_pl; pl <= high_pl; pl++) { target_vco_f = target_clk_f * pl_to_div[pl]; - for (m = priv->params->min_m; m <= priv->params->max_m; m++) { + for (m = clk->params->min_m; m <= clk->params->max_m; m++) { u_f = ref_clk_f / m; - if (u_f < priv->params->min_u) + if (u_f < clk->params->min_u) break; - if (u_f > priv->params->max_u) + if (u_f > clk->params->max_u) continue; n = (target_vco_f * m) / ref_clk_f; n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f; - if (n > priv->params->max_n) + if (n > clk->params->max_n) break; for (; n <= n2; n++) { - if (n < priv->params->min_n) + if (n < clk->params->min_n) continue; - if (n > priv->params->max_n) + if (n > clk->params->max_n) break; vco_f = ref_clk_f * n / m; @@ -250,71 +248,75 @@ found_match: WARN_ON(best_delta == ~0); if (best_delta != 0) - nv_debug(priv, "no best match for target @ %dMHz on gpc_pll", - target_clk_f); + nvkm_debug(subdev, + "no best match for target @ %dMHz on gpc_pll", + target_clk_f); - priv->m = best_m; - priv->n = best_n; - priv->pl = best_pl; + clk->m = best_m; + clk->n = best_n; + clk->pl = best_pl; - target_freq = gk20a_pllg_calc_rate(priv) / MHZ; + target_freq = gk20a_pllg_calc_rate(clk) / MHZ; - nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", - target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]); + nvkm_debug(subdev, + "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", + target_freq, clk->m, clk->n, clk->pl, pl_to_div[clk->pl]); return 0; } static int -gk20a_pllg_slide(struct gk20a_clk_priv *priv, u32 n) +gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) { + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 val; int ramp_timeout; /* get old coefficients */ - val = nv_rd32(priv, GPCPLL_COEFF); + val = nvkm_rd32(device, GPCPLL_COEFF); /* do nothing if NDIV is the same */ if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH))) return 0; /* setup */ - nv_mask(priv, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, + nvkm_mask(device, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, 0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT); - nv_mask(priv, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, + nvkm_mask(device, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, 0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT); /* pll slowdown mode */ - nv_mask(priv, GPCPLL_NDIV_SLOWDOWN, + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT), BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT)); /* new ndiv ready for ramp */ - val = nv_rd32(priv, GPCPLL_COEFF); + val = nvkm_rd32(device, GPCPLL_COEFF); val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT); val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT; udelay(1); - nv_wr32(priv, GPCPLL_COEFF, val); + nvkm_wr32(device, GPCPLL_COEFF, val); /* dynamic ramp to new ndiv */ - val = nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN); + val = nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT; udelay(1); - nv_wr32(priv, GPCPLL_NDIV_SLOWDOWN, val); + nvkm_wr32(device, GPCPLL_NDIV_SLOWDOWN, val); for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) { udelay(1); - val = nv_rd32(priv, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); + val = nvkm_rd32(device, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK) break; } /* exit slowdown mode */ - nv_mask(priv, GPCPLL_NDIV_SLOWDOWN, + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) | BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0); - nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN); + nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); if (ramp_timeout <= 0) { - nv_error(priv, "gpcpll dynamic ramp timeout\n"); + nvkm_error(subdev, "gpcpll dynamic ramp timeout\n"); return -ETIMEDOUT; } @@ -322,149 +324,147 @@ gk20a_pllg_slide(struct gk20a_clk_priv *priv, u32 n) } static void -_gk20a_pllg_enable(struct gk20a_clk_priv *priv) +_gk20a_pllg_enable(struct gk20a_clk *clk) { - nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); - nv_rd32(priv, GPCPLL_CFG); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); + nvkm_rd32(device, GPCPLL_CFG); } static void -_gk20a_pllg_disable(struct gk20a_clk_priv *priv) +_gk20a_pllg_disable(struct gk20a_clk *clk) { - nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); - nv_rd32(priv, GPCPLL_CFG); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); + nvkm_rd32(device, GPCPLL_CFG); } static int -_gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv, bool allow_slide) +_gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) { + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 val, cfg; u32 m_old, pl_old, n_lo; /* get old coefficients */ - val = nv_rd32(priv, GPCPLL_COEFF); + val = nvkm_rd32(device, GPCPLL_COEFF); m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); /* do NDIV slide if there is no change in M and PL */ - cfg = nv_rd32(priv, GPCPLL_CFG); - if (allow_slide && priv->m == m_old && priv->pl == pl_old && + cfg = nvkm_rd32(device, GPCPLL_CFG); + if (allow_slide && clk->m == m_old && clk->pl == pl_old && (cfg & GPCPLL_CFG_ENABLE)) { - return gk20a_pllg_slide(priv, priv->n); + return gk20a_pllg_slide(clk, clk->n); } /* slide down to NDIV_LO */ - n_lo = DIV_ROUND_UP(m_old * priv->params->min_vco, - priv->parent_rate / MHZ); + n_lo = DIV_ROUND_UP(m_old * clk->params->min_vco, + clk->parent_rate / MHZ); if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) { - int ret = gk20a_pllg_slide(priv, n_lo); + int ret = gk20a_pllg_slide(clk, n_lo); if (ret) return ret; } /* split FO-to-bypass jump in halfs by setting out divider 1:2 */ - nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, 0x2 << GPC2CLK_OUT_VCODIV_SHIFT); /* put PLL in bypass before programming it */ - val = nv_rd32(priv, SEL_VCO); + val = nvkm_rd32(device, SEL_VCO); val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); udelay(2); - nv_wr32(priv, SEL_VCO, val); + nvkm_wr32(device, SEL_VCO, val); /* get out from IDDQ */ - val = nv_rd32(priv, GPCPLL_CFG); + val = nvkm_rd32(device, GPCPLL_CFG); if (val & GPCPLL_CFG_IDDQ) { val &= ~GPCPLL_CFG_IDDQ; - nv_wr32(priv, GPCPLL_CFG, val); - nv_rd32(priv, GPCPLL_CFG); + nvkm_wr32(device, GPCPLL_CFG, val); + nvkm_rd32(device, GPCPLL_CFG); udelay(2); } - _gk20a_pllg_disable(priv); + _gk20a_pllg_disable(clk); - nv_debug(priv, "%s: m=%d n=%d pl=%d\n", __func__, priv->m, priv->n, - priv->pl); + nvkm_debug(subdev, "%s: m=%d n=%d pl=%d\n", __func__, + clk->m, clk->n, clk->pl); - n_lo = DIV_ROUND_UP(priv->m * priv->params->min_vco, - priv->parent_rate / MHZ); - val = priv->m << GPCPLL_COEFF_M_SHIFT; - val |= (allow_slide ? n_lo : priv->n) << GPCPLL_COEFF_N_SHIFT; - val |= priv->pl << GPCPLL_COEFF_P_SHIFT; - nv_wr32(priv, GPCPLL_COEFF, val); + n_lo = DIV_ROUND_UP(clk->m * clk->params->min_vco, + clk->parent_rate / MHZ); + val = clk->m << GPCPLL_COEFF_M_SHIFT; + val |= (allow_slide ? n_lo : clk->n) << GPCPLL_COEFF_N_SHIFT; + val |= clk->pl << GPCPLL_COEFF_P_SHIFT; + nvkm_wr32(device, GPCPLL_COEFF, val); - _gk20a_pllg_enable(priv); + _gk20a_pllg_enable(clk); - val = nv_rd32(priv, GPCPLL_CFG); + val = nvkm_rd32(device, GPCPLL_CFG); if (val & GPCPLL_CFG_LOCK_DET_OFF) { val &= ~GPCPLL_CFG_LOCK_DET_OFF; - nv_wr32(priv, GPCPLL_CFG, val); + nvkm_wr32(device, GPCPLL_CFG, val); } - if (!nvkm_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, - GPCPLL_CFG_LOCK)) { - nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__); + if (nvkm_usec(device, 300, + if (nvkm_rd32(device, GPCPLL_CFG) & GPCPLL_CFG_LOCK) + break; + ) < 0) return -ETIMEDOUT; - } /* switch to VCO mode */ - nv_mask(priv, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); + nvkm_mask(device, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); /* restore out divider 1:1 */ - val = nv_rd32(priv, GPC2CLK_OUT); + val = nvkm_rd32(device, GPC2CLK_OUT); val &= ~GPC2CLK_OUT_VCODIV_MASK; udelay(2); - nv_wr32(priv, GPC2CLK_OUT, val); + nvkm_wr32(device, GPC2CLK_OUT, val); /* slide up to new NDIV */ - return allow_slide ? gk20a_pllg_slide(priv, priv->n) : 0; + return allow_slide ? gk20a_pllg_slide(clk, clk->n) : 0; } static int -gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv) +gk20a_pllg_program_mnp(struct gk20a_clk *clk) { int err; - err = _gk20a_pllg_program_mnp(priv, true); + err = _gk20a_pllg_program_mnp(clk, true); if (err) - err = _gk20a_pllg_program_mnp(priv, false); + err = _gk20a_pllg_program_mnp(clk, false); return err; } static void -gk20a_pllg_disable(struct gk20a_clk_priv *priv) +gk20a_pllg_disable(struct gk20a_clk *clk) { + struct nvkm_device *device = clk->base.subdev.device; u32 val; /* slide to VCO min */ - val = nv_rd32(priv, GPCPLL_CFG); + val = nvkm_rd32(device, GPCPLL_CFG); if (val & GPCPLL_CFG_ENABLE) { u32 coeff, m, n_lo; - coeff = nv_rd32(priv, GPCPLL_COEFF); + coeff = nvkm_rd32(device, GPCPLL_COEFF); m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); - n_lo = DIV_ROUND_UP(m * priv->params->min_vco, - priv->parent_rate / MHZ); - gk20a_pllg_slide(priv, n_lo); + n_lo = DIV_ROUND_UP(m * clk->params->min_vco, + clk->parent_rate / MHZ); + gk20a_pllg_slide(clk, n_lo); } /* put PLL in bypass before disabling it */ - nv_mask(priv, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); + nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); - _gk20a_pllg_disable(priv); + _gk20a_pllg_disable(clk); } #define GK20A_CLK_GPC_MDIV 1000 -static struct nvkm_domain -gk20a_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, - { nv_clk_src_max } -}; - static struct nvkm_pstate gk20a_pstates[] = { { @@ -560,87 +560,99 @@ gk20a_pstates[] = { }; static int -gk20a_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gk20a_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct gk20a_clk_priv *priv = (void *)clk; + struct gk20a_clk *clk = gk20a_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; switch (src) { case nv_clk_src_crystal: - return nv_device(clk)->crystal; + return device->crystal; case nv_clk_src_gpc: - gk20a_pllg_read_mnp(priv); - return gk20a_pllg_calc_rate(priv) / GK20A_CLK_GPC_MDIV; + gk20a_pllg_read_mnp(clk); + return gk20a_pllg_calc_rate(clk) / GK20A_CLK_GPC_MDIV; default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } } static int -gk20a_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gk20a_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gk20a_clk_priv *priv = (void *)clk; + struct gk20a_clk *clk = gk20a_clk(base); - return gk20a_pllg_calc_mnp(priv, cstate->domain[nv_clk_src_gpc] * + return gk20a_pllg_calc_mnp(clk, cstate->domain[nv_clk_src_gpc] * GK20A_CLK_GPC_MDIV); } static int -gk20a_clk_prog(struct nvkm_clk *clk) +gk20a_clk_prog(struct nvkm_clk *base) { - struct gk20a_clk_priv *priv = (void *)clk; + struct gk20a_clk *clk = gk20a_clk(base); - return gk20a_pllg_program_mnp(priv); + return gk20a_pllg_program_mnp(clk); } static void -gk20a_clk_tidy(struct nvkm_clk *clk) +gk20a_clk_tidy(struct nvkm_clk *base) { } -static int -gk20a_clk_fini(struct nvkm_object *object, bool suspend) +static void +gk20a_clk_fini(struct nvkm_clk *base) { - struct gk20a_clk_priv *priv = (void *)object; - int ret; - - ret = nvkm_clk_fini(&priv->base, false); - - gk20a_pllg_disable(priv); - - return ret; + struct gk20a_clk *clk = gk20a_clk(base); + gk20a_pllg_disable(clk); } static int -gk20a_clk_init(struct nvkm_object *object) +gk20a_clk_init(struct nvkm_clk *base) { - struct gk20a_clk_priv *priv = (void *)object; + struct gk20a_clk *clk = gk20a_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; int ret; - nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); - - ret = nvkm_clk_init(&priv->base); - if (ret) - return ret; + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); - ret = gk20a_clk_prog(&priv->base); + ret = gk20a_clk_prog(&clk->base); if (ret) { - nv_error(priv, "cannot initialize clock\n"); + nvkm_error(subdev, "cannot initialize clock\n"); return ret; } return 0; } -static int -gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_clk_func +gk20a_clk = { + .init = gk20a_clk_init, + .fini = gk20a_clk_fini, + .read = gk20a_clk_read, + .calc = gk20a_clk_calc, + .prog = gk20a_clk_prog, + .tidy = gk20a_clk_tidy, + .pstates = gk20a_pstates, + .nr_pstates = ARRAY_SIZE(gk20a_pstates), + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, + { nv_clk_src_max } + } +}; + +int +gk20a_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct gk20a_clk_priv *priv; - struct nouveau_platform_device *plat; - int ret; - int i; + struct nvkm_device_tegra *tdev = device->func->tegra(device); + struct gk20a_clk *clk; + int ret, i; + + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; /* Finish initializing the pstates */ for (i = 0; i < ARRAY_SIZE(gk20a_pstates); i++) { @@ -648,33 +660,11 @@ gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, gk20a_pstates[i].pstate = i + 1; } - ret = nvkm_clk_create(parent, engine, oclass, gk20a_domains, - gk20a_pstates, ARRAY_SIZE(gk20a_pstates), - true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + clk->params = &gk20a_pllg_params; + clk->parent_rate = clk_get_rate(tdev->clk); - priv->params = &gk20a_pllg_params; - - plat = nv_device_to_platform(nv_device(parent)); - priv->parent_rate = clk_get_rate(plat->gpu->clk); - nv_info(priv, "parent clock rate: %d Mhz\n", priv->parent_rate / MHZ); - - priv->base.read = gk20a_clk_read; - priv->base.calc = gk20a_clk_calc; - priv->base.prog = gk20a_clk_prog; - priv->base.tidy = gk20a_clk_tidy; - return 0; + ret = nvkm_clk_ctor(&gk20a_clk, device, index, true, &clk->base); + nvkm_info(&clk->base.subdev, "parent clock rate: %d Mhz\n", + clk->parent_rate / MHZ); + return ret; } - -struct nvkm_oclass -gk20a_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_clk_ctor, - .dtor = _nvkm_subdev_dtor, - .init = gk20a_clk_init, - .fini = gk20a_clk_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 822d32a28..c233e3f65 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -22,56 +22,58 @@ * Authors: Ben Skeggs * Roy Spliet */ +#define gt215_clk(p) container_of((p), struct gt215_clk, base) #include "gt215.h" #include "pll.h" -#include <core/device.h> #include <engine/fifo.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> #include <subdev/timer.h> -struct gt215_clk_priv { +struct gt215_clk { struct nvkm_clk base; struct gt215_clk_info eng[nv_clk_src_max]; }; -static u32 read_clk(struct gt215_clk_priv *, int, bool); -static u32 read_pll(struct gt215_clk_priv *, int, u32); +static u32 read_clk(struct gt215_clk *, int, bool); +static u32 read_pll(struct gt215_clk *, int, u32); static u32 -read_vco(struct gt215_clk_priv *priv, int clk) +read_vco(struct gt215_clk *clk, int idx) { - u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 sctl = nvkm_rd32(device, 0x4120 + (idx * 4)); switch (sctl & 0x00000030) { case 0x00000000: - return nv_device(priv)->crystal; + return device->crystal; case 0x00000020: - return read_pll(priv, 0x41, 0x00e820); + return read_pll(clk, 0x41, 0x00e820); case 0x00000030: - return read_pll(priv, 0x42, 0x00e8a0); + return read_pll(clk, 0x42, 0x00e8a0); default: return 0; } } static u32 -read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) +read_clk(struct gt215_clk *clk, int idx, bool ignore_en) { + struct nvkm_device *device = clk->base.subdev.device; u32 sctl, sdiv, sclk; /* refclk for the 0xe8xx plls is a fixed frequency */ - if (clk >= 0x40) { - if (nv_device(priv)->chipset == 0xaf) { + if (idx >= 0x40) { + if (device->chipset == 0xaf) { /* no joke.. seriously.. sigh.. */ - return nv_rd32(priv, 0x00471c) * 1000; + return nvkm_rd32(device, 0x00471c) * 1000; } - return nv_device(priv)->crystal; + return device->crystal; } - sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + sctl = nvkm_rd32(device, 0x4120 + (idx * 4)); if (!ignore_en && !(sctl & 0x00000100)) return 0; @@ -83,7 +85,7 @@ read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) switch (sctl & 0x00003000) { case 0x00000000: if (!(sctl & 0x00000200)) - return nv_device(priv)->crystal; + return device->crystal; return 0; case 0x00002000: if (sctl & 0x00000040) @@ -94,7 +96,7 @@ read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) if (!(sctl & 0x00000001)) return 0; - sclk = read_vco(priv, clk); + sclk = read_vco(clk, idx); sdiv = ((sctl & 0x003f0000) >> 16) + 2; return (sclk * 2) / sdiv; default: @@ -103,14 +105,15 @@ read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) } static u32 -read_pll(struct gt215_clk_priv *priv, int clk, u32 pll) +read_pll(struct gt215_clk *clk, int idx, u32 pll) { - u32 ctrl = nv_rd32(priv, pll + 0); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, pll + 0); u32 sclk = 0, P = 1, N = 1, M = 1; if (!(ctrl & 0x00000008)) { if (ctrl & 0x00000001) { - u32 coef = nv_rd32(priv, pll + 4); + u32 coef = nvkm_rd32(device, pll + 4); M = (coef & 0x000000ff) >> 0; N = (coef & 0x0000ff00) >> 8; P = (coef & 0x003f0000) >> 16; @@ -121,10 +124,10 @@ read_pll(struct gt215_clk_priv *priv, int clk, u32 pll) if ((pll & 0x00ff00) == 0x00e800) P = 1; - sclk = read_clk(priv, 0x00 + clk, false); + sclk = read_clk(clk, 0x00 + idx, false); } } else { - sclk = read_clk(priv, 0x10 + clk, false); + sclk = read_clk(clk, 0x10 + idx, false); } if (M * P) @@ -134,41 +137,43 @@ read_pll(struct gt215_clk_priv *priv, int clk, u32 pll) } static int -gt215_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gt215_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct gt215_clk_priv *priv = (void *)clk; + struct gt215_clk *clk = gt215_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 hsrc; switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return device->crystal; case nv_clk_src_core: case nv_clk_src_core_intm: - return read_pll(priv, 0x00, 0x4200); + return read_pll(clk, 0x00, 0x4200); case nv_clk_src_shader: - return read_pll(priv, 0x01, 0x4220); + return read_pll(clk, 0x01, 0x4220); case nv_clk_src_mem: - return read_pll(priv, 0x02, 0x4000); + return read_pll(clk, 0x02, 0x4000); case nv_clk_src_disp: - return read_clk(priv, 0x20, false); + return read_clk(clk, 0x20, false); case nv_clk_src_vdec: - return read_clk(priv, 0x21, false); + return read_clk(clk, 0x21, false); case nv_clk_src_daemon: - return read_clk(priv, 0x25, false); + return read_clk(clk, 0x25, false); case nv_clk_src_host: - hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28; + hsrc = (nvkm_rd32(device, 0xc040) & 0x30000000) >> 28; switch (hsrc) { case 0: - return read_clk(priv, 0x1d, false); + return read_clk(clk, 0x1d, false); case 2: case 3: return 277000; default: - nv_error(clk, "unknown HOST clock source %d\n", hsrc); + nvkm_error(subdev, "unknown HOST clock source %d\n", hsrc); return -EINVAL; } default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } @@ -176,11 +181,12 @@ gt215_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) } int -gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz, +gt215_clk_info(struct nvkm_clk *base, int idx, u32 khz, struct gt215_clk_info *info) { - struct gt215_clk_priv *priv = (void *)clock; - u32 oclk, sclk, sdiv, diff; + struct gt215_clk *clk = gt215_clk(base); + u32 oclk, sclk, sdiv; + s32 diff; info->clk = 0; @@ -195,7 +201,7 @@ gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz, info->clk = 0x00002140; return khz; default: - sclk = read_vco(priv, clk); + sclk = read_vco(clk, idx); sdiv = min((sclk * 2) / khz, (u32)65); oclk = (sclk * 2) / sdiv; diff = ((khz + 3000) - oclk); @@ -223,11 +229,11 @@ gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz, } int -gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz, +gt215_pll_info(struct nvkm_clk *base, int idx, u32 pll, u32 khz, struct gt215_clk_info *info) { - struct nvkm_bios *bios = nvkm_bios(clock); - struct gt215_clk_priv *priv = (void *)clock; + struct gt215_clk *clk = gt215_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll limits; int P, N, M, diff; int ret; @@ -236,22 +242,22 @@ gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz, /* If we can get a within [-2, 3) MHz of a divider, we'll disable the * PLL and use the divider instead. */ - ret = gt215_clk_info(clock, clk, khz, info); + ret = gt215_clk_info(&clk->base, idx, khz, info); diff = khz - ret; if (!pll || (diff >= -2000 && diff < 3000)) { goto out; } /* Try with PLL */ - ret = nvbios_pll_parse(bios, pll, &limits); + ret = nvbios_pll_parse(subdev->device->bios, pll, &limits); if (ret) return ret; - ret = gt215_clk_info(clock, clk - 0x10, limits.refclk, info); + ret = gt215_clk_info(&clk->base, idx - 0x10, limits.refclk, info); if (ret != limits.refclk) return -EINVAL; - ret = gt215_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); + ret = gt215_pll_calc(subdev, &limits, khz, &N, NULL, &M, &P); if (ret >= 0) { info->pll = (P << 16) | (N << 8) | M; } @@ -262,22 +268,22 @@ out: } static int -calc_clk(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate, - int clk, u32 pll, int idx) +calc_clk(struct gt215_clk *clk, struct nvkm_cstate *cstate, + int idx, u32 pll, int dom) { - int ret = gt215_pll_info(&priv->base, clk, pll, cstate->domain[idx], - &priv->eng[idx]); + int ret = gt215_pll_info(&clk->base, idx, pll, cstate->domain[dom], + &clk->eng[dom]); if (ret >= 0) return 0; return ret; } static int -calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate) +calc_host(struct gt215_clk *clk, struct nvkm_cstate *cstate) { int ret = 0; u32 kHz = cstate->domain[nv_clk_src_host]; - struct gt215_clk_info *info = &priv->eng[nv_clk_src_host]; + struct gt215_clk_info *info = &clk->eng[nv_clk_src_host]; if (kHz == 277000) { info->clk = 0; @@ -287,7 +293,7 @@ calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate) info->host_out = NVA3_HOST_CLK; - ret = gt215_clk_info(&priv->base, 0x1d, kHz, info); + ret = gt215_clk_info(&clk->base, 0x1d, kHz, info); if (ret >= 0) return 0; @@ -297,21 +303,33 @@ calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate) int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) { - struct nvkm_fifo *pfifo = nvkm_fifo(clk); + struct nvkm_device *device = clk->subdev.device; + struct nvkm_fifo *fifo = device->fifo; /* halt and idle execution engines */ - nv_mask(clk, 0x020060, 0x00070000, 0x00000000); - nv_mask(clk, 0x002504, 0x00000001, 0x00000001); + nvkm_mask(device, 0x020060, 0x00070000, 0x00000000); + nvkm_mask(device, 0x002504, 0x00000001, 0x00000001); /* Wait until the interrupt handler is finished */ - if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) + if (nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x000100)) + break; + ) < 0) return -EBUSY; - if (pfifo) - pfifo->pause(pfifo, flags); + if (fifo) + nvkm_fifo_pause(fifo, flags); - if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x002504) & 0x00000010) + break; + ) < 0) return -EIO; - if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) + + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x00251c) & 0x0000003f; + if (tmp == 0x0000003f) + break; + ) < 0) return -EIO; return 0; @@ -320,86 +338,94 @@ gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags) { - struct nvkm_fifo *pfifo = nvkm_fifo(clk); + struct nvkm_device *device = clk->subdev.device; + struct nvkm_fifo *fifo = device->fifo; - if (pfifo && flags) - pfifo->start(pfifo, flags); + if (fifo && flags) + nvkm_fifo_start(fifo, flags); - nv_mask(clk, 0x002504, 0x00000001, 0x00000000); - nv_mask(clk, 0x020060, 0x00070000, 0x00040000); + nvkm_mask(device, 0x002504, 0x00000001, 0x00000000); + nvkm_mask(device, 0x020060, 0x00070000, 0x00040000); } static void -disable_clk_src(struct gt215_clk_priv *priv, u32 src) +disable_clk_src(struct gt215_clk *clk, u32 src) { - nv_mask(priv, src, 0x00000100, 0x00000000); - nv_mask(priv, src, 0x00000001, 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, src, 0x00000100, 0x00000000); + nvkm_mask(device, src, 0x00000001, 0x00000000); } static void -prog_pll(struct gt215_clk_priv *priv, int clk, u32 pll, int idx) +prog_pll(struct gt215_clk *clk, int idx, u32 pll, int dom) { - struct gt215_clk_info *info = &priv->eng[idx]; - const u32 src0 = 0x004120 + (clk * 4); - const u32 src1 = 0x004160 + (clk * 4); + struct gt215_clk_info *info = &clk->eng[dom]; + struct nvkm_device *device = clk->base.subdev.device; + const u32 src0 = 0x004120 + (idx * 4); + const u32 src1 = 0x004160 + (idx * 4); const u32 ctrl = pll + 0; const u32 coef = pll + 4; u32 bypass; if (info->pll) { /* Always start from a non-PLL clock */ - bypass = nv_rd32(priv, ctrl) & 0x00000008; + bypass = nvkm_rd32(device, ctrl) & 0x00000008; if (!bypass) { - nv_mask(priv, src1, 0x00000101, 0x00000101); - nv_mask(priv, ctrl, 0x00000008, 0x00000008); + nvkm_mask(device, src1, 0x00000101, 0x00000101); + nvkm_mask(device, ctrl, 0x00000008, 0x00000008); udelay(20); } - nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk); - nv_wr32(priv, coef, info->pll); - nv_mask(priv, ctrl, 0x00000015, 0x00000015); - nv_mask(priv, ctrl, 0x00000010, 0x00000000); - if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) { - nv_mask(priv, ctrl, 0x00000010, 0x00000010); - nv_mask(priv, src0, 0x00000101, 0x00000000); + nvkm_mask(device, src0, 0x003f3141, 0x00000101 | info->clk); + nvkm_wr32(device, coef, info->pll); + nvkm_mask(device, ctrl, 0x00000015, 0x00000015); + nvkm_mask(device, ctrl, 0x00000010, 0x00000000); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, ctrl) & 0x00020000) + break; + ) < 0) { + nvkm_mask(device, ctrl, 0x00000010, 0x00000010); + nvkm_mask(device, src0, 0x00000101, 0x00000000); return; } - nv_mask(priv, ctrl, 0x00000010, 0x00000010); - nv_mask(priv, ctrl, 0x00000008, 0x00000000); - disable_clk_src(priv, src1); + nvkm_mask(device, ctrl, 0x00000010, 0x00000010); + nvkm_mask(device, ctrl, 0x00000008, 0x00000000); + disable_clk_src(clk, src1); } else { - nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk); - nv_mask(priv, ctrl, 0x00000018, 0x00000018); + nvkm_mask(device, src1, 0x003f3141, 0x00000101 | info->clk); + nvkm_mask(device, ctrl, 0x00000018, 0x00000018); udelay(20); - nv_mask(priv, ctrl, 0x00000001, 0x00000000); - disable_clk_src(priv, src0); + nvkm_mask(device, ctrl, 0x00000001, 0x00000000); + disable_clk_src(clk, src0); } } static void -prog_clk(struct gt215_clk_priv *priv, int clk, int idx) +prog_clk(struct gt215_clk *clk, int idx, int dom) { - struct gt215_clk_info *info = &priv->eng[idx]; - nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk); + struct gt215_clk_info *info = &clk->eng[dom]; + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x004120 + (idx * 4), 0x003f3141, 0x00000101 | info->clk); } static void -prog_host(struct gt215_clk_priv *priv) +prog_host(struct gt215_clk *clk) { - struct gt215_clk_info *info = &priv->eng[nv_clk_src_host]; - u32 hsrc = (nv_rd32(priv, 0xc040)); + struct gt215_clk_info *info = &clk->eng[nv_clk_src_host]; + struct nvkm_device *device = clk->base.subdev.device; + u32 hsrc = (nvkm_rd32(device, 0xc040)); switch (info->host_out) { case NVA3_HOST_277: if ((hsrc & 0x30000000) == 0) { - nv_wr32(priv, 0xc040, hsrc | 0x20000000); - disable_clk_src(priv, 0x4194); + nvkm_wr32(device, 0xc040, hsrc | 0x20000000); + disable_clk_src(clk, 0x4194); } break; case NVA3_HOST_CLK: - prog_clk(priv, 0x1d, nv_clk_src_host); + prog_clk(clk, 0x1d, nv_clk_src_host); if ((hsrc & 0x30000000) >= 0x20000000) { - nv_wr32(priv, 0xc040, hsrc & ~0x30000000); + nvkm_wr32(device, 0xc040, hsrc & ~0x30000000); } break; default: @@ -407,44 +433,45 @@ prog_host(struct gt215_clk_priv *priv) } /* This seems to be a clock gating factor on idle, always set to 64 */ - nv_wr32(priv, 0xc044, 0x3e); + nvkm_wr32(device, 0xc044, 0x3e); } static void -prog_core(struct gt215_clk_priv *priv, int idx) +prog_core(struct gt215_clk *clk, int dom) { - struct gt215_clk_info *info = &priv->eng[idx]; - u32 fb_delay = nv_rd32(priv, 0x10002c); + struct gt215_clk_info *info = &clk->eng[dom]; + struct nvkm_device *device = clk->base.subdev.device; + u32 fb_delay = nvkm_rd32(device, 0x10002c); if (fb_delay < info->fb_delay) - nv_wr32(priv, 0x10002c, info->fb_delay); + nvkm_wr32(device, 0x10002c, info->fb_delay); - prog_pll(priv, 0x00, 0x004200, idx); + prog_pll(clk, 0x00, 0x004200, dom); if (fb_delay > info->fb_delay) - nv_wr32(priv, 0x10002c, info->fb_delay); + nvkm_wr32(device, 0x10002c, info->fb_delay); } static int -gt215_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gt215_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gt215_clk_priv *priv = (void *)clk; - struct gt215_clk_info *core = &priv->eng[nv_clk_src_core]; + struct gt215_clk *clk = gt215_clk(base); + struct gt215_clk_info *core = &clk->eng[nv_clk_src_core]; int ret; - if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) || - (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) || - (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) || - (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) || - (ret = calc_host(priv, cstate))) + if ((ret = calc_clk(clk, cstate, 0x10, 0x4200, nv_clk_src_core)) || + (ret = calc_clk(clk, cstate, 0x11, 0x4220, nv_clk_src_shader)) || + (ret = calc_clk(clk, cstate, 0x20, 0x0000, nv_clk_src_disp)) || + (ret = calc_clk(clk, cstate, 0x21, 0x0000, nv_clk_src_vdec)) || + (ret = calc_host(clk, cstate))) return ret; /* XXX: Should be reading the highest bit in the VBIOS clock to decide * whether to use a PLL or not... but using a PLL defeats the purpose */ if (core->pll) { - ret = gt215_clk_info(clk, 0x10, + ret = gt215_clk_info(&clk->base, 0x10, cstate->domain[nv_clk_src_core_intm], - &priv->eng[nv_clk_src_core_intm]); + &clk->eng[nv_clk_src_core_intm]); if (ret < 0) return ret; } @@ -453,81 +480,67 @@ gt215_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) } static int -gt215_clk_prog(struct nvkm_clk *clk) +gt215_clk_prog(struct nvkm_clk *base) { - struct gt215_clk_priv *priv = (void *)clk; - struct gt215_clk_info *core = &priv->eng[nv_clk_src_core]; + struct gt215_clk *clk = gt215_clk(base); + struct gt215_clk_info *core = &clk->eng[nv_clk_src_core]; int ret = 0; unsigned long flags; unsigned long *f = &flags; - ret = gt215_clk_pre(clk, f); + ret = gt215_clk_pre(&clk->base, f); if (ret) goto out; if (core->pll) - prog_core(priv, nv_clk_src_core_intm); + prog_core(clk, nv_clk_src_core_intm); - prog_core(priv, nv_clk_src_core); - prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader); - prog_clk(priv, 0x20, nv_clk_src_disp); - prog_clk(priv, 0x21, nv_clk_src_vdec); - prog_host(priv); + prog_core(clk, nv_clk_src_core); + prog_pll(clk, 0x01, 0x004220, nv_clk_src_shader); + prog_clk(clk, 0x20, nv_clk_src_disp); + prog_clk(clk, 0x21, nv_clk_src_vdec); + prog_host(clk); out: if (ret == -EBUSY) f = NULL; - gt215_clk_post(clk, f); + gt215_clk_post(&clk->base, f); return ret; } static void -gt215_clk_tidy(struct nvkm_clk *clk) +gt215_clk_tidy(struct nvkm_clk *base) { } -static struct nvkm_domain -gt215_domain[] = { - { nv_clk_src_crystal , 0xff }, - { nv_clk_src_core , 0x00, 0, "core", 1000 }, - { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, - { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0x03 }, - { nv_clk_src_disp , 0x04 }, - { nv_clk_src_host , 0x05 }, - { nv_clk_src_core_intm, 0x06 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +gt215_clk = { + .read = gt215_clk_read, + .calc = gt215_clk_calc, + .prog = gt215_clk_prog, + .tidy = gt215_clk_tidy, + .domains = { + { nv_clk_src_crystal , 0xff }, + { nv_clk_src_core , 0x00, 0, "core", 1000 }, + { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, + { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x03 }, + { nv_clk_src_disp , 0x04 }, + { nv_clk_src_host , 0x05 }, + { nv_clk_src_core_intm, 0x06 }, + { nv_clk_src_max } + } }; -static int -gt215_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt215_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct gt215_clk_priv *priv; - int ret; + struct gt215_clk *clk; - ret = nvkm_clk_create(parent, engine, oclass, gt215_domain, - NULL, 0, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - priv->base.read = gt215_clk_read; - priv->base.calc = gt215_clk_calc; - priv->base.prog = gt215_clk_prog; - priv->base.tidy = gt215_clk_tidy; - return 0; + return nvkm_clk_ctor(>215_clk, device, index, true, &clk->base); } - -struct nvkm_oclass -gt215_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h index b447d9cd4..8865b59fe 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h @@ -1,6 +1,6 @@ #ifndef __NVKM_CLK_NVA3_H__ #define __NVKM_CLK_NVA3_H__ -#include <subdev/clk.h> +#include "priv.h" struct gt215_clk_info { u32 clk; @@ -13,6 +13,6 @@ struct gt215_clk_info { }; int gt215_pll_info(struct nvkm_clk *, int, u32, u32, struct gt215_clk_info *); -int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags); -void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags); +int gt215_clk_pre(struct nvkm_clk *, unsigned long *flags); +void gt215_clk_post(struct nvkm_clk *, unsigned long *flags); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index c54417b14..1c21b8b53 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -21,15 +21,15 @@ * * Authors: Ben Skeggs */ +#define mcp77_clk(p) container_of((p), struct mcp77_clk, base) #include "gt215.h" #include "pll.h" -#include <core/device.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> #include <subdev/timer.h> -struct mcp77_clk_priv { +struct mcp77_clk { struct nvkm_clk base; enum nv_clk_src csrc, ssrc, vsrc; u32 cctrl, sctrl; @@ -39,27 +39,29 @@ struct mcp77_clk_priv { }; static u32 -read_div(struct nvkm_clk *clk) +read_div(struct mcp77_clk *clk) { - return nv_rd32(clk, 0x004600); + struct nvkm_device *device = clk->base.subdev.device; + return nvkm_rd32(device, 0x004600); } static u32 -read_pll(struct nvkm_clk *clk, u32 base) +read_pll(struct mcp77_clk *clk, u32 base) { - u32 ctrl = nv_rd32(clk, base + 0); - u32 coef = nv_rd32(clk, base + 4); - u32 ref = clk->read(clk, nv_clk_src_href); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, base + 0); + u32 coef = nvkm_rd32(device, base + 4); + u32 ref = nvkm_clk_read(&clk->base, nv_clk_src_href); u32 post_div = 0; u32 clock = 0; int N1, M1; switch (base){ case 0x4020: - post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16); + post_div = 1 << ((nvkm_rd32(device, 0x4070) & 0x000f0000) >> 16); break; case 0x4028: - post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16; + post_div = (nvkm_rd32(device, 0x4040) & 0x000f0000) >> 16; break; default: break; @@ -76,59 +78,61 @@ read_pll(struct nvkm_clk *clk, u32 base) } static int -mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +mcp77_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct mcp77_clk_priv *priv = (void *)clk; - u32 mast = nv_rd32(clk, 0x00c054); + struct mcp77_clk *clk = mcp77_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; + u32 mast = nvkm_rd32(device, 0x00c054); u32 P = 0; switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return device->crystal; case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclkm4: - return clk->read(clk, nv_clk_src_href) * 4; + return nvkm_clk_read(&clk->base, nv_clk_src_href) * 4; case nv_clk_src_hclkm2d3: - return clk->read(clk, nv_clk_src_href) * 2 / 3; + return nvkm_clk_read(&clk->base, nv_clk_src_href) * 2 / 3; case nv_clk_src_host: switch (mast & 0x000c0000) { - case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm2d3); case 0x00040000: break; - case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4); - case 0x000c0000: return clk->read(clk, nv_clk_src_cclk); + case 0x00080000: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4); + case 0x000c0000: return nvkm_clk_read(&clk->base, nv_clk_src_cclk); } break; case nv_clk_src_core: - P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { - case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000001: return 0; - case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P; + case 0x00000002: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4) >> P; case 0x00000003: return read_pll(clk, 0x004028) >> P; } break; case nv_clk_src_cclk: if ((mast & 0x03000000) != 0x03000000) - return clk->read(clk, nv_clk_src_core); + return nvkm_clk_read(&clk->base, nv_clk_src_core); if ((mast & 0x00000200) == 0x00000000) - return clk->read(clk, nv_clk_src_core); + return nvkm_clk_read(&clk->base, nv_clk_src_core); switch (mast & 0x00000c00) { - case 0x00000000: return clk->read(clk, nv_clk_src_href); - case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4); - case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_href); + case 0x00000400: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4); + case 0x00000800: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm2d3); default: return 0; } case nv_clk_src_shader: - P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004020) & 0x00070000) >> 16; switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000040) - return clk->read(clk, nv_clk_src_href) >> P; - return clk->read(clk, nv_clk_src_crystal) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_href) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000010: break; case 0x00000020: return read_pll(clk, 0x004028) >> P; case 0x00000030: return read_pll(clk, 0x004020) >> P; @@ -142,7 +146,7 @@ mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) switch (mast & 0x00400000) { case 0x00400000: - return clk->read(clk, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; break; default: return 500000 >> P; @@ -153,29 +157,28 @@ mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) break; } - nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast); return 0; } static u32 -calc_pll(struct mcp77_clk_priv *priv, u32 reg, +calc_pll(struct mcp77_clk *clk, u32 reg, u32 clock, int *N, int *M, int *P) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll pll; - struct nvkm_clk *clk = &priv->base; int ret; - ret = nvbios_pll_parse(bios, reg, &pll); + ret = nvbios_pll_parse(subdev->device->bios, reg, &pll); if (ret) return 0; pll.vco2.max_freq = 0; - pll.refclk = clk->read(clk, nv_clk_src_href); + pll.refclk = nvkm_clk_read(&clk->base, nv_clk_src_href); if (!pll.refclk) return 0; - return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P); + return nv04_pll_calc(subdev, &pll, clock, N, M, NULL, NULL, P); } static inline u32 @@ -197,26 +200,27 @@ calc_P(u32 src, u32 target, int *div) } static int -mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +mcp77_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct mcp77_clk_priv *priv = (void *)clk; + struct mcp77_clk *clk = mcp77_clk(base); const int shader = cstate->domain[nv_clk_src_shader]; const int core = cstate->domain[nv_clk_src_core]; const int vdec = cstate->domain[nv_clk_src_vdec]; + struct nvkm_subdev *subdev = &clk->base.subdev; u32 out = 0, clock = 0; int N, M, P1, P2 = 0; int divs = 0; /* cclk: find suitable source, disable PLL if we can */ - if (core < clk->read(clk, nv_clk_src_hclkm4)) - out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs); + if (core < nvkm_clk_read(&clk->base, nv_clk_src_hclkm4)) + out = calc_P(nvkm_clk_read(&clk->base, nv_clk_src_hclkm4), core, &divs); /* Calculate clock * 2, so shader clock can use it too */ - clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1); + clock = calc_pll(clk, 0x4028, (core << 1), &N, &M, &P1); if (abs(core - out) <= abs(core - (clock >> 1))) { - priv->csrc = nv_clk_src_hclkm4; - priv->cctrl = divs << 16; + clk->csrc = nv_clk_src_hclkm4; + clk->cctrl = divs << 16; } else { /* NVCTRL is actually used _after_ NVPOST, and after what we * call NVPLL. To make matters worse, NVPOST is an integer @@ -226,31 +230,31 @@ mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) P1 = 2; } - priv->csrc = nv_clk_src_core; - priv->ccoef = (N << 8) | M; + clk->csrc = nv_clk_src_core; + clk->ccoef = (N << 8) | M; - priv->cctrl = (P2 + 1) << 16; - priv->cpost = (1 << P1) << 16; + clk->cctrl = (P2 + 1) << 16; + clk->cpost = (1 << P1) << 16; } /* sclk: nvpll + divisor, href or spll */ out = 0; - if (shader == clk->read(clk, nv_clk_src_href)) { - priv->ssrc = nv_clk_src_href; + if (shader == nvkm_clk_read(&clk->base, nv_clk_src_href)) { + clk->ssrc = nv_clk_src_href; } else { - clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1); - if (priv->csrc == nv_clk_src_core) + clock = calc_pll(clk, 0x4020, shader, &N, &M, &P1); + if (clk->csrc == nv_clk_src_core) out = calc_P((core << 1), shader, &divs); if (abs(shader - out) <= abs(shader - clock) && (divs + P2) <= 7) { - priv->ssrc = nv_clk_src_core; - priv->sctrl = (divs + P2) << 16; + clk->ssrc = nv_clk_src_core; + clk->sctrl = (divs + P2) << 16; } else { - priv->ssrc = nv_clk_src_shader; - priv->scoef = (N << 8) | M; - priv->sctrl = P1 << 16; + clk->ssrc = nv_clk_src_shader; + clk->scoef = (N << 8) | M; + clk->sctrl = P1 << 16; } } @@ -258,172 +262,162 @@ mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) out = calc_P(core, vdec, &divs); clock = calc_P(500000, vdec, &P1); if(abs(vdec - out) <= abs(vdec - clock)) { - priv->vsrc = nv_clk_src_cclk; - priv->vdiv = divs << 16; + clk->vsrc = nv_clk_src_cclk; + clk->vdiv = divs << 16; } else { - priv->vsrc = nv_clk_src_vdec; - priv->vdiv = P1 << 16; + clk->vsrc = nv_clk_src_vdec; + clk->vdiv = P1 << 16; } /* Print strategy! */ - nv_debug(priv, "nvpll: %08x %08x %08x\n", - priv->ccoef, priv->cpost, priv->cctrl); - nv_debug(priv, " spll: %08x %08x %08x\n", - priv->scoef, priv->spost, priv->sctrl); - nv_debug(priv, " vdiv: %08x\n", priv->vdiv); - if (priv->csrc == nv_clk_src_hclkm4) - nv_debug(priv, "core: hrefm4\n"); + nvkm_debug(subdev, "nvpll: %08x %08x %08x\n", + clk->ccoef, clk->cpost, clk->cctrl); + nvkm_debug(subdev, " spll: %08x %08x %08x\n", + clk->scoef, clk->spost, clk->sctrl); + nvkm_debug(subdev, " vdiv: %08x\n", clk->vdiv); + if (clk->csrc == nv_clk_src_hclkm4) + nvkm_debug(subdev, "core: hrefm4\n"); else - nv_debug(priv, "core: nvpll\n"); + nvkm_debug(subdev, "core: nvpll\n"); - if (priv->ssrc == nv_clk_src_hclkm4) - nv_debug(priv, "shader: hrefm4\n"); - else if (priv->ssrc == nv_clk_src_core) - nv_debug(priv, "shader: nvpll\n"); + if (clk->ssrc == nv_clk_src_hclkm4) + nvkm_debug(subdev, "shader: hrefm4\n"); + else if (clk->ssrc == nv_clk_src_core) + nvkm_debug(subdev, "shader: nvpll\n"); else - nv_debug(priv, "shader: spll\n"); + nvkm_debug(subdev, "shader: spll\n"); - if (priv->vsrc == nv_clk_src_hclkm4) - nv_debug(priv, "vdec: 500MHz\n"); + if (clk->vsrc == nv_clk_src_hclkm4) + nvkm_debug(subdev, "vdec: 500MHz\n"); else - nv_debug(priv, "vdec: core\n"); + nvkm_debug(subdev, "vdec: core\n"); return 0; } static int -mcp77_clk_prog(struct nvkm_clk *clk) +mcp77_clk_prog(struct nvkm_clk *base) { - struct mcp77_clk_priv *priv = (void *)clk; + struct mcp77_clk *clk = mcp77_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 pllmask = 0, mast; unsigned long flags; unsigned long *f = &flags; int ret = 0; - ret = gt215_clk_pre(clk, f); + ret = gt215_clk_pre(&clk->base, f); if (ret) goto out; /* First switch to safe clocks: href */ - mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640); + mast = nvkm_mask(device, 0xc054, 0x03400e70, 0x03400640); mast &= ~0x00400e73; mast |= 0x03000000; - switch (priv->csrc) { + switch (clk->csrc) { case nv_clk_src_hclkm4: - nv_mask(clk, 0x4028, 0x00070000, priv->cctrl); + nvkm_mask(device, 0x4028, 0x00070000, clk->cctrl); mast |= 0x00000002; break; case nv_clk_src_core: - nv_wr32(clk, 0x402c, priv->ccoef); - nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl); - nv_wr32(clk, 0x4040, priv->cpost); + nvkm_wr32(device, 0x402c, clk->ccoef); + nvkm_wr32(device, 0x4028, 0x80000000 | clk->cctrl); + nvkm_wr32(device, 0x4040, clk->cpost); pllmask |= (0x3 << 8); mast |= 0x00000003; break; default: - nv_warn(priv,"Reclocking failed: unknown core clock\n"); + nvkm_warn(subdev, "Reclocking failed: unknown core clock\n"); goto resume; } - switch (priv->ssrc) { + switch (clk->ssrc) { case nv_clk_src_href: - nv_mask(clk, 0x4020, 0x00070000, 0x00000000); + nvkm_mask(device, 0x4020, 0x00070000, 0x00000000); /* mast |= 0x00000000; */ break; case nv_clk_src_core: - nv_mask(clk, 0x4020, 0x00070000, priv->sctrl); + nvkm_mask(device, 0x4020, 0x00070000, clk->sctrl); mast |= 0x00000020; break; case nv_clk_src_shader: - nv_wr32(clk, 0x4024, priv->scoef); - nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl); - nv_wr32(clk, 0x4070, priv->spost); + nvkm_wr32(device, 0x4024, clk->scoef); + nvkm_wr32(device, 0x4020, 0x80000000 | clk->sctrl); + nvkm_wr32(device, 0x4070, clk->spost); pllmask |= (0x3 << 12); mast |= 0x00000030; break; default: - nv_warn(priv,"Reclocking failed: unknown sclk clock\n"); + nvkm_warn(subdev, "Reclocking failed: unknown sclk clock\n"); goto resume; } - if (!nv_wait(clk, 0x004080, pllmask, pllmask)) { - nv_warn(priv,"Reclocking failed: unstable PLLs\n"); + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x004080) & pllmask; + if (tmp == pllmask) + break; + ) < 0) goto resume; - } - switch (priv->vsrc) { + switch (clk->vsrc) { case nv_clk_src_cclk: mast |= 0x00400000; default: - nv_wr32(clk, 0x4600, priv->vdiv); + nvkm_wr32(device, 0x4600, clk->vdiv); } - nv_wr32(clk, 0xc054, mast); + nvkm_wr32(device, 0xc054, mast); resume: /* Disable some PLLs and dividers when unused */ - if (priv->csrc != nv_clk_src_core) { - nv_wr32(clk, 0x4040, 0x00000000); - nv_mask(clk, 0x4028, 0x80000000, 0x00000000); + if (clk->csrc != nv_clk_src_core) { + nvkm_wr32(device, 0x4040, 0x00000000); + nvkm_mask(device, 0x4028, 0x80000000, 0x00000000); } - if (priv->ssrc != nv_clk_src_shader) { - nv_wr32(clk, 0x4070, 0x00000000); - nv_mask(clk, 0x4020, 0x80000000, 0x00000000); + if (clk->ssrc != nv_clk_src_shader) { + nvkm_wr32(device, 0x4070, 0x00000000); + nvkm_mask(device, 0x4020, 0x80000000, 0x00000000); } out: if (ret == -EBUSY) f = NULL; - gt215_clk_post(clk, f); + gt215_clk_post(&clk->base, f); return ret; } static void -mcp77_clk_tidy(struct nvkm_clk *clk) +mcp77_clk_tidy(struct nvkm_clk *base) { } -static struct nvkm_domain -mcp77_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +mcp77_clk = { + .read = mcp77_clk_read, + .calc = mcp77_clk_calc, + .prog = mcp77_clk_prog, + .tidy = mcp77_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, + { nv_clk_src_max } + } }; -static int -mcp77_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +mcp77_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct mcp77_clk_priv *priv; - int ret; + struct mcp77_clk *clk; - ret = nvkm_clk_create(parent, engine, oclass, mcp77_domains, - NULL, 0, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - priv->base.read = mcp77_clk_read; - priv->base.calc = mcp77_clk_calc; - priv->base.prog = mcp77_clk_prog; - priv->base.tidy = mcp77_clk_tidy; - return 0; + return nvkm_clk_ctor(&mcp77_clk, device, index, true, &clk->base); } - -struct nvkm_oclass * -mcp77_clk_oclass = &(struct nvkm_oclass) { - .handle = NV_SUBDEV(CLK, 0xaa), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = mcp77_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c index 63dbbb575..b280f85e8 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c @@ -21,23 +21,19 @@ * * Authors: Ben Skeggs */ -#include <subdev/clk.h> +#include "priv.h" #include "pll.h" #include <subdev/bios.h> #include <subdev/bios/pll.h> #include <subdev/devinit/nv04.h> -struct nv04_clk_priv { - struct nvkm_clk base; -}; - int nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info, int clk, struct nvkm_pll_vals *pv) { int N1, M1, N2, M2, P; - int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P); + int ret = nv04_pll_calc(&clock->subdev, info, clk, &N1, &M1, &N2, &M2, &P); if (ret) { pv->refclk = info->refclk; pv->N1 = N1; @@ -52,8 +48,9 @@ nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info, int nv04_clk_pll_prog(struct nvkm_clk *clk, u32 reg1, struct nvkm_pll_vals *pv) { - struct nvkm_devinit *devinit = nvkm_devinit(clk); - int cv = nvkm_bios(clk)->version.chip; + struct nvkm_device *device = clk->subdev.device; + struct nvkm_devinit *devinit = device->devinit; + int cv = device->bios->version.chip; if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || cv >= 0x40) { @@ -67,37 +64,20 @@ nv04_clk_pll_prog(struct nvkm_clk *clk, u32 reg1, struct nvkm_pll_vals *pv) return 0; } -static struct nvkm_domain -nv04_domain[] = { - { nv_clk_src_max } +static const struct nvkm_clk_func +nv04_clk = { + .domains = { + { nv_clk_src_max } + } }; -static int -nv04_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv04_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct nv04_clk_priv *priv; - int ret; - - ret = nvkm_clk_create(parent, engine, oclass, nv04_domain, - NULL, 0, false, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.pll_calc = nv04_clk_pll_calc; - priv->base.pll_prog = nv04_clk_pll_prog; - return 0; + int ret = nvkm_clk_new_(&nv04_clk, device, index, false, pclk); + if (ret == 0) { + (*pclk)->pll_calc = nv04_clk_pll_calc; + (*pclk)->pll_prog = nv04_clk_pll_prog; + } + return ret; } - -struct nvkm_oclass -nv04_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index ed838130c..2ab9b9b84 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -21,14 +21,14 @@ * * Authors: Ben Skeggs */ -#include <subdev/clk.h> +#define nv40_clk(p) container_of((p), struct nv40_clk, base) +#include "priv.h" #include "pll.h" -#include <core/device.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> -struct nv40_clk_priv { +struct nv40_clk { struct nvkm_clk base; u32 ctrl; u32 npll_ctrl; @@ -36,64 +36,56 @@ struct nv40_clk_priv { u32 spll; }; -static struct nvkm_domain -nv40_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, - { nv_clk_src_max } -}; - static u32 -read_pll_1(struct nv40_clk_priv *priv, u32 reg) +read_pll_1(struct nv40_clk *clk, u32 reg) { - u32 ctrl = nv_rd32(priv, reg + 0x00); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, reg + 0x00); int P = (ctrl & 0x00070000) >> 16; int N = (ctrl & 0x0000ff00) >> 8; int M = (ctrl & 0x000000ff) >> 0; - u32 ref = 27000, clk = 0; + u32 ref = 27000, khz = 0; if (ctrl & 0x80000000) - clk = ref * N / M; + khz = ref * N / M; - return clk >> P; + return khz >> P; } static u32 -read_pll_2(struct nv40_clk_priv *priv, u32 reg) +read_pll_2(struct nv40_clk *clk, u32 reg) { - u32 ctrl = nv_rd32(priv, reg + 0x00); - u32 coef = nv_rd32(priv, reg + 0x04); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, reg + 0x00); + u32 coef = nvkm_rd32(device, reg + 0x04); int N2 = (coef & 0xff000000) >> 24; int M2 = (coef & 0x00ff0000) >> 16; int N1 = (coef & 0x0000ff00) >> 8; int M1 = (coef & 0x000000ff) >> 0; int P = (ctrl & 0x00070000) >> 16; - u32 ref = 27000, clk = 0; + u32 ref = 27000, khz = 0; if ((ctrl & 0x80000000) && M1) { - clk = ref * N1 / M1; + khz = ref * N1 / M1; if ((ctrl & 0x40000100) == 0x40000000) { if (M2) - clk = clk * N2 / M2; + khz = khz * N2 / M2; else - clk = 0; + khz = 0; } } - return clk >> P; + return khz >> P; } static u32 -read_clk(struct nv40_clk_priv *priv, u32 src) +read_clk(struct nv40_clk *clk, u32 src) { switch (src) { case 3: - return read_pll_2(priv, 0x004000); + return read_pll_2(clk, 0x004000); case 2: - return read_pll_1(priv, 0x004008); + return read_pll_1(clk, 0x004008); default: break; } @@ -102,46 +94,48 @@ read_clk(struct nv40_clk_priv *priv, u32 src) } static int -nv40_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +nv40_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct nv40_clk_priv *priv = (void *)clk; - u32 mast = nv_rd32(priv, 0x00c040); + struct nv40_clk *clk = nv40_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; + u32 mast = nvkm_rd32(device, 0x00c040); switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return device->crystal; case nv_clk_src_href: return 100000; /*XXX: PCIE/AGP differ*/ case nv_clk_src_core: - return read_clk(priv, (mast & 0x00000003) >> 0); + return read_clk(clk, (mast & 0x00000003) >> 0); case nv_clk_src_shader: - return read_clk(priv, (mast & 0x00000030) >> 4); + return read_clk(clk, (mast & 0x00000030) >> 4); case nv_clk_src_mem: - return read_pll_2(priv, 0x4020); + return read_pll_2(clk, 0x4020); default: break; } - nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast); return -EINVAL; } static int -nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk, +nv40_clk_calc_pll(struct nv40_clk *clk, u32 reg, u32 khz, int *N1, int *M1, int *N2, int *M2, int *log2P) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll pll; int ret; - ret = nvbios_pll_parse(bios, reg, &pll); + ret = nvbios_pll_parse(subdev->device->bios, reg, &pll); if (ret) return ret; - if (clk < pll.vco1.max_freq) + if (khz < pll.vco1.max_freq) pll.vco2.max_freq = 0; - ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P); + ret = nv04_pll_calc(subdev, &pll, khz, N1, M1, N2, M2, log2P); if (ret == 0) return -ERANGE; @@ -149,93 +143,90 @@ nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk, } static int -nv40_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +nv40_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct nv40_clk_priv *priv = (void *)clk; + struct nv40_clk *clk = nv40_clk(base); int gclk = cstate->domain[nv_clk_src_core]; int sclk = cstate->domain[nv_clk_src_shader]; int N1, M1, N2, M2, log2P; int ret; /* core/geometric clock */ - ret = nv40_clk_calc_pll(priv, 0x004000, gclk, + ret = nv40_clk_calc_pll(clk, 0x004000, gclk, &N1, &M1, &N2, &M2, &log2P); if (ret < 0) return ret; if (N2 == M2) { - priv->npll_ctrl = 0x80000100 | (log2P << 16); - priv->npll_coef = (N1 << 8) | M1; + clk->npll_ctrl = 0x80000100 | (log2P << 16); + clk->npll_coef = (N1 << 8) | M1; } else { - priv->npll_ctrl = 0xc0000000 | (log2P << 16); - priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; + clk->npll_ctrl = 0xc0000000 | (log2P << 16); + clk->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; } /* use the second pll for shader/rop clock, if it differs from core */ if (sclk && sclk != gclk) { - ret = nv40_clk_calc_pll(priv, 0x004008, sclk, + ret = nv40_clk_calc_pll(clk, 0x004008, sclk, &N1, &M1, NULL, NULL, &log2P); if (ret < 0) return ret; - priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; - priv->ctrl = 0x00000223; + clk->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; + clk->ctrl = 0x00000223; } else { - priv->spll = 0x00000000; - priv->ctrl = 0x00000333; + clk->spll = 0x00000000; + clk->ctrl = 0x00000333; } return 0; } static int -nv40_clk_prog(struct nvkm_clk *clk) +nv40_clk_prog(struct nvkm_clk *base) { - struct nv40_clk_priv *priv = (void *)clk; - nv_mask(priv, 0x00c040, 0x00000333, 0x00000000); - nv_wr32(priv, 0x004004, priv->npll_coef); - nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl); - nv_mask(priv, 0x004008, 0xc007ffff, priv->spll); + struct nv40_clk *clk = nv40_clk(base); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x00c040, 0x00000333, 0x00000000); + nvkm_wr32(device, 0x004004, clk->npll_coef); + nvkm_mask(device, 0x004000, 0xc0070100, clk->npll_ctrl); + nvkm_mask(device, 0x004008, 0xc007ffff, clk->spll); mdelay(5); - nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl); + nvkm_mask(device, 0x00c040, 0x00000333, clk->ctrl); return 0; } static void -nv40_clk_tidy(struct nvkm_clk *clk) +nv40_clk_tidy(struct nvkm_clk *obj) { } -static int -nv40_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_clk_func +nv40_clk = { + .read = nv40_clk_read, + .calc = nv40_clk_calc, + .prog = nv40_clk_prog, + .tidy = nv40_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_max } + } +}; + +int +nv40_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct nv40_clk_priv *priv; - int ret; + struct nv40_clk *clk; - ret = nvkm_clk_create(parent, engine, oclass, nv40_domain, - NULL, 0, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + clk->base.pll_calc = nv04_clk_pll_calc; + clk->base.pll_prog = nv04_clk_pll_prog; + *pclk = &clk->base; - priv->base.pll_calc = nv04_clk_pll_calc; - priv->base.pll_prog = nv04_clk_pll_prog; - priv->base.read = nv40_clk_read; - priv->base.calc = nv40_clk_calc; - priv->base.prog = nv40_clk_prog; - priv->base.tidy = nv40_clk_tidy; - return 0; + return nvkm_clk_ctor(&nv40_clk, device, index, true, &clk->base); } - -struct nvkm_oclass -nv40_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index 9b4ffd634..5841f2979 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -25,38 +25,39 @@ #include "pll.h" #include "seq.h" -#include <core/device.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> static u32 -read_div(struct nv50_clk_priv *priv) +read_div(struct nv50_clk *clk) { - switch (nv_device(priv)->chipset) { + struct nvkm_device *device = clk->base.subdev.device; + switch (device->chipset) { case 0x50: /* it exists, but only has bit 31, not the dividers.. */ case 0x84: case 0x86: case 0x98: case 0xa0: - return nv_rd32(priv, 0x004700); + return nvkm_rd32(device, 0x004700); case 0x92: case 0x94: case 0x96: - return nv_rd32(priv, 0x004800); + return nvkm_rd32(device, 0x004800); default: return 0x00000000; } } static u32 -read_pll_src(struct nv50_clk_priv *priv, u32 base) +read_pll_src(struct nv50_clk *clk, u32 base) { - struct nvkm_clk *clk = &priv->base; - u32 coef, ref = clk->read(clk, nv_clk_src_crystal); - u32 rsel = nv_rd32(priv, 0x00e18c); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; + u32 coef, ref = nvkm_clk_read(&clk->base, nv_clk_src_crystal); + u32 rsel = nvkm_rd32(device, 0x00e18c); int P, N, M, id; - switch (nv_device(priv)->chipset) { + switch (device->chipset) { case 0x50: case 0xa0: switch (base) { @@ -65,11 +66,11 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) case 0x4008: id = !!(rsel & 0x00000008); break; case 0x4030: id = 0; break; default: - nv_error(priv, "ref: bad pll 0x%06x\n", base); + nvkm_error(subdev, "ref: bad pll %06x\n", base); return 0; } - coef = nv_rd32(priv, 0x00e81c + (id * 0x0c)); + coef = nvkm_rd32(device, 0x00e81c + (id * 0x0c)); ref *= (coef & 0x01000000) ? 2 : 4; P = (coef & 0x00070000) >> 16; N = ((coef & 0x0000ff00) >> 8) + 1; @@ -78,7 +79,7 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) case 0x84: case 0x86: case 0x92: - coef = nv_rd32(priv, 0x00e81c); + coef = nvkm_rd32(device, 0x00e81c); P = (coef & 0x00070000) >> 16; N = (coef & 0x0000ff00) >> 8; M = (coef & 0x000000ff) >> 0; @@ -86,26 +87,26 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) case 0x94: case 0x96: case 0x98: - rsel = nv_rd32(priv, 0x00c050); + rsel = nvkm_rd32(device, 0x00c050); switch (base) { case 0x4020: rsel = (rsel & 0x00000003) >> 0; break; case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break; case 0x4028: rsel = (rsel & 0x00001800) >> 11; break; case 0x4030: rsel = 3; break; default: - nv_error(priv, "ref: bad pll 0x%06x\n", base); + nvkm_error(subdev, "ref: bad pll %06x\n", base); return 0; } switch (rsel) { case 0: id = 1; break; - case 1: return clk->read(clk, nv_clk_src_crystal); - case 2: return clk->read(clk, nv_clk_src_href); + case 1: return nvkm_clk_read(&clk->base, nv_clk_src_crystal); + case 2: return nvkm_clk_read(&clk->base, nv_clk_src_href); case 3: id = 0; break; } - coef = nv_rd32(priv, 0x00e81c + (id * 0x28)); - P = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7; + coef = nvkm_rd32(device, 0x00e81c + (id * 0x28)); + P = (nvkm_rd32(device, 0x00e824 + (id * 0x28)) >> 16) & 7; P += (coef & 0x00070000) >> 16; N = (coef & 0x0000ff00) >> 8; M = (coef & 0x000000ff) >> 0; @@ -121,10 +122,11 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) } static u32 -read_pll_ref(struct nv50_clk_priv *priv, u32 base) +read_pll_ref(struct nv50_clk *clk, u32 base) { - struct nvkm_clk *clk = &priv->base; - u32 src, mast = nv_rd32(priv, 0x00c040); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; + u32 src, mast = nvkm_rd32(device, 0x00c040); switch (base) { case 0x004028: @@ -140,33 +142,33 @@ read_pll_ref(struct nv50_clk_priv *priv, u32 base) src = !!(mast & 0x02000000); break; case 0x00e810: - return clk->read(clk, nv_clk_src_crystal); + return nvkm_clk_read(&clk->base, nv_clk_src_crystal); default: - nv_error(priv, "bad pll 0x%06x\n", base); + nvkm_error(subdev, "bad pll %06x\n", base); return 0; } if (src) - return clk->read(clk, nv_clk_src_href); + return nvkm_clk_read(&clk->base, nv_clk_src_href); - return read_pll_src(priv, base); + return read_pll_src(clk, base); } static u32 -read_pll(struct nv50_clk_priv *priv, u32 base) +read_pll(struct nv50_clk *clk, u32 base) { - struct nvkm_clk *clk = &priv->base; - u32 mast = nv_rd32(priv, 0x00c040); - u32 ctrl = nv_rd32(priv, base + 0); - u32 coef = nv_rd32(priv, base + 4); - u32 ref = read_pll_ref(priv, base); + struct nvkm_device *device = clk->base.subdev.device; + u32 mast = nvkm_rd32(device, 0x00c040); + u32 ctrl = nvkm_rd32(device, base + 0); + u32 coef = nvkm_rd32(device, base + 4); + u32 ref = read_pll_ref(clk, base); u32 freq = 0; int N1, N2, M1, M2; if (base == 0x004028 && (mast & 0x00100000)) { /* wtf, appears to only disable post-divider on gt200 */ - if (nv_device(priv)->chipset != 0xa0) - return clk->read(clk, nv_clk_src_dom6); + if (device->chipset != 0xa0) + return nvkm_clk_read(&clk->base, nv_clk_src_dom6); } N2 = (coef & 0xff000000) >> 24; @@ -186,71 +188,73 @@ read_pll(struct nv50_clk_priv *priv, u32 base) return freq; } -static int -nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +int +nv50_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct nv50_clk_priv *priv = (void *)clk; - u32 mast = nv_rd32(priv, 0x00c040); + struct nv50_clk *clk = nv50_clk(base); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; + u32 mast = nvkm_rd32(device, 0x00c040); u32 P = 0; switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return device->crystal; case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclk: - return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000); + return div_u64((u64)nvkm_clk_read(&clk->base, nv_clk_src_href) * 27778, 10000); case nv_clk_src_hclkm3: - return clk->read(clk, nv_clk_src_hclk) * 3; + return nvkm_clk_read(&clk->base, nv_clk_src_hclk) * 3; case nv_clk_src_hclkm3d2: - return clk->read(clk, nv_clk_src_hclk) * 3 / 2; + return nvkm_clk_read(&clk->base, nv_clk_src_hclk) * 3 / 2; case nv_clk_src_host: switch (mast & 0x30000000) { - case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_href); case 0x10000000: break; case 0x20000000: /* !0x50 */ - case 0x30000000: return clk->read(clk, nv_clk_src_hclk); + case 0x30000000: return nvkm_clk_read(&clk->base, nv_clk_src_hclk); } break; case nv_clk_src_core: if (!(mast & 0x00100000)) - P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { - case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; - case 0x00000001: return clk->read(clk, nv_clk_src_dom6); - case 0x00000002: return read_pll(priv, 0x004020) >> P; - case 0x00000003: return read_pll(priv, 0x004028) >> P; + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; + case 0x00000001: return nvkm_clk_read(&clk->base, nv_clk_src_dom6); + case 0x00000002: return read_pll(clk, 0x004020) >> P; + case 0x00000003: return read_pll(clk, 0x004028) >> P; } break; case nv_clk_src_shader: - P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004020) & 0x00070000) >> 16; switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000080) - return clk->read(clk, nv_clk_src_host) >> P; - return clk->read(clk, nv_clk_src_crystal) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_host) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000010: break; - case 0x00000020: return read_pll(priv, 0x004028) >> P; - case 0x00000030: return read_pll(priv, 0x004020) >> P; + case 0x00000020: return read_pll(clk, 0x004028) >> P; + case 0x00000030: return read_pll(clk, 0x004020) >> P; } break; case nv_clk_src_mem: - P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16; - if (nv_rd32(priv, 0x004008) & 0x00000200) { + P = (nvkm_rd32(device, 0x004008) & 0x00070000) >> 16; + if (nvkm_rd32(device, 0x004008) & 0x00000200) { switch (mast & 0x0000c000) { case 0x00000000: - return clk->read(clk, nv_clk_src_crystal) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00008000: case 0x0000c000: - return clk->read(clk, nv_clk_src_href) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_href) >> P; } } else { - return read_pll(priv, 0x004008) >> P; + return read_pll(clk, 0x004008) >> P; } break; case nv_clk_src_vdec: - P = (read_div(priv) & 0x00000700) >> 8; - switch (nv_device(priv)->chipset) { + P = (read_div(clk) & 0x00000700) >> 8; + switch (device->chipset) { case 0x84: case 0x86: case 0x92: @@ -259,51 +263,51 @@ nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) case 0xa0: switch (mast & 0x00000c00) { case 0x00000000: - if (nv_device(priv)->chipset == 0xa0) /* wtf?? */ - return clk->read(clk, nv_clk_src_core) >> P; - return clk->read(clk, nv_clk_src_crystal) >> P; + if (device->chipset == 0xa0) /* wtf?? */ + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000400: return 0; case 0x00000800: if (mast & 0x01000000) - return read_pll(priv, 0x004028) >> P; - return read_pll(priv, 0x004030) >> P; + return read_pll(clk, 0x004028) >> P; + return read_pll(clk, 0x004030) >> P; case 0x00000c00: - return clk->read(clk, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; } break; case 0x98: switch (mast & 0x00000c00) { case 0x00000000: - return clk->read(clk, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; case 0x00000400: return 0; case 0x00000800: - return clk->read(clk, nv_clk_src_hclkm3d2) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_hclkm3d2) >> P; case 0x00000c00: - return clk->read(clk, nv_clk_src_mem) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_mem) >> P; } break; } break; case nv_clk_src_dom6: - switch (nv_device(priv)->chipset) { + switch (device->chipset) { case 0x50: case 0xa0: - return read_pll(priv, 0x00e810) >> 2; + return read_pll(clk, 0x00e810) >> 2; case 0x84: case 0x86: case 0x92: case 0x94: case 0x96: case 0x98: - P = (read_div(priv) & 0x00000007) >> 0; + P = (read_div(clk) & 0x00000007) >> 0; switch (mast & 0x0c000000) { - case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_href); case 0x04000000: break; - case 0x08000000: return clk->read(clk, nv_clk_src_hclk); + case 0x08000000: return nvkm_clk_read(&clk->base, nv_clk_src_hclk); case 0x0c000000: - return clk->read(clk, nv_clk_src_hclkm3) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_hclkm3) >> P; } break; default: @@ -313,27 +317,27 @@ nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) break; } - nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast); return -EINVAL; } static u32 -calc_pll(struct nv50_clk_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P) +calc_pll(struct nv50_clk *clk, u32 reg, u32 idx, int *N, int *M, int *P) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll pll; int ret; - ret = nvbios_pll_parse(bios, reg, &pll); + ret = nvbios_pll_parse(subdev->device->bios, reg, &pll); if (ret) return 0; pll.vco2.max_freq = 0; - pll.refclk = read_pll_ref(priv, reg); + pll.refclk = read_pll_ref(clk, reg); if (!pll.refclk) return 0; - return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P); + return nv04_pll_calc(subdev, &pll, idx, N, M, NULL, NULL, P); } static inline u32 @@ -360,11 +364,13 @@ clk_same(u32 a, u32 b) return ((a / 1000) == (b / 1000)); } -static int -nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +int +nv50_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct nv50_clk_priv *priv = (void *)clk; - struct nv50_clk_hwsq *hwsq = &priv->hwsq; + struct nv50_clk *clk = nv50_clk(base); + struct nv50_clk_hwsq *hwsq = &clk->hwsq; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; const int shader = cstate->domain[nv_clk_src_shader]; const int core = cstate->domain[nv_clk_src_core]; const int vdec = cstate->domain[nv_clk_src_vdec]; @@ -375,7 +381,7 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) int freq, out; /* prepare a hwsq script from which we'll perform the reclock */ - out = clk_init(hwsq, nv_subdev(clk)); + out = clk_init(hwsq, subdev); if (out) return out; @@ -393,15 +399,15 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) freq = calc_div(core, vdec, &P1); /* see how close we can get using xpll/hclk as a source */ - if (nv_device(priv)->chipset != 0x98) - out = read_pll(priv, 0x004030); + if (device->chipset != 0x98) + out = read_pll(clk, 0x004030); else - out = clk->read(clk, nv_clk_src_hclkm3d2); + out = nvkm_clk_read(&clk->base, nv_clk_src_hclkm3d2); out = calc_div(out, vdec, &P2); /* select whichever gets us closest */ if (abs(vdec - freq) <= abs(vdec - out)) { - if (nv_device(priv)->chipset != 0x98) + if (device->chipset != 0x98) mastv |= 0x00000c00; divsv |= P1 << 8; } else { @@ -417,14 +423,14 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) * of the host clock frequency */ if (dom6) { - if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) { + if (clk_same(dom6, nvkm_clk_read(&clk->base, nv_clk_src_href))) { mastv |= 0x00000000; } else - if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) { + if (clk_same(dom6, nvkm_clk_read(&clk->base, nv_clk_src_hclk))) { mastv |= 0x08000000; } else { - freq = clk->read(clk, nv_clk_src_hclk) * 3; - freq = calc_div(freq, dom6, &P1); + freq = nvkm_clk_read(&clk->base, nv_clk_src_hclk) * 3; + calc_div(freq, dom6, &P1); mastv |= 0x0c000000; divsv |= P1; @@ -444,13 +450,13 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) /* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6, * sclk to hclk) before reprogramming */ - if (nv_device(priv)->chipset < 0x92) + if (device->chipset < 0x92) clk_mask(hwsq, mast, 0x001000b0, 0x00100080); else clk_mask(hwsq, mast, 0x000000b3, 0x00000081); /* core: for the moment at least, always use nvpll */ - freq = calc_pll(priv, 0x4028, core, &N, &M, &P1); + freq = calc_pll(clk, 0x4028, core, &N, &M, &P1); if (freq == 0) return -ERANGE; @@ -468,7 +474,7 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16)); clk_mask(hwsq, mast, 0x00100033, 0x00000023); } else { - freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1); + freq = calc_pll(clk, 0x4020, shader, &N, &M, &P1); if (freq == 0) return -ERANGE; @@ -485,77 +491,71 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) return 0; } -static int -nv50_clk_prog(struct nvkm_clk *clk) +int +nv50_clk_prog(struct nvkm_clk *base) { - struct nv50_clk_priv *priv = (void *)clk; - return clk_exec(&priv->hwsq, true); + struct nv50_clk *clk = nv50_clk(base); + return clk_exec(&clk->hwsq, true); } -static void -nv50_clk_tidy(struct nvkm_clk *clk) +void +nv50_clk_tidy(struct nvkm_clk *base) { - struct nv50_clk_priv *priv = (void *)clk; - clk_exec(&priv->hwsq, false); + struct nv50_clk *clk = nv50_clk(base); + clk_exec(&clk->hwsq, false); } int -nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_clk_new_(const struct nvkm_clk_func *func, struct nvkm_device *device, + int index, bool allow_reclock, struct nvkm_clk **pclk) { - struct nv50_clk_oclass *pclass = (void *)oclass; - struct nv50_clk_priv *priv; + struct nv50_clk *clk; int ret; - ret = nvkm_clk_create(parent, engine, oclass, pclass->domains, - NULL, 0, false, &priv); - *pobject = nv_object(priv); + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + ret = nvkm_clk_ctor(func, device, index, allow_reclock, &clk->base); + *pclk = &clk->base; if (ret) return ret; - priv->hwsq.r_fifo = hwsq_reg(0x002504); - priv->hwsq.r_spll[0] = hwsq_reg(0x004020); - priv->hwsq.r_spll[1] = hwsq_reg(0x004024); - priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028); - priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c); - switch (nv_device(priv)->chipset) { + clk->hwsq.r_fifo = hwsq_reg(0x002504); + clk->hwsq.r_spll[0] = hwsq_reg(0x004020); + clk->hwsq.r_spll[1] = hwsq_reg(0x004024); + clk->hwsq.r_nvpll[0] = hwsq_reg(0x004028); + clk->hwsq.r_nvpll[1] = hwsq_reg(0x00402c); + switch (device->chipset) { case 0x92: case 0x94: case 0x96: - priv->hwsq.r_divs = hwsq_reg(0x004800); + clk->hwsq.r_divs = hwsq_reg(0x004800); break; default: - priv->hwsq.r_divs = hwsq_reg(0x004700); + clk->hwsq.r_divs = hwsq_reg(0x004700); break; } - priv->hwsq.r_mast = hwsq_reg(0x00c040); - - priv->base.read = nv50_clk_read; - priv->base.calc = nv50_clk_calc; - priv->base.prog = nv50_clk_prog; - priv->base.tidy = nv50_clk_tidy; + clk->hwsq.r_mast = hwsq_reg(0x00c040); return 0; } -static struct nvkm_domain -nv50_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +nv50_clk = { + .read = nv50_clk_read, + .calc = nv50_clk_calc, + .prog = nv50_clk_prog, + .tidy = nv50_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_max } + } }; -struct nvkm_oclass * -nv50_clk_oclass = &(struct nv50_clk_oclass) { - .base.handle = NV_SUBDEV(CLK, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, - .domains = nv50_domains, -}.base; +int +nv50_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) +{ + return nv50_clk_new_(&nv50_clk, device, index, false, pclk); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h index 0ead76a32..d3c7fb6ef 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h @@ -1,7 +1,9 @@ -#ifndef __NVKM_CLK_NV50_H__ -#define __NVKM_CLK_NV50_H__ +#ifndef __NV50_CLK_H__ +#define __NV50_CLK_H__ +#define nv50_clk(p) container_of((p), struct nv50_clk, base) +#include "priv.h" + #include <subdev/bus/hwsq.h> -#include <subdev/clk.h> struct nv50_clk_hwsq { struct hwsq base; @@ -12,17 +14,15 @@ struct nv50_clk_hwsq { struct hwsq_reg r_mast; }; -struct nv50_clk_priv { +struct nv50_clk { struct nvkm_clk base; struct nv50_clk_hwsq hwsq; }; -int nv50_clk_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -struct nv50_clk_oclass { - struct nvkm_oclass base; - struct nvkm_domain *domains; -}; +int nv50_clk_new_(const struct nvkm_clk_func *, struct nvkm_device *, int, + bool, struct nvkm_clk **); +int nv50_clk_read(struct nvkm_clk *, enum nv_clk_src); +int nv50_clk_calc(struct nvkm_clk *, struct nvkm_cstate *); +int nv50_clk_prog(struct nvkm_clk *); +void nv50_clk_tidy(struct nvkm_clk *); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c index 783a3e78d..c6fccd600 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c @@ -79,7 +79,7 @@ gt215_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, } if (unlikely(best_err == ~0)) { - nv_error(subdev, "unable to find matching pll values\n"); + nvkm_error(subdev, "unable to find matching pll values\n"); return -EINVAL; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c index f2292895a..5ad67879e 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c @@ -37,7 +37,7 @@ getMNP_single(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - struct nvkm_bios *bios = nvkm_bios(subdev); + struct nvkm_bios *bios = subdev->device->bios; int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq; int minM = info->vco1.min_m, maxM = info->vco1.max_m; int minN = info->vco1.min_n, maxN = info->vco1.max_n; @@ -136,7 +136,7 @@ getMNP_double(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - int chip_version = nvkm_bios(subdev)->version.chip; + int chip_version = subdev->device->bios->version.chip; int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq; int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq; int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq; @@ -240,6 +240,6 @@ nv04_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, u32 freq, } if (!ret) - nv_error(subdev, "unable to compute acceptable pll values\n"); + nvkm_error(subdev, "unable to compute acceptable pll values\n"); return ret; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h new file mode 100644 index 000000000..51eafc00c --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h @@ -0,0 +1,26 @@ +#ifndef __NVKM_CLK_PRIV_H__ +#define __NVKM_CLK_PRIV_H__ +#define nvkm_clk(p) container_of((p), struct nvkm_clk, subdev) +#include <subdev/clk.h> + +struct nvkm_clk_func { + int (*init)(struct nvkm_clk *); + void (*fini)(struct nvkm_clk *); + int (*read)(struct nvkm_clk *, enum nv_clk_src); + int (*calc)(struct nvkm_clk *, struct nvkm_cstate *); + int (*prog)(struct nvkm_clk *); + void (*tidy)(struct nvkm_clk *); + struct nvkm_pstate *pstates; + int nr_pstates; + struct nvkm_domain domains[]; +}; + +int nvkm_clk_ctor(const struct nvkm_clk_func *, struct nvkm_device *, int, + bool allow_reclock, struct nvkm_clk *); +int nvkm_clk_new_(const struct nvkm_clk_func *, struct nvkm_device *, int, + bool allow_reclock, struct nvkm_clk **); + +int nv04_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, int clk, + struct nvkm_pll_vals *); +int nv04_clk_pll_prog(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index b0d7c5f40..5f25402f6 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -23,74 +23,108 @@ */ #include "priv.h" -#include <core/device.h> #include <core/option.h> #include <subdev/vga.h> -int -_nvkm_devinit_fini(struct nvkm_object *object, bool suspend) +u32 +nvkm_devinit_mmio(struct nvkm_devinit *init, u32 addr) { - struct nvkm_devinit *devinit = (void *)object; + if (init->func->mmio) + addr = init->func->mmio(init, addr); + return addr; +} - /* force full reinit on resume */ - if (suspend) - devinit->post = true; +int +nvkm_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 khz) +{ + return init->func->pll_set(init, type, khz); +} - /* unlock the extended vga crtc regs */ - nv_lockvgac(devinit, false); +void +nvkm_devinit_meminit(struct nvkm_devinit *init) +{ + if (init->func->meminit) + init->func->meminit(init); +} - return nvkm_subdev_fini(&devinit->base, suspend); +u64 +nvkm_devinit_disable(struct nvkm_devinit *init) +{ + if (init && init->func->disable) + return init->func->disable(init); + return 0; } int -_nvkm_devinit_init(struct nvkm_object *object) +nvkm_devinit_post(struct nvkm_devinit *init, u64 *disable) { - struct nvkm_devinit_impl *impl = (void *)object->oclass; - struct nvkm_devinit *devinit = (void *)object; - int ret; + int ret = 0; + if (init && init->func->post) + ret = init->func->post(init, init->post); + *disable = nvkm_devinit_disable(init); + return ret; +} - ret = nvkm_subdev_init(&devinit->base); - if (ret) - return ret; +static int +nvkm_devinit_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_devinit *init = nvkm_devinit(subdev); + /* force full reinit on resume */ + if (suspend) + init->post = true; + return 0; +} + +static int +nvkm_devinit_preinit(struct nvkm_subdev *subdev) +{ + struct nvkm_devinit *init = nvkm_devinit(subdev); - ret = impl->post(&devinit->base, devinit->post); - if (ret) - return ret; + if (init->func->preinit) + init->func->preinit(init); - if (impl->disable) - nv_device(devinit)->disable_mask |= impl->disable(devinit); + /* unlock the extended vga crtc regs */ + nvkm_lockvgac(subdev->device, false); return 0; } -void -_nvkm_devinit_dtor(struct nvkm_object *object) +static int +nvkm_devinit_init(struct nvkm_subdev *subdev) +{ + struct nvkm_devinit *init = nvkm_devinit(subdev); + if (init->func->init) + init->func->init(init); + return 0; +} + +static void * +nvkm_devinit_dtor(struct nvkm_subdev *subdev) { - struct nvkm_devinit *devinit = (void *)object; + struct nvkm_devinit *init = nvkm_devinit(subdev); + void *data = init; - /* lock crtc regs */ - nv_lockvgac(devinit, true); + if (init->func->dtor) + data = init->func->dtor(init); - nvkm_subdev_destroy(&devinit->base); + /* lock crtc regs */ + nvkm_lockvgac(subdev->device, true); + return data; } -int -nvkm_devinit_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int size, void **pobject) +static const struct nvkm_subdev_func +nvkm_devinit = { + .dtor = nvkm_devinit_dtor, + .preinit = nvkm_devinit_preinit, + .init = nvkm_devinit_init, + .fini = nvkm_devinit_fini, +}; + +void +nvkm_devinit_ctor(const struct nvkm_devinit_func *func, + struct nvkm_device *device, int index, + struct nvkm_devinit *init) { - struct nvkm_devinit_impl *impl = (void *)oclass; - struct nvkm_device *device = nv_device(parent); - struct nvkm_devinit *devinit; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "DEVINIT", - "init", size, pobject); - devinit = *pobject; - if (ret) - return ret; - - devinit->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false); - devinit->meminit = impl->meminit; - devinit->pll_set = impl->pll_set; - devinit->mmio = impl->mmio; - return 0; + nvkm_subdev_ctor(&nvkm_devinit, device, index, 0, &init->subdev); + init->func = func; + init->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false); } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h index 36684c3f9..6c5bbff12 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h @@ -23,7 +23,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include <core/device.h> #include <subdev/fb/regsnv04.h> #define NV04_PFB_DEBUG_0 0x00100080 @@ -48,8 +47,8 @@ static inline struct io_mapping * fbmem_init(struct nvkm_device *dev) { - return io_mapping_create_wc(nv_device_resource_start(dev, 1), - nv_device_resource_len(dev, 1)); + return io_mapping_create_wc(dev->func->resource_addr(dev, 1), + dev->func->resource_size(dev, 1)); } static inline void diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c index ca776ce75..e895289bf 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c @@ -27,40 +27,42 @@ #include <subdev/bios/init.h> static u64 -g84_devinit_disable(struct nvkm_devinit *devinit) +g84_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MPEG); - disable |= (1ULL << NVDEV_ENGINE_VP); - disable |= (1ULL << NVDEV_ENGINE_BSP); - disable |= (1ULL << NVDEV_ENGINE_CIPHER); + disable |= (1ULL << NVKM_ENGINE_MPEG); + disable |= (1ULL << NVKM_ENGINE_VP); + disable |= (1ULL << NVKM_ENGINE_BSP); + disable |= (1ULL << NVKM_ENGINE_CIPHER); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_BSP); + disable |= (1ULL << NVKM_ENGINE_BSP); if (!(r00154c & 0x00000040)) - disable |= (1ULL << NVDEV_ENGINE_CIPHER); + disable |= (1ULL << NVKM_ENGINE_CIPHER); return disable; } -struct nvkm_oclass * -g84_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x84), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +g84_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = nv50_devinit_pll_set, .disable = g84_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +g84_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&g84_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c index d29bacee6..a9d45844d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c @@ -27,39 +27,41 @@ #include <subdev/bios/init.h> static u64 -g98_devinit_disable(struct nvkm_devinit *devinit) +g98_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSVLD); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (!(r00154c & 0x00000040)) - disable |= (1ULL << NVDEV_ENGINE_SEC); + disable |= (1ULL << NVKM_ENGINE_SEC); return disable; } -struct nvkm_oclass * -g98_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x98), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +g98_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = nv50_devinit_pll_set, .disable = g98_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +g98_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&g98_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c index c61102f70..22b0140e2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c @@ -29,19 +29,19 @@ #include <subdev/clk/pll.h> int -gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) +gf100_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) { - struct nv50_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; struct nvbios_pll info; int N, fN, M, P; int ret; - ret = nvbios_pll_parse(bios, type, &info); + ret = nvbios_pll_parse(device->bios, type, &info); if (ret) return ret; - ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P); + ret = gt215_pll_calc(subdev, &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; @@ -50,12 +50,12 @@ gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) case PLL_VPLL1: case PLL_VPLL2: case PLL_VPLL3: - nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); - nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); - nv_wr32(priv, info.reg + 0x10, fN << 16); + nvkm_mask(device, info.reg + 0x0c, 0x00000000, 0x00000100); + nvkm_wr32(device, info.reg + 0x04, (P << 16) | (N << 8) | M); + nvkm_wr32(device, info.reg + 0x10, fN << 16); break; default: - nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); + nvkm_warn(subdev, "%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } @@ -64,64 +64,44 @@ gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } static u64 -gf100_devinit_disable(struct nvkm_devinit *devinit) +gf100_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r022500 = nv_rd32(priv, 0x022500); + struct nvkm_device *device = init->subdev.device; + u32 r022500 = nvkm_rd32(device, 0x022500); u64 disable = 0ULL; if (r022500 & 0x00000001) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (r022500 & 0x00000002) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (r022500 & 0x00000004) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (r022500 & 0x00000008) - disable |= (1ULL << NVDEV_ENGINE_MSENC); + disable |= (1ULL << NVKM_ENGINE_MSENC); if (r022500 & 0x00000100) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); if (r022500 & 0x00000200) - disable |= (1ULL << NVDEV_ENGINE_CE1); + disable |= (1ULL << NVKM_ENGINE_CE1); return disable; } +static const struct nvkm_devinit_func +gf100_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, + .pll_set = gf100_devinit_pll_set, + .disable = gf100_devinit_disable, +}; + int -gf100_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) { - struct nvkm_devinit_impl *impl = (void *)oclass; - struct nv50_devinit_priv *priv; - u64 disable; - int ret; - - ret = nvkm_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - disable = impl->disable(&priv->base); - if (disable & (1ULL << NVDEV_ENGINE_DISP)) - priv->base.post = true; - - return 0; + return nv50_devinit_new_(&gf100_devinit, device, index, pinit); } - -struct nvkm_oclass * -gf100_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, - .pll_set = gf100_devinit_pll_set, - .disable = gf100_devinit_disable, - .post = nvbios_init, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c index 87ca0ece3..2be98bd78 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c @@ -27,33 +27,35 @@ #include <subdev/bios/init.h> u64 -gm107_devinit_disable(struct nvkm_devinit *devinit) +gm107_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r021c00 = nv_rd32(priv, 0x021c00); - u32 r021c04 = nv_rd32(priv, 0x021c04); + struct nvkm_device *device = init->subdev.device; + u32 r021c00 = nvkm_rd32(device, 0x021c00); + u32 r021c04 = nvkm_rd32(device, 0x021c04); u64 disable = 0ULL; if (r021c00 & 0x00000001) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); if (r021c00 & 0x00000004) - disable |= (1ULL << NVDEV_ENGINE_CE2); + disable |= (1ULL << NVKM_ENGINE_CE2); if (r021c04 & 0x00000001) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); return disable; } -struct nvkm_oclass * -gm107_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +gm107_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = gf100_devinit_pll_set, .disable = gm107_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +gm107_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&gm107_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c index 1076fcf0d..2b9c3f11b 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c @@ -28,69 +28,74 @@ #include <subdev/bios/pmu.h> static void -pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec) +pmu_code(struct nv50_devinit *init, u32 pmu, u32 img, u32 len, bool sec) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_device *device = init->base.subdev.device; + struct nvkm_bios *bios = device->bios; int i; - nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu); + nvkm_wr32(device, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu); for (i = 0; i < len; i += 4) { if ((i & 0xff) == 0) - nv_wr32(priv, 0x10a188, (pmu + i) >> 8); - nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i)); + nvkm_wr32(device, 0x10a188, (pmu + i) >> 8); + nvkm_wr32(device, 0x10a184, nvbios_rd32(bios, img + i)); } while (i & 0xff) { - nv_wr32(priv, 0x10a184, 0x00000000); + nvkm_wr32(device, 0x10a184, 0x00000000); i += 4; } } static void -pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len) +pmu_data(struct nv50_devinit *init, u32 pmu, u32 img, u32 len) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_device *device = init->base.subdev.device; + struct nvkm_bios *bios = device->bios; int i; - nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu); + nvkm_wr32(device, 0x10a1c0, 0x01000000 | pmu); for (i = 0; i < len; i += 4) - nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i)); + nvkm_wr32(device, 0x10a1c4, nvbios_rd32(bios, img + i)); } static u32 -pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi) +pmu_args(struct nv50_devinit *init, u32 argp, u32 argi) { - nv_wr32(priv, 0x10a1c0, argp); - nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi); - return nv_rd32(priv, 0x10a1c4); + struct nvkm_device *device = init->base.subdev.device; + nvkm_wr32(device, 0x10a1c0, argp); + nvkm_wr32(device, 0x10a1c0, nvkm_rd32(device, 0x10a1c4) + argi); + return nvkm_rd32(device, 0x10a1c4); } static void -pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr) +pmu_exec(struct nv50_devinit *init, u32 init_addr) { - nv_wr32(priv, 0x10a104, init_addr); - nv_wr32(priv, 0x10a10c, 0x00000000); - nv_wr32(priv, 0x10a100, 0x00000002); + struct nvkm_device *device = init->base.subdev.device; + nvkm_wr32(device, 0x10a104, init_addr); + nvkm_wr32(device, 0x10a10c, 0x00000000); + nvkm_wr32(device, 0x10a100, 0x00000002); } static int -pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post, +pmu_load(struct nv50_devinit *init, u8 type, bool post, u32 *init_addr_pmu, u32 *args_addr_pmu) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pmuR pmu; if (!nvbios_pmuRm(bios, type, &pmu)) { - nv_error(priv, "VBIOS PMU fuc %02x not found\n", type); + nvkm_error(subdev, "VBIOS PMU fuc %02x not found\n", type); return -EINVAL; } if (!post) return 0; - pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false); - pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true); - pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size); + pmu_code(init, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false); + pmu_code(init, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true); + pmu_data(init, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size); if (init_addr_pmu) { *init_addr_pmu = pmu.init_addr_pmu; @@ -98,75 +103,79 @@ pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post, return 0; } - return pmu_exec(priv, pmu.init_addr_pmu), 0; + return pmu_exec(init, pmu.init_addr_pmu), 0; } static int -gm204_devinit_post(struct nvkm_subdev *subdev, bool post) +gm204_devinit_post(struct nvkm_devinit *base, bool post) { - struct nv50_devinit_priv *priv = (void *)nvkm_devinit(subdev); - struct nvkm_bios *bios = nvkm_bios(priv); + struct nv50_devinit *init = nv50_devinit(base); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct bit_entry bit_I; - u32 init, args; + u32 exec, args; int ret; if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 || bit_I.length < 0x1c) { - nv_error(priv, "VBIOS PMU init data not found\n"); + nvkm_error(subdev, "VBIOS PMU init data not found\n"); return -EINVAL; } /* reset PMU and load init table parser ucode */ if (post) { - nv_mask(priv, 0x000200, 0x00002000, 0x00000000); - nv_mask(priv, 0x000200, 0x00002000, 0x00002000); - nv_rd32(priv, 0x000200); - while (nv_rd32(priv, 0x10a10c) & 0x00000006) { + nvkm_mask(device, 0x000200, 0x00002000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00002000, 0x00002000); + nvkm_rd32(device, 0x000200); + while (nvkm_rd32(device, 0x10a10c) & 0x00000006) { } } - ret = pmu_load(priv, 0x04, post, &init, &args); + ret = pmu_load(init, 0x04, post, &exec, &args); if (ret) return ret; /* upload first chunk of init data */ if (post) { - u32 pmu = pmu_args(priv, args + 0x08, 0x08); - u32 img = nv_ro16(bios, bit_I.offset + 0x14); - u32 len = nv_ro16(bios, bit_I.offset + 0x16); - pmu_data(priv, pmu, img, len); + u32 pmu = pmu_args(init, args + 0x08, 0x08); + u32 img = nvbios_rd16(bios, bit_I.offset + 0x14); + u32 len = nvbios_rd16(bios, bit_I.offset + 0x16); + pmu_data(init, pmu, img, len); } /* upload second chunk of init data */ if (post) { - u32 pmu = pmu_args(priv, args + 0x08, 0x10); - u32 img = nv_ro16(bios, bit_I.offset + 0x18); - u32 len = nv_ro16(bios, bit_I.offset + 0x1a); - pmu_data(priv, pmu, img, len); + u32 pmu = pmu_args(init, args + 0x08, 0x10); + u32 img = nvbios_rd16(bios, bit_I.offset + 0x18); + u32 len = nvbios_rd16(bios, bit_I.offset + 0x1a); + pmu_data(init, pmu, img, len); } /* execute init tables */ if (post) { - nv_wr32(priv, 0x10a040, 0x00005000); - pmu_exec(priv, init); - while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) { + nvkm_wr32(device, 0x10a040, 0x00005000); + pmu_exec(init, exec); + while (!(nvkm_rd32(device, 0x10a040) & 0x00002000)) { } } /* load and execute some other ucode image (bios therm?) */ - return pmu_load(priv, 0x01, post, NULL, NULL); + return pmu_load(init, 0x01, post, NULL, NULL); } -struct nvkm_oclass * -gm204_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +gm204_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = gm204_devinit_post, .pll_set = gf100_devinit_pll_set, .disable = gm107_devinit_disable, - .post = gm204_devinit_post, -}.base; +}; + +int +gm204_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&gm204_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c index 6a3e8d4ef..9a8522fa9 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c @@ -29,32 +29,32 @@ #include <subdev/clk/pll.h> int -gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) +gt215_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) { - struct nv50_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; struct nvbios_pll info; int N, fN, M, P; int ret; - ret = nvbios_pll_parse(bios, type, &info); + ret = nvbios_pll_parse(device->bios, type, &info); if (ret) return ret; - ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P); + ret = gt215_pll_calc(subdev, &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: - nv_wr32(priv, info.reg + 0, 0x50000610); - nv_mask(priv, info.reg + 4, 0x003fffff, - (P << 16) | (M << 8) | N); - nv_wr32(priv, info.reg + 8, fN); + nvkm_wr32(device, info.reg + 0, 0x50000610); + nvkm_mask(device, info.reg + 4, 0x003fffff, + (P << 16) | (M << 8) | N); + nvkm_wr32(device, info.reg + 8, fN); break; default: - nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); + nvkm_warn(subdev, "%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } @@ -63,24 +63,24 @@ gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } static u64 -gt215_devinit_disable(struct nvkm_devinit *devinit) +gt215_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (!(r00154c & 0x00000200)) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); return disable; } @@ -99,9 +99,10 @@ gt215_devinit_mmio_part[] = { }; static u32 -gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) +gt215_devinit_mmio(struct nvkm_devinit *base, u32 addr) { - struct nv50_devinit_priv *priv = (void *)devinit; + struct nv50_devinit *init = nv50_devinit(base); + struct nvkm_device *device = init->base.subdev.device; u32 *mmio = gt215_devinit_mmio_part; /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP @@ -113,7 +114,7 @@ gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) * * the binary driver avoids touching these registers at all, however, * the video bios doesn't care and does what the scripts say. it's - * presumed that the io-port access to priv registers isn't effected + * presumed that the io-port access to init registers isn't effected * by the screw-up bug mentioned above. * * really, a new opcode should've been invented to handle these @@ -122,9 +123,9 @@ gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) while (mmio[0]) { if (addr >= mmio[0] && addr <= mmio[1]) { u32 part = (addr / mmio[2]) & 7; - if (!priv->r001540) - priv->r001540 = nv_rd32(priv, 0x001540); - if (part >= hweight8((priv->r001540 >> 16) & 0xff)) + if (!init->r001540) + init->r001540 = nvkm_rd32(device, 0x001540); + if (part >= hweight8((init->r001540 >> 16) & 0xff)) return ~0; return addr; } @@ -134,17 +135,19 @@ gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) return addr; } -struct nvkm_oclass * -gt215_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0xa3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +gt215_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, + .mmio = gt215_devinit_mmio, .pll_set = gt215_devinit_pll_set, .disable = gt215_devinit_disable, - .mmio = gt215_devinit_mmio, - .post = nvbios_init, -}.base; +}; + +int +gt215_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(>215_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c index 55cf48bbc..ce4f718e9 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c @@ -27,40 +27,42 @@ #include <subdev/bios/init.h> static u64 -mcp89_devinit_disable(struct nvkm_devinit *devinit) +mcp89_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (!(r00154c & 0x00000040)) - disable |= (1ULL << NVDEV_ENGINE_VIC); + disable |= (1ULL << NVKM_ENGINE_VIC); if (!(r00154c & 0x00000200)) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); return disable; } -struct nvkm_oclass * -mcp89_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0xaf), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +mcp89_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = gt215_devinit_pll_set, .disable = mcp89_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +mcp89_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&mcp89_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index 03a0da834..c8d455346 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -33,25 +33,26 @@ #include <subdev/vga.h> static void -nv04_devinit_meminit(struct nvkm_devinit *devinit) +nv04_devinit_meminit(struct nvkm_devinit *init) { - struct nv04_devinit_priv *priv = (void *)devinit; + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; u32 patt = 0xdeadbeef; struct io_mapping *fb; int i; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(device); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } /* Sequencer and refresh off */ - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20); - nv_mask(priv, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) | 0x20); + nvkm_mask(device, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); - nv_mask(priv, NV04_PFB_BOOT_0, ~0, + nvkm_mask(device, NV04_PFB_BOOT_0, ~0, NV04_PFB_BOOT_0_RAM_AMOUNT_16MB | NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT); @@ -62,49 +63,49 @@ nv04_devinit_meminit(struct nvkm_devinit *devinit) fbmem_poke(fb, 0x400000, patt + 1); if (fbmem_peek(fb, 0) == patt + 1) { - nv_mask(priv, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT); - nv_mask(priv, NV04_PFB_DEBUG_0, + nvkm_mask(device, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); for (i = 0; i < 4; i++) fbmem_poke(fb, 4 * i, patt); if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff)) - nv_mask(priv, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); } else if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) { - nv_mask(priv, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); } else if (fbmem_peek(fb, 0) != patt) { if (fbmem_readback(fb, 0x800000, patt)) - nv_mask(priv, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); else - nv_mask(priv, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT); } else if (!fbmem_readback(fb, 0x800000, patt)) { - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); } /* Refresh on, sequencer on */ - nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20); + nvkm_mask(device, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) & ~0x20); fbmem_fini(fb); } @@ -139,11 +140,12 @@ powerctrl_1_shift(int chip_version, int reg) } void -setPLL_single(struct nvkm_devinit *devinit, u32 reg, +setPLL_single(struct nvkm_devinit *init, u32 reg, struct nvkm_pll_vals *pv) { - int chip_version = nvkm_bios(devinit)->version.chip; - uint32_t oldpll = nv_rd32(devinit, reg); + struct nvkm_device *device = init->subdev.device; + int chip_version = device->bios->version.chip; + uint32_t oldpll = nvkm_rd32(device, reg); int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff; uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1; uint32_t saved_powerctrl_1 = 0; @@ -153,30 +155,30 @@ setPLL_single(struct nvkm_devinit *devinit, u32 reg, return; /* already set */ if (shift_powerctrl_1 >= 0) { - saved_powerctrl_1 = nv_rd32(devinit, 0x001584); - nv_wr32(devinit, 0x001584, + saved_powerctrl_1 = nvkm_rd32(device, 0x001584); + nvkm_wr32(device, 0x001584, (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | 1 << shift_powerctrl_1); } if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1)) /* upclock -- write new post divider first */ - nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff)); + nvkm_wr32(device, reg, pv->log2P << 16 | (oldpll & 0xffff)); else /* downclock -- write new NM first */ - nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1); + nvkm_wr32(device, reg, (oldpll & 0xffff0000) | pv->NM1); if ((chip_version < 0x17 || chip_version == 0x1a) && chip_version != 0x11) /* wait a bit on older chips */ msleep(64); - nv_rd32(devinit, reg); + nvkm_rd32(device, reg); /* then write the other half as well */ - nv_wr32(devinit, reg, pll); + nvkm_wr32(device, reg, pll); if (shift_powerctrl_1 >= 0) - nv_wr32(devinit, 0x001584, saved_powerctrl_1); + nvkm_wr32(device, 0x001584, saved_powerctrl_1); } static uint32_t @@ -193,14 +195,15 @@ new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580) } void -setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, +setPLL_double_highregs(struct nvkm_devinit *init, u32 reg1, struct nvkm_pll_vals *pv) { - int chip_version = nvkm_bios(devinit)->version.chip; + struct nvkm_device *device = init->subdev.device; + int chip_version = device->bios->version.chip; bool nv3035 = chip_version == 0x30 || chip_version == 0x35; uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70); - uint32_t oldpll1 = nv_rd32(devinit, reg1); - uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0; + uint32_t oldpll1 = nvkm_rd32(device, reg1); + uint32_t oldpll2 = !nv3035 ? nvkm_rd32(device, reg2) : 0; uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1; uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2; uint32_t oldramdac580 = 0, ramdac580 = 0; @@ -215,7 +218,7 @@ setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, pll2 = 0; } if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */ - oldramdac580 = nv_rd32(devinit, 0x680580); + oldramdac580 = nvkm_rd32(device, 0x680580); ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580); if (oldramdac580 != ramdac580) oldpll1 = ~0; /* force mismatch */ @@ -231,8 +234,8 @@ setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, return; /* already set */ if (shift_powerctrl_1 >= 0) { - saved_powerctrl_1 = nv_rd32(devinit, 0x001584); - nv_wr32(devinit, 0x001584, + saved_powerctrl_1 = nvkm_rd32(device, 0x001584); + nvkm_wr32(device, 0x001584, (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | 1 << shift_powerctrl_1); } @@ -251,26 +254,26 @@ setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, shift_c040 += 2; } - savedc040 = nv_rd32(devinit, 0xc040); + savedc040 = nvkm_rd32(device, 0xc040); if (shift_c040 != 14) - nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040)); + nvkm_wr32(device, 0xc040, savedc040 & ~(3 << shift_c040)); } if (oldramdac580 != ramdac580) - nv_wr32(devinit, 0x680580, ramdac580); + nvkm_wr32(device, 0x680580, ramdac580); if (!nv3035) - nv_wr32(devinit, reg2, pll2); - nv_wr32(devinit, reg1, pll1); + nvkm_wr32(device, reg2, pll2); + nvkm_wr32(device, reg1, pll1); if (shift_powerctrl_1 >= 0) - nv_wr32(devinit, 0x001584, saved_powerctrl_1); + nvkm_wr32(device, 0x001584, saved_powerctrl_1); if (chip_version >= 0x40) - nv_wr32(devinit, 0xc040, savedc040); + nvkm_wr32(device, 0xc040, savedc040); } void -setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, +setPLL_double_lowregs(struct nvkm_devinit *init, u32 NMNMreg, struct nvkm_pll_vals *pv) { /* When setting PLLs, there is a merry game of disabling and enabling @@ -280,10 +283,10 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, * combined herein. Without luck it deviates from each card's formula * so as to not work on any :) */ - + struct nvkm_device *device = init->subdev.device; uint32_t Preg = NMNMreg - 4; bool mpll = Preg == 0x4020; - uint32_t oldPval = nv_rd32(devinit, Preg); + uint32_t oldPval = nvkm_rd32(device, Preg); uint32_t NMNM = pv->NM2 << 16 | pv->NM1; uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) | 0xc << 28 | pv->log2P << 16; @@ -292,7 +295,7 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, uint32_t maskc040 = ~(3 << 14), savedc040; bool single_stage = !pv->NM2 || pv->N2 == pv->M2; - if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) + if (nvkm_rd32(device, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) return; if (Preg == 0x4000) @@ -304,7 +307,7 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, struct nvbios_pll info; uint8_t Pval2; - if (nvbios_pll_parse(nvkm_bios(devinit), Preg, &info)) + if (nvbios_pll_parse(device->bios, Preg, &info)) return; Pval2 = pv->log2P + info.bias_p; @@ -312,47 +315,48 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, Pval2 = info.max_p; Pval |= 1 << 28 | Pval2 << 20; - saved4600 = nv_rd32(devinit, 0x4600); - nv_wr32(devinit, 0x4600, saved4600 | 8 << 28); + saved4600 = nvkm_rd32(device, 0x4600); + nvkm_wr32(device, 0x4600, saved4600 | 8 << 28); } if (single_stage) Pval |= mpll ? 1 << 12 : 1 << 8; - nv_wr32(devinit, Preg, oldPval | 1 << 28); - nv_wr32(devinit, Preg, Pval & ~(4 << 28)); + nvkm_wr32(device, Preg, oldPval | 1 << 28); + nvkm_wr32(device, Preg, Pval & ~(4 << 28)); if (mpll) { Pval |= 8 << 20; - nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28)); - nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28)); + nvkm_wr32(device, 0x4020, Pval & ~(0xc << 28)); + nvkm_wr32(device, 0x4038, Pval & ~(0xc << 28)); } - savedc040 = nv_rd32(devinit, 0xc040); - nv_wr32(devinit, 0xc040, savedc040 & maskc040); + savedc040 = nvkm_rd32(device, 0xc040); + nvkm_wr32(device, 0xc040, savedc040 & maskc040); - nv_wr32(devinit, NMNMreg, NMNM); + nvkm_wr32(device, NMNMreg, NMNM); if (NMNMreg == 0x4024) - nv_wr32(devinit, 0x403c, NMNM); + nvkm_wr32(device, 0x403c, NMNM); - nv_wr32(devinit, Preg, Pval); + nvkm_wr32(device, Preg, Pval); if (mpll) { Pval &= ~(8 << 20); - nv_wr32(devinit, 0x4020, Pval); - nv_wr32(devinit, 0x4038, Pval); - nv_wr32(devinit, 0x4600, saved4600); + nvkm_wr32(device, 0x4020, Pval); + nvkm_wr32(device, 0x4038, Pval); + nvkm_wr32(device, 0x4600, saved4600); } - nv_wr32(devinit, 0xc040, savedc040); + nvkm_wr32(device, 0xc040, savedc040); if (mpll) { - nv_wr32(devinit, 0x4020, Pval & ~(1 << 28)); - nv_wr32(devinit, 0x4038, Pval & ~(1 << 28)); + nvkm_wr32(device, 0x4020, Pval & ~(1 << 28)); + nvkm_wr32(device, 0x4038, Pval & ~(1 << 28)); } } int nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(devinit); + struct nvkm_subdev *subdev = &devinit->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvkm_pll_vals pv; struct nvbios_pll info; int cv = bios->version.chip; @@ -363,8 +367,7 @@ nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) if (ret) return ret; - ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, - &N1, &M1, &N2, &M2, &P); + ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) return -EINVAL; @@ -388,83 +391,76 @@ nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } int -nv04_devinit_fini(struct nvkm_object *object, bool suspend) +nv04_devinit_post(struct nvkm_devinit *init, bool execute) { - struct nv04_devinit_priv *priv = (void *)object; - int ret; + return nvbios_init(&init->subdev, execute); +} - /* make i2c busses accessible */ - nv_mask(priv, 0x000200, 0x00000001, 0x00000001); +void +nv04_devinit_preinit(struct nvkm_devinit *base) +{ + struct nv04_devinit *init = nv04_devinit(base); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; - ret = nvkm_devinit_fini(&priv->base, suspend); - if (ret) - return ret; + /* make i2c busses accessible */ + nvkm_mask(device, 0x000200, 0x00000001, 0x00000001); /* unslave crtcs */ - if (priv->owner < 0) - priv->owner = nv_rdvgaowner(priv); - nv_wrvgaowner(priv, 0); - return 0; -} - -int -nv04_devinit_init(struct nvkm_object *object) -{ - struct nv04_devinit_priv *priv = (void *)object; - - if (!priv->base.post) { - u32 htotal = nv_rdvgac(priv, 0, 0x06); - htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8; - htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4; - htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10; - htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11; + if (init->owner < 0) + init->owner = nvkm_rdvgaowner(device); + nvkm_wrvgaowner(device, 0); + + if (!init->base.post) { + u32 htotal = nvkm_rdvgac(device, 0, 0x06); + htotal |= (nvkm_rdvgac(device, 0, 0x07) & 0x01) << 8; + htotal |= (nvkm_rdvgac(device, 0, 0x07) & 0x20) << 4; + htotal |= (nvkm_rdvgac(device, 0, 0x25) & 0x01) << 10; + htotal |= (nvkm_rdvgac(device, 0, 0x41) & 0x01) << 11; if (!htotal) { - nv_info(priv, "adaptor not initialised\n"); - priv->base.post = true; + nvkm_debug(subdev, "adaptor not initialised\n"); + init->base.post = true; } } - - return nvkm_devinit_init(&priv->base); } -void -nv04_devinit_dtor(struct nvkm_object *object) +void * +nv04_devinit_dtor(struct nvkm_devinit *base) { - struct nv04_devinit_priv *priv = (void *)object; - + struct nv04_devinit *init = nv04_devinit(base); /* restore vga owner saved at first init */ - nv_wrvgaowner(priv, priv->owner); - - nvkm_devinit_destroy(&priv->base); + nvkm_wrvgaowner(init->base.subdev.device, init->owner); + return init; } int -nv04_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_devinit_new_(const struct nvkm_devinit_func *func, + struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) { - struct nv04_devinit_priv *priv; - int ret; + struct nv04_devinit *init; - ret = nvkm_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(init = kzalloc(sizeof(*init), GFP_KERNEL))) + return -ENOMEM; + *pinit = &init->base; - priv->owner = -1; + nvkm_devinit_ctor(func, device, index, &init->base); + init->owner = -1; return 0; } -struct nvkm_oclass * -nv04_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv04_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv04_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv04_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv04_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h index 7c63abf11..4a87c8c2b 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h @@ -1,19 +1,19 @@ -#ifndef __NVKM_DEVINIT_NV04_H__ -#define __NVKM_DEVINIT_NV04_H__ +#ifndef __NV04_DEVINIT_H__ +#define __NV04_DEVINIT_H__ +#define nv04_devinit(p) container_of((p), struct nv04_devinit, base) #include "priv.h" struct nvkm_pll_vals; -struct nv04_devinit_priv { +struct nv04_devinit { struct nvkm_devinit base; int owner; }; -int nv04_devinit_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv04_devinit_dtor(struct nvkm_object *); -int nv04_devinit_init(struct nvkm_object *); -int nv04_devinit_fini(struct nvkm_object *, bool); +int nv04_devinit_new_(const struct nvkm_devinit_func *, struct nvkm_device *, + int, struct nvkm_devinit **); +void *nv04_devinit_dtor(struct nvkm_devinit *); +void nv04_devinit_preinit(struct nvkm_devinit *); +void nv04_devinit_fini(struct nvkm_devinit *); int nv04_devinit_pll_set(struct nvkm_devinit *, u32, u32); void setPLL_single(struct nvkm_devinit *, u32, struct nvkm_pll_vals *); diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c index def864921..9891eadca 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c @@ -32,7 +32,7 @@ #include <subdev/vga.h> static void -nv05_devinit_meminit(struct nvkm_devinit *devinit) +nv05_devinit_meminit(struct nvkm_devinit *init) { static const u8 default_config_tab[][2] = { { 0x24, 0x00 }, @@ -44,8 +44,9 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) { 0x06, 0x00 }, { 0x00, 0x00 } }; - struct nv04_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct io_mapping *fb; u32 patt = 0xdeadbeef; u16 data; @@ -53,88 +54,90 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) int i, v; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(device); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } - strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2; + strap = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2; if ((data = bmp_mem_init_table(bios))) { - ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0); - ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1); + ramcfg[0] = nvbios_rd08(bios, data + 2 * strap + 0); + ramcfg[1] = nvbios_rd08(bios, data + 2 * strap + 1); } else { ramcfg[0] = default_config_tab[strap][0]; ramcfg[1] = default_config_tab[strap][1]; } /* Sequencer off */ - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) | 0x20); - if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) + if (nvkm_rd32(device, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) goto out; - nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + nvkm_mask(device, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); /* If present load the hardcoded scrambling table */ if (data) { for (i = 0, data += 0x10; i < 8; i++, data += 4) { - u32 scramble = nv_ro32(bios, data); - nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble); + u32 scramble = nvbios_rd32(bios, data); + nvkm_wr32(device, NV04_PFB_SCRAMBLE(i), scramble); } } /* Set memory type/width/length defaults depending on the straps */ - nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); + nvkm_mask(device, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); if (ramcfg[1] & 0x80) - nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); + nvkm_mask(device, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); - nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); - nv_mask(priv, NV04_PFB_CFG1, 0, 1); + nvkm_mask(device, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); + nvkm_mask(device, NV04_PFB_CFG1, 0, 1); /* Probe memory bus width */ for (i = 0; i < 4; i++) fbmem_poke(fb, 4 * i, patt); if (fbmem_peek(fb, 0xc) != patt) - nv_mask(priv, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128, 0); /* Probe memory length */ - v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; + v = nvkm_rd32(device, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB && (!fbmem_readback(fb, 0x1000000, ++patt) || !fbmem_readback(fb, 0, ++patt))) - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_16MB); if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB && !fbmem_readback(fb, 0x800000, ++patt)) - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); if (!fbmem_readback(fb, 0x400000, ++patt)) - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); out: /* Sequencer on */ - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) & ~0x20); fbmem_fini(fb); } -struct nvkm_oclass * -nv05_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x05), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv05_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv05_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv05_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv05_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c index 7aabc1bf0..570822f83 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c @@ -30,33 +30,33 @@ #include <subdev/bios/init.h> static void -nv10_devinit_meminit(struct nvkm_devinit *devinit) +nv10_devinit_meminit(struct nvkm_devinit *init) { - struct nv04_devinit_priv *priv = (void *)devinit; + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; static const int mem_width[] = { 0x10, 0x00, 0x20 }; int mem_width_count; uint32_t patt = 0xdeadbeef; struct io_mapping *fb; int i, j, k; - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) + if (device->card_type >= NV_11 && device->chipset >= 0x17) mem_width_count = 3; else mem_width_count = 2; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(device); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } - nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + nvkm_wr32(device, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Probe memory bus width */ for (i = 0; i < mem_width_count; i++) { - nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]); + nvkm_mask(device, NV04_PFB_CFG0, 0x30, mem_width[i]); for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) @@ -75,7 +75,7 @@ mem_width_found: /* Probe amount of installed memory */ for (i = 0; i < 4; i++) { - int off = nv_rd32(priv, 0x10020c) - 0x100000; + int off = nvkm_rd32(device, 0x10020c) - 0x100000; fbmem_poke(fb, off, patt); fbmem_poke(fb, 0, 0); @@ -90,22 +90,24 @@ mem_width_found: } /* IC missing - disable the upper half memory space. */ - nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0); + nvkm_mask(device, NV04_PFB_CFG0, 0x1000, 0); amount_found: fbmem_fini(fb); } -struct nvkm_oclass * -nv10_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x10), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv10_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv10_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv10_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv10_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c index 9f36fff5a..fefafec7e 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c @@ -26,15 +26,17 @@ #include <subdev/bios.h> #include <subdev/bios/init.h> -struct nvkm_oclass * -nv1a_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x1a), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv1a_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv1a_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv1a_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c index 02fcfd921..4ef04e0d8 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c @@ -30,48 +30,50 @@ #include <subdev/bios/init.h> static void -nv20_devinit_meminit(struct nvkm_devinit *devinit) +nv20_devinit_meminit(struct nvkm_devinit *init) { - struct nv04_devinit_priv *priv = (void *)devinit; - struct nvkm_device *device = nv_device(priv); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900); uint32_t amount, off; struct io_mapping *fb; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(device); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } - nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + nvkm_wr32(device, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Allow full addressing */ - nv_mask(priv, NV04_PFB_CFG0, 0, mask); + nvkm_mask(device, NV04_PFB_CFG0, 0, mask); - amount = nv_rd32(priv, 0x10020c); + amount = nvkm_rd32(device, 0x10020c); for (off = amount; off > 0x2000000; off -= 0x2000000) fbmem_poke(fb, off - 4, off); - amount = nv_rd32(priv, 0x10020c); + amount = nvkm_rd32(device, 0x10020c); if (amount != fbmem_peek(fb, amount - 4)) /* IC missing - disable the upper half memory space. */ - nv_mask(priv, NV04_PFB_CFG0, mask, 0); + nvkm_mask(device, NV04_PFB_CFG0, mask, 0); fbmem_fini(fb); } -struct nvkm_oclass * -nv20_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x20), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv20_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv20_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv20_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv20_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index 26b7cb13e..337c2c692 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -29,47 +29,48 @@ #include <subdev/bios/init.h> #include <subdev/bios/pll.h> #include <subdev/clk/pll.h> -#include <subdev/ibus.h> #include <subdev/vga.h> int -nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) +nv50_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) { - struct nv50_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct nvbios_pll info; int N1, M1, N2, M2, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) { - nv_error(devinit, "failed to retrieve pll data, %d\n", ret); + nvkm_error(subdev, "failed to retrieve pll data, %d\n", ret); return ret; } - ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P); + ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) { - nv_error(devinit, "failed pll calculation\n"); + nvkm_error(subdev, "failed pll calculation\n"); return ret; } switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: - nv_wr32(priv, info.reg + 0, 0x10000611); - nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); - nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) | - (M2 << 16) | N2); + nvkm_wr32(device, info.reg + 0, 0x10000611); + nvkm_mask(device, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); + nvkm_mask(device, info.reg + 8, 0x7fff00ff, (P << 28) | + (M2 << 16) | N2); break; case PLL_MEMORY: - nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) | - (info.bias_p << 19) | - (P << 16)); - nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); + nvkm_mask(device, info.reg + 0, 0x01ff0000, + (P << 22) | + (info.bias_p << 19) | + (P << 16)); + nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); break; default: - nv_mask(priv, info.reg + 0, 0x00070000, (P << 16)); - nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); + nvkm_mask(device, info.reg + 0, 0x00070000, (P << 16)); + nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); break; } @@ -77,57 +78,68 @@ nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } static u64 -nv50_devinit_disable(struct nvkm_devinit *devinit) +nv50_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) - disable |= (1ULL << NVDEV_ENGINE_MPEG); + disable |= (1ULL << NVKM_ENGINE_MPEG); return disable; } -int -nv50_devinit_init(struct nvkm_object *object) +void +nv50_devinit_preinit(struct nvkm_devinit *base) { - struct nvkm_bios *bios = nvkm_bios(object); - struct nvkm_ibus *ibus = nvkm_ibus(object); - struct nv50_devinit_priv *priv = (void *)object; - struct nvbios_outp info; - struct dcb_output outp; - u8 ver = 0xff, hdr, cnt, len; - int ret, i = 0; + struct nv50_devinit *init = nv50_devinit(base); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; - if (!priv->base.post) { - if (!nv_rdvgac(priv, 0, 0x00) && - !nv_rdvgac(priv, 0, 0x1a)) { - nv_info(priv, "adaptor not initialised\n"); - priv->base.post = true; - } + /* our heuristics can't detect whether the board has had its + * devinit scripts executed or not if the display engine is + * missing, assume it's a secondary gpu which requires post + */ + if (!init->base.post) { + u64 disable = nvkm_devinit_disable(&init->base); + if (disable & (1ULL << NVKM_ENGINE_DISP)) + init->base.post = true; } - /* some boards appear to require certain priv register timeouts - * to be bumped before runing devinit scripts. not a clue why - * the vbios engineers didn't make the scripts just work... + /* magic to detect whether or not x86 vbios code has executed + * the devinit scripts to initialise the board */ - if (priv->base.post && ibus) - nv_ofuncs(ibus)->init(nv_object(ibus)); + if (!init->base.post) { + if (!nvkm_rdvgac(device, 0, 0x00) && + !nvkm_rdvgac(device, 0, 0x1a)) { + nvkm_debug(subdev, "adaptor not initialised\n"); + init->base.post = true; + } + } +} - ret = nvkm_devinit_init(&priv->base); - if (ret) - return ret; +void +nv50_devinit_init(struct nvkm_devinit *base) +{ + struct nv50_devinit *init = nv50_devinit(base); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvbios_outp info; + struct dcb_output outp; + u8 ver = 0xff, hdr, cnt, len; + int i = 0; /* if we ran the init tables, we have to execute the first script * pointer of each dcb entry's display encoder table in order * to properly initialise each encoder. */ - while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { + while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { if (nvbios_outp_match(bios, outp.hasht, outp.hashm, &ver, &hdr, &cnt, &len, &info)) { - struct nvbios_init init = { - .subdev = nv_subdev(priv), + struct nvbios_init exec = { + .subdev = subdev, .bios = bios, .offset = info.script[0], .outp = &outp, @@ -135,40 +147,39 @@ nv50_devinit_init(struct nvkm_object *object) .execute = 1, }; - nvbios_exec(&init); + nvbios_exec(&exec); } i++; } - - return 0; } int -nv50_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_devinit_new_(const struct nvkm_devinit_func *func, + struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) { - struct nv50_devinit_priv *priv; - int ret; + struct nv50_devinit *init; - ret = nvkm_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(init = kzalloc(sizeof(*init), GFP_KERNEL))) + return -ENOMEM; + *pinit = &init->base; + nvkm_devinit_ctor(func, device, index, &init->base); return 0; } -struct nvkm_oclass * -nv50_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +nv50_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = nv50_devinit_pll_set, .disable = nv50_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +nv50_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&nv50_devinit, device, index, pinit); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h index 9243521c8..5de70a848 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h @@ -1,16 +1,17 @@ -#ifndef __NVKM_DEVINIT_NV50_H__ -#define __NVKM_DEVINIT_NV50_H__ +#ifndef __NV50_DEVINIT_H__ +#define __NV50_DEVINIT_H__ +#define nv50_devinit(p) container_of((p), struct nv50_devinit, base) #include "priv.h" -struct nv50_devinit_priv { +struct nv50_devinit { struct nvkm_devinit base; u32 r001540; }; -int nv50_devinit_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -int nv50_devinit_init(struct nvkm_object *); +int nv50_devinit_new_(const struct nvkm_devinit_func *, struct nvkm_device *, + int, struct nvkm_devinit **); +void nv50_devinit_preinit(struct nvkm_devinit *); +void nv50_devinit_init(struct nvkm_devinit *); int nv50_devinit_pll_set(struct nvkm_devinit *, u32, u32); int gt215_devinit_pll_set(struct nvkm_devinit *, u32, u32); diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h index bb51a95d8..e1f6ae58f 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h @@ -1,34 +1,21 @@ #ifndef __NVKM_DEVINIT_PRIV_H__ #define __NVKM_DEVINIT_PRIV_H__ +#define nvkm_devinit(p) container_of((p), struct nvkm_devinit, subdev) #include <subdev/devinit.h> -struct nvkm_devinit_impl { - struct nvkm_oclass base; +struct nvkm_devinit_func { + void *(*dtor)(struct nvkm_devinit *); + void (*preinit)(struct nvkm_devinit *); + void (*init)(struct nvkm_devinit *); + int (*post)(struct nvkm_devinit *, bool post); + u32 (*mmio)(struct nvkm_devinit *, u32); void (*meminit)(struct nvkm_devinit *); int (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq); u64 (*disable)(struct nvkm_devinit *); - u32 (*mmio)(struct nvkm_devinit *, u32); - int (*post)(struct nvkm_subdev *, bool); }; -#define nvkm_devinit_create(p,e,o,d) \ - nvkm_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_devinit_destroy(p) ({ \ - struct nvkm_devinit *d = (p); \ - _nvkm_devinit_dtor(nv_object(d)); \ -}) -#define nvkm_devinit_init(p) ({ \ - struct nvkm_devinit *d = (p); \ - _nvkm_devinit_init(nv_object(d)); \ -}) -#define nvkm_devinit_fini(p,s) ({ \ - struct nvkm_devinit *d = (p); \ - _nvkm_devinit_fini(nv_object(d), (s)); \ -}) +void nvkm_devinit_ctor(const struct nvkm_devinit_func *, struct nvkm_device *, + int index, struct nvkm_devinit *); -int nvkm_devinit_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_devinit_dtor(struct nvkm_object *); -int _nvkm_devinit_init(struct nvkm_object *); -int _nvkm_devinit_fini(struct nvkm_object *, bool suspend); +int nv04_devinit_post(struct nvkm_devinit *, bool); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild index d6be4c6c5..08105701a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild @@ -23,6 +23,8 @@ 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/ram.o nvkm-y += nvkm/subdev/fb/ramnv04.o nvkm-y += nvkm/subdev/fb/ramnv10.o nvkm-y += nvkm/subdev/fb/ramnv1a.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 61fde43da..a719b9bec 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -22,144 +22,151 @@ * Authors: Ben Skeggs */ #include "priv.h" +#include "ram.h" #include <subdev/bios.h> #include <subdev/bios/M0203.h> +#include <engine/gr.h> +#include <engine/mpeg.h> + +bool +nvkm_fb_memtype_valid(struct nvkm_fb *fb, u32 memtype) +{ + return fb->func->memtype_valid(fb, memtype); +} + +void +nvkm_fb_tile_fini(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) +{ + fb->func->tile.fini(fb, region, tile); +} + +void +nvkm_fb_tile_init(struct nvkm_fb *fb, int region, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *tile) +{ + fb->func->tile.init(fb, region, addr, size, pitch, flags, tile); +} + +void +nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) +{ + struct nvkm_device *device = fb->subdev.device; + if (fb->func->tile.prog) { + fb->func->tile.prog(fb, region, tile); + if (device->gr) + nvkm_engine_tile(&device->gr->engine, region); + if (device->mpeg) + nvkm_engine_tile(device->mpeg, region); + } +} int nvkm_fb_bios_memtype(struct nvkm_bios *bios) { - const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2; + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; + const u8 ramcfg = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2; struct nvbios_M0203E M0203E; u8 ver, hdr; if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) { switch (M0203E.type) { - case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2; - case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3; - case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3; - case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5; + case M0203E_TYPE_DDR2 : return NVKM_RAM_TYPE_DDR2; + case M0203E_TYPE_DDR3 : return NVKM_RAM_TYPE_DDR3; + case M0203E_TYPE_GDDR3: return NVKM_RAM_TYPE_GDDR3; + case M0203E_TYPE_GDDR5: return NVKM_RAM_TYPE_GDDR5; default: - nv_warn(bios, "M0203E type %02x\n", M0203E.type); - return NV_MEM_TYPE_UNKNOWN; + nvkm_warn(subdev, "M0203E type %02x\n", M0203E.type); + return NVKM_RAM_TYPE_UNKNOWN; } } - nv_warn(bios, "M0203E not matched!\n"); - return NV_MEM_TYPE_UNKNOWN; + nvkm_warn(subdev, "M0203E not matched!\n"); + return NVKM_RAM_TYPE_UNKNOWN; } -int -_nvkm_fb_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_fb_intr(struct nvkm_subdev *subdev) { - struct nvkm_fb *pfb = (void *)object; - int ret; + struct nvkm_fb *fb = nvkm_fb(subdev); + if (fb->func->intr) + fb->func->intr(fb); +} - if (pfb->ram) { - ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend); - if (ret && suspend) +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) { + nvkm_error(subdev, "vram setup failed, %d\n", ret); return ret; + } } - - return nvkm_subdev_fini(&pfb->base, suspend); + return 0; } -int -_nvkm_fb_init(struct nvkm_object *object) +static int +nvkm_fb_init(struct nvkm_subdev *subdev) { - struct nvkm_fb *pfb = (void *)object; + struct nvkm_fb *fb = nvkm_fb(subdev); int ret, i; - ret = nvkm_subdev_init(&pfb->base); - if (ret) - return ret; - - if (pfb->ram) { - ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram)); + if (fb->ram) { + ret = nvkm_ram_init(fb->ram); if (ret) return ret; } - for (i = 0; i < pfb->tile.regions; i++) - pfb->tile.prog(pfb, i, &pfb->tile.region[i]); + for (i = 0; i < fb->tile.regions; i++) + fb->func->tile.prog(fb, i, &fb->tile.region[i]); + if (fb->func->init) + fb->func->init(fb); return 0; } -void -_nvkm_fb_dtor(struct nvkm_object *object) +static void * +nvkm_fb_dtor(struct nvkm_subdev *subdev) { - struct nvkm_fb *pfb = (void *)object; + struct nvkm_fb *fb = nvkm_fb(subdev); int i; - for (i = 0; i < pfb->tile.regions; i++) - pfb->tile.fini(pfb, i, &pfb->tile.region[i]); - nvkm_mm_fini(&pfb->tags); + for (i = 0; i < fb->tile.regions; i++) + fb->func->tile.fini(fb, i, &fb->tile.region[i]); - if (pfb->ram) { - nvkm_mm_fini(&pfb->vram); - nvkm_object_ref(NULL, (struct nvkm_object **)&pfb->ram); - } + nvkm_ram_del(&fb->ram); - nvkm_subdev_destroy(&pfb->base); + if (fb->func->dtor) + return fb->func->dtor(fb); + return fb; } -int -nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) -{ - struct nvkm_fb_impl *impl = (void *)oclass; - static const char *name[] = { - [NV_MEM_TYPE_UNKNOWN] = "unknown", - [NV_MEM_TYPE_STOLEN ] = "stolen system memory", - [NV_MEM_TYPE_SGRAM ] = "SGRAM", - [NV_MEM_TYPE_SDRAM ] = "SDRAM", - [NV_MEM_TYPE_DDR1 ] = "DDR1", - [NV_MEM_TYPE_DDR2 ] = "DDR2", - [NV_MEM_TYPE_DDR3 ] = "DDR3", - [NV_MEM_TYPE_GDDR2 ] = "GDDR2", - [NV_MEM_TYPE_GDDR3 ] = "GDDR3", - [NV_MEM_TYPE_GDDR4 ] = "GDDR4", - [NV_MEM_TYPE_GDDR5 ] = "GDDR5", - }; - struct nvkm_object *ram; - struct nvkm_fb *pfb; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PFB", "fb", - length, pobject); - pfb = *pobject; - if (ret) - return ret; - - pfb->memtype_valid = impl->memtype; - - if (!impl->ram) - return 0; - - ret = nvkm_object_ctor(nv_object(pfb), NULL, impl->ram, NULL, 0, &ram); - if (ret) { - nv_fatal(pfb, "error detecting memory configuration!!\n"); - return ret; - } - - pfb->ram = (void *)ram; +static const struct nvkm_subdev_func +nvkm_fb = { + .dtor = nvkm_fb_dtor, + .oneinit = nvkm_fb_oneinit, + .init = nvkm_fb_init, + .intr = nvkm_fb_intr, +}; - if (!nvkm_mm_initialised(&pfb->vram)) { - ret = nvkm_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1); - if (ret) - return ret; - } - - if (!nvkm_mm_initialised(&pfb->tags)) { - ret = nvkm_mm_init(&pfb->tags, 0, pfb->ram->tags ? - ++pfb->ram->tags : 0, 1); - if (ret) - return ret; - } +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); + fb->func = func; + fb->tile.regions = fb->func->tile.regions; +} - nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]); - nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20)); - nv_info(pfb, " ZCOMP: %d tags\n", pfb->ram->tags); +int +nvkm_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, + int index, struct nvkm_fb **pfb) +{ + if (!(*pfb = kzalloc(sizeof(**pfb), GFP_KERNEL))) + return -ENOMEM; + nvkm_fb_ctor(func, device, index, *pfb); return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c index 6c968d1e9..9c28392d0 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c @@ -22,17 +22,16 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" -struct nvkm_oclass * -g84_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x84), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram = &nv50_ram_oclass, +static const struct nv50_fb_func +g84_fb = { + .ram_new = nv50_ram_new, .trap = 0x001d07ff, -}.base.base; +}; + +int +g84_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&g84_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c index 15b462ae3..60ece0a8a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> * Roy Spliet <rspliet@eclipso.eu> */ -#include "priv.h" +#include "ram.h" struct ramxlat { int id; @@ -42,9 +42,9 @@ ramxlat(const struct ramxlat *xlat, int id) static const struct ramxlat ramgddr3_cl_lo[] = { - { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 }, + { 5, 5 }, { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 }, { 12, 8 }, /* the below are mentioned in some, but not all, gddr3 docs */ - { 12, 4 }, { 13, 5 }, { 14, 6 }, + { 13, 9 }, { 14, 6 }, /* XXX: Per Samsung docs, are these used? They overlap with Qimonda */ /* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 }, * { 15, 11 }, */ @@ -61,24 +61,25 @@ ramgddr3_cl_hi[] = { static const struct ramxlat ramgddr3_wr_lo[] = { { 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 }, - { 11, 0 }, + { 11, 0 }, { 13 , 1 }, /* the below are mentioned in some, but not all, gddr3 docs */ - { 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 }, + { 4, 0 }, { 6, 3 }, { 12, 1 }, { -1 } }; int nvkm_gddr3_calc(struct nvkm_ram *ram) { - int CL, WR, CWL, DLL = 0, ODT = 0, hi; + int CL, WR, CWL, DLL = 0, ODT = 0, RON, hi; switch (ram->next->bios.timing_ver) { case 0x10: CWL = ram->next->bios.timing_10_CWL; CL = ram->next->bios.timing_10_CL; WR = ram->next->bios.timing_10_WR; - DLL = !ram->next->bios.ramcfg_10_DLLoff; + DLL = !ram->next->bios.ramcfg_DLLoff; ODT = ram->next->bios.timing_10_ODT; + RON = ram->next->bios.ramcfg_RON; break; case 0x20: CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7; @@ -86,14 +87,17 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16; /* XXX: Get these values from the VBIOS instead */ DLL = !(ram->mr[1] & 0x1); - ODT = (ram->mr[1] & 0x004) >> 2 | - (ram->mr[1] & 0x040) >> 5 | - (ram->mr[1] & 0x200) >> 7; + RON = !(ram->mr[1] & 0x300) >> 8; break; default: return -ENOSYS; } + if (ram->next->bios.timing_ver == 0x20 || + ram->next->bios.ramcfg_timing == 0xff) { + ODT = (ram->mr[1] & 0xc) >> 2; + } + hi = ram->mr[2] & 0x1; CL = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL); WR = ramxlat(ramgddr3_wr_lo, WR); @@ -107,7 +111,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) ram->mr[1] &= ~0x3fc; ram->mr[1] |= (ODT & 0x03) << 2; - ram->mr[1] |= (ODT & 0x03) << 8; + ram->mr[1] |= (RON & 0x03) << 8; ram->mr[1] |= (WR & 0x03) << 4; ram->mr[1] |= (WR & 0x04) << 5; ram->mr[1] |= !DLL << 6; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c index f6f9eee1d..2cc074d39 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "priv.h" +#include "ram.h" /* binary driver only executes this path if the condition (a) is true * for any configuration (combination of rammap+ramcfg+timing) that @@ -38,11 +38,12 @@ nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts) int WL, CL, WR, at[2], dt, ds; int rq = ram->freq < 1000000; /* XXX */ + xd = !ram->next->bios.ramcfg_DLLoff; + switch (ram->next->bios.ramcfg_ver) { case 0x11: pd = ram->next->bios.ramcfg_11_01_80; lf = ram->next->bios.ramcfg_11_01_40; - xd = !ram->next->bios.ramcfg_11_01_20; vh = ram->next->bios.ramcfg_11_02_10; vr = ram->next->bios.ramcfg_11_02_04; vo = ram->next->bios.ramcfg_11_06; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index d51aa0237..008bb9849 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -22,101 +22,90 @@ * Authors: Ben Skeggs */ #include "gf100.h" - -#include <core/device.h> +#include "ram.h" extern const u8 gf100_pte_storage_type_map[256]; bool -gf100_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags) +gf100_fb_memtype_valid(struct nvkm_fb *fb, u32 tile_flags) { u8 memtype = (tile_flags & 0x0000ff00) >> 8; return likely((gf100_pte_storage_type_map[memtype] != 0xff)); } -static void -gf100_fb_intr(struct nvkm_subdev *subdev) +void +gf100_fb_intr(struct nvkm_fb *base) { - struct gf100_fb_priv *priv = (void *)subdev; - u32 intr = nv_rd32(priv, 0x000100); - if (intr & 0x08000000) { - nv_debug(priv, "PFFB intr\n"); - intr &= ~0x08000000; - } - if (intr & 0x00002000) { - nv_debug(priv, "PBFB intr\n"); - intr &= ~0x00002000; - } + struct gf100_fb *fb = gf100_fb(base); + struct nvkm_subdev *subdev = &fb->base.subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x000100); + if (intr & 0x08000000) + nvkm_debug(subdev, "PFFB intr\n"); + if (intr & 0x00002000) + nvkm_debug(subdev, "PBFB intr\n"); } -int -gf100_fb_init(struct nvkm_object *object) +void +gf100_fb_init(struct nvkm_fb *base) { - struct gf100_fb_priv *priv = (void *)object; - int ret; + struct gf100_fb *fb = gf100_fb(base); + struct nvkm_device *device = fb->base.subdev.device; - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; + if (fb->r100c10_page) + nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); - if (priv->r100c10_page) - nv_wr32(priv, 0x100c10, priv->r100c10 >> 8); - - nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ - return 0; + nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ } -void -gf100_fb_dtor(struct nvkm_object *object) +void * +gf100_fb_dtor(struct nvkm_fb *base) { - struct nvkm_device *device = nv_device(object); - struct gf100_fb_priv *priv = (void *)object; + struct gf100_fb *fb = gf100_fb(base); + struct nvkm_device *device = fb->base.subdev.device; - if (priv->r100c10_page) { - dma_unmap_page(nv_device_base(device), priv->r100c10, PAGE_SIZE, + if (fb->r100c10_page) { + dma_unmap_page(device->dev, fb->r100c10, PAGE_SIZE, DMA_BIDIRECTIONAL); - __free_page(priv->r100c10_page); + __free_page(fb->r100c10_page); } - nvkm_fb_destroy(&priv->base); + return fb; } int -gf100_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, + int index, struct nvkm_fb **pfb) { - struct nvkm_device *device = nv_device(parent); - struct gf100_fb_priv *priv; - int ret; - - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (priv->r100c10_page) { - priv->r100c10 = dma_map_page(nv_device_base(device), - priv->r100c10_page, 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(nv_device_base(device), priv->r100c10)) + struct gf100_fb *fb; + + if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL))) + return -ENOMEM; + nvkm_fb_ctor(func, device, index, &fb->base); + *pfb = &fb->base; + + fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (fb->r100c10_page) { + fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0, + PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(device->dev, fb->r100c10)) return -EFAULT; } - nv_subdev(priv)->intr = gf100_fb_intr; return 0; } -struct nvkm_oclass * -gf100_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fb_ctor, - .dtor = gf100_fb_dtor, - .init = gf100_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, - .ram = &gf100_ram_oclass, -}.base; +static const struct nvkm_fb_func +gf100_fb = { + .dtor = gf100_fb_dtor, + .init = gf100_fb_init, + .intr = gf100_fb_intr, + .ram_new = gf100_ram_new, + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gf100_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gf100_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h index 0af4da259..2160e5a39 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h @@ -1,28 +1,17 @@ #ifndef __NVKM_RAM_NVC0_H__ #define __NVKM_RAM_NVC0_H__ +#define gf100_fb(p) container_of((p), struct gf100_fb, base) #include "priv.h" -#include "nv50.h" -struct gf100_fb_priv { +struct gf100_fb { struct nvkm_fb base; struct page *r100c10_page; dma_addr_t r100c10; }; -int gf100_fb_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_fb_dtor(struct nvkm_object *); -int gf100_fb_init(struct nvkm_object *); -bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); - -#define gf100_ram_create(p,e,o,m,d) \ - gf100_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d) -int gf100_ram_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32, int, void **); -int gf100_ram_get(struct nvkm_fb *, u64, u32, u32, u32, - struct nvkm_mem **); -void gf100_ram_put(struct nvkm_fb *, struct nvkm_mem **); - -int gk104_ram_init(struct nvkm_object*); +int gf100_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, + int index, struct nvkm_fb **); +void *gf100_fb_dtor(struct nvkm_fb *); +void gf100_fb_init(struct nvkm_fb *); +void gf100_fb_intr(struct nvkm_fb *); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c index 1c0831766..0edb3c316 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c @@ -22,16 +22,19 @@ * Authors: Ben Skeggs */ #include "gf100.h" +#include "ram.h" -struct nvkm_oclass * -gk104_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fb_ctor, - .dtor = gf100_fb_dtor, - .init = gf100_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, - .ram = &gk104_ram_oclass, -}.base; +static const struct nvkm_fb_func +gk104_fb = { + .dtor = gf100_fb_dtor, + .init = gf100_fb_init, + .intr = gf100_fb_intr, + .ram_new = gk104_ram_new, + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gk104_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gk104_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index a5d7857d3..81447eb4c 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -19,50 +19,23 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "gf100.h" +#include "priv.h" -struct gk20a_fb_priv { - struct nvkm_fb base; -}; - -static int -gk20a_fb_init(struct nvkm_object *object) +static void +gk20a_fb_init(struct nvkm_fb *fb) { - struct gk20a_fb_priv *priv = (void *)object; - int ret; - - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; - - nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ - return 0; + struct nvkm_device *device = fb->subdev.device; + nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ } -static int -gk20a_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk20a_fb_priv *priv; - int ret; - - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_fb_func +gk20a_fb = { + .init = gk20a_fb_init, + .memtype_valid = gf100_fb_memtype_valid, +}; - return 0; +int +gk20a_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&gk20a_fb, device, index, pfb); } - -struct nvkm_oclass * -gk20a_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = gk20a_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c index 843f9356b..2a91df865 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c @@ -22,16 +22,19 @@ * Authors: Ben Skeggs */ #include "gf100.h" +#include "ram.h" -struct nvkm_oclass * -gm107_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fb_ctor, - .dtor = gf100_fb_dtor, - .init = gf100_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, - .ram = &gm107_ram_oclass, -}.base; +static const struct nvkm_fb_func +gm107_fb = { + .dtor = gf100_fb_dtor, + .init = gf100_fb_init, + .intr = gf100_fb_intr, + .ram_new = gm107_ram_new, + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gm107_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gm107_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c index dd9b8a0a3..ebb30608d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c @@ -22,17 +22,16 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" -struct nvkm_oclass * -gt215_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0xa3), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram = >215_ram_oclass, +static const struct nv50_fb_func +gt215_fb = { + .ram_new = gt215_ram_new, .trap = 0x000d0fff, -}.base.base; +}; + +int +gt215_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(>215_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c index 7be4a47ef..73b3b86a2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c @@ -22,17 +22,16 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" -struct nvkm_oclass * -mcp77_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0xaa), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram = &mcp77_ram_oclass, +static const struct nv50_fb_func +mcp77_fb = { + .ram_new = mcp77_ram_new, .trap = 0x001d07ff, -}.base.base; +}; + +int +mcp77_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&mcp77_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c index 2d00656fa..6d11e32ec 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c @@ -22,17 +22,16 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" -struct nvkm_oclass * -mcp89_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0xaf), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram = &mcp77_ram_oclass, +static const struct nv50_fb_func +mcp89_fb = { + .ram_new = mcp77_ram_new, .trap = 0x089d1fff, -}.base.base; +}; + +int +mcp89_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&mcp89_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c index c063dec7d..8ff2e5db4 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c @@ -21,67 +21,39 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" #include "regsnv04.h" bool -nv04_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags) +nv04_fb_memtype_valid(struct nvkm_fb *fb, u32 tile_flags) { if (!(tile_flags & 0xff00)) return true; - return false; } -static int -nv04_fb_init(struct nvkm_object *object) +static void +nv04_fb_init(struct nvkm_fb *fb) { - struct nv04_fb_priv *priv = (void *)object; - int ret; - - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; + struct nvkm_device *device = fb->subdev.device; /* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows * nvidia reading PFB_CFG_0, then writing back its original value. * (which was 0x701114 in this case) */ - nv_wr32(priv, NV04_PFB_CFG0, 0x1114); - return 0; + nvkm_wr32(device, NV04_PFB_CFG0, 0x1114); } +static const struct nvkm_fb_func +nv04_fb = { + .init = nv04_fb_init, + .ram_new = nv04_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + int -nv04_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) { - struct nv04_fb_impl *impl = (void *)oclass; - struct nv04_fb_priv *priv; - int ret; - - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.tile.regions = impl->tile.regions; - priv->base.tile.init = impl->tile.init; - priv->base.tile.comp = impl->tile.comp; - priv->base.tile.fini = impl->tile.fini; - priv->base.tile.prog = impl->tile.prog; - return 0; + return nvkm_fb_new_(&nv04_fb, device, index, pfb); } - -struct nvkm_oclass * -nv04_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x04), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv04_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv04_ram_oclass, -}.base.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h deleted file mode 100644 index caa0d03aa..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __NVKM_FB_NV04_H__ -#define __NVKM_FB_NV04_H__ -#include "priv.h" - -struct nv04_fb_priv { - struct nvkm_fb base; -}; - -int nv04_fb_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -struct nv04_fb_impl { - struct nvkm_fb_impl base; - struct { - int regions; - void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); - void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags, - struct nvkm_fb_tile *); - void (*fini)(struct nvkm_fb *, int i, - struct nvkm_fb_tile *); - void (*prog)(struct nvkm_fb *, int i, - struct nvkm_fb_tile *); - } tile; -}; - -void nv10_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); -void nv10_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); -void nv10_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); - -void nv20_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); -void nv20_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); -void nv20_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); - -int nv30_fb_init(struct nvkm_object *); -void nv30_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); - -void nv40_fb_tile_comp(struct nvkm_fb *, int i, u32 size, u32 flags, - struct nvkm_fb_tile *); - -int nv41_fb_init(struct nvkm_object *); -void nv41_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); - -int nv44_fb_init(struct nvkm_object *); -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 *); -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c index f3530e4a6..e8c44f5a3 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c @@ -23,10 +23,11 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" void -nv10_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv10_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { tile->addr = 0x80000000 | addr; @@ -35,7 +36,7 @@ nv10_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, } void -nv10_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv10_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { tile->addr = 0; tile->limit = 0; @@ -44,27 +45,27 @@ nv10_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) } void -nv10_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv10_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100240 + (i * 0x10)); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100244 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100248 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100240 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100240 + (i * 0x10)); } -struct nvkm_oclass * -nv10_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x10), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv10_ram_oclass, +static const struct nvkm_fb_func +nv10_fb = { .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, .tile.prog = nv10_fb_tile_prog, -}.base.base; + .ram_new = nv10_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv10_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv10_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c index 83bcb73ca..2ae0beb87 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c @@ -23,21 +23,21 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" -struct nvkm_oclass * -nv1a_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x1a), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv1a_ram_oclass, +static const struct nvkm_fb_func +nv1a_fb = { .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, .tile.prog = nv10_fb_tile_prog, -}.base.base; + .ram_new = nv1a_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv1a_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv1a_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c index e37084b8d..126865dfe 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c @@ -23,28 +23,29 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" void -nv20_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv20_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { tile->addr = 0x00000001 | addr; tile->limit = max(1u, addr + size) - 1; tile->pitch = pitch; if (flags & 4) { - pfb->tile.comp(pfb, i, size, flags, tile); + fb->func->tile.comp(fb, i, size, flags, tile); tile->addr |= 2; } } static void -nv20_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv20_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */ else tile->zcomp = 0x04000000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; @@ -56,39 +57,39 @@ nv20_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } void -nv20_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv20_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { tile->addr = 0; tile->limit = 0; tile->pitch = 0; tile->zcomp = 0; - nvkm_mm_free(&pfb->tags, &tile->tag); + nvkm_mm_free(&fb->ram->tags, &tile->tag); } void -nv20_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv20_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100240 + (i * 0x10)); - nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100244 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100248 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100240 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100240 + (i * 0x10)); + nvkm_wr32(device, 0x100300 + (i * 0x04), tile->zcomp); } -struct nvkm_oclass * -nv20_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x20), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, +static const struct nvkm_fb_func +nv20_fb = { .tile.regions = 8, .tile.init = nv20_fb_tile_init, .tile.comp = nv20_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv20_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv20_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c index bc9f54f38..c56746d2a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c @@ -23,15 +23,16 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" static void -nv25_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv25_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */ else tile->zcomp = 0x00200000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; @@ -41,20 +42,19 @@ nv25_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } } -struct nvkm_oclass * -nv25_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x25), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, +static const struct nvkm_fb_func +nv25_fb = { .tile.regions = 8, .tile.init = nv20_fb_tile_init, .tile.comp = nv25_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv25_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv25_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c index 09ebb9477..2a7c4831b 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c @@ -23,20 +23,19 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" - -#include <core/device.h> +#include "priv.h" +#include "ram.h" void -nv30_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv30_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { /* for performance, select alternate bank offset for zeta */ if (!(flags & 4)) { tile->addr = (0 << 4); } else { - if (pfb->tile.comp) /* z compression */ - pfb->tile.comp(pfb, i, size, flags, tile); + if (fb->func->tile.comp) /* z compression */ + fb->func->tile.comp(fb, i, size, flags, tile); tile->addr = (1 << 4); } @@ -47,12 +46,12 @@ nv30_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, } static void -nv30_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv30_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */ else tile->zcomp |= 0x02000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); @@ -64,23 +63,24 @@ nv30_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } static int -calc_bias(struct nv04_fb_priv *priv, int k, int i, int j) +calc_bias(struct nvkm_fb *fb, int k, int i, int j) { - struct nvkm_device *device = nv_device(priv); + struct nvkm_device *device = fb->subdev.device; int b = (device->chipset > 0x30 ? - nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : + nvkm_rd32(device, 0x122c + 0x10 * k + 0x4 * j) >> + (4 * (i ^ 1)) : 0) & 0xf; return 2 * (b & 0x8 ? b - 0x10 : b); } static int -calc_ref(struct nv04_fb_priv *priv, int l, int k, int i) +calc_ref(struct nvkm_fb *fb, int l, int k, int i) { int j, x = 0; for (j = 0; j < 4; j++) { - int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j); + int m = (l >> (8 * i) & 0xff) + calc_bias(fb, k, i, j); x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j); } @@ -88,16 +88,11 @@ calc_ref(struct nv04_fb_priv *priv, int l, int k, int i) return x; } -int -nv30_fb_init(struct nvkm_object *object) +void +nv30_fb_init(struct nvkm_fb *fb) { - struct nvkm_device *device = nv_device(object); - struct nv04_fb_priv *priv = (void *)object; - int ret, i, j; - - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; + struct nvkm_device *device = fb->subdev.device; + int i, j; /* Init the memory timing regs at 0x10037c/0x1003ac */ if (device->chipset == 0x30 || @@ -105,36 +100,34 @@ nv30_fb_init(struct nvkm_object *object) device->chipset == 0x35) { /* Related to ROP count */ int n = (device->chipset == 0x31 ? 2 : 4); - int l = nv_rd32(priv, 0x1003d0); + int l = nvkm_rd32(device, 0x1003d0); for (i = 0; i < n; i++) { for (j = 0; j < 3; j++) - nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j, - calc_ref(priv, l, 0, j)); + nvkm_wr32(device, 0x10037c + 0xc * i + 0x4 * j, + calc_ref(fb, l, 0, j)); for (j = 0; j < 2; j++) - nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j, - calc_ref(priv, l, 1, j)); + nvkm_wr32(device, 0x1003ac + 0x8 * i + 0x4 * j, + calc_ref(fb, l, 1, j)); } } - - return 0; } -struct nvkm_oclass * -nv30_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x30), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv30_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, +static const struct nvkm_fb_func +nv30_fb = { + .init = nv30_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv30_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv30_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv30_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c index c01dc1839..1604b3789 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c @@ -23,15 +23,16 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" static void -nv35_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv35_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */ else tile->zcomp |= 0x08000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); @@ -42,20 +43,20 @@ nv35_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } } -struct nvkm_oclass * -nv35_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x35), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv30_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, +static const struct nvkm_fb_func +nv35_fb = { + .init = nv30_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv35_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv35_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv35_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c index cad75a1ce..80cc0a6e3 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c @@ -23,15 +23,16 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" static void -nv36_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv36_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */ else tile->zcomp |= 0x20000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); @@ -42,20 +43,20 @@ nv36_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } } -struct nvkm_oclass * -nv36_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x36), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv30_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, +static const struct nvkm_fb_func +nv36_fb = { + .init = nv30_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv36_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv36_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv36_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c index dbe5c1910..deec46a31 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c @@ -23,16 +23,17 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" void -nv40_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv40_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x80); - u32 tags = round_up(tiles / pfb->ram->parts, 0x100); + u32 tags = round_up(tiles / fb->ram->parts, 0x100); if ( (flags & 2) && - !nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + !nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */ tile->zcomp |= ((tile->tag->offset ) >> 8); tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13; @@ -42,34 +43,26 @@ nv40_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } } -static int -nv40_fb_init(struct nvkm_object *object) +static void +nv40_fb_init(struct nvkm_fb *fb) { - struct nv04_fb_priv *priv = (void *)object; - int ret; - - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; - - nv_mask(priv, 0x10033c, 0x00008000, 0x00000000); - return 0; + nvkm_mask(fb->subdev.device, 0x10033c, 0x00008000, 0x00000000); } -struct nvkm_oclass * -nv40_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x40), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv40_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv40_ram_oclass, +static const struct nvkm_fb_func +nv40_fb = { + .init = nv40_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv40_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv40_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv40_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h deleted file mode 100644 index 602182661..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __NVKM_FB_NV40_H__ -#define __NVKM_FB_NV40_H__ -#include "priv.h" - -struct nv40_ram { - struct nvkm_ram base; - u32 ctrl; - u32 coef; -}; - -int nv40_ram_calc(struct nvkm_fb *, u32); -int nv40_ram_prog(struct nvkm_fb *); -void nv40_ram_tidy(struct nvkm_fb *); -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c index d9e1a40a2..79e57dd5a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c @@ -23,46 +23,40 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" void -nv41_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv41_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100600 + (i * 0x10)); - nv_wr32(pfb, 0x100700 + (i * 0x04), tile->zcomp); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100604 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100608 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100600 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100600 + (i * 0x10)); + nvkm_wr32(device, 0x100700 + (i * 0x04), tile->zcomp); } -int -nv41_fb_init(struct nvkm_object *object) +void +nv41_fb_init(struct nvkm_fb *fb) { - struct nv04_fb_priv *priv = (void *)object; - int ret; - - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x100800, 0x00000001); - return 0; + nvkm_wr32(fb->subdev.device, 0x100800, 0x00000001); } -struct nvkm_oclass * -nv41_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x41), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv41_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv41_ram_oclass, +static const struct nvkm_fb_func +nv41_fb = { + .init = nv41_fb_init, .tile.regions = 12, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv41_fb_tile_prog, -}.base.base; + .ram_new = nv41_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv41_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv41_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c index 20b97c83c..06246cce5 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c @@ -23,10 +23,11 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" static void -nv44_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv44_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { tile->addr = 0x00000001; /* mode = vram */ @@ -36,42 +37,36 @@ nv44_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, } void -nv44_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv44_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100600 + (i * 0x10)); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100604 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100608 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100600 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100600 + (i * 0x10)); } -int -nv44_fb_init(struct nvkm_object *object) +void +nv44_fb_init(struct nvkm_fb *fb) { - struct nv04_fb_priv *priv = (void *)object; - int ret; - - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x100850, 0x80000000); - nv_wr32(priv, 0x100800, 0x00000001); - return 0; + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100850, 0x80000000); + nvkm_wr32(device, 0x100800, 0x00000001); } -struct nvkm_oclass * -nv44_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x44), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv44_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv44_ram_oclass, +static const struct nvkm_fb_func +nv44_fb = { + .init = nv44_fb_init, .tile.regions = 12, .tile.init = nv44_fb_tile_init, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv44_fb_tile_prog, -}.base.base; + .ram_new = nv44_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv44_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv44_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c index 5bfac38cd..3598a1aa6 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c @@ -23,10 +23,11 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" void -nv46_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv46_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { /* for performance, select alternate bank offset for zeta */ @@ -39,19 +40,19 @@ nv46_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, tile->pitch = pitch; } -struct nvkm_oclass * -nv46_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x46), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv44_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv44_ram_oclass, +static const struct nvkm_fb_func +nv46_fb = { + .init = nv44_fb_init, .tile.regions = 15, .tile.init = nv46_fb_tile_init, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv44_fb_tile_prog, -}.base.base; + .ram_new = nv44_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv46_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv46_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c index d3b3988d1..c505e4429 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c @@ -23,22 +23,23 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" -struct nvkm_oclass * -nv47_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x47), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv41_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv41_ram_oclass, +static const struct nvkm_fb_func +nv47_fb = { + .init = nv41_fb_init, .tile.regions = 15, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv41_fb_tile_prog, -}.base.base; + .ram_new = nv41_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv47_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv47_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c index 236e36c50..7b91b9f17 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c @@ -23,22 +23,23 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" -struct nvkm_oclass * -nv49_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x49), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv41_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv49_ram_oclass, +static const struct nvkm_fb_func +nv49_fb = { + .init = nv41_fb_init, .tile.regions = 15, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv41_fb_tile_prog, -}.base.base; + .ram_new = nv49_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv49_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv49_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c index 1352b6a73..4e98210c1 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c @@ -23,21 +23,22 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" +#include "ram.h" -struct nvkm_oclass * -nv4e_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x4e), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv44_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv4e_ram_oclass, +static const struct nvkm_fb_func +nv4e_fb = { + .init = nv44_fb_init, .tile.regions = 12, .tile.init = nv46_fb_tile_init, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv44_fb_tile_prog, -}.base.base; + .ram_new = nv44_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv4e_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv4e_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 0480ce52a..f5edfadb5 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -22,11 +22,11 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" #include <core/client.h> -#include <core/device.h> -#include <core/engctx.h> #include <core/enum.h> +#include <engine/fifo.h> int nv50_fb_memtype[0x80] = { @@ -40,130 +40,139 @@ nv50_fb_memtype[0x80] = { 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 }; -bool -nv50_fb_memtype_valid(struct nvkm_fb *pfb, u32 memtype) +static int +nv50_fb_ram_new(struct nvkm_fb *base, struct nvkm_ram **pram) +{ + struct nv50_fb *fb = nv50_fb(base); + return fb->func->ram_new(&fb->base, pram); +} + +static bool +nv50_fb_memtype_valid(struct nvkm_fb *fb, u32 memtype) { return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0; } static const struct nvkm_enum vm_dispatch_subclients[] = { - { 0x00000000, "GRCTX", NULL }, - { 0x00000001, "NOTIFY", NULL }, - { 0x00000002, "QUERY", NULL }, - { 0x00000003, "COND", NULL }, - { 0x00000004, "M2M_IN", NULL }, - { 0x00000005, "M2M_OUT", NULL }, - { 0x00000006, "M2M_NOTIFY", NULL }, + { 0x00000000, "GRCTX" }, + { 0x00000001, "NOTIFY" }, + { 0x00000002, "QUERY" }, + { 0x00000003, "COND" }, + { 0x00000004, "M2M_IN" }, + { 0x00000005, "M2M_OUT" }, + { 0x00000006, "M2M_NOTIFY" }, {} }; static const struct nvkm_enum vm_ccache_subclients[] = { - { 0x00000000, "CB", NULL }, - { 0x00000001, "TIC", NULL }, - { 0x00000002, "TSC", NULL }, + { 0x00000000, "CB" }, + { 0x00000001, "TIC" }, + { 0x00000002, "TSC" }, {} }; static const struct nvkm_enum vm_prop_subclients[] = { - { 0x00000000, "RT0", NULL }, - { 0x00000001, "RT1", NULL }, - { 0x00000002, "RT2", NULL }, - { 0x00000003, "RT3", NULL }, - { 0x00000004, "RT4", NULL }, - { 0x00000005, "RT5", NULL }, - { 0x00000006, "RT6", NULL }, - { 0x00000007, "RT7", NULL }, - { 0x00000008, "ZETA", NULL }, - { 0x00000009, "LOCAL", NULL }, - { 0x0000000a, "GLOBAL", NULL }, - { 0x0000000b, "STACK", NULL }, - { 0x0000000c, "DST2D", NULL }, + { 0x00000000, "RT0" }, + { 0x00000001, "RT1" }, + { 0x00000002, "RT2" }, + { 0x00000003, "RT3" }, + { 0x00000004, "RT4" }, + { 0x00000005, "RT5" }, + { 0x00000006, "RT6" }, + { 0x00000007, "RT7" }, + { 0x00000008, "ZETA" }, + { 0x00000009, "LOCAL" }, + { 0x0000000a, "GLOBAL" }, + { 0x0000000b, "STACK" }, + { 0x0000000c, "DST2D" }, {} }; static const struct nvkm_enum vm_pfifo_subclients[] = { - { 0x00000000, "PUSHBUF", NULL }, - { 0x00000001, "SEMAPHORE", NULL }, + { 0x00000000, "PUSHBUF" }, + { 0x00000001, "SEMAPHORE" }, {} }; static const struct nvkm_enum vm_bar_subclients[] = { - { 0x00000000, "FB", NULL }, - { 0x00000001, "IN", NULL }, + { 0x00000000, "FB" }, + { 0x00000001, "IN" }, {} }; static const struct nvkm_enum vm_client[] = { - { 0x00000000, "STRMOUT", NULL }, + { 0x00000000, "STRMOUT" }, { 0x00000003, "DISPATCH", vm_dispatch_subclients }, - { 0x00000004, "PFIFO_WRITE", NULL }, + { 0x00000004, "PFIFO_WRITE" }, { 0x00000005, "CCACHE", vm_ccache_subclients }, - { 0x00000006, "PMSPPP", NULL }, - { 0x00000007, "CLIPID", NULL }, - { 0x00000008, "PFIFO_READ", NULL }, - { 0x00000009, "VFETCH", NULL }, - { 0x0000000a, "TEXTURE", NULL }, + { 0x00000006, "PMSPPP" }, + { 0x00000007, "CLIPID" }, + { 0x00000008, "PFIFO_READ" }, + { 0x00000009, "VFETCH" }, + { 0x0000000a, "TEXTURE" }, { 0x0000000b, "PROP", vm_prop_subclients }, - { 0x0000000c, "PVP", NULL }, - { 0x0000000d, "PBSP", NULL }, - { 0x0000000e, "PCRYPT", NULL }, - { 0x0000000f, "PCOUNTER", NULL }, - { 0x00000011, "PDAEMON", NULL }, + { 0x0000000c, "PVP" }, + { 0x0000000d, "PBSP" }, + { 0x0000000e, "PCRYPT" }, + { 0x0000000f, "PCOUNTER" }, + { 0x00000011, "PDAEMON" }, {} }; static const struct nvkm_enum vm_engine[] = { - { 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR }, - { 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP }, - { 0x00000004, "PEEPHOLE", NULL }, - { 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO }, + { 0x00000000, "PGRAPH" }, + { 0x00000001, "PVP" }, + { 0x00000004, "PEEPHOLE" }, + { 0x00000005, "PFIFO", vm_pfifo_subclients }, { 0x00000006, "BAR", vm_bar_subclients }, - { 0x00000008, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP }, - { 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG }, - { 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP }, - { 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CIPHER }, - { 0x0000000b, "PCOUNTER", NULL }, - { 0x0000000c, "SEMAPHORE_BG", NULL }, - { 0x0000000d, "PCE0", NULL, NVDEV_ENGINE_CE0 }, - { 0x0000000e, "PDAEMON", NULL }, + { 0x00000008, "PMSPPP" }, + { 0x00000008, "PMPEG" }, + { 0x00000009, "PBSP" }, + { 0x0000000a, "PCRYPT" }, + { 0x0000000b, "PCOUNTER" }, + { 0x0000000c, "SEMAPHORE_BG" }, + { 0x0000000d, "PCE0" }, + { 0x0000000e, "PDAEMON" }, {} }; static const struct nvkm_enum vm_fault[] = { - { 0x00000000, "PT_NOT_PRESENT", NULL }, - { 0x00000001, "PT_TOO_SHORT", NULL }, - { 0x00000002, "PAGE_NOT_PRESENT", NULL }, - { 0x00000003, "PAGE_SYSTEM_ONLY", NULL }, - { 0x00000004, "PAGE_READ_ONLY", NULL }, - { 0x00000006, "NULL_DMAOBJ", NULL }, - { 0x00000007, "WRONG_MEMTYPE", NULL }, - { 0x0000000b, "VRAM_LIMIT", NULL }, - { 0x0000000f, "DMAOBJ_LIMIT", NULL }, + { 0x00000000, "PT_NOT_PRESENT" }, + { 0x00000001, "PT_TOO_SHORT" }, + { 0x00000002, "PAGE_NOT_PRESENT" }, + { 0x00000003, "PAGE_SYSTEM_ONLY" }, + { 0x00000004, "PAGE_READ_ONLY" }, + { 0x00000006, "NULL_DMAOBJ" }, + { 0x00000007, "WRONG_MEMTYPE" }, + { 0x0000000b, "VRAM_LIMIT" }, + { 0x0000000f, "DMAOBJ_LIMIT" }, {} }; static void -nv50_fb_intr(struct nvkm_subdev *subdev) +nv50_fb_intr(struct nvkm_fb *base) { - struct nvkm_device *device = nv_device(subdev); - struct nvkm_engine *engine; - struct nv50_fb_priv *priv = (void *)subdev; - const struct nvkm_enum *en, *cl; - struct nvkm_object *engctx = NULL; - u32 trap[6], idx, chan; + struct nv50_fb *fb = nv50_fb(base); + struct nvkm_subdev *subdev = &fb->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_fifo *fifo = device->fifo; + struct nvkm_fifo_chan *chan; + const struct nvkm_enum *en, *re, *cl, *sc; + u32 trap[6], idx, inst; u8 st0, st1, st2, st3; + unsigned long flags; int i; - idx = nv_rd32(priv, 0x100c90); + idx = nvkm_rd32(device, 0x100c90); if (!(idx & 0x80000000)) return; idx &= 0x00ffffff; for (i = 0; i < 6; i++) { - nv_wr32(priv, 0x100c90, idx | i << 24); - trap[i] = nv_rd32(priv, 0x100c94); + nvkm_wr32(device, 0x100c90, idx | i << 24); + trap[i] = nvkm_rd32(device, 0x100c94); } - nv_wr32(priv, 0x100c90, idx | 0x80000000); + nvkm_wr32(device, 0x100c90, idx | 0x80000000); /* decode status bits into something more useful */ if (device->chipset < 0xa3 || @@ -178,143 +187,103 @@ nv50_fb_intr(struct nvkm_subdev *subdev) st2 = (trap[0] & 0x00ff0000) >> 16; st3 = (trap[0] & 0xff000000) >> 24; } - chan = (trap[2] << 16) | trap[1]; + inst = ((trap[2] << 16) | trap[1]) << 12; en = nvkm_enum_find(vm_engine, st0); - - if (en && en->data2) { - const struct nvkm_enum *orig_en = en; - while (en->name && en->value == st0 && en->data2) { - engine = nvkm_engine(subdev, en->data2); - /*XXX: clean this up */ - if (!engine && en->data2 == NVDEV_ENGINE_BSP) - engine = nvkm_engine(subdev, NVDEV_ENGINE_MSVLD); - if (!engine && en->data2 == NVDEV_ENGINE_CIPHER) - engine = nvkm_engine(subdev, NVDEV_ENGINE_SEC); - if (!engine && en->data2 == NVDEV_ENGINE_VP) - engine = nvkm_engine(subdev, NVDEV_ENGINE_MSPDEC); - if (engine) { - engctx = nvkm_engctx_get(engine, chan); - if (engctx) - break; - } - en++; - } - if (!engctx) - en = orig_en; - } - - nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ", - (trap[5] & 0x00000100) ? "read" : "write", - trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan, - nvkm_client_name(engctx)); - - nvkm_engctx_put(engctx); - - if (en) - pr_cont("%s/", en->name); - else - pr_cont("%02x/", st0); - + re = nvkm_enum_find(vm_fault , st1); cl = nvkm_enum_find(vm_client, st2); - if (cl) - pr_cont("%s/", cl->name); - else - pr_cont("%02x/", st2); - - if (cl && cl->data) cl = nvkm_enum_find(cl->data, st3); - else if (en && en->data) cl = nvkm_enum_find(en->data, st3); - else cl = NULL; - if (cl) - pr_cont("%s", cl->name); - else - pr_cont("%02x", st3); - - pr_cont(" reason: "); - en = nvkm_enum_find(vm_fault, st1); - if (en) - pr_cont("%s\n", en->name); - else - pr_cont("0x%08x\n", st1); + if (cl && cl->data) sc = nvkm_enum_find(cl->data, st3); + else if (en && en->data) sc = nvkm_enum_find(en->data, st3); + else sc = NULL; + + chan = nvkm_fifo_chan_inst(fifo, inst, &flags); + nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] " + "engine %02x [%s] client %02x [%s] " + "subclient %02x [%s] reason %08x [%s]\n", + (trap[5] & 0x00000100) ? "read" : "write", + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, + chan ? chan->chid : -1, inst, + chan ? chan->object.client->name : "unknown", + st0, en ? en->name : "", + st2, cl ? cl->name : "", st3, sc ? sc->name : "", + st1, re ? re->name : ""); + nvkm_fifo_chan_put(fifo, flags, &chan); } -int -nv50_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void +nv50_fb_init(struct nvkm_fb *base) { - struct nvkm_device *device = nv_device(parent); - struct nv50_fb_priv *priv; - int ret; - - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + struct nv50_fb *fb = nv50_fb(base); + struct nvkm_device *device = fb->base.subdev.device; - priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (priv->r100c08_page) { - priv->r100c08 = dma_map_page(nv_device_base(device), - priv->r100c08_page, 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(nv_device_base(device), priv->r100c08)) - return -EFAULT; - } else { - nv_warn(priv, "failed 0x100c08 page alloc\n"); - } + /* Not a clue what this is exactly. Without pointing it at a + * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) + * cause IOMMU "read from address 0" errors (rh#561267) + */ + nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8); - nv_subdev(priv)->intr = nv50_fb_intr; - return 0; + /* This is needed to get meaningful information from 100c90 + * on traps. No idea what these values mean exactly. */ + nvkm_wr32(device, 0x100c90, fb->func->trap); } -void -nv50_fb_dtor(struct nvkm_object *object) +static void * +nv50_fb_dtor(struct nvkm_fb *base) { - struct nvkm_device *device = nv_device(object); - struct nv50_fb_priv *priv = (void *)object; + struct nv50_fb *fb = nv50_fb(base); + struct nvkm_device *device = fb->base.subdev.device; - if (priv->r100c08_page) { - dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE, + if (fb->r100c08_page) { + dma_unmap_page(device->dev, fb->r100c08, PAGE_SIZE, DMA_BIDIRECTIONAL); - __free_page(priv->r100c08_page); + __free_page(fb->r100c08_page); } - nvkm_fb_destroy(&priv->base); + return fb; } +static const struct nvkm_fb_func +nv50_fb_ = { + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .intr = nv50_fb_intr, + .ram_new = nv50_fb_ram_new, + .memtype_valid = nv50_fb_memtype_valid, +}; + int -nv50_fb_init(struct nvkm_object *object) +nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device, + int index, struct nvkm_fb **pfb) { - struct nv50_fb_impl *impl = (void *)object->oclass; - struct nv50_fb_priv *priv = (void *)object; - int ret; - - ret = nvkm_fb_init(&priv->base); - if (ret) - return ret; - - /* Not a clue what this is exactly. Without pointing it at a - * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) - * cause IOMMU "read from address 0" errors (rh#561267) - */ - nv_wr32(priv, 0x100c08, priv->r100c08 >> 8); + struct nv50_fb *fb; + + if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL))) + return -ENOMEM; + nvkm_fb_ctor(&nv50_fb_, device, index, &fb->base); + fb->func = func; + *pfb = &fb->base; + + fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (fb->r100c08_page) { + fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0, + PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(device->dev, fb->r100c08)) + return -EFAULT; + } else { + nvkm_warn(&fb->base.subdev, "failed 100c08 page alloc\n"); + } - /* This is needed to get meaningful information from 100c90 - * on traps. No idea what these values mean exactly. */ - nv_wr32(priv, 0x100c90, impl->trap); return 0; } -struct nvkm_oclass * -nv50_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x50), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram = &nv50_ram_oclass, +static const struct nv50_fb_func +nv50_fb = { + .ram_new = nv50_ram_new, .trap = 0x000707ff, -}.base.base; +}; + +int +nv50_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&nv50_fb, device, index, pfb); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h index f3cde3f1f..faa88c8c6 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h @@ -1,31 +1,21 @@ #ifndef __NVKM_FB_NV50_H__ #define __NVKM_FB_NV50_H__ +#define nv50_fb(p) container_of((p), struct nv50_fb, base) #include "priv.h" -struct nv50_fb_priv { +struct nv50_fb { + const struct nv50_fb_func *func; struct nvkm_fb base; struct page *r100c08_page; dma_addr_t r100c08; }; -int nv50_fb_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv50_fb_dtor(struct nvkm_object *); -int nv50_fb_init(struct nvkm_object *); - -struct nv50_fb_impl { - struct nvkm_fb_impl base; +struct nv50_fb_func { + int (*ram_new)(struct nvkm_fb *, struct nvkm_ram **); u32 trap; }; -#define nv50_ram_create(p,e,o,d) \ - nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d) -int nv50_ram_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -int nv50_ram_get(struct nvkm_fb *, u64 size, u32 align, u32 ncmin, - u32 memtype, struct nvkm_mem **); -void nv50_ram_put(struct nvkm_fb *, struct nvkm_mem **); -void __nv50_ram_put(struct nvkm_fb *, struct nvkm_mem *); +int nv50_fb_new_(const struct nv50_fb_func *, struct nvkm_device *, int index, + struct nvkm_fb **pfb); extern int nv50_fb_memtype[0x80]; #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index 485c4b648..62b9feb53 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -1,73 +1,62 @@ #ifndef __NVKM_FB_PRIV_H__ #define __NVKM_FB_PRIV_H__ +#define nvkm_fb(p) container_of((p), struct nvkm_fb, subdev) #include <subdev/fb.h> struct nvkm_bios; -#define nvkm_ram_create(p,e,o,d) \ - nvkm_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d) -#define nvkm_ram_destroy(p) \ - nvkm_object_destroy(&(p)->base) -#define nvkm_ram_init(p) \ - nvkm_object_init(&(p)->base) -#define nvkm_ram_fini(p,s) \ - nvkm_object_fini(&(p)->base, (s)) +struct nvkm_fb_func { + void *(*dtor)(struct nvkm_fb *); + void (*init)(struct nvkm_fb *); + void (*intr)(struct nvkm_fb *); -#define nvkm_ram_create_(p,e,o,s,d) \ - nvkm_object_create_((p), (e), (o), 0, (s), (void **)d) -#define _nvkm_ram_dtor nvkm_object_destroy -#define _nvkm_ram_init nvkm_object_init -#define _nvkm_ram_fini nvkm_object_fini + struct { + int regions; + void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); + void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags, + struct nvkm_fb_tile *); + void (*fini)(struct nvkm_fb *, int i, struct nvkm_fb_tile *); + void (*prog)(struct nvkm_fb *, int i, struct nvkm_fb_tile *); + } tile; -extern struct nvkm_oclass nv04_ram_oclass; -extern struct nvkm_oclass nv10_ram_oclass; -extern struct nvkm_oclass nv1a_ram_oclass; -extern struct nvkm_oclass nv20_ram_oclass; -extern struct nvkm_oclass nv40_ram_oclass; -extern struct nvkm_oclass nv41_ram_oclass; -extern struct nvkm_oclass nv44_ram_oclass; -extern struct nvkm_oclass nv49_ram_oclass; -extern struct nvkm_oclass nv4e_ram_oclass; -extern struct nvkm_oclass nv50_ram_oclass; -extern struct nvkm_oclass gt215_ram_oclass; -extern struct nvkm_oclass mcp77_ram_oclass; -extern struct nvkm_oclass gf100_ram_oclass; -extern struct nvkm_oclass gk104_ram_oclass; -extern struct nvkm_oclass gm107_ram_oclass; + int (*ram_new)(struct nvkm_fb *, struct nvkm_ram **); -int nvkm_sddr2_calc(struct nvkm_ram *ram); -int nvkm_sddr3_calc(struct nvkm_ram *ram); -int nvkm_gddr3_calc(struct nvkm_ram *ram); -int nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts); + bool (*memtype_valid)(struct nvkm_fb *, u32 memtype); +}; -#define nvkm_fb_create(p,e,c,d) \ - nvkm_fb_create_((p), (e), (c), sizeof(**d), (void **)d) -#define nvkm_fb_destroy(p) ({ \ - struct nvkm_fb *pfb = (p); \ - _nvkm_fb_dtor(nv_object(pfb)); \ -}) -#define nvkm_fb_init(p) ({ \ - struct nvkm_fb *pfb = (p); \ - _nvkm_fb_init(nv_object(pfb)); \ -}) -#define nvkm_fb_fini(p,s) ({ \ - struct nvkm_fb *pfb = (p); \ - _nvkm_fb_fini(nv_object(pfb), (s)); \ -}) +void nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device, + int index, struct nvkm_fb *); +int nvkm_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *device, + int index, struct nvkm_fb **); +int nvkm_fb_bios_memtype(struct nvkm_bios *); -int nvkm_fb_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_fb_dtor(struct nvkm_object *); -int _nvkm_fb_init(struct nvkm_object *); -int _nvkm_fb_fini(struct nvkm_object *, bool); +bool nv04_fb_memtype_valid(struct nvkm_fb *, u32 memtype); -struct nvkm_fb_impl { - struct nvkm_oclass base; - struct nvkm_oclass *ram; - bool (*memtype)(struct nvkm_fb *, u32); -}; +void nv10_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); +void nv10_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); +void nv10_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); -bool nv04_fb_memtype_valid(struct nvkm_fb *, u32 memtype); -bool nv50_fb_memtype_valid(struct nvkm_fb *, u32 memtype); +void nv20_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); +void nv20_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); +void nv20_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); + +void nv30_fb_init(struct nvkm_fb *); +void nv30_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); + +void nv40_fb_tile_comp(struct nvkm_fb *, int i, u32 size, u32 flags, + struct nvkm_fb_tile *); + +void nv41_fb_init(struct nvkm_fb *); +void nv41_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); + +void nv44_fb_init(struct nvkm_fb *); +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 nvkm_fb_bios_memtype(struct nvkm_bios *); +bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c new file mode 100644 index 000000000..c17d559db --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c @@ -0,0 +1,100 @@ +/* + * Copyright 2015 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 "ram.h" + +int +nvkm_ram_init(struct nvkm_ram *ram) +{ + if (ram->func->init) + return ram->func->init(ram); + return 0; +} + +void +nvkm_ram_del(struct nvkm_ram **pram) +{ + struct nvkm_ram *ram = *pram; + if (ram && !WARN_ON(!ram->func)) { + if (ram->func->dtor) + *pram = ram->func->dtor(ram); + nvkm_mm_fini(&ram->tags); + nvkm_mm_fini(&ram->vram); + kfree(*pram); + *pram = NULL; + } +} + +int +nvkm_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb, + enum nvkm_ram_type type, u64 size, u32 tags, + struct nvkm_ram *ram) +{ + static const char *name[] = { + [NVKM_RAM_TYPE_UNKNOWN] = "of unknown memory type", + [NVKM_RAM_TYPE_STOLEN ] = "stolen system memory", + [NVKM_RAM_TYPE_SGRAM ] = "SGRAM", + [NVKM_RAM_TYPE_SDRAM ] = "SDRAM", + [NVKM_RAM_TYPE_DDR1 ] = "DDR1", + [NVKM_RAM_TYPE_DDR2 ] = "DDR2", + [NVKM_RAM_TYPE_DDR3 ] = "DDR3", + [NVKM_RAM_TYPE_GDDR2 ] = "GDDR2", + [NVKM_RAM_TYPE_GDDR3 ] = "GDDR3", + [NVKM_RAM_TYPE_GDDR4 ] = "GDDR4", + [NVKM_RAM_TYPE_GDDR5 ] = "GDDR5", + }; + struct nvkm_subdev *subdev = &fb->subdev; + int ret; + + nvkm_info(subdev, "%d MiB %s\n", (int)(size >> 20), name[type]); + ram->func = func; + ram->fb = fb; + ram->type = type; + ram->size = size; + + if (!nvkm_mm_initialised(&ram->vram)) { + ret = nvkm_mm_init(&ram->vram, 0, size >> NVKM_RAM_MM_SHIFT, 1); + if (ret) + return ret; + } + + if (!nvkm_mm_initialised(&ram->tags)) { + ret = nvkm_mm_init(&ram->tags, 0, tags ? ++tags : 0, 1); + if (ret) + return ret; + + nvkm_debug(subdev, "%d compression tags\n", tags); + } + + return 0; +} + +int +nvkm_ram_new_(const struct nvkm_ram_func *func, struct nvkm_fb *fb, + enum nvkm_ram_type type, u64 size, u32 tags, + struct nvkm_ram **pram) +{ + if (!(*pram = kzalloc(sizeof(**pram), GFP_KERNEL))) + return -ENOMEM; + return nvkm_ram_ctor(func, fb, type, size, tags, *pram); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h new file mode 100644 index 000000000..f816cbf2c --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h @@ -0,0 +1,50 @@ +#ifndef __NVKM_FB_RAM_PRIV_H__ +#define __NVKM_FB_RAM_PRIV_H__ +#include "priv.h" + +int nvkm_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, + enum nvkm_ram_type, u64 size, u32 tags, + struct nvkm_ram *); +int nvkm_ram_new_(const struct nvkm_ram_func *, struct nvkm_fb *, + enum nvkm_ram_type, u64 size, u32 tags, + struct nvkm_ram **); +void nvkm_ram_del(struct nvkm_ram **); +int nvkm_ram_init(struct nvkm_ram *); + +extern const struct nvkm_ram_func nv04_ram_func; + +int nv50_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, + struct nvkm_ram *); +int nv50_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); +void nv50_ram_put(struct nvkm_ram *, struct nvkm_mem **); +void __nv50_ram_put(struct nvkm_ram *, struct nvkm_mem *); + +int gf100_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, + u32, struct nvkm_ram *); +int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); +void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **); + +int gk104_ram_init(struct nvkm_ram *ram); + +/* RAM type-specific MR calculation routines */ +int nvkm_sddr2_calc(struct nvkm_ram *); +int nvkm_sddr3_calc(struct nvkm_ram *); +int nvkm_gddr3_calc(struct nvkm_ram *); +int nvkm_gddr5_calc(struct nvkm_ram *, bool nuts); + +int nv04_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv10_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv1a_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv20_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv40_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv41_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv44_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv49_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv4e_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv50_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gt215_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int mcp77_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gf100_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gk104_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gm107_ram_new(struct nvkm_fb *, struct nvkm_ram **); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h index f343682b1..9ef9d6aa3 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h @@ -1,10 +1,11 @@ #ifndef __NVKM_FBRAM_FUC_H__ #define __NVKM_FBRAM_FUC_H__ +#include <subdev/fb.h> #include <subdev/pmu.h> struct ramfuc { struct nvkm_memx *memx; - struct nvkm_fb *pfb; + struct nvkm_fb *fb; int sequence; }; @@ -54,17 +55,14 @@ ramfuc_reg(u32 addr) } static inline int -ramfuc_init(struct ramfuc *ram, struct nvkm_fb *pfb) +ramfuc_init(struct ramfuc *ram, struct nvkm_fb *fb) { - struct nvkm_pmu *pmu = nvkm_pmu(pfb); - int ret; - - ret = nvkm_memx_init(pmu, &ram->memx); + int ret = nvkm_memx_init(fb->subdev.device->pmu, &ram->memx); if (ret) return ret; ram->sequence++; - ram->pfb = pfb; + ram->fb = fb; return 0; } @@ -72,9 +70,9 @@ static inline int ramfuc_exec(struct ramfuc *ram, bool exec) { int ret = 0; - if (ram->pfb) { + if (ram->fb) { ret = nvkm_memx_fini(&ram->memx, exec); - ram->pfb = NULL; + ram->fb = NULL; } return ret; } @@ -82,8 +80,9 @@ ramfuc_exec(struct ramfuc *ram, bool exec) static inline u32 ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg) { + struct nvkm_device *device = ram->fb->subdev.device; if (reg->sequence != ram->sequence) - reg->data = nv_rd32(ram->pfb, reg->addr); + reg->data = nvkm_rd32(device, reg->addr); return reg->data; } @@ -144,11 +143,9 @@ ramfuc_train(struct ramfuc *ram) } static inline int -ramfuc_train_result(struct nvkm_fb *pfb, u32 *result, u32 rsize) +ramfuc_train_result(struct nvkm_fb *fb, u32 *result, u32 rsize) { - struct nvkm_pmu *pmu = nvkm_pmu(pfb); - - return nvkm_memx_train_result(pmu, result, rsize); + return nvkm_memx_train_result(fb->subdev.device->pmu, result, rsize); } static inline void diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index de9f39569..772425ca5 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#include "gf100.h" +#define gf100_ram(p) container_of((p), struct gf100_ram, base) +#include "ram.h" #include "ramfuc.h" -#include <core/device.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> @@ -108,9 +108,10 @@ static void gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) { struct gf100_ram *ram = container_of(fuc, typeof(*ram), fuc); - struct nvkm_fb *pfb = nvkm_fb(ram); - u32 part = nv_rd32(pfb, 0x022438), i; - u32 mask = nv_rd32(pfb, 0x022554); + struct nvkm_fb *fb = ram->base.fb; + struct nvkm_device *device = fb->subdev.device; + u32 part = nvkm_rd32(device, 0x022438), i; + u32 mask = nvkm_rd32(device, 0x022554); u32 addr = 0x110974; ram_wr32(fuc, 0x10f910, magic); @@ -124,12 +125,14 @@ gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) } static int -gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) +gf100_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_clk *clk = nvkm_clk(pfb); - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gf100_ram *ram = (void *)pfb->ram; + struct gf100_ram *ram = gf100_ram(base); struct gf100_ramfuc *fuc = &ram->fuc; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_clk *clk = device->clk; + struct nvkm_bios *bios = device->bios; struct nvbios_ramcfg cfg; u8 ver, cnt, len, strap; struct { @@ -145,37 +148,37 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size, &cnt, &ramcfg.size, &cfg); if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) { - nv_error(pfb, "invalid/missing rammap entry\n"); + nvkm_error(subdev, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(pfb)); + strap = nvbios_ramcfg_index(subdev); if (strap >= cnt) { - nv_error(pfb, "invalid ramcfg strap\n"); + nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; } ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) { - nv_error(pfb, "invalid/missing ramcfg entry\n"); + nvkm_error(subdev, "invalid/missing ramcfg entry\n"); return -EINVAL; } /* lookup memory timings, if bios says they're present */ - strap = nv_ro08(bios, ramcfg.data + 0x01); + strap = nvbios_rd08(bios, ramcfg.data + 0x01); if (strap != 0xff) { timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size, &cnt, &len); if (!timing.data || ver != 0x10 || timing.size < 0x19) { - nv_error(pfb, "invalid/missing timing entry\n"); + nvkm_error(subdev, "invalid/missing timing entry\n"); return -EINVAL; } } else { timing.data = 0; } - ret = ram_init(fuc, pfb); + ret = ram_init(fuc, ram->base.fb); if (ret) return ret; @@ -184,9 +187,9 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) /* determine target mclk configuration */ if (!(ram_rd32(fuc, 0x137300) & 0x00000100)) - ref = clk->read(clk, nv_clk_src_sppll0); + ref = nvkm_clk_read(clk, nv_clk_src_sppll0); else - ref = clk->read(clk, nv_clk_src_sppll1); + ref = nvkm_clk_read(clk, nv_clk_src_sppll1); div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2; out = (ref * 2) / (div + 2); mode = freq != out; @@ -210,10 +213,10 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) if (mode == 1 && from == 0) { /* calculate refpll */ - ret = gt215_pll_calc(nv_subdev(pfb), &ram->refpll, - ram->mempll.refclk, &N1, NULL, &M1, &P); + ret = gt215_pll_calc(subdev, &ram->refpll, ram->mempll.refclk, + &N1, NULL, &M1, &P); if (ret <= 0) { - nv_error(pfb, "unable to calc refpll\n"); + nvkm_error(subdev, "unable to calc refpll\n"); return ret ? ret : -ERANGE; } @@ -225,10 +228,10 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000); /* calculate mempll */ - ret = gt215_pll_calc(nv_subdev(pfb), &ram->mempll, freq, + ret = gt215_pll_calc(subdev, &ram->mempll, freq, &N1, NULL, &M1, &P); if (ret <= 0) { - nv_error(pfb, "unable to calc refpll\n"); + nvkm_error(subdev, "unable to calc refpll\n"); return ret ? ret : -ERANGE; } @@ -402,49 +405,48 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) } static int -gf100_ram_prog(struct nvkm_fb *pfb) +gf100_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(pfb); - struct gf100_ram *ram = (void *)pfb->ram; - struct gf100_ramfuc *fuc = &ram->fuc; - ram_exec(fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); + struct gf100_ram *ram = gf100_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + ram_exec(&ram->fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); return 0; } static void -gf100_ram_tidy(struct nvkm_fb *pfb) +gf100_ram_tidy(struct nvkm_ram *base) { - struct gf100_ram *ram = (void *)pfb->ram; - struct gf100_ramfuc *fuc = &ram->fuc; - ram_exec(fuc, false); + struct gf100_ram *ram = gf100_ram(base); + ram_exec(&ram->fuc, false); } extern const u8 gf100_pte_storage_type_map[256]; void -gf100_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) +gf100_ram_put(struct nvkm_ram *ram, struct nvkm_mem **pmem) { - struct nvkm_ltc *ltc = nvkm_ltc(pfb); + struct nvkm_ltc *ltc = ram->fb->subdev.device->ltc; struct nvkm_mem *mem = *pmem; *pmem = NULL; if (unlikely(mem == NULL)) return; - mutex_lock(&pfb->base.mutex); + mutex_lock(&ram->fb->subdev.mutex); if (mem->tag) - ltc->tags_free(ltc, &mem->tag); - __nv50_ram_put(pfb, mem); - mutex_unlock(&pfb->base.mutex); + nvkm_ltc_tags_free(ltc, &mem->tag); + __nv50_ram_put(ram, mem); + mutex_unlock(&ram->fb->subdev.mutex); kfree(mem); } int -gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, +gf100_ram_get(struct nvkm_ram *ram, u64 size, u32 align, u32 ncmin, u32 memtype, struct nvkm_mem **pmem) { - struct nvkm_mm *mm = &pfb->vram; + struct nvkm_ltc *ltc = ram->fb->subdev.device->ltc; + struct nvkm_mm *mm = &ram->vram; struct nvkm_mm_node *r; struct nvkm_mem *mem; int type = (memtype & 0x0ff); @@ -452,9 +454,9 @@ gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, const bool comp = gf100_pte_storage_type_map[type] != type; int ret; - size >>= 12; - align >>= 12; - ncmin >>= 12; + size >>= NVKM_RAM_MM_SHIFT; + align >>= NVKM_RAM_MM_SHIFT; + ncmin >>= NVKM_RAM_MM_SHIFT; if (!ncmin) ncmin = size; @@ -465,14 +467,12 @@ gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, INIT_LIST_HEAD(&mem->regions); mem->size = size; - mutex_lock(&pfb->base.mutex); + mutex_lock(&ram->fb->subdev.mutex); if (comp) { - struct nvkm_ltc *ltc = nvkm_ltc(pfb); - /* compression only works with lpages */ - if (align == (1 << (17 - 12))) { + if (align == (1 << (17 - NVKM_RAM_MM_SHIFT))) { int n = size >> 5; - ltc->tags_alloc(ltc, n, &mem->tag); + nvkm_ltc_tags_alloc(ltc, n, &mem->tag); } if (unlikely(!mem->tag)) @@ -486,178 +486,173 @@ gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, else ret = nvkm_mm_head(mm, 0, 1, size, ncmin, align, &r); if (ret) { - mutex_unlock(&pfb->base.mutex); - pfb->ram->put(pfb, &mem); + mutex_unlock(&ram->fb->subdev.mutex); + ram->func->put(ram, &mem); return ret; } list_add_tail(&r->rl_entry, &mem->regions); size -= r->length; } while (size); - mutex_unlock(&pfb->base.mutex); + mutex_unlock(&ram->fb->subdev.mutex); r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry); - mem->offset = (u64)r->offset << 12; + mem->offset = (u64)r->offset << NVKM_RAM_MM_SHIFT; *pmem = mem; return 0; } -int -gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 maskaddr, int size, - void **pobject) +static int +gf100_ram_init(struct nvkm_ram *base) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nvkm_ram *ram; - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 parts = nv_rd32(pfb, 0x022438); - u32 pmask = nv_rd32(pfb, maskaddr); - u32 bsize = nv_rd32(pfb, 0x10f20c); - u32 offset, length; - bool uniform = true; - int ret, part; + static const u8 train0[] = { + 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, + 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + }; + static const u32 train1[] = { + 0x00000000, 0xffffffff, + 0x55555555, 0xaaaaaaaa, + 0x33333333, 0xcccccccc, + 0xf0f0f0f0, 0x0f0f0f0f, + 0x00ff00ff, 0xff00ff00, + 0x0000ffff, 0xffff0000, + }; + struct gf100_ram *ram = gf100_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + int i; - ret = nvkm_ram_create_(parent, engine, oclass, size, pobject); - ram = *pobject; - if (ret) - return ret; + switch (ram->base.type) { + case NVKM_RAM_TYPE_GDDR5: + break; + default: + return 0; + } - nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800)); - nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask); + /* prepare for ddr link training, and load training patterns */ + for (i = 0; i < 0x30; i++) { + nvkm_wr32(device, 0x10f968, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f96c, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f920, 0x00000100 | train0[i % 12]); + nvkm_wr32(device, 0x10f924, 0x00000100 | train0[i % 12]); + nvkm_wr32(device, 0x10f918, train1[i % 12]); + nvkm_wr32(device, 0x10f91c, train1[i % 12]); + nvkm_wr32(device, 0x10f920, 0x00000000 | train0[i % 12]); + nvkm_wr32(device, 0x10f924, 0x00000000 | train0[i % 12]); + nvkm_wr32(device, 0x10f918, train1[i % 12]); + nvkm_wr32(device, 0x10f91c, train1[i % 12]); + } - ram->type = nvkm_fb_bios_memtype(bios); - ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1; + return 0; +} + +static const struct nvkm_ram_func +gf100_ram_func = { + .init = gf100_ram_init, + .get = gf100_ram_get, + .put = gf100_ram_put, + .calc = gf100_ram_calc, + .prog = gf100_ram_prog, + .tidy = gf100_ram_tidy, +}; + +int +gf100_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb, + u32 maskaddr, struct nvkm_ram *ram) +{ + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + const u32 rsvd_head = ( 256 * 1024); /* vga memory */ + const u32 rsvd_tail = (1024 * 1024); /* vbios etc */ + u32 parts = nvkm_rd32(device, 0x022438); + u32 pmask = nvkm_rd32(device, maskaddr); + u64 bsize = (u64)nvkm_rd32(device, 0x10f20c) << 20; + u64 psize, size = 0; + enum nvkm_ram_type type = nvkm_fb_bios_memtype(bios); + bool uniform = true; + int ret, i; + + nvkm_debug(subdev, "100800: %08x\n", nvkm_rd32(device, 0x100800)); + nvkm_debug(subdev, "parts %08x mask %08x\n", parts, pmask); /* read amount of vram attached to each memory controller */ - for (part = 0; part < parts; part++) { - if (!(pmask & (1 << part))) { - u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000)); - if (psize != bsize) { - if (psize < bsize) - bsize = psize; - uniform = false; - } - - nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize); - ram->size += (u64)psize << 20; + for (i = 0; i < parts; i++) { + if (pmask & (1 << i)) + continue; + + psize = (u64)nvkm_rd32(device, 0x11020c + (i * 0x1000)) << 20; + if (psize != bsize) { + if (psize < bsize) + bsize = psize; + uniform = false; } + + nvkm_debug(subdev, "%d: %d MiB\n", i, (u32)(psize >> 20)); + size += psize; } + ret = nvkm_ram_ctor(func, fb, type, size, 0, ram); + if (ret) + return ret; + + nvkm_mm_fini(&ram->vram); + /* if all controllers have the same amount attached, there's no holes */ if (uniform) { - offset = rsvd_head; - length = (ram->size >> 12) - rsvd_head - rsvd_tail; - ret = nvkm_mm_init(&pfb->vram, offset, length, 1); + ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + (size - rsvd_head - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); + if (ret) + return ret; } else { /* otherwise, address lowest common amount from 0GiB */ - ret = nvkm_mm_init(&pfb->vram, rsvd_head, - (bsize << 8) * parts - rsvd_head, 1); + ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + ((bsize * parts) - rsvd_head) >> + NVKM_RAM_MM_SHIFT, 1); if (ret) return ret; /* and the rest starting from (8GiB + common_size) */ - offset = (0x0200000000ULL >> 12) + (bsize << 8); - length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail; - - ret = nvkm_mm_init(&pfb->vram, offset, length, 1); + ret = nvkm_mm_init(&ram->vram, (0x0200000000ULL + bsize) >> + NVKM_RAM_MM_SHIFT, + (size - (bsize * parts) - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); if (ret) - nvkm_mm_fini(&pfb->vram); - } - - if (ret) - return ret; - - ram->get = gf100_ram_get; - ram->put = gf100_ram_put; - return 0; -} - -static int -gf100_ram_init(struct nvkm_object *object) -{ - struct nvkm_fb *pfb = (void *)object->parent; - struct gf100_ram *ram = (void *)object; - int ret, i; - - ret = nvkm_ram_init(&ram->base); - if (ret) - return ret; - - /* prepare for ddr link training, and load training patterns */ - switch (ram->base.type) { - case NV_MEM_TYPE_GDDR5: { - static const u8 train0[] = { - 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, - 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, - }; - static const u32 train1[] = { - 0x00000000, 0xffffffff, - 0x55555555, 0xaaaaaaaa, - 0x33333333, 0xcccccccc, - 0xf0f0f0f0, 0x0f0f0f0f, - 0x00ff00ff, 0xff00ff00, - 0x0000ffff, 0xffff0000, - }; - - for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]); - nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]); - nv_wr32(pfb, 0x10f918, train1[i % 12]); - nv_wr32(pfb, 0x10f91c, train1[i % 12]); - nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]); - nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]); - nv_wr32(pfb, 0x10f918, train1[i % 12]); - nv_wr32(pfb, 0x10f91c, train1[i % 12]); - } - } break; - default: - break; + return ret; } + ram->ranks = (nvkm_rd32(device, 0x10f200) & 0x00000004) ? 2 : 1; return 0; } -static int -gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_bios *bios = nvkm_bios(parent); + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct gf100_ram *ram; int ret; - ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram); - *pobject = nv_object(ram); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = gf100_ram_ctor(&gf100_ram_func, fb, 0x022554, &ram->base); if (ret) return ret; ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll); if (ret) { - nv_error(ram, "mclk refpll data not found\n"); + nvkm_error(subdev, "mclk refpll data not found\n"); return ret; } ret = nvbios_pll_parse(bios, 0x04, &ram->mempll); if (ret) { - nv_error(ram, "mclk pll data not found\n"); + nvkm_error(subdev, "mclk pll data not found\n"); return ret; } - switch (ram->base.type) { - case NV_MEM_TYPE_GDDR5: - ram->base.calc = gf100_ram_calc; - ram->base.prog = gf100_ram_prog; - ram->base.tidy = gf100_ram_tidy; - break; - default: - nv_warn(ram, "reclocking of this ram type unsupported\n"); - return 0; - } - ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20); ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24); ram->fuc.r_0x137320 = ramfuc_reg(0x137320); @@ -718,14 +713,3 @@ gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4); return 0; } - -struct nvkm_oclass -gf100_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = gf100_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 1ef15c3e6..9df45030f 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ +#define gk104_ram(p) container_of((p), struct gk104_ram, base) +#include "ram.h" #include "ramfuc.h" -#include "gf100.h" -#include <core/device.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/init.h> @@ -229,8 +229,9 @@ static void gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, u32 _mask, u32 _data, u32 _copy) { - struct gk104_fb_priv *priv = (void *)nvkm_fb(ram); + struct nvkm_fb *fb = ram->base.fb; struct ramfuc *fuc = &ram->fuc.base; + struct nvkm_device *device = fb->subdev.device; u32 addr = 0x110000 + (reg->addr & 0xfff); u32 mask = _mask | _copy; u32 data = (_data & _mask) | (reg->data & _copy); @@ -238,7 +239,7 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, for (i = 0; i < 16; i++, addr += 0x1000) { if (ram->pnuts & (1 << i)) { - u32 prev = nv_rd32(priv, addr); + u32 prev = nvkm_rd32(device, addr); u32 next = (prev & ~mask) | data; nvkm_memx_wr32(fuc->memx, addr, next); } @@ -248,9 +249,8 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, gk104_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c)) static int -gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq) +gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq) { - struct gk104_ram *ram = (void *)pfb->ram; struct gk104_ramfuc *fuc = &ram->fuc; struct nvkm_ram_data *next = ram->base.next; int vc = !next->bios.ramcfg_11_02_08; @@ -673,10 +673,28 @@ gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq) * DDR3 ******************************************************************************/ +static void +nvkm_sddr3_dll_reset(struct gk104_ramfuc *fuc) +{ + ram_nuke(fuc, mr[0]); + ram_mask(fuc, mr[0], 0x100, 0x100); + ram_mask(fuc, mr[0], 0x100, 0x000); +} + +static void +nvkm_sddr3_dll_disable(struct gk104_ramfuc *fuc) +{ + u32 mr1_old = ram_rd32(fuc, mr[1]); + + if (!(mr1_old & 0x1)) { + ram_mask(fuc, mr[1], 0x1, 0x1); + ram_nsec(fuc, 1000); + } +} + static int -gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq) +gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq) { - struct gk104_ram *ram = (void *)pfb->ram; struct gk104_ramfuc *fuc = &ram->fuc; const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1); const u32 runk0 = ram->fN1 << 16; @@ -703,6 +721,10 @@ gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq) ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000); ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */ + + if (next->bios.ramcfg_DLLoff) + nvkm_sddr3_dll_disable(fuc); + ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */ ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */ ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000); @@ -880,17 +902,20 @@ gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq) ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */ ram_nsec(fuc, 1000); - ram_nuke(fuc, mr[0]); - ram_mask(fuc, mr[0], 0x100, 0x100); - ram_mask(fuc, mr[0], 0x100, 0x000); + if (!next->bios.ramcfg_DLLoff) { + ram_mask(fuc, mr[1], 0x1, 0x0); + nvkm_sddr3_dll_reset(fuc); + } - ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]); + ram_mask(fuc, mr[2], 0x00000fff, ram->base.mr[2]); + ram_mask(fuc, mr[1], 0xffffffff, ram->base.mr[1]); ram_wr32(fuc, mr[0], ram->base.mr[0]); ram_nsec(fuc, 1000); - ram_nuke(fuc, mr[0]); - ram_mask(fuc, mr[0], 0x100, 0x100); - ram_mask(fuc, mr[0], 0x100, 0x000); + if (!next->bios.ramcfg_DLLoff) { + nvkm_sddr3_dll_reset(fuc); + ram_nsec(fuc, 1000); + } if (vc == 0 && ram_have(fuc, gpio2E)) { u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]); @@ -926,9 +951,9 @@ gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq) ******************************************************************************/ static int -gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data) +gk104_ram_calc_data(struct gk104_ram *ram, u32 khz, struct nvkm_ram_data *data) { - struct gk104_ram *ram = (void *)pfb->ram; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_ram_data *cfg; u32 mhz = khz / 1000; @@ -941,19 +966,80 @@ gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data) } } - nv_error(ram, "ramcfg data for %dMHz not found\n", mhz); + nvkm_error(subdev, "ramcfg data for %dMHz not found\n", mhz); return -EINVAL; } static int -gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) +gk104_calc_pll_output(int fN, int M, int N, int P, int clk) +{ + return ((clk * N) + (((u16)(fN + 4096) * clk) >> 13)) / (M * P); +} + +static int +gk104_pll_calc_hiclk(int target_khz, int crystal, + int *N1, int *fN1, int *M1, int *P1, + int *N2, int *M2, int *P2) +{ + int best_clk = 0, best_err = target_khz, p_ref, n_ref; + bool upper = false; + + *M1 = 1; + /* M has to be 1, otherwise it gets unstable */ + *M2 = 1; + /* can be 1 or 2, sticking with 1 for simplicity */ + *P2 = 1; + + for (p_ref = 0x7; p_ref >= 0x5; --p_ref) { + for (n_ref = 0x25; n_ref <= 0x2b; ++n_ref) { + int cur_N, cur_clk, cur_err; + + cur_clk = gk104_calc_pll_output(0, 1, n_ref, p_ref, crystal); + cur_N = target_khz / cur_clk; + cur_err = target_khz + - gk104_calc_pll_output(0xf000, 1, cur_N, 1, cur_clk); + + /* we found a better combination */ + if (cur_err < best_err) { + best_err = cur_err; + best_clk = cur_clk; + *N2 = cur_N; + *N1 = n_ref; + *P1 = p_ref; + upper = false; + } + + cur_N += 1; + cur_err = gk104_calc_pll_output(0xf000, 1, cur_N, 1, cur_clk) + - target_khz; + if (cur_err < best_err) { + best_err = cur_err; + best_clk = cur_clk; + *N2 = cur_N; + *N1 = n_ref; + *P1 = p_ref; + upper = true; + } + } + } + + /* adjust fN to get closer to the target clock */ + *fN1 = (u16)((((best_err / *N2 * *P2) * (*P1 * *M1)) << 13) / crystal); + if (upper) + *fN1 = (u16)(1 - *fN1); + + return gk104_calc_pll_output(*fN1, 1, *N1, *P1, crystal); +} + +static int +gk104_ram_calc_xits(struct gk104_ram *ram, struct nvkm_ram_data *next) { - struct gk104_ram *ram = (void *)pfb->ram; struct gk104_ramfuc *fuc = &ram->fuc; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; int refclk, i; int ret; - ret = ram_init(fuc, pfb); + ret = ram_init(fuc, ram->base.fb); if (ret) return ret; @@ -969,31 +1055,24 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) * kepler boards, no idea how/why they're chosen. */ refclk = next->freq; - if (ram->mode == 2) - refclk = fuc->mempll.refclk; - - /* calculate refpll coefficients */ - ret = gt215_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1, - &ram->fN1, &ram->M1, &ram->P1); - fuc->mempll.refclk = ret; - if (ret <= 0) { - nv_error(pfb, "unable to calc refpll\n"); - return -EINVAL; - } - - /* calculate mempll coefficients, if we're using it */ if (ram->mode == 2) { - /* post-divider doesn't work... the reg takes the values but - * appears to completely ignore it. there *is* a bit at - * bit 28 that appears to divide the clock by 2 if set. - */ - fuc->mempll.min_p = 1; - fuc->mempll.max_p = 2; - - ret = gt215_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq, - &ram->N2, NULL, &ram->M2, &ram->P2); + ret = gk104_pll_calc_hiclk(next->freq, subdev->device->crystal, + &ram->N1, &ram->fN1, &ram->M1, &ram->P1, + &ram->N2, &ram->M2, &ram->P2); + fuc->mempll.refclk = ret; if (ret <= 0) { - nv_error(pfb, "unable to calc mempll\n"); + nvkm_error(subdev, "unable to calc plls\n"); + return -EINVAL; + } + nvkm_debug(subdev, "sucessfully calced PLLs for clock %i kHz" + " (refclock: %i kHz)\n", next->freq, ret); + } else { + /* calculate refpll coefficients */ + ret = gt215_pll_calc(subdev, &fuc->refpll, refclk, &ram->N1, + &ram->fN1, &ram->M1, &ram->P1); + fuc->mempll.refclk = ret; + if (ret <= 0) { + nvkm_error(subdev, "unable to calc refpll\n"); return -EINVAL; } } @@ -1005,15 +1084,15 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) ram->base.freq = next->freq; switch (ram->base.type) { - case NV_MEM_TYPE_DDR3: + case NVKM_RAM_TYPE_DDR3: ret = nvkm_sddr3_calc(&ram->base); if (ret == 0) - ret = gk104_ram_calc_sddr3(pfb, next->freq); + ret = gk104_ram_calc_sddr3(ram, next->freq); break; - case NV_MEM_TYPE_GDDR5: + case NVKM_RAM_TYPE_GDDR5: ret = nvkm_gddr5_calc(&ram->base, ram->pnuts != 0); if (ret == 0) - ret = gk104_ram_calc_gddr5(pfb, next->freq); + ret = gk104_ram_calc_gddr5(ram, next->freq); break; default: ret = -ENOSYS; @@ -1024,21 +1103,22 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) } static int -gk104_ram_calc(struct nvkm_fb *pfb, u32 freq) +gk104_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_clk *clk = nvkm_clk(pfb); - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = gk104_ram(base); + struct nvkm_clk *clk = ram->base.fb->subdev.device->clk; struct nvkm_ram_data *xits = &ram->base.xition; struct nvkm_ram_data *copy; int ret; if (ram->base.next == NULL) { - ret = gk104_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem), + ret = gk104_ram_calc_data(ram, + nvkm_clk_read(clk, nv_clk_src_mem), &ram->base.former); if (ret) return ret; - ret = gk104_ram_calc_data(pfb, freq, &ram->base.target); + ret = gk104_ram_calc_data(ram, freq, &ram->base.target); if (ret) return ret; @@ -1062,13 +1142,13 @@ gk104_ram_calc(struct nvkm_fb *pfb, u32 freq) ram->base.next = &ram->base.target; } - return gk104_ram_calc_xits(pfb, ram->base.next); + return gk104_ram_calc_xits(ram, ram->base.next); } static void -gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) +gk104_ram_prog_0(struct gk104_ram *ram, u32 freq) { - struct gk104_ram *ram = (void *)pfb->ram; + struct nvkm_device *device = ram->base.fb->subdev.device; struct nvkm_ram_data *cfg; u32 mhz = freq / 1000; u32 mask, data; @@ -1090,31 +1170,31 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) data |= cfg->bios.rammap_11_09_01ff; mask |= 0x000001ff; } - nv_mask(pfb, 0x10f468, mask, data); + nvkm_mask(device, 0x10f468, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) { data |= cfg->bios.rammap_11_0a_0400; mask |= 0x00000001; } - nv_mask(pfb, 0x10f420, mask, data); + nvkm_mask(device, 0x10f420, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) { data |= cfg->bios.rammap_11_0a_0800; mask |= 0x00000001; } - nv_mask(pfb, 0x10f430, mask, data); + nvkm_mask(device, 0x10f430, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) { data |= cfg->bios.rammap_11_0b_01f0; mask |= 0x0000001f; } - nv_mask(pfb, 0x10f400, mask, data); + nvkm_mask(device, 0x10f400, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) { data |= cfg->bios.rammap_11_0b_0200 << 9; mask |= 0x00000200; } - nv_mask(pfb, 0x10f410, mask, data); + nvkm_mask(device, 0x10f410, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0d) { data |= cfg->bios.rammap_11_0d << 16; @@ -1124,7 +1204,7 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) data |= cfg->bios.rammap_11_0f << 8; mask |= 0x0000ff00; } - nv_mask(pfb, 0x10f440, mask, data); + nvkm_mask(device, 0x10f440, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0e) { data |= cfg->bios.rammap_11_0e << 8; @@ -1138,15 +1218,15 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) data |= cfg->bios.rammap_11_0b_0400 << 5; mask |= 0x00000020; } - nv_mask(pfb, 0x10f444, mask, data); + nvkm_mask(device, 0x10f444, mask, data); } static int -gk104_ram_prog(struct nvkm_fb *pfb) +gk104_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(pfb); - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = gk104_ram(base); struct gk104_ramfuc *fuc = &ram->fuc; + struct nvkm_device *device = ram->base.fb->subdev.device; struct nvkm_ram_data *next = ram->base.next; if (!nvkm_boolopt(device->cfgopt, "NvMemExec", true)) { @@ -1154,20 +1234,19 @@ gk104_ram_prog(struct nvkm_fb *pfb) return (ram->base.next == &ram->base.xition); } - gk104_ram_prog_0(pfb, 1000); + gk104_ram_prog_0(ram, 1000); ram_exec(fuc, true); - gk104_ram_prog_0(pfb, next->freq); + gk104_ram_prog_0(ram, next->freq); return (ram->base.next == &ram->base.xition); } static void -gk104_ram_tidy(struct nvkm_fb *pfb) +gk104_ram_tidy(struct nvkm_ram *base) { - struct gk104_ram *ram = (void *)pfb->ram; - struct gk104_ramfuc *fuc = &ram->fuc; + struct gk104_ram *ram = gk104_ram(base); ram->base.next = NULL; - ram_exec(fuc, false); + ram_exec(&ram->fuc, false); } struct gk104_ram_train { @@ -1183,10 +1262,10 @@ struct gk104_ram_train { }; static int -gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg, +gk104_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, struct gk104_ram_train *train) { - struct nvkm_bios *bios = nvkm_bios(pfb); + struct nvkm_bios *bios = ram->fb->subdev.device->bios; struct nvbios_M0205E M0205E; struct nvbios_M0205S M0205S; struct nvbios_M0209E M0209E; @@ -1244,33 +1323,35 @@ gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg, } static int -gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train) +gk104_ram_train_init_0(struct nvkm_ram *ram, struct gk104_ram_train *train) { + struct nvkm_subdev *subdev = &ram->fb->subdev; + struct nvkm_device *device = subdev->device; int i, j; if ((train->mask & 0x03d3) != 0x03d3) { - nv_warn(pfb, "missing link training data\n"); + nvkm_warn(subdev, "missing link training data\n"); return -EINVAL; } for (i = 0; i < 0x30; i++) { for (j = 0; j < 8; j += 4) { - nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f920 + j, 0x00000000 | + nvkm_wr32(device, 0x10f968 + j, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f920 + j, 0x00000000 | train->type08.data[i] << 4 | train->type06.data[i]); - nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]); - nv_wr32(pfb, 0x10f920 + j, 0x00000100 | + nvkm_wr32(device, 0x10f918 + j, train->type00.data[i]); + nvkm_wr32(device, 0x10f920 + j, 0x00000100 | train->type09.data[i] << 4 | train->type07.data[i]); - nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]); + nvkm_wr32(device, 0x10f918 + j, train->type01.data[i]); } } for (j = 0; j < 8; j += 4) { for (i = 0; i < 0x100; i++) { - nv_wr32(pfb, 0x10f968 + j, i); - nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]); + nvkm_wr32(device, 0x10f968 + j, i); + nvkm_wr32(device, 0x10f900 + j, train->type04.data[i]); } } @@ -1278,23 +1359,24 @@ gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train) } static int -gk104_ram_train_init(struct nvkm_fb *pfb) +gk104_ram_train_init(struct nvkm_ram *ram) { - u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb)); + u8 ramcfg = nvbios_ramcfg_index(&ram->fb->subdev); struct gk104_ram_train *train; - int ret = -ENOMEM, i; + int ret, i; - if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) { - for (i = 0; i < 0x100; i++) { - ret = gk104_ram_train_type(pfb, i, ramcfg, train); - if (ret && ret != -ENOENT) - break; - } + if (!(train = kzalloc(sizeof(*train), GFP_KERNEL))) + return -ENOMEM; + + for (i = 0; i < 0x100; i++) { + ret = gk104_ram_train_type(ram, i, ramcfg, train); + if (ret && ret != -ENOENT) + break; } - switch (pfb->ram->type) { - case NV_MEM_TYPE_GDDR5: - ret = gk104_ram_train_init_0(pfb, train); + switch (ram->type) { + case NVKM_RAM_TYPE_GDDR5: + ret = gk104_ram_train_init_0(ram, train); break; default: ret = 0; @@ -1306,18 +1388,14 @@ gk104_ram_train_init(struct nvkm_fb *pfb) } int -gk104_ram_init(struct nvkm_object *object) +gk104_ram_init(struct nvkm_ram *ram) { - struct nvkm_fb *pfb = (void *)object->parent; - struct gk104_ram *ram = (void *)object; - struct nvkm_bios *bios = nvkm_bios(pfb); + struct nvkm_subdev *subdev = &ram->fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; u8 ver, hdr, cnt, len, snr, ssz; u32 data, save; - int ret, i; - - ret = nvkm_ram_init(&ram->base); - if (ret) - return ret; + int i; /* run a bunch of tables from rammap table. there's actually * individual pointers for each rammap entry too, but, nvidia @@ -1334,33 +1412,32 @@ gk104_ram_init(struct nvkm_object *object) if (!data || hdr < 0x15) return -EINVAL; - cnt = nv_ro08(bios, data + 0x14); /* guess at count */ - data = nv_ro32(bios, data + 0x10); /* guess u32... */ - save = nv_rd32(pfb, 0x10f65c) & 0x000000f0; + cnt = nvbios_rd08(bios, data + 0x14); /* guess at count */ + data = nvbios_rd32(bios, data + 0x10); /* guess u32... */ + save = nvkm_rd32(device, 0x10f65c) & 0x000000f0; for (i = 0; i < cnt; i++, data += 4) { if (i != save >> 4) { - nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4); + nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4); nvbios_exec(&(struct nvbios_init) { - .subdev = nv_subdev(pfb), + .subdev = subdev, .bios = bios, - .offset = nv_ro32(bios, data), + .offset = nvbios_rd32(bios, data), .execute = 1, }); } } - nv_mask(pfb, 0x10f65c, 0x000000f0, save); - nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000); - nv_wr32(pfb, 0x10ecc0, 0xffffffff); - nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010); + nvkm_mask(device, 0x10f65c, 0x000000f0, save); + nvkm_mask(device, 0x10f584, 0x11000000, 0x00000000); + nvkm_wr32(device, 0x10ecc0, 0xffffffff); + nvkm_mask(device, 0x10f160, 0x00000010, 0x00000010); - return gk104_ram_train_init(pfb); + return gk104_ram_train_init(ram); } static int gk104_ram_ctor_data(struct gk104_ram *ram, u8 ramcfg, int i) { - struct nvkm_fb *pfb = (void *)nv_object(ram)->parent; - struct nvkm_bios *bios = nvkm_bios(pfb); + struct nvkm_bios *bios = ram->base.fb->subdev.device->bios; struct nvkm_ram_data *cfg; struct nvbios_ramcfg *d = &ram->diff; struct nvbios_ramcfg *p, *n; @@ -1426,63 +1503,64 @@ done: return ret; } -static void -gk104_ram_dtor(struct nvkm_object *object) +static void * +gk104_ram_dtor(struct nvkm_ram *base) { - struct gk104_ram *ram = (void *)object; + struct gk104_ram *ram = gk104_ram(base); struct nvkm_ram_data *cfg, *tmp; list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) { kfree(cfg); } - nvkm_ram_destroy(&ram->base); + return ram; } -static int -gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_ram_func +gk104_ram_func = { + .dtor = gk104_ram_dtor, + .init = gk104_ram_init, + .get = gf100_ram_get, + .put = gf100_ram_put, + .calc = gk104_ram_calc, + .prog = gk104_ram_prog, + .tidy = gk104_ram_tidy, +}; + +int +gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nvkm_gpio *gpio = nvkm_gpio(pfb); + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvkm_gpio *gpio = device->gpio; struct dcb_gpio_func func; struct gk104_ram *ram; int ret, i; - u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb)); + u8 ramcfg = nvbios_ramcfg_index(subdev); u32 tmp; - ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram); - *pobject = nv_object(ram); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = gf100_ram_ctor(&gk104_ram_func, fb, 0x022554, &ram->base); if (ret) return ret; INIT_LIST_HEAD(&ram->cfg); - switch (ram->base.type) { - case NV_MEM_TYPE_DDR3: - case NV_MEM_TYPE_GDDR5: - ram->base.calc = gk104_ram_calc; - ram->base.prog = gk104_ram_prog; - ram->base.tidy = gk104_ram_tidy; - break; - default: - nv_warn(pfb, "reclocking of this RAM type is unsupported\n"); - break; - } - /* calculate a mask of differently configured memory partitions, * because, of course reclocking wasn't complicated enough * already without having to treat some of them differently to * the others.... */ - ram->parts = nv_rd32(pfb, 0x022438); - ram->pmask = nv_rd32(pfb, 0x022554); + ram->parts = nvkm_rd32(device, 0x022438); + ram->pmask = nvkm_rd32(device, 0x022554); ram->pnuts = 0; for (i = 0, tmp = 0; i < ram->parts; i++) { if (!(ram->pmask & (1 << i))) { - u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000)); + u32 cfg1 = nvkm_rd32(device, 0x110204 + (i * 0x1000)); if (tmp && tmp != cfg1) { ram->pnuts |= (1 << i); continue; @@ -1505,7 +1583,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (i = 0; !ret; i++) { ret = gk104_ram_ctor_data(ram, ramcfg, i); if (ret && ret != -ENOENT) { - nv_error(pfb, "failed to parse ramcfg data\n"); + nvkm_error(subdev, "failed to parse ramcfg data\n"); return ret; } } @@ -1513,25 +1591,25 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* parse bios data for both pll's */ ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); if (ret) { - nv_error(pfb, "mclk refpll data not found\n"); + nvkm_error(subdev, "mclk refpll data not found\n"); return ret; } ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll); if (ret) { - nv_error(pfb, "mclk pll data not found\n"); + nvkm_error(subdev, "mclk pll data not found\n"); return ret; } /* lookup memory voltage gpios */ - ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func); + ret = nvkm_gpio_find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func); if (ret == 0) { ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04)); ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12; ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12; } - ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); + ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); if (ret == 0) { ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04)); ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12; @@ -1588,7 +1666,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914); switch (ram->base.type) { - case NV_MEM_TYPE_GDDR5: + case NVKM_RAM_TYPE_GDDR5: ram->fuc.r_mr[0] = ramfuc_reg(0x10f300); ram->fuc.r_mr[1] = ramfuc_reg(0x10f330); ram->fuc.r_mr[2] = ramfuc_reg(0x10f334); @@ -1600,8 +1678,9 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_mr[8] = ramfuc_reg(0x10f354); ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c); break; - case NV_MEM_TYPE_DDR3: + case NVKM_RAM_TYPE_DDR3: ram->fuc.r_mr[0] = ramfuc_reg(0x10f300); + ram->fuc.r_mr[1] = ramfuc_reg(0x10f304); ram->fuc.r_mr[2] = ramfuc_reg(0x10f320); break; default: @@ -1626,14 +1705,3 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_0x100750 = ramfuc_reg(0x100750); return 0; } - -struct nvkm_oclass -gk104_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ram_ctor, - .dtor = gk104_ram_dtor, - .init = gk104_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c index a298b39f5..43d807f6c 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c @@ -21,35 +21,20 @@ * * Authors: Ben Skeggs */ -#include "gf100.h" +#include "ram.h" -struct gm107_ram { - struct nvkm_ram base; +static const struct nvkm_ram_func +gm107_ram_func = { + .init = gk104_ram_init, + .get = gf100_ram_get, + .put = gf100_ram_put, }; -static int -gm107_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct gm107_ram *ram; - int ret; + if (!(*pram = kzalloc(sizeof(**pram), GFP_KERNEL))) + return -ENOMEM; - ret = gf100_ram_create(parent, engine, oclass, 0x021c14, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - - return 0; + return gf100_ram_ctor(&gm107_ram_func, fb, 0x021c14, *pram); } - -struct nvkm_oclass -gm107_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = gk104_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 24176401b..d15ea886d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -22,11 +22,10 @@ * Authors: Ben Skeggs * Roy Spliet <rspliet@eclipso.eu> */ - +#define gt215_ram(p) container_of((p), struct gt215_ram, base) +#include "ram.h" #include "ramfuc.h" -#include "nv50.h" -#include <core/device.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/M0205.h> @@ -35,9 +34,6 @@ #include <subdev/clk/gt215.h> #include <subdev/gpio.h> -/* XXX: Remove when memx gains GPIO support */ -extern int nv50_gpio_location(int line, u32 *reg, u32 *shift); - struct gt215_ramfuc { struct ramfuc base; struct ramfuc_reg r_0x001610; @@ -76,7 +72,7 @@ struct gt215_ramfuc { struct ramfuc_reg r_0x111400; struct ramfuc_reg r_0x611200; struct ramfuc_reg r_mr[4]; - struct ramfuc_reg r_gpioFBVREF; + struct ramfuc_reg r_gpio[4]; }; struct gt215_ltrain { @@ -154,14 +150,14 @@ gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) * Link training for (at least) DDR3 */ int -gt215_link_train(struct nvkm_fb *pfb) +gt215_link_train(struct gt215_ram *ram) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gt215_ram *ram = (void *)pfb->ram; - struct nvkm_clk *clk = nvkm_clk(pfb); struct gt215_ltrain *train = &ram->ltrain; - struct nvkm_device *device = nv_device(pfb); struct gt215_ramfuc *fuc = &ram->fuc; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvkm_clk *clk = device->clk; u32 *result, r1700; int ret, i; struct nvbios_M0205T M0205T = { 0 }; @@ -182,27 +178,29 @@ gt215_link_train(struct nvkm_fb *pfb) /* Clock speeds for training and back */ nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T); - if (M0205T.freq == 0) + if (M0205T.freq == 0) { + kfree(result); return -ENOENT; + } - clk_current = clk->read(clk, nv_clk_src_mem); + clk_current = nvkm_clk_read(clk, nv_clk_src_mem); ret = gt215_clk_pre(clk, f); if (ret) goto out; /* First: clock up/down */ - ret = ram->base.calc(pfb, (u32) M0205T.freq * 1000); + ret = ram->base.func->calc(&ram->base, (u32) M0205T.freq * 1000); if (ret) goto out; /* Do this *after* calc, eliminates write in script */ - nv_wr32(pfb, 0x111400, 0x00000000); + nvkm_wr32(device, 0x111400, 0x00000000); /* XXX: Magic writes that improve train reliability? */ - nv_mask(pfb, 0x100674, 0x0000ffff, 0x00000000); - nv_mask(pfb, 0x1005e4, 0x0000ffff, 0x00000000); - nv_mask(pfb, 0x100b0c, 0x000000ff, 0x00000000); - nv_wr32(pfb, 0x100c04, 0x00000400); + nvkm_mask(device, 0x100674, 0x0000ffff, 0x00000000); + nvkm_mask(device, 0x1005e4, 0x0000ffff, 0x00000000); + nvkm_mask(device, 0x100b0c, 0x000000ff, 0x00000000); + nvkm_wr32(device, 0x100c04, 0x00000400); /* Now the training script */ r1700 = ram_rd32(fuc, 0x001700); @@ -235,22 +233,22 @@ gt215_link_train(struct nvkm_fb *pfb) ram_exec(fuc, true); - ram->base.calc(pfb, clk_current); + ram->base.func->calc(&ram->base, clk_current); ram_exec(fuc, true); /* Post-processing, avoids flicker */ - nv_mask(pfb, 0x616308, 0x10, 0x10); - nv_mask(pfb, 0x616b08, 0x10, 0x10); + nvkm_mask(device, 0x616308, 0x10, 0x10); + nvkm_mask(device, 0x616b08, 0x10, 0x10); gt215_clk_post(clk, f); - ram_train_result(pfb, result, 64); + ram_train_result(ram->base.fb, result, 64); for (i = 0; i < 64; i++) - nv_debug(pfb, "Train: %08x", result[i]); + nvkm_debug(subdev, "Train: %08x", result[i]); gt215_link_train_calc(result, train); - nv_debug(pfb, "Train: %08x %08x %08x", train->r_100720, - train->r_1111e0, train->r_111400); + nvkm_debug(subdev, "Train: %08x %08x %08x", train->r_100720, + train->r_1111e0, train->r_111400); kfree(result); @@ -265,11 +263,12 @@ out: train->state = NVA3_TRAIN_UNSUPPORTED; gt215_clk_post(clk, f); + kfree(result); return ret; } int -gt215_link_train_init(struct nvkm_fb *pfb) +gt215_link_train_init(struct gt215_ram *ram) { static const u32 pattern[16] = { 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, @@ -277,9 +276,9 @@ gt215_link_train_init(struct nvkm_fb *pfb) 0x33333333, 0x55555555, 0x77777777, 0x66666666, 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, }; - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gt215_ram *ram = (void *)pfb->ram; struct gt215_ltrain *train = &ram->ltrain; + struct nvkm_device *device = ram->base.fb->subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_mem *mem; struct nvbios_M0205E M0205E; u8 ver, hdr, cnt, len; @@ -298,48 +297,47 @@ gt215_link_train_init(struct nvkm_fb *pfb) train->state = NVA3_TRAIN_ONCE; - ret = pfb->ram->get(pfb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem); + ret = ram->base.func->get(&ram->base, 0x8000, 0x10000, 0, 0x800, + &ram->ltrain.mem); if (ret) return ret; mem = ram->ltrain.mem; - nv_wr32(pfb, 0x100538, 0x10000000 | (mem->offset >> 16)); - nv_wr32(pfb, 0x1005a8, 0x0000ffff); - nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x100538, 0x10000000 | (mem->offset >> 16)); + nvkm_wr32(device, 0x1005a8, 0x0000ffff); + nvkm_mask(device, 0x10f800, 0x00000001, 0x00000001); for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f8c0, (i << 8) | i); - nv_wr32(pfb, 0x10f900, pattern[i % 16]); + nvkm_wr32(device, 0x10f8c0, (i << 8) | i); + nvkm_wr32(device, 0x10f900, pattern[i % 16]); } for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f8e0, (i << 8) | i); - nv_wr32(pfb, 0x10f920, pattern[i % 16]); + nvkm_wr32(device, 0x10f8e0, (i << 8) | i); + nvkm_wr32(device, 0x10f920, pattern[i % 16]); } /* And upload the pattern */ - r001700 = nv_rd32(pfb, 0x1700); - nv_wr32(pfb, 0x1700, mem->offset >> 16); + r001700 = nvkm_rd32(device, 0x1700); + nvkm_wr32(device, 0x1700, mem->offset >> 16); for (i = 0; i < 16; i++) - nv_wr32(pfb, 0x700000 + (i << 2), pattern[i]); + nvkm_wr32(device, 0x700000 + (i << 2), pattern[i]); for (i = 0; i < 16; i++) - nv_wr32(pfb, 0x700100 + (i << 2), pattern[i]); - nv_wr32(pfb, 0x1700, r001700); + nvkm_wr32(device, 0x700100 + (i << 2), pattern[i]); + nvkm_wr32(device, 0x1700, r001700); - train->r_100720 = nv_rd32(pfb, 0x100720); - train->r_1111e0 = nv_rd32(pfb, 0x1111e0); - train->r_111400 = nv_rd32(pfb, 0x111400); + train->r_100720 = nvkm_rd32(device, 0x100720); + train->r_1111e0 = nvkm_rd32(device, 0x1111e0); + train->r_111400 = nvkm_rd32(device, 0x111400); return 0; } void -gt215_link_train_fini(struct nvkm_fb *pfb) +gt215_link_train_fini(struct gt215_ram *ram) { - struct gt215_ram *ram = (void *)pfb->ram; - if (ram->ltrain.mem) - pfb->ram->put(pfb, &ram->ltrain.mem); + ram->base.func->put(&ram->base, &ram->ltrain.mem); } /* @@ -347,24 +345,25 @@ gt215_link_train_fini(struct nvkm_fb *pfb) */ #define T(t) cfg->timing_10_##t static int -gt215_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) +gt215_ram_timing_calc(struct gt215_ram *ram, u32 *timing) { - struct gt215_ram *ram = (void *)pfb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; int tUNK_base, tUNK_40_0, prevCL; u32 cur2, cur3, cur7, cur8; - cur2 = nv_rd32(pfb, 0x100228); - cur3 = nv_rd32(pfb, 0x10022c); - cur7 = nv_rd32(pfb, 0x10023c); - cur8 = nv_rd32(pfb, 0x100240); + cur2 = nvkm_rd32(device, 0x100228); + cur3 = nvkm_rd32(device, 0x10022c); + cur7 = nvkm_rd32(device, 0x10023c); + cur8 = nvkm_rd32(device, 0x100240); switch ((!T(CWL)) * ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: T(CWL) = T(CL) - 1; break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: T(CWL) = ((cur2 & 0xff000000) >> 24) + 1; break; } @@ -402,8 +401,8 @@ gt215_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) timing[8] = cur8 & 0xffffff00; switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_DDR2: + case NVKM_RAM_TYPE_GDDR3: tUNK_40_0 = prevCL - (cur8 & 0xff); if (tUNK_40_0 > 0) timing[8] |= T(CL); @@ -412,11 +411,11 @@ gt215_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) break; } - nv_debug(pfb, "Entry: 220: %08x %08x %08x %08x\n", - timing[0], timing[1], timing[2], timing[3]); - nv_debug(pfb, " 230: %08x %08x %08x %08x\n", - timing[4], timing[5], timing[6], timing[7]); - nv_debug(pfb, " 240: %08x\n", timing[8]); + nvkm_debug(subdev, "Entry: 220: %08x %08x %08x %08x\n", + timing[0], timing[1], timing[2], timing[3]); + nvkm_debug(subdev, " 230: %08x %08x %08x %08x\n", + timing[4], timing[5], timing[6], timing[7]); + nvkm_debug(subdev, " 240: %08x\n", timing[8]); return 0; } #undef T @@ -464,36 +463,42 @@ gt215_ram_lock_pll(struct gt215_ramfuc *fuc, struct gt215_clk_info *mclk) } static void -gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val) +gt215_ram_gpio(struct gt215_ramfuc *fuc, u8 tag, u32 val) { - struct nvkm_gpio *gpio = nvkm_gpio(fuc->base.pfb); + struct nvkm_gpio *gpio = fuc->base.fb->subdev.device->gpio; struct dcb_gpio_func func; u32 reg, sh, gpio_val; int ret; - if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) { - ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); + if (nvkm_gpio_get(gpio, 0, tag, DCB_GPIO_UNUSED) != val) { + ret = nvkm_gpio_find(gpio, 0, tag, DCB_GPIO_UNUSED, &func); if (ret) return; - nv50_gpio_location(func.line, ®, &sh); - gpio_val = ram_rd32(fuc, gpioFBVREF); + reg = func.line >> 3; + sh = (func.line & 0x7) << 2; + gpio_val = ram_rd32(fuc, gpio[reg]); if (gpio_val & (8 << sh)) val = !val; + if (!(func.log[1] & 1)) + val = !val; - ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh)); + ram_mask(fuc, gpio[reg], (0x3 << sh), ((val | 0x2) << sh)); ram_nsec(fuc, 20000); } } static int -gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) +gt215_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gt215_ram *ram = (void *)pfb->ram; + struct gt215_ram *ram = gt215_ram(base); struct gt215_ramfuc *fuc = &ram->fuc; struct gt215_ltrain *train = &ram->ltrain; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct gt215_clk_info mclk; + struct nvkm_gpio *gpio = device->gpio; struct nvkm_ram_data *next; u8 ver, hdr, cnt, len, strap; u32 data; @@ -508,28 +513,27 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram->base.next = next; if (ram->ltrain.state == NVA3_TRAIN_ONCE) - gt215_link_train(pfb); + gt215_link_train(ram); /* lookup memory config data relevant to the target frequency */ - i = 0; data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x05) { - nv_error(pfb, "invalid/missing rammap entry\n"); + nvkm_error(subdev, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(pfb)); + strap = nvbios_ramcfg_index(subdev); if (strap >= cnt) { - nv_error(pfb, "invalid ramcfg strap\n"); + nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; } data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap, &ver, &hdr, &next->bios); if (!data || ver != 0x10 || hdr < 0x09) { - nv_error(pfb, "invalid/missing ramcfg entry\n"); + nvkm_error(subdev, "invalid/missing ramcfg entry\n"); return -EINVAL; } @@ -539,20 +543,20 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x17) { - nv_error(pfb, "invalid/missing timing entry\n"); + nvkm_error(subdev, "invalid/missing timing entry\n"); return -EINVAL; } } - ret = gt215_pll_info(nvkm_clk(pfb), 0x12, 0x4000, freq, &mclk); + ret = gt215_pll_info(device->clk, 0x12, 0x4000, freq, &mclk); if (ret < 0) { - nv_error(pfb, "failed mclk calculation\n"); + nvkm_error(subdev, "failed mclk calculation\n"); return ret; } - gt215_ram_timing_calc(pfb, timing); + gt215_ram_timing_calc(ram, timing); - ret = ram_init(fuc, pfb); + ret = ram_init(fuc, ram->base.fb); if (ret) return ret; @@ -562,13 +566,13 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram->base.mr[2] = ram_rd32(fuc, mr[2]); switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: ret = nvkm_sddr2_calc(&ram->base); break; - case NV_MEM_TYPE_DDR3: + case NVKM_RAM_TYPE_DDR3: ret = nvkm_sddr3_calc(&ram->base); break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: ret = nvkm_gddr3_calc(&ram->base); break; default: @@ -579,7 +583,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) if (ret) return ret; - /* XXX: where the fuck does 750MHz come from? */ + /* XXX: 750MHz seems rather arbitrary */ if (freq <= 750000) { r004018 = 0x10000000; r100760 = 0x22222222; @@ -590,7 +594,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) r100da0 = 0x00000000; } - if (!next->bios.ramcfg_10_DLLoff) + if (!next->bios.ramcfg_DLLoff) r004018 |= 0x00004000; /* pll2pll requires to switch to a safe clock first */ @@ -623,24 +627,24 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_nsec(fuc, 2000); if (!next->bios.ramcfg_10_02_10) { - if (ram->base.type == NV_MEM_TYPE_GDDR3) + if (ram->base.type == NVKM_RAM_TYPE_GDDR3) ram_mask(fuc, 0x111100, 0x04020000, 0x00020000); else ram_mask(fuc, 0x111100, 0x04020000, 0x04020000); } /* If we're disabling the DLL, do it now */ - switch (next->bios.ramcfg_10_DLLoff * ram->base.type) { - case NV_MEM_TYPE_DDR3: + switch (next->bios.ramcfg_DLLoff * ram->base.type) { + case NVKM_RAM_TYPE_DDR3: nvkm_sddr3_dll_disable(fuc, ram->base.mr); break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: nvkm_gddr3_dll_disable(fuc, ram->base.mr); break; } - if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT) - gt215_ram_fbvref(fuc, 0); + if (next->bios.timing_10_ODT) + gt215_ram_gpio(fuc, 0x2e, 1); /* Brace RAM for impact */ ram_wr32(fuc, 0x1002d4, 0x00000001); @@ -650,9 +654,26 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_wr32(fuc, 0x1002dc, 0x00000001); ram_nsec(fuc, 2000); - if (nv_device(pfb)->chipset == 0xa3 && freq <= 500000) + if (device->chipset == 0xa3 && freq <= 500000) ram_mask(fuc, 0x100700, 0x00000006, 0x00000006); + /* Alter FBVDD/Q, apparently must be done with PLL disabled, thus + * set it to bypass */ + if (nvkm_gpio_get(gpio, 0, 0x18, DCB_GPIO_UNUSED) == + next->bios.ramcfg_FBVDDQ) { + data = ram_rd32(fuc, 0x004000) & 0x9; + + if (data == 0x1) + ram_mask(fuc, 0x004000, 0x8, 0x8); + if (data & 0x1) + ram_mask(fuc, 0x004000, 0x1, 0x0); + + gt215_ram_gpio(fuc, 0x18, !next->bios.ramcfg_FBVDDQ); + + if (data & 0x1) + ram_mask(fuc, 0x004000, 0x1, 0x1); + } + /* Fiddle with clocks */ /* There's 4 scenario's * pll->pll: first switch to a 324MHz clock, set up new PLL, switch @@ -708,7 +729,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_mask(fuc, 0x1007e0, 0x22222222, r100760); } - if (nv_device(pfb)->chipset == 0xa3 && freq > 500000) { + if (device->chipset == 0xa3 && freq > 500000) { ram_mask(fuc, 0x100700, 0x00000006, 0x00000000); } @@ -750,39 +771,43 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100; r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000; - if (next->bios.ramcfg_10_02_04) { - switch (ram->base.type) { - case NV_MEM_TYPE_DDR3: - if (nv_device(pfb)->chipset != 0xa8) - r111100 |= 0x00000004; - /* no break */ - case NV_MEM_TYPE_DDR2: - r111100 |= 0x08000000; - break; - default: - break; - } - } else { - switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: - r111100 |= 0x1a800000; + /* NVA8 seems to skip various bits related to ramcfg_10_02_04 */ + if (device->chipset == 0xa8) { + r111100 |= 0x08000000; + if (!next->bios.ramcfg_10_02_04) unk714 |= 0x00000010; - break; - case NV_MEM_TYPE_DDR3: - if (nv_device(pfb)->chipset == 0xa8) { - r111100 |= 0x08000000; - } else { - r111100 &= ~0x00000004; + } else { + if (next->bios.ramcfg_10_02_04) { + switch (ram->base.type) { + case NVKM_RAM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR3: + r111100 &= ~0x00000020; + if (next->bios.ramcfg_10_02_10) + r111100 |= 0x08000004; + else + r111100 |= 0x00000024; + break; + default: + break; + } + } else { + switch (ram->base.type) { + case NVKM_RAM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR3: + r111100 &= ~0x00000024; r111100 |= 0x12800000; + + if (next->bios.ramcfg_10_02_10) + r111100 |= 0x08000000; + unk714 |= 0x00000010; + break; + case NVKM_RAM_TYPE_GDDR3: + r111100 |= 0x30000000; + unk714 |= 0x00000020; + break; + default: + break; } - unk714 |= 0x00000010; - break; - case NV_MEM_TYPE_GDDR3: - r111100 |= 0x30000000; - unk714 |= 0x00000020; - break; - default: - break; } } @@ -806,20 +831,20 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_mask(fuc, 0x100718, 0xffffffff, unk718); ram_mask(fuc, 0x111100, 0xffffffff, r111100); - if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT) - gt215_ram_fbvref(fuc, 1); + if (!next->bios.timing_10_ODT) + gt215_ram_gpio(fuc, 0x2e, 0); /* Reset DLL */ - if (!next->bios.ramcfg_10_DLLoff) + if (!next->bios.ramcfg_DLLoff) nvkm_sddr2_dll_reset(fuc); - if (ram->base.type == NV_MEM_TYPE_GDDR3) { + if (ram->base.type == NVKM_RAM_TYPE_GDDR3) { ram_nsec(fuc, 31000); } else { ram_nsec(fuc, 14000); } - if (ram->base.type == NV_MEM_TYPE_DDR3) { + if (ram->base.type == NVKM_RAM_TYPE_DDR3) { ram_wr32(fuc, 0x100264, 0x1); ram_nsec(fuc, 2000); } @@ -855,24 +880,24 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) } static int -gt215_ram_prog(struct nvkm_fb *pfb) +gt215_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(pfb); - struct gt215_ram *ram = (void *)pfb->ram; + struct gt215_ram *ram = gt215_ram(base); struct gt215_ramfuc *fuc = &ram->fuc; + struct nvkm_device *device = ram->base.fb->subdev.device; bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true); if (exec) { - nv_mask(pfb, 0x001534, 0x2, 0x2); + nvkm_mask(device, 0x001534, 0x2, 0x2); ram_exec(fuc, true); /* Post-processing, avoids flicker */ - nv_mask(pfb, 0x002504, 0x1, 0x0); - nv_mask(pfb, 0x001534, 0x2, 0x0); + nvkm_mask(device, 0x002504, 0x1, 0x0); + nvkm_mask(device, 0x001534, 0x2, 0x0); - nv_mask(pfb, 0x616308, 0x10, 0x10); - nv_mask(pfb, 0x616b08, 0x10, 0x10); + nvkm_mask(device, 0x616308, 0x10, 0x10); + nvkm_mask(device, 0x616b08, 0x10, 0x10); } else { ram_exec(fuc, false); } @@ -880,69 +905,53 @@ gt215_ram_prog(struct nvkm_fb *pfb) } static void -gt215_ram_tidy(struct nvkm_fb *pfb) +gt215_ram_tidy(struct nvkm_ram *base) { - struct gt215_ram *ram = (void *)pfb->ram; - struct gt215_ramfuc *fuc = &ram->fuc; - ram_exec(fuc, false); + struct gt215_ram *ram = gt215_ram(base); + ram_exec(&ram->fuc, false); } static int -gt215_ram_init(struct nvkm_object *object) +gt215_ram_init(struct nvkm_ram *base) { - struct nvkm_fb *pfb = (void *)object->parent; - struct gt215_ram *ram = (void *)object; - int ret; - - ret = nvkm_ram_init(&ram->base); - if (ret) - return ret; - - gt215_link_train_init(pfb); + struct gt215_ram *ram = gt215_ram(base); + gt215_link_train_init(ram); return 0; } -static int -gt215_ram_fini(struct nvkm_object *object, bool suspend) +static void * +gt215_ram_dtor(struct nvkm_ram *base) { - struct nvkm_fb *pfb = (void *)object->parent; - - if (!suspend) - gt215_link_train_fini(pfb); - - return 0; + struct gt215_ram *ram = gt215_ram(base); + gt215_link_train_fini(ram); + return ram; } -static int -gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 datasize, - struct nvkm_object **pobject) +static const struct nvkm_ram_func +gt215_ram_func = { + .dtor = gt215_ram_dtor, + .init = gt215_ram_init, + .get = nv50_ram_get, + .put = nv50_ram_put, + .calc = gt215_ram_calc, + .prog = gt215_ram_prog, + .tidy = gt215_ram_tidy, +}; + +int +gt215_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_gpio *gpio = nvkm_gpio(pfb); - struct dcb_gpio_func func; struct gt215_ram *ram; int ret, i; - u32 reg, shift; - ret = nv50_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = nv50_ram_ctor(>215_ram_func, fb, &ram->base); if (ret) return ret; - switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: - case NV_MEM_TYPE_DDR3: - case NV_MEM_TYPE_GDDR3: - ram->base.calc = gt215_ram_calc; - ram->base.prog = gt215_ram_prog; - ram->base.tidy = gt215_ram_tidy; - break; - default: - nv_warn(ram, "reclocking of this ram type unsupported\n"); - return 0; - } - ram->fuc.r_0x001610 = ramfuc_reg(0x001610); ram->fuc.r_0x001700 = ramfuc_reg(0x001700); ram->fuc.r_0x002504 = ramfuc_reg(0x002504); @@ -991,22 +1000,10 @@ gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0); ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4); } - - ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); - if (ret == 0) { - nv50_gpio_location(func.line, ®, &shift); - ram->fuc.r_gpioFBVREF = ramfuc_reg(reg); - } + ram->fuc.r_gpio[0] = ramfuc_reg(0x00e104); + ram->fuc.r_gpio[1] = ramfuc_reg(0x00e108); + ram->fuc.r_gpio[2] = ramfuc_reg(0x00e120); + ram->fuc.r_gpio[3] = ramfuc_reg(0x00e124); return 0; } - -struct nvkm_oclass -gt215_ram_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = gt215_ram_init, - .fini = gt215_ram_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c index abc18e89a..0a0e44b75 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c @@ -21,81 +21,67 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#define mcp77_ram(p) container_of((p), struct mcp77_ram, base) +#include "ram.h" -struct mcp77_ram_priv { +struct mcp77_ram { struct nvkm_ram base; u64 poller_base; }; static int -mcp77_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 datasize, - struct nvkm_object **pobject) +mcp77_ram_init(struct nvkm_ram *base) { - u32 rsvd_head = ( 256 * 1024); /* vga memory */ - u32 rsvd_tail = (1024 * 1024); /* vbios etc */ - struct nvkm_fb *pfb = nvkm_fb(parent); - struct mcp77_ram_priv *priv; - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.type = NV_MEM_TYPE_STOLEN; - priv->base.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12; - priv->base.size = (u64)nv_rd32(pfb, 0x100e14) << 12; + struct mcp77_ram *ram = mcp77_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + u32 dniso = ((ram->base.size - (ram->poller_base + 0x00)) >> 5) - 1; + u32 hostnb = ((ram->base.size - (ram->poller_base + 0x20)) >> 5) - 1; + u32 flush = ((ram->base.size - (ram->poller_base + 0x40)) >> 5) - 1; - rsvd_tail += 0x1000; - priv->poller_base = priv->base.size - rsvd_tail; - - ret = nvkm_mm_init(&pfb->vram, rsvd_head >> 12, - (priv->base.size - (rsvd_head + rsvd_tail)) >> 12, - 1); - if (ret) - return ret; - - priv->base.get = nv50_ram_get; - priv->base.put = nv50_ram_put; + /* Enable NISO poller for various clients and set their associated + * read address, only for MCP77/78 and MCP79/7A. (fd#25701) + */ + nvkm_wr32(device, 0x100c18, dniso); + nvkm_mask(device, 0x100c14, 0x00000000, 0x00000001); + nvkm_wr32(device, 0x100c1c, hostnb); + nvkm_mask(device, 0x100c14, 0x00000000, 0x00000002); + nvkm_wr32(device, 0x100c24, flush); + nvkm_mask(device, 0x100c14, 0x00000000, 0x00010000); return 0; } -static int -mcp77_ram_init(struct nvkm_object *object) +static const struct nvkm_ram_func +mcp77_ram_func = { + .init = mcp77_ram_init, + .get = nv50_ram_get, + .put = nv50_ram_put, +}; + +int +mcp77_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(object); - struct mcp77_ram_priv *priv = (void *)object; + struct nvkm_device *device = fb->subdev.device; + u32 rsvd_head = ( 256 * 1024); /* vga memory */ + u32 rsvd_tail = (1024 * 1024) + 0x1000; /* vbios etc + poller mem */ + u64 base = (u64)nvkm_rd32(device, 0x100e10) << 12; + u64 size = (u64)nvkm_rd32(device, 0x100e14) << 12; + struct mcp77_ram *ram; int ret; - u64 dniso, hostnb, flush; - ret = nvkm_ram_init(&priv->base); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = nvkm_ram_ctor(&mcp77_ram_func, fb, NVKM_RAM_TYPE_STOLEN, + size, 0, &ram->base); if (ret) return ret; - dniso = ((priv->base.size - (priv->poller_base + 0x00)) >> 5) - 1; - hostnb = ((priv->base.size - (priv->poller_base + 0x20)) >> 5) - 1; - flush = ((priv->base.size - (priv->poller_base + 0x40)) >> 5) - 1; + ram->poller_base = size - rsvd_tail; + ram->base.stolen = base; + nvkm_mm_fini(&ram->base.vram); - /* Enable NISO poller for various clients and set their associated - * read address, only for MCP77/78 and MCP79/7A. (fd#25701) - */ - nv_wr32(pfb, 0x100c18, dniso); - nv_mask(pfb, 0x100c14, 0x00000000, 0x00000001); - nv_wr32(pfb, 0x100c1c, hostnb); - nv_mask(pfb, 0x100c14, 0x00000000, 0x00000002); - nv_wr32(pfb, 0x100c24, flush); - nv_mask(pfb, 0x100c14, 0x00000000, 0x00010000); - return 0; + return nvkm_mm_init(&ram->base.vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + (size - rsvd_head - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); } - -struct nvkm_oclass -mcp77_ram_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = mcp77_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = mcp77_ram_init, - .fini = _nvkm_ram_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c index 855de1617..6f053a03d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c @@ -21,59 +21,45 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" #include "regsnv04.h" -static int -nv04_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ram *ram; - u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0); - int ret; +const struct nvkm_ram_func +nv04_ram_func = { +}; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; +int +nv04_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) +{ + struct nvkm_device *device = fb->subdev.device; + u32 boot0 = nvkm_rd32(device, NV04_PFB_BOOT_0); + u64 size; + enum nvkm_ram_type type; if (boot0 & 0x00000100) { - ram->size = ((boot0 >> 12) & 0xf) * 2 + 2; - ram->size *= 1024 * 1024; + size = ((boot0 >> 12) & 0xf) * 2 + 2; + size *= 1024 * 1024; } else { switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: - ram->size = 32 * 1024 * 1024; + size = 32 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: - ram->size = 16 * 1024 * 1024; + size = 16 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: - ram->size = 8 * 1024 * 1024; + size = 8 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: - ram->size = 4 * 1024 * 1024; + size = 4 * 1024 * 1024; break; } } if ((boot0 & 0x00000038) <= 0x10) - ram->type = NV_MEM_TYPE_SGRAM; + type = NVKM_RAM_TYPE_SGRAM; else - ram->type = NV_MEM_TYPE_SDRAM; + type = NVKM_RAM_TYPE_SDRAM; - return 0; + return nvkm_ram_new_(&nv04_ram_func, fb, type, size, 0, pram); } - -struct nvkm_oclass -nv04_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c index 3b8a1eda5..dfd155c98 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c @@ -21,39 +21,20 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -static int -nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv10_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ram *ram; - u32 cfg0 = nv_rd32(pfb, 0x100200); - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; + struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 cfg0 = nvkm_rd32(device, 0x100200); + enum nvkm_ram_type type; if (cfg0 & 0x00000001) - ram->type = NV_MEM_TYPE_DDR1; + type = NVKM_RAM_TYPE_DDR1; else - ram->type = NV_MEM_TYPE_SDRAM; + type = NVKM_RAM_TYPE_SDRAM; - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; - return 0; + return nvkm_ram_new_(&nv04_ram_func, fb, type, size, 0, pram); } - -struct nvkm_oclass -nv10_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c index fbae05db4..3c6a8710e 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c @@ -21,33 +21,21 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -#include <core/device.h> - -static int -nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv1a_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ram *ram; struct pci_dev *bridge; u32 mem, mib; - int ret; bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); if (!bridge) { - nv_fatal(pfb, "no bridge device\n"); + nvkm_error(&fb->subdev, "no bridge device\n"); return -ENODEV; } - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - - if (nv_device(pfb)->chipset == 0x1a) { + if (fb->subdev.device->chipset == 0x1a) { pci_read_config_dword(bridge, 0x7c, &mem); mib = ((mem >> 6) & 31) + 1; } else { @@ -55,18 +43,6 @@ nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, mib = ((mem >> 4) & 127) + 1; } - ram->type = NV_MEM_TYPE_STOLEN; - ram->size = mib * 1024 * 1024; - return 0; + return nvkm_ram_new_(&nv04_ram_func, fb, NVKM_RAM_TYPE_STOLEN, + mib * 1024 * 1024, 0, pram); } - -struct nvkm_oclass -nv1a_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv1a_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c index d9e7187bd..747e47c10 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c @@ -21,42 +21,29 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -static int -nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv20_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ram *ram; - u32 pbus1218 = nv_rd32(pfb, 0x001218); + struct nvkm_device *device = fb->subdev.device; + u32 pbus1218 = nvkm_rd32(device, 0x001218); + u32 size = (nvkm_rd32(device, 0x10020c) & 0xff000000); + u32 tags = nvkm_rd32(device, 0x100320); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + switch (pbus1218 & 0x00000300) { + case 0x00000000: type = NVKM_RAM_TYPE_SDRAM; break; + case 0x00000100: type = NVKM_RAM_TYPE_DDR1 ; break; + case 0x00000200: type = NVKM_RAM_TYPE_GDDR3; break; + case 0x00000300: type = NVKM_RAM_TYPE_GDDR2; break; + } + + ret = nvkm_ram_new_(&nv04_ram_func, fb, type, size, tags, pram); if (ret) return ret; - switch (pbus1218 & 0x00000300) { - case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break; - } - ram->size = (nv_rd32(pfb, 0x10020c) & 0xff000000); - ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->tags = nv_rd32(pfb, 0x100320); + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - -struct nvkm_oclass -nv20_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv20_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index 3d31fa45c..56f8cffc2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -21,9 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" -#include <core/device.h> #include <subdev/bios.h> #include <subdev/bios/bit.h> #include <subdev/bios/init.h> @@ -31,23 +30,23 @@ #include <subdev/clk/pll.h> #include <subdev/timer.h> -int -nv40_ram_calc(struct nvkm_fb *pfb, u32 freq) +static int +nv40_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nv40_ram *ram = (void *)pfb->ram; + struct nv40_ram *ram = nv40_ram(base); + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pll pll; int N1, M1, N2, M2; int log2P, ret; ret = nvbios_pll_parse(bios, 0x04, &pll); if (ret) { - nv_error(pfb, "mclk pll data not found\n"); + nvkm_error(subdev, "mclk pll data not found\n"); return ret; } - ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq, - &N1, &M1, &N2, &M2, &log2P); + ret = nv04_pll_calc(subdev, &pll, freq, &N1, &M1, &N2, &M2, &log2P); if (ret < 0) return ret; @@ -64,11 +63,13 @@ nv40_ram_calc(struct nvkm_fb *pfb, u32 freq) return 0; } -int -nv40_ram_prog(struct nvkm_fb *pfb) +static int +nv40_ram_prog(struct nvkm_ram *base) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nv40_ram *ram = (void *)pfb->ram; + struct nv40_ram *ram = nv40_ram(base); + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct bit_entry M; u32 crtc_mask = 0; u8 sr1[2]; @@ -76,12 +77,12 @@ nv40_ram_prog(struct nvkm_fb *pfb) /* determine which CRTCs are active, fetch VGA_SR1 for each */ for (i = 0; i < 2; i++) { - u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000)); + u32 vbl = nvkm_rd32(device, 0x600808 + (i * 0x2000)); u32 cnt = 0; do { - if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) { - nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); - sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000)); + if (vbl != nvkm_rd32(device, 0x600808 + (i * 0x2000))) { + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); + sr1[i] = nvkm_rd08(device, 0x0c03c5 + (i * 0x2000)); if (!(sr1[i] & 0x20)) crtc_mask |= (1 << i); break; @@ -94,55 +95,66 @@ nv40_ram_prog(struct nvkm_fb *pfb) for (i = 0; i < 2; i++) { if (!(crtc_mask & (1 << i))) continue; - nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); - nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); + + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000)); + if (!(tmp & 0x00010000)) + break; + ); + + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000)); + if ( (tmp & 0x00010000)) + break; + ); + + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); + nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); } /* prepare ram for reclocking */ - nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */ - nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */ - nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */ - nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ - nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */ + nvkm_wr32(device, 0x1002d4, 0x00000001); /* precharge */ + nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */ + nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */ + nvkm_mask(device, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ + nvkm_wr32(device, 0x1002dc, 0x00000001); /* enable self-refresh */ /* change the PLL of each memory partition */ - nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000); - switch (nv_device(pfb)->chipset) { + nvkm_mask(device, 0x00c040, 0x0000c000, 0x00000000); + switch (device->chipset) { case 0x40: case 0x45: case 0x41: case 0x42: case 0x47: - nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl); - nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl); - nv_wr32(pfb, 0x004048, ram->coef); - nv_wr32(pfb, 0x004030, ram->coef); + nvkm_mask(device, 0x004044, 0xc0771100, ram->ctrl); + nvkm_mask(device, 0x00402c, 0xc0771100, ram->ctrl); + nvkm_wr32(device, 0x004048, ram->coef); + nvkm_wr32(device, 0x004030, ram->coef); case 0x43: case 0x49: case 0x4b: - nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl); - nv_wr32(pfb, 0x00403c, ram->coef); + nvkm_mask(device, 0x004038, 0xc0771100, ram->ctrl); + nvkm_wr32(device, 0x00403c, ram->coef); default: - nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl); - nv_wr32(pfb, 0x004024, ram->coef); + nvkm_mask(device, 0x004020, 0xc0771100, ram->ctrl); + nvkm_wr32(device, 0x004024, ram->coef); break; } udelay(100); - nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000); + nvkm_mask(device, 0x00c040, 0x0000c000, 0x0000c000); /* re-enable normal operation of memory controller */ - nv_wr32(pfb, 0x1002dc, 0x00000000); - nv_mask(pfb, 0x100210, 0x80000000, 0x80000000); + nvkm_wr32(device, 0x1002dc, 0x00000000); + nvkm_mask(device, 0x100210, 0x80000000, 0x80000000); udelay(100); /* execute memory reset script from vbios */ if (!bit_entry(bios, 'M', &M)) { struct nvbios_init init = { - .subdev = nv_subdev(pfb), + .subdev = subdev, .bios = bios, - .offset = nv_ro16(bios, M.offset + 0x00), + .offset = nvbios_rd16(bios, M.offset + 0x00), .execute = 1, }; @@ -155,58 +167,64 @@ nv40_ram_prog(struct nvkm_fb *pfb) for (i = 0; i < 2; i++) { if (!(crtc_mask & (1 << i))) continue; - nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]); + + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000)); + if ( (tmp & 0x00010000)) + break; + ); + + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); + nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]); } return 0; } -void -nv40_ram_tidy(struct nvkm_fb *pfb) +static void +nv40_ram_tidy(struct nvkm_ram *base) { } -static int -nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_ram_func +nv40_ram_func = { + .calc = nv40_ram_calc, + .prog = nv40_ram_prog, + .tidy = nv40_ram_tidy, +}; + +int +nv40_ram_new_(struct nvkm_fb *fb, enum nvkm_ram_type type, u64 size, + u32 tags, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); struct nv40_ram *ram; - u32 pbus1218 = nv_rd32(pfb, 0x001218); - int ret; + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + return nvkm_ram_ctor(&nv40_ram_func, fb, type, size, tags, &ram->base); +} - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; +int +nv40_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) +{ + struct nvkm_device *device = fb->subdev.device; + u32 pbus1218 = nvkm_rd32(device, 0x001218); + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 tags = nvkm_rd32(device, 0x100320); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; + int ret; switch (pbus1218 & 0x00000300) { - case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break; + case 0x00000000: type = NVKM_RAM_TYPE_SDRAM; break; + case 0x00000100: type = NVKM_RAM_TYPE_DDR1 ; break; + case 0x00000200: type = NVKM_RAM_TYPE_GDDR3; break; + case 0x00000300: type = NVKM_RAM_TYPE_DDR2 ; break; } - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(pfb, 0x100320); - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; + ret = nv40_ram_new_(fb, type, size, tags, pram); + if (ret) + return ret; + + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - - -struct nvkm_oclass -nv40_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h new file mode 100644 index 000000000..8a0524566 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h @@ -0,0 +1,14 @@ +#ifndef __NV40_FB_RAM_H__ +#define __NV40_FB_RAM_H__ +#define nv40_ram(p) container_of((p), struct nv40_ram, base) +#include "ram.h" + +struct nv40_ram { + struct nvkm_ram base; + u32 ctrl; + u32 coef; +}; + +int nv40_ram_new_(struct nvkm_fb *fb, enum nvkm_ram_type, u64, u32, + struct nvkm_ram **); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c index 33c612b13..114828be2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c @@ -21,46 +21,29 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" -static int -nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv41_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nv40_ram *ram; - u32 pfb474 = nv_rd32(pfb, 0x100474); + struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 tags = nvkm_rd32(device, 0x100320); + u32 fb474 = nvkm_rd32(device, 0x100474); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + if (fb474 & 0x00000004) + type = NVKM_RAM_TYPE_GDDR3; + if (fb474 & 0x00000002) + type = NVKM_RAM_TYPE_DDR2; + if (fb474 & 0x00000001) + type = NVKM_RAM_TYPE_DDR1; + + ret = nv40_ram_new_(fb, type, size, tags, pram); if (ret) return ret; - if (pfb474 & 0x00000004) - ram->base.type = NV_MEM_TYPE_GDDR3; - if (pfb474 & 0x00000002) - ram->base.type = NV_MEM_TYPE_DDR2; - if (pfb474 & 0x00000001) - ram->base.type = NV_MEM_TYPE_DDR1; - - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(pfb, 0x100320); - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - -struct nvkm_oclass -nv41_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv41_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c index f575a7246..bc56fbf1c 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c @@ -21,44 +21,22 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" -static int -nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv44_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nv40_ram *ram; - u32 pfb474 = nv_rd32(pfb, 0x100474); - int ret; + struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 fb474 = nvkm_rd32(device, 0x100474); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; + if (fb474 & 0x00000004) + type = NVKM_RAM_TYPE_GDDR3; + if (fb474 & 0x00000002) + type = NVKM_RAM_TYPE_DDR2; + if (fb474 & 0x00000001) + type = NVKM_RAM_TYPE_DDR1; - if (pfb474 & 0x00000004) - ram->base.type = NV_MEM_TYPE_GDDR3; - if (pfb474 & 0x00000002) - ram->base.type = NV_MEM_TYPE_DDR2; - if (pfb474 & 0x00000001) - ram->base.type = NV_MEM_TYPE_DDR1; - - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; - return 0; + return nv40_ram_new_(fb, type, size, 0, pram); } - -struct nvkm_oclass -nv44_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c index 51b44cdb2..c01f4b102 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c @@ -21,46 +21,29 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" -static int -nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv49_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nv40_ram *ram; - u32 pfb914 = nv_rd32(pfb, 0x100914); + struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 tags = nvkm_rd32(device, 0x100320); + u32 fb914 = nvkm_rd32(device, 0x100914); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - - switch (pfb914 & 0x00000003) { - case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break; - case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break; - case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break; + switch (fb914 & 0x00000003) { + case 0x00000000: type = NVKM_RAM_TYPE_DDR1 ; break; + case 0x00000001: type = NVKM_RAM_TYPE_DDR2 ; break; + case 0x00000002: type = NVKM_RAM_TYPE_GDDR3; break; case 0x00000003: break; } - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(pfb, 0x100320); - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; + ret = nv40_ram_new_(fb, type, size, tags, pram); + if (ret) + return ret; + + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - -struct nvkm_oclass -nv49_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv49_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c index f3ed1c60d..fa3c2e062 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c @@ -21,34 +21,13 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -static int -nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv4e_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ram *ram; - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->type = NV_MEM_TYPE_STOLEN; - return 0; + struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + return nvkm_ram_new_(&nv04_ram_func, fb, NVKM_RAM_TYPE_UNKNOWN, + size, 0, pram); } - -struct nvkm_oclass -nv4e_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv4e_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index d2c81dd63..87bde8ff2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -21,16 +21,19 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#define nv50_ram(p) container_of((p), struct nv50_ram, base) +#include "ram.h" #include "ramseq.h" +#include "nv50.h" -#include <core/device.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/perf.h> #include <subdev/bios/pll.h> +#include <subdev/bios/rammap.h> #include <subdev/bios/timing.h> #include <subdev/clk/pll.h> +#include <subdev/gpio.h> struct nv50_ramseq { struct hwsq base; @@ -38,16 +41,26 @@ struct nv50_ramseq { struct hwsq_reg r_0x004008; struct hwsq_reg r_0x00400c; struct hwsq_reg r_0x00c040; + struct hwsq_reg r_0x100200; struct hwsq_reg r_0x100210; + struct hwsq_reg r_0x10021c; struct hwsq_reg r_0x1002d0; struct hwsq_reg r_0x1002d4; struct hwsq_reg r_0x1002dc; - struct hwsq_reg r_0x100da0[8]; + struct hwsq_reg r_0x10053c; + struct hwsq_reg r_0x1005a0; + struct hwsq_reg r_0x1005a4; + struct hwsq_reg r_0x100710; + struct hwsq_reg r_0x100714; + struct hwsq_reg r_0x100718; + struct hwsq_reg r_0x10071c; + struct hwsq_reg r_0x100da0; struct hwsq_reg r_0x100e20; struct hwsq_reg r_0x100e24; struct hwsq_reg r_0x611200; struct hwsq_reg r_timing[9]; struct hwsq_reg r_mr[4]; + struct hwsq_reg r_gpio[4]; }; struct nv50_ram { @@ -55,71 +68,256 @@ struct nv50_ram { struct nv50_ramseq hwsq; }; -#define QFX5800NVA0 1 +#define T(t) cfg->timing_10_##t +static int +nv50_ram_timing_calc(struct nv50_ram *ram, u32 *timing) +{ + struct nvbios_ramcfg *cfg = &ram->base.target.bios; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; + u32 cur2, cur4, cur7, cur8; + u8 unkt3b; + + cur2 = nvkm_rd32(device, 0x100228); + cur4 = nvkm_rd32(device, 0x100230); + cur7 = nvkm_rd32(device, 0x10023c); + cur8 = nvkm_rd32(device, 0x100240); + + switch ((!T(CWL)) * ram->base.type) { + case NVKM_RAM_TYPE_DDR2: + T(CWL) = T(CL) - 1; + break; + case NVKM_RAM_TYPE_GDDR3: + T(CWL) = ((cur2 & 0xff000000) >> 24) + 1; + break; + } + + /* XXX: N=1 is not proper statistics */ + if (device->chipset == 0xa0) { + unkt3b = 0x19 + ram->base.next->bios.rammap_00_16_40; + timing[6] = (0x2d + T(CL) - T(CWL) + + ram->base.next->bios.rammap_00_16_40) << 16 | + T(CWL) << 8 | + (0x2f + T(CL) - T(CWL)); + } else { + unkt3b = 0x16; + timing[6] = (0x2b + T(CL) - T(CWL)) << 16 | + max_t(s8, T(CWL) - 2, 1) << 8 | + (0x2e + T(CL) - T(CWL)); + } + + timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC)); + timing[1] = (T(WR) + 1 + T(CWL)) << 24 | + max_t(u8, T(18), 1) << 16 | + (T(WTR) + 1 + T(CWL)) << 8 | + (3 + T(CL) - T(CWL)); + timing[2] = (T(CWL) - 1) << 24 | + (T(RRD) << 16) | + (T(RCDWR) << 8) | + T(RCDRD); + timing[3] = (unkt3b - 2 + T(CL)) << 24 | + unkt3b << 16 | + (T(CL) - 1) << 8 | + (T(CL) - 1); + timing[4] = (cur4 & 0xffff0000) | + T(13) << 8 | + T(13); + timing[5] = T(RFC) << 24 | + max_t(u8, T(RCDRD), T(RCDWR)) << 16 | + T(RP); + /* Timing 6 is already done above */ + timing[7] = (cur7 & 0xff00ffff) | (T(CL) - 1) << 16; + timing[8] = (cur8 & 0xffffff00); + + /* XXX: P.version == 1 only has DDR2 and GDDR3? */ + if (ram->base.type == NVKM_RAM_TYPE_DDR2) { + timing[5] |= (T(CL) + 3) << 8; + timing[8] |= (T(CL) - 4); + } else + if (ram->base.type == NVKM_RAM_TYPE_GDDR3) { + timing[5] |= (T(CL) + 2) << 8; + timing[8] |= (T(CL) - 2); + } + + nvkm_debug(subdev, " 220: %08x %08x %08x %08x\n", + timing[0], timing[1], timing[2], timing[3]); + nvkm_debug(subdev, " 230: %08x %08x %08x %08x\n", + timing[4], timing[5], timing[6], timing[7]); + nvkm_debug(subdev, " 240: %08x\n", timing[8]); + return 0; +} + +static int +nv50_ram_timing_read(struct nv50_ram *ram, u32 *timing) +{ + unsigned int i; + struct nvbios_ramcfg *cfg = &ram->base.target.bios; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; + + for (i = 0; i <= 8; i++) + timing[i] = nvkm_rd32(device, 0x100220 + (i * 4)); + + /* Derive the bare minimum for the MR calculation to succeed */ + cfg->timing_ver = 0x10; + T(CL) = (timing[3] & 0xff) + 1; + + switch (ram->base.type) { + case NVKM_RAM_TYPE_DDR2: + T(CWL) = T(CL) - 1; + break; + case NVKM_RAM_TYPE_GDDR3: + T(CWL) = ((timing[2] & 0xff000000) >> 24) + 1; + break; + default: + return -ENOSYS; + break; + } + + T(WR) = ((timing[1] >> 24) & 0xff) - 1 - T(CWL); + + return 0; +} +#undef T + +static void +nvkm_sddr2_dll_reset(struct nv50_ramseq *hwsq) +{ + ram_mask(hwsq, mr[0], 0x100, 0x100); + ram_mask(hwsq, mr[0], 0x100, 0x000); + ram_nsec(hwsq, 24000); +} + +static void +nv50_ram_gpio(struct nv50_ramseq *hwsq, u8 tag, u32 val) +{ + struct nvkm_gpio *gpio = hwsq->base.subdev->device->gpio; + struct dcb_gpio_func func; + u32 reg, sh, gpio_val; + int ret; + + if (nvkm_gpio_get(gpio, 0, tag, DCB_GPIO_UNUSED) != val) { + ret = nvkm_gpio_find(gpio, 0, tag, DCB_GPIO_UNUSED, &func); + if (ret) + return; + + reg = func.line >> 3; + sh = (func.line & 0x7) << 2; + gpio_val = ram_rd32(hwsq, gpio[reg]); + + if (gpio_val & (8 << sh)) + val = !val; + if (!(func.log[1] & 1)) + val = !val; + + ram_mask(hwsq, gpio[reg], (0x3 << sh), ((val | 0x2) << sh)); + ram_nsec(hwsq, 20000); + } +} static int -nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) +nv50_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nv50_ram *ram = (void *)pfb->ram; + struct nv50_ram *ram = nv50_ram(base); struct nv50_ramseq *hwsq = &ram->hwsq; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_perfE perfE; struct nvbios_pll mpll; - struct { - u32 data; - u8 size; - } ramcfg, timing; - u8 ver, hdr, cnt, len, strap; + struct nvkm_ram_data *next; + u8 ver, hdr, cnt, len, strap, size; + u32 data; + u32 r100da0, r004008, unk710, unk714, unk718, unk71c; int N1, M1, N2, M2, P; int ret, i; + u32 timing[9]; + + next = &ram->base.target; + next->freq = freq; + ram->base.next = next; /* lookup closest matching performance table entry for frequency */ i = 0; do { - ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt, - &ramcfg.size, &perfE); - if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) || - (ramcfg.size < 2)) { - nv_error(pfb, "invalid/missing perftab entry\n"); + data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt, + &size, &perfE); + if (!data || (ver < 0x25 || ver >= 0x40) || + (size < 2)) { + nvkm_error(subdev, "invalid/missing perftab entry\n"); return -EINVAL; } } while (perfE.memory < freq); + nvbios_rammapEp_from_perf(bios, data, hdr, &next->bios); + /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(pfb)); + strap = nvbios_ramcfg_index(subdev); if (strap >= cnt) { - nv_error(pfb, "invalid ramcfg strap\n"); + nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; } - ramcfg.data += hdr + (strap * ramcfg.size); + data = nvbios_rammapSp_from_perf(bios, data + hdr, size, strap, + &next->bios); + if (!data) { + nvkm_error(subdev, "invalid/missing rammap entry "); + return -EINVAL; + } /* lookup memory timings, if bios says they're present */ - strap = nv_ro08(bios, ramcfg.data + 0x01); - if (strap != 0xff) { - timing.data = nvbios_timingEe(bios, strap, &ver, &hdr, - &cnt, &len); - if (!timing.data || ver != 0x10 || hdr < 0x12) { - nv_error(pfb, "invalid/missing timing entry " + if (next->bios.ramcfg_timing != 0xff) { + data = nvbios_timingEp(bios, next->bios.ramcfg_timing, + &ver, &hdr, &cnt, &len, &next->bios); + if (!data || ver != 0x10 || hdr < 0x12) { + nvkm_error(subdev, "invalid/missing timing entry " "%02x %04x %02x %02x\n", - strap, timing.data, ver, hdr); + strap, data, ver, hdr); return -EINVAL; } + nv50_ram_timing_calc(ram, timing); } else { - timing.data = 0; + nv50_ram_timing_read(ram, timing); } - ret = ram_init(hwsq, nv_subdev(pfb)); + ret = ram_init(hwsq, subdev); if (ret) return ret; - ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */ - ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */ + /* Determine ram-specific MR values */ + ram->base.mr[0] = ram_rd32(hwsq, mr[0]); + ram->base.mr[1] = ram_rd32(hwsq, mr[1]); + ram->base.mr[2] = ram_rd32(hwsq, mr[2]); + + switch (ram->base.type) { + case NVKM_RAM_TYPE_GDDR3: + ret = nvkm_gddr3_calc(&ram->base); + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) { + nvkm_error(subdev, "Could not calculate MR\n"); + return ret; + } + + if (subdev->device->chipset <= 0x96 && !next->bios.ramcfg_00_03_02) + ram_mask(hwsq, 0x100710, 0x00000200, 0x00000000); + + /* Always disable this bit during reclock */ + ram_mask(hwsq, 0x100200, 0x00000800, 0x00000000); + + ram_wait_vblank(hwsq); ram_wr32(hwsq, 0x611200, 0x00003300); ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */ ram_nsec(hwsq, 8000); ram_setf(hwsq, 0x10, 0x00); /* disable fb */ ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */ + ram_nsec(hwsq, 2000); + + if (next->bios.timing_10_ODT) + nv50_ram_gpio(hwsq, 0x2e, 1); ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */ ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */ @@ -129,97 +327,174 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) ret = nvbios_pll_parse(bios, 0x004008, &mpll); mpll.vco2.max_freq = 0; - if (ret == 0) { - ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq, + if (ret >= 0) { + ret = nv04_pll_calc(subdev, &mpll, freq, &N1, &M1, &N2, &M2, &P); - if (ret == 0) + if (ret <= 0) ret = -EINVAL; } if (ret < 0) return ret; + /* XXX: 750MHz seems rather arbitrary */ + if (freq <= 750000) { + r100da0 = 0x00000010; + r004008 = 0x90000000; + } else { + r100da0 = 0x00000000; + r004008 = 0x80000000; + } + + r004008 |= (mpll.bias_p << 19) | (P << 22) | (P << 16); + ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000); - ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200); + /* XXX: Is rammap_00_16_40 the DLL bit we've seen in GT215? Why does + * it have a different rammap bit from DLLoff? */ + ram_mask(hwsq, 0x004008, 0x00004200, 0x00000200 | + next->bios.rammap_00_16_40 << 14); ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1); - ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) | - (P << 22) | (P << 16)); -#if QFX5800NVA0 - for (i = 0; i < 8; i++) - ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/ -#endif - ram_nsec(hwsq, 96000); /*XXX*/ + ram_mask(hwsq, 0x004008, 0x91ff0000, r004008); + + /* XXX: GDDR3 only? */ + if (subdev->device->chipset >= 0x92) + ram_wr32(hwsq, 0x100da0, r100da0); + + nv50_ram_gpio(hwsq, 0x18, !next->bios.ramcfg_FBVDDQ); + ram_nsec(hwsq, 64000); /*XXX*/ + ram_nsec(hwsq, 32000); /*XXX*/ + ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000); ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */ + ram_wr32(hwsq, 0x1002d4, 0x00000001); /* disable self-refresh */ ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */ ram_nsec(hwsq, 12000); switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: ram_nuke(hwsq, mr[0]); /* force update */ ram_mask(hwsq, mr[0], 0x000, 0x000); break; - case NV_MEM_TYPE_GDDR3: - ram_mask(hwsq, mr[2], 0x000, 0x000); + case NVKM_RAM_TYPE_GDDR3: + ram_nuke(hwsq, mr[1]); /* force update */ + ram_wr32(hwsq, mr[1], ram->base.mr[1]); ram_nuke(hwsq, mr[0]); /* force update */ - ram_mask(hwsq, mr[0], 0x000, 0x000); + ram_wr32(hwsq, mr[0], ram->base.mr[0]); break; default: break; } - ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/ - - ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/ - -#if QFX5800NVA0 - ram_nuke(hwsq, 0x100e24); - ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000); - ram_nuke(hwsq, 0x100e20); - ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000); -#endif + ram_mask(hwsq, timing[3], 0xffffffff, timing[3]); + ram_mask(hwsq, timing[1], 0xffffffff, timing[1]); + ram_mask(hwsq, timing[6], 0xffffffff, timing[6]); + ram_mask(hwsq, timing[7], 0xffffffff, timing[7]); + ram_mask(hwsq, timing[8], 0xffffffff, timing[8]); + ram_mask(hwsq, timing[0], 0xffffffff, timing[0]); + ram_mask(hwsq, timing[2], 0xffffffff, timing[2]); + ram_mask(hwsq, timing[4], 0xffffffff, timing[4]); + ram_mask(hwsq, timing[5], 0xffffffff, timing[5]); + + if (!next->bios.ramcfg_00_03_02) + ram_mask(hwsq, 0x10021c, 0x00010000, 0x00000000); + ram_mask(hwsq, 0x100200, 0x00001000, !next->bios.ramcfg_00_04_02 << 12); + + /* XXX: A lot of this could be "chipset"/"ram type" specific stuff */ + unk710 = ram_rd32(hwsq, 0x100710) & ~0x00000100; + unk714 = ram_rd32(hwsq, 0x100714) & ~0xf0000020; + unk718 = ram_rd32(hwsq, 0x100718) & ~0x00000100; + unk71c = ram_rd32(hwsq, 0x10071c) & ~0x00000100; + if (subdev->device->chipset <= 0x96) { + unk710 &= ~0x0000006e; + unk714 &= ~0x00000100; + + if (!next->bios.ramcfg_00_03_08) + unk710 |= 0x00000060; + if (!next->bios.ramcfg_FBVDDQ) + unk714 |= 0x00000100; + if ( next->bios.ramcfg_00_04_04) + unk710 |= 0x0000000e; + } else { + unk710 &= ~0x00000001; - ram_mask(hwsq, mr[0], 0x100, 0x100); - ram_mask(hwsq, mr[0], 0x100, 0x000); + if (!next->bios.ramcfg_00_03_08) + unk710 |= 0x00000001; + } + + if ( next->bios.ramcfg_00_03_01) + unk71c |= 0x00000100; + if ( next->bios.ramcfg_00_03_02) + unk710 |= 0x00000100; + if (!next->bios.ramcfg_00_03_08) + unk714 |= 0x00000020; + if ( next->bios.ramcfg_00_04_04) + unk714 |= 0x70000000; + if ( next->bios.ramcfg_00_04_20) + unk718 |= 0x00000100; + + ram_mask(hwsq, 0x100714, 0xffffffff, unk714); + ram_mask(hwsq, 0x10071c, 0xffffffff, unk71c); + ram_mask(hwsq, 0x100718, 0xffffffff, unk718); + ram_mask(hwsq, 0x100710, 0xffffffff, unk710); + + /* XXX: G94 does not even test these regs in trace. Harmless we do it, + * but why is it omitted? */ + if (next->bios.rammap_00_16_20) { + ram_wr32(hwsq, 0x1005a0, next->bios.ramcfg_00_07 << 16 | + next->bios.ramcfg_00_06 << 8 | + next->bios.ramcfg_00_05); + ram_wr32(hwsq, 0x1005a4, next->bios.ramcfg_00_09 << 8 | + next->bios.ramcfg_00_08); + ram_mask(hwsq, 0x10053c, 0x00001000, 0x00000000); + } else { + ram_mask(hwsq, 0x10053c, 0x00001000, 0x00001000); + } + ram_mask(hwsq, mr[1], 0xffffffff, ram->base.mr[1]); + + if (!next->bios.timing_10_ODT) + nv50_ram_gpio(hwsq, 0x2e, 0); + + /* Reset DLL */ + if (!next->bios.ramcfg_DLLoff) + nvkm_sddr2_dll_reset(hwsq); ram_setf(hwsq, 0x10, 0x01); /* enable fb */ ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */ ram_wr32(hwsq, 0x611200, 0x00003330); ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */ + + if (next->bios.rammap_00_17_02) + ram_mask(hwsq, 0x100200, 0x00000800, 0x00000800); + if (!next->bios.rammap_00_16_40) + ram_mask(hwsq, 0x004008, 0x00004000, 0x00000000); + if (next->bios.ramcfg_00_03_02) + ram_mask(hwsq, 0x10021c, 0x00010000, 0x00010000); + if (subdev->device->chipset <= 0x96 && next->bios.ramcfg_00_03_02) + ram_mask(hwsq, 0x100710, 0x00000200, 0x00000200); + return 0; } static int -nv50_ram_prog(struct nvkm_fb *pfb) +nv50_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(pfb); - struct nv50_ram *ram = (void *)pfb->ram; - struct nv50_ramseq *hwsq = &ram->hwsq; - - ram_exec(hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); + struct nv50_ram *ram = nv50_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + ram_exec(&ram->hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); return 0; } static void -nv50_ram_tidy(struct nvkm_fb *pfb) +nv50_ram_tidy(struct nvkm_ram *base) { - struct nv50_ram *ram = (void *)pfb->ram; - struct nv50_ramseq *hwsq = &ram->hwsq; - ram_exec(hwsq, false); + struct nv50_ram *ram = nv50_ram(base); + ram_exec(&ram->hwsq, false); } void -__nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem *mem) +__nv50_ram_put(struct nvkm_ram *ram, struct nvkm_mem *mem) { struct nvkm_mm_node *this; @@ -227,14 +502,14 @@ __nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem *mem) this = list_first_entry(&mem->regions, typeof(*this), rl_entry); list_del(&this->rl_entry); - nvkm_mm_free(&pfb->vram, &this); + nvkm_mm_free(&ram->vram, &this); } - nvkm_mm_free(&pfb->tags, &mem->tag); + nvkm_mm_free(&ram->tags, &mem->tag); } void -nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) +nv50_ram_put(struct nvkm_ram *ram, struct nvkm_mem **pmem) { struct nvkm_mem *mem = *pmem; @@ -242,19 +517,19 @@ nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) if (unlikely(mem == NULL)) return; - mutex_lock(&pfb->base.mutex); - __nv50_ram_put(pfb, mem); - mutex_unlock(&pfb->base.mutex); + mutex_lock(&ram->fb->subdev.mutex); + __nv50_ram_put(ram, mem); + mutex_unlock(&ram->fb->subdev.mutex); kfree(mem); } int -nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, +nv50_ram_get(struct nvkm_ram *ram, u64 size, u32 align, u32 ncmin, u32 memtype, struct nvkm_mem **pmem) { - struct nvkm_mm *heap = &pfb->vram; - struct nvkm_mm *tags = &pfb->tags; + struct nvkm_mm *heap = &ram->vram; + struct nvkm_mm *tags = &ram->tags; struct nvkm_mm_node *r; struct nvkm_mem *mem; int comp = (memtype & 0x300) >> 8; @@ -262,17 +537,17 @@ nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, int back = (memtype & 0x800); int min, max, ret; - max = (size >> 12); - min = ncmin ? (ncmin >> 12) : max; - align >>= 12; + max = (size >> NVKM_RAM_MM_SHIFT); + min = ncmin ? (ncmin >> NVKM_RAM_MM_SHIFT) : max; + align >>= NVKM_RAM_MM_SHIFT; mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) return -ENOMEM; - mutex_lock(&pfb->base.mutex); + mutex_lock(&ram->fb->subdev.mutex); if (comp) { - if (align == 16) { + if (align == (1 << (16 - NVKM_RAM_MM_SHIFT))) { int n = (max >> 4) * comp; ret = nvkm_mm_head(tags, 0, 1, n, n, 1, &mem->tag); @@ -295,34 +570,45 @@ nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, else ret = nvkm_mm_head(heap, 0, type, max, min, align, &r); if (ret) { - mutex_unlock(&pfb->base.mutex); - pfb->ram->put(pfb, &mem); + mutex_unlock(&ram->fb->subdev.mutex); + ram->func->put(ram, &mem); return ret; } list_add_tail(&r->rl_entry, &mem->regions); max -= r->length; } while (max); - mutex_unlock(&pfb->base.mutex); + mutex_unlock(&ram->fb->subdev.mutex); r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry); - mem->offset = (u64)r->offset << 12; + mem->offset = (u64)r->offset << NVKM_RAM_MM_SHIFT; *pmem = mem; return 0; } +static const struct nvkm_ram_func +nv50_ram_func = { + .get = nv50_ram_get, + .put = nv50_ram_put, + .calc = nv50_ram_calc, + .prog = nv50_ram_prog, + .tidy = nv50_ram_tidy, +}; + static u32 -nv50_fb_vram_rblock(struct nvkm_fb *pfb, struct nvkm_ram *ram) +nv50_fb_vram_rblock(struct nvkm_ram *ram) { + struct nvkm_subdev *subdev = &ram->fb->subdev; + struct nvkm_device *device = subdev->device; int colbits, rowbitsa, rowbitsb, banks; u64 rowsize, predicted; u32 r0, r4, rt, rblock_size; - r0 = nv_rd32(pfb, 0x100200); - r4 = nv_rd32(pfb, 0x100204); - rt = nv_rd32(pfb, 0x100250); - nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", - r0, r4, rt, nv_rd32(pfb, 0x001540)); + r0 = nvkm_rd32(device, 0x100200); + r4 = nvkm_rd32(device, 0x100204); + rt = nvkm_rd32(device, 0x100250); + nvkm_debug(subdev, "memcfg %08x %08x %08x %08x\n", + r0, r4, rt, nvkm_rd32(device, 0x001540)); colbits = (r4 & 0x0000f000) >> 12; rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; @@ -335,103 +621,94 @@ nv50_fb_vram_rblock(struct nvkm_fb *pfb, struct nvkm_ram *ram) predicted += rowsize << rowbitsb; if (predicted != ram->size) { - nv_warn(pfb, "memory controller reports %d MiB VRAM\n", - (u32)(ram->size >> 20)); + nvkm_warn(subdev, "memory controller reports %d MiB VRAM\n", + (u32)(ram->size >> 20)); } rblock_size = rowsize; if (rt & 1) rblock_size *= 3; - nv_debug(pfb, "rblock %d bytes\n", rblock_size); + nvkm_debug(subdev, "rblock %d bytes\n", rblock_size); return rblock_size; } int -nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nv50_ram_ctor(const struct nvkm_ram_func *func, + struct nvkm_fb *fb, struct nvkm_ram *ram) { - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ram *ram; + struct nvkm_device *device = fb->subdev.device; + struct nvkm_bios *bios = device->bios; + const u32 rsvd_head = ( 256 * 1024); /* vga memory */ + const u32 rsvd_tail = (1024 * 1024); /* vbios etc */ + u64 size = nvkm_rd32(device, 0x10020c); + u32 tags = nvkm_rd32(device, 0x100320); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create_(parent, engine, oclass, length, pobject); - ram = *pobject; - if (ret) - return ret; - - ram->size = nv_rd32(pfb, 0x10020c); - ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); - - ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16; - ram->parts = hweight8(ram->part_mask); - - switch (nv_rd32(pfb, 0x100714) & 0x00000007) { - case 0: ram->type = NV_MEM_TYPE_DDR1; break; + switch (nvkm_rd32(device, 0x100714) & 0x00000007) { + case 0: type = NVKM_RAM_TYPE_DDR1; break; case 1: - if (nvkm_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) - ram->type = NV_MEM_TYPE_DDR3; + if (nvkm_fb_bios_memtype(bios) == NVKM_RAM_TYPE_DDR3) + type = NVKM_RAM_TYPE_DDR3; else - ram->type = NV_MEM_TYPE_DDR2; + type = NVKM_RAM_TYPE_DDR2; break; - case 2: ram->type = NV_MEM_TYPE_GDDR3; break; - case 3: ram->type = NV_MEM_TYPE_GDDR4; break; - case 4: ram->type = NV_MEM_TYPE_GDDR5; break; + case 2: type = NVKM_RAM_TYPE_GDDR3; break; + case 3: type = NVKM_RAM_TYPE_GDDR4; break; + case 4: type = NVKM_RAM_TYPE_GDDR5; break; default: break; } - ret = nvkm_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) - - (rsvd_head + rsvd_tail), - nv50_fb_vram_rblock(pfb, ram) >> 12); + size = (size & 0x000000ff) << 32 | (size & 0xffffff00); + + ret = nvkm_ram_ctor(func, fb, type, size, tags, ram); if (ret) return ret; - ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; - ram->tags = nv_rd32(pfb, 0x100320); - ram->get = nv50_ram_get; - ram->put = nv50_ram_put; - return 0; + ram->part_mask = (nvkm_rd32(device, 0x001540) & 0x00ff0000) >> 16; + ram->parts = hweight8(ram->part_mask); + ram->ranks = (nvkm_rd32(device, 0x100200) & 0x4) ? 2 : 1; + nvkm_mm_fini(&ram->vram); + + return nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + (size - rsvd_head - rsvd_tail) >> NVKM_RAM_MM_SHIFT, + nv50_fb_vram_rblock(ram) >> NVKM_RAM_MM_SHIFT); } -static int -nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 datasize, - struct nvkm_object **pobject) +int +nv50_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { struct nv50_ram *ram; int ret, i; - ret = nv50_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = nv50_ram_ctor(&nv50_ram_func, fb, &ram->base); if (ret) return ret; - switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: - case NV_MEM_TYPE_GDDR3: - ram->base.calc = nv50_ram_calc; - ram->base.prog = nv50_ram_prog; - ram->base.tidy = nv50_ram_tidy; - break; - default: - nv_warn(ram, "reclocking of this ram type unsupported\n"); - return 0; - } - ram->hwsq.r_0x002504 = hwsq_reg(0x002504); ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040); ram->hwsq.r_0x004008 = hwsq_reg(0x004008); ram->hwsq.r_0x00400c = hwsq_reg(0x00400c); + ram->hwsq.r_0x100200 = hwsq_reg(0x100200); ram->hwsq.r_0x100210 = hwsq_reg(0x100210); + ram->hwsq.r_0x10021c = hwsq_reg(0x10021c); ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0); ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4); ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc); - for (i = 0; i < 8; i++) - ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04)); + ram->hwsq.r_0x10053c = hwsq_reg(0x10053c); + ram->hwsq.r_0x1005a0 = hwsq_reg(0x1005a0); + ram->hwsq.r_0x1005a4 = hwsq_reg(0x1005a4); + ram->hwsq.r_0x100710 = hwsq_reg(0x100710); + ram->hwsq.r_0x100714 = hwsq_reg(0x100714); + ram->hwsq.r_0x100718 = hwsq_reg(0x100718); + ram->hwsq.r_0x10071c = hwsq_reg(0x10071c); + ram->hwsq.r_0x100da0 = hwsq_stride(0x100da0, 4, ram->base.part_mask); ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20); ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24); ram->hwsq.r_0x611200 = hwsq_reg(0x611200); @@ -451,15 +728,10 @@ nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4); } + ram->hwsq.r_gpio[0] = hwsq_reg(0x00e104); + ram->hwsq.r_gpio[1] = hwsq_reg(0x00e108); + ram->hwsq.r_gpio[2] = hwsq_reg(0x00e120); + ram->hwsq.r_gpio[3] = hwsq_reg(0x00e124); + return 0; } - -struct nvkm_oclass -nv50_ram_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h index 0f1f97ccd..8df7306d5 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h @@ -11,5 +11,6 @@ #define ram_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d)) #define ram_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d)) #define ram_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d)) +#define ram_wait_vblank(s) hwsq_wait_vblank(&(s)->base) #define ram_nsec(s,n) hwsq_nsec(&(s)->base, (n)) #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c index afab42df2..b9f1ffdfc 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c @@ -65,7 +65,7 @@ nvkm_sddr2_calc(struct nvkm_ram *ram) case 0x10: CL = ram->next->bios.timing_10_CL; WR = ram->next->bios.timing_10_WR; - DLL = !ram->next->bios.ramcfg_10_DLLoff; + DLL = !ram->next->bios.ramcfg_DLLoff; ODT = ram->next->bios.timing_10_ODT & 3; break; case 0x20: @@ -76,6 +76,12 @@ nvkm_sddr2_calc(struct nvkm_ram *ram) return -ENOSYS; } + if (ram->next->bios.timing_ver == 0x20 || + ram->next->bios.ramcfg_timing == 0xff) { + ODT = (ram->mr[1] & 0x004) >> 2 | + (ram->mr[1] & 0x040) >> 5; + } + CL = ramxlat(ramddr2_cl, CL); WR = ramxlat(ramddr2_wr, WR); if (CL < 0 || WR < 0) diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c index 10844355c..26900333b 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c @@ -53,7 +53,7 @@ static const struct ramxlat ramddr3_wr[] = { { 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 }, /* the below are mentioned in some, but not all, ddr3 docs */ - { 14, 7 }, { 16, 0 }, + { 14, 7 }, { 15, 7 }, { 16, 0 }, { -1 } }; @@ -61,7 +61,7 @@ static const struct ramxlat ramddr3_cwl[] = { { 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 }, /* the below are mentioned in some, but not all, ddr3 docs */ - { 9, 4 }, + { 9, 4 }, { 10, 5 }, { -1 } }; @@ -70,6 +70,8 @@ nvkm_sddr3_calc(struct nvkm_ram *ram) { int CWL, CL, WR, DLL = 0, ODT = 0; + DLL = !ram->next->bios.ramcfg_DLLoff; + switch (ram->next->bios.timing_ver) { case 0x10: if (ram->next->bios.timing_hdr < 0x17) { @@ -79,7 +81,6 @@ nvkm_sddr3_calc(struct nvkm_ram *ram) CWL = ram->next->bios.timing_10_CWL; CL = ram->next->bios.timing_10_CL; WR = ram->next->bios.timing_10_WR; - DLL = !ram->next->bios.ramcfg_10_DLLoff; ODT = ram->next->bios.timing_10_ODT; break; case 0x20: @@ -87,7 +88,6 @@ nvkm_sddr3_calc(struct nvkm_ram *ram) CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0; WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16; /* XXX: Get these values from the VBIOS instead */ - DLL = !(ram->mr[1] & 0x1); ODT = (ram->mr[1] & 0x004) >> 2 | (ram->mr[1] & 0x040) >> 5 | (ram->mr[1] & 0x200) >> 7; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c index b7b7193bb..f4144979a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c @@ -21,31 +21,34 @@ * * Authors: Martin Peres */ -#include <subdev/fuse.h> +#include "priv.h" -int -_nvkm_fuse_init(struct nvkm_object *object) +u32 +nvkm_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct nvkm_fuse *fuse = (void *)object; - return nvkm_subdev_init(&fuse->base); + return fuse->func->read(fuse, addr); } -void -_nvkm_fuse_dtor(struct nvkm_object *object) +static void * +nvkm_fuse_dtor(struct nvkm_subdev *subdev) { - struct nvkm_fuse *fuse = (void *)object; - nvkm_subdev_destroy(&fuse->base); + return nvkm_fuse(subdev); } +static const struct nvkm_subdev_func +nvkm_fuse = { + .dtor = nvkm_fuse_dtor, +}; + int -nvkm_fuse_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_fuse_new_(const struct nvkm_fuse_func *func, struct nvkm_device *device, + int index, struct nvkm_fuse **pfuse) { struct nvkm_fuse *fuse; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "FUSE", - "fuse", length, pobject); - fuse = *pobject; - return ret; + if (!(fuse = *pfuse = kzalloc(sizeof(*fuse), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_fuse, device, index, 0, &fuse->subdev); + fuse->func = func; + spin_lock_init(&fuse->lock); + return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c index 393ef3a0f..13671fedc 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c @@ -23,56 +23,31 @@ */ #include "priv.h" -struct gf100_fuse_priv { - struct nvkm_fuse base; - - spinlock_t fuse_enable_lock; -}; - static u32 -gf100_fuse_rd32(struct nvkm_object *object, u64 addr) +gf100_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct gf100_fuse_priv *priv = (void *)object; + struct nvkm_device *device = fuse->subdev.device; unsigned long flags; u32 fuse_enable, unk, val; /* racy if another part of nvkm start writing to these regs */ - spin_lock_irqsave(&priv->fuse_enable_lock, flags); - fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800); - unk = nv_mask(priv, 0x21000, 0x1, 0x1); - val = nv_rd32(priv, 0x21100 + addr); - nv_wr32(priv, 0x21000, unk); - nv_wr32(priv, 0x22400, fuse_enable); - spin_unlock_irqrestore(&priv->fuse_enable_lock, flags); + spin_lock_irqsave(&fuse->lock, flags); + fuse_enable = nvkm_mask(device, 0x022400, 0x800, 0x800); + unk = nvkm_mask(device, 0x021000, 0x1, 0x1); + val = nvkm_rd32(device, 0x021100 + addr); + nvkm_wr32(device, 0x021000, unk); + nvkm_wr32(device, 0x022400, fuse_enable); + spin_unlock_irqrestore(&fuse->lock, flags); return val; } +static const struct nvkm_fuse_func +gf100_fuse = { + .read = gf100_fuse_read, +}; -static int -gf100_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_fuse_new(struct nvkm_device *device, int index, struct nvkm_fuse **pfuse) { - struct gf100_fuse_priv *priv; - int ret; - - ret = nvkm_fuse_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - spin_lock_init(&priv->fuse_enable_lock); - return 0; + return nvkm_fuse_new_(&gf100_fuse, device, index, pfuse); } - -struct nvkm_oclass -gf100_fuse_oclass = { - .handle = NV_SUBDEV(FUSE, 0xC0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fuse_ctor, - .dtor = _nvkm_fuse_dtor, - .init = _nvkm_fuse_init, - .fini = _nvkm_fuse_fini, - .rd32 = gf100_fuse_rd32, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c index 0b256aa49..9aff4ea04 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c @@ -23,40 +23,20 @@ */ #include "priv.h" -struct gm107_fuse_priv { - struct nvkm_fuse base; -}; - static u32 -gm107_fuse_rd32(struct nvkm_object *object, u64 addr) +gm107_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct gf100_fuse_priv *priv = (void *)object; - return nv_rd32(priv, 0x21100 + addr); + struct nvkm_device *device = fuse->subdev.device; + return nvkm_rd32(device, 0x021100 + addr); } +static const struct nvkm_fuse_func +gm107_fuse = { + .read = gm107_fuse_read, +}; -static int -gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm107_fuse_new(struct nvkm_device *device, int index, struct nvkm_fuse **pfuse) { - struct gm107_fuse_priv *priv; - int ret; - - ret = nvkm_fuse_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - - return ret; + return nvkm_fuse_new_(&gm107_fuse, device, index, pfuse); } - -struct nvkm_oclass -gm107_fuse_oclass = { - .handle = NV_SUBDEV(FUSE, 0x117), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_fuse_ctor, - .dtor = _nvkm_fuse_dtor, - .init = _nvkm_fuse_init, - .fini = _nvkm_fuse_fini, - .rd32 = gm107_fuse_rd32, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c index 0d2afc426..514c193db 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c @@ -23,54 +23,29 @@ */ #include "priv.h" -struct nv50_fuse_priv { - struct nvkm_fuse base; - - spinlock_t fuse_enable_lock; -}; - static u32 -nv50_fuse_rd32(struct nvkm_object *object, u64 addr) +nv50_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct nv50_fuse_priv *priv = (void *)object; + struct nvkm_device *device = fuse->subdev.device; unsigned long flags; u32 fuse_enable, val; /* racy if another part of nvkm start writing to this reg */ - spin_lock_irqsave(&priv->fuse_enable_lock, flags); - fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800); - val = nv_rd32(priv, 0x21000 + addr); - nv_wr32(priv, 0x1084, fuse_enable); - spin_unlock_irqrestore(&priv->fuse_enable_lock, flags); + spin_lock_irqsave(&fuse->lock, flags); + fuse_enable = nvkm_mask(device, 0x001084, 0x800, 0x800); + val = nvkm_rd32(device, 0x021000 + addr); + nvkm_wr32(device, 0x001084, fuse_enable); + spin_unlock_irqrestore(&fuse->lock, flags); return val; } +static const struct nvkm_fuse_func +nv50_fuse = { + .read = &nv50_fuse_read, +}; -static int -nv50_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_fuse_new(struct nvkm_device *device, int index, struct nvkm_fuse **pfuse) { - struct nv50_fuse_priv *priv; - int ret; - - ret = nvkm_fuse_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - spin_lock_init(&priv->fuse_enable_lock); - return 0; + return nvkm_fuse_new_(&nv50_fuse, device, index, pfuse); } - -struct nvkm_oclass -nv50_fuse_oclass = { - .handle = NV_SUBDEV(FUSE, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fuse_ctor, - .dtor = _nvkm_fuse_dtor, - .init = _nvkm_fuse_init, - .fini = _nvkm_fuse_fini, - .rd32 = nv50_fuse_rd32, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h index 7e050f789..b0390b540 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h @@ -1,7 +1,12 @@ #ifndef __NVKM_FUSE_PRIV_H__ #define __NVKM_FUSE_PRIV_H__ +#define nvkm_fuse(p) container_of((p), struct nvkm_fuse, subdev) #include <subdev/fuse.h> -int _nvkm_fuse_init(struct nvkm_object *object); -void _nvkm_fuse_dtor(struct nvkm_object *object); +struct nvkm_fuse_func { + u32 (*read)(struct nvkm_fuse *, u32 addr); +}; + +int nvkm_fuse_new_(const struct nvkm_fuse_func *, struct nvkm_device *, + int index, struct nvkm_fuse **); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild index ea42a9ed1..e52c5e87f 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild @@ -2,5 +2,5 @@ nvkm-y += nvkm/subdev/gpio/base.o nvkm-y += nvkm/subdev/gpio/nv10.o nvkm-y += nvkm/subdev/gpio/nv50.o nvkm-y += nvkm/subdev/gpio/g94.o -nvkm-y += nvkm/subdev/gpio/gf110.o +nvkm-y += nvkm/subdev/gpio/gf119.o nvkm-y += nvkm/subdev/gpio/gk104.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index dea58161b..d45ec99f0 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -23,28 +23,33 @@ */ #include "priv.h" -#include <core/device.h> #include <core/notify.h> static int nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out) { - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV; + return gpio->func->drive(gpio, line, dir, out); } static int nvkm_gpio_sense(struct nvkm_gpio *gpio, int idx, int line) { - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - return impl->sense ? impl->sense(gpio, line) : -ENODEV; + return gpio->func->sense(gpio, line); } -static int +void +nvkm_gpio_reset(struct nvkm_gpio *gpio, u8 func) +{ + if (gpio->func->reset) + gpio->func->reset(gpio, func); +} + +int nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { - struct nvkm_bios *bios = nvkm_bios(gpio); + struct nvkm_device *device = gpio->subdev.device; + struct nvkm_bios *bios = device->bios; u8 ver, len; u16 data; @@ -56,11 +61,11 @@ nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, return 0; /* Apple iMac G4 NV18 */ - if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) { + if (device->quirk && device->quirk->tv_gpio) { if (tag == DCB_GPIO_TVDAC0) { *func = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, - .line = 4, + .line = device->quirk->tv_gpio, .log[0] = 0, .log[1] = 1, }; @@ -71,7 +76,7 @@ nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, return -ENOENT; } -static int +int nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state) { struct dcb_gpio_func func; @@ -87,7 +92,7 @@ nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state) return ret; } -static int +int nvkm_gpio_get(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line) { struct dcb_gpio_func func; @@ -107,16 +112,14 @@ static void nvkm_gpio_intr_fini(struct nvkm_event *event, int type, int index) { struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event); - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - impl->intr_mask(gpio, type, 1 << index, 0); + gpio->func->intr_mask(gpio, type, 1 << index, 0); } static void nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index) { struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event); - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - impl->intr_mask(gpio, type, 1 << index, 1 << index); + gpio->func->intr_mask(gpio, type, 1 << index, 1 << index); } static int @@ -133,16 +136,22 @@ nvkm_gpio_intr_ctor(struct nvkm_object *object, void *data, u32 size, return -EINVAL; } +static const struct nvkm_event_func +nvkm_gpio_intr_func = { + .ctor = nvkm_gpio_intr_ctor, + .init = nvkm_gpio_intr_init, + .fini = nvkm_gpio_intr_fini, +}; + static void nvkm_gpio_intr(struct nvkm_subdev *subdev) { struct nvkm_gpio *gpio = nvkm_gpio(subdev); - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; u32 hi, lo, i; - impl->intr_stat(gpio, &hi, &lo); + gpio->func->intr_stat(gpio, &hi, &lo); - for (i = 0; (hi | lo) && i < impl->lines; i++) { + for (i = 0; (hi | lo) && i < gpio->func->lines; i++) { struct nvkm_gpio_ntfy_rep rep = { .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) | (NVKM_GPIO_LO * !!(lo & (1 << i))), @@ -151,24 +160,15 @@ nvkm_gpio_intr(struct nvkm_subdev *subdev) } } -static const struct nvkm_event_func -nvkm_gpio_intr_func = { - .ctor = nvkm_gpio_intr_ctor, - .init = nvkm_gpio_intr_init, - .fini = nvkm_gpio_intr_fini, -}; - -int -_nvkm_gpio_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_gpio_fini(struct nvkm_subdev *subdev, bool suspend) { - const struct nvkm_gpio_impl *impl = (void *)object->oclass; - struct nvkm_gpio *gpio = nvkm_gpio(object); - u32 mask = (1 << impl->lines) - 1; - - impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); - impl->intr_stat(gpio, &mask, &mask); + struct nvkm_gpio *gpio = nvkm_gpio(subdev); + u32 mask = (1 << gpio->func->lines) - 1; - return nvkm_subdev_fini(&gpio->base, suspend); + gpio->func->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); + gpio->func->intr_stat(gpio, &mask, &mask); + return 0; } static struct dmi_system_id gpio_reset_ids[] = { @@ -182,70 +182,43 @@ static struct dmi_system_id gpio_reset_ids[] = { { } }; -int -_nvkm_gpio_init(struct nvkm_object *object) +static int +nvkm_gpio_init(struct nvkm_subdev *subdev) { - struct nvkm_gpio *gpio = nvkm_gpio(object); - int ret; - - ret = nvkm_subdev_init(&gpio->base); - if (ret) - return ret; - - if (gpio->reset && dmi_check_system(gpio_reset_ids)) - gpio->reset(gpio, DCB_GPIO_UNUSED); - - return ret; + struct nvkm_gpio *gpio = nvkm_gpio(subdev); + if (dmi_check_system(gpio_reset_ids)) + nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED); + return 0; } -void -_nvkm_gpio_dtor(struct nvkm_object *object) +static void * +nvkm_gpio_dtor(struct nvkm_subdev *subdev) { - struct nvkm_gpio *gpio = (void *)object; + struct nvkm_gpio *gpio = nvkm_gpio(subdev); nvkm_event_fini(&gpio->event); - nvkm_subdev_destroy(&gpio->base); + return gpio; } -int -nvkm_gpio_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) -{ - const struct nvkm_gpio_impl *impl = (void *)oclass; - struct nvkm_gpio *gpio; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "GPIO", - "gpio", length, pobject); - gpio = *pobject; - if (ret) - return ret; - - gpio->find = nvkm_gpio_find; - gpio->set = nvkm_gpio_set; - gpio->get = nvkm_gpio_get; - gpio->reset = impl->reset; - - ret = nvkm_event_init(&nvkm_gpio_intr_func, 2, impl->lines, - &gpio->event); - if (ret) - return ret; - - nv_subdev(gpio)->intr = nvkm_gpio_intr; - return 0; -} +static const struct nvkm_subdev_func +nvkm_gpio = { + .dtor = nvkm_gpio_dtor, + .init = nvkm_gpio_init, + .fini = nvkm_gpio_fini, + .intr = nvkm_gpio_intr, +}; int -_nvkm_gpio_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_gpio_new_(const struct nvkm_gpio_func *func, struct nvkm_device *device, + int index, struct nvkm_gpio **pgpio) { struct nvkm_gpio *gpio; - int ret; - ret = nvkm_gpio_create(parent, engine, oclass, &gpio); - *pobject = nv_object(gpio); - if (ret) - return ret; + if (!(gpio = *pgpio = kzalloc(sizeof(*gpio), GFP_KERNEL))) + return -ENOMEM; - return 0; + nvkm_subdev_ctor(&nvkm_gpio, device, index, 0, &gpio->subdev); + gpio->func = func; + + return nvkm_event_init(&nvkm_gpio_intr_func, 2, func->lines, + &gpio->event); } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c index 12b3e01fc..6dcda55fb 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c @@ -26,21 +26,23 @@ void g94_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr0 = nv_rd32(gpio, 0x00e054); - u32 intr1 = nv_rd32(gpio, 0x00e074); - u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0; - u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1; + struct nvkm_device *device = gpio->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x00e054); + u32 intr1 = nvkm_rd32(device, 0x00e074); + u32 stat0 = nvkm_rd32(device, 0x00e050) & intr0; + u32 stat1 = nvkm_rd32(device, 0x00e070) & intr1; *lo = (stat1 & 0xffff0000) | (stat0 >> 16); *hi = (stat1 << 16) | (stat0 & 0x0000ffff); - nv_wr32(gpio, 0x00e054, intr0); - nv_wr32(gpio, 0x00e074, intr1); + nvkm_wr32(device, 0x00e054, intr0); + nvkm_wr32(device, 0x00e074, intr1); } void g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte0 = nv_rd32(gpio, 0x00e050); - u32 inte1 = nv_rd32(gpio, 0x00e070); + struct nvkm_device *device = gpio->subdev.device; + u32 inte0 = nvkm_rd32(device, 0x00e050); + u32 inte1 = nvkm_rd32(device, 0x00e070); if (type & NVKM_GPIO_LO) inte0 = (inte0 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) @@ -51,23 +53,22 @@ g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) inte1 = (inte1 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte1 = (inte1 & ~mask) | data; - nv_wr32(gpio, 0x00e050, inte0); - nv_wr32(gpio, 0x00e070, inte1); + nvkm_wr32(device, 0x00e050, inte0); + nvkm_wr32(device, 0x00e070, inte1); } -struct nvkm_oclass * -g94_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +g94_gpio = { .lines = 32, .intr_stat = g94_gpio_intr_stat, .intr_mask = g94_gpio_intr_mask, .drive = nv50_gpio_drive, .sense = nv50_gpio_sense, .reset = nv50_gpio_reset, -}.base; +}; + +int +g94_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&g94_gpio, device, index, pgpio); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf119.c index 2c3bb255d..bb7400dfa 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf119.c @@ -24,15 +24,16 @@ #include "priv.h" void -gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) +gf119_gpio_reset(struct nvkm_gpio *gpio, u8 match) { - struct nvkm_bios *bios = nvkm_bios(gpio); + struct nvkm_device *device = gpio->subdev.device; + struct nvkm_bios *bios = device->bios; u8 ver, len; u16 entry; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { - u32 data = nv_ro32(bios, entry); + u32 data = nvbios_rd32(bios, entry); u8 line = (data & 0x0000003f); u8 defs = !!(data & 0x00000080); u8 func = (data & 0x0000ff00) >> 8; @@ -43,42 +44,43 @@ gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) (match != DCB_GPIO_UNUSED && match != func)) continue; - gpio->set(gpio, 0, func, line, defs); + nvkm_gpio_set(gpio, 0, func, line, defs); - nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0); + nvkm_mask(device, 0x00d610 + (line * 4), 0xff, unk0); if (unk1--) - nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line); + nvkm_mask(device, 0x00d740 + (unk1 * 4), 0xff, line); } } int -gf110_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) +gf119_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) { + struct nvkm_device *device = gpio->subdev.device; u32 data = ((dir ^ 1) << 13) | (out << 12); - nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data); - nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */ + nvkm_mask(device, 0x00d610 + (line * 4), 0x00003000, data); + nvkm_mask(device, 0x00d604, 0x00000001, 0x00000001); /* update? */ return 0; } int -gf110_gpio_sense(struct nvkm_gpio *gpio, int line) +gf119_gpio_sense(struct nvkm_gpio *gpio, int line) { - return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); + struct nvkm_device *device = gpio->subdev.device; + return !!(nvkm_rd32(device, 0x00d610 + (line * 4)) & 0x00004000); } -struct nvkm_oclass * -gf110_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +gf119_gpio = { .lines = 32, .intr_stat = g94_gpio_intr_stat, .intr_mask = g94_gpio_intr_mask, - .drive = gf110_gpio_drive, - .sense = gf110_gpio_sense, - .reset = gf110_gpio_reset, -}.base; + .drive = gf119_gpio_drive, + .sense = gf119_gpio_sense, + .reset = gf119_gpio_reset, +}; + +int +gf119_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&gf119_gpio, device, index, pgpio); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c index 42fd2faaa..3f45afd17 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c @@ -26,21 +26,23 @@ static void gk104_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr0 = nv_rd32(gpio, 0x00dc00); - u32 intr1 = nv_rd32(gpio, 0x00dc80); - u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0; - u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1; + struct nvkm_device *device = gpio->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x00dc00); + u32 intr1 = nvkm_rd32(device, 0x00dc80); + u32 stat0 = nvkm_rd32(device, 0x00dc08) & intr0; + u32 stat1 = nvkm_rd32(device, 0x00dc88) & intr1; *lo = (stat1 & 0xffff0000) | (stat0 >> 16); *hi = (stat1 << 16) | (stat0 & 0x0000ffff); - nv_wr32(gpio, 0x00dc00, intr0); - nv_wr32(gpio, 0x00dc80, intr1); + nvkm_wr32(device, 0x00dc00, intr0); + nvkm_wr32(device, 0x00dc80, intr1); } void gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte0 = nv_rd32(gpio, 0x00dc08); - u32 inte1 = nv_rd32(gpio, 0x00dc88); + struct nvkm_device *device = gpio->subdev.device; + u32 inte0 = nvkm_rd32(device, 0x00dc08); + u32 inte1 = nvkm_rd32(device, 0x00dc88); if (type & NVKM_GPIO_LO) inte0 = (inte0 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) @@ -51,23 +53,22 @@ gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) inte1 = (inte1 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte1 = (inte1 & ~mask) | data; - nv_wr32(gpio, 0x00dc08, inte0); - nv_wr32(gpio, 0x00dc88, inte1); + nvkm_wr32(device, 0x00dc08, inte0); + nvkm_wr32(device, 0x00dc88, inte1); } -struct nvkm_oclass * -gk104_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +gk104_gpio = { .lines = 32, .intr_stat = gk104_gpio_intr_stat, .intr_mask = gk104_gpio_intr_mask, - .drive = gf110_gpio_drive, - .sense = gf110_gpio_sense, - .reset = gf110_gpio_reset, -}.base; + .drive = gf119_gpio_drive, + .sense = gf119_gpio_sense, + .reset = gf119_gpio_reset, +}; + +int +gk104_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&gk104_gpio, device, index, pgpio); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c index 2b2951542..ae3499b48 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c @@ -28,19 +28,20 @@ static int nv10_gpio_sense(struct nvkm_gpio *gpio, int line) { + struct nvkm_device *device = gpio->subdev.device; if (line < 2) { line = line * 16; - line = nv_rd32(gpio, 0x600818) >> line; + line = nvkm_rd32(device, 0x600818) >> line; return !!(line & 0x0100); } else if (line < 10) { line = (line - 2) * 4; - line = nv_rd32(gpio, 0x60081c) >> line; + line = nvkm_rd32(device, 0x60081c) >> line; return !!(line & 0x04); } else if (line < 14) { line = (line - 10) * 4; - line = nv_rd32(gpio, 0x600850) >> line; + line = nvkm_rd32(device, 0x600850) >> line; return !!(line & 0x04); } @@ -50,6 +51,7 @@ nv10_gpio_sense(struct nvkm_gpio *gpio, int line) static int nv10_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) { + struct nvkm_device *device = gpio->subdev.device; u32 reg, mask, data; if (line < 2) { @@ -73,43 +75,44 @@ nv10_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) return -EINVAL; } - nv_mask(gpio, reg, mask << line, data << line); + nvkm_mask(device, reg, mask << line, data << line); return 0; } static void nv10_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr = nv_rd32(gpio, 0x001104); - u32 stat = nv_rd32(gpio, 0x001144) & intr; + struct nvkm_device *device = gpio->subdev.device; + u32 intr = nvkm_rd32(device, 0x001104); + u32 stat = nvkm_rd32(device, 0x001144) & intr; *lo = (stat & 0xffff0000) >> 16; *hi = (stat & 0x0000ffff); - nv_wr32(gpio, 0x001104, intr); + nvkm_wr32(device, 0x001104, intr); } static void nv10_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte = nv_rd32(gpio, 0x001144); + struct nvkm_device *device = gpio->subdev.device; + u32 inte = nvkm_rd32(device, 0x001144); if (type & NVKM_GPIO_LO) inte = (inte & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte = (inte & ~mask) | data; - nv_wr32(gpio, 0x001144, inte); + nvkm_wr32(device, 0x001144, inte); } -struct nvkm_oclass * -nv10_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0x10), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +nv10_gpio = { .lines = 16, .intr_stat = nv10_gpio_intr_stat, .intr_mask = nv10_gpio_intr_mask, .drive = nv10_gpio_drive, .sense = nv10_gpio_sense, -}.base; +}; + +int +nv10_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&nv10_gpio, device, index, pgpio); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c index 6a031035b..73923fd5f 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c @@ -26,14 +26,15 @@ void nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match) { - struct nvkm_bios *bios = nvkm_bios(gpio); + struct nvkm_device *device = gpio->subdev.device; + struct nvkm_bios *bios = device->bios; u8 ver, len; u16 entry; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { static const u32 regs[] = { 0xe100, 0xe28c }; - u32 data = nv_ro32(bios, entry); + u32 data = nvbios_rd32(bios, entry); u8 line = (data & 0x0000001f); u8 func = (data & 0x0000ff00) >> 8; u8 defs = !!(data & 0x01000000); @@ -47,13 +48,13 @@ nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match) (match != DCB_GPIO_UNUSED && match != func)) continue; - gpio->set(gpio, 0, func, line, defs); + nvkm_gpio_set(gpio, 0, func, line, defs); - nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh); + nvkm_mask(device, reg, 0x00010001 << lsh, val << lsh); } } -int +static int nv50_gpio_location(int line, u32 *reg, u32 *shift) { const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; @@ -69,60 +70,63 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift) int nv50_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) { + struct nvkm_device *device = gpio->subdev.device; u32 reg, shift; if (nv50_gpio_location(line, ®, &shift)) return -EINVAL; - nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift); + nvkm_mask(device, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift); return 0; } int nv50_gpio_sense(struct nvkm_gpio *gpio, int line) { + struct nvkm_device *device = gpio->subdev.device; u32 reg, shift; if (nv50_gpio_location(line, ®, &shift)) return -EINVAL; - return !!(nv_rd32(gpio, reg) & (4 << shift)); + return !!(nvkm_rd32(device, reg) & (4 << shift)); } static void nv50_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr = nv_rd32(gpio, 0x00e054); - u32 stat = nv_rd32(gpio, 0x00e050) & intr; + struct nvkm_device *device = gpio->subdev.device; + u32 intr = nvkm_rd32(device, 0x00e054); + u32 stat = nvkm_rd32(device, 0x00e050) & intr; *lo = (stat & 0xffff0000) >> 16; *hi = (stat & 0x0000ffff); - nv_wr32(gpio, 0x00e054, intr); + nvkm_wr32(device, 0x00e054, intr); } static void nv50_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte = nv_rd32(gpio, 0x00e050); + struct nvkm_device *device = gpio->subdev.device; + u32 inte = nvkm_rd32(device, 0x00e050); if (type & NVKM_GPIO_LO) inte = (inte & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte = (inte & ~mask) | data; - nv_wr32(gpio, 0x00e050, inte); + nvkm_wr32(device, 0x00e050, inte); } -struct nvkm_oclass * -nv50_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +nv50_gpio = { .lines = 16, .intr_stat = nv50_gpio_intr_stat, .intr_mask = nv50_gpio_intr_mask, .drive = nv50_gpio_drive, .sense = nv50_gpio_sense, .reset = nv50_gpio_reset, -}.base; +}; + +int +nv50_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&nv50_gpio, device, index, pgpio); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h index 382f8d44e..371bcdbbe 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h @@ -1,33 +1,9 @@ #ifndef __NVKM_GPIO_PRIV_H__ #define __NVKM_GPIO_PRIV_H__ +#define nvkm_gpio(p) container_of((p), struct nvkm_gpio, subdev) #include <subdev/gpio.h> -#define nvkm_gpio_create(p,e,o,d) \ - nvkm_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_gpio_destroy(p) ({ \ - struct nvkm_gpio *gpio = (p); \ - _nvkm_gpio_dtor(nv_object(gpio)); \ -}) -#define nvkm_gpio_init(p) ({ \ - struct nvkm_gpio *gpio = (p); \ - _nvkm_gpio_init(nv_object(gpio)); \ -}) -#define nvkm_gpio_fini(p,s) ({ \ - struct nvkm_gpio *gpio = (p); \ - _nvkm_gpio_fini(nv_object(gpio), (s)); \ -}) - -int nvkm_gpio_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -int _nvkm_gpio_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_gpio_dtor(struct nvkm_object *); -int _nvkm_gpio_init(struct nvkm_object *); -int _nvkm_gpio_fini(struct nvkm_object *, bool); - -struct nvkm_gpio_impl { - struct nvkm_oclass base; +struct nvkm_gpio_func { int lines; /* read and ack pending interrupts, returning only data @@ -51,6 +27,9 @@ struct nvkm_gpio_impl { void (*reset)(struct nvkm_gpio *, u8); }; +int nvkm_gpio_new_(const struct nvkm_gpio_func *, struct nvkm_device *, + int index, struct nvkm_gpio **); + void nv50_gpio_reset(struct nvkm_gpio *, u8); int nv50_gpio_drive(struct nvkm_gpio *, int, int, int); int nv50_gpio_sense(struct nvkm_gpio *, int); @@ -58,7 +37,7 @@ int nv50_gpio_sense(struct nvkm_gpio *, int); void g94_gpio_intr_stat(struct nvkm_gpio *, u32 *, u32 *); void g94_gpio_intr_mask(struct nvkm_gpio *, u32, u32, u32); -void gf110_gpio_reset(struct nvkm_gpio *, u8); -int gf110_gpio_drive(struct nvkm_gpio *, int, int, int); -int gf110_gpio_sense(struct nvkm_gpio *, int); +void gf119_gpio_reset(struct nvkm_gpio *, u8); +int gf119_gpio_drive(struct nvkm_gpio *, int, int, int); +int gf119_gpio_sense(struct nvkm_gpio *, int); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild index d68307409..1f730613c 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild @@ -1,16 +1,30 @@ nvkm-y += nvkm/subdev/i2c/base.o -nvkm-y += nvkm/subdev/i2c/anx9805.o -nvkm-y += nvkm/subdev/i2c/aux.o -nvkm-y += nvkm/subdev/i2c/bit.o -nvkm-y += nvkm/subdev/i2c/pad.o -nvkm-y += nvkm/subdev/i2c/padnv04.o -nvkm-y += nvkm/subdev/i2c/padg94.o -nvkm-y += nvkm/subdev/i2c/padgm204.o nvkm-y += nvkm/subdev/i2c/nv04.o nvkm-y += nvkm/subdev/i2c/nv4e.o nvkm-y += nvkm/subdev/i2c/nv50.o nvkm-y += nvkm/subdev/i2c/g94.o -nvkm-y += nvkm/subdev/i2c/gf110.o nvkm-y += nvkm/subdev/i2c/gf117.o +nvkm-y += nvkm/subdev/i2c/gf119.o nvkm-y += nvkm/subdev/i2c/gk104.o nvkm-y += nvkm/subdev/i2c/gm204.o + +nvkm-y += nvkm/subdev/i2c/pad.o +nvkm-y += nvkm/subdev/i2c/padnv04.o +nvkm-y += nvkm/subdev/i2c/padnv4e.o +nvkm-y += nvkm/subdev/i2c/padnv50.o +nvkm-y += nvkm/subdev/i2c/padg94.o +nvkm-y += nvkm/subdev/i2c/padgf119.o +nvkm-y += nvkm/subdev/i2c/padgm204.o + +nvkm-y += nvkm/subdev/i2c/bus.o +nvkm-y += nvkm/subdev/i2c/busnv04.o +nvkm-y += nvkm/subdev/i2c/busnv4e.o +nvkm-y += nvkm/subdev/i2c/busnv50.o +nvkm-y += nvkm/subdev/i2c/busgf119.o +nvkm-y += nvkm/subdev/i2c/bit.o + +nvkm-y += nvkm/subdev/i2c/aux.o +nvkm-y += nvkm/subdev/i2c/auxg94.o +nvkm-y += nvkm/subdev/i2c/auxgm204.o + +nvkm-y += nvkm/subdev/i2c/anx9805.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c index d17dd1cf3..b7b01c3f7 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c @@ -21,272 +21,258 @@ * * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "port.h" +#define anx9805_pad(p) container_of((p), struct anx9805_pad, base) +#define anx9805_bus(p) container_of((p), struct anx9805_bus, base) +#define anx9805_aux(p) container_of((p), struct anx9805_aux, base) +#include "aux.h" +#include "bus.h" + +struct anx9805_pad { + struct nvkm_i2c_pad base; + struct nvkm_i2c_bus *bus; + u8 addr; +}; -struct anx9805_i2c_port { - struct nvkm_i2c_port base; - u32 addr; - u32 ctrl; +struct anx9805_bus { + struct nvkm_i2c_bus base; + struct anx9805_pad *pad; + u8 addr; }; static int -anx9805_train(struct nvkm_i2c_port *port, int link_nr, int link_bw, bool enh) +anx9805_bus_xfer(struct nvkm_i2c_bus *base, struct i2c_msg *msgs, int num) { - struct anx9805_i2c_port *chan = (void *)port; - struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent; - u8 tmp, i; - - DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh); + struct anx9805_bus *bus = anx9805_bus(base); + struct anx9805_pad *pad = bus->pad; + struct i2c_adapter *adap = &pad->bus->i2c; + struct i2c_msg *msg = msgs; + int ret = -ETIMEDOUT; + int i, j, cnt = num; + u8 seg = 0x00, off = 0x00, tmp; - nv_wri2cr(mast, chan->addr, 0xa0, link_bw); - nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); - nv_wri2cr(mast, chan->addr, 0xa2, 0x01); - nv_wri2cr(mast, chan->addr, 0xa8, 0x01); + tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x10; + nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x10); + nvkm_wri2cr(adap, pad->addr, 0x07, tmp); + nvkm_wri2cr(adap, bus->addr, 0x43, 0x05); + mdelay(5); - i = 0; - while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) { - mdelay(5); - if (i++ == 100) { - nv_error(port, "link training timed out\n"); - return -ETIMEDOUT; + while (cnt--) { + if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) { + nvkm_wri2cr(adap, bus->addr, 0x40, msg->addr << 1); + nvkm_wri2cr(adap, bus->addr, 0x41, seg); + nvkm_wri2cr(adap, bus->addr, 0x42, off); + nvkm_wri2cr(adap, bus->addr, 0x44, msg->len); + nvkm_wri2cr(adap, bus->addr, 0x45, 0x00); + nvkm_wri2cr(adap, bus->addr, 0x43, 0x01); + for (i = 0; i < msg->len; i++) { + j = 0; + while (nvkm_rdi2cr(adap, bus->addr, 0x46) & 0x10) { + mdelay(5); + if (j++ == 32) + goto done; + } + msg->buf[i] = nvkm_rdi2cr(adap, bus->addr, 0x47); + } + } else + if (!(msg->flags & I2C_M_RD)) { + if (msg->addr == 0x50 && msg->len == 0x01) { + off = msg->buf[0]; + } else + if (msg->addr == 0x30 && msg->len == 0x01) { + seg = msg->buf[0]; + } else + goto done; + } else { + goto done; } + msg++; } - if (tmp & 0x70) { - nv_error(port, "link training failed: 0x%02x\n", tmp); - return -EIO; + ret = num; +done: + nvkm_wri2cr(adap, bus->addr, 0x43, 0x00); + return ret; +} + +static const struct nvkm_i2c_bus_func +anx9805_bus_func = { + .xfer = anx9805_bus_xfer, +}; + +static int +anx9805_bus_new(struct nvkm_i2c_pad *base, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + struct anx9805_pad *pad = anx9805_pad(base); + struct anx9805_bus *bus; + int ret; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + bus->pad = pad; + + ret = nvkm_i2c_bus_ctor(&anx9805_bus_func, &pad->base, id, &bus->base); + if (ret) + return ret; + + switch (pad->addr) { + case 0x39: bus->addr = 0x3d; break; + case 0x3b: bus->addr = 0x3f; break; + default: + return -ENOSYS; } - return 1; + return 0; } +struct anx9805_aux { + struct nvkm_i2c_aux base; + struct anx9805_pad *pad; + u8 addr; +}; + static int -anx9805_aux(struct nvkm_i2c_port *port, bool retry, - u8 type, u32 addr, u8 *data, u8 size) +anx9805_aux_xfer(struct nvkm_i2c_aux *base, bool retry, + u8 type, u32 addr, u8 *data, u8 size) { - struct anx9805_i2c_port *chan = (void *)port; - struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent; + struct anx9805_aux *aux = anx9805_aux(base); + struct anx9805_pad *pad = aux->pad; + struct i2c_adapter *adap = &pad->bus->i2c; int i, ret = -ETIMEDOUT; u8 buf[16] = {}; u8 tmp; - DBG("%02x %05x %d\n", type, addr, size); + AUX_DBG(&aux->base, "%02x %05x %d", type, addr, size); - tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; - nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); - nv_wri2cr(mast, chan->ctrl, 0x07, tmp); - nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); + tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x04; + nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x04); + nvkm_wri2cr(adap, pad->addr, 0x07, tmp); + nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01); - nv_wri2cr(mast, chan->addr, 0xe4, 0x80); + nvkm_wri2cr(adap, aux->addr, 0xe4, 0x80); if (!(type & 1)) { memcpy(buf, data, size); - DBG("%16ph", buf); + AUX_DBG(&aux->base, "%16ph", buf); for (i = 0; i < size; i++) - nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]); + nvkm_wri2cr(adap, aux->addr, 0xf0 + i, buf[i]); } - nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); - nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); - nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); - nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16); - nv_wri2cr(mast, chan->addr, 0xe9, 0x01); + nvkm_wri2cr(adap, aux->addr, 0xe5, ((size - 1) << 4) | type); + nvkm_wri2cr(adap, aux->addr, 0xe6, (addr & 0x000ff) >> 0); + nvkm_wri2cr(adap, aux->addr, 0xe7, (addr & 0x0ff00) >> 8); + nvkm_wri2cr(adap, aux->addr, 0xe8, (addr & 0xf0000) >> 16); + nvkm_wri2cr(adap, aux->addr, 0xe9, 0x01); i = 0; - while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) { + while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xe9)) & 0x01) { mdelay(5); if (i++ == 32) goto done; } - if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) { + if ((tmp = nvkm_rdi2cr(adap, pad->addr, 0xf7)) & 0x01) { ret = -EIO; goto done; } if (type & 1) { for (i = 0; i < size; i++) - buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); - DBG("%16ph", buf); + buf[i] = nvkm_rdi2cr(adap, aux->addr, 0xf0 + i); + AUX_DBG(&aux->base, "%16ph", buf); memcpy(data, buf, size); } ret = 0; done: - nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); + nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01); return ret; } -static const struct nvkm_i2c_func -anx9805_aux_func = { - .aux = anx9805_aux, - .lnk_ctl = anx9805_train, -}; - static int -anx9805_aux_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +anx9805_aux_lnk_ctl(struct nvkm_i2c_aux *base, + int link_nr, int link_bw, bool enh) { - struct nvkm_i2c_port *mast = (void *)parent; - struct anx9805_i2c_port *chan; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_aux_algo, &anx9805_aux_func, - &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - switch ((oclass->handle & 0xff00) >> 8) { - case 0x0d: - chan->addr = 0x38; - chan->ctrl = 0x39; - break; - case 0x0e: - chan->addr = 0x3c; - chan->ctrl = 0x3b; - break; - default: - BUG_ON(1); - } - - if (mast->adapter.algo == &i2c_bit_algo) { - struct i2c_algo_bit_data *algo = mast->adapter.algo_data; - algo->udelay = max(algo->udelay, 40); - } - - return 0; -} - -static struct nvkm_ofuncs -anx9805_aux_ofuncs = { - .ctor = anx9805_aux_chan_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, -}; + struct anx9805_aux *aux = anx9805_aux(base); + struct anx9805_pad *pad = aux->pad; + struct i2c_adapter *adap = &pad->bus->i2c; + u8 tmp, i; -static int -anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - struct anx9805_i2c_port *port = adap->algo_data; - struct nvkm_i2c_port *mast = (void *)nv_object(port)->parent; - struct i2c_msg *msg = msgs; - int ret = -ETIMEDOUT; - int i, j, cnt = num; - u8 seg = 0x00, off = 0x00, tmp; + AUX_DBG(&aux->base, "ANX9805 train %d %02x %d", + link_nr, link_bw, enh); - tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10; - nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10); - nv_wri2cr(mast, port->ctrl, 0x07, tmp); - nv_wri2cr(mast, port->addr, 0x43, 0x05); - mdelay(5); + nvkm_wri2cr(adap, aux->addr, 0xa0, link_bw); + nvkm_wri2cr(adap, aux->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); + nvkm_wri2cr(adap, aux->addr, 0xa2, 0x01); + nvkm_wri2cr(adap, aux->addr, 0xa8, 0x01); - while (cnt--) { - if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) { - nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1); - nv_wri2cr(mast, port->addr, 0x41, seg); - nv_wri2cr(mast, port->addr, 0x42, off); - nv_wri2cr(mast, port->addr, 0x44, msg->len); - nv_wri2cr(mast, port->addr, 0x45, 0x00); - nv_wri2cr(mast, port->addr, 0x43, 0x01); - for (i = 0; i < msg->len; i++) { - j = 0; - while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) { - mdelay(5); - if (j++ == 32) - goto done; - } - msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47); - } - } else - if (!(msg->flags & I2C_M_RD)) { - if (msg->addr == 0x50 && msg->len == 0x01) { - off = msg->buf[0]; - } else - if (msg->addr == 0x30 && msg->len == 0x01) { - seg = msg->buf[0]; - } else - goto done; - } else { - goto done; + i = 0; + while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xa8)) & 0x01) { + mdelay(5); + if (i++ == 100) { + AUX_ERR(&aux->base, "link training timeout"); + return -ETIMEDOUT; } - msg++; } - ret = num; -done: - nv_wri2cr(mast, port->addr, 0x43, 0x00); - return ret; -} + if (tmp & 0x70) { + AUX_ERR(&aux->base, "link training failed"); + return -EIO; + } -static u32 -anx9805_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return 0; } -static const struct i2c_algorithm -anx9805_i2c_algo = { - .master_xfer = anx9805_xfer, - .functionality = anx9805_func -}; - -static const struct nvkm_i2c_func -anx9805_i2c_func = { +static const struct nvkm_i2c_aux_func +anx9805_aux_func = { + .xfer = anx9805_aux_xfer, + .lnk_ctl = anx9805_aux_lnk_ctl, }; static int -anx9805_ddc_port_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +anx9805_aux_new(struct nvkm_i2c_pad *base, int id, u8 drive, + struct nvkm_i2c_aux **pbus) { - struct nvkm_i2c_port *mast = (void *)parent; - struct anx9805_i2c_port *port; + struct anx9805_pad *pad = anx9805_pad(base); + struct anx9805_aux *aux; int ret; - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &anx9805_i2c_algo, &anx9805_i2c_func, &port); - *pobject = nv_object(port); + if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL))) + return -ENOMEM; + *pbus = &aux->base; + aux->pad = pad; + + ret = nvkm_i2c_aux_ctor(&anx9805_aux_func, &pad->base, id, &aux->base); if (ret) return ret; - switch ((oclass->handle & 0xff00) >> 8) { - case 0x0d: - port->addr = 0x3d; - port->ctrl = 0x39; - break; - case 0x0e: - port->addr = 0x3f; - port->ctrl = 0x3b; - break; + switch (pad->addr) { + case 0x39: aux->addr = 0x38; break; + case 0x3b: aux->addr = 0x3c; break; default: - BUG_ON(1); - } - - if (mast->adapter.algo == &i2c_bit_algo) { - struct i2c_algo_bit_data *algo = mast->adapter.algo_data; - algo->udelay = max(algo->udelay, 40); + return -ENOSYS; } return 0; } -static struct nvkm_ofuncs -anx9805_ddc_ofuncs = { - .ctor = anx9805_ddc_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, +static const struct nvkm_i2c_pad_func +anx9805_pad_func = { + .bus_new_4 = anx9805_bus_new, + .aux_new_6 = anx9805_aux_new, }; -struct nvkm_oclass -nvkm_anx9805_sclass[] = { - { .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs }, - { .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs }, - { .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs }, - { .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs }, - {} -}; +int +anx9805_pad_new(struct nvkm_i2c_bus *bus, int id, u8 addr, + struct nvkm_i2c_pad **ppad) +{ + struct anx9805_pad *pad; + + if (!(pad = kzalloc(sizeof(*pad), GFP_KERNEL))) + return -ENOMEM; + *ppad = &pad->base; + + nvkm_i2c_pad_ctor(&anx9805_pad_func, bus->pad->i2c, id, &pad->base); + pad->bus = bus; + pad->addr = addr; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c index 1c18860f8..f0851d57d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c @@ -21,50 +21,17 @@ * * Authors: Ben Skeggs */ -#include "priv.h" - -int -nv_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *i2c = nvkm_i2c(port); - if (port->func->aux) { - int ret = i2c->acquire(port, 0); - if (ret == 0) { - ret = port->func->aux(port, true, 9, addr, data, size); - i2c->release(port); - } - return ret; - } - return -ENODEV; -} - -int -nv_wraux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *i2c = nvkm_i2c(port); - if (port->func->aux) { - int ret = i2c->acquire(port, 0); - if (ret == 0) { - ret = port->func->aux(port, true, 8, addr, data, size); - i2c->release(port); - } - return ret; - } - return -ENODEV; -} +#include "aux.h" +#include "pad.h" static int -aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - struct nvkm_i2c_port *port = adap->algo_data; - struct nvkm_i2c *i2c = nvkm_i2c(port); + struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c); struct i2c_msg *msg = msgs; int ret, mcnt = num; - if (!port->func->aux) - return -ENODEV; - - ret = i2c->acquire(port, 0); + ret = nvkm_i2c_aux_acquire(aux); if (ret) return ret; @@ -84,9 +51,9 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (mcnt || remaining > 16) cmd |= 4; /* MOT */ - ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt); + ret = aux->func->xfer(aux, true, cmd, msg->addr, ptr, cnt); if (ret < 0) { - i2c->release(port); + nvkm_i2c_aux_release(aux); return ret; } @@ -97,17 +64,111 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) msg++; } - i2c->release(port); + nvkm_i2c_aux_release(aux); return num; } static u32 -aux_func(struct i2c_adapter *adap) +nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } -const struct i2c_algorithm nvkm_i2c_aux_algo = { - .master_xfer = aux_xfer, - .functionality = aux_func +const struct i2c_algorithm +nvkm_i2c_aux_i2c_algo = { + .master_xfer = nvkm_i2c_aux_i2c_xfer, + .functionality = nvkm_i2c_aux_i2c_func }; + +void +nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor) +{ + struct nvkm_i2c_pad *pad = aux->pad; + AUX_TRACE(aux, "monitor: %s", monitor ? "yes" : "no"); + if (monitor) + nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX); + else + nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF); +} + +void +nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux) +{ + struct nvkm_i2c_pad *pad = aux->pad; + AUX_TRACE(aux, "release"); + nvkm_i2c_pad_release(pad); + mutex_unlock(&aux->mutex); +} + +int +nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux) +{ + struct nvkm_i2c_pad *pad = aux->pad; + int ret; + AUX_TRACE(aux, "acquire"); + mutex_lock(&aux->mutex); + ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX); + if (ret) + mutex_unlock(&aux->mutex); + return ret; +} + +int +nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type, + u32 addr, u8 *data, u8 size) +{ + return aux->func->xfer(aux, retry, type, addr, data, size); +} + +int +nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef) +{ + if (aux->func->lnk_ctl) + return aux->func->lnk_ctl(aux, nr, bw, ef); + return -ENODEV; +} + +void +nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux) +{ + struct nvkm_i2c_aux *aux = *paux; + if (aux && !WARN_ON(!aux->func)) { + AUX_TRACE(aux, "dtor"); + list_del(&aux->head); + i2c_del_adapter(&aux->i2c); + kfree(*paux); + *paux = NULL; + } +} + +int +nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_aux *aux) +{ + struct nvkm_device *device = pad->i2c->subdev.device; + + aux->func = func; + aux->pad = pad; + aux->id = id; + mutex_init(&aux->mutex); + list_add_tail(&aux->head, &pad->i2c->aux); + AUX_TRACE(aux, "ctor"); + + snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x", + dev_name(device->dev), id); + aux->i2c.owner = THIS_MODULE; + aux->i2c.dev.parent = device->dev; + aux->i2c.algo = &nvkm_i2c_aux_i2c_algo; + return i2c_add_adapter(&aux->i2c); +} + +int +nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_aux **paux) +{ + if (!(*paux = kzalloc(sizeof(**paux), GFP_KERNEL))) + return -ENOMEM; + return nvkm_i2c_aux_ctor(func, pad, id, *paux); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h new file mode 100644 index 000000000..35a892e4a --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h @@ -0,0 +1,30 @@ +#ifndef __NVKM_I2C_AUX_H__ +#define __NVKM_I2C_AUX_H__ +#include "pad.h" + +struct nvkm_i2c_aux_func { + int (*xfer)(struct nvkm_i2c_aux *, bool retry, u8 type, + u32 addr, u8 *data, u8 size); + int (*lnk_ctl)(struct nvkm_i2c_aux *, int link_nr, int link_bw, + bool enhanced_framing); +}; + +int nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_aux *); +int nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_aux **); +void nvkm_i2c_aux_del(struct nvkm_i2c_aux **); +int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type, + u32 addr, u8 *data, u8 size); + +int g94_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); +int gm204_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); + +#define AUX_MSG(b,l,f,a...) do { \ + struct nvkm_i2c_aux *_aux = (b); \ + nvkm_##l(&_aux->pad->i2c->subdev, "aux %04x: "f"\n", _aux->id, ##a); \ +} while(0) +#define AUX_ERR(b,f,a...) AUX_MSG((b), error, f, ##a) +#define AUX_DBG(b,f,a...) AUX_MSG((b), debug, f, ##a) +#define AUX_TRACE(b,f,a...) AUX_MSG((b), trace, f, ##a) +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c new file mode 100644 index 000000000..954f5b76b --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c @@ -0,0 +1,181 @@ +/* + * Copyright 2015 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 busions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#define g94_i2c_aux(p) container_of((p), struct g94_i2c_aux, base) +#include "aux.h" + +struct g94_i2c_aux { + struct nvkm_i2c_aux base; + int ch; +}; + +static void +g94_i2c_aux_fini(struct g94_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00310000, 0x00000000); +} + +static int +g94_i2c_aux_init(struct g94_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 unksel = 1; /* nfi which to use, or if it matters.. */ + const u32 ureq = unksel ? 0x00100000 : 0x00200000; + const u32 urep = unksel ? 0x01000000 : 0x02000000; + u32 ctrl, timeout; + + /* wait up to 1ms for any previous transaction to be done... */ + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl); + return -EBUSY; + } + } while (ctrl & 0x03010000); + + /* set some magic, and wait up to 1ms for it to appear */ + nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00300000, ureq); + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "magic wait %08x", ctrl); + g94_i2c_aux_fini(aux); + return -EBUSY; + } + } while ((ctrl & 0x03000000) != urep); + + return 0; +} + +static int +g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, + u8 type, u32 addr, u8 *data, u8 size) +{ + struct g94_i2c_aux *aux = g94_i2c_aux(obj); + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 base = aux->ch * 0x50; + u32 ctrl, stat, timeout, retries; + u32 xbuf[4] = {}; + int ret, i; + + AUX_TRACE(&aux->base, "%d: %08x %d", type, addr, size); + + ret = g94_i2c_aux_init(aux); + if (ret < 0) + goto out; + + stat = nvkm_rd32(device, 0x00e4e8 + base); + if (!(stat & 0x10000000)) { + AUX_TRACE(&aux->base, "sink not detected"); + ret = -ENXIO; + goto out; + } + + if (!(type & 1)) { + memcpy(xbuf, data, size); + for (i = 0; i < 16; i += 4) { + AUX_TRACE(&aux->base, "wr %08x", xbuf[i / 4]); + nvkm_wr32(device, 0x00e4c0 + base + i, xbuf[i / 4]); + } + } + + ctrl = nvkm_rd32(device, 0x00e4e4 + base); + ctrl &= ~0x0001f0ff; + ctrl |= type << 12; + ctrl |= size - 1; + nvkm_wr32(device, 0x00e4e0 + base, addr); + + /* (maybe) retry transaction a number of times on failure... */ + for (retries = 0; !ret && retries < 32; retries++) { + /* reset, and delay a while if this is a retry */ + nvkm_wr32(device, 0x00e4e4 + base, 0x80000000 | ctrl); + nvkm_wr32(device, 0x00e4e4 + base, 0x00000000 | ctrl); + if (retries) + udelay(400); + + /* transaction request, wait up to 1ms for it to complete */ + nvkm_wr32(device, 0x00e4e4 + base, 0x00010000 | ctrl); + + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00e4e4 + base); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "timeout %08x", ctrl); + ret = -EIO; + goto out; + } + } while (ctrl & 0x00010000); + ret = 1; + + /* read status, and check if transaction completed ok */ + stat = nvkm_mask(device, 0x00e4e8 + base, 0, 0); + if ((stat & 0x000f0000) == 0x00080000 || + (stat & 0x000f0000) == 0x00020000) + ret = retry ? 0 : 1; + if ((stat & 0x00000100)) + ret = -ETIMEDOUT; + if ((stat & 0x00000e00)) + ret = -EIO; + + AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat); + } + + if (type & 1) { + for (i = 0; i < 16; i += 4) { + xbuf[i / 4] = nvkm_rd32(device, 0x00e4d0 + base + i); + AUX_TRACE(&aux->base, "rd %08x", xbuf[i / 4]); + } + memcpy(data, xbuf, size); + } + +out: + g94_i2c_aux_fini(aux); + return ret < 0 ? ret : (stat & 0x000f0000) >> 16; +} + +static const struct nvkm_i2c_aux_func +g94_i2c_aux_func = { + .xfer = g94_i2c_aux_xfer, +}; + +int +g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive, + struct nvkm_i2c_aux **paux) +{ + struct g94_i2c_aux *aux; + + if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL))) + return -ENOMEM; + *paux = &aux->base; + + nvkm_i2c_aux_ctor(&g94_i2c_aux_func, pad, index, &aux->base); + aux->ch = drive; + aux->base.intr = 1 << aux->ch; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c new file mode 100644 index 000000000..bed231b56 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c @@ -0,0 +1,181 @@ +/* + * Copyright 2015 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 busions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#define gm204_i2c_aux(p) container_of((p), struct gm204_i2c_aux, base) +#include "aux.h" + +struct gm204_i2c_aux { + struct nvkm_i2c_aux base; + int ch; +}; + +static void +gm204_i2c_aux_fini(struct gm204_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00310000, 0x00000000); +} + +static int +gm204_i2c_aux_init(struct gm204_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 unksel = 1; /* nfi which to use, or if it matters.. */ + const u32 ureq = unksel ? 0x00100000 : 0x00200000; + const u32 urep = unksel ? 0x01000000 : 0x02000000; + u32 ctrl, timeout; + + /* wait up to 1ms for any previous transaction to be done... */ + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00d954 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl); + return -EBUSY; + } + } while (ctrl & 0x03010000); + + /* set some magic, and wait up to 1ms for it to appear */ + nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00300000, ureq); + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00d954 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "magic wait %08x", ctrl); + gm204_i2c_aux_fini(aux); + return -EBUSY; + } + } while ((ctrl & 0x03000000) != urep); + + return 0; +} + +static int +gm204_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, + u8 type, u32 addr, u8 *data, u8 size) +{ + struct gm204_i2c_aux *aux = gm204_i2c_aux(obj); + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 base = aux->ch * 0x50; + u32 ctrl, stat, timeout, retries; + u32 xbuf[4] = {}; + int ret, i; + + AUX_TRACE(&aux->base, "%d: %08x %d", type, addr, size); + + ret = gm204_i2c_aux_init(aux); + if (ret < 0) + goto out; + + stat = nvkm_rd32(device, 0x00d958 + base); + if (!(stat & 0x10000000)) { + AUX_TRACE(&aux->base, "sink not detected"); + ret = -ENXIO; + goto out; + } + + if (!(type & 1)) { + memcpy(xbuf, data, size); + for (i = 0; i < 16; i += 4) { + AUX_TRACE(&aux->base, "wr %08x", xbuf[i / 4]); + nvkm_wr32(device, 0x00d930 + base + i, xbuf[i / 4]); + } + } + + ctrl = nvkm_rd32(device, 0x00d954 + base); + ctrl &= ~0x0001f0ff; + ctrl |= type << 12; + ctrl |= size - 1; + nvkm_wr32(device, 0x00d950 + base, addr); + + /* (maybe) retry transaction a number of times on failure... */ + for (retries = 0; !ret && retries < 32; retries++) { + /* reset, and delay a while if this is a retry */ + nvkm_wr32(device, 0x00d954 + base, 0x80000000 | ctrl); + nvkm_wr32(device, 0x00d954 + base, 0x00000000 | ctrl); + if (retries) + udelay(400); + + /* transaction request, wait up to 1ms for it to complete */ + nvkm_wr32(device, 0x00d954 + base, 0x00010000 | ctrl); + + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00d954 + base); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "timeout %08x", ctrl); + ret = -EIO; + goto out; + } + } while (ctrl & 0x00010000); + ret = 1; + + /* read status, and check if transaction completed ok */ + stat = nvkm_mask(device, 0x00d958 + base, 0, 0); + if ((stat & 0x000f0000) == 0x00080000 || + (stat & 0x000f0000) == 0x00020000) + ret = retry ? 0 : 1; + if ((stat & 0x00000100)) + ret = -ETIMEDOUT; + if ((stat & 0x00000e00)) + ret = -EIO; + + AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat); + } + + if (type & 1) { + for (i = 0; i < 16; i += 4) { + xbuf[i / 4] = nvkm_rd32(device, 0x00d940 + base + i); + AUX_TRACE(&aux->base, "rd %08x", xbuf[i / 4]); + } + memcpy(data, xbuf, size); + } + +out: + gm204_i2c_aux_fini(aux); + return ret < 0 ? ret : (stat & 0x000f0000) >> 16; +} + +static const struct nvkm_i2c_aux_func +gm204_i2c_aux_func = { + .xfer = gm204_i2c_aux_xfer, +}; + +int +gm204_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive, + struct nvkm_i2c_aux **paux) +{ + struct gm204_i2c_aux *aux; + + if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL))) + return -ENOMEM; + *paux = &aux->base; + + nvkm_i2c_aux_ctor(&gm204_i2c_aux_func, pad, index, &aux->base); + aux->ch = drive; + aux->base.intr = 1 << aux->ch; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 9200f122c..243a71ff0 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -22,328 +22,91 @@ * Authors: Ben Skeggs */ #include "priv.h" +#include "aux.h" +#include "bus.h" #include "pad.h" -#include <core/device.h> #include <core/notify.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> +#include <subdev/bios/i2c.h> -/****************************************************************************** - * interface to linux i2c bit-banging algorithm - *****************************************************************************/ - -#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT -#define CSTMSEL true -#else -#define CSTMSEL false -#endif - -static int -nvkm_i2c_pre_xfer(struct i2c_adapter *adap) +static struct nvkm_i2c_pad * +nvkm_i2c_pad_find(struct nvkm_i2c *i2c, int id) { - struct i2c_algo_bit_data *bit = adap->algo_data; - struct nvkm_i2c_port *port = bit->data; - return nvkm_i2c(port)->acquire(port, bit->timeout); -} + struct nvkm_i2c_pad *pad; -static void -nvkm_i2c_post_xfer(struct i2c_adapter *adap) -{ - struct i2c_algo_bit_data *bit = adap->algo_data; - struct nvkm_i2c_port *port = bit->data; - return nvkm_i2c(port)->release(port); -} - -static void -nvkm_i2c_setscl(void *data, int state) -{ - struct nvkm_i2c_port *port = data; - port->func->drive_scl(port, state); -} - -static void -nvkm_i2c_setsda(void *data, int state) -{ - struct nvkm_i2c_port *port = data; - port->func->drive_sda(port, state); -} - -static int -nvkm_i2c_getscl(void *data) -{ - struct nvkm_i2c_port *port = data; - return port->func->sense_scl(port); -} - -static int -nvkm_i2c_getsda(void *data) -{ - struct nvkm_i2c_port *port = data; - return port->func->sense_sda(port); -} - -/****************************************************************************** - * base i2c "port" class implementation - *****************************************************************************/ - -int -_nvkm_i2c_port_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_i2c_port *port = (void *)object; - struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); - nv_ofuncs(pad)->fini(nv_object(pad), suspend); - return nvkm_object_fini(&port->base, suspend); -} - -void -_nvkm_i2c_port_dtor(struct nvkm_object *object) -{ - struct nvkm_i2c_port *port = (void *)object; - i2c_del_adapter(&port->adapter); - nvkm_object_destroy(&port->base); -} - -int -nvkm_i2c_port_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u8 index, - const struct i2c_algorithm *algo, - const struct nvkm_i2c_func *func, - int size, void **pobject) -{ - struct nvkm_device *device = nv_device(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_i2c_port *port; - int ret; - - ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject); - port = *pobject; - if (ret) - return ret; - - snprintf(port->adapter.name, sizeof(port->adapter.name), - "nvkm-%s-%d", device->name, index); - port->adapter.owner = THIS_MODULE; - port->adapter.dev.parent = nv_device_base(device); - port->index = index; - port->aux = -1; - port->func = func; - mutex_init(&port->mutex); - - if ( algo == &nvkm_i2c_bit_algo && - !nvkm_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { - struct i2c_algo_bit_data *bit; - - bit = kzalloc(sizeof(*bit), GFP_KERNEL); - if (!bit) - return -ENOMEM; - - bit->udelay = 10; - bit->timeout = usecs_to_jiffies(2200); - bit->data = port; - bit->pre_xfer = nvkm_i2c_pre_xfer; - bit->post_xfer = nvkm_i2c_post_xfer; - bit->setsda = nvkm_i2c_setsda; - bit->setscl = nvkm_i2c_setscl; - bit->getsda = nvkm_i2c_getsda; - bit->getscl = nvkm_i2c_getscl; - - port->adapter.algo_data = bit; - ret = i2c_bit_add_bus(&port->adapter); - } else { - port->adapter.algo_data = port; - port->adapter.algo = algo; - ret = i2c_add_adapter(&port->adapter); + list_for_each_entry(pad, &i2c->pad, head) { + if (pad->id == id) + return pad; } - if (ret == 0) - list_add_tail(&port->head, &i2c->ports); - return ret; + return NULL; } -/****************************************************************************** - * base i2c subdev class implementation - *****************************************************************************/ - -static struct nvkm_i2c_port * -nvkm_i2c_find(struct nvkm_i2c *i2c, u8 index) +struct nvkm_i2c_bus * +nvkm_i2c_bus_find(struct nvkm_i2c *i2c, int id) { - struct nvkm_bios *bios = nvkm_bios(i2c); - struct nvkm_i2c_port *port; + struct nvkm_bios *bios = i2c->subdev.device->bios; + struct nvkm_i2c_bus *bus; - if (index == NV_I2C_DEFAULT(0) || - index == NV_I2C_DEFAULT(1)) { + if (id == NVKM_I2C_BUS_PRI || id == NVKM_I2C_BUS_SEC) { u8 ver, hdr, cnt, len; u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len); if (i2c && ver >= 0x30) { - u8 auxidx = nv_ro08(bios, i2c + 4); - if (index == NV_I2C_DEFAULT(0)) - index = (auxidx & 0x0f) >> 0; + u8 auxidx = nvbios_rd08(bios, i2c + 4); + if (id == NVKM_I2C_BUS_PRI) + id = NVKM_I2C_BUS_CCB((auxidx & 0x0f) >> 0); else - index = (auxidx & 0xf0) >> 4; + id = NVKM_I2C_BUS_CCB((auxidx & 0xf0) >> 4); } else { - index = 2; + id = NVKM_I2C_BUS_CCB(2); } } - list_for_each_entry(port, &i2c->ports, head) { - if (port->index == index) - return port; + list_for_each_entry(bus, &i2c->bus, head) { + if (bus->id == id) + return bus; } return NULL; } -static struct nvkm_i2c_port * -nvkm_i2c_find_type(struct nvkm_i2c *i2c, u16 type) +struct nvkm_i2c_aux * +nvkm_i2c_aux_find(struct nvkm_i2c *i2c, int id) { - struct nvkm_i2c_port *port; + struct nvkm_i2c_aux *aux; - list_for_each_entry(port, &i2c->ports, head) { - if (nv_hclass(port) == type) - return port; + list_for_each_entry(aux, &i2c->aux, head) { + if (aux->id == id) + return aux; } return NULL; } static void -nvkm_i2c_release_pad(struct nvkm_i2c_port *port) -{ - struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); - struct nvkm_i2c *i2c = nvkm_i2c(port); - - if (atomic_dec_and_test(&nv_object(pad)->usecount)) { - nv_ofuncs(pad)->fini(nv_object(pad), false); - wake_up_all(&i2c->wait); - } -} - -static int -nvkm_i2c_try_acquire_pad(struct nvkm_i2c_port *port) -{ - struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); - - if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) { - struct nvkm_object *owner = (void *)pad->port; - do { - if (owner == (void *)port) - return 0; - owner = owner->parent; - } while(owner); - nvkm_i2c_release_pad(port); - return -EBUSY; - } - - pad->next = port; - nv_ofuncs(pad)->init(nv_object(pad)); - return 0; -} - -static int -nvkm_i2c_acquire_pad(struct nvkm_i2c_port *port, unsigned long timeout) -{ - struct nvkm_i2c *i2c = nvkm_i2c(port); - - if (timeout) { - if (wait_event_timeout(i2c->wait, - nvkm_i2c_try_acquire_pad(port) == 0, - timeout) == 0) - return -EBUSY; - } else { - wait_event(i2c->wait, nvkm_i2c_try_acquire_pad(port) == 0); - } - - return 0; -} - -static void -nvkm_i2c_release(struct nvkm_i2c_port *port) -__releases(pad->mutex) -{ - nvkm_i2c(port)->release_pad(port); - mutex_unlock(&port->mutex); -} - -static int -nvkm_i2c_acquire(struct nvkm_i2c_port *port, unsigned long timeout) -__acquires(pad->mutex) -{ - int ret; - mutex_lock(&port->mutex); - if ((ret = nvkm_i2c(port)->acquire_pad(port, timeout))) - mutex_unlock(&port->mutex); - return ret; -} - -static int -nvkm_i2c_identify(struct nvkm_i2c *i2c, int index, const char *what, - struct nvkm_i2c_board_info *info, - bool (*match)(struct nvkm_i2c_port *, - struct i2c_board_info *, void *), void *data) -{ - struct nvkm_i2c_port *port = nvkm_i2c_find(i2c, index); - int i; - - if (!port) { - nv_debug(i2c, "no bus when probing %s on %d\n", what, index); - return -ENODEV; - } - - nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index); - for (i = 0; info[i].dev.addr; i++) { - u8 orig_udelay = 0; - - if ((port->adapter.algo == &i2c_bit_algo) && - (info[i].udelay != 0)) { - struct i2c_algo_bit_data *algo = port->adapter.algo_data; - nv_debug(i2c, "using custom udelay %d instead of %d\n", - info[i].udelay, algo->udelay); - orig_udelay = algo->udelay; - algo->udelay = info[i].udelay; - } - - if (nv_probe_i2c(port, info[i].dev.addr) && - (!match || match(port, &info[i].dev, data))) { - nv_info(i2c, "detected %s: %s\n", what, - info[i].dev.type); - return i; - } - - if (orig_udelay) { - struct i2c_algo_bit_data *algo = port->adapter.algo_data; - algo->udelay = orig_udelay; - } - } - - nv_debug(i2c, "no devices found.\n"); - return -ENODEV; -} - -static void -nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int index) +nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int id) { struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event); - struct nvkm_i2c_port *port = i2c->find(i2c, index); - const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass; - if (port && port->aux >= 0) - impl->aux_mask(i2c, type, 1 << port->aux, 0); + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id); + if (aux) + i2c->func->aux_mask(i2c, type, aux->intr, 0); } static void -nvkm_i2c_intr_init(struct nvkm_event *event, int type, int index) +nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id) { struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event); - struct nvkm_i2c_port *port = i2c->find(i2c, index); - const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass; - if (port && port->aux >= 0) - impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux); + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id); + if (aux) + i2c->func->aux_mask(i2c, type, aux->intr, aux->intr); } static int nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) + struct nvkm_notify *notify) { struct nvkm_i2c_ntfy_req *req = data; if (!WARN_ON(size != sizeof(*req))) { @@ -355,38 +118,6 @@ nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size, return -EINVAL; } -static void -nvkm_i2c_intr(struct nvkm_subdev *subdev) -{ - struct nvkm_i2c_impl *impl = (void *)nv_oclass(subdev); - struct nvkm_i2c *i2c = nvkm_i2c(subdev); - struct nvkm_i2c_port *port; - u32 hi, lo, rq, tx, e; - - if (impl->aux_stat) { - impl->aux_stat(i2c, &hi, &lo, &rq, &tx); - if (hi || lo || rq || tx) { - list_for_each_entry(port, &i2c->ports, head) { - if (e = 0, port->aux < 0) - continue; - - if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG; - if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG; - if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ; - if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE; - if (e) { - struct nvkm_i2c_ntfy_rep rep = { - .mask = e, - }; - nvkm_event_send(&i2c->event, rep.mask, - port->index, &rep, - sizeof(rep)); - } - } - } - } -} - static const struct nvkm_event_func nvkm_i2c_intr_func = { .ctor = nvkm_i2c_intr_ctor, @@ -394,229 +125,272 @@ nvkm_i2c_intr_func = { .fini = nvkm_i2c_intr_fini, }; -int -_nvkm_i2c_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_i2c_intr(struct nvkm_subdev *subdev) { - struct nvkm_i2c_impl *impl = (void *)nv_oclass(object); - struct nvkm_i2c *i2c = (void *)object; - struct nvkm_i2c_port *port; - u32 mask; - int ret; + struct nvkm_i2c *i2c = nvkm_i2c(subdev); + struct nvkm_i2c_aux *aux; + u32 hi, lo, rq, tx; + + if (!i2c->func->aux_stat) + return; + + i2c->func->aux_stat(i2c, &hi, &lo, &rq, &tx); + if (!hi && !lo && !rq && !tx) + return; - list_for_each_entry(port, &i2c->ports, head) { - ret = nv_ofuncs(port)->fini(nv_object(port), suspend); - if (ret && suspend) - goto fail; + list_for_each_entry(aux, &i2c->aux, head) { + u32 mask = 0; + if (hi & aux->intr) mask |= NVKM_I2C_PLUG; + if (lo & aux->intr) mask |= NVKM_I2C_UNPLUG; + if (rq & aux->intr) mask |= NVKM_I2C_IRQ; + if (tx & aux->intr) mask |= NVKM_I2C_DONE; + if (mask) { + struct nvkm_i2c_ntfy_rep rep = { + .mask = mask, + }; + nvkm_event_send(&i2c->event, rep.mask, aux->id, + &rep, sizeof(rep)); + } } +} + +static int +nvkm_i2c_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_i2c *i2c = nvkm_i2c(subdev); + struct nvkm_i2c_pad *pad; + u32 mask; - if ((mask = (1 << impl->aux) - 1), impl->aux_stat) { - impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); - impl->aux_stat(i2c, &mask, &mask, &mask, &mask); + if ((mask = (1 << i2c->func->aux) - 1), i2c->func->aux_stat) { + i2c->func->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); + i2c->func->aux_stat(i2c, &mask, &mask, &mask, &mask); } - return nvkm_subdev_fini(&i2c->base, suspend); -fail: - list_for_each_entry_continue_reverse(port, &i2c->ports, head) { - nv_ofuncs(port)->init(nv_object(port)); + list_for_each_entry(pad, &i2c->pad, head) { + nvkm_i2c_pad_fini(pad); } - return ret; + return 0; } -int -_nvkm_i2c_init(struct nvkm_object *object) +static int +nvkm_i2c_init(struct nvkm_subdev *subdev) { - struct nvkm_i2c *i2c = (void *)object; - struct nvkm_i2c_port *port; - int ret; - - ret = nvkm_subdev_init(&i2c->base); - if (ret == 0) { - list_for_each_entry(port, &i2c->ports, head) { - ret = nv_ofuncs(port)->init(nv_object(port)); - if (ret) - goto fail; - } + struct nvkm_i2c *i2c = nvkm_i2c(subdev); + struct nvkm_i2c_bus *bus; + struct nvkm_i2c_pad *pad; + + list_for_each_entry(pad, &i2c->pad, head) { + nvkm_i2c_pad_init(pad); } - return ret; -fail: - list_for_each_entry_continue_reverse(port, &i2c->ports, head) { - nv_ofuncs(port)->fini(nv_object(port), false); + list_for_each_entry(bus, &i2c->bus, head) { + nvkm_i2c_bus_init(bus); } - return ret; + return 0; } -void -_nvkm_i2c_dtor(struct nvkm_object *object) +static void * +nvkm_i2c_dtor(struct nvkm_subdev *subdev) { - struct nvkm_i2c *i2c = (void *)object; - struct nvkm_i2c_port *port, *temp; + struct nvkm_i2c *i2c = nvkm_i2c(subdev); nvkm_event_fini(&i2c->event); - list_for_each_entry_safe(port, temp, &i2c->ports, head) { - nvkm_object_ref(NULL, (struct nvkm_object **)&port); + while (!list_empty(&i2c->aux)) { + struct nvkm_i2c_aux *aux = + list_first_entry(&i2c->aux, typeof(*aux), head); + nvkm_i2c_aux_del(&aux); } - nvkm_subdev_destroy(&i2c->base); -} - -static struct nvkm_oclass * -nvkm_i2c_extdev_sclass[] = { - nvkm_anx9805_sclass, -}; + while (!list_empty(&i2c->bus)) { + struct nvkm_i2c_bus *bus = + list_first_entry(&i2c->bus, typeof(*bus), head); + nvkm_i2c_bus_del(&bus); + } -static void -nvkm_i2c_create_port(struct nvkm_i2c *i2c, int index, u8 type, - struct dcb_i2c_entry *info) -{ - const struct nvkm_i2c_impl *impl = (void *)nv_oclass(i2c); - struct nvkm_oclass *oclass; - struct nvkm_object *parent; - struct nvkm_object *object; - int ret, pad; - - if (info->share != DCB_I2C_UNUSED) { - pad = info->share; - oclass = impl->pad_s; - } else { - if (type != DCB_I2C_NVIO_AUX) - pad = 0x100 + info->drive; - else - pad = 0x100 + info->auxch; - oclass = impl->pad_x; + while (!list_empty(&i2c->pad)) { + struct nvkm_i2c_pad *pad = + list_first_entry(&i2c->pad, typeof(*pad), head); + nvkm_i2c_pad_del(&pad); } - ret = nvkm_object_ctor(nv_object(i2c), NULL, oclass, - NULL, pad, &parent); - if (ret < 0) - return; + return i2c; +} - oclass = impl->sclass; - do { - ret = -EINVAL; - if (oclass->handle == type) { - ret = nvkm_object_ctor(parent, NULL, oclass, - info, index, &object); - } - } while (ret && (++oclass)->handle); +static const struct nvkm_subdev_func +nvkm_i2c = { + .dtor = nvkm_i2c_dtor, + .init = nvkm_i2c_init, + .fini = nvkm_i2c_fini, + .intr = nvkm_i2c_intr, +}; - nvkm_object_ref(NULL, &parent); +static const struct nvkm_i2c_drv { + u8 bios; + u8 addr; + int (*pad_new)(struct nvkm_i2c_bus *, int id, u8 addr, + struct nvkm_i2c_pad **); } +nvkm_i2c_drv[] = { + { 0x0d, 0x39, anx9805_pad_new }, + { 0x0e, 0x3b, anx9805_pad_new }, + {} +}; int -nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, + int index, struct nvkm_i2c **pi2c) { - struct nvkm_bios *bios = nvkm_bios(parent); + struct nvkm_bios *bios = device->bios; struct nvkm_i2c *i2c; - struct nvkm_object *object; - struct dcb_i2c_entry info; - int ret, i, j, index = -1; - struct dcb_output outp; - u8 ver, hdr; - u32 data; - - ret = nvkm_subdev_create(parent, engine, oclass, 0, "I2C", "i2c", &i2c); - *pobject = nv_object(i2c); - if (ret) - return ret; - - nv_subdev(i2c)->intr = nvkm_i2c_intr; - i2c->find = nvkm_i2c_find; - i2c->find_type = nvkm_i2c_find_type; - i2c->acquire_pad = nvkm_i2c_acquire_pad; - i2c->release_pad = nvkm_i2c_release_pad; - i2c->acquire = nvkm_i2c_acquire; - i2c->release = nvkm_i2c_release; - i2c->identify = nvkm_i2c_identify; - init_waitqueue_head(&i2c->wait); - INIT_LIST_HEAD(&i2c->ports); - - while (!dcb_i2c_parse(bios, ++index, &info)) { - switch (info.type) { - case DCB_I2C_NV04_BIT: - case DCB_I2C_NV4E_BIT: - case DCB_I2C_NVIO_BIT: - nvkm_i2c_create_port(i2c, NV_I2C_PORT(index), - info.type, &info); - break; - case DCB_I2C_NVIO_AUX: - nvkm_i2c_create_port(i2c, NV_I2C_AUX(index), - info.type, &info); - break; - case DCB_I2C_PMGR: - if (info.drive != DCB_I2C_UNUSED) { - nvkm_i2c_create_port(i2c, NV_I2C_PORT(index), - DCB_I2C_NVIO_BIT, &info); - } - if (info.auxch != DCB_I2C_UNUSED) { - nvkm_i2c_create_port(i2c, NV_I2C_AUX(index), - DCB_I2C_NVIO_AUX, &info); - } - break; - case DCB_I2C_UNUSED: - default: + struct dcb_i2c_entry ccbE; + struct dcb_output dcbE; + u8 ver, hdr; + int ret, i; + + if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_i2c, device, index, 0, &i2c->subdev); + i2c->func = func; + INIT_LIST_HEAD(&i2c->pad); + INIT_LIST_HEAD(&i2c->bus); + INIT_LIST_HEAD(&i2c->aux); + + i = -1; + while (!dcb_i2c_parse(bios, ++i, &ccbE)) { + struct nvkm_i2c_pad *pad = NULL; + struct nvkm_i2c_bus *bus = NULL; + struct nvkm_i2c_aux *aux = NULL; + + nvkm_debug(&i2c->subdev, "ccb %02x: type %02x drive %02x " + "sense %02x share %02x auxch %02x\n", i, ccbE.type, + ccbE.drive, ccbE.sense, ccbE.share, ccbE.auxch); + + if (ccbE.share != DCB_I2C_UNUSED) { + const int id = NVKM_I2C_PAD_HYBRID(ccbE.share); + if (!(pad = nvkm_i2c_pad_find(i2c, id))) + ret = func->pad_s_new(i2c, id, &pad); + else + ret = 0; + } else { + ret = func->pad_x_new(i2c, NVKM_I2C_PAD_CCB(i), &pad); + } + + if (ret) { + nvkm_error(&i2c->subdev, "ccb %02x pad, %d\n", i, ret); + nvkm_i2c_pad_del(&pad); + continue; + } + + if (pad->func->bus_new_0 && ccbE.type == DCB_I2C_NV04_BIT) { + ret = pad->func->bus_new_0(pad, NVKM_I2C_BUS_CCB(i), + ccbE.drive, + ccbE.sense, &bus); + } else + if (pad->func->bus_new_4 && + ( ccbE.type == DCB_I2C_NV4E_BIT || + ccbE.type == DCB_I2C_NVIO_BIT || + (ccbE.type == DCB_I2C_PMGR && + ccbE.drive != DCB_I2C_UNUSED))) { + ret = pad->func->bus_new_4(pad, NVKM_I2C_BUS_CCB(i), + ccbE.drive, &bus); + } + + if (ret) { + nvkm_error(&i2c->subdev, "ccb %02x bus, %d\n", i, ret); + nvkm_i2c_bus_del(&bus); + } + + if (pad->func->aux_new_6 && + ( ccbE.type == DCB_I2C_NVIO_AUX || + (ccbE.type == DCB_I2C_PMGR && + ccbE.auxch != DCB_I2C_UNUSED))) { + ret = pad->func->aux_new_6(pad, NVKM_I2C_BUS_CCB(i), + ccbE.auxch, &aux); + } else { + ret = 0; + } + + if (ret) { + nvkm_error(&i2c->subdev, "ccb %02x aux, %d\n", i, ret); + nvkm_i2c_aux_del(&aux); + } + + if (ccbE.type != DCB_I2C_UNUSED && !bus && !aux) { + nvkm_warn(&i2c->subdev, "ccb %02x was ignored\n", i); continue; } } - /* in addition to the busses specified in the i2c table, there - * may be ddc/aux channels hiding behind external tmds/dp/etc - * transmitters. - */ - index = NV_I2C_EXT(0); i = -1; - while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) { - if (!outp.location || !outp.extdev) + while (dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE)) { + const struct nvkm_i2c_drv *drv = nvkm_i2c_drv; + struct nvkm_i2c_bus *bus; + struct nvkm_i2c_pad *pad; + + /* internal outputs handled by native i2c busses (above) */ + if (!dcbE.location) continue; - switch (outp.type) { - case DCB_OUTPUT_TMDS: - info.type = NV_I2C_TYPE_EXTDDC(outp.extdev); - break; - case DCB_OUTPUT_DP: - info.type = NV_I2C_TYPE_EXTAUX(outp.extdev); - break; - default: + /* we need an i2c bus to talk to the external encoder */ + bus = nvkm_i2c_bus_find(i2c, dcbE.i2c_index); + if (!bus) { + nvkm_debug(&i2c->subdev, "dcb %02x no bus\n", i); continue; } - ret = -ENODEV; - j = -1; - while (ret && ++j < ARRAY_SIZE(nvkm_i2c_extdev_sclass)) { - parent = nv_object(i2c->find(i2c, outp.i2c_index)); - oclass = nvkm_i2c_extdev_sclass[j]; - do { - if (oclass->handle != info.type) - continue; - ret = nvkm_object_ctor(parent, NULL, oclass, - NULL, index++, &object); - } while (ret && (++oclass)->handle); + /* ... and a driver for it */ + while (drv->pad_new) { + if (drv->bios == dcbE.extdev) + break; + drv++; } - } - ret = nvkm_event_init(&nvkm_i2c_intr_func, 4, index, &i2c->event); - if (ret) - return ret; - - return 0; -} + if (!drv->pad_new) { + nvkm_debug(&i2c->subdev, "dcb %02x drv %02x unknown\n", + i, dcbE.extdev); + continue; + } -int -_nvkm_i2c_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_i2c *i2c; - int ret; + /* find/create an instance of the driver */ + pad = nvkm_i2c_pad_find(i2c, NVKM_I2C_PAD_EXT(dcbE.extdev)); + if (!pad) { + const int id = NVKM_I2C_PAD_EXT(dcbE.extdev); + ret = drv->pad_new(bus, id, drv->addr, &pad); + if (ret) { + nvkm_error(&i2c->subdev, "dcb %02x pad, %d\n", + i, ret); + nvkm_i2c_pad_del(&pad); + continue; + } + } - ret = nvkm_i2c_create(parent, engine, oclass, &i2c); - *pobject = nv_object(i2c); - if (ret) - return ret; + /* create any i2c bus / aux channel required by the output */ + if (pad->func->aux_new_6 && dcbE.type == DCB_OUTPUT_DP) { + const int id = NVKM_I2C_AUX_EXT(dcbE.extdev); + struct nvkm_i2c_aux *aux = NULL; + ret = pad->func->aux_new_6(pad, id, 0, &aux); + if (ret) { + nvkm_error(&i2c->subdev, "dcb %02x aux, %d\n", + i, ret); + nvkm_i2c_aux_del(&aux); + } + } else + if (pad->func->bus_new_4) { + const int id = NVKM_I2C_BUS_EXT(dcbE.extdev); + struct nvkm_i2c_bus *bus = NULL; + ret = pad->func->bus_new_4(pad, id, 0, &bus); + if (ret) { + nvkm_error(&i2c->subdev, "dcb %02x bus, %d\n", + i, ret); + nvkm_i2c_bus_del(&bus); + } + } + } - return 0; + return nvkm_event_init(&nvkm_i2c_intr_func, 4, i, &i2c->event); } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c index 861a453d2..cdce11bba 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c @@ -9,7 +9,7 @@ * 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. + * all copies or substantial busions 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, @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "bus.h" #ifdef CONFIG_NOUVEAU_I2C_INTERNAL #define T_TIMEOUT 2200000 @@ -29,205 +29,188 @@ #define T_HOLD 5000 static inline void -i2c_drive_scl(struct nvkm_i2c_port *port, int state) +nvkm_i2c_drive_scl(struct nvkm_i2c_bus *bus, int state) { - port->func->drive_scl(port, state); + bus->func->drive_scl(bus, state); } static inline void -i2c_drive_sda(struct nvkm_i2c_port *port, int state) +nvkm_i2c_drive_sda(struct nvkm_i2c_bus *bus, int state) { - port->func->drive_sda(port, state); + bus->func->drive_sda(bus, state); } static inline int -i2c_sense_scl(struct nvkm_i2c_port *port) +nvkm_i2c_sense_scl(struct nvkm_i2c_bus *bus) { - return port->func->sense_scl(port); + return bus->func->sense_scl(bus); } static inline int -i2c_sense_sda(struct nvkm_i2c_port *port) +nvkm_i2c_sense_sda(struct nvkm_i2c_bus *bus) { - return port->func->sense_sda(port); + return bus->func->sense_sda(bus); } static void -i2c_delay(struct nvkm_i2c_port *port, u32 nsec) +nvkm_i2c_delay(struct nvkm_i2c_bus *bus, u32 nsec) { udelay((nsec + 500) / 1000); } static bool -i2c_raise_scl(struct nvkm_i2c_port *port) +nvkm_i2c_raise_scl(struct nvkm_i2c_bus *bus) { u32 timeout = T_TIMEOUT / T_RISEFALL; - i2c_drive_scl(port, 1); + nvkm_i2c_drive_scl(bus, 1); do { - i2c_delay(port, T_RISEFALL); - } while (!i2c_sense_scl(port) && --timeout); + nvkm_i2c_delay(bus, T_RISEFALL); + } while (!nvkm_i2c_sense_scl(bus) && --timeout); return timeout != 0; } static int -i2c_start(struct nvkm_i2c_port *port) +i2c_start(struct nvkm_i2c_bus *bus) { int ret = 0; - if (!i2c_sense_scl(port) || - !i2c_sense_sda(port)) { - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 1); - if (!i2c_raise_scl(port)) + if (!nvkm_i2c_sense_scl(bus) || + !nvkm_i2c_sense_sda(bus)) { + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_drive_sda(bus, 1); + if (!nvkm_i2c_raise_scl(bus)) ret = -EBUSY; } - i2c_drive_sda(port, 0); - i2c_delay(port, T_HOLD); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_sda(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); return ret; } static void -i2c_stop(struct nvkm_i2c_port *port) +i2c_stop(struct nvkm_i2c_bus *bus) { - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 0); - i2c_delay(port, T_RISEFALL); - - i2c_drive_scl(port, 1); - i2c_delay(port, T_HOLD); - i2c_drive_sda(port, 1); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_drive_sda(bus, 0); + nvkm_i2c_delay(bus, T_RISEFALL); + + nvkm_i2c_drive_scl(bus, 1); + nvkm_i2c_delay(bus, T_HOLD); + nvkm_i2c_drive_sda(bus, 1); + nvkm_i2c_delay(bus, T_HOLD); } static int -i2c_bitw(struct nvkm_i2c_port *port, int sda) +i2c_bitw(struct nvkm_i2c_bus *bus, int sda) { - i2c_drive_sda(port, sda); - i2c_delay(port, T_RISEFALL); + nvkm_i2c_drive_sda(bus, sda); + nvkm_i2c_delay(bus, T_RISEFALL); - if (!i2c_raise_scl(port)) + if (!nvkm_i2c_raise_scl(bus)) return -ETIMEDOUT; - i2c_delay(port, T_HOLD); + nvkm_i2c_delay(bus, T_HOLD); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); return 0; } static int -i2c_bitr(struct nvkm_i2c_port *port) +i2c_bitr(struct nvkm_i2c_bus *bus) { int sda; - i2c_drive_sda(port, 1); - i2c_delay(port, T_RISEFALL); + nvkm_i2c_drive_sda(bus, 1); + nvkm_i2c_delay(bus, T_RISEFALL); - if (!i2c_raise_scl(port)) + if (!nvkm_i2c_raise_scl(bus)) return -ETIMEDOUT; - i2c_delay(port, T_HOLD); + nvkm_i2c_delay(bus, T_HOLD); - sda = i2c_sense_sda(port); + sda = nvkm_i2c_sense_sda(bus); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); return sda; } static int -i2c_get_byte(struct nvkm_i2c_port *port, u8 *byte, bool last) +nvkm_i2c_get_byte(struct nvkm_i2c_bus *bus, u8 *byte, bool last) { int i, bit; *byte = 0; for (i = 7; i >= 0; i--) { - bit = i2c_bitr(port); + bit = i2c_bitr(bus); if (bit < 0) return bit; *byte |= bit << i; } - return i2c_bitw(port, last ? 1 : 0); + return i2c_bitw(bus, last ? 1 : 0); } static int -i2c_put_byte(struct nvkm_i2c_port *port, u8 byte) +nvkm_i2c_put_byte(struct nvkm_i2c_bus *bus, u8 byte) { int i, ret; for (i = 7; i >= 0; i--) { - ret = i2c_bitw(port, !!(byte & (1 << i))); + ret = i2c_bitw(bus, !!(byte & (1 << i))); if (ret < 0) return ret; } - ret = i2c_bitr(port); + ret = i2c_bitr(bus); if (ret == 1) /* nack */ ret = -EIO; return ret; } static int -i2c_addr(struct nvkm_i2c_port *port, struct i2c_msg *msg) +i2c_addr(struct nvkm_i2c_bus *bus, struct i2c_msg *msg) { u32 addr = msg->addr << 1; if (msg->flags & I2C_M_RD) addr |= 1; - return i2c_put_byte(port, addr); + return nvkm_i2c_put_byte(bus, addr); } -static int -i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +int +nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *bus, struct i2c_msg *msgs, int num) { - struct nvkm_i2c_port *port = adap->algo_data; struct i2c_msg *msg = msgs; int ret = 0, mcnt = num; - ret = nvkm_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT)); - if (ret) - return ret; - while (!ret && mcnt--) { u8 remaining = msg->len; u8 *ptr = msg->buf; - ret = i2c_start(port); + ret = i2c_start(bus); if (ret == 0) - ret = i2c_addr(port, msg); + ret = i2c_addr(bus, msg); if (msg->flags & I2C_M_RD) { while (!ret && remaining--) - ret = i2c_get_byte(port, ptr++, !remaining); + ret = nvkm_i2c_get_byte(bus, ptr++, !remaining); } else { while (!ret && remaining--) - ret = i2c_put_byte(port, *ptr++); + ret = nvkm_i2c_put_byte(bus, *ptr++); } msg++; } - i2c_stop(port); - nvkm_i2c(port)->release(port); + i2c_stop(bus); return (ret < 0) ? ret : num; } #else -static int -i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +int +nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *bus, struct i2c_msg *msgs, int num) { return -ENODEV; } #endif - -static u32 -i2c_bit_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -const struct i2c_algorithm nvkm_i2c_bit_algo = { - .master_xfer = i2c_bit_xfer, - .functionality = i2c_bit_func -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c new file mode 100644 index 000000000..807a2b67b --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c @@ -0,0 +1,245 @@ +/* + * Copyright 2015 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 "bus.h" +#include "pad.h" + +#include <core/option.h> + +/******************************************************************************* + * i2c-algo-bit + ******************************************************************************/ +static int +nvkm_i2c_bus_pre_xfer(struct i2c_adapter *adap) +{ + struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c); + return nvkm_i2c_bus_acquire(bus); +} + +static void +nvkm_i2c_bus_post_xfer(struct i2c_adapter *adap) +{ + struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c); + return nvkm_i2c_bus_release(bus); +} + +static void +nvkm_i2c_bus_setscl(void *data, int state) +{ + struct nvkm_i2c_bus *bus = data; + bus->func->drive_scl(bus, state); +} + +static void +nvkm_i2c_bus_setsda(void *data, int state) +{ + struct nvkm_i2c_bus *bus = data; + bus->func->drive_sda(bus, state); +} + +static int +nvkm_i2c_bus_getscl(void *data) +{ + struct nvkm_i2c_bus *bus = data; + return bus->func->sense_scl(bus); +} + +static int +nvkm_i2c_bus_getsda(void *data) +{ + struct nvkm_i2c_bus *bus = data; + return bus->func->sense_sda(bus); +} + +/******************************************************************************* + * !i2c-algo-bit (off-chip i2c bus / hw i2c / internal bit-banging algo) + ******************************************************************************/ +static int +nvkm_i2c_bus_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c); + int ret; + + ret = nvkm_i2c_bus_acquire(bus); + if (ret) + return ret; + + ret = bus->func->xfer(bus, msgs, num); + nvkm_i2c_bus_release(bus); + return ret; +} + +static u32 +nvkm_i2c_bus_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm +nvkm_i2c_bus_algo = { + .master_xfer = nvkm_i2c_bus_xfer, + .functionality = nvkm_i2c_bus_func, +}; + +/******************************************************************************* + * nvkm_i2c_bus base + ******************************************************************************/ +void +nvkm_i2c_bus_init(struct nvkm_i2c_bus *bus) +{ + BUS_TRACE(bus, "init"); + if (bus->func->init) + bus->func->init(bus); +} + +void +nvkm_i2c_bus_release(struct nvkm_i2c_bus *bus) +{ + struct nvkm_i2c_pad *pad = bus->pad; + BUS_TRACE(bus, "release"); + nvkm_i2c_pad_release(pad); + mutex_unlock(&bus->mutex); +} + +int +nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *bus) +{ + struct nvkm_i2c_pad *pad = bus->pad; + int ret; + BUS_TRACE(bus, "acquire"); + mutex_lock(&bus->mutex); + ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C); + if (ret) + mutex_unlock(&bus->mutex); + return ret; +} + +int +nvkm_i2c_bus_probe(struct nvkm_i2c_bus *bus, const char *what, + struct nvkm_i2c_bus_probe *info, + bool (*match)(struct nvkm_i2c_bus *, + struct i2c_board_info *, void *), void *data) +{ + int i; + + BUS_DBG(bus, "probing %ss", what); + for (i = 0; info[i].dev.addr; i++) { + u8 orig_udelay = 0; + + if ((bus->i2c.algo == &i2c_bit_algo) && (info[i].udelay != 0)) { + struct i2c_algo_bit_data *algo = bus->i2c.algo_data; + BUS_DBG(bus, "%dms delay instead of %dms", + info[i].udelay, algo->udelay); + orig_udelay = algo->udelay; + algo->udelay = info[i].udelay; + } + + if (nvkm_probe_i2c(&bus->i2c, info[i].dev.addr) && + (!match || match(bus, &info[i].dev, data))) { + BUS_DBG(bus, "detected %s: %s", + what, info[i].dev.type); + return i; + } + + if (orig_udelay) { + struct i2c_algo_bit_data *algo = bus->i2c.algo_data; + algo->udelay = orig_udelay; + } + } + + BUS_DBG(bus, "no devices found."); + return -ENODEV; +} + +void +nvkm_i2c_bus_del(struct nvkm_i2c_bus **pbus) +{ + struct nvkm_i2c_bus *bus = *pbus; + if (bus && !WARN_ON(!bus->func)) { + BUS_TRACE(bus, "dtor"); + list_del(&bus->head); + i2c_del_adapter(&bus->i2c); + kfree(bus->i2c.algo_data); + kfree(*pbus); + *pbus = NULL; + } +} + +int +nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_bus *bus) +{ + struct nvkm_device *device = pad->i2c->subdev.device; + struct i2c_algo_bit_data *bit; +#ifndef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT + const bool internal = false; +#else + const bool internal = true; +#endif + int ret; + + bus->func = func; + bus->pad = pad; + bus->id = id; + mutex_init(&bus->mutex); + list_add_tail(&bus->head, &pad->i2c->bus); + BUS_TRACE(bus, "ctor"); + + snprintf(bus->i2c.name, sizeof(bus->i2c.name), "nvkm-%s-bus-%04x", + dev_name(device->dev), id); + bus->i2c.owner = THIS_MODULE; + bus->i2c.dev.parent = device->dev; + + if ( bus->func->drive_scl && + !nvkm_boolopt(device->cfgopt, "NvI2C", internal)) { + if (!(bit = kzalloc(sizeof(*bit), GFP_KERNEL))) + return -ENOMEM; + bit->udelay = 10; + bit->timeout = usecs_to_jiffies(2200); + bit->data = bus; + bit->pre_xfer = nvkm_i2c_bus_pre_xfer; + bit->post_xfer = nvkm_i2c_bus_post_xfer; + bit->setscl = nvkm_i2c_bus_setscl; + bit->setsda = nvkm_i2c_bus_setsda; + bit->getscl = nvkm_i2c_bus_getscl; + bit->getsda = nvkm_i2c_bus_getsda; + bus->i2c.algo_data = bit; + ret = i2c_bit_add_bus(&bus->i2c); + } else { + bus->i2c.algo = &nvkm_i2c_bus_algo; + ret = i2c_add_adapter(&bus->i2c); + } + + return ret; +} + +int +nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_bus **pbus) +{ + if (!(*pbus = kzalloc(sizeof(**pbus), GFP_KERNEL))) + return -ENOMEM; + return nvkm_i2c_bus_ctor(func, pad, id, *pbus); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h new file mode 100644 index 000000000..e1be14c23 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h @@ -0,0 +1,37 @@ +#ifndef __NVKM_I2C_BUS_H__ +#define __NVKM_I2C_BUS_H__ +#include "pad.h" + +struct nvkm_i2c_bus_func { + void (*init)(struct nvkm_i2c_bus *); + void (*drive_scl)(struct nvkm_i2c_bus *, int state); + void (*drive_sda)(struct nvkm_i2c_bus *, int state); + int (*sense_scl)(struct nvkm_i2c_bus *); + int (*sense_sda)(struct nvkm_i2c_bus *); + int (*xfer)(struct nvkm_i2c_bus *, struct i2c_msg *, int num); +}; + +int nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_bus *); +int nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_bus **); +void nvkm_i2c_bus_del(struct nvkm_i2c_bus **); +void nvkm_i2c_bus_init(struct nvkm_i2c_bus *); + +int nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *, struct i2c_msg *, int); + +int nv04_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, u8, + struct nvkm_i2c_bus **); + +int nv4e_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **); +int nv50_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **); +int gf119_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **); + +#define BUS_MSG(b,l,f,a...) do { \ + struct nvkm_i2c_bus *_bus = (b); \ + nvkm_##l(&_bus->pad->i2c->subdev, "bus %04x: "f"\n", _bus->id, ##a); \ +} while(0) +#define BUS_ERR(b,f,a...) BUS_MSG((b), error, f, ##a) +#define BUS_DBG(b,f,a...) BUS_MSG((b), debug, f, ##a) +#define BUS_TRACE(b,f,a...) BUS_MSG((b), trace, f, ##a) +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c new file mode 100644 index 000000000..96bbdda0f --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c @@ -0,0 +1,95 @@ +/* + * Copyright 2015 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 busions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#define gf119_i2c_bus(p) container_of((p), struct gf119_i2c_bus, base) +#include "bus.h" + +struct gf119_i2c_bus { + struct nvkm_i2c_bus base; + u32 addr; +}; + +static void +gf119_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x00000001, state ? 0x00000001 : 0); +} + +static void +gf119_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x00000002, state ? 0x00000002 : 0); +} + +static int +gf119_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000010); +} + +static int +gf119_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000020); +} + +static void +gf119_i2c_bus_init(struct nvkm_i2c_bus *base) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_wr32(device, bus->addr, 0x00000007); +} + +static const struct nvkm_i2c_bus_func +gf119_i2c_bus_func = { + .init = gf119_i2c_bus_init, + .drive_scl = gf119_i2c_bus_drive_scl, + .drive_sda = gf119_i2c_bus_drive_sda, + .sense_scl = gf119_i2c_bus_sense_scl, + .sense_sda = gf119_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +gf119_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + struct gf119_i2c_bus *bus; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&gf119_i2c_bus_func, pad, id, &bus->base); + bus->addr = 0x00d014 + (drive * 0x20); + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c new file mode 100644 index 000000000..a58db1592 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c @@ -0,0 +1,96 @@ +/* + * Copyright 2015 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 busions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#define nv04_i2c_bus(p) container_of((p), struct nv04_i2c_bus, base) +#include "bus.h" + +#include <subdev/vga.h> + +struct nv04_i2c_bus { + struct nvkm_i2c_bus base; + u8 drive; + u8 sense; +}; + +static void +nv04_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + u8 val = nvkm_rdvgac(device, 0, bus->drive); + if (state) val |= 0x20; + else val &= 0xdf; + nvkm_wrvgac(device, 0, bus->drive, val | 0x01); +} + +static void +nv04_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + u8 val = nvkm_rdvgac(device, 0, bus->drive); + if (state) val |= 0x10; + else val &= 0xef; + nvkm_wrvgac(device, 0, bus->drive, val | 0x01); +} + +static int +nv04_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rdvgac(device, 0, bus->sense) & 0x04); +} + +static int +nv04_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rdvgac(device, 0, bus->sense) & 0x08); +} + +static const struct nvkm_i2c_bus_func +nv04_i2c_bus_func = { + .drive_scl = nv04_i2c_bus_drive_scl, + .drive_sda = nv04_i2c_bus_drive_sda, + .sense_scl = nv04_i2c_bus_sense_scl, + .sense_sda = nv04_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +nv04_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, u8 sense, + struct nvkm_i2c_bus **pbus) +{ + struct nv04_i2c_bus *bus; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&nv04_i2c_bus_func, pad, id, &bus->base); + bus->drive = drive; + bus->sense = sense; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c new file mode 100644 index 000000000..cdd73dcb1 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c @@ -0,0 +1,86 @@ +/* + * Copyright 2015 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 busions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#define nv4e_i2c_bus(p) container_of((p), struct nv4e_i2c_bus, base) +#include "bus.h" + +struct nv4e_i2c_bus { + struct nvkm_i2c_bus base; + u32 addr; +}; + +static void +nv4e_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x2f, state ? 0x21 : 0x01); +} + +static void +nv4e_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x1f, state ? 0x11 : 0x01); +} + +static int +nv4e_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00040000); +} + +static int +nv4e_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00080000); +} + +static const struct nvkm_i2c_bus_func +nv4e_i2c_bus_func = { + .drive_scl = nv4e_i2c_bus_drive_scl, + .drive_sda = nv4e_i2c_bus_drive_sda, + .sense_scl = nv4e_i2c_bus_sense_scl, + .sense_sda = nv4e_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +nv4e_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + struct nv4e_i2c_bus *bus; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&nv4e_i2c_bus_func, pad, id, &bus->base); + bus->addr = 0x600800 + drive; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c new file mode 100644 index 000000000..8db839938 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c @@ -0,0 +1,113 @@ +/* + * Copyright 2015 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 busions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ +#define nv50_i2c_bus(p) container_of((p), struct nv50_i2c_bus, base) +#include "bus.h" + +#include <subdev/vga.h> + +struct nv50_i2c_bus { + struct nvkm_i2c_bus base; + u32 addr; + u32 data; +}; + +static void +nv50_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + if (state) bus->data |= 0x01; + else bus->data &= 0xfe; + nvkm_wr32(device, bus->addr, bus->data); +} + +static void +nv50_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + if (state) bus->data |= 0x02; + else bus->data &= 0xfd; + nvkm_wr32(device, bus->addr, bus->data); +} + +static int +nv50_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000001); +} + +static int +nv50_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000002); +} + +static void +nv50_i2c_bus_init(struct nvkm_i2c_bus *base) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_wr32(device, bus->addr, (bus->data = 0x00000007)); +} + +static const struct nvkm_i2c_bus_func +nv50_i2c_bus_func = { + .init = nv50_i2c_bus_init, + .drive_scl = nv50_i2c_bus_drive_scl, + .drive_sda = nv50_i2c_bus_drive_sda, + .sense_scl = nv50_i2c_bus_sense_scl, + .sense_sda = nv50_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +nv50_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + static const u32 addr[] = { + 0x00e138, 0x00e150, 0x00e168, 0x00e180, + 0x00e254, 0x00e274, 0x00e764, 0x00e780, + 0x00e79c, 0x00e7b8 + }; + struct nv50_i2c_bus *bus; + + if (drive >= ARRAY_SIZE(addr)) { + nvkm_warn(&pad->i2c->subdev, "bus %d unknown\n", drive); + return -ENODEV; + } + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&nv50_i2c_bus_func, pad, id, &bus->base); + bus->addr = addr[drive]; + bus->data = 0x00000007; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c index 2a2dd47b9..bb2a31d88 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c @@ -21,26 +21,29 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "priv.h" +#include "pad.h" void g94_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) { - u32 intr = nv_rd32(i2c, 0x00e06c); - u32 stat = nv_rd32(i2c, 0x00e068) & intr, i; + struct nvkm_device *device = i2c->subdev.device; + u32 intr = nvkm_rd32(device, 0x00e06c); + u32 stat = nvkm_rd32(device, 0x00e068) & intr, i; for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { if ((stat & (1 << (i * 4)))) *hi |= 1 << i; if ((stat & (2 << (i * 4)))) *lo |= 1 << i; if ((stat & (4 << (i * 4)))) *rq |= 1 << i; if ((stat & (8 << (i * 4)))) *tx |= 1 << i; } - nv_wr32(i2c, 0x00e06c, intr); + nvkm_wr32(device, 0x00e06c, intr); } void g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) { - u32 temp = nv_rd32(i2c, 0x00e068), i; + struct nvkm_device *device = i2c->subdev.device; + u32 temp = nvkm_rd32(device, 0x00e068), i; for (i = 0; i < 8; i++) { if (mask & (1 << i)) { if (!(data & (1 << i))) { @@ -50,230 +53,20 @@ g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) temp |= type << (i * 4); } } - nv_wr32(i2c, 0x00e068, temp); -} - -#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) - -static void -auxch_fini(struct nvkm_i2c *aux, int ch) -{ - nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); -} - -static int -auxch_init(struct nvkm_i2c *aux, int ch) -{ - const u32 unksel = 1; /* nfi which to use, or if it matters.. */ - const u32 ureq = unksel ? 0x00100000 : 0x00200000; - const u32 urep = unksel ? 0x01000000 : 0x02000000; - u32 ctrl, timeout; - - /* wait up to 1ms for any previous transaction to be done... */ - timeout = 1000; - do { - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("begin idle timeout 0x%08x\n", ctrl); - return -EBUSY; - } - } while (ctrl & 0x03010000); - - /* set some magic, and wait up to 1ms for it to appear */ - nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); - timeout = 1000; - do { - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("magic wait 0x%08x\n", ctrl); - auxch_fini(aux, ch); - return -EBUSY; - } - } while ((ctrl & 0x03000000) != urep); - - return 0; -} - -int -g94_aux(struct nvkm_i2c_port *base, bool retry, - u8 type, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *aux = nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - u32 ctrl, stat, timeout, retries; - u32 xbuf[4] = {}; - int ch = port->addr; - int ret, i; - - AUX_DBG("%d: 0x%08x %d\n", type, addr, size); - - ret = auxch_init(aux, ch); - if (ret) - goto out; - - stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50)); - if (!(stat & 0x10000000)) { - AUX_DBG("sink not detected\n"); - ret = -ENXIO; - goto out; - } - - if (!(type & 1)) { - memcpy(xbuf, data, size); - for (i = 0; i < 16; i += 4) { - AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); - nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); - } - } - - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); - ctrl &= ~0x0001f0ff; - ctrl |= type << 12; - ctrl |= size - 1; - nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); - - /* (maybe) retry transaction a number of times on failure... */ - for (retries = 0; !ret && retries < 32; retries++) { - /* reset, and delay a while if this is a retry */ - nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); - nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); - if (retries) - udelay(400); - - /* transaction request, wait up to 1ms for it to complete */ - nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); - - timeout = 1000; - do { - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("tx req timeout 0x%08x\n", ctrl); - ret = -EIO; - goto out; - } - } while (ctrl & 0x00010000); - ret = 1; - - /* read status, and check if transaction completed ok */ - stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); - if ((stat & 0x000f0000) == 0x00080000 || - (stat & 0x000f0000) == 0x00020000) - ret = retry ? 0 : 1; - if ((stat & 0x00000100)) - ret = -ETIMEDOUT; - if ((stat & 0x00000e00)) - ret = -EIO; - - AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); - } - - if (type & 1) { - for (i = 0; i < 16; i += 4) { - xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i); - AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); - } - memcpy(data, xbuf, size); - } - -out: - auxch_fini(aux, ch); - return ret < 0 ? ret : (stat & 0x000f0000) >> 16; + nvkm_wr32(device, 0x00e068, temp); } static const struct nvkm_i2c_func -g94_i2c_func = { - .drive_scl = nv50_i2c_drive_scl, - .drive_sda = nv50_i2c_drive_sda, - .sense_scl = nv50_i2c_sense_scl, - .sense_sda = nv50_i2c_sense_sda, -}; - -static int -g94_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &g94_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - if (info->drive >= nv50_i2c_addr_nr) - return -EINVAL; - - port->state = 7; - port->addr = nv50_i2c_addr[info->drive]; - return 0; -} - -static const struct nvkm_i2c_func -g94_aux_func = { - .aux = g94_aux, +g94_i2c = { + .pad_x_new = g94_i2c_pad_x_new, + .pad_s_new = g94_i2c_pad_s_new, + .aux = 4, + .aux_stat = g94_aux_stat, + .aux_mask = g94_aux_mask, }; int -g94_aux_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +g94_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) { - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_aux_algo, &g94_aux_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->base.aux = info->auxch; - port->addr = info->auxch; - return 0; + return nvkm_i2c_new_(&g94_i2c, device, index, pi2c); } - -static struct nvkm_oclass -g94_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_aux_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; - -struct nvkm_oclass * -g94_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = g94_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &g94_i2c_pad_oclass, - .aux = 4, - .aux_stat = g94_aux_stat, - .aux_mask = g94_aux_mask, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c deleted file mode 100644 index 4d4ac6638..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "nv50.h" - -static int -gf110_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000010); -} - -static int -gf110_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000020); -} - -static const struct nvkm_i2c_func -gf110_i2c_func = { - .drive_scl = nv50_i2c_drive_scl, - .drive_sda = nv50_i2c_drive_sda, - .sense_scl = gf110_i2c_sense_scl, - .sense_sda = gf110_i2c_sense_sda, -}; - -int -gf110_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &gf110_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->state = 0x00000007; - port->addr = 0x00d014 + (info->drive * 0x20); - return 0; -} - -struct nvkm_oclass -gf110_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_aux_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; - -struct nvkm_oclass * -gf110_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = gf110_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &g94_i2c_pad_oclass, - .aux = 4, - .aux_stat = g94_aux_stat, - .aux_mask = g94_aux_mask, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c index e290b40f2..ae4aad3fc 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c @@ -21,18 +21,16 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "priv.h" +#include "pad.h" -struct nvkm_oclass * -gf117_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0xd7), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = gf110_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &nv04_i2c_pad_oclass, -}.base; +static const struct nvkm_i2c_func +gf117_i2c = { + .pad_x_new = gf119_i2c_pad_x_new, +}; + +int +gf117_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&gf117_i2c, device, index, pi2c); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf119.c index 8d2a8f457..6f2b02af4 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf119.c @@ -21,18 +21,20 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" +#include "pad.h" -struct nvkm_oclass * -gf106_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0xc3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, - .intr = gf100_mc_intr, - .msi_rearm = nv40_mc_msi_rearm, - .unk260 = gf100_mc_unk260, -}.base; +static const struct nvkm_i2c_func +gf119_i2c = { + .pad_x_new = gf119_i2c_pad_x_new, + .pad_s_new = gf119_i2c_pad_s_new, + .aux = 4, + .aux_stat = g94_aux_stat, + .aux_mask = g94_aux_mask, +}; + +int +gf119_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&gf119_i2c, device, index, pi2c); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c index 1a464903a..f9f6bf4b6 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c @@ -21,26 +21,29 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "priv.h" +#include "pad.h" void gk104_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) { - u32 intr = nv_rd32(i2c, 0x00dc60); - u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i; + struct nvkm_device *device = i2c->subdev.device; + u32 intr = nvkm_rd32(device, 0x00dc60); + u32 stat = nvkm_rd32(device, 0x00dc68) & intr, i; for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { if ((stat & (1 << (i * 4)))) *hi |= 1 << i; if ((stat & (2 << (i * 4)))) *lo |= 1 << i; if ((stat & (4 << (i * 4)))) *rq |= 1 << i; if ((stat & (8 << (i * 4)))) *tx |= 1 << i; } - nv_wr32(i2c, 0x00dc60, intr); + nvkm_wr32(device, 0x00dc60, intr); } void gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) { - u32 temp = nv_rd32(i2c, 0x00dc68), i; + struct nvkm_device *device = i2c->subdev.device; + u32 temp = nvkm_rd32(device, 0x00dc68), i; for (i = 0; i < 8; i++) { if (mask & (1 << i)) { if (!(data & (1 << i))) { @@ -50,22 +53,20 @@ gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) temp |= type << (i * 4); } } - nv_wr32(i2c, 0x00dc68, temp); + nvkm_wr32(device, 0x00dc68, temp); } -struct nvkm_oclass * -gk104_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = gf110_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &g94_i2c_pad_oclass, +static const struct nvkm_i2c_func +gk104_i2c = { + .pad_x_new = gf119_i2c_pad_x_new, + .pad_s_new = gf119_i2c_pad_s_new, .aux = 4, .aux_stat = gk104_aux_stat, .aux_mask = gk104_aux_mask, -}.base; +}; + +int +gk104_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&gk104_i2c, device, index, pi2c); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c index ab64237b3..ff9f7d62f 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c @@ -21,199 +21,20 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" - -#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) - -static void -auxch_fini(struct nvkm_i2c *aux, int ch) -{ - nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000); -} - -static int -auxch_init(struct nvkm_i2c *aux, int ch) -{ - const u32 unksel = 1; /* nfi which to use, or if it matters.. */ - const u32 ureq = unksel ? 0x00100000 : 0x00200000; - const u32 urep = unksel ? 0x01000000 : 0x02000000; - u32 ctrl, timeout; - - /* wait up to 1ms for any previous transaction to be done... */ - timeout = 1000; - do { - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("begin idle timeout 0x%08x\n", ctrl); - return -EBUSY; - } - } while (ctrl & 0x03010000); - - /* set some magic, and wait up to 1ms for it to appear */ - nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq); - timeout = 1000; - do { - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("magic wait 0x%08x\n", ctrl); - auxch_fini(aux, ch); - return -EBUSY; - } - } while ((ctrl & 0x03000000) != urep); - - return 0; -} - -int -gm204_aux(struct nvkm_i2c_port *base, bool retry, - u8 type, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *aux = nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - u32 ctrl, stat, timeout, retries; - u32 xbuf[4] = {}; - int ch = port->addr; - int ret, i; - - AUX_DBG("%d: 0x%08x %d\n", type, addr, size); - - ret = auxch_init(aux, ch); - if (ret) - goto out; - - stat = nv_rd32(aux, 0x00d958 + (ch * 0x50)); - if (!(stat & 0x10000000)) { - AUX_DBG("sink not detected\n"); - ret = -ENXIO; - goto out; - } - - if (!(type & 1)) { - memcpy(xbuf, data, size); - for (i = 0; i < 16; i += 4) { - AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); - nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]); - } - } - - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); - ctrl &= ~0x0001f0ff; - ctrl |= type << 12; - ctrl |= size - 1; - nv_wr32(aux, 0x00d950 + (ch * 0x50), addr); - - /* (maybe) retry transaction a number of times on failure... */ - for (retries = 0; !ret && retries < 32; retries++) { - /* reset, and delay a while if this is a retry */ - nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl); - nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl); - if (retries) - udelay(400); - - /* transaction request, wait up to 1ms for it to complete */ - nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl); - - timeout = 1000; - do { - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("tx req timeout 0x%08x\n", ctrl); - ret = -EIO; - goto out; - } - } while (ctrl & 0x00010000); - ret = 1; - - /* read status, and check if transaction completed ok */ - stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0); - if ((stat & 0x000f0000) == 0x00080000 || - (stat & 0x000f0000) == 0x00020000) - ret = retry ? 0 : 1; - if ((stat & 0x00000100)) - ret = -ETIMEDOUT; - if ((stat & 0x00000e00)) - ret = -EIO; - - AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); - } - - if (type & 1) { - for (i = 0; i < 16; i += 4) { - xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i); - AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); - } - memcpy(data, xbuf, size); - } - -out: - auxch_fini(aux, ch); - return ret < 0 ? ret : (stat & 0x000f0000) >> 16; -} +#include "priv.h" +#include "pad.h" static const struct nvkm_i2c_func -gm204_aux_func = { - .aux = gm204_aux, +gm204_i2c = { + .pad_x_new = gf119_i2c_pad_x_new, + .pad_s_new = gm204_i2c_pad_s_new, + .aux = 8, + .aux_stat = gk104_aux_stat, + .aux_mask = gk104_aux_mask, }; int -gm204_aux_port_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +gm204_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) { - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_aux_algo, &gm204_aux_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->base.aux = info->auxch; - port->addr = info->auxch; - return 0; + return nvkm_i2c_new_(&gm204_i2c, device, index, pi2c); } - -struct nvkm_oclass -gm204_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_aux_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; - -struct nvkm_oclass * -gm204_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = gm204_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &gm204_i2c_pad_oclass, - .aux = 8, - .aux_stat = gk104_aux_stat, - .aux_mask = gk104_aux_mask, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c index 4cdf1c489..18776f493 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c @@ -22,107 +22,15 @@ * Authors: Ben Skeggs */ #include "priv.h" - -#include <subdev/vga.h> - -struct nv04_i2c_priv { - struct nvkm_i2c base; -}; - -struct nv04_i2c_port { - struct nvkm_i2c_port base; - u8 drive; - u8 sense; -}; - -static void -nv04_i2c_drive_scl(struct nvkm_i2c_port *base, int state) -{ - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv04_i2c_port *port = (void *)base; - u8 val = nv_rdvgac(priv, 0, port->drive); - if (state) val |= 0x20; - else val &= 0xdf; - nv_wrvgac(priv, 0, port->drive, val | 0x01); -} - -static void -nv04_i2c_drive_sda(struct nvkm_i2c_port *base, int state) -{ - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv04_i2c_port *port = (void *)base; - u8 val = nv_rdvgac(priv, 0, port->drive); - if (state) val |= 0x10; - else val &= 0xef; - nv_wrvgac(priv, 0, port->drive, val | 0x01); -} - -static int -nv04_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv04_i2c_port *port = (void *)base; - return !!(nv_rdvgac(priv, 0, port->sense) & 0x04); -} - -static int -nv04_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv04_i2c_port *port = (void *)base; - return !!(nv_rdvgac(priv, 0, port->sense) & 0x08); -} +#include "pad.h" static const struct nvkm_i2c_func -nv04_i2c_func = { - .drive_scl = nv04_i2c_drive_scl, - .drive_sda = nv04_i2c_drive_sda, - .sense_scl = nv04_i2c_sense_scl, - .sense_sda = nv04_i2c_sense_sda, +nv04_i2c = { + .pad_x_new = nv04_i2c_pad_new, }; -static int -nv04_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +int +nv04_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) { - struct dcb_i2c_entry *info = data; - struct nv04_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &nv04_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->drive = info->drive; - port->sense = info->sense; - return 0; + return nvkm_i2c_new_(&nv04_i2c, device, index, pi2c); } - -static struct nvkm_oclass -nv04_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; - -struct nvkm_oclass * -nv04_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = nv04_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c index 046fe5e2e..6b762f7ce 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c @@ -22,99 +22,15 @@ * Authors: Ben Skeggs */ #include "priv.h" - -#include <subdev/vga.h> - -struct nv4e_i2c_priv { - struct nvkm_i2c base; -}; - -struct nv4e_i2c_port { - struct nvkm_i2c_port base; - u32 addr; -}; - -static void -nv4e_i2c_drive_scl(struct nvkm_i2c_port *base, int state) -{ - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv4e_i2c_port *port = (void *)base; - nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01); -} - -static void -nv4e_i2c_drive_sda(struct nvkm_i2c_port *base, int state) -{ - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv4e_i2c_port *port = (void *)base; - nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01); -} - -static int -nv4e_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv4e_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00040000); -} - -static int -nv4e_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv4e_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00080000); -} +#include "pad.h" static const struct nvkm_i2c_func -nv4e_i2c_func = { - .drive_scl = nv4e_i2c_drive_scl, - .drive_sda = nv4e_i2c_drive_sda, - .sense_scl = nv4e_i2c_sense_scl, - .sense_sda = nv4e_i2c_sense_sda, +nv4e_i2c = { + .pad_x_new = nv4e_i2c_pad_new, }; -static int -nv4e_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +int +nv4e_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) { - struct dcb_i2c_entry *info = data; - struct nv4e_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &nv4e_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->addr = 0x600800 + info->drive; - return 0; + return nvkm_i2c_new_(&nv4e_i2c, device, index, pi2c); } - -static struct nvkm_oclass -nv4e_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv4e_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; - -struct nvkm_oclass * -nv4e_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x4e), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = nv4e_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c index fba5b26a5..75640ab97 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c @@ -21,113 +21,16 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" - -void -nv50_i2c_drive_scl(struct nvkm_i2c_port *base, int state) -{ - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - if (state) port->state |= 0x01; - else port->state &= 0xfe; - nv_wr32(priv, port->addr, port->state); -} - -void -nv50_i2c_drive_sda(struct nvkm_i2c_port *base, int state) -{ - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - if (state) port->state |= 0x02; - else port->state &= 0xfd; - nv_wr32(priv, port->addr, port->state); -} - -int -nv50_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000001); -} - -int -nv50_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); - struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000002); -} +#include "priv.h" +#include "pad.h" static const struct nvkm_i2c_func -nv50_i2c_func = { - .drive_scl = nv50_i2c_drive_scl, - .drive_sda = nv50_i2c_drive_sda, - .sense_scl = nv50_i2c_sense_scl, - .sense_sda = nv50_i2c_sense_sda, -}; - -const u32 nv50_i2c_addr[] = { - 0x00e138, 0x00e150, 0x00e168, 0x00e180, - 0x00e254, 0x00e274, 0x00e764, 0x00e780, - 0x00e79c, 0x00e7b8 +nv50_i2c = { + .pad_x_new = nv50_i2c_pad_new, }; -const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr); - -static int -nv50_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &nv50_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - if (info->drive >= nv50_i2c_addr_nr) - return -EINVAL; - - port->state = 0x00000007; - port->addr = nv50_i2c_addr[info->drive]; - return 0; -} int -nv50_i2c_port_init(struct nvkm_object *object) +nv50_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(object); - struct nv50_i2c_port *port = (void *)object; - nv_wr32(priv, port->addr, port->state); - return nvkm_i2c_port_init(&port->base); + return nvkm_i2c_new_(&nv50_i2c, device, index, pi2c); } - -static struct nvkm_oclass -nv50_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; - -struct nvkm_oclass * -nv50_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, - .sclass = nv50_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h deleted file mode 100644 index b3139e721..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __NV50_I2C_H__ -#define __NV50_I2C_H__ -#include "priv.h" - -struct nv50_i2c_priv { - struct nvkm_i2c base; -}; - -struct nv50_i2c_port { - struct nvkm_i2c_port base; - u32 addr; - u32 state; -}; - -extern const u32 nv50_i2c_addr[]; -extern const int nv50_i2c_addr_nr; -int nv50_i2c_port_init(struct nvkm_object *); -int nv50_i2c_sense_scl(struct nvkm_i2c_port *); -int nv50_i2c_sense_sda(struct nvkm_i2c_port *); -void nv50_i2c_drive_scl(struct nvkm_i2c_port *, int state); -void nv50_i2c_drive_sda(struct nvkm_i2c_port *, int state); - -int g94_aux_port_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void g94_i2c_acquire(struct nvkm_i2c_port *); -void g94_i2c_release(struct nvkm_i2c_port *); - -int gf110_i2c_port_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c index a242eeb67..2c5fcb9c5 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c @@ -1,5 +1,5 @@ /* - * Copyright 2014 Red Hat Inc. + * Copyright 2015 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"), @@ -19,65 +19,98 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * - * Authors: Ben Skeggs + * Authors: Ben Skeggs <bskeggs@redhat.com> */ #include "pad.h" -int -_nvkm_i2c_pad_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_i2c_pad_mode_locked(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c_pad *pad = (void *)object; - DBG("-> NULL\n"); - pad->port = NULL; - return nvkm_object_fini(&pad->base, suspend); + PAD_TRACE(pad, "-> %s", (mode == NVKM_I2C_PAD_AUX) ? "aux" : + (mode == NVKM_I2C_PAD_I2C) ? "i2c" : "off"); + if (pad->func->mode) + pad->func->mode(pad, mode); } -int -_nvkm_i2c_pad_init(struct nvkm_object *object) +void +nvkm_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c_pad *pad = (void *)object; - DBG("-> PORT:%02x\n", pad->next->index); - pad->port = pad->next; - return nvkm_object_init(&pad->base); + PAD_TRACE(pad, "mode %d", mode); + mutex_lock(&pad->mutex); + nvkm_i2c_pad_mode_locked(pad, mode); + pad->mode = mode; + mutex_unlock(&pad->mutex); } -int -nvkm_i2c_pad_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int index, - int size, void **pobject) +void +nvkm_i2c_pad_release(struct nvkm_i2c_pad *pad) { - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_i2c_port *port; - struct nvkm_i2c_pad *pad; - int ret; + PAD_TRACE(pad, "release"); + if (pad->mode == NVKM_I2C_PAD_OFF) + nvkm_i2c_pad_mode_locked(pad, pad->mode); + mutex_unlock(&pad->mutex); +} - list_for_each_entry(port, &i2c->ports, head) { - pad = nvkm_i2c_pad(port); - if (pad->index == index) { - atomic_inc(&nv_object(pad)->refcount); - *pobject = pad; - return 1; +int +nvkm_i2c_pad_acquire(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) +{ + PAD_TRACE(pad, "acquire"); + mutex_lock(&pad->mutex); + if (pad->mode != mode) { + if (pad->mode != NVKM_I2C_PAD_OFF) { + mutex_unlock(&pad->mutex); + return -EBUSY; } + nvkm_i2c_pad_mode_locked(pad, mode); } + return 0; +} + +void +nvkm_i2c_pad_fini(struct nvkm_i2c_pad *pad) +{ + PAD_TRACE(pad, "fini"); + nvkm_i2c_pad_mode_locked(pad, NVKM_I2C_PAD_OFF); +} - ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject); - pad = *pobject; - if (ret) - return ret; +void +nvkm_i2c_pad_init(struct nvkm_i2c_pad *pad) +{ + PAD_TRACE(pad, "init"); + nvkm_i2c_pad_mode_locked(pad, pad->mode); +} - pad->index = index; - return 0; +void +nvkm_i2c_pad_del(struct nvkm_i2c_pad **ppad) +{ + struct nvkm_i2c_pad *pad = *ppad; + if (pad) { + PAD_TRACE(pad, "dtor"); + list_del(&pad->head); + kfree(pad); + pad = NULL; + } +} + +void +nvkm_i2c_pad_ctor(const struct nvkm_i2c_pad_func *func, struct nvkm_i2c *i2c, + int id, struct nvkm_i2c_pad *pad) +{ + pad->func = func; + pad->i2c = i2c; + pad->id = id; + pad->mode = NVKM_I2C_PAD_OFF; + mutex_init(&pad->mutex); + list_add_tail(&pad->head, &i2c->pad); + PAD_TRACE(pad, "ctor"); } int -_nvkm_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +nvkm_i2c_pad_new_(const struct nvkm_i2c_pad_func *func, struct nvkm_i2c *i2c, + int id, struct nvkm_i2c_pad **ppad) { - struct nvkm_i2c_pad *pad; - int ret; - ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); - *pobject = nv_object(pad); - return ret; + if (!(*ppad = kzalloc(sizeof(**ppad), GFP_KERNEL))) + return -ENOMEM; + nvkm_i2c_pad_ctor(func, i2c, id, *ppad); + return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h index f3422cc6f..9eeb99294 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h @@ -1,56 +1,67 @@ #ifndef __NVKM_I2C_PAD_H__ #define __NVKM_I2C_PAD_H__ -#include "priv.h" +#include <subdev/i2c.h> struct nvkm_i2c_pad { - struct nvkm_object base; - int index; - struct nvkm_i2c_port *port; - struct nvkm_i2c_port *next; + const struct nvkm_i2c_pad_func *func; + struct nvkm_i2c *i2c; +#define NVKM_I2C_PAD_HYBRID(n) /* 'n' is hw pad index */ (n) +#define NVKM_I2C_PAD_CCB(n) /* 'n' is ccb index */ ((n) + 0x100) +#define NVKM_I2C_PAD_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x200) + int id; + + enum nvkm_i2c_pad_mode { + NVKM_I2C_PAD_OFF, + NVKM_I2C_PAD_I2C, + NVKM_I2C_PAD_AUX, + } mode; + struct mutex mutex; + struct list_head head; +}; + +struct nvkm_i2c_pad_func { + int (*bus_new_0)(struct nvkm_i2c_pad *, int id, u8 drive, u8 sense, + struct nvkm_i2c_bus **); + int (*bus_new_4)(struct nvkm_i2c_pad *, int id, u8 drive, + struct nvkm_i2c_bus **); + + int (*aux_new_6)(struct nvkm_i2c_pad *, int id, u8 drive, + struct nvkm_i2c_aux **); + + void (*mode)(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); }; -static inline struct nvkm_i2c_pad * -nvkm_i2c_pad(struct nvkm_i2c_port *port) -{ - struct nvkm_object *pad = nv_object(port); - while (!nv_iclass(pad->parent, NV_SUBDEV_CLASS)) - pad = pad->parent; - return (void *)pad; -} - -#define nvkm_i2c_pad_create(p,e,o,i,d) \ - nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d) -#define nvkm_i2c_pad_destroy(p) ({ \ - struct nvkm_i2c_pad *_p = (p); \ - _nvkm_i2c_pad_dtor(nv_object(_p)); \ -}) -#define nvkm_i2c_pad_init(p) ({ \ - struct nvkm_i2c_pad *_p = (p); \ - _nvkm_i2c_pad_init(nv_object(_p)); \ -}) -#define nvkm_i2c_pad_fini(p,s) ({ \ - struct nvkm_i2c_pad *_p = (p); \ - _nvkm_i2c_pad_fini(nv_object(_p), (s)); \ -}) - -int nvkm_i2c_pad_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int index, int, void **); - -int _nvkm_i2c_pad_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_i2c_pad_dtor nvkm_object_destroy -int _nvkm_i2c_pad_init(struct nvkm_object *); -int _nvkm_i2c_pad_fini(struct nvkm_object *, bool); - -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_i2c_pad *_pad = (void *)pad; \ - nv_##l(_pad, "PAD:%c:%02x: "f, \ - _pad->index >= 0x100 ? 'X' : 'S', \ - _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \ +void nvkm_i2c_pad_ctor(const struct nvkm_i2c_pad_func *, struct nvkm_i2c *, + int id, struct nvkm_i2c_pad *); +int nvkm_i2c_pad_new_(const struct nvkm_i2c_pad_func *, struct nvkm_i2c *, + int id, struct nvkm_i2c_pad **); +void nvkm_i2c_pad_del(struct nvkm_i2c_pad **); +void nvkm_i2c_pad_init(struct nvkm_i2c_pad *); +void nvkm_i2c_pad_fini(struct nvkm_i2c_pad *); +void nvkm_i2c_pad_mode(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); +int nvkm_i2c_pad_acquire(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); +void nvkm_i2c_pad_release(struct nvkm_i2c_pad *); + +void g94_i2c_pad_mode(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); + +int nv04_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int nv4e_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int nv50_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int g94_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gf119_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gm204_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); + +int g94_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gf119_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gm204_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); + +int anx9805_pad_new(struct nvkm_i2c_bus *, int, u8, struct nvkm_i2c_pad **); + +#define PAD_MSG(p,l,f,a...) do { \ + struct nvkm_i2c_pad *_pad = (p); \ + nvkm_##l(&_pad->i2c->subdev, "pad %04x: "f"\n", _pad->id, ##a); \ } while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif +#define PAD_ERR(p,f,a...) PAD_MSG((p), error, f, ##a) +#define PAD_DBG(p,f,a...) PAD_MSG((p), debug, f, ##a) +#define PAD_TRACE(p,f,a...) PAD_MSG((p), trace, f, ##a) #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c index e9832f7a7..5904bc5f2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c @@ -22,64 +22,55 @@ * Authors: Ben Skeggs */ #include "pad.h" +#include "aux.h" +#include "bus.h" -struct g94_i2c_pad { - struct nvkm_i2c_pad base; - int addr; -}; - -static int -g94_i2c_pad_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct g94_i2c_pad *pad = (void *)object; - nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001); - return nvkm_i2c_pad_fini(&pad->base, suspend); -} - -static int -g94_i2c_pad_init(struct nvkm_object *object) +void +g94_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct g94_i2c_pad *pad = (void *)object; + struct nvkm_subdev *subdev = &pad->i2c->subdev; + struct nvkm_device *device = subdev->device; + const u32 base = (pad->id - NVKM_I2C_PAD_HYBRID(0)) * 0x50; - switch (nv_oclass(pad->base.next)->handle) { - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): - nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002); + switch (mode) { + case NVKM_I2C_PAD_OFF: + nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000001); + break; + case NVKM_I2C_PAD_I2C: + nvkm_mask(device, 0x00e500 + base, 0x0000c003, 0x0000c001); + nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000000); + break; + case NVKM_I2C_PAD_AUX: + nvkm_mask(device, 0x00e500 + base, 0x0000c003, 0x00000002); + nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000000); break; - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): default: - nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001); + WARN_ON(1); break; } - - nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000); - return nvkm_i2c_pad_init(&pad->base); } -static int -g94_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct g94_i2c_pad *pad; - int ret; - - ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); - *pobject = nv_object(pad); - if (ret) - return ret; +static const struct nvkm_i2c_pad_func +g94_i2c_pad_s_func = { + .bus_new_4 = nv50_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, + .mode = g94_i2c_pad_mode, +}; - pad->addr = index * 0x50;; - return 0; +int +g94_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&g94_i2c_pad_s_func, i2c, id, ppad); } -struct nvkm_oclass -g94_i2c_pad_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_i2c_pad_ctor, - .dtor = _nvkm_i2c_pad_dtor, - .init = g94_i2c_pad_init, - .fini = g94_i2c_pad_fini, - }, +static const struct nvkm_i2c_pad_func +g94_i2c_pad_x_func = { + .bus_new_4 = nv50_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, }; + +int +g94_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&g94_i2c_pad_x_func, i2c, id, ppad); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c new file mode 100644 index 000000000..d53212f1a --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c @@ -0,0 +1,51 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "pad.h" +#include "aux.h" +#include "bus.h" + +static const struct nvkm_i2c_pad_func +gf119_i2c_pad_s_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, + .mode = g94_i2c_pad_mode, +}; + +int +gf119_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gf119_i2c_pad_s_func, i2c, id, ppad); +} + +static const struct nvkm_i2c_pad_func +gf119_i2c_pad_x_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, +}; + +int +gf119_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gf119_i2c_pad_x_func, i2c, id, ppad); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c index be5904054..24a4d760c 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c @@ -22,64 +22,55 @@ * Authors: Ben Skeggs */ #include "pad.h" +#include "aux.h" +#include "bus.h" -struct gm204_i2c_pad { - struct nvkm_i2c_pad base; - int addr; -}; - -static int -gm204_i2c_pad_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct gm204_i2c_pad *pad = (void *)object; - nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000001); - return nvkm_i2c_pad_fini(&pad->base, suspend); -} - -static int -gm204_i2c_pad_init(struct nvkm_object *object) +static void +gm204_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct gm204_i2c_pad *pad = (void *)object; + struct nvkm_subdev *subdev = &pad->i2c->subdev; + struct nvkm_device *device = subdev->device; + const u32 base = (pad->id - NVKM_I2C_PAD_HYBRID(0)) * 0x50; - switch (nv_oclass(pad->base.next)->handle) { - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): - nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x00000002); + switch (mode) { + case NVKM_I2C_PAD_OFF: + nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000001); + break; + case NVKM_I2C_PAD_I2C: + nvkm_mask(device, 0x00d970 + base, 0x0000c003, 0x0000c001); + nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000000); + break; + case NVKM_I2C_PAD_AUX: + nvkm_mask(device, 0x00d970 + base, 0x0000c003, 0x00000002); + nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000000); break; - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): default: - nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001); + WARN_ON(1); break; } - - nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000000); - return nvkm_i2c_pad_init(&pad->base); } -static int -gm204_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct gm204_i2c_pad *pad; - int ret; - - ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); - *pobject = nv_object(pad); - if (ret) - return ret; +static const struct nvkm_i2c_pad_func +gm204_i2c_pad_s_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = gm204_i2c_aux_new, + .mode = gm204_i2c_pad_mode, +}; - pad->addr = index * 0x50;; - return 0; +int +gm204_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gm204_i2c_pad_s_func, i2c, id, ppad); } -struct nvkm_oclass -gm204_i2c_pad_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_i2c_pad_ctor, - .dtor = _nvkm_i2c_pad_dtor, - .init = gm204_i2c_pad_init, - .fini = gm204_i2c_pad_fini, - }, +static const struct nvkm_i2c_pad_func +gm204_i2c_pad_x_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = gm204_i2c_aux_new, }; + +int +gm204_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gm204_i2c_pad_x_func, i2c, id, ppad); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c index 22c7daaad..310046ad9 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c @@ -22,13 +22,15 @@ * Authors: Ben Skeggs */ #include "pad.h" +#include "bus.h" -struct nvkm_oclass -nv04_i2c_pad_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_pad_ctor, - .dtor = _nvkm_i2c_pad_dtor, - .init = _nvkm_i2c_pad_init, - .fini = _nvkm_i2c_pad_fini, - }, +static const struct nvkm_i2c_pad_func +nv04_i2c_pad_func = { + .bus_new_0 = nv04_i2c_bus_new, }; + +int +nv04_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&nv04_i2c_pad_func, i2c, id, ppad); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c index c0aac7e20..dda6fc0b0 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c @@ -1,5 +1,5 @@ /* - * Copyright 2014 Ilia Mirkin + * 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"), @@ -19,18 +19,18 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * - * Authors: Ilia Mirkin + * Authors: Ben Skeggs */ -#include "nv04.h" +#include "pad.h" +#include "bus.h" -struct nvkm_oclass * -nv4c_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x4c), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv44_mc_init, - .fini = _nvkm_mc_fini, - }, - .intr = nv04_mc_intr, -}.base; +static const struct nvkm_i2c_pad_func +nv4e_i2c_pad_func = { + .bus_new_4 = nv4e_i2c_bus_new, +}; + +int +nv4e_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&nv4e_i2c_pad_func, i2c, id, ppad); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c index f042e7d83..a03f25b19 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat Inc. + * 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"), @@ -21,17 +21,16 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "pad.h" +#include "bus.h" -struct nvkm_oclass * -g94_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, - .intr = nv50_mc_intr, - .msi_rearm = nv40_mc_msi_rearm, -}.base; +static const struct nvkm_i2c_pad_func +nv50_i2c_pad_func = { + .bus_new_4 = nv50_i2c_bus_new, +}; + +int +nv50_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&nv50_i2c_pad_func, i2c, id, ppad); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h deleted file mode 100644 index 586f53dad..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __NVKM_I2C_PORT_H__ -#define __NVKM_I2C_PORT_H__ -#include "priv.h" - -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_i2c_port *_port = (void *)port; \ - nv_##l(_port, "PORT:%02x: "f, _port->index, ##a); \ -} while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h index 6586e1567..bf655a66e 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h @@ -1,69 +1,14 @@ #ifndef __NVKM_I2C_PRIV_H__ #define __NVKM_I2C_PRIV_H__ +#define nvkm_i2c(p) container_of((p), struct nvkm_i2c, subdev) #include <subdev/i2c.h> -extern struct nvkm_oclass nv04_i2c_pad_oclass; -extern struct nvkm_oclass g94_i2c_pad_oclass; -extern struct nvkm_oclass gm204_i2c_pad_oclass; +int nvkm_i2c_new_(const struct nvkm_i2c_func *, struct nvkm_device *, + int index, struct nvkm_i2c **); -#define nvkm_i2c_port_create(p,e,o,i,a,f,d) \ - nvkm_i2c_port_create_((p), (e), (o), (i), (a), (f), \ - sizeof(**d), (void **)d) -#define nvkm_i2c_port_destroy(p) ({ \ - struct nvkm_i2c_port *port = (p); \ - _nvkm_i2c_port_dtor(nv_object(i2c)); \ -}) -#define nvkm_i2c_port_init(p) \ - nvkm_object_init(&(p)->base) -#define nvkm_i2c_port_fini(p,s) \ - nvkm_object_fini(&(p)->base, (s)) - -int nvkm_i2c_port_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u8, - const struct i2c_algorithm *, - const struct nvkm_i2c_func *, - int, void **); -void _nvkm_i2c_port_dtor(struct nvkm_object *); -#define _nvkm_i2c_port_init nvkm_object_init -int _nvkm_i2c_port_fini(struct nvkm_object *, bool); - -#define nvkm_i2c_create(p,e,o,d) \ - nvkm_i2c_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_i2c_destroy(p) ({ \ - struct nvkm_i2c *i2c = (p); \ - _nvkm_i2c_dtor(nv_object(i2c)); \ -}) -#define nvkm_i2c_init(p) ({ \ - struct nvkm_i2c *i2c = (p); \ - _nvkm_i2c_init(nv_object(i2c)); \ -}) -#define nvkm_i2c_fini(p,s) ({ \ - struct nvkm_i2c *i2c = (p); \ - _nvkm_i2c_fini(nv_object(i2c), (s)); \ -}) - -int nvkm_i2c_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -int _nvkm_i2c_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_i2c_dtor(struct nvkm_object *); -int _nvkm_i2c_init(struct nvkm_object *); -int _nvkm_i2c_fini(struct nvkm_object *, bool); - -extern struct nvkm_oclass nvkm_anx9805_sclass[]; -extern struct nvkm_oclass gf110_i2c_sclass[]; - -extern const struct i2c_algorithm nvkm_i2c_bit_algo; -extern const struct i2c_algorithm nvkm_i2c_aux_algo; - -struct nvkm_i2c_impl { - struct nvkm_oclass base; - - /* supported i2c port classes */ - struct nvkm_oclass *sclass; - struct nvkm_oclass *pad_x; - struct nvkm_oclass *pad_s; +struct nvkm_i2c_func { + int (*pad_x_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **); + int (*pad_s_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **); /* number of native dp aux channels present */ int aux; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild index a0b12d272..de888fa62 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild @@ -1,3 +1,4 @@ nvkm-y += nvkm/subdev/ibus/gf100.o +nvkm-y += nvkm/subdev/ibus/gf117.o nvkm-y += nvkm/subdev/ibus/gk104.o nvkm-y += nvkm/subdev/ibus/gk20a.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c index 8e578f802..72d6330d2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c @@ -21,57 +21,56 @@ * * Authors: Ben Skeggs */ -#include <subdev/ibus.h> - -struct gf100_ibus_priv { - struct nvkm_ibus base; -}; +#include "priv.h" static void -gf100_ibus_intr_hub(struct gf100_ibus_priv *priv, int i) +gf100_ibus_intr_hub(struct nvkm_subdev *ibus, int i) { - u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0400)); - u32 data = nv_rd32(priv, 0x122124 + (i * 0x0400)); - u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0400)); - nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); + struct nvkm_device *device = ibus->device; + u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0400)); + u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0400)); + u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0400)); + nvkm_error(ibus, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_mask(device, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); } static void -gf100_ibus_intr_rop(struct gf100_ibus_priv *priv, int i) +gf100_ibus_intr_rop(struct nvkm_subdev *ibus, int i) { - u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0400)); - u32 data = nv_rd32(priv, 0x124124 + (i * 0x0400)); - u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0400)); - nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); + struct nvkm_device *device = ibus->device; + u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0400)); + u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0400)); + u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0400)); + nvkm_error(ibus, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_mask(device, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); } static void -gf100_ibus_intr_gpc(struct gf100_ibus_priv *priv, int i) +gf100_ibus_intr_gpc(struct nvkm_subdev *ibus, int i) { - u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0400)); - u32 data = nv_rd32(priv, 0x128124 + (i * 0x0400)); - u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0400)); - nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); + struct nvkm_device *device = ibus->device; + u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0400)); + u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0400)); + u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0400)); + nvkm_error(ibus, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_mask(device, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); } -static void -gf100_ibus_intr(struct nvkm_subdev *subdev) +void +gf100_ibus_intr(struct nvkm_subdev *ibus) { - struct gf100_ibus_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0x121c58); - u32 intr1 = nv_rd32(priv, 0x121c5c); - u32 hubnr = nv_rd32(priv, 0x121c70); - u32 ropnr = nv_rd32(priv, 0x121c74); - u32 gpcnr = nv_rd32(priv, 0x121c78); + struct nvkm_device *device = ibus->device; + u32 intr0 = nvkm_rd32(device, 0x121c58); + u32 intr1 = nvkm_rd32(device, 0x121c5c); + u32 hubnr = nvkm_rd32(device, 0x121c70); + u32 ropnr = nvkm_rd32(device, 0x121c74); + u32 gpcnr = nvkm_rd32(device, 0x121c78); u32 i; for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { u32 stat = 0x00000100 << i; if (intr0 & stat) { - gf100_ibus_intr_hub(priv, i); + gf100_ibus_intr_hub(ibus, i); intr0 &= ~stat; } } @@ -79,7 +78,7 @@ gf100_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) { u32 stat = 0x00010000 << i; if (intr0 & stat) { - gf100_ibus_intr_rop(priv, i); + gf100_ibus_intr_rop(ibus, i); intr0 &= ~stat; } } @@ -87,36 +86,37 @@ gf100_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; intr1 && i < gpcnr; i++) { u32 stat = 0x00000001 << i; if (intr1 & stat) { - gf100_ibus_intr_gpc(priv, i); + gf100_ibus_intr_gpc(ibus, i); intr1 &= ~stat; } } } static int -gf100_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_ibus_init(struct nvkm_subdev *ibus) { - struct gf100_ibus_priv *priv; - int ret; - - ret = nvkm_ibus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->intr = gf100_ibus_intr; + struct nvkm_device *device = ibus->device; + nvkm_mask(device, 0x122310, 0x0003ffff, 0x00000800); + nvkm_wr32(device, 0x12232c, 0x00100064); + nvkm_wr32(device, 0x122330, 0x00100064); + nvkm_wr32(device, 0x122334, 0x00100064); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000100); return 0; } -struct nvkm_oclass -gf100_ibus_oclass = { - .handle = NV_SUBDEV(IBUS, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ibus_ctor, - .dtor = _nvkm_ibus_dtor, - .init = _nvkm_ibus_init, - .fini = _nvkm_ibus_fini, - }, +static const struct nvkm_subdev_func +gf100_ibus = { + .init = gf100_ibus_init, + .intr = gf100_ibus_intr, }; + +int +gf100_ibus_new(struct nvkm_device *device, int index, + struct nvkm_subdev **pibus) +{ + struct nvkm_subdev *ibus; + if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&gf100_ibus, device, index, 0, ibus); + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf117.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf117.c new file mode 100644 index 000000000..f69f263c5 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf117.c @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Samuel Pitosiet + * + * 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: Samuel Pitoiset + */ +#include "priv.h" + +static int +gf117_ibus_init(struct nvkm_subdev *ibus) +{ + struct nvkm_device *device = ibus->device; + nvkm_mask(device, 0x122310, 0x0003ffff, 0x00000800); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000100); + nvkm_mask(device, 0x1223b0, 0x0003ffff, 0x00000fff); + return 0; +} + +static const struct nvkm_subdev_func +gf117_ibus = { + .init = gf117_ibus_init, + .intr = gf100_ibus_intr, +}; + +int +gf117_ibus_new(struct nvkm_device *device, int index, + struct nvkm_subdev **pibus) +{ + struct nvkm_subdev *ibus; + if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&gf117_ibus, device, index, 0, ibus); + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c index 7b6e9a6cd..ba33609f6 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c @@ -23,55 +23,54 @@ */ #include <subdev/ibus.h> -struct gk104_ibus_priv { - struct nvkm_ibus base; -}; - static void -gk104_ibus_intr_hub(struct gk104_ibus_priv *priv, int i) +gk104_ibus_intr_hub(struct nvkm_subdev *ibus, int i) { - u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0800)); - u32 data = nv_rd32(priv, 0x122124 + (i * 0x0800)); - u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0800)); - nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); + struct nvkm_device *device = ibus->device; + u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0800)); + u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0800)); + u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0800)); + nvkm_error(ibus, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_mask(device, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr_rop(struct gk104_ibus_priv *priv, int i) +gk104_ibus_intr_rop(struct nvkm_subdev *ibus, int i) { - u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0800)); - u32 data = nv_rd32(priv, 0x124124 + (i * 0x0800)); - u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0800)); - nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); + struct nvkm_device *device = ibus->device; + u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0800)); + u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0800)); + u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0800)); + nvkm_error(ibus, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_mask(device, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr_gpc(struct gk104_ibus_priv *priv, int i) +gk104_ibus_intr_gpc(struct nvkm_subdev *ibus, int i) { - u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0800)); - u32 data = nv_rd32(priv, 0x128124 + (i * 0x0800)); - u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0800)); - nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); + struct nvkm_device *device = ibus->device; + u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0800)); + u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0800)); + u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0800)); + nvkm_error(ibus, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_mask(device, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr(struct nvkm_subdev *subdev) +gk104_ibus_intr(struct nvkm_subdev *ibus) { - struct gk104_ibus_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0x120058); - u32 intr1 = nv_rd32(priv, 0x12005c); - u32 hubnr = nv_rd32(priv, 0x120070); - u32 ropnr = nv_rd32(priv, 0x120074); - u32 gpcnr = nv_rd32(priv, 0x120078); + struct nvkm_device *device = ibus->device; + u32 intr0 = nvkm_rd32(device, 0x120058); + u32 intr1 = nvkm_rd32(device, 0x12005c); + u32 hubnr = nvkm_rd32(device, 0x120070); + u32 ropnr = nvkm_rd32(device, 0x120074); + u32 gpcnr = nvkm_rd32(device, 0x120078); u32 i; for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { u32 stat = 0x00000100 << i; if (intr0 & stat) { - gk104_ibus_intr_hub(priv, i); + gk104_ibus_intr_hub(ibus, i); intr0 &= ~stat; } } @@ -79,7 +78,7 @@ gk104_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) { u32 stat = 0x00010000 << i; if (intr0 & stat) { - gk104_ibus_intr_rop(priv, i); + gk104_ibus_intr_rop(ibus, i); intr0 &= ~stat; } } @@ -87,53 +86,40 @@ gk104_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; intr1 && i < gpcnr; i++) { u32 stat = 0x00000001 << i; if (intr1 & stat) { - gk104_ibus_intr_gpc(priv, i); + gk104_ibus_intr_gpc(ibus, i); intr1 &= ~stat; } } } static int -gk104_ibus_init(struct nvkm_object *object) +gk104_ibus_init(struct nvkm_subdev *ibus) { - struct gk104_ibus_priv *priv = (void *)object; - int ret = nvkm_ibus_init(&priv->base); - if (ret == 0) { - nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000); - nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200); - nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800); - nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100); - nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff); - nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200); - nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880); - } - return ret; + struct nvkm_device *device = ibus->device; + nvkm_mask(device, 0x122318, 0x0003ffff, 0x00001000); + nvkm_mask(device, 0x12231c, 0x0003ffff, 0x00000200); + nvkm_mask(device, 0x122310, 0x0003ffff, 0x00000800); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000100); + nvkm_mask(device, 0x1223b0, 0x0003ffff, 0x00000fff); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000200); + nvkm_mask(device, 0x122358, 0x0003ffff, 0x00002880); + return 0; } -static int -gk104_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk104_ibus_priv *priv; - int ret; - - ret = nvkm_ibus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_subdev_func +gk104_ibus = { + .preinit = gk104_ibus_init, + .init = gk104_ibus_init, + .intr = gk104_ibus_intr, +}; - nv_subdev(priv)->intr = gk104_ibus_intr; +int +gk104_ibus_new(struct nvkm_device *device, int index, + struct nvkm_subdev **pibus) +{ + struct nvkm_subdev *ibus; + if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&gk104_ibus, device, index, 0, ibus); return 0; } - -struct nvkm_oclass -gk104_ibus_oclass = { - .handle = NV_SUBDEV(IBUS, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ibus_ctor, - .dtor = _nvkm_ibus_dtor, - .init = gk104_ibus_init, - .fini = _nvkm_ibus_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c index c0fdb89e7..3484079e8 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c @@ -22,81 +22,68 @@ #include <subdev/ibus.h> #include <subdev/timer.h> -struct gk20a_ibus_priv { - struct nvkm_ibus base; -}; - static void -gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv) +gk20a_ibus_init_ibus_ring(struct nvkm_subdev *ibus) { - nv_mask(priv, 0x137250, 0x3f, 0); + struct nvkm_device *device = ibus->device; + nvkm_mask(device, 0x137250, 0x3f, 0); - nv_mask(priv, 0x000200, 0x20, 0); + nvkm_mask(device, 0x000200, 0x20, 0); usleep_range(20, 30); - nv_mask(priv, 0x000200, 0x20, 0x20); - - nv_wr32(priv, 0x12004c, 0x4); - nv_wr32(priv, 0x122204, 0x2); - nv_rd32(priv, 0x122204); + nvkm_mask(device, 0x000200, 0x20, 0x20); + + nvkm_wr32(device, 0x12004c, 0x4); + nvkm_wr32(device, 0x122204, 0x2); + nvkm_rd32(device, 0x122204); + + /* + * Bug: increase clock timeout to avoid operation failure at high + * gpcclk rate. + */ + nvkm_wr32(device, 0x122354, 0x800); + nvkm_wr32(device, 0x128328, 0x800); + nvkm_wr32(device, 0x124320, 0x800); } static void -gk20a_ibus_intr(struct nvkm_subdev *subdev) +gk20a_ibus_intr(struct nvkm_subdev *ibus) { - struct gk20a_ibus_priv *priv = (void *)subdev; - u32 status0 = nv_rd32(priv, 0x120058); + struct nvkm_device *device = ibus->device; + u32 status0 = nvkm_rd32(device, 0x120058); if (status0 & 0x7) { - nv_debug(priv, "resetting priv ring\n"); - gk20a_ibus_init_priv_ring(priv); + nvkm_debug(ibus, "resetting ibus ring\n"); + gk20a_ibus_init_ibus_ring(ibus); } /* Acknowledge interrupt */ - nv_mask(priv, 0x12004c, 0x2, 0x2); - - if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00)) - nv_warn(priv, "timeout waiting for ringmaster ack\n"); + nvkm_mask(device, 0x12004c, 0x2, 0x2); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x12004c) & 0x0000003f)) + break; + ); } static int -gk20a_ibus_init(struct nvkm_object *object) +gk20a_ibus_init(struct nvkm_subdev *ibus) { - struct gk20a_ibus_priv *priv = (void *)object; - int ret; - - ret = _nvkm_ibus_init(object); - if (ret) - return ret; - - gk20a_ibus_init_priv_ring(priv); - + gk20a_ibus_init_ibus_ring(ibus); return 0; } -static int -gk20a_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk20a_ibus_priv *priv; - int ret; - - ret = nvkm_ibus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_subdev_func +gk20a_ibus = { + .init = gk20a_ibus_init, + .intr = gk20a_ibus_intr, +}; - nv_subdev(priv)->intr = gk20a_ibus_intr; +int +gk20a_ibus_new(struct nvkm_device *device, int index, + struct nvkm_subdev **pibus) +{ + struct nvkm_subdev *ibus; + if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&gk20a_ibus, device, index, 0, ibus); return 0; } - -struct nvkm_oclass -gk20a_ibus_oclass = { - .handle = NV_SUBDEV(IBUS, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_ibus_ctor, - .dtor = _nvkm_ibus_dtor, - .init = gk20a_ibus_init, - .fini = _nvkm_ibus_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h new file mode 100644 index 000000000..48e1b6365 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/priv.h @@ -0,0 +1,7 @@ +#ifndef __NVKM_IBUS_PRIV_H__ +#define __NVKM_IBUS_PRIV_H__ + +#include <subdev/ibus.h> + +void gf100_ibus_intr(struct nvkm_subdev *); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index d16358cc6..1d7dd3829 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -23,124 +23,296 @@ */ #include "priv.h" -#include <core/engine.h> +#include <core/memory.h> +#include <subdev/bar.h> /****************************************************************************** * instmem object base implementation *****************************************************************************/ +#define nvkm_instobj(p) container_of((p), struct nvkm_instobj, memory) -void -_nvkm_instobj_dtor(struct nvkm_object *object) +struct nvkm_instobj { + struct nvkm_memory memory; + struct nvkm_memory *parent; + struct nvkm_instmem *imem; + struct list_head head; + u32 *suspend; + void __iomem *map; +}; + +static enum nvkm_memory_target +nvkm_instobj_target(struct nvkm_memory *memory) +{ + memory = nvkm_instobj(memory)->parent; + return nvkm_memory_target(memory); +} + +static u64 +nvkm_instobj_addr(struct nvkm_memory *memory) +{ + memory = nvkm_instobj(memory)->parent; + return nvkm_memory_addr(memory); +} + +static u64 +nvkm_instobj_size(struct nvkm_memory *memory) +{ + memory = nvkm_instobj(memory)->parent; + return nvkm_memory_size(memory); +} + +static void +nvkm_instobj_release(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + nvkm_bar_flush(iobj->imem->subdev.device->bar); +} + +static void __iomem * +nvkm_instobj_acquire(struct nvkm_memory *memory) +{ + return nvkm_instobj(memory)->map; +} + +static u32 +nvkm_instobj_rd32(struct nvkm_memory *memory, u64 offset) +{ + return ioread32_native(nvkm_instobj(memory)->map + offset); +} + +static void +nvkm_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) { - struct nvkm_instmem *imem = nvkm_instmem(object); - struct nvkm_instobj *iobj = (void *)object; + iowrite32_native(data, nvkm_instobj(memory)->map + offset); +} + +static void +nvkm_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset) +{ + memory = nvkm_instobj(memory)->parent; + nvkm_memory_map(memory, vma, offset); +} - mutex_lock(&nv_subdev(imem)->mutex); +static void * +nvkm_instobj_dtor(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + spin_lock(&iobj->imem->lock); list_del(&iobj->head); - mutex_unlock(&nv_subdev(imem)->mutex); + spin_unlock(&iobj->imem->lock); + nvkm_memory_del(&iobj->parent); + return iobj; +} + +const struct nvkm_memory_func +nvkm_instobj_func = { + .dtor = nvkm_instobj_dtor, + .target = nvkm_instobj_target, + .addr = nvkm_instobj_addr, + .size = nvkm_instobj_size, + .acquire = nvkm_instobj_acquire, + .release = nvkm_instobj_release, + .rd32 = nvkm_instobj_rd32, + .wr32 = nvkm_instobj_wr32, + .map = nvkm_instobj_map, +}; + +static void +nvkm_instobj_boot(struct nvkm_memory *memory, struct nvkm_vm *vm) +{ + memory = nvkm_instobj(memory)->parent; + nvkm_memory_boot(memory, vm); +} + +static void +nvkm_instobj_release_slow(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + nvkm_instobj_release(memory); + nvkm_done(iobj->parent); +} + +static void __iomem * +nvkm_instobj_acquire_slow(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + iobj->map = nvkm_kmap(iobj->parent); + if (iobj->map) + memory->func = &nvkm_instobj_func; + return iobj->map; +} + +static u32 +nvkm_instobj_rd32_slow(struct nvkm_memory *memory, u64 offset) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + return nvkm_ro32(iobj->parent, offset); +} - return nvkm_object_destroy(&iobj->base); +static void +nvkm_instobj_wr32_slow(struct nvkm_memory *memory, u64 offset, u32 data) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + return nvkm_wo32(iobj->parent, offset, data); } +const struct nvkm_memory_func +nvkm_instobj_func_slow = { + .dtor = nvkm_instobj_dtor, + .target = nvkm_instobj_target, + .addr = nvkm_instobj_addr, + .size = nvkm_instobj_size, + .boot = nvkm_instobj_boot, + .acquire = nvkm_instobj_acquire_slow, + .release = nvkm_instobj_release_slow, + .rd32 = nvkm_instobj_rd32_slow, + .wr32 = nvkm_instobj_wr32_slow, + .map = nvkm_instobj_map, +}; + int -nvkm_instobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nvkm_instmem *imem = nvkm_instmem(parent); + struct nvkm_memory *memory = NULL; struct nvkm_instobj *iobj; + u32 offset; int ret; - ret = nvkm_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS, - length, pobject); - iobj = *pobject; + ret = imem->func->memory_new(imem, size, align, zero, &memory); if (ret) - return ret; + goto done; - mutex_lock(&imem->base.mutex); - list_add(&iobj->head, &imem->list); - mutex_unlock(&imem->base.mutex); - return 0; + if (!imem->func->persistent) { + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + + nvkm_memory_ctor(&nvkm_instobj_func_slow, &iobj->memory); + iobj->parent = memory; + iobj->imem = imem; + spin_lock(&iobj->imem->lock); + list_add_tail(&iobj->head, &imem->list); + spin_unlock(&iobj->imem->lock); + memory = &iobj->memory; + } + + if (!imem->func->zero && zero) { + void __iomem *map = nvkm_kmap(memory); + if (unlikely(!map)) { + for (offset = 0; offset < size; offset += 4) + nvkm_wo32(memory, offset, 0x00000000); + } else { + memset_io(map, 0x00, size); + } + nvkm_done(memory); + } + +done: + if (ret) + nvkm_memory_del(&memory); + *pmemory = memory; + return ret; } /****************************************************************************** * instmem subdev base implementation *****************************************************************************/ -static int -nvkm_instmem_alloc(struct nvkm_instmem *imem, struct nvkm_object *parent, - u32 size, u32 align, struct nvkm_object **pobject) +u32 +nvkm_instmem_rd32(struct nvkm_instmem *imem, u32 addr) { - struct nvkm_instmem_impl *impl = (void *)imem->base.object.oclass; - struct nvkm_instobj_args args = { .size = size, .align = align }; - return nvkm_object_ctor(parent, &parent->engine->subdev.object, - impl->instobj, &args, sizeof(args), pobject); + return imem->func->rd32(imem, addr); } -int -_nvkm_instmem_fini(struct nvkm_object *object, bool suspend) +void +nvkm_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data) +{ + return imem->func->wr32(imem, addr, data); +} + +static int +nvkm_instmem_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_instmem *imem = (void *)object; + struct nvkm_instmem *imem = nvkm_instmem(subdev); struct nvkm_instobj *iobj; - int i, ret = 0; + int i; + + if (imem->func->fini) + imem->func->fini(imem); if (suspend) { - mutex_lock(&imem->base.mutex); list_for_each_entry(iobj, &imem->list, head) { - iobj->suspend = vmalloc(iobj->size); - if (!iobj->suspend) { - ret = -ENOMEM; - break; - } - - for (i = 0; i < iobj->size; i += 4) - iobj->suspend[i / 4] = nv_ro32(iobj, i); + struct nvkm_memory *memory = iobj->parent; + u64 size = nvkm_memory_size(memory); + + iobj->suspend = vmalloc(size); + if (!iobj->suspend) + return -ENOMEM; + + for (i = 0; i < size; i += 4) + iobj->suspend[i / 4] = nvkm_ro32(memory, i); } - mutex_unlock(&imem->base.mutex); - if (ret) - return ret; } - return nvkm_subdev_fini(&imem->base, suspend); + return 0; } -int -_nvkm_instmem_init(struct nvkm_object *object) +static int +nvkm_instmem_oneinit(struct nvkm_subdev *subdev) { - struct nvkm_instmem *imem = (void *)object; - struct nvkm_instobj *iobj; - int ret, i; + struct nvkm_instmem *imem = nvkm_instmem(subdev); + if (imem->func->oneinit) + return imem->func->oneinit(imem); + return 0; +} - ret = nvkm_subdev_init(&imem->base); - if (ret) - return ret; +static int +nvkm_instmem_init(struct nvkm_subdev *subdev) +{ + struct nvkm_instmem *imem = nvkm_instmem(subdev); + struct nvkm_instobj *iobj; + int i; - mutex_lock(&imem->base.mutex); list_for_each_entry(iobj, &imem->list, head) { if (iobj->suspend) { - for (i = 0; i < iobj->size; i += 4) - nv_wo32(iobj, i, iobj->suspend[i / 4]); + struct nvkm_memory *memory = iobj->parent; + u64 size = nvkm_memory_size(memory); + for (i = 0; i < size; i += 4) + nvkm_wo32(memory, i, iobj->suspend[i / 4]); vfree(iobj->suspend); iobj->suspend = NULL; } } - mutex_unlock(&imem->base.mutex); + return 0; } -int -nvkm_instmem_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +static void * +nvkm_instmem_dtor(struct nvkm_subdev *subdev) { - struct nvkm_instmem *imem; - int ret; + struct nvkm_instmem *imem = nvkm_instmem(subdev); + if (imem->func->dtor) + return imem->func->dtor(imem); + return imem; +} - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "INSTMEM", - "instmem", length, pobject); - imem = *pobject; - if (ret) - return ret; +static const struct nvkm_subdev_func +nvkm_instmem = { + .dtor = nvkm_instmem_dtor, + .oneinit = nvkm_instmem_oneinit, + .init = nvkm_instmem_init, + .fini = nvkm_instmem_fini, +}; +void +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); + imem->func = func; + spin_lock_init(&imem->lock); INIT_LIST_HEAD(&imem->list); - imem->alloc = nvkm_instmem_alloc; - return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index dd0994d9e..14107b5b7 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -23,418 +23,607 @@ /* * GK20A does not have dedicated video memory, and to accurately represent this * fact Nouveau will not create a RAM device for it. Therefore its instmem - * implementation must be done directly on top of system memory, while providing - * coherent read and write operations. + * implementation must be done directly on top of system memory, while + * preserving coherency for read and write operations. * * Instmem can be allocated through two means: - * 1) If an IOMMU mapping has been probed, the IOMMU API is used to make memory + * 1) If an IOMMU unit has been probed, the IOMMU API is used to make memory * pages contiguous to the GPU. This is the preferred way. - * 2) If no IOMMU mapping is probed, the DMA API is used to allocate physically + * 2) If no IOMMU unit is probed, the DMA API is used to allocate physically * contiguous memory. * - * In both cases CPU read and writes are performed using PRAMIN (i.e. using the - * GPU path) to ensure these operations are coherent for the GPU. This allows us - * to use more "relaxed" allocation parameters when using the DMA API, since we - * never need a kernel mapping. + * In both cases CPU read and writes are performed by creating a write-combined + * mapping. The GPU L2 cache must thus be flushed/invalidated when required. To + * be conservative we do this every time we acquire or release an instobj, but + * ideally L2 management should be handled at a higher level. + * + * To improve performance, CPU mappings are not removed upon instobj release. + * Instead they are placed into a LRU list to be recycled when the mapped space + * goes beyond a certain threshold. At the moment this limit is 1MB. */ +#include "priv.h" -#include <subdev/fb.h> +#include <core/memory.h> #include <core/mm.h> -#include <core/device.h> - -#ifdef __KERNEL__ -#include <linux/dma-attrs.h> -#include <linux/iommu.h> -#include <nouveau_platform.h> -#endif +#include <core/tegra.h> +#include <subdev/fb.h> +#include <subdev/ltc.h> -#include "priv.h" +struct gk20a_instobj { + struct nvkm_memory memory; + struct nvkm_mem mem; + struct gk20a_instmem *imem; -struct gk20a_instobj_priv { - struct nvkm_instobj base; - /* Must be second member here - see nouveau_gpuobj_map_vm() */ - struct nvkm_mem *mem; - /* Pointed by mem */ - struct nvkm_mem _mem; + /* CPU mapping */ + u32 *vaddr; + struct list_head vaddr_node; }; +#define gk20a_instobj(p) container_of((p), struct gk20a_instobj, memory) /* * Used for objects allocated using the DMA API */ struct gk20a_instobj_dma { - struct gk20a_instobj_priv base; + struct gk20a_instobj base; - void *cpuaddr; + u32 *cpuaddr; dma_addr_t handle; struct nvkm_mm_node r; }; +#define gk20a_instobj_dma(p) \ + container_of(gk20a_instobj(p), struct gk20a_instobj_dma, base) /* * Used for objects flattened using the IOMMU API */ struct gk20a_instobj_iommu { - struct gk20a_instobj_priv base; + struct gk20a_instobj base; - /* array of base.mem->size pages */ + /* will point to the higher half of pages */ + dma_addr_t *dma_addrs; + /* array of base.mem->size pages (+ dma_addr_ts) */ struct page *pages[]; }; +#define gk20a_instobj_iommu(p) \ + container_of(gk20a_instobj(p), struct gk20a_instobj_iommu, base) -struct gk20a_instmem_priv { +struct gk20a_instmem { struct nvkm_instmem base; + + /* protects vaddr_* and gk20a_instobj::vaddr* */ spinlock_t lock; - u64 addr; + + /* CPU mappings LRU */ + unsigned int vaddr_use; + unsigned int vaddr_max; + struct list_head vaddr_lru; /* Only used if IOMMU if present */ struct mutex *mm_mutex; struct nvkm_mm *mm; struct iommu_domain *domain; unsigned long iommu_pgshift; + u16 iommu_bit; /* Only used by DMA API */ struct dma_attrs attrs; + + void __iomem * (*cpu_map)(struct nvkm_memory *); }; +#define gk20a_instmem(p) container_of((p), struct gk20a_instmem, base) + +static enum nvkm_memory_target +gk20a_instobj_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_HOST; +} + +static u64 +gk20a_instobj_addr(struct nvkm_memory *memory) +{ + return gk20a_instobj(memory)->mem.offset; +} + +static u64 +gk20a_instobj_size(struct nvkm_memory *memory) +{ + return (u64)gk20a_instobj(memory)->mem.size << 12; +} + +static void __iomem * +gk20a_instobj_cpu_map_dma(struct nvkm_memory *memory) +{ +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) + struct gk20a_instobj_dma *node = gk20a_instobj_dma(memory); + struct device *dev = node->base.imem->base.subdev.device->dev; + int npages = nvkm_memory_size(memory) >> 12; + struct page *pages[npages]; + int i; + + /* we shouldn't see a gk20a on anything but arm/arm64 anyways */ + /* phys_to_page does not exist on all platforms... */ + pages[0] = pfn_to_page(dma_to_phys(dev, node->handle) >> PAGE_SHIFT); + for (i = 1; i < npages; i++) + pages[i] = pages[0] + i; + + return vmap(pages, npages, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); +#else + BUG(); + return NULL; +#endif +} + +static void __iomem * +gk20a_instobj_cpu_map_iommu(struct nvkm_memory *memory) +{ + struct gk20a_instobj_iommu *node = gk20a_instobj_iommu(memory); + int npages = nvkm_memory_size(memory) >> 12; + + return vmap(node->pages, npages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); +} /* - * Use PRAMIN to read/write data and avoid coherency issues. - * PRAMIN uses the GPU path and ensures data will always be coherent. - * - * A dynamic mapping based solution would be desirable in the future, but - * the issue remains of how to maintain coherency efficiently. On ARM it is - * not easy (if possible at all?) to create uncached temporary mappings. + * Must be called while holding gk20a_instmem_lock */ +static void +gk20a_instmem_vaddr_gc(struct gk20a_instmem *imem, const u64 size) +{ + while (imem->vaddr_use + size > imem->vaddr_max) { + struct gk20a_instobj *obj; + + /* no candidate that can be unmapped, abort... */ + if (list_empty(&imem->vaddr_lru)) + break; + + obj = list_first_entry(&imem->vaddr_lru, struct gk20a_instobj, + vaddr_node); + list_del(&obj->vaddr_node); + vunmap(obj->vaddr); + obj->vaddr = NULL; + imem->vaddr_use -= nvkm_memory_size(&obj->memory); + nvkm_debug(&imem->base.subdev, "(GC) vaddr used: %x/%x\n", + imem->vaddr_use, imem->vaddr_max); -static u32 -gk20a_instobj_rd32(struct nvkm_object *object, u64 offset) + } +} + +static void __iomem * +gk20a_instobj_acquire(struct nvkm_memory *memory) { - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object); - struct gk20a_instobj_priv *node = (void *)object; + struct gk20a_instobj *node = gk20a_instobj(memory); + struct gk20a_instmem *imem = node->imem; + struct nvkm_ltc *ltc = imem->base.subdev.device->ltc; + const u64 size = nvkm_memory_size(memory); unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; - u32 data; - - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; + + nvkm_ltc_flush(ltc); + + spin_lock_irqsave(&imem->lock, flags); + + if (node->vaddr) { + /* remove us from the LRU list since we cannot be unmapped */ + list_del(&node->vaddr_node); + + goto out; + } + + /* try to free some address space if we reached the limit */ + gk20a_instmem_vaddr_gc(imem, size); + + node->vaddr = imem->cpu_map(memory); + + if (!node->vaddr) { + nvkm_error(&imem->base.subdev, "cannot map instobj - " + "this is not going to end well...\n"); + goto out; } - data = nv_rd32(priv, 0x700000 + addr); - spin_unlock_irqrestore(&priv->lock, flags); - return data; + + imem->vaddr_use += size; + nvkm_debug(&imem->base.subdev, "vaddr used: %x/%x\n", + imem->vaddr_use, imem->vaddr_max); + +out: + spin_unlock_irqrestore(&imem->lock, flags); + + return node->vaddr; } static void -gk20a_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) +gk20a_instobj_release(struct nvkm_memory *memory) { - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object); - struct gk20a_instobj_priv *node = (void *)object; + struct gk20a_instobj *node = gk20a_instobj(memory); + struct gk20a_instmem *imem = node->imem; + struct nvkm_ltc *ltc = imem->base.subdev.device->ltc; unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; - } - nv_wr32(priv, 0x700000 + addr, data); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&imem->lock, flags); + + /* add ourselves to the LRU list so our CPU mapping can be freed */ + list_add_tail(&node->vaddr_node, &imem->vaddr_lru); + + spin_unlock_irqrestore(&imem->lock, flags); + + wmb(); + nvkm_ltc_invalidate(ltc); +} + +static u32 +gk20a_instobj_rd32(struct nvkm_memory *memory, u64 offset) +{ + struct gk20a_instobj *node = gk20a_instobj(memory); + + return node->vaddr[offset / 4]; } static void -gk20a_instobj_dtor_dma(struct gk20a_instobj_priv *_node) +gk20a_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) { - struct gk20a_instobj_dma *node = (void *)_node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node); - struct device *dev = nv_device_base(nv_device(priv)); + struct gk20a_instobj *node = gk20a_instobj(memory); - if (unlikely(!node->cpuaddr)) - return; + node->vaddr[offset / 4] = data; +} - dma_free_attrs(dev, _node->mem->size << PAGE_SHIFT, node->cpuaddr, - node->handle, &priv->attrs); +static void +gk20a_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset) +{ + struct gk20a_instobj *node = gk20a_instobj(memory); + + nvkm_vm_map_at(vma, offset, &node->mem); } +/* + * Clear the CPU mapping of an instobj if it exists + */ static void -gk20a_instobj_dtor_iommu(struct gk20a_instobj_priv *_node) +gk20a_instobj_dtor(struct gk20a_instobj *node) +{ + struct gk20a_instmem *imem = node->imem; + struct gk20a_instobj *obj; + unsigned long flags; + + spin_lock_irqsave(&imem->lock, flags); + + if (!node->vaddr) + goto out; + + list_for_each_entry(obj, &imem->vaddr_lru, vaddr_node) { + if (obj == node) { + list_del(&obj->vaddr_node); + break; + } + } + vunmap(node->vaddr); + node->vaddr = NULL; + imem->vaddr_use -= nvkm_memory_size(&node->memory); + nvkm_debug(&imem->base.subdev, "vaddr used: %x/%x\n", + imem->vaddr_use, imem->vaddr_max); + +out: + spin_unlock_irqrestore(&imem->lock, flags); +} + +static void * +gk20a_instobj_dtor_dma(struct nvkm_memory *memory) +{ + struct gk20a_instobj_dma *node = gk20a_instobj_dma(memory); + struct gk20a_instmem *imem = node->base.imem; + struct device *dev = imem->base.subdev.device->dev; + + gk20a_instobj_dtor(&node->base); + + if (unlikely(!node->cpuaddr)) + goto out; + + dma_free_attrs(dev, node->base.mem.size << PAGE_SHIFT, node->cpuaddr, + node->handle, &imem->attrs); + +out: + return node; +} + +static void * +gk20a_instobj_dtor_iommu(struct nvkm_memory *memory) { - struct gk20a_instobj_iommu *node = (void *)_node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node); + struct gk20a_instobj_iommu *node = gk20a_instobj_iommu(memory); + struct gk20a_instmem *imem = node->base.imem; + struct device *dev = imem->base.subdev.device->dev; struct nvkm_mm_node *r; int i; - if (unlikely(list_empty(&_node->mem->regions))) - return; + gk20a_instobj_dtor(&node->base); - r = list_first_entry(&_node->mem->regions, struct nvkm_mm_node, + if (unlikely(list_empty(&node->base.mem.regions))) + goto out; + + r = list_first_entry(&node->base.mem.regions, struct nvkm_mm_node, rl_entry); - /* clear bit 34 to unmap pages */ - r->offset &= ~BIT(34 - priv->iommu_pgshift); + /* clear IOMMU bit to unmap pages */ + r->offset &= ~BIT(imem->iommu_bit - imem->iommu_pgshift); /* Unmap pages from GPU address space and free them */ - for (i = 0; i < _node->mem->size; i++) { - iommu_unmap(priv->domain, - (r->offset + i) << priv->iommu_pgshift, PAGE_SIZE); + for (i = 0; i < node->base.mem.size; i++) { + iommu_unmap(imem->domain, + (r->offset + i) << imem->iommu_pgshift, PAGE_SIZE); + dma_unmap_page(dev, node->dma_addrs[i], PAGE_SIZE, + DMA_BIDIRECTIONAL); __free_page(node->pages[i]); } /* Release area from GPU address space */ - mutex_lock(priv->mm_mutex); - nvkm_mm_free(priv->mm, &r); - mutex_unlock(priv->mm_mutex); -} + mutex_lock(imem->mm_mutex); + nvkm_mm_free(imem->mm, &r); + mutex_unlock(imem->mm_mutex); -static void -gk20a_instobj_dtor(struct nvkm_object *object) -{ - struct gk20a_instobj_priv *node = (void *)object; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node); +out: + return node; +} - if (priv->domain) - gk20a_instobj_dtor_iommu(node); - else - gk20a_instobj_dtor_dma(node); +static const struct nvkm_memory_func +gk20a_instobj_func_dma = { + .dtor = gk20a_instobj_dtor_dma, + .target = gk20a_instobj_target, + .addr = gk20a_instobj_addr, + .size = gk20a_instobj_size, + .acquire = gk20a_instobj_acquire, + .release = gk20a_instobj_release, + .rd32 = gk20a_instobj_rd32, + .wr32 = gk20a_instobj_wr32, + .map = gk20a_instobj_map, +}; - nvkm_instobj_destroy(&node->base); -} +static const struct nvkm_memory_func +gk20a_instobj_func_iommu = { + .dtor = gk20a_instobj_dtor_iommu, + .target = gk20a_instobj_target, + .addr = gk20a_instobj_addr, + .size = gk20a_instobj_size, + .acquire = gk20a_instobj_acquire, + .release = gk20a_instobj_release, + .rd32 = gk20a_instobj_rd32, + .wr32 = gk20a_instobj_wr32, + .map = gk20a_instobj_map, +}; static int -gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 npages, u32 align, - struct gk20a_instobj_priv **_node) +gk20a_instobj_ctor_dma(struct gk20a_instmem *imem, u32 npages, u32 align, + struct gk20a_instobj **_node) { struct gk20a_instobj_dma *node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent); - struct device *dev = nv_device_base(nv_device(parent)); - int ret; + struct nvkm_subdev *subdev = &imem->base.subdev; + struct device *dev = subdev->device->dev; - ret = nvkm_instobj_create_(parent, engine, oclass, sizeof(*node), - (void **)&node); + if (!(node = kzalloc(sizeof(*node), GFP_KERNEL))) + return -ENOMEM; *_node = &node->base; - if (ret) - return ret; + + nvkm_memory_ctor(&gk20a_instobj_func_dma, &node->base.memory); node->cpuaddr = dma_alloc_attrs(dev, npages << PAGE_SHIFT, &node->handle, GFP_KERNEL, - &priv->attrs); + &imem->attrs); if (!node->cpuaddr) { - nv_error(priv, "cannot allocate DMA memory\n"); + nvkm_error(subdev, "cannot allocate DMA memory\n"); return -ENOMEM; } /* alignment check */ if (unlikely(node->handle & (align - 1))) - nv_warn(priv, "memory not aligned as requested: %pad (0x%x)\n", - &node->handle, align); + nvkm_warn(subdev, + "memory not aligned as requested: %pad (0x%x)\n", + &node->handle, align); /* present memory for being mapped using small pages */ node->r.type = 12; node->r.offset = node->handle >> 12; node->r.length = (npages << PAGE_SHIFT) >> 12; - node->base._mem.offset = node->handle; + node->base.mem.offset = node->handle; - INIT_LIST_HEAD(&node->base._mem.regions); - list_add_tail(&node->r.rl_entry, &node->base._mem.regions); + INIT_LIST_HEAD(&node->base.mem.regions); + list_add_tail(&node->r.rl_entry, &node->base.mem.regions); return 0; } static int -gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 npages, u32 align, - struct gk20a_instobj_priv **_node) +gk20a_instobj_ctor_iommu(struct gk20a_instmem *imem, u32 npages, u32 align, + struct gk20a_instobj **_node) { struct gk20a_instobj_iommu *node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent); + struct nvkm_subdev *subdev = &imem->base.subdev; + struct device *dev = subdev->device->dev; struct nvkm_mm_node *r; int ret; int i; - ret = nvkm_instobj_create_(parent, engine, oclass, - sizeof(*node) + sizeof(node->pages[0]) * npages, - (void **)&node); + /* + * despite their variable size, instmem allocations are small enough + * (< 1 page) to be handled by kzalloc + */ + if (!(node = kzalloc(sizeof(*node) + ((sizeof(node->pages[0]) + + sizeof(*node->dma_addrs)) * npages), GFP_KERNEL))) + return -ENOMEM; *_node = &node->base; - if (ret) - return ret; + node->dma_addrs = (void *)(node->pages + npages); + + nvkm_memory_ctor(&gk20a_instobj_func_iommu, &node->base.memory); /* Allocate backing memory */ for (i = 0; i < npages; i++) { struct page *p = alloc_page(GFP_KERNEL); + dma_addr_t dma_adr; if (p == NULL) { ret = -ENOMEM; goto free_pages; } node->pages[i] = p; + dma_adr = dma_map_page(dev, p, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, dma_adr)) { + nvkm_error(subdev, "DMA mapping error!\n"); + ret = -ENOMEM; + goto free_pages; + } + node->dma_addrs[i] = dma_adr; } - mutex_lock(priv->mm_mutex); + mutex_lock(imem->mm_mutex); /* Reserve area from GPU address space */ - ret = nvkm_mm_head(priv->mm, 0, 1, npages, npages, - align >> priv->iommu_pgshift, &r); - mutex_unlock(priv->mm_mutex); + ret = nvkm_mm_head(imem->mm, 0, 1, npages, npages, + align >> imem->iommu_pgshift, &r); + mutex_unlock(imem->mm_mutex); if (ret) { - nv_error(priv, "virtual space is full!\n"); + nvkm_error(subdev, "IOMMU space is full!\n"); goto free_pages; } /* Map into GPU address space */ for (i = 0; i < npages; i++) { - struct page *p = node->pages[i]; - u32 offset = (r->offset + i) << priv->iommu_pgshift; + u32 offset = (r->offset + i) << imem->iommu_pgshift; - ret = iommu_map(priv->domain, offset, page_to_phys(p), + ret = iommu_map(imem->domain, offset, node->dma_addrs[i], PAGE_SIZE, IOMMU_READ | IOMMU_WRITE); if (ret < 0) { - nv_error(priv, "IOMMU mapping failure: %d\n", ret); + nvkm_error(subdev, "IOMMU mapping failure: %d\n", ret); while (i-- > 0) { offset -= PAGE_SIZE; - iommu_unmap(priv->domain, offset, PAGE_SIZE); + iommu_unmap(imem->domain, offset, PAGE_SIZE); } goto release_area; } } - /* Bit 34 tells that an address is to be resolved through the IOMMU */ - r->offset |= BIT(34 - priv->iommu_pgshift); + /* IOMMU bit tells that an address is to be resolved through the IOMMU */ + r->offset |= BIT(imem->iommu_bit - imem->iommu_pgshift); - node->base._mem.offset = ((u64)r->offset) << priv->iommu_pgshift; + node->base.mem.offset = ((u64)r->offset) << imem->iommu_pgshift; - INIT_LIST_HEAD(&node->base._mem.regions); - list_add_tail(&r->rl_entry, &node->base._mem.regions); + INIT_LIST_HEAD(&node->base.mem.regions); + list_add_tail(&r->rl_entry, &node->base.mem.regions); return 0; release_area: - mutex_lock(priv->mm_mutex); - nvkm_mm_free(priv->mm, &r); - mutex_unlock(priv->mm_mutex); + mutex_lock(imem->mm_mutex); + nvkm_mm_free(imem->mm, &r); + mutex_unlock(imem->mm_mutex); free_pages: - for (i = 0; i < npages && node->pages[i] != NULL; i++) + for (i = 0; i < npages && node->pages[i] != NULL; i++) { + dma_addr_t dma_addr = node->dma_addrs[i]; + if (dma_addr) + dma_unmap_page(dev, dma_addr, PAGE_SIZE, + DMA_BIDIRECTIONAL); __free_page(node->pages[i]); + } return ret; } static int -gk20a_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 _size, - struct nvkm_object **pobject) +gk20a_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nvkm_instobj_args *args = data; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent); - struct gk20a_instobj_priv *node; - u32 size, align; + struct gk20a_instmem *imem = gk20a_instmem(base); + struct nvkm_subdev *subdev = &imem->base.subdev; + struct gk20a_instobj *node = NULL; int ret; - nv_debug(parent, "%s (%s): size: %x align: %x\n", __func__, - priv->domain ? "IOMMU" : "DMA", args->size, args->align); + nvkm_debug(subdev, "%s (%s): size: %x align: %x\n", __func__, + imem->domain ? "IOMMU" : "DMA", size, align); /* Round size and align to page bounds */ - size = max(roundup(args->size, PAGE_SIZE), PAGE_SIZE); - align = max(roundup(args->align, PAGE_SIZE), PAGE_SIZE); + size = max(roundup(size, PAGE_SIZE), PAGE_SIZE); + align = max(roundup(align, PAGE_SIZE), PAGE_SIZE); - if (priv->domain) - ret = gk20a_instobj_ctor_iommu(parent, engine, oclass, - size >> PAGE_SHIFT, align, &node); + if (imem->domain) + ret = gk20a_instobj_ctor_iommu(imem, size >> PAGE_SHIFT, + align, &node); else - ret = gk20a_instobj_ctor_dma(parent, engine, oclass, - size >> PAGE_SHIFT, align, &node); - *pobject = nv_object(node); + ret = gk20a_instobj_ctor_dma(imem, size >> PAGE_SHIFT, + align, &node); + *pmemory = node ? &node->memory : NULL; if (ret) return ret; - node->mem = &node->_mem; + node->imem = imem; /* present memory for being mapped using small pages */ - node->mem->size = size >> 12; - node->mem->memtype = 0; - node->mem->page_shift = 12; - - node->base.addr = node->mem->offset; - node->base.size = size; + node->mem.size = size >> 12; + node->mem.memtype = 0; + node->mem.page_shift = 12; - nv_debug(parent, "alloc size: 0x%x, align: 0x%x, gaddr: 0x%llx\n", - size, align, node->mem->offset); + nvkm_debug(subdev, "alloc size: 0x%x, align: 0x%x, gaddr: 0x%llx\n", + size, align, node->mem.offset); return 0; } -static struct nvkm_instobj_impl -gk20a_instobj_oclass = { - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_instobj_ctor, - .dtor = gk20a_instobj_dtor, - .init = _nvkm_instobj_init, - .fini = _nvkm_instobj_fini, - .rd32 = gk20a_instobj_rd32, - .wr32 = gk20a_instobj_wr32, - }, -}; +static void * +gk20a_instmem_dtor(struct nvkm_instmem *base) +{ + struct gk20a_instmem *imem = gk20a_instmem(base); + /* perform some sanity checks... */ + if (!list_empty(&imem->vaddr_lru)) + nvkm_warn(&base->subdev, "instobj LRU not empty!\n"); + if (imem->vaddr_use != 0) + nvkm_warn(&base->subdev, "instobj vmap area not empty! " + "0x%x bytes still mapped\n", imem->vaddr_use); -static int -gk20a_instmem_fini(struct nvkm_object *object, bool suspend) -{ - struct gk20a_instmem_priv *priv = (void *)object; - priv->addr = ~0ULL; - return nvkm_instmem_fini(&priv->base, suspend); + return imem; } -static int -gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk20a_instmem_priv *priv; - struct nouveau_platform_device *plat; - int ret; - - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - spin_lock_init(&priv->lock); +static const struct nvkm_instmem_func +gk20a_instmem = { + .dtor = gk20a_instmem_dtor, + .memory_new = gk20a_instobj_new, + .persistent = true, + .zero = false, +}; - plat = nv_device_to_platform(nv_device(parent)); - if (plat->gpu->iommu.domain) { - priv->domain = plat->gpu->iommu.domain; - priv->mm = plat->gpu->iommu.mm; - priv->iommu_pgshift = plat->gpu->iommu.pgshift; - priv->mm_mutex = &plat->gpu->iommu.mutex; +int +gk20a_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) +{ + struct nvkm_device_tegra *tdev = device->func->tegra(device); + struct gk20a_instmem *imem; - nv_info(priv, "using IOMMU\n"); + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&gk20a_instmem, device, index, &imem->base); + spin_lock_init(&imem->lock); + *pimem = &imem->base; + + /* do not allow more than 1MB of CPU-mapped instmem */ + imem->vaddr_use = 0; + imem->vaddr_max = 0x100000; + INIT_LIST_HEAD(&imem->vaddr_lru); + + if (tdev->iommu.domain) { + imem->mm_mutex = &tdev->iommu.mutex; + imem->mm = &tdev->iommu.mm; + imem->domain = tdev->iommu.domain; + imem->iommu_pgshift = tdev->iommu.pgshift; + imem->cpu_map = gk20a_instobj_cpu_map_iommu; + imem->iommu_bit = tdev->func->iommu_bit; + + nvkm_info(&imem->base.subdev, "using IOMMU\n"); } else { - init_dma_attrs(&priv->attrs); - /* - * We will access instmem through PRAMIN and thus do not need a - * consistent CPU pointer or kernel mapping - */ - dma_set_attr(DMA_ATTR_NON_CONSISTENT, &priv->attrs); - dma_set_attr(DMA_ATTR_WEAK_ORDERING, &priv->attrs); - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &priv->attrs); - dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &priv->attrs); - - nv_info(priv, "using DMA API\n"); + init_dma_attrs(&imem->attrs); + /* We will access the memory through our own mapping */ + dma_set_attr(DMA_ATTR_NON_CONSISTENT, &imem->attrs); + dma_set_attr(DMA_ATTR_WEAK_ORDERING, &imem->attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &imem->attrs); + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &imem->attrs); + imem->cpu_map = gk20a_instobj_cpu_map_dma; + + nvkm_info(&imem->base.subdev, "using DMA API\n"); } return 0; } - -struct nvkm_oclass * -gk20a_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_instmem_ctor, - .dtor = _nvkm_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = gk20a_instmem_fini, - }, - .instobj = &gk20a_instobj_oclass.base, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index 282143f49..6133c8bb2 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -21,173 +21,207 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#define nv04_instmem(p) container_of((p), struct nv04_instmem, base) +#include "priv.h" +#include <core/memory.h> #include <core/ramht.h> +struct nv04_instmem { + struct nvkm_instmem base; + struct nvkm_mm heap; +}; + /****************************************************************************** * instmem object implementation *****************************************************************************/ +#define nv04_instobj(p) container_of((p), struct nv04_instobj, memory) -static u32 -nv04_instobj_rd32(struct nvkm_object *object, u64 addr) +struct nv04_instobj { + struct nvkm_memory memory; + struct nv04_instmem *imem; + struct nvkm_mm_node *node; +}; + +static enum nvkm_memory_target +nv04_instobj_target(struct nvkm_memory *memory) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv04_instobj_priv *node = (void *)object; - return nv_ro32(priv, node->mem->offset + addr); + return NVKM_MEM_TARGET_INST; } -static void -nv04_instobj_wr32(struct nvkm_object *object, u64 addr, u32 data) +static u64 +nv04_instobj_addr(struct nvkm_memory *memory) +{ + return nv04_instobj(memory)->node->offset; +} + +static u64 +nv04_instobj_size(struct nvkm_memory *memory) +{ + return nv04_instobj(memory)->node->length; +} + +static void __iomem * +nv04_instobj_acquire(struct nvkm_memory *memory) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv04_instobj_priv *node = (void *)object; - nv_wo32(priv, node->mem->offset + addr, data); + struct nv04_instobj *iobj = nv04_instobj(memory); + struct nvkm_device *device = iobj->imem->base.subdev.device; + return device->pri + 0x700000 + iobj->node->offset; } static void -nv04_instobj_dtor(struct nvkm_object *object) +nv04_instobj_release(struct nvkm_memory *memory) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv04_instobj_priv *node = (void *)object; - struct nvkm_subdev *subdev = (void *)priv; +} - mutex_lock(&subdev->mutex); - nvkm_mm_free(&priv->heap, &node->mem); - mutex_unlock(&subdev->mutex); +static u32 +nv04_instobj_rd32(struct nvkm_memory *memory, u64 offset) +{ + struct nv04_instobj *iobj = nv04_instobj(memory); + struct nvkm_device *device = iobj->imem->base.subdev.device; + return nvkm_rd32(device, 0x700000 + iobj->node->offset + offset); +} - nvkm_instobj_destroy(&node->base); +static void +nv04_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) +{ + struct nv04_instobj *iobj = nv04_instobj(memory); + struct nvkm_device *device = iobj->imem->base.subdev.device; + nvkm_wr32(device, 0x700000 + iobj->node->offset + offset, data); } +static void * +nv04_instobj_dtor(struct nvkm_memory *memory) +{ + struct nv04_instobj *iobj = nv04_instobj(memory); + mutex_lock(&iobj->imem->base.subdev.mutex); + nvkm_mm_free(&iobj->imem->heap, &iobj->node); + mutex_unlock(&iobj->imem->base.subdev.mutex); + return iobj; +} + +static const struct nvkm_memory_func +nv04_instobj_func = { + .dtor = nv04_instobj_dtor, + .target = nv04_instobj_target, + .size = nv04_instobj_size, + .addr = nv04_instobj_addr, + .acquire = nv04_instobj_acquire, + .release = nv04_instobj_release, + .rd32 = nv04_instobj_rd32, + .wr32 = nv04_instobj_wr32, +}; + static int -nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(parent); - struct nv04_instobj_priv *node; - struct nvkm_instobj_args *args = data; - struct nvkm_subdev *subdev = (void *)priv; + struct nv04_instmem *imem = nv04_instmem(base); + struct nv04_instobj *iobj; int ret; - if (!args->align) - args->align = 1; + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) + return -ENOMEM; + *pmemory = &iobj->memory; - ret = nvkm_instobj_create(parent, engine, oclass, &node); - *pobject = nv_object(node); - if (ret) - return ret; - - mutex_lock(&subdev->mutex); - ret = nvkm_mm_head(&priv->heap, 0, 1, args->size, args->size, - args->align, &node->mem); - mutex_unlock(&subdev->mutex); - if (ret) - return ret; + nvkm_memory_ctor(&nv04_instobj_func, &iobj->memory); + iobj->imem = imem; - node->base.addr = node->mem->offset; - node->base.size = node->mem->length; - return 0; + mutex_lock(&imem->base.subdev.mutex); + ret = nvkm_mm_head(&imem->heap, 0, 1, size, size, + align ? align : 1, &iobj->node); + mutex_unlock(&imem->base.subdev.mutex); + return ret; } -struct nvkm_instobj_impl -nv04_instobj_oclass = { - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_instobj_ctor, - .dtor = nv04_instobj_dtor, - .init = _nvkm_instobj_init, - .fini = _nvkm_instobj_fini, - .rd32 = nv04_instobj_rd32, - .wr32 = nv04_instobj_wr32, - }, -}; - /****************************************************************************** * instmem subdev implementation *****************************************************************************/ static u32 -nv04_instmem_rd32(struct nvkm_object *object, u64 addr) +nv04_instmem_rd32(struct nvkm_instmem *imem, u32 addr) { - return nv_rd32(object, 0x700000 + addr); + return nvkm_rd32(imem->subdev.device, 0x700000 + addr); } static void -nv04_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - return nv_wr32(object, 0x700000 + addr, data); -} - -void -nv04_instmem_dtor(struct nvkm_object *object) +nv04_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data) { - struct nv04_instmem_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->ramfc); - nvkm_gpuobj_ref(NULL, &priv->ramro); - nvkm_ramht_ref(NULL, &priv->ramht); - nvkm_gpuobj_ref(NULL, &priv->vbios); - nvkm_mm_fini(&priv->heap); - if (priv->iomem) - iounmap(priv->iomem); - nvkm_instmem_destroy(&priv->base); + nvkm_wr32(imem->subdev.device, 0x700000 + addr, data); } static int -nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_instmem_oneinit(struct nvkm_instmem *base) { - struct nv04_instmem_priv *priv; + struct nv04_instmem *imem = nv04_instmem(base); + struct nvkm_device *device = imem->base.subdev.device; int ret; - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - /* PRAMIN aperture maps over the end of VRAM, reserve it */ - priv->base.reserved = 512 * 1024; + imem->base.reserved = 512 * 1024; - ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1); + ret = nvkm_mm_init(&imem->heap, 0, imem->base.reserved, 1); if (ret) return ret; /* 0x00000-0x10000: reserve for probable vbios image */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0, - &priv->vbios); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x10000, 0, false, + &imem->base.vbios); if (ret) return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht); + ret = nvkm_ramht_new(device, 0x08000, 0, NULL, &imem->base.ramht); if (ret) return ret; /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00800, 0, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x00800, 0, true, + &imem->base.ramfc); if (ret) return ret; /* 0x18800-0x18a00: reserve for RAMRO */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00200, 0, 0, - &priv->ramro); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x00200, 0, false, + &imem->base.ramro); if (ret) return ret; return 0; } -struct nvkm_oclass * -nv04_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_instmem_ctor, - .dtor = nv04_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = _nvkm_instmem_fini, - .rd32 = nv04_instmem_rd32, - .wr32 = nv04_instmem_wr32, - }, - .instobj = &nv04_instobj_oclass.base, -}.base; +static void * +nv04_instmem_dtor(struct nvkm_instmem *base) +{ + struct nv04_instmem *imem = nv04_instmem(base); + nvkm_memory_del(&imem->base.ramfc); + nvkm_memory_del(&imem->base.ramro); + nvkm_ramht_del(&imem->base.ramht); + nvkm_memory_del(&imem->base.vbios); + nvkm_mm_fini(&imem->heap); + return imem; +} + +static const struct nvkm_instmem_func +nv04_instmem = { + .dtor = nv04_instmem_dtor, + .oneinit = nv04_instmem_oneinit, + .rd32 = nv04_instmem_rd32, + .wr32 = nv04_instmem_wr32, + .memory_new = nv04_instobj_new, + .persistent = false, + .zero = false, +}; + +int +nv04_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) +{ + struct nv04_instmem *imem; + + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&nv04_instmem, device, index, &imem->base); + *pimem = &imem->base; + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h deleted file mode 100644 index 42b6c9280..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __NV04_INSTMEM_H__ -#define __NV04_INSTMEM_H__ -#include "priv.h" - -#include <core/mm.h> - -extern struct nvkm_instobj_impl nv04_instobj_oclass; - -struct nv04_instmem_priv { - struct nvkm_instmem base; - - void __iomem *iomem; - struct nvkm_mm heap; - - struct nvkm_gpuobj *vbios; - struct nvkm_ramht *ramht; - struct nvkm_gpuobj *ramro; - struct nvkm_gpuobj *ramfc; -}; - -static inline struct nv04_instmem_priv * -nv04_instmem(void *obj) -{ - return (void *)nvkm_instmem(obj); -} - -struct nv04_instobj_priv { - struct nvkm_instobj base; - struct nvkm_mm_node *mem; -}; - -void nv04_instmem_dtor(struct nvkm_object *); - -int nv04_instmem_alloc(struct nvkm_instmem *, struct nvkm_object *, - u32 size, u32 align, struct nvkm_object **pobject); -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index b42b8588f..c0543875e 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -21,116 +21,239 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#define nv40_instmem(p) container_of((p), struct nv40_instmem, base) +#include "priv.h" +#include <core/memory.h> #include <core/ramht.h> #include <engine/gr/nv40.h> +struct nv40_instmem { + struct nvkm_instmem base; + struct nvkm_mm heap; + void __iomem *iomem; +}; + /****************************************************************************** - * instmem subdev implementation + * instmem object implementation *****************************************************************************/ +#define nv40_instobj(p) container_of((p), struct nv40_instobj, memory) + +struct nv40_instobj { + struct nvkm_memory memory; + struct nv40_instmem *imem; + struct nvkm_mm_node *node; +}; + +static enum nvkm_memory_target +nv40_instobj_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_INST; +} + +static u64 +nv40_instobj_addr(struct nvkm_memory *memory) +{ + return nv40_instobj(memory)->node->offset; +} + +static u64 +nv40_instobj_size(struct nvkm_memory *memory) +{ + return nv40_instobj(memory)->node->length; +} + +static void __iomem * +nv40_instobj_acquire(struct nvkm_memory *memory) +{ + struct nv40_instobj *iobj = nv40_instobj(memory); + return iobj->imem->iomem + iobj->node->offset; +} + +static void +nv40_instobj_release(struct nvkm_memory *memory) +{ +} static u32 -nv40_instmem_rd32(struct nvkm_object *object, u64 addr) +nv40_instobj_rd32(struct nvkm_memory *memory, u64 offset) { - struct nv04_instmem_priv *priv = (void *)object; - return ioread32_native(priv->iomem + addr); + struct nv40_instobj *iobj = nv40_instobj(memory); + return ioread32_native(iobj->imem->iomem + iobj->node->offset + offset); } static void -nv40_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) +nv40_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) +{ + struct nv40_instobj *iobj = nv40_instobj(memory); + iowrite32_native(data, iobj->imem->iomem + iobj->node->offset + offset); +} + +static void * +nv40_instobj_dtor(struct nvkm_memory *memory) { - struct nv04_instmem_priv *priv = (void *)object; - iowrite32_native(data, priv->iomem + addr); + struct nv40_instobj *iobj = nv40_instobj(memory); + mutex_lock(&iobj->imem->base.subdev.mutex); + nvkm_mm_free(&iobj->imem->heap, &iobj->node); + mutex_unlock(&iobj->imem->base.subdev.mutex); + return iobj; } +static const struct nvkm_memory_func +nv40_instobj_func = { + .dtor = nv40_instobj_dtor, + .target = nv40_instobj_target, + .size = nv40_instobj_size, + .addr = nv40_instobj_addr, + .acquire = nv40_instobj_acquire, + .release = nv40_instobj_release, + .rd32 = nv40_instobj_rd32, + .wr32 = nv40_instobj_wr32, +}; + static int -nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nvkm_device *device = nv_device(parent); - struct nv04_instmem_priv *priv; - int ret, bar, vs; + struct nv40_instmem *imem = nv40_instmem(base); + struct nv40_instobj *iobj; + int ret; - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) + return -ENOMEM; + *pmemory = &iobj->memory; - /* map bar */ - if (nv_device_resource_len(device, 2)) - bar = 2; - else - bar = 3; + nvkm_memory_ctor(&nv40_instobj_func, &iobj->memory); + iobj->imem = imem; - priv->iomem = ioremap(nv_device_resource_start(device, bar), - nv_device_resource_len(device, bar)); - if (!priv->iomem) { - nv_error(priv, "unable to map PRAMIN BAR\n"); - return -EFAULT; - } + mutex_lock(&imem->base.subdev.mutex); + ret = nvkm_mm_head(&imem->heap, 0, 1, size, size, + align ? align : 1, &iobj->node); + mutex_unlock(&imem->base.subdev.mutex); + return ret; +} + +/****************************************************************************** + * instmem subdev implementation + *****************************************************************************/ + +static u32 +nv40_instmem_rd32(struct nvkm_instmem *base, u32 addr) +{ + return ioread32_native(nv40_instmem(base)->iomem + addr); +} + +static void +nv40_instmem_wr32(struct nvkm_instmem *base, u32 addr, u32 data) +{ + iowrite32_native(data, nv40_instmem(base)->iomem + addr); +} + +static int +nv40_instmem_oneinit(struct nvkm_instmem *base) +{ + struct nv40_instmem *imem = nv40_instmem(base); + struct nvkm_device *device = imem->base.subdev.device; + int ret, vs; /* PRAMIN aperture maps over the end of vram, reserve enough space * to fit graphics contexts for every channel, the magics come * from engine/gr/nv40.c */ - vs = hweight8((nv_rd32(priv, 0x001540) & 0x0000ff00) >> 8); - if (device->chipset == 0x40) priv->base.reserved = 0x6aa0 * vs; - else if (device->chipset < 0x43) priv->base.reserved = 0x4f00 * vs; - else if (nv44_gr_class(priv)) priv->base.reserved = 0x4980 * vs; - else priv->base.reserved = 0x4a40 * vs; - priv->base.reserved += 16 * 1024; - priv->base.reserved *= 32; /* per-channel */ - priv->base.reserved += 512 * 1024; /* pci(e)gart table */ - priv->base.reserved += 512 * 1024; /* object storage */ - - priv->base.reserved = round_up(priv->base.reserved, 4096); - - ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1); + vs = hweight8((nvkm_rd32(device, 0x001540) & 0x0000ff00) >> 8); + if (device->chipset == 0x40) imem->base.reserved = 0x6aa0 * vs; + else if (device->chipset < 0x43) imem->base.reserved = 0x4f00 * vs; + else if (nv44_gr_class(device)) imem->base.reserved = 0x4980 * vs; + else imem->base.reserved = 0x4a40 * vs; + imem->base.reserved += 16 * 1024; + imem->base.reserved *= 32; /* per-channel */ + imem->base.reserved += 512 * 1024; /* pci(e)gart table */ + imem->base.reserved += 512 * 1024; /* object storage */ + imem->base.reserved = round_up(imem->base.reserved, 4096); + + ret = nvkm_mm_init(&imem->heap, 0, imem->base.reserved, 1); if (ret) return ret; /* 0x00000-0x10000: reserve for probable vbios image */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0, - &priv->vbios); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x10000, 0, false, + &imem->base.vbios); if (ret) return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht); + ret = nvkm_ramht_new(device, 0x08000, 0, NULL, &imem->base.ramht); if (ret) return ret; /* 0x18000-0x18200: reserve for RAMRO * 0x18200-0x20000: padding */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x08000, 0, 0, - &priv->ramro); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x08000, 0, false, + &imem->base.ramro); if (ret) return ret; /* 0x20000-0x21000: reserve for RAMFC * 0x21000-0x40000: padding and some unknown crap */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x20000, 0, true, + &imem->base.ramfc); if (ret) return ret; return 0; } -struct nvkm_oclass * -nv40_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0x40), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_instmem_ctor, - .dtor = nv04_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = _nvkm_instmem_fini, - .rd32 = nv40_instmem_rd32, - .wr32 = nv40_instmem_wr32, - }, - .instobj = &nv04_instobj_oclass.base, -}.base; +static void * +nv40_instmem_dtor(struct nvkm_instmem *base) +{ + struct nv40_instmem *imem = nv40_instmem(base); + nvkm_memory_del(&imem->base.ramfc); + nvkm_memory_del(&imem->base.ramro); + nvkm_ramht_del(&imem->base.ramht); + nvkm_memory_del(&imem->base.vbios); + nvkm_mm_fini(&imem->heap); + if (imem->iomem) + iounmap(imem->iomem); + return imem; +} + +static const struct nvkm_instmem_func +nv40_instmem = { + .dtor = nv40_instmem_dtor, + .oneinit = nv40_instmem_oneinit, + .rd32 = nv40_instmem_rd32, + .wr32 = nv40_instmem_wr32, + .memory_new = nv40_instobj_new, + .persistent = false, + .zero = false, +}; + +int +nv40_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) +{ + struct nv40_instmem *imem; + int bar; + + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&nv40_instmem, device, index, &imem->base); + *pimem = &imem->base; + + /* map bar */ + if (device->func->resource_size(device, 2)) + bar = 2; + else + bar = 3; + + imem->iomem = ioremap(device->func->resource_addr(device, bar), + device->func->resource_size(device, bar)); + if (!imem->iomem) { + nvkm_error(&imem->base.subdev, "unable to map PRAMIN BAR\n"); + return -EFAULT; + } + + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 8404143f9..6d512c062 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -21,149 +21,229 @@ * * Authors: Ben Skeggs */ +#define nv50_instmem(p) container_of((p), struct nv50_instmem, base) #include "priv.h" +#include <core/memory.h> +#include <subdev/bar.h> #include <subdev/fb.h> +#include <subdev/mmu.h> -struct nv50_instmem_priv { +struct nv50_instmem { struct nvkm_instmem base; + unsigned long lock_flags; spinlock_t lock; u64 addr; }; -struct nv50_instobj_priv { - struct nvkm_instobj base; - struct nvkm_mem *mem; -}; - /****************************************************************************** * instmem object implementation *****************************************************************************/ +#define nv50_instobj(p) container_of((p), struct nv50_instobj, memory) -static u32 -nv50_instobj_rd32(struct nvkm_object *object, u64 offset) +struct nv50_instobj { + struct nvkm_memory memory; + struct nv50_instmem *imem; + struct nvkm_mem *mem; + struct nvkm_vma bar; + void *map; +}; + +static enum nvkm_memory_target +nv50_instobj_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_VRAM; +} + +static u64 +nv50_instobj_addr(struct nvkm_memory *memory) +{ + return nv50_instobj(memory)->mem->offset; +} + +static u64 +nv50_instobj_size(struct nvkm_memory *memory) +{ + return (u64)nv50_instobj(memory)->mem->size << NVKM_RAM_MM_SHIFT; +} + +static void +nv50_instobj_boot(struct nvkm_memory *memory, struct nvkm_vm *vm) +{ + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nvkm_subdev *subdev = &iobj->imem->base.subdev; + struct nvkm_device *device = subdev->device; + u64 size = nvkm_memory_size(memory); + void __iomem *map; + int ret; + + iobj->map = ERR_PTR(-ENOMEM); + + ret = nvkm_vm_get(vm, size, 12, NV_MEM_ACCESS_RW, &iobj->bar); + if (ret == 0) { + map = ioremap(device->func->resource_addr(device, 3) + + (u32)iobj->bar.offset, size); + if (map) { + nvkm_memory_map(memory, &iobj->bar, 0); + iobj->map = map; + } else { + nvkm_warn(subdev, "PRAMIN ioremap failed\n"); + nvkm_vm_put(&iobj->bar); + } + } else { + nvkm_warn(subdev, "PRAMIN exhausted\n"); + } +} + +static void +nv50_instobj_release(struct nvkm_memory *memory) { - struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv50_instobj_priv *node = (void *)object; + struct nv50_instmem *imem = nv50_instobj(memory)->imem; + spin_unlock_irqrestore(&imem->lock, imem->lock_flags); +} + +static void __iomem * +nv50_instobj_acquire(struct nvkm_memory *memory) +{ + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nv50_instmem *imem = iobj->imem; + struct nvkm_bar *bar = imem->base.subdev.device->bar; + struct nvkm_vm *vm; unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; + + if (!iobj->map && (vm = nvkm_bar_kmap(bar))) + nvkm_memory_boot(memory, vm); + if (!IS_ERR_OR_NULL(iobj->map)) + return iobj->map; + + spin_lock_irqsave(&imem->lock, flags); + imem->lock_flags = flags; + return NULL; +} + +static u32 +nv50_instobj_rd32(struct nvkm_memory *memory, u64 offset) +{ + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nv50_instmem *imem = iobj->imem; + struct nvkm_device *device = imem->base.subdev.device; + u64 base = (iobj->mem->offset + offset) & 0xffffff00000ULL; + u64 addr = (iobj->mem->offset + offset) & 0x000000fffffULL; u32 data; - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; + if (unlikely(imem->addr != base)) { + nvkm_wr32(device, 0x001700, base >> 16); + imem->addr = base; } - data = nv_rd32(priv, 0x700000 + addr); - spin_unlock_irqrestore(&priv->lock, flags); + data = nvkm_rd32(device, 0x700000 + addr); return data; } static void -nv50_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) +nv50_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) { - struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv50_instobj_priv *node = (void *)object; - unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; - - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nv50_instmem *imem = iobj->imem; + struct nvkm_device *device = imem->base.subdev.device; + u64 base = (iobj->mem->offset + offset) & 0xffffff00000ULL; + u64 addr = (iobj->mem->offset + offset) & 0x000000fffffULL; + + if (unlikely(imem->addr != base)) { + nvkm_wr32(device, 0x001700, base >> 16); + imem->addr = base; } - nv_wr32(priv, 0x700000 + addr, data); - spin_unlock_irqrestore(&priv->lock, flags); + nvkm_wr32(device, 0x700000 + addr, data); } static void -nv50_instobj_dtor(struct nvkm_object *object) +nv50_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset) { - struct nv50_instobj_priv *node = (void *)object; - struct nvkm_fb *pfb = nvkm_fb(object); - pfb->ram->put(pfb, &node->mem); - nvkm_instobj_destroy(&node->base); + struct nv50_instobj *iobj = nv50_instobj(memory); + nvkm_vm_map_at(vma, offset, iobj->mem); } +static void * +nv50_instobj_dtor(struct nvkm_memory *memory) +{ + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nvkm_ram *ram = iobj->imem->base.subdev.device->fb->ram; + if (!IS_ERR_OR_NULL(iobj->map)) { + nvkm_vm_put(&iobj->bar); + iounmap(iobj->map); + } + ram->func->put(ram, &iobj->mem); + return iobj; +} + +static const struct nvkm_memory_func +nv50_instobj_func = { + .dtor = nv50_instobj_dtor, + .target = nv50_instobj_target, + .size = nv50_instobj_size, + .addr = nv50_instobj_addr, + .boot = nv50_instobj_boot, + .acquire = nv50_instobj_acquire, + .release = nv50_instobj_release, + .rd32 = nv50_instobj_rd32, + .wr32 = nv50_instobj_wr32, + .map = nv50_instobj_map, +}; + static int -nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_instobj_args *args = data; - struct nv50_instobj_priv *node; + struct nv50_instmem *imem = nv50_instmem(base); + struct nv50_instobj *iobj; + struct nvkm_ram *ram = imem->base.subdev.device->fb->ram; int ret; - args->size = max((args->size + 4095) & ~4095, (u32)4096); - args->align = max((args->align + 4095) & ~4095, (u32)4096); + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) + return -ENOMEM; + *pmemory = &iobj->memory; - ret = nvkm_instobj_create(parent, engine, oclass, &node); - *pobject = nv_object(node); - if (ret) - return ret; + nvkm_memory_ctor(&nv50_instobj_func, &iobj->memory); + iobj->imem = imem; + + size = max((size + 4095) & ~4095, (u32)4096); + align = max((align + 4095) & ~4095, (u32)4096); - ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem); + ret = ram->func->get(ram, size, align, 0, 0x800, &iobj->mem); if (ret) return ret; - node->base.addr = node->mem->offset; - node->base.size = node->mem->size << 12; - node->mem->page_shift = 12; + iobj->mem->page_shift = 12; return 0; } -static struct nvkm_instobj_impl -nv50_instobj_oclass = { - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_instobj_ctor, - .dtor = nv50_instobj_dtor, - .init = _nvkm_instobj_init, - .fini = _nvkm_instobj_fini, - .rd32 = nv50_instobj_rd32, - .wr32 = nv50_instobj_wr32, - }, -}; - /****************************************************************************** * instmem subdev implementation *****************************************************************************/ -static int -nv50_instmem_fini(struct nvkm_object *object, bool suspend) +static void +nv50_instmem_fini(struct nvkm_instmem *base) { - struct nv50_instmem_priv *priv = (void *)object; - priv->addr = ~0ULL; - return nvkm_instmem_fini(&priv->base, suspend); + nv50_instmem(base)->addr = ~0ULL; } -static int -nv50_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_instmem_priv *priv; - int ret; +static const struct nvkm_instmem_func +nv50_instmem = { + .fini = nv50_instmem_fini, + .memory_new = nv50_instobj_new, + .persistent = false, + .zero = false, +}; - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +int +nv50_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) +{ + struct nv50_instmem *imem; - spin_lock_init(&priv->lock); + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&nv50_instmem, device, index, &imem->base); + spin_lock_init(&imem->lock); + *pimem = &imem->base; return 0; } - -struct nvkm_oclass * -nv50_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_instmem_ctor, - .dtor = _nvkm_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = nv50_instmem_fini, - }, - .instobj = &nv50_instobj_oclass.base, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index b10e292e5..ace447186 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -1,54 +1,20 @@ #ifndef __NVKM_INSTMEM_PRIV_H__ #define __NVKM_INSTMEM_PRIV_H__ +#define nvkm_instmem(p) container_of((p), struct nvkm_instmem, subdev) #include <subdev/instmem.h> -struct nvkm_instobj_impl { - struct nvkm_oclass base; +struct nvkm_instmem_func { + void *(*dtor)(struct nvkm_instmem *); + int (*oneinit)(struct nvkm_instmem *); + void (*fini)(struct nvkm_instmem *); + u32 (*rd32)(struct nvkm_instmem *, u32 addr); + void (*wr32)(struct nvkm_instmem *, u32 addr, u32 data); + int (*memory_new)(struct nvkm_instmem *, u32 size, u32 align, + bool zero, struct nvkm_memory **); + bool persistent; + bool zero; }; -struct nvkm_instobj_args { - u32 size; - u32 align; -}; - -#define nvkm_instobj_create(p,e,o,d) \ - nvkm_instobj_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_instobj_destroy(p) ({ \ - struct nvkm_instobj *iobj = (p); \ - _nvkm_instobj_dtor(nv_object(iobj)); \ -}) -#define nvkm_instobj_init(p) \ - nvkm_object_init(&(p)->base) -#define nvkm_instobj_fini(p,s) \ - nvkm_object_fini(&(p)->base, (s)) - -int nvkm_instobj_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_instobj_dtor(struct nvkm_object *); -#define _nvkm_instobj_init nvkm_object_init -#define _nvkm_instobj_fini nvkm_object_fini - -struct nvkm_instmem_impl { - struct nvkm_oclass base; - struct nvkm_oclass *instobj; -}; - -#define nvkm_instmem_create(p,e,o,d) \ - nvkm_instmem_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_instmem_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) -#define nvkm_instmem_init(p) ({ \ - struct nvkm_instmem *imem = (p); \ - _nvkm_instmem_init(nv_object(imem)); \ -}) -#define nvkm_instmem_fini(p,s) ({ \ - struct nvkm_instmem *imem = (p); \ - _nvkm_instmem_fini(nv_object(imem), (s)); \ -}) - -int nvkm_instmem_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -#define _nvkm_instmem_dtor _nvkm_subdev_dtor -int _nvkm_instmem_init(struct nvkm_object *); -int _nvkm_instmem_fini(struct nvkm_object *, bool); +void nvkm_instmem_ctor(const struct nvkm_instmem_func *, struct nvkm_device *, + int index, struct nvkm_instmem *); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c index 2fb87fbfd..85b1464c0 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c @@ -23,102 +23,124 @@ */ #include "priv.h" -static int +#include <subdev/fb.h> + +int nvkm_ltc_tags_alloc(struct nvkm_ltc *ltc, u32 n, struct nvkm_mm_node **pnode) { - struct nvkm_ltc_priv *priv = (void *)ltc; - int ret; - - ret = nvkm_mm_head(&priv->tags, 0, 1, n, n, 1, pnode); + int ret = nvkm_mm_head(<c->tags, 0, 1, n, n, 1, pnode); if (ret) *pnode = NULL; - return ret; } -static void +void nvkm_ltc_tags_free(struct nvkm_ltc *ltc, struct nvkm_mm_node **pnode) { - struct nvkm_ltc_priv *priv = (void *)ltc; - nvkm_mm_free(&priv->tags, pnode); + nvkm_mm_free(<c->tags, pnode); } -static void +void nvkm_ltc_tags_clear(struct nvkm_ltc *ltc, u32 first, u32 count) { - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); - struct nvkm_ltc_priv *priv = (void *)ltc; const u32 limit = first + count - 1; - BUG_ON((first > limit) || (limit >= priv->num_tags)); + BUG_ON((first > limit) || (limit >= ltc->num_tags)); - impl->cbc_clear(priv, first, limit); - impl->cbc_wait(priv); + ltc->func->cbc_clear(ltc, first, limit); + ltc->func->cbc_wait(ltc); } -static int +int nvkm_ltc_zbc_color_get(struct nvkm_ltc *ltc, int index, const u32 color[4]) { - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); - struct nvkm_ltc_priv *priv = (void *)ltc; - memcpy(priv->zbc_color[index], color, sizeof(priv->zbc_color[index])); - impl->zbc_clear_color(priv, index, color); + memcpy(ltc->zbc_color[index], color, sizeof(ltc->zbc_color[index])); + ltc->func->zbc_clear_color(ltc, index, color); return index; } -static int +int nvkm_ltc_zbc_depth_get(struct nvkm_ltc *ltc, int index, const u32 depth) { - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); - struct nvkm_ltc_priv *priv = (void *)ltc; - priv->zbc_depth[index] = depth; - impl->zbc_clear_depth(priv, index, depth); + ltc->zbc_depth[index] = depth; + ltc->func->zbc_clear_depth(ltc, index, depth); return index; } -int -_nvkm_ltc_init(struct nvkm_object *object) +void +nvkm_ltc_invalidate(struct nvkm_ltc *ltc) { - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object); - struct nvkm_ltc_priv *priv = (void *)object; - int ret, i; + if (ltc->func->invalidate) + ltc->func->invalidate(ltc); +} - ret = nvkm_subdev_init(&priv->base.base); - if (ret) - return ret; +void +nvkm_ltc_flush(struct nvkm_ltc *ltc) +{ + if (ltc->func->flush) + ltc->func->flush(ltc); +} - for (i = priv->base.zbc_min; i <= priv->base.zbc_max; i++) { - impl->zbc_clear_color(priv, i, priv->zbc_color[i]); - impl->zbc_clear_depth(priv, i, priv->zbc_depth[i]); +static void +nvkm_ltc_intr(struct nvkm_subdev *subdev) +{ + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + ltc->func->intr(ltc); +} + +static int +nvkm_ltc_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + return ltc->func->oneinit(ltc); +} + +static int +nvkm_ltc_init(struct nvkm_subdev *subdev) +{ + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + int i; + + for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + ltc->func->zbc_clear_color(ltc, i, ltc->zbc_color[i]); + ltc->func->zbc_clear_depth(ltc, i, ltc->zbc_depth[i]); } + ltc->func->init(ltc); return 0; } +static void * +nvkm_ltc_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + struct nvkm_ram *ram = ltc->subdev.device->fb->ram; + nvkm_mm_fini(<c->tags); + if (ram) + nvkm_mm_free(&ram->vram, <c->tag_ram); + return ltc; +} + +static const struct nvkm_subdev_func +nvkm_ltc = { + .dtor = nvkm_ltc_dtor, + .oneinit = nvkm_ltc_oneinit, + .init = nvkm_ltc_init, + .intr = nvkm_ltc_intr, +}; + int -nvkm_ltc_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_ltc_new_(const struct nvkm_ltc_func *func, struct nvkm_device *device, + int index, struct nvkm_ltc **pltc) { - const struct nvkm_ltc_impl *impl = (void *)oclass; - struct nvkm_ltc_priv *priv; - int ret; + struct nvkm_ltc *ltc; - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PLTCG", - "l2c", length, pobject); - priv = *pobject; - if (ret) - return ret; - - memset(priv->zbc_color, 0x00, sizeof(priv->zbc_color)); - memset(priv->zbc_depth, 0x00, sizeof(priv->zbc_depth)); - - priv->base.base.intr = impl->intr; - priv->base.tags_alloc = nvkm_ltc_tags_alloc; - priv->base.tags_free = nvkm_ltc_tags_free; - priv->base.tags_clear = nvkm_ltc_tags_clear; - priv->base.zbc_min = 1; /* reserve 0 for disabled */ - priv->base.zbc_max = min(impl->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1; - priv->base.zbc_color_get = nvkm_ltc_zbc_color_get; - priv->base.zbc_depth_get = nvkm_ltc_zbc_depth_get; + if (!(ltc = *pltc = kzalloc(sizeof(*ltc), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_ltc, device, index, 0, <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; return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index 7fb5ea031..fb0de83da 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -28,38 +28,47 @@ #include <subdev/timer.h> void -gf100_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit) +gf100_ltc_cbc_clear(struct nvkm_ltc *ltc, u32 start, u32 limit) { - nv_wr32(priv, 0x17e8cc, start); - nv_wr32(priv, 0x17e8d0, limit); - nv_wr32(priv, 0x17e8c8, 0x00000004); + struct nvkm_device *device = ltc->subdev.device; + nvkm_wr32(device, 0x17e8cc, start); + nvkm_wr32(device, 0x17e8d0, limit); + nvkm_wr32(device, 0x17e8c8, 0x00000004); } void -gf100_ltc_cbc_wait(struct nvkm_ltc_priv *priv) +gf100_ltc_cbc_wait(struct nvkm_ltc *ltc) { + struct nvkm_device *device = ltc->subdev.device; int c, s; - for (c = 0; c < priv->ltc_nr; c++) { - for (s = 0; s < priv->lts_nr; s++) - nv_wait(priv, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0); + for (c = 0; c < ltc->ltc_nr; c++) { + for (s = 0; s < ltc->lts_nr; s++) { + const u32 addr = 0x1410c8 + (c * 0x2000) + (s * 0x400); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, addr)) + break; + ); + } } } void -gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) +gf100_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4]) { - nv_mask(priv, 0x17ea44, 0x0000000f, i); - nv_wr32(priv, 0x17ea48, color[0]); - nv_wr32(priv, 0x17ea4c, color[1]); - nv_wr32(priv, 0x17ea50, color[2]); - nv_wr32(priv, 0x17ea54, color[3]); + struct nvkm_device *device = ltc->subdev.device; + nvkm_mask(device, 0x17ea44, 0x0000000f, i); + nvkm_wr32(device, 0x17ea48, color[0]); + nvkm_wr32(device, 0x17ea4c, color[1]); + nvkm_wr32(device, 0x17ea50, color[2]); + nvkm_wr32(device, 0x17ea54, color[3]); } void -gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth) +gf100_ltc_zbc_clear_depth(struct nvkm_ltc *ltc, int i, const u32 depth) { - nv_mask(priv, 0x17ea44, 0x0000000f, i); - nv_wr32(priv, 0x17ea58, depth); + struct nvkm_device *device = ltc->subdev.device; + nvkm_mask(device, 0x17ea44, 0x0000000f, i); + nvkm_wr32(device, 0x17ea58, depth); } static const struct nvkm_bitfield @@ -81,88 +90,90 @@ gf100_ltc_lts_intr_name[] = { }; static void -gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts) +gf100_ltc_lts_intr(struct nvkm_ltc *ltc, int c, int s) { - u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400); - u32 intr = nv_rd32(priv, base + 0x020); + struct nvkm_subdev *subdev = <c->subdev; + struct nvkm_device *device = subdev->device; + u32 base = 0x141000 + (c * 0x2000) + (s * 0x400); + u32 intr = nvkm_rd32(device, base + 0x020); u32 stat = intr & 0x0000ffff; + char msg[128]; if (stat) { - nv_info(priv, "LTC%d_LTS%d:", ltc, lts); - nvkm_bitfield_print(gf100_ltc_lts_intr_name, stat); - pr_cont("\n"); + nvkm_snprintbf(msg, sizeof(msg), gf100_ltc_lts_intr_name, stat); + nvkm_error(subdev, "LTC%d_LTS%d: %08x [%s]\n", c, s, stat, msg); } - nv_wr32(priv, base + 0x020, intr); + nvkm_wr32(device, base + 0x020, intr); } void -gf100_ltc_intr(struct nvkm_subdev *subdev) +gf100_ltc_intr(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *priv = (void *)subdev; + struct nvkm_device *device = ltc->subdev.device; u32 mask; - mask = nv_rd32(priv, 0x00017c); + mask = nvkm_rd32(device, 0x00017c); while (mask) { - u32 lts, ltc = __ffs(mask); - for (lts = 0; lts < priv->lts_nr; lts++) - gf100_ltc_lts_intr(priv, ltc, lts); - mask &= ~(1 << ltc); + u32 s, c = __ffs(mask); + for (s = 0; s < ltc->lts_nr; s++) + gf100_ltc_lts_intr(ltc, c, s); + mask &= ~(1 << c); } } -static int -gf100_ltc_init(struct nvkm_object *object) +void +gf100_ltc_invalidate(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *priv = (void *)object; - u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); - int ret; + struct nvkm_device *device = ltc->subdev.device; + s64 taken; - ret = nvkm_ltc_init(priv); - if (ret) - return ret; + nvkm_wr32(device, 0x70004, 0x00000001); + taken = nvkm_wait_msec(device, 2, 0x70004, 0x00000003, 0x00000000); + if (taken < 0) + nvkm_warn(<c->subdev, "LTC invalidate timeout\n"); - nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - nv_wr32(priv, 0x17e8d8, priv->ltc_nr); - nv_wr32(priv, 0x17e8d4, priv->tag_base); - nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); - return 0; + if (taken > 0) + nvkm_debug(<c->subdev, "LTC invalidate took %lld ns\n", taken); } void -gf100_ltc_dtor(struct nvkm_object *object) +gf100_ltc_flush(struct nvkm_ltc *ltc) { - struct nvkm_fb *pfb = nvkm_fb(object); - struct nvkm_ltc_priv *priv = (void *)object; + struct nvkm_device *device = ltc->subdev.device; + s64 taken; - nvkm_mm_fini(&priv->tags); - if (pfb->ram) - nvkm_mm_free(&pfb->vram, &priv->tag_ram); + nvkm_wr32(device, 0x70010, 0x00000001); + taken = nvkm_wait_msec(device, 2, 0x70010, 0x00000003, 0x00000000); + if (taken < 0) + nvkm_warn(<c->subdev, "LTC flush timeout\n"); - nvkm_ltc_destroy(priv); + if (taken > 0) + nvkm_debug(<c->subdev, "LTC flush took %lld ns\n", taken); } /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ int -gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv) +gf100_ltc_oneinit_tag_ram(struct nvkm_ltc *ltc) { + struct nvkm_ram *ram = ltc->subdev.device->fb->ram; u32 tag_size, tag_margin, tag_align; int ret; /* No VRAM, no tags for now. */ - if (!pfb->ram) { - priv->num_tags = 0; + if (!ram) { + ltc->num_tags = 0; goto mm_init; } /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ - priv->num_tags = (pfb->ram->size >> 17) / 4; - if (priv->num_tags > (1 << 17)) - priv->num_tags = 1 << 17; /* we have 17 bits in PTE */ - priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */ + ltc->num_tags = (ram->size >> 17) / 4; + if (ltc->num_tags > (1 << 17)) + ltc->num_tags = 1 << 17; /* we have 17 bits in PTE */ + ltc->num_tags = (ltc->num_tags + 63) & ~63; /* round up to 64 */ - tag_align = priv->ltc_nr * 0x800; + tag_align = ltc->ltc_nr * 0x800; tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align; /* 4 part 4 sub: 0x2000 bytes for 56 tags */ @@ -173,72 +184,73 @@ gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv) * * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %. */ - tag_size = (priv->num_tags / 64) * 0x6000 + tag_margin; + tag_size = (ltc->num_tags / 64) * 0x6000 + tag_margin; tag_size += tag_align; tag_size = (tag_size + 0xfff) >> 12; /* round up */ - ret = nvkm_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1, - &priv->tag_ram); + ret = nvkm_mm_tail(&ram->vram, 1, 1, tag_size, tag_size, 1, + <c->tag_ram); if (ret) { - priv->num_tags = 0; + ltc->num_tags = 0; } else { - u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin; + u64 tag_base = ((u64)ltc->tag_ram->offset << 12) + tag_margin; tag_base += tag_align - 1; - ret = do_div(tag_base, tag_align); + do_div(tag_base, tag_align); - priv->tag_base = tag_base; + ltc->tag_base = tag_base; } mm_init: - ret = nvkm_mm_init(&priv->tags, 0, priv->num_tags, 1); - return ret; + return nvkm_mm_init(<c->tags, 0, ltc->num_tags, 1); } int -gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_ltc_oneinit(struct nvkm_ltc *ltc) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ltc_priv *priv; - u32 parts, mask; - int ret, i; - - ret = nvkm_ltc_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - parts = nv_rd32(priv, 0x022438); - mask = nv_rd32(priv, 0x022554); + struct nvkm_device *device = ltc->subdev.device; + const u32 parts = nvkm_rd32(device, 0x022438); + const u32 mask = nvkm_rd32(device, 0x022554); + const u32 slice = nvkm_rd32(device, 0x17e8dc) >> 28; + int i; + for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) - priv->ltc_nr++; + ltc->ltc_nr++; } - priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; + ltc->lts_nr = slice; - ret = gf100_ltc_init_tag_ram(pfb, priv); - if (ret) - return ret; + return gf100_ltc_oneinit_tag_ram(ltc); +} + +static void +gf100_ltc_init(struct nvkm_ltc *ltc) +{ + struct nvkm_device *device = ltc->subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - nv_subdev(priv)->intr = gf100_ltc_intr; - return 0; + nvkm_mask(device, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + nvkm_wr32(device, 0x17e8d8, ltc->ltc_nr); + nvkm_wr32(device, 0x17e8d4, ltc->tag_base); + nvkm_mask(device, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); } -struct nvkm_oclass * -gf100_ltc_oclass = &(struct nvkm_ltc_impl) { - .base.handle = NV_SUBDEV(LTC, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ltc_ctor, - .dtor = gf100_ltc_dtor, - .init = gf100_ltc_init, - .fini = _nvkm_ltc_fini, - }, +static const struct nvkm_ltc_func +gf100_ltc = { + .oneinit = gf100_ltc_oneinit, + .init = gf100_ltc_init, .intr = gf100_ltc_intr, .cbc_clear = gf100_ltc_cbc_clear, .cbc_wait = gf100_ltc_cbc_wait, .zbc = 16, .zbc_clear_color = gf100_ltc_zbc_clear_color, .zbc_clear_depth = gf100_ltc_zbc_clear_depth, -}.base; + .invalidate = gf100_ltc_invalidate, + .flush = gf100_ltc_flush, +}; + +int +gf100_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&gf100_ltc, device, index, pltc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c index d53959b5e..b4f6e0034 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c @@ -23,37 +23,34 @@ */ #include "priv.h" -static int -gk104_ltc_init(struct nvkm_object *object) +static void +gk104_ltc_init(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *priv = (void *)object; - u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); - int ret; + struct nvkm_device *device = ltc->subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - ret = nvkm_ltc_init(priv); - if (ret) - return ret; - - nv_wr32(priv, 0x17e8d8, priv->ltc_nr); - nv_wr32(priv, 0x17e000, priv->ltc_nr); - nv_wr32(priv, 0x17e8d4, priv->tag_base); - nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); - return 0; + nvkm_wr32(device, 0x17e8d8, ltc->ltc_nr); + nvkm_wr32(device, 0x17e000, ltc->ltc_nr); + nvkm_wr32(device, 0x17e8d4, ltc->tag_base); + nvkm_mask(device, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); } -struct nvkm_oclass * -gk104_ltc_oclass = &(struct nvkm_ltc_impl) { - .base.handle = NV_SUBDEV(LTC, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ltc_ctor, - .dtor = gf100_ltc_dtor, - .init = gk104_ltc_init, - .fini = _nvkm_ltc_fini, - }, +static const struct nvkm_ltc_func +gk104_ltc = { + .oneinit = gf100_ltc_oneinit, + .init = gk104_ltc_init, .intr = gf100_ltc_intr, .cbc_clear = gf100_ltc_cbc_clear, .cbc_wait = gf100_ltc_cbc_wait, .zbc = 16, .zbc_clear_color = gf100_ltc_zbc_clear_color, .zbc_clear_depth = gf100_ltc_zbc_clear_depth, -}.base; + .invalidate = gf100_ltc_invalidate, + .flush = gf100_ltc_flush, +}; + +int +gk104_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&gk104_ltc, device, index, pltc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 6b3f6f4ce..3043bbfd7 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -27,127 +27,123 @@ #include <subdev/timer.h> static void -gm107_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit) +gm107_ltc_cbc_clear(struct nvkm_ltc *ltc, u32 start, u32 limit) { - nv_wr32(priv, 0x17e270, start); - nv_wr32(priv, 0x17e274, limit); - nv_wr32(priv, 0x17e26c, 0x00000004); + struct nvkm_device *device = ltc->subdev.device; + nvkm_wr32(device, 0x17e270, start); + nvkm_wr32(device, 0x17e274, limit); + nvkm_wr32(device, 0x17e26c, 0x00000004); } static void -gm107_ltc_cbc_wait(struct nvkm_ltc_priv *priv) +gm107_ltc_cbc_wait(struct nvkm_ltc *ltc) { + struct nvkm_device *device = ltc->subdev.device; int c, s; - for (c = 0; c < priv->ltc_nr; c++) { - for (s = 0; s < priv->lts_nr; s++) - nv_wait(priv, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0); + for (c = 0; c < ltc->ltc_nr; c++) { + for (s = 0; s < ltc->lts_nr; s++) { + const u32 addr = 0x14046c + (c * 0x2000) + (s * 0x200); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, addr)) + break; + ); + } } } static void -gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) +gm107_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4]) { - nv_mask(priv, 0x17e338, 0x0000000f, i); - nv_wr32(priv, 0x17e33c, color[0]); - nv_wr32(priv, 0x17e340, color[1]); - nv_wr32(priv, 0x17e344, color[2]); - nv_wr32(priv, 0x17e348, color[3]); + struct nvkm_device *device = ltc->subdev.device; + nvkm_mask(device, 0x17e338, 0x0000000f, i); + nvkm_wr32(device, 0x17e33c, color[0]); + nvkm_wr32(device, 0x17e340, color[1]); + nvkm_wr32(device, 0x17e344, color[2]); + nvkm_wr32(device, 0x17e348, color[3]); } static void -gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth) +gm107_ltc_zbc_clear_depth(struct nvkm_ltc *ltc, int i, const u32 depth) { - nv_mask(priv, 0x17e338, 0x0000000f, i); - nv_wr32(priv, 0x17e34c, depth); + struct nvkm_device *device = ltc->subdev.device; + nvkm_mask(device, 0x17e338, 0x0000000f, i); + nvkm_wr32(device, 0x17e34c, depth); } static void -gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts) +gm107_ltc_lts_isr(struct nvkm_ltc *ltc, int c, int s) { - u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400); - u32 stat = nv_rd32(priv, base + 0x00c); + struct nvkm_subdev *subdev = <c->subdev; + struct nvkm_device *device = subdev->device; + u32 base = 0x140000 + (c * 0x2000) + (s * 0x400); + u32 stat = nvkm_rd32(device, base + 0x00c); if (stat) { - nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); - nv_wr32(priv, base + 0x00c, stat); + nvkm_error(subdev, "LTC%d_LTS%d: %08x\n", c, s, stat); + nvkm_wr32(device, base + 0x00c, stat); } } static void -gm107_ltc_intr(struct nvkm_subdev *subdev) +gm107_ltc_intr(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *priv = (void *)subdev; + struct nvkm_device *device = ltc->subdev.device; u32 mask; - mask = nv_rd32(priv, 0x00017c); + mask = nvkm_rd32(device, 0x00017c); while (mask) { - u32 lts, ltc = __ffs(mask); - for (lts = 0; lts < priv->lts_nr; lts++) - gm107_ltc_lts_isr(priv, ltc, lts); - mask &= ~(1 << ltc); + u32 s, c = __ffs(mask); + for (s = 0; s < ltc->lts_nr; s++) + gm107_ltc_lts_isr(ltc, c, s); + mask &= ~(1 << c); } } static int -gm107_ltc_init(struct nvkm_object *object) +gm107_ltc_oneinit(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *priv = (void *)object; - u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); - int ret; - - ret = nvkm_ltc_init(priv); - if (ret) - return ret; - - nv_wr32(priv, 0x17e27c, priv->ltc_nr); - nv_wr32(priv, 0x17e278, priv->tag_base); - nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); - return 0; -} + struct nvkm_device *device = ltc->subdev.device; + const u32 parts = nvkm_rd32(device, 0x022438); + const u32 mask = nvkm_rd32(device, 0x021c14); + const u32 slice = nvkm_rd32(device, 0x17e280) >> 28; + int i; -static int -gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_ltc_priv *priv; - u32 parts, mask; - int ret, i; - - ret = nvkm_ltc_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - parts = nv_rd32(priv, 0x022438); - mask = nv_rd32(priv, 0x021c14); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) - priv->ltc_nr++; + ltc->ltc_nr++; } - priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28; + ltc->lts_nr = slice; + + return gf100_ltc_oneinit_tag_ram(ltc); +} - ret = gf100_ltc_init_tag_ram(pfb, priv); - if (ret) - return ret; +static void +gm107_ltc_init(struct nvkm_ltc *ltc) +{ + struct nvkm_device *device = ltc->subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - return 0; + nvkm_wr32(device, 0x17e27c, ltc->ltc_nr); + nvkm_wr32(device, 0x17e278, ltc->tag_base); + nvkm_mask(device, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); } -struct nvkm_oclass * -gm107_ltc_oclass = &(struct nvkm_ltc_impl) { - .base.handle = NV_SUBDEV(LTC, 0xff), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_ltc_ctor, - .dtor = gf100_ltc_dtor, - .init = gm107_ltc_init, - .fini = _nvkm_ltc_fini, - }, +static const struct nvkm_ltc_func +gm107_ltc = { + .oneinit = gm107_ltc_oneinit, + .init = gm107_ltc_init, .intr = gm107_ltc_intr, .cbc_clear = gm107_ltc_cbc_clear, .cbc_wait = gm107_ltc_cbc_wait, .zbc = 16, .zbc_clear_color = gm107_ltc_zbc_clear_color, .zbc_clear_depth = gm107_ltc_zbc_clear_depth, -}.base; + .invalidate = gf100_ltc_invalidate, + .flush = gf100_ltc_flush, +}; + +int +gm107_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&gm107_ltc, device, index, pltc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h index 09537d7b6..4e3755b82 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h @@ -1,69 +1,34 @@ #ifndef __NVKM_LTC_PRIV_H__ #define __NVKM_LTC_PRIV_H__ +#define nvkm_ltc(p) container_of((p), struct nvkm_ltc, subdev) #include <subdev/ltc.h> -#include <core/mm.h> -struct nvkm_fb; +int nvkm_ltc_new_(const struct nvkm_ltc_func *, struct nvkm_device *, + int index, struct nvkm_ltc **); -struct nvkm_ltc_priv { - struct nvkm_ltc base; - u32 ltc_nr; - u32 lts_nr; +struct nvkm_ltc_func { + int (*oneinit)(struct nvkm_ltc *); + void (*init)(struct nvkm_ltc *); + void (*intr)(struct nvkm_ltc *); - u32 num_tags; - u32 tag_base; - struct nvkm_mm tags; - struct nvkm_mm_node *tag_ram; - - u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4]; - u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT]; -}; - -#define nvkm_ltc_create(p,e,o,d) \ - nvkm_ltc_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_ltc_destroy(p) ({ \ - struct nvkm_ltc_priv *_priv = (p); \ - _nvkm_ltc_dtor(nv_object(_priv)); \ -}) -#define nvkm_ltc_init(p) ({ \ - struct nvkm_ltc_priv *_priv = (p); \ - _nvkm_ltc_init(nv_object(_priv)); \ -}) -#define nvkm_ltc_fini(p,s) ({ \ - struct nvkm_ltc_priv *_priv = (p); \ - _nvkm_ltc_fini(nv_object(_priv), (s)); \ -}) - -int nvkm_ltc_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); - -#define _nvkm_ltc_dtor _nvkm_subdev_dtor -int _nvkm_ltc_init(struct nvkm_object *); -#define _nvkm_ltc_fini _nvkm_subdev_fini - -int gf100_ltc_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_ltc_dtor(struct nvkm_object *); -int gf100_ltc_init_tag_ram(struct nvkm_fb *, struct nvkm_ltc_priv *); -int gf100_ltc_tags_alloc(struct nvkm_ltc *, u32, struct nvkm_mm_node **); -void gf100_ltc_tags_free(struct nvkm_ltc *, struct nvkm_mm_node **); - -struct nvkm_ltc_impl { - struct nvkm_oclass base; - void (*intr)(struct nvkm_subdev *); - - void (*cbc_clear)(struct nvkm_ltc_priv *, u32 start, u32 limit); - void (*cbc_wait)(struct nvkm_ltc_priv *); + void (*cbc_clear)(struct nvkm_ltc *, u32 start, u32 limit); + void (*cbc_wait)(struct nvkm_ltc *); int zbc; - void (*zbc_clear_color)(struct nvkm_ltc_priv *, int, const u32[4]); - void (*zbc_clear_depth)(struct nvkm_ltc_priv *, int, const u32); + void (*zbc_clear_color)(struct nvkm_ltc *, int, const u32[4]); + void (*zbc_clear_depth)(struct nvkm_ltc *, int, const u32); + + void (*invalidate)(struct nvkm_ltc *); + void (*flush)(struct nvkm_ltc *); }; -void gf100_ltc_intr(struct nvkm_subdev *); -void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *, u32, u32); -void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *); -void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *, int, const u32[4]); -void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *, int, const u32); +int gf100_ltc_oneinit(struct nvkm_ltc *); +int gf100_ltc_oneinit_tag_ram(struct nvkm_ltc *); +void gf100_ltc_intr(struct nvkm_ltc *); +void gf100_ltc_cbc_clear(struct nvkm_ltc *, u32, u32); +void gf100_ltc_cbc_wait(struct nvkm_ltc *); +void gf100_ltc_zbc_clear_color(struct nvkm_ltc *, int, const u32[4]); +void gf100_ltc_zbc_clear_depth(struct nvkm_ltc *, int, const u32); +void gf100_ltc_invalidate(struct nvkm_ltc *); +void gf100_ltc_flush(struct nvkm_ltc *); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild index 721643f04..bef325dcb 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild @@ -1,11 +1,7 @@ nvkm-y += nvkm/subdev/mc/base.o nvkm-y += nvkm/subdev/mc/nv04.o -nvkm-y += nvkm/subdev/mc/nv40.o nvkm-y += nvkm/subdev/mc/nv44.o -nvkm-y += nvkm/subdev/mc/nv4c.o nvkm-y += nvkm/subdev/mc/nv50.o -nvkm-y += nvkm/subdev/mc/g94.o nvkm-y += nvkm/subdev/mc/g98.o nvkm-y += nvkm/subdev/mc/gf100.o -nvkm-y += nvkm/subdev/mc/gf106.o nvkm-y += nvkm/subdev/mc/gk20a.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 5b051a266..954fbbe56 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -23,147 +23,101 @@ */ #include "priv.h" -#include <core/device.h> #include <core/option.h> -static inline void -nvkm_mc_unk260(struct nvkm_mc *pmc, u32 data) +void +nvkm_mc_unk260(struct nvkm_mc *mc, u32 data) { - const struct nvkm_mc_oclass *impl = (void *)nv_oclass(pmc); - if (impl->unk260) - impl->unk260(pmc, data); + if (mc->func->unk260) + mc->func->unk260(mc, data); } -static inline u32 -nvkm_mc_intr_mask(struct nvkm_mc *pmc) +void +nvkm_mc_intr_unarm(struct nvkm_mc *mc) { - u32 intr = nv_rd32(pmc, 0x000100); - if (intr == 0xffffffff) /* likely fallen off the bus */ - intr = 0x00000000; - return intr; + return mc->func->intr_unarm(mc); } -static irqreturn_t -nvkm_mc_intr(int irq, void *arg) +void +nvkm_mc_intr_rearm(struct nvkm_mc *mc) { - struct nvkm_mc *pmc = arg; - const struct nvkm_mc_oclass *oclass = (void *)nv_object(pmc)->oclass; - const struct nvkm_mc_intr *map = oclass->intr; - struct nvkm_subdev *unit; - u32 intr; + return mc->func->intr_rearm(mc); +} - nv_wr32(pmc, 0x000140, 0x00000000); - nv_rd32(pmc, 0x000140); - intr = nvkm_mc_intr_mask(pmc); - if (pmc->use_msi) - oclass->msi_rearm(pmc); +static u32 +nvkm_mc_intr_mask(struct nvkm_mc *mc) +{ + u32 intr = mc->func->intr_mask(mc); + if (WARN_ON_ONCE(intr == 0xffffffff)) + intr = 0; /* likely fallen off the bus */ + return intr; +} - if (intr) { - u32 stat = intr = nvkm_mc_intr_mask(pmc); - while (map->stat) { - if (intr & map->stat) { - unit = nvkm_subdev(pmc, map->unit); - if (unit && unit->intr) - unit->intr(unit); - stat &= ~map->stat; - } - map++; +void +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; + + stat = intr = nvkm_mc_intr_mask(mc); + while (map->stat) { + if (intr & map->stat) { + subdev = nvkm_device_subdev(device, map->unit); + if (subdev) + nvkm_subdev_intr(subdev); + stat &= ~map->stat; } - - if (stat) - nv_error(pmc, "unknown intr 0x%08x\n", stat); + map++; } - nv_wr32(pmc, 0x000140, 0x00000001); - return intr ? IRQ_HANDLED : IRQ_NONE; + if (stat) + nvkm_error(&mc->subdev, "intr %08x\n", stat); + *handled = intr != 0; } -int -_nvkm_mc_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_mc *pmc = (void *)object; - nv_wr32(pmc, 0x000140, 0x00000000); - return nvkm_subdev_fini(&pmc->base, suspend); + struct nvkm_mc *mc = nvkm_mc(subdev); + nvkm_mc_intr_unarm(mc); + return 0; } -int -_nvkm_mc_init(struct nvkm_object *object) +static int +nvkm_mc_init(struct nvkm_subdev *subdev) { - struct nvkm_mc *pmc = (void *)object; - int ret = nvkm_subdev_init(&pmc->base); - if (ret) - return ret; - nv_wr32(pmc, 0x000140, 0x00000001); + struct nvkm_mc *mc = nvkm_mc(subdev); + if (mc->func->init) + mc->func->init(mc); + nvkm_mc_intr_rearm(mc); return 0; } -void -_nvkm_mc_dtor(struct nvkm_object *object) +static void * +nvkm_mc_dtor(struct nvkm_subdev *subdev) { - struct nvkm_device *device = nv_device(object); - struct nvkm_mc *pmc = (void *)object; - free_irq(pmc->irq, pmc); - if (pmc->use_msi) - pci_disable_msi(device->pdev); - nvkm_subdev_destroy(&pmc->base); + return nvkm_mc(subdev); } +static const struct nvkm_subdev_func +nvkm_mc = { + .dtor = nvkm_mc_dtor, + .init = nvkm_mc_init, + .fini = nvkm_mc_fini, +}; + int -nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *bclass, int length, void **pobject) +nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, + int index, struct nvkm_mc **pmc) { - const struct nvkm_mc_oclass *oclass = (void *)bclass; - struct nvkm_device *device = nv_device(parent); - struct nvkm_mc *pmc; - int ret; - - ret = nvkm_subdev_create_(parent, engine, bclass, 0, "PMC", - "master", length, pobject); - pmc = *pobject; - if (ret) - return ret; - - pmc->unk260 = nvkm_mc_unk260; - - if (nv_device_is_pci(device)) { - switch (device->pdev->device & 0x0ff0) { - case 0x00f0: - case 0x02e0: - /* BR02? NFI how these would be handled yet exactly */ - break; - default: - switch (device->chipset) { - case 0xaa: - /* reported broken, nv also disable it */ - break; - default: - pmc->use_msi = true; - break; - } - } - - pmc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI", - pmc->use_msi); - - if (pmc->use_msi && oclass->msi_rearm) { - pmc->use_msi = pci_enable_msi(device->pdev) == 0; - if (pmc->use_msi) { - nv_info(pmc, "MSI interrupts enabled\n"); - oclass->msi_rearm(pmc); - } - } else { - pmc->use_msi = false; - } - } - - ret = nv_device_get_irq(device, true); - if (ret < 0) - return ret; - pmc->irq = ret; + struct nvkm_mc *mc; - ret = request_irq(pmc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", pmc); - if (ret < 0) - return ret; + if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_mc, device, index, 0, &mc->subdev); + mc->func = func; return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index 8ab7f1272..7344ad659 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -21,38 +21,40 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" static const struct nvkm_mc_intr g98_mc_intr[] = { - { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */ - { 0x00000001, NVDEV_ENGINE_MSPPP }, - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00004000, NVDEV_ENGINE_SEC }, /* NV84:NVA3 */ - { 0x00008000, NVDEV_ENGINE_MSVLD }, - { 0x00020000, NVDEV_ENGINE_MSPDEC }, - { 0x00040000, NVDEV_SUBDEV_PMU }, /* NVA3:NVC0 */ - { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */ - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x00400000, NVDEV_ENGINE_CE0 }, /* NVA3- */ - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x80000000, NVDEV_ENGINE_SW }, - { 0x0042d101, NVDEV_SUBDEV_FB }, + { 0x04000000, NVKM_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */ + { 0x00000001, NVKM_ENGINE_MSPPP }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00004000, NVKM_ENGINE_SEC }, /* NV84:NVA3 */ + { 0x00008000, NVKM_ENGINE_MSVLD }, + { 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- */ + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x80000000, NVKM_ENGINE_SW }, + { 0x0042d101, NVKM_SUBDEV_FB }, {}, }; -struct nvkm_oclass * -g98_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x98), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +g98_mc = { + .init = nv50_mc_init, .intr = g98_mc_intr, - .msi_rearm = nv40_mc_msi_rearm, -}.base; + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, +}; + +int +g98_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&g98_mc, device, index, pmc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 2425984b0..122fe69e8 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -21,56 +21,77 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" const struct nvkm_mc_intr gf100_mc_intr[] = { - { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work. */ - { 0x00000001, NVDEV_ENGINE_MSPPP }, - { 0x00000020, NVDEV_ENGINE_CE0 }, - { 0x00000040, NVDEV_ENGINE_CE1 }, - { 0x00000080, NVDEV_ENGINE_CE2 }, - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00002000, NVDEV_SUBDEV_FB }, - { 0x00008000, NVDEV_ENGINE_MSVLD }, - { 0x00040000, NVDEV_SUBDEV_THERM }, - { 0x00020000, NVDEV_ENGINE_MSPDEC }, - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x01000000, NVDEV_SUBDEV_PMU }, - { 0x02000000, NVDEV_SUBDEV_LTC }, - { 0x08000000, NVDEV_SUBDEV_FB }, - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x40000000, NVDEV_SUBDEV_IBUS }, - { 0x80000000, NVDEV_ENGINE_SW }, + { 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 }, + { 0x00008000, NVKM_ENGINE_MSVLD }, + { 0x00040000, NVKM_SUBDEV_THERM }, + { 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 }, + { 0x40000000, NVKM_SUBDEV_IBUS }, + { 0x80000000, NVKM_ENGINE_SW }, {}, }; -static void -gf100_mc_msi_rearm(struct nvkm_mc *pmc) +void +gf100_mc_intr_unarm(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000000); + nvkm_wr32(device, 0x000144, 0x00000000); + nvkm_rd32(device, 0x000140); +} + +void +gf100_mc_intr_rearm(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000001); + nvkm_wr32(device, 0x000144, 0x00000001); +} + +u32 +gf100_mc_intr_mask(struct nvkm_mc *mc) { - struct nv04_mc_priv *priv = (void *)pmc; - nv_wr32(priv, 0x088704, 0x00000000); + struct nvkm_device *device = mc->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x000100); + u32 intr1 = nvkm_rd32(device, 0x000104); + return intr0 | intr1; } void -gf100_mc_unk260(struct nvkm_mc *pmc, u32 data) +gf100_mc_unk260(struct nvkm_mc *mc, u32 data) { - nv_wr32(pmc, 0x000260, data); + nvkm_wr32(mc->subdev.device, 0x000260, data); } -struct nvkm_oclass * -gf100_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +gf100_mc = { + .init = nv50_mc_init, .intr = gf100_mc_intr, - .msi_rearm = gf100_mc_msi_rearm, + .intr_unarm = gf100_mc_intr_unarm, + .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, .unk260 = gf100_mc_unk260, -}.base; +}; + +int +gf100_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&gf100_mc, device, index, pmc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index 43b277429..d92efb33b 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -21,17 +21,19 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -struct nvkm_oclass * -gk20a_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +gk20a_mc = { + .init = nv50_mc_init, .intr = gf100_mc_intr, - .msi_rearm = nv40_mc_msi_rearm, -}.base; + .intr_unarm = gf100_mc_intr_unarm, + .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, +}; + +int +gk20a_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&gk20a_mc, device, index, pmc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index 32713827b..d282ec155 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -21,58 +21,63 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" const struct nvkm_mc_intr nv04_mc_intr[] = { - { 0x00000001, NVDEV_ENGINE_MPEG }, /* NV17- MPEG/ME */ - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00010000, NVDEV_ENGINE_DISP }, - { 0x00020000, NVDEV_ENGINE_VP }, /* NV40- */ - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */ - { 0x02000000, NVDEV_ENGINE_DISP }, /* NV11- PCRTC1 */ - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x80000000, NVDEV_ENGINE_SW }, + { 0x00000001, NVKM_ENGINE_MPEG }, /* NV17- MPEG/ME */ + { 0x00000100, NVKM_ENGINE_FIFO }, + { 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 */ + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x80000000, NVKM_ENGINE_SW }, {} }; -int -nv04_mc_init(struct nvkm_object *object) +void +nv04_mc_intr_unarm(struct nvkm_mc *mc) { - struct nv04_mc_priv *priv = (void *)object; - - nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ - nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */ - - return nvkm_mc_init(&priv->base); + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000000); + nvkm_rd32(device, 0x000140); } -int -nv04_mc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +void +nv04_mc_intr_rearm(struct nvkm_mc *mc) { - struct nv04_mc_priv *priv; - int ret; + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000001); +} - ret = nvkm_mc_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +u32 +nv04_mc_intr_mask(struct nvkm_mc *mc) +{ + return nvkm_rd32(mc->subdev.device, 0x000100); +} - return 0; +void +nv04_mc_init(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000200, 0xffffffff); /* everything enabled */ + nvkm_wr32(device, 0x001850, 0x00000001); /* disable rom access */ } -struct nvkm_oclass * -nv04_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv04_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +nv04_mc = { + .init = nv04_mc_init, .intr = nv04_mc_intr, -}.base; + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, +}; + +int +nv04_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv04_mc, device, index, pmc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h deleted file mode 100644 index 411de3d08..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __NVKM_MC_NV04_H__ -#define __NVKM_MC_NV04_H__ -#include "priv.h" - -struct nv04_mc_priv { - struct nvkm_mc base; -}; - -int nv04_mc_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -extern const struct nvkm_mc_intr nv04_mc_intr[]; -int nv04_mc_init(struct nvkm_object *); -void nv40_mc_msi_rearm(struct nvkm_mc *); -int nv44_mc_init(struct nvkm_object *object); -int nv50_mc_init(struct nvkm_object *); -extern const struct nvkm_mc_intr nv50_mc_intr[]; -extern const struct nvkm_mc_intr gf100_mc_intr[]; -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index 2c7f7c701..9a3ac9965 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -21,33 +21,33 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -int -nv44_mc_init(struct nvkm_object *object) +void +nv44_mc_init(struct nvkm_mc *mc) { - struct nv04_mc_priv *priv = (void *)object; - u32 tmp = nv_rd32(priv, 0x10020c); - - nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ + struct nvkm_device *device = mc->subdev.device; + u32 tmp = nvkm_rd32(device, 0x10020c); - nv_wr32(priv, 0x001700, tmp); - nv_wr32(priv, 0x001704, 0); - nv_wr32(priv, 0x001708, 0); - nv_wr32(priv, 0x00170c, tmp); + nvkm_wr32(device, 0x000200, 0xffffffff); /* everything enabled */ - return nvkm_mc_init(&priv->base); + nvkm_wr32(device, 0x001700, tmp); + nvkm_wr32(device, 0x001704, 0); + nvkm_wr32(device, 0x001708, 0); + nvkm_wr32(device, 0x00170c, tmp); } -struct nvkm_oclass * -nv44_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x44), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv44_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +nv44_mc = { + .init = nv44_mc_init, .intr = nv04_mc_intr, - .msi_rearm = nv40_mc_msi_rearm, -}.base; + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, +}; + +int +nv44_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv44_mc, device, index, pmc); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 40e3019e1..5f27d7b8f 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -21,52 +21,44 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" - -#include <core/device.h> +#include "priv.h" const struct nvkm_mc_intr nv50_mc_intr[] = { - { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */ - { 0x00000001, NVDEV_ENGINE_MPEG }, - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00004000, NVDEV_ENGINE_CIPHER }, /* NV84- */ - { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ - { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */ - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x80000000, NVDEV_ENGINE_SW }, - { 0x0002d101, NVDEV_SUBDEV_FB }, + { 0x04000000, NVKM_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */ + { 0x00000001, NVKM_ENGINE_MPEG }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 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 */ + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x80000000, NVKM_ENGINE_SW }, + { 0x0002d101, NVKM_SUBDEV_FB }, {}, }; -static void -nv50_mc_msi_rearm(struct nvkm_mc *pmc) +void +nv50_mc_init(struct nvkm_mc *mc) { - struct nvkm_device *device = nv_device(pmc); - pci_write_config_byte(device->pdev, 0x68, 0xff); + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000200, 0xffffffff); /* everything on */ } +static const struct nvkm_mc_func +nv50_mc = { + .init = nv50_mc_init, + .intr = nv50_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, +}; + int -nv50_mc_init(struct nvkm_object *object) +nv50_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) { - struct nv04_mc_priv *priv = (void *)object; - nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */ - return nvkm_mc_init(&priv->base); + return nvkm_mc_new_(&nv50_mc, device, index, pmc); } - -struct nvkm_oclass * -nv50_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, - .intr = nv50_mc_intr, - .msi_rearm = nv50_mc_msi_rearm, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index d2cad07af..307f6c692 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -1,36 +1,42 @@ #ifndef __NVKM_MC_PRIV_H__ #define __NVKM_MC_PRIV_H__ +#define nvkm_mc(p) container_of((p), struct nvkm_mc, subdev) #include <subdev/mc.h> -#define nvkm_mc_create(p,e,o,d) \ - nvkm_mc_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_mc_destroy(p) ({ \ - struct nvkm_mc *pmc = (p); _nvkm_mc_dtor(nv_object(pmc)); \ -}) -#define nvkm_mc_init(p) ({ \ - struct nvkm_mc *pmc = (p); _nvkm_mc_init(nv_object(pmc)); \ -}) -#define nvkm_mc_fini(p,s) ({ \ - struct nvkm_mc *pmc = (p); _nvkm_mc_fini(nv_object(pmc), (s)); \ -}) - -int nvkm_mc_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_mc_dtor(struct nvkm_object *); -int _nvkm_mc_init(struct nvkm_object *); -int _nvkm_mc_fini(struct nvkm_object *, bool); +int nvkm_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, + int index, struct nvkm_mc **); struct nvkm_mc_intr { u32 stat; u32 unit; }; -struct nvkm_mc_oclass { - struct nvkm_oclass base; +struct nvkm_mc_func { + void (*init)(struct nvkm_mc *); const struct nvkm_mc_intr *intr; - void (*msi_rearm)(struct nvkm_mc *); + /* 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 *); 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 *); + +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); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index 277b6ec04..e04a2296e 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#include <subdev/mmu.h> -#include <subdev/fb.h> +#include "priv.h" #include <core/gpuobj.h> +#include <subdev/fb.h> void nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) @@ -32,12 +32,12 @@ nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; struct nvkm_mm_node *r; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); u32 end, len; delta = 0; @@ -46,14 +46,14 @@ nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) u32 num = r->length >> bits; while (num) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; end = (pte + num); if (unlikely(end >= max)) end = max; len = end - pte; - mmu->map(vma, pgt, node, pte, len, phys, delta); + mmu->func->map(vma, pgt, node, pte, len, phys, delta); num -= len; pte += len; @@ -67,7 +67,7 @@ nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) } } - mmu->flush(vm); + mmu->func->flush(vm); } static void @@ -76,20 +76,20 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, { struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); unsigned m, sglen; u32 end, len; int i; struct scatterlist *sg; for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; sglen = sg_dma_len(sg) >> PAGE_SHIFT; end = pte + sglen; @@ -100,7 +100,7 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, for (m = 0; m < len; m++) { dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - mmu->map_sg(vma, pgt, mem, pte, 1, &addr); + mmu->func->map_sg(vma, pgt, mem, pte, 1, &addr); num--; pte++; @@ -115,7 +115,7 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, for (; m < sglen; m++) { dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - mmu->map_sg(vma, pgt, mem, pte, 1, &addr); + mmu->func->map_sg(vma, pgt, mem, pte, 1, &addr); num--; pte++; if (num == 0) @@ -125,7 +125,7 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, } finish: - mmu->flush(vm); + mmu->func->flush(vm); } static void @@ -135,24 +135,24 @@ nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length, struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; dma_addr_t *list = mem->pages; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); u32 end, len; while (num) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; end = (pte + num); if (unlikely(end >= max)) end = max; len = end - pte; - mmu->map_sg(vma, pgt, mem, pte, len, list); + mmu->func->map_sg(vma, pgt, mem, pte, len, list); num -= len; pte += len; @@ -163,7 +163,7 @@ nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length, } } - mmu->flush(vm); + mmu->func->flush(vm); } void @@ -183,24 +183,24 @@ nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length) { struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); u32 end, len; while (num) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; end = (pte + num); if (unlikely(end >= max)) end = max; len = end - pte; - mmu->unmap(pgt, pte, len); + mmu->func->unmap(vma, pgt, pte, len); num -= len; pte += len; @@ -210,7 +210,7 @@ nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length) } } - mmu->flush(vm); + mmu->func->flush(vm); } void @@ -225,7 +225,7 @@ nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde) struct nvkm_mmu *mmu = vm->mmu; struct nvkm_vm_pgd *vpgd; struct nvkm_vm_pgt *vpgt; - struct nvkm_gpuobj *pgt; + struct nvkm_memory *pgt; u32 pde; for (pde = fpde; pde <= lpde; pde++) { @@ -233,16 +233,14 @@ nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde) if (--vpgt->refcount[big]) continue; - pgt = vpgt->obj[big]; - vpgt->obj[big] = NULL; + pgt = vpgt->mem[big]; + vpgt->mem[big] = NULL; list_for_each_entry(vpgd, &vm->pgd_list, head) { - mmu->map_pgt(vpgd->obj, pde, vpgt->obj); + mmu->func->map_pgt(vpgd->obj, pde, vpgt->mem); } - mutex_unlock(&nv_subdev(mmu)->mutex); - nvkm_gpuobj_ref(NULL, &pgt); - mutex_lock(&nv_subdev(mmu)->mutex); + nvkm_memory_del(&pgt); } } @@ -252,34 +250,23 @@ nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type) struct nvkm_mmu *mmu = vm->mmu; struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; struct nvkm_vm_pgd *vpgd; - struct nvkm_gpuobj *pgt; - int big = (type != mmu->spg_shift); + int big = (type != mmu->func->spg_shift); u32 pgt_size; int ret; - pgt_size = (1 << (mmu->pgt_bits + 12)) >> type; + pgt_size = (1 << (mmu->func->pgt_bits + 12)) >> type; pgt_size *= 8; - mutex_unlock(&nv_subdev(mmu)->mutex); - ret = nvkm_gpuobj_new(nv_object(vm->mmu), NULL, pgt_size, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &pgt); - mutex_lock(&nv_subdev(mmu)->mutex); + ret = nvkm_memory_new(mmu->subdev.device, NVKM_MEM_TARGET_INST, + pgt_size, 0x1000, true, &vpgt->mem[big]); if (unlikely(ret)) return ret; - /* someone beat us to filling the PDE while we didn't have the lock */ - if (unlikely(vpgt->refcount[big]++)) { - mutex_unlock(&nv_subdev(mmu)->mutex); - nvkm_gpuobj_ref(NULL, &pgt); - mutex_lock(&nv_subdev(mmu)->mutex); - return 0; - } - - vpgt->obj[big] = pgt; list_for_each_entry(vpgd, &vm->pgd_list, head) { - mmu->map_pgt(vpgd->obj, pde, vpgt->obj); + mmu->func->map_pgt(vpgd->obj, pde, vpgt->mem); } + vpgt->refcount[big]++; return 0; } @@ -293,20 +280,20 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, u32 fpde, lpde, pde; int ret; - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&vm->mutex); ret = nvkm_mm_head(&vm->mm, 0, page_shift, msize, msize, align, &vma->node); if (unlikely(ret != 0)) { - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); return ret; } - fpde = (vma->node->offset >> mmu->pgt_bits); - lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits; + fpde = (vma->node->offset >> mmu->func->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> mmu->func->pgt_bits; for (pde = fpde; pde <= lpde; pde++) { struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; - int big = (vma->node->type != mmu->spg_shift); + int big = (vma->node->type != mmu->func->spg_shift); if (likely(vpgt->refcount[big])) { vpgt->refcount[big]++; @@ -318,11 +305,11 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, if (pde != fpde) nvkm_vm_unmap_pgt(vm, big, fpde, pde - 1); nvkm_mm_free(&vm->mm, &vma->node); - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); return ret; } } - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); vma->vm = NULL; nvkm_vm_ref(vm, &vma->vm, NULL); @@ -334,27 +321,49 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, void nvkm_vm_put(struct nvkm_vma *vma) { - struct nvkm_vm *vm = vma->vm; - struct nvkm_mmu *mmu = vm->mmu; + struct nvkm_mmu *mmu; + struct nvkm_vm *vm; u32 fpde, lpde; if (unlikely(vma->node == NULL)) return; - fpde = (vma->node->offset >> mmu->pgt_bits); - lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits; + vm = vma->vm; + mmu = vm->mmu; + + fpde = (vma->node->offset >> mmu->func->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> mmu->func->pgt_bits; - mutex_lock(&nv_subdev(mmu)->mutex); - nvkm_vm_unmap_pgt(vm, vma->node->type != mmu->spg_shift, fpde, lpde); + mutex_lock(&vm->mutex); + nvkm_vm_unmap_pgt(vm, vma->node->type != mmu->func->spg_shift, fpde, lpde); nvkm_mm_free(&vm->mm, &vma->node); - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); nvkm_vm_ref(NULL, &vma->vm, NULL); } int +nvkm_vm_boot(struct nvkm_vm *vm, u64 size) +{ + struct nvkm_mmu *mmu = vm->mmu; + struct nvkm_memory *pgt; + int ret; + + ret = nvkm_memory_new(mmu->subdev.device, NVKM_MEM_TARGET_INST, + (size >> mmu->func->spg_shift) * 8, 0x1000, true, &pgt); + if (ret == 0) { + vm->pgt[0].refcount[0] = 1; + vm->pgt[0].mem[0] = pgt; + nvkm_memory_boot(pgt, vm); + } + + return ret; +} + +int nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, - u32 block, struct nvkm_vm **pvm) + u32 block, struct lock_class_key *key, struct nvkm_vm **pvm) { + static struct lock_class_key _key; struct nvkm_vm *vm; u64 mm_length = (offset + length) - mm_offset; int ret; @@ -363,11 +372,12 @@ nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, if (!vm) return -ENOMEM; + __mutex_init(&vm->mutex, "&vm->mutex", key ? key : &_key); INIT_LIST_HEAD(&vm->pgd_list); vm->mmu = mmu; kref_init(&vm->refcount); - vm->fpde = offset >> (mmu->pgt_bits + 12); - vm->lpde = (offset + length - 1) >> (mmu->pgt_bits + 12); + vm->fpde = offset >> (mmu->func->pgt_bits + 12); + vm->lpde = (offset + length - 1) >> (mmu->func->pgt_bits + 12); vm->pgt = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt)); if (!vm->pgt) { @@ -390,10 +400,12 @@ nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, int nvkm_vm_new(struct nvkm_device *device, u64 offset, u64 length, u64 mm_offset, - struct nvkm_vm **pvm) + struct lock_class_key *key, struct nvkm_vm **pvm) { - struct nvkm_mmu *mmu = nvkm_mmu(device); - return mmu->create(mmu, offset, length, mm_offset, pvm); + struct nvkm_mmu *mmu = device->mmu; + if (!mmu->func->create) + return -EINVAL; + return mmu->func->create(mmu, offset, length, mm_offset, key, pvm); } static int @@ -410,38 +422,33 @@ nvkm_vm_link(struct nvkm_vm *vm, struct nvkm_gpuobj *pgd) if (!vpgd) return -ENOMEM; - nvkm_gpuobj_ref(pgd, &vpgd->obj); + vpgd->obj = pgd; - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&vm->mutex); for (i = vm->fpde; i <= vm->lpde; i++) - mmu->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); + mmu->func->map_pgt(pgd, i, vm->pgt[i - vm->fpde].mem); list_add(&vpgd->head, &vm->pgd_list); - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); return 0; } static void nvkm_vm_unlink(struct nvkm_vm *vm, struct nvkm_gpuobj *mpgd) { - struct nvkm_mmu *mmu = vm->mmu; struct nvkm_vm_pgd *vpgd, *tmp; - struct nvkm_gpuobj *pgd = NULL; if (!mpgd) return; - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&vm->mutex); list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { if (vpgd->obj == mpgd) { - pgd = vpgd->obj; list_del(&vpgd->head); kfree(vpgd); break; } } - mutex_unlock(&nv_subdev(mmu)->mutex); - - nvkm_gpuobj_ref(NULL, &pgd); + mutex_unlock(&vm->mutex); } static void @@ -478,3 +485,58 @@ nvkm_vm_ref(struct nvkm_vm *ref, struct nvkm_vm **ptr, struct nvkm_gpuobj *pgd) *ptr = ref; return 0; } + +static int +nvkm_mmu_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_mmu *mmu = nvkm_mmu(subdev); + if (mmu->func->oneinit) + return mmu->func->oneinit(mmu); + return 0; +} + +static int +nvkm_mmu_init(struct nvkm_subdev *subdev) +{ + struct nvkm_mmu *mmu = nvkm_mmu(subdev); + if (mmu->func->init) + mmu->func->init(mmu); + return 0; +} + +static void * +nvkm_mmu_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_mmu *mmu = nvkm_mmu(subdev); + if (mmu->func->dtor) + return mmu->func->dtor(mmu); + return mmu; +} + +static const struct nvkm_subdev_func +nvkm_mmu = { + .dtor = nvkm_mmu_dtor, + .oneinit = nvkm_mmu_oneinit, + .init = nvkm_mmu_init, +}; + +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); + mmu->func = func; + mmu->limit = func->limit; + mmu->dma_bits = func->dma_bits; + mmu->lpg_shift = func->lpg_shift; +} + +int +nvkm_mmu_new_(const struct nvkm_mmu_func *func, struct nvkm_device *device, + int index, struct nvkm_mmu **pmmu) +{ + if (!(*pmmu = kzalloc(sizeof(**pmmu), GFP_KERNEL))) + return -ENOMEM; + nvkm_mmu_ctor(func, device, index, *pmmu); + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 294cda37f..7ac507c92 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -21,19 +21,14 @@ * * Authors: Ben Skeggs */ -#include <subdev/mmu.h> -#include <subdev/bar.h> +#include "priv.h" + #include <subdev/fb.h> #include <subdev/ltc.h> #include <subdev/timer.h> #include <core/gpuobj.h> -struct gf100_mmu_priv { - struct nvkm_mmu base; -}; - - /* Map from compressed to corresponding uncompressed storage type. * The value 0xff represents an invalid storage type. */ @@ -75,17 +70,19 @@ const u8 gf100_pte_storage_type_map[256] = static void -gf100_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 index, struct nvkm_gpuobj *pgt[2]) +gf100_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 index, struct nvkm_memory *pgt[2]) { u32 pde[2] = { 0, 0 }; if (pgt[0]) - pde[1] = 0x00000001 | (pgt[0]->addr >> 8); + pde[1] = 0x00000001 | (nvkm_memory_addr(pgt[0]) >> 8); if (pgt[1]) - pde[0] = 0x00000001 | (pgt[1]->addr >> 8); + pde[0] = 0x00000001 | (nvkm_memory_addr(pgt[1]) >> 8); - nv_wo32(pgd, (index * 8) + 0, pde[0]); - nv_wo32(pgd, (index * 8) + 4, pde[1]); + nvkm_kmap(pgd); + nvkm_wo32(pgd, (index * 8) + 0, pde[0]); + nvkm_wo32(pgd, (index * 8) + 4, pde[1]); + nvkm_done(pgd); } static inline u64 @@ -103,7 +100,7 @@ gf100_vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target) } static void -gf100_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +gf100_vm_map(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) { u64 next = 1 << (vma->node->type - 8); @@ -112,126 +109,113 @@ gf100_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, pte <<= 3; if (mem->tag) { - struct nvkm_ltc *ltc = nvkm_ltc(vma->vm->mmu); + struct nvkm_ltc *ltc = vma->vm->mmu->subdev.device->ltc; u32 tag = mem->tag->offset + (delta >> 17); phys |= (u64)tag << (32 + 12); next |= (u64)1 << (32 + 12); - ltc->tags_clear(ltc, tag, cnt); + nvkm_ltc_tags_clear(ltc, tag, cnt); } + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte + 0, lower_32_bits(phys)); - nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + nvkm_wo32(pgt, pte + 0, lower_32_bits(phys)); + nvkm_wo32(pgt, pte + 4, upper_32_bits(phys)); phys += next; pte += 8; } + nvkm_done(pgt); } static void -gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5; /* compressed storage types are invalid for system memory */ u32 memtype = gf100_pte_storage_type_map[mem->memtype & 0xff]; + nvkm_kmap(pgt); pte <<= 3; while (cnt--) { u64 phys = gf100_vm_addr(vma, *list++, memtype, target); - nv_wo32(pgt, pte + 0, lower_32_bits(phys)); - nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + nvkm_wo32(pgt, pte + 0, lower_32_bits(phys)); + nvkm_wo32(pgt, pte + 4, upper_32_bits(phys)); pte += 8; } + nvkm_done(pgt); } static void -gf100_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +gf100_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { + nvkm_kmap(pgt); pte <<= 3; while (cnt--) { - nv_wo32(pgt, pte + 0, 0x00000000); - nv_wo32(pgt, pte + 4, 0x00000000); + nvkm_wo32(pgt, pte + 0, 0x00000000); + nvkm_wo32(pgt, pte + 4, 0x00000000); pte += 8; } + nvkm_done(pgt); } static void gf100_vm_flush(struct nvkm_vm *vm) { - struct gf100_mmu_priv *priv = (void *)vm->mmu; - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_mmu *mmu = vm->mmu; + struct nvkm_device *device = mmu->subdev.device; struct nvkm_vm_pgd *vpgd; u32 type; - bar->flush(bar); - type = 0x00000001; /* PAGE_ALL */ - if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR])) + if (atomic_read(&vm->engref[NVKM_SUBDEV_BAR])) type |= 0x00000004; /* HUB_ONLY */ - mutex_lock(&nv_subdev(priv)->mutex); + mutex_lock(&mmu->subdev.mutex); list_for_each_entry(vpgd, &vm->pgd_list, head) { /* looks like maybe a "free flush slots" counter, the * faster you write to 0x100cbc to more it decreases */ - if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) { - nv_error(priv, "vm timeout 0: 0x%08x %d\n", - nv_rd32(priv, 0x100c80), type); - } + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100c80) & 0x00ff0000) + break; + ); - nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8); - nv_wr32(priv, 0x100cbc, 0x80000000 | type); + nvkm_wr32(device, 0x100cb8, vpgd->obj->addr >> 8); + nvkm_wr32(device, 0x100cbc, 0x80000000 | type); /* wait for flush to be queued? */ - if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) { - nv_error(priv, "vm timeout 1: 0x%08x %d\n", - nv_rd32(priv, 0x100c80), type); - } + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100c80) & 0x00008000) + break; + ); } - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_unlock(&mmu->subdev.mutex); } static int gf100_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, - struct nvkm_vm **pvm) + struct lock_class_key *key, struct nvkm_vm **pvm) { - return nvkm_vm_create(mmu, offset, length, mm_offset, 4096, pvm); + return nvkm_vm_create(mmu, offset, length, mm_offset, 4096, key, pvm); } -static int -gf100_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_mmu_func +gf100_mmu = { + .limit = (1ULL << 40), + .dma_bits = 40, + .pgt_bits = 27 - 12, + .spg_shift = 12, + .lpg_shift = 17, + .create = gf100_vm_create, + .map_pgt = gf100_vm_map_pgt, + .map = gf100_vm_map, + .map_sg = gf100_vm_map_sg, + .unmap = gf100_vm_unmap, + .flush = gf100_vm_flush, +}; + +int +gf100_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) { - struct gf100_mmu_priv *priv; - int ret; - - ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.limit = 1ULL << 40; - priv->base.dma_bits = 40; - priv->base.pgt_bits = 27 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 17; - priv->base.create = gf100_vm_create; - priv->base.map_pgt = gf100_vm_map_pgt; - priv->base.map = gf100_vm_map; - priv->base.map_sg = gf100_vm_map_sg; - priv->base.unmap = gf100_vm_unmap; - priv->base.flush = gf100_vm_flush; - return 0; + return nvkm_mmu_new_(&gf100_mmu, device, index, pmmu); } - -struct nvkm_oclass -gf100_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_mmu_ctor, - .dtor = _nvkm_mmu_dtor, - .init = _nvkm_mmu_init, - .fini = _nvkm_mmu_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index fe93ea271..37927c3fd 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -23,7 +23,6 @@ */ #include "nv04.h" -#include <core/device.h> #include <core/gpuobj.h> #define NV04_PDMA_SIZE (128 * 1024 * 1024) @@ -34,30 +33,34 @@ ******************************************************************************/ static void -nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { pte = 0x00008 + (pte * 4); + nvkm_kmap(pgt); while (cnt) { u32 page = PAGE_SIZE / NV04_PDMA_PAGE; u32 phys = (u32)*list++; while (cnt && page--) { - nv_wo32(pgt, pte, phys | 3); + nvkm_wo32(pgt, pte, phys | 3); phys += NV04_PDMA_PAGE; pte += 4; cnt -= 1; } } + nvkm_done(pgt); } static void -nv04_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv04_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { pte = 0x00008 + (pte * 4); + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte, 0x00000000); + nvkm_wo32(pgt, pte, 0x00000000); pte += 4; } + nvkm_done(pgt); } static void @@ -66,86 +69,81 @@ nv04_vm_flush(struct nvkm_vm *vm) } /******************************************************************************* - * VM object - ******************************************************************************/ - -int -nv04_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mmstart, - struct nvkm_vm **pvm) -{ - return -EINVAL; -} - -/******************************************************************************* * MMU subdev ******************************************************************************/ static int -nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_mmu_oneinit(struct nvkm_mmu *base) { - struct nv04_mmu_priv *priv; - struct nvkm_gpuobj *dma; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; + struct nvkm_memory *dma; int ret; - ret = nvkm_mmu_create(parent, engine, oclass, "PCIGART", - "pcigart", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.create = nv04_vm_create; - priv->base.limit = NV04_PDMA_SIZE; - priv->base.dma_bits = 32; - priv->base.pgt_bits = 32 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 12; - priv->base.map_sg = nv04_vm_map_sg; - priv->base.unmap = nv04_vm_unmap; - priv->base.flush = nv04_vm_flush; - - ret = nvkm_vm_create(&priv->base, 0, NV04_PDMA_SIZE, 0, 4096, - &priv->vm); + ret = nvkm_vm_create(&mmu->base, 0, NV04_PDMA_SIZE, 0, 4096, NULL, + &mmu->vm); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 + 8, - 16, NVOBJ_FLAG_ZERO_ALLOC, - &priv->vm->pgt[0].obj[0]); - dma = priv->vm->pgt[0].obj[0]; - priv->vm->pgt[0].refcount[0] = 1; + 16, true, &dma); + mmu->vm->pgt[0].mem[0] = dma; + mmu->vm->pgt[0].refcount[0] = 1; if (ret) return ret; - nv_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */ - nv_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1); + nvkm_kmap(dma); + nvkm_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */ + nvkm_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1); + nvkm_done(dma); return 0; } -void -nv04_mmu_dtor(struct nvkm_object *object) +void * +nv04_mmu_dtor(struct nvkm_mmu *base) { - struct nv04_mmu_priv *priv = (void *)object; - if (priv->vm) { - nvkm_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]); - nvkm_vm_ref(NULL, &priv->vm, NULL); + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; + if (mmu->vm) { + nvkm_memory_del(&mmu->vm->pgt[0].mem[0]); + nvkm_vm_ref(NULL, &mmu->vm, NULL); } - if (priv->nullp) { - pci_free_consistent(nv_device(priv)->pdev, 16 * 1024, - priv->nullp, priv->null); + if (mmu->nullp) { + dma_free_coherent(device->dev, 16 * 1024, + mmu->nullp, mmu->null); } - nvkm_mmu_destroy(&priv->base); + return mmu; +} + +int +nv04_mmu_new_(const struct nvkm_mmu_func *func, struct nvkm_device *device, + int index, struct nvkm_mmu **pmmu) +{ + struct nv04_mmu *mmu; + if (!(mmu = kzalloc(sizeof(*mmu), GFP_KERNEL))) + return -ENOMEM; + *pmmu = &mmu->base; + nvkm_mmu_ctor(func, device, index, &mmu->base); + return 0; } -struct nvkm_oclass -nv04_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mmu_ctor, - .dtor = nv04_mmu_dtor, - .init = _nvkm_mmu_init, - .fini = _nvkm_mmu_fini, - }, +const struct nvkm_mmu_func +nv04_mmu = { + .oneinit = nv04_mmu_oneinit, + .dtor = nv04_mmu_dtor, + .limit = NV04_PDMA_SIZE, + .dma_bits = 32, + .pgt_bits = 32 - 12, + .spg_shift = 12, + .lpg_shift = 12, + .map_sg = nv04_vm_map_sg, + .unmap = nv04_vm_unmap, + .flush = nv04_vm_flush, }; + +int +nv04_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) +{ + return nv04_mmu_new_(&nv04_mmu, device, index, pmmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h index 7bf6f4b38..363e33b29 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h @@ -1,19 +1,18 @@ #ifndef __NV04_MMU_PRIV__ #define __NV04_MMU_PRIV__ +#define nv04_mmu(p) container_of((p), struct nv04_mmu, base) +#include "priv.h" -#include <subdev/mmu.h> - -struct nv04_mmu_priv { +struct nv04_mmu { struct nvkm_mmu base; struct nvkm_vm *vm; dma_addr_t null; void *nullp; }; -static inline struct nv04_mmu_priv * -nv04_mmu(void *obj) -{ - return (void *)nvkm_mmu(obj); -} +int nv04_mmu_new_(const struct nvkm_mmu_func *, struct nvkm_device *, + int index, struct nvkm_mmu **); +void *nv04_mmu_dtor(struct nvkm_mmu *); +extern const struct nvkm_mmu_func nv04_mmu; #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 61ee3ab11..c6a26f907 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -23,7 +23,6 @@ */ #include "nv04.h" -#include <core/device.h> #include <core/gpuobj.h> #include <core/option.h> #include <subdev/timer.h> @@ -36,45 +35,50 @@ ******************************************************************************/ static void -nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { pte = pte * 4; + nvkm_kmap(pgt); while (cnt) { u32 page = PAGE_SIZE / NV41_GART_PAGE; u64 phys = (u64)*list++; while (cnt && page--) { - nv_wo32(pgt, pte, (phys >> 7) | 1); + nvkm_wo32(pgt, pte, (phys >> 7) | 1); phys += NV41_GART_PAGE; pte += 4; cnt -= 1; } } + nvkm_done(pgt); } static void -nv41_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv41_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { pte = pte * 4; + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte, 0x00000000); + nvkm_wo32(pgt, pte, 0x00000000); pte += 4; } + nvkm_done(pgt); } static void nv41_vm_flush(struct nvkm_vm *vm) { - struct nv04_mmu_priv *priv = (void *)vm->mmu; - - mutex_lock(&nv_subdev(priv)->mutex); - nv_wr32(priv, 0x100810, 0x00000022); - if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) { - nv_warn(priv, "flush timeout, 0x%08x\n", - nv_rd32(priv, 0x100810)); - } - nv_wr32(priv, 0x100810, 0x00000000); - mutex_unlock(&nv_subdev(priv)->mutex); + struct nv04_mmu *mmu = nv04_mmu(vm->mmu); + struct nvkm_device *device = mmu->base.subdev.device; + + mutex_lock(&mmu->base.subdev.mutex); + nvkm_wr32(device, 0x100810, 0x00000022); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100810) & 0x00000020) + break; + ); + nvkm_wr32(device, 0x100810, 0x00000000); + mutex_unlock(&mmu->base.subdev.mutex); } /******************************************************************************* @@ -82,76 +86,56 @@ nv41_vm_flush(struct nvkm_vm *vm) ******************************************************************************/ static int -nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv41_mmu_oneinit(struct nvkm_mmu *base) { - struct nvkm_device *device = nv_device(parent); - struct nv04_mmu_priv *priv; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; int ret; - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || - !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) { - return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass, - data, size, pobject); - } - - ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART", - "pciegart", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.create = nv04_vm_create; - priv->base.limit = NV41_GART_SIZE; - priv->base.dma_bits = 39; - priv->base.pgt_bits = 32 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 12; - priv->base.map_sg = nv41_vm_map_sg; - priv->base.unmap = nv41_vm_unmap; - priv->base.flush = nv41_vm_flush; - - ret = nvkm_vm_create(&priv->base, 0, NV41_GART_SIZE, 0, 4096, - &priv->vm); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, - (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, - &priv->vm->pgt[0].obj[0]); - priv->vm->pgt[0].refcount[0] = 1; + ret = nvkm_vm_create(&mmu->base, 0, NV41_GART_SIZE, 0, 4096, NULL, + &mmu->vm); if (ret) return ret; - return 0; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16, true, + &mmu->vm->pgt[0].mem[0]); + mmu->vm->pgt[0].refcount[0] = 1; + return ret; } -static int -nv41_mmu_init(struct nvkm_object *object) +static void +nv41_mmu_init(struct nvkm_mmu *base) { - struct nv04_mmu_priv *priv = (void *)object; - struct nvkm_gpuobj *dma = priv->vm->pgt[0].obj[0]; - int ret; - - ret = nvkm_mmu_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x100800, dma->addr | 0x00000002); - nv_mask(priv, 0x10008c, 0x00000100, 0x00000100); - nv_wr32(priv, 0x100820, 0x00000000); - return 0; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; + struct nvkm_memory *dma = mmu->vm->pgt[0].mem[0]; + nvkm_wr32(device, 0x100800, 0x00000002 | nvkm_memory_addr(dma)); + nvkm_mask(device, 0x10008c, 0x00000100, 0x00000100); + nvkm_wr32(device, 0x100820, 0x00000000); } -struct nvkm_oclass -nv41_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x41), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv41_mmu_ctor, - .dtor = nv04_mmu_dtor, - .init = nv41_mmu_init, - .fini = _nvkm_mmu_fini, - }, +static const struct nvkm_mmu_func +nv41_mmu = { + .dtor = nv04_mmu_dtor, + .oneinit = nv41_mmu_oneinit, + .init = nv41_mmu_init, + .limit = NV41_GART_SIZE, + .dma_bits = 39, + .pgt_bits = 32 - 12, + .spg_shift = 12, + .lpg_shift = 12, + .map_sg = nv41_vm_map_sg, + .unmap = nv41_vm_unmap, + .flush = nv41_vm_flush, }; + +int +nv41_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) +{ + if (device->type == NVKM_DEVICE_AGP || + !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) + return nv04_mmu_new(device, index, pmmu); + + return nv04_mmu_new_(&nv41_mmu, device, index, pmmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index b90ded188..a648c2395 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -23,7 +23,6 @@ */ #include "nv04.h" -#include <core/device.h> #include <core/gpuobj.h> #include <core/option.h> #include <subdev/timer.h> @@ -36,16 +35,16 @@ ******************************************************************************/ static void -nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null, +nv44_vm_fill(struct nvkm_memory *pgt, dma_addr_t null, dma_addr_t *list, u32 pte, u32 cnt) { u32 base = (pte << 2) & ~0x0000000f; u32 tmp[4]; - tmp[0] = nv_ro32(pgt, base + 0x0); - tmp[1] = nv_ro32(pgt, base + 0x4); - tmp[2] = nv_ro32(pgt, base + 0x8); - tmp[3] = nv_ro32(pgt, base + 0xc); + tmp[0] = nvkm_ro32(pgt, base + 0x0); + tmp[1] = nvkm_ro32(pgt, base + 0x4); + tmp[2] = nvkm_ro32(pgt, base + 0x8); + tmp[3] = nvkm_ro32(pgt, base + 0xc); while (cnt--) { u32 addr = list ? (*list++ >> 12) : (null >> 12); @@ -75,24 +74,25 @@ nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null, } } - nv_wo32(pgt, base + 0x0, tmp[0]); - nv_wo32(pgt, base + 0x4, tmp[1]); - nv_wo32(pgt, base + 0x8, tmp[2]); - nv_wo32(pgt, base + 0xc, tmp[3] | 0x40000000); + nvkm_wo32(pgt, base + 0x0, tmp[0]); + nvkm_wo32(pgt, base + 0x4, tmp[1]); + nvkm_wo32(pgt, base + 0x8, tmp[2]); + nvkm_wo32(pgt, base + 0xc, tmp[3] | 0x40000000); } static void -nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { - struct nv04_mmu_priv *priv = (void *)vma->vm->mmu; + struct nv04_mmu *mmu = nv04_mmu(vma->vm->mmu); u32 tmp[4]; int i; + nvkm_kmap(pgt); if (pte & 3) { u32 max = 4 - (pte & 3); u32 part = (cnt > max) ? max : cnt; - nv44_vm_fill(pgt, priv->null, list, pte, part); + nv44_vm_fill(pgt, mmu->null, list, pte, part); pte += part; list += part; cnt -= part; @@ -101,51 +101,57 @@ nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, while (cnt >= 4) { for (i = 0; i < 4; i++) tmp[i] = *list++ >> 12; - nv_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27); - nv_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22); - nv_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17); - nv_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000); + nvkm_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27); + nvkm_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22); + nvkm_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17); + nvkm_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000); cnt -= 4; } if (cnt) - nv44_vm_fill(pgt, priv->null, list, pte, cnt); + nv44_vm_fill(pgt, mmu->null, list, pte, cnt); + nvkm_done(pgt); } static void -nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv44_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { - struct nv04_mmu_priv *priv = (void *)nvkm_mmu(pgt); + struct nv04_mmu *mmu = nv04_mmu(vma->vm->mmu); + nvkm_kmap(pgt); if (pte & 3) { u32 max = 4 - (pte & 3); u32 part = (cnt > max) ? max : cnt; - nv44_vm_fill(pgt, priv->null, NULL, pte, part); + nv44_vm_fill(pgt, mmu->null, NULL, pte, part); pte += part; cnt -= part; } while (cnt >= 4) { - nv_wo32(pgt, pte++ * 4, 0x00000000); - nv_wo32(pgt, pte++ * 4, 0x00000000); - nv_wo32(pgt, pte++ * 4, 0x00000000); - nv_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); cnt -= 4; } if (cnt) - nv44_vm_fill(pgt, priv->null, NULL, pte, cnt); + nv44_vm_fill(pgt, mmu->null, NULL, pte, cnt); + nvkm_done(pgt); } static void nv44_vm_flush(struct nvkm_vm *vm) { - struct nv04_mmu_priv *priv = (void *)vm->mmu; - nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE); - nv_wr32(priv, 0x100808, 0x00000020); - if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001)) - nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808)); - nv_wr32(priv, 0x100808, 0x00000000); + struct nv04_mmu *mmu = nv04_mmu(vm->mmu); + struct nvkm_device *device = mmu->base.subdev.device; + nvkm_wr32(device, 0x100814, mmu->base.limit - NV44_GART_PAGE); + nvkm_wr32(device, 0x100808, 0x00000020); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100808) & 0x00000001) + break; + ); + nvkm_wr32(device, 0x100808, 0x00000000); } /******************************************************************************* @@ -153,95 +159,78 @@ nv44_vm_flush(struct nvkm_vm *vm) ******************************************************************************/ static int -nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv44_mmu_oneinit(struct nvkm_mmu *base) { - struct nvkm_device *device = nv_device(parent); - struct nv04_mmu_priv *priv; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; int ret; - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || - !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) { - return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass, - data, size, pobject); - } - - ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART", - "pciegart", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.create = nv04_vm_create; - priv->base.limit = NV44_GART_SIZE; - priv->base.dma_bits = 39; - priv->base.pgt_bits = 32 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 12; - priv->base.map_sg = nv44_vm_map_sg; - priv->base.unmap = nv44_vm_unmap; - priv->base.flush = nv44_vm_flush; - - priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null); - if (!priv->nullp) { - nv_error(priv, "unable to allocate dummy pages\n"); - return -ENOMEM; + mmu->nullp = dma_alloc_coherent(device->dev, 16 * 1024, + &mmu->null, GFP_KERNEL); + if (!mmu->nullp) { + nvkm_warn(&mmu->base.subdev, "unable to allocate dummy pages\n"); + mmu->null = 0; } - ret = nvkm_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096, - &priv->vm); + ret = nvkm_vm_create(&mmu->base, 0, NV44_GART_SIZE, 0, 4096, NULL, + &mmu->vm); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, (NV44_GART_SIZE / NV44_GART_PAGE) * 4, - 512 * 1024, NVOBJ_FLAG_ZERO_ALLOC, - &priv->vm->pgt[0].obj[0]); - priv->vm->pgt[0].refcount[0] = 1; - if (ret) - return ret; - - return 0; + 512 * 1024, true, + &mmu->vm->pgt[0].mem[0]); + mmu->vm->pgt[0].refcount[0] = 1; + return ret; } -static int -nv44_mmu_init(struct nvkm_object *object) +static void +nv44_mmu_init(struct nvkm_mmu *base) { - struct nv04_mmu_priv *priv = (void *)object; - struct nvkm_gpuobj *gart = priv->vm->pgt[0].obj[0]; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; + struct nvkm_memory *gart = mmu->vm->pgt[0].mem[0]; u32 addr; - int ret; - - ret = nvkm_mmu_init(&priv->base); - if (ret) - return ret; /* calculate vram address of this PRAMIN block, object must be * allocated on 512KiB alignment, and not exceed a total size * of 512KiB for this to work correctly */ - addr = nv_rd32(priv, 0x10020c); - addr -= ((gart->addr >> 19) + 1) << 19; - - nv_wr32(priv, 0x100850, 0x80000000); - nv_wr32(priv, 0x100818, priv->null); - nv_wr32(priv, 0x100804, NV44_GART_SIZE); - nv_wr32(priv, 0x100850, 0x00008000); - nv_mask(priv, 0x10008c, 0x00000200, 0x00000200); - nv_wr32(priv, 0x100820, 0x00000000); - nv_wr32(priv, 0x10082c, 0x00000001); - nv_wr32(priv, 0x100800, addr | 0x00000010); - return 0; + addr = nvkm_rd32(device, 0x10020c); + addr -= ((nvkm_memory_addr(gart) >> 19) + 1) << 19; + + nvkm_wr32(device, 0x100850, 0x80000000); + nvkm_wr32(device, 0x100818, mmu->null); + nvkm_wr32(device, 0x100804, NV44_GART_SIZE); + nvkm_wr32(device, 0x100850, 0x00008000); + nvkm_mask(device, 0x10008c, 0x00000200, 0x00000200); + nvkm_wr32(device, 0x100820, 0x00000000); + nvkm_wr32(device, 0x10082c, 0x00000001); + nvkm_wr32(device, 0x100800, addr | 0x00000010); } -struct nvkm_oclass -nv44_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x44), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_mmu_ctor, - .dtor = nv04_mmu_dtor, - .init = nv44_mmu_init, - .fini = _nvkm_mmu_fini, - }, +static const struct nvkm_mmu_func +nv44_mmu = { + .dtor = nv04_mmu_dtor, + .oneinit = nv44_mmu_oneinit, + .init = nv44_mmu_init, + .limit = NV44_GART_SIZE, + .dma_bits = 39, + .pgt_bits = 32 - 12, + .spg_shift = 12, + .lpg_shift = 12, + .map_sg = nv44_vm_map_sg, + .unmap = nv44_vm_unmap, + .flush = nv44_vm_flush, }; + +int +nv44_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) +{ + if (device->type == NVKM_DEVICE_AGP || + !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) + return nv04_mmu_new(device, index, pmmu); + + return nv04_mmu_new_(&nv44_mmu, device, index, pmmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index b83550fa7..a1f8d65f0 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -21,31 +21,28 @@ * * Authors: Ben Skeggs */ -#include <subdev/mmu.h> -#include <subdev/bar.h> -#include <subdev/fb.h> -#include <subdev/timer.h> +#include "priv.h" -#include <core/engine.h> #include <core/gpuobj.h> - -struct nv50_mmu_priv { - struct nvkm_mmu base; -}; +#include <subdev/fb.h> +#include <subdev/timer.h> +#include <engine/gr.h> static void -nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2]) +nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_memory *pgt[2]) { u64 phys = 0xdeadcafe00000000ULL; u32 coverage = 0; if (pgt[0]) { - phys = 0x00000003 | pgt[0]->addr; /* present, 4KiB pages */ - coverage = (pgt[0]->size >> 3) << 12; + /* present, 4KiB pages */ + phys = 0x00000003 | nvkm_memory_addr(pgt[0]); + coverage = (nvkm_memory_size(pgt[0]) >> 3) << 12; } else if (pgt[1]) { - phys = 0x00000001 | pgt[1]->addr; /* present */ - coverage = (pgt[1]->size >> 3) << 16; + /* present, 64KiB pages */ + phys = 0x00000001 | nvkm_memory_addr(pgt[1]); + coverage = (nvkm_memory_size(pgt[1]) >> 3) << 16; } if (phys & 1) { @@ -57,8 +54,10 @@ nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2]) phys |= 0x20; } - nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); - nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); + nvkm_kmap(pgd); + nvkm_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); + nvkm_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); + nvkm_done(pgd); } static inline u64 @@ -75,17 +74,18 @@ vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target) } static void -nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv50_vm_map(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) { + struct nvkm_ram *ram = vma->vm->mmu->subdev.device->fb->ram; u32 comp = (mem->memtype & 0x180) >> 7; u32 block, target; int i; /* IGPs don't have real VRAM, re-target to stolen system memory */ target = 0; - if (nvkm_fb(vma->vm->mmu)->ram->stolen) { - phys += nvkm_fb(vma->vm->mmu)->ram->stolen; + if (ram->stolen) { + phys += ram->stolen; target = 3; } @@ -93,6 +93,7 @@ nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, pte <<= 3; cnt <<= 3; + nvkm_kmap(pgt); while (cnt) { u32 offset_h = upper_32_bits(phys); u32 offset_l = lower_32_bits(phys); @@ -113,129 +114,118 @@ nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } while (block) { - nv_wo32(pgt, pte + 0, offset_l); - nv_wo32(pgt, pte + 4, offset_h); + nvkm_wo32(pgt, pte + 0, offset_l); + nvkm_wo32(pgt, pte + 4, offset_h); pte += 8; block -= 8; } } + nvkm_done(pgt); } static void -nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2; pte <<= 3; + nvkm_kmap(pgt); while (cnt--) { u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target); - nv_wo32(pgt, pte + 0, lower_32_bits(phys)); - nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + nvkm_wo32(pgt, pte + 0, lower_32_bits(phys)); + nvkm_wo32(pgt, pte + 4, upper_32_bits(phys)); pte += 8; } + nvkm_done(pgt); } static void -nv50_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv50_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { pte <<= 3; + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte + 0, 0x00000000); - nv_wo32(pgt, pte + 4, 0x00000000); + nvkm_wo32(pgt, pte + 0, 0x00000000); + nvkm_wo32(pgt, pte + 4, 0x00000000); pte += 8; } + nvkm_done(pgt); } static void nv50_vm_flush(struct nvkm_vm *vm) { - struct nv50_mmu_priv *priv = (void *)vm->mmu; - struct nvkm_bar *bar = nvkm_bar(priv); - struct nvkm_engine *engine; + struct nvkm_mmu *mmu = vm->mmu; + struct nvkm_subdev *subdev = &mmu->subdev; + struct nvkm_device *device = subdev->device; int i, vme; - bar->flush(bar); - - mutex_lock(&nv_subdev(priv)->mutex); - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + mutex_lock(&subdev->mutex); + for (i = 0; i < NVKM_SUBDEV_NR; i++) { if (!atomic_read(&vm->engref[i])) continue; /* unfortunate hw bug workaround... */ - engine = nvkm_engine(priv, i); - if (engine && engine->tlb_flush) { - engine->tlb_flush(engine); - continue; + if (i == NVKM_ENGINE_GR && device->gr) { + int ret = nvkm_gr_tlb_flush(device->gr); + if (ret != -ENODEV) + continue; } switch (i) { - case NVDEV_ENGINE_GR : vme = 0x00; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: vme = 0x01; break; - case NVDEV_SUBDEV_BAR : vme = 0x06; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : vme = 0x08; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : vme = 0x09; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : vme = 0x0a; break; - case NVDEV_ENGINE_CE0 : vme = 0x0d; break; + case NVKM_ENGINE_GR : vme = 0x00; break; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: vme = 0x01; break; + case NVKM_SUBDEV_BAR : vme = 0x06; break; + case NVKM_ENGINE_MSPPP : + case NVKM_ENGINE_MPEG : vme = 0x08; break; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : vme = 0x09; break; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : vme = 0x0a; break; + case NVKM_ENGINE_CE0 : vme = 0x0d; break; default: continue; } - nv_wr32(priv, 0x100c80, (vme << 16) | 1); - if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) - nv_error(priv, "vm flush timeout: engine %d\n", vme); + nvkm_wr32(device, 0x100c80, (vme << 16) | 1); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) + break; + ) < 0) + nvkm_error(subdev, "vm flush timeout: engine %d\n", vme); } - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_unlock(&subdev->mutex); } static int -nv50_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, - u64 mm_offset, struct nvkm_vm **pvm) +nv50_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, + struct lock_class_key *key, struct nvkm_vm **pvm) { - u32 block = (1 << (mmu->pgt_bits + 12)); + u32 block = (1 << (mmu->func->pgt_bits + 12)); if (block > length) block = length; - return nvkm_vm_create(mmu, offset, length, mm_offset, block, pvm); + return nvkm_vm_create(mmu, offset, length, mm_offset, block, key, pvm); } -static int -nv50_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_mmu_func +nv50_mmu = { + .limit = (1ULL << 40), + .dma_bits = 40, + .pgt_bits = 29 - 12, + .spg_shift = 12, + .lpg_shift = 16, + .create = nv50_vm_create, + .map_pgt = nv50_vm_map_pgt, + .map = nv50_vm_map, + .map_sg = nv50_vm_map_sg, + .unmap = nv50_vm_unmap, + .flush = nv50_vm_flush, +}; + +int +nv50_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) { - struct nv50_mmu_priv *priv; - int ret; - - ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.limit = 1ULL << 40; - priv->base.dma_bits = 40; - priv->base.pgt_bits = 29 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 16; - priv->base.create = nv50_vm_create; - priv->base.map_pgt = nv50_vm_map_pgt; - priv->base.map = nv50_vm_map; - priv->base.map_sg = nv50_vm_map_sg; - priv->base.unmap = nv50_vm_unmap; - priv->base.flush = nv50_vm_flush; - return 0; + return nvkm_mmu_new_(&nv50_mmu, device, index, pmmu); } - -struct nvkm_oclass -nv50_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mmu_ctor, - .dtor = _nvkm_mmu_dtor, - .init = _nvkm_mmu_init, - .fini = _nvkm_mmu_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h new file mode 100644 index 000000000..27cedc60b --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h @@ -0,0 +1,39 @@ +#ifndef __NVKM_MMU_PRIV_H__ +#define __NVKM_MMU_PRIV_H__ +#define nvkm_mmu(p) container_of((p), struct nvkm_mmu, subdev) +#include <subdev/mmu.h> + +void nvkm_mmu_ctor(const struct nvkm_mmu_func *, struct nvkm_device *, + int index, struct nvkm_mmu *); +int nvkm_mmu_new_(const struct nvkm_mmu_func *, struct nvkm_device *, + int index, struct nvkm_mmu **); + +struct nvkm_mmu_func { + void *(*dtor)(struct nvkm_mmu *); + int (*oneinit)(struct nvkm_mmu *); + void (*init)(struct nvkm_mmu *); + + u64 limit; + u8 dma_bits; + u32 pgt_bits; + u8 spg_shift; + u8 lpg_shift; + + int (*create)(struct nvkm_mmu *, u64 offset, u64 length, u64 mm_offset, + struct lock_class_key *, struct nvkm_vm **); + + void (*map_pgt)(struct nvkm_gpuobj *pgd, u32 pde, + struct nvkm_memory *pgt[2]); + void (*map)(struct nvkm_vma *, struct nvkm_memory *, + struct nvkm_mem *, u32 pte, u32 cnt, + u64 phys, u64 delta); + void (*map_sg)(struct nvkm_vma *, struct nvkm_memory *, + struct nvkm_mem *, u32 pte, u32 cnt, dma_addr_t *); + void (*unmap)(struct nvkm_vma *, struct nvkm_memory *pgt, + u32 pte, u32 cnt); + void (*flush)(struct nvkm_vm *); +}; + +int nvkm_vm_create(struct nvkm_mmu *, u64, u64, u64, u32, + struct lock_class_key *, struct nvkm_vm **); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 0ca9dcabb..9700a7625 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -23,14 +23,13 @@ */ #include "mxms.h" -#include <core/device.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/mxm.h> #include <subdev/i2c.h> static bool -mxm_shadow_rom_fetch(struct nvkm_i2c_port *i2c, u8 addr, +mxm_shadow_rom_fetch(struct nvkm_i2c_bus *bus, u8 addr, u8 offset, u8 size, u8 *data) { struct i2c_msg msgs[] = { @@ -38,27 +37,28 @@ mxm_shadow_rom_fetch(struct nvkm_i2c_port *i2c, u8 addr, { .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, }, }; - return i2c_transfer(&i2c->adapter, msgs, 2) == 2; + return i2c_transfer(&bus->i2c, msgs, 2) == 2; } static bool mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version) { - struct nvkm_bios *bios = nvkm_bios(mxm); - struct nvkm_i2c *i2c = nvkm_i2c(mxm); - struct nvkm_i2c_port *port = NULL; + struct nvkm_device *device = mxm->subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; + struct nvkm_i2c_bus *bus = NULL; u8 i2cidx, mxms[6], addr, size; i2cidx = mxm_ddc_map(bios, 1 /* LVDS_DDC */) & 0x0f; if (i2cidx < 0x0f) - port = i2c->find(i2c, i2cidx); - if (!port) + bus = nvkm_i2c_bus_find(i2c, i2cidx); + if (!bus) return false; addr = 0x54; - if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) { + if (!mxm_shadow_rom_fetch(bus, addr, 0, 6, mxms)) { addr = 0x56; - if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) + if (!mxm_shadow_rom_fetch(bus, addr, 0, 6, mxms)) return false; } @@ -67,7 +67,7 @@ mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version) mxm->mxms = kmalloc(size, GFP_KERNEL); if (mxm->mxms && - mxm_shadow_rom_fetch(port, addr, 0, size, mxm->mxms)) + mxm_shadow_rom_fetch(bus, addr, 0, size, mxm->mxms)) return true; kfree(mxm->mxms); @@ -79,7 +79,8 @@ mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version) static bool mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) { - struct nvkm_device *device = nv_device(mxm); + struct nvkm_subdev *subdev = &mxm->subdev; + struct nvkm_device *device = subdev->device; static char muid[] = { 0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C, 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 @@ -94,7 +95,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) acpi_handle handle; int rev; - handle = ACPI_HANDLE(nv_device_base(device)); + handle = ACPI_HANDLE(device->dev); if (!handle) return false; @@ -106,7 +107,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) rev = (version & 0xf0) << 4 | (version & 0x0f); obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4); if (!obj) { - nv_debug(mxm, "DSM MXMS failed\n"); + nvkm_debug(subdev, "DSM MXMS failed\n"); return false; } @@ -114,7 +115,8 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) mxm->mxms = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL); } else if (obj->type == ACPI_TYPE_INTEGER) { - nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); + nvkm_debug(subdev, "DSM MXMS returned 0x%llx\n", + obj->integer.value); } ACPI_FREE(obj); @@ -129,6 +131,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) static u8 wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version) { + struct nvkm_subdev *subdev = &mxm->subdev; u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 }; struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args }; struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -137,18 +140,18 @@ wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version) status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn); if (ACPI_FAILURE(status)) { - nv_debug(mxm, "WMMX MXMI returned %d\n", status); + nvkm_debug(subdev, "WMMX MXMI returned %d\n", status); return 0x00; } obj = retn.pointer; if (obj->type == ACPI_TYPE_INTEGER) { version = obj->integer.value; - nv_debug(mxm, "WMMX MXMI version %d.%d\n", - (version >> 4), version & 0x0f); + nvkm_debug(subdev, "WMMX MXMI version %d.%d\n", + (version >> 4), version & 0x0f); } else { version = 0; - nv_debug(mxm, "WMMX MXMI returned non-integer\n"); + nvkm_debug(subdev, "WMMX MXMI returned non-integer\n"); } kfree(obj); @@ -158,6 +161,7 @@ wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version) static bool mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version) { + struct nvkm_subdev *subdev = &mxm->subdev; u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 }; struct acpi_buffer args = { sizeof(mxms_args), mxms_args }; struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -165,7 +169,7 @@ mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version) acpi_status status; if (!wmi_has_guid(WMI_WMMX_GUID)) { - nv_debug(mxm, "WMMX GUID not found\n"); + nvkm_debug(subdev, "WMMX GUID not found\n"); return false; } @@ -177,7 +181,7 @@ mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version) status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn); if (ACPI_FAILURE(status)) { - nv_debug(mxm, "WMMX MXMS returned %d\n", status); + nvkm_debug(subdev, "WMMX MXMS returned %d\n", status); return false; } @@ -211,7 +215,7 @@ mxm_shadow(struct nvkm_mxm *mxm, u8 version) { struct mxm_shadow_h *shadow = _mxm_shadow; do { - nv_debug(mxm, "checking %s\n", shadow->name); + nvkm_debug(&mxm->subdev, "checking %s\n", shadow->name); if (shadow->exec(mxm, version)) { if (mxms_valid(mxm)) return 0; @@ -222,33 +226,33 @@ mxm_shadow(struct nvkm_mxm *mxm, u8 version) return -ENOENT; } +static const struct nvkm_subdev_func +nvkm_mxm = { +}; + int -nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_mxm_new_(struct nvkm_device *device, int index, struct nvkm_mxm **pmxm) { - struct nvkm_device *device = nv_device(parent); - struct nvkm_bios *bios = nvkm_bios(device); + struct nvkm_bios *bios = device->bios; struct nvkm_mxm *mxm; u8 ver, len; u16 data; - int ret; - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "MXM", "mxm", - length, pobject); - mxm = *pobject; - if (ret) - return ret; + if (!(mxm = *pmxm = kzalloc(sizeof(*mxm), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_mxm, device, index, 0, &mxm->subdev); data = mxm_table(bios, &ver, &len); - if (!data || !(ver = nv_ro08(bios, data))) { - nv_debug(mxm, "no VBIOS data, nothing to do\n"); + if (!data || !(ver = nvbios_rd08(bios, data))) { + nvkm_debug(&mxm->subdev, "no VBIOS data, nothing to do\n"); return 0; } - nv_info(mxm, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f); + nvkm_info(&mxm->subdev, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f); if (mxm_shadow(mxm, ver)) { - nv_info(mxm, "failed to locate valid SIS\n"); + nvkm_warn(&mxm->subdev, "failed to locate valid SIS\n"); #if 0 /* we should, perhaps, fall back to some kind of limited * mode here if the x86 vbios hasn't already done the @@ -261,8 +265,8 @@ nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine, #endif } - nv_info(mxm, "MXMS Version %d.%d\n", - mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff); + nvkm_debug(&mxm->subdev, "MXMS Version %d.%d\n", + mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff); mxms_foreach(mxm, 0, NULL, NULL); if (nvkm_boolopt(device->cfgopt, "NvMXMDCB", true)) diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c index a9b1d63fe..45a2f8e78 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c @@ -47,7 +47,7 @@ mxms_version(struct nvkm_mxm *mxm) break; } - nv_debug(mxm, "unknown version %d.%d\n", mxms[4], mxms[5]); + nvkm_debug(&mxm->subdev, "unknown version %d.%d\n", mxms[4], mxms[5]); return 0x0000; } @@ -71,7 +71,7 @@ mxms_checksum(struct nvkm_mxm *mxm) while (size--) sum += *mxms++; if (sum) { - nv_debug(mxm, "checksum invalid\n"); + nvkm_debug(&mxm->subdev, "checksum invalid\n"); return false; } return true; @@ -82,7 +82,7 @@ mxms_valid(struct nvkm_mxm *mxm) { u8 *mxms = mxms_data(mxm); if (*(u32 *)mxms != 0x5f4d584d) { - nv_debug(mxm, "signature invalid\n"); + nvkm_debug(&mxm->subdev, "signature invalid\n"); return false; } @@ -96,6 +96,7 @@ bool mxms_foreach(struct nvkm_mxm *mxm, u8 types, bool (*exec)(struct nvkm_mxm *, u8 *, void *), void *info) { + struct nvkm_subdev *subdev = &mxm->subdev; u8 *mxms = mxms_data(mxm); u8 *desc = mxms + mxms_headerlen(mxm); u8 *fini = desc + mxms_structlen(mxm) - 1; @@ -140,29 +141,28 @@ mxms_foreach(struct nvkm_mxm *mxm, u8 types, entries = desc[1] & 0x07; break; default: - nv_debug(mxm, "unknown descriptor type %d\n", type); + nvkm_debug(subdev, "unknown descriptor type %d\n", type); return false; } - if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) { - static const char * mxms_desc_name[] = { + if (mxm->subdev.debug >= NV_DBG_DEBUG && (exec == NULL)) { + static const char * mxms_desc[] = { "ODS", "SCCS", "TS", "IPS", "GSD", "VSS", "BCS", "FCS", }; u8 *dump = desc; + char data[32], *ptr; int i, j; - nv_debug(mxm, "%4s: ", mxms_desc_name[type]); - for (j = headerlen - 1; j >= 0; j--) - pr_cont("%02x", dump[j]); - pr_cont("\n"); + for (j = headerlen - 1, ptr = data; j >= 0; j--) + ptr += sprintf(ptr, "%02x", dump[j]); dump += headerlen; + nvkm_debug(subdev, "%4s: %s\n", mxms_desc[type], data); for (i = 0; i < entries; i++, dump += recordlen) { - nv_debug(mxm, " "); - for (j = recordlen - 1; j >= 0; j--) - pr_cont("%02x", dump[j]); - pr_cont("\n"); + for (j = recordlen - 1, ptr = data; j >= 0; j--) + ptr += sprintf(ptr, "%02x", dump[j]); + nvkm_debug(subdev, " %s\n", data); } } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h index 4ef804012..333e0c015 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h @@ -1,6 +1,6 @@ #ifndef __NVMXM_MXMS_H__ #define __NVMXM_MXMS_H__ -#include <subdev/mxm.h> +#include "priv.h" struct mxms_odev { u8 outp_type; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c index f20e4ca87..db14fad2d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c @@ -28,10 +28,6 @@ #include <subdev/bios/dcb.h> #include <subdev/bios/mxm.h> -struct nv50_mxm_priv { - struct nvkm_mxm base; -}; - struct context { u32 *outp; struct mxms_odev desc; @@ -53,7 +49,7 @@ mxm_match_tmds_partner(struct nvkm_mxm *mxm, u8 *data, void *info) static bool mxm_match_dcb(struct nvkm_mxm *mxm, u8 *data, void *info) { - struct nvkm_bios *bios = nvkm_bios(mxm); + struct nvkm_bios *bios = mxm->subdev.device->bios; struct context *ctx = info; u64 desc = *(u64 *)data; @@ -107,8 +103,8 @@ mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb) * if one isn't found, disable it. */ if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) { - nv_debug(mxm, "disable %d: 0x%08x 0x%08x\n", - idx, ctx.outp[0], ctx.outp[1]); + nvkm_debug(&mxm->subdev, "disable %d: %08x %08x\n", + idx, ctx.outp[0], ctx.outp[1]); ctx.outp[0] |= 0x0000000f; return 0; } @@ -180,20 +176,22 @@ mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb) static bool mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info) { + struct nvkm_subdev *subdev = &mxm->subdev; u64 desc = *(u64 *)data; if ((desc & 0xf0) != 0xf0) - nv_info(mxm, "unmatched output device 0x%016llx\n", desc); + nvkm_info(subdev, "unmatched output device %016llx\n", desc); return true; } static void mxm_dcb_sanitise(struct nvkm_mxm *mxm) { - struct nvkm_bios *bios = nvkm_bios(mxm); + struct nvkm_subdev *subdev = &mxm->subdev; + struct nvkm_bios *bios = subdev->device->bios; u8 ver, hdr, cnt, len; u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); if (dcb == 0x0000 || ver != 0x40) { - nv_debug(mxm, "unsupported DCB version\n"); + nvkm_debug(subdev, "unsupported DCB version\n"); return; } @@ -201,31 +199,20 @@ mxm_dcb_sanitise(struct nvkm_mxm *mxm) mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL); } -static int -nv50_mxm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_mxm_new(struct nvkm_device *device, int index, struct nvkm_subdev **pmxm) { - struct nv50_mxm_priv *priv; + struct nvkm_mxm *mxm; int ret; - ret = nvkm_mxm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mxm_new_(device, index, &mxm); + if (mxm) + *pmxm = &mxm->subdev; if (ret) return ret; - if (priv->base.action & MXM_SANITISE_DCB) - mxm_dcb_sanitise(&priv->base); + if (mxm->action & MXM_SANITISE_DCB) + mxm_dcb_sanitise(mxm); + return 0; } - -struct nvkm_oclass -nv50_mxm_oclass = { - .handle = NV_SUBDEV(MXM, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mxm_ctor, - .dtor = _nvkm_mxm_dtor, - .init = _nvkm_mxm_init, - .fini = _nvkm_mxm_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h new file mode 100644 index 000000000..7d970157a --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h @@ -0,0 +1,15 @@ +#ifndef __NVKM_MXM_PRIV_H__ +#define __NVKM_MXM_PRIV_H__ +#define nvkm_mxm(p) container_of((p), struct nvkm_mxm, subdev) +#include <subdev/mxm.h> + +#define MXM_SANITISE_DCB 0x00000001 + +struct nvkm_mxm { + struct nvkm_subdev subdev; + u32 action; + u8 *mxms; +}; + +int nvkm_mxm_new_(struct nvkm_device *, int index, struct nvkm_mxm **); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild new file mode 100644 index 000000000..4476ef75a --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -0,0 +1,9 @@ +nvkm-y += nvkm/subdev/pci/agp.o +nvkm-y += nvkm/subdev/pci/base.o +nvkm-y += nvkm/subdev/pci/nv04.o +nvkm-y += nvkm/subdev/pci/nv40.o +nvkm-y += nvkm/subdev/pci/nv46.o +nvkm-y += nvkm/subdev/pci/nv4c.o +nvkm-y += nvkm/subdev/pci/g84.o +nvkm-y += nvkm/subdev/pci/g94.o +nvkm-y += nvkm/subdev/pci/gf100.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c new file mode 100644 index 000000000..385a90f91 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c @@ -0,0 +1,175 @@ +/* + * Copyright 2015 Nouveau Project + * + * 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 "agp.h" +#ifdef __NVKM_PCI_AGP_H__ +#include <core/option.h> + +struct nvkm_device_agp_quirk { + u16 hostbridge_vendor; + u16 hostbridge_device; + u16 chip_vendor; + u16 chip_device; + int mode; +}; + +static const struct nvkm_device_agp_quirk +nvkm_device_agp_quirks[] = { + /* VIA Apollo PRO133x / GeForce FX 5600 Ultra - fdo#20341 */ + { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 }, + /* SiS 761 does not support AGP cards, use PCI mode */ + { PCI_VENDOR_ID_SI, 0x0761, PCI_ANY_ID, PCI_ANY_ID, 0 }, + {}, +}; + +void +nvkm_agp_fini(struct nvkm_pci *pci) +{ + if (pci->agp.acquired) { + agp_backend_release(pci->agp.bridge); + pci->agp.acquired = false; + } +} + +/* Ensure AGP controller is in a consistent state in case we need to + * execute the VBIOS DEVINIT scripts. + */ +void +nvkm_agp_preinit(struct nvkm_pci *pci) +{ + struct nvkm_device *device = pci->subdev.device; + u32 mode = nvkm_pci_rd32(pci, 0x004c); + u32 save[2]; + + /* First of all, disable fast writes, otherwise if it's already + * enabled in the AGP bridge and we disable the card's AGP + * controller we might be locking ourselves out of it. + */ + if ((mode | pci->agp.mode) & PCI_AGP_COMMAND_FW) { + mode = pci->agp.mode & ~PCI_AGP_COMMAND_FW; + agp_enable(pci->agp.bridge, mode); + } + + /* clear busmaster bit, and disable AGP */ + save[0] = nvkm_pci_rd32(pci, 0x0004); + nvkm_pci_wr32(pci, 0x0004, save[0] & ~0x00000004); + nvkm_pci_wr32(pci, 0x004c, 0x00000000); + + /* reset PGRAPH, PFIFO and PTIMER */ + save[1] = nvkm_mask(device, 0x000200, 0x00011100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00011100, save[1]); + + /* and restore busmaster bit (gives effect of resetting AGP) */ + nvkm_pci_wr32(pci, 0x0004, save[0]); +} + +int +nvkm_agp_init(struct nvkm_pci *pci) +{ + if (!agp_backend_acquire(pci->pdev)) { + nvkm_error(&pci->subdev, "failed to acquire agp\n"); + return -ENODEV; + } + + agp_enable(pci->agp.bridge, pci->agp.mode); + pci->agp.acquired = true; + return 0; +} + +void +nvkm_agp_dtor(struct nvkm_pci *pci) +{ + arch_phys_wc_del(pci->agp.mtrr); +} + +void +nvkm_agp_ctor(struct nvkm_pci *pci) +{ + const struct nvkm_device_agp_quirk *quirk = nvkm_device_agp_quirks; + struct nvkm_subdev *subdev = &pci->subdev; + struct nvkm_device *device = subdev->device; + struct agp_kern_info info; + int mode = -1; + +#ifdef __powerpc__ + /* Disable AGP by default on all PowerPC machines for now -- At + * least some UniNorth-2 AGP bridges are known to be broken: + * DMA from the host to the card works just fine, but writeback + * from the card to the host goes straight to memory + * untranslated bypassing that GATT somehow, making them quite + * painful to deal with... + */ + mode = 0; +#endif + mode = nvkm_longopt(device->cfgopt, "NvAGP", mode); + + /* acquire bridge temporarily, so that we can copy its info */ + if (!(pci->agp.bridge = agp_backend_acquire(pci->pdev))) { + nvkm_warn(subdev, "failed to acquire agp\n"); + return; + } + agp_copy_info(pci->agp.bridge, &info); + agp_backend_release(pci->agp.bridge); + + pci->agp.mode = info.mode; + pci->agp.base = info.aper_base; + pci->agp.size = info.aper_size * 1024 * 1024; + pci->agp.cma = info.cant_use_aperture; + pci->agp.mtrr = -1; + + /* determine if bridge + chipset combination needs a workaround */ + while (quirk->hostbridge_vendor) { + if (info.device->vendor == quirk->hostbridge_vendor && + info.device->device == quirk->hostbridge_device && + (quirk->chip_vendor == (u16)PCI_ANY_ID || + pci->pdev->vendor == quirk->chip_vendor) && + (quirk->chip_device == (u16)PCI_ANY_ID || + pci->pdev->device == quirk->chip_device)) { + nvkm_info(subdev, "forcing default agp mode to %dX, " + "use NvAGP=<mode> to override\n", + quirk->mode); + mode = quirk->mode; + break; + } + quirk++; + } + + /* apply quirk / user-specified mode */ + if (mode >= 1) { + if (pci->agp.mode & 0x00000008) + mode /= 4; /* AGPv3 */ + pci->agp.mode &= ~0x00000007; + pci->agp.mode |= (mode & 0x7); + } else + if (mode == 0) { + pci->agp.bridge = NULL; + return; + } + + /* fast writes appear to be broken on nv18, they make the card + * lock up randomly. + */ + if (device->chipset == 0x18) + pci->agp.mode &= ~PCI_AGP_COMMAND_FW; + + pci->agp.mtrr = arch_phys_wc_add(pci->agp.base, pci->agp.size); +} +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h new file mode 100644 index 000000000..df2dd0836 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h @@ -0,0 +1,18 @@ +#include "priv.h" +#if defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)) +#ifndef __NVKM_PCI_AGP_H__ +#define __NVKM_PCI_AGP_H__ + +void nvkm_agp_ctor(struct nvkm_pci *); +void nvkm_agp_dtor(struct nvkm_pci *); +void nvkm_agp_preinit(struct nvkm_pci *); +int nvkm_agp_init(struct nvkm_pci *); +void nvkm_agp_fini(struct nvkm_pci *); +#endif +#else +static inline void nvkm_agp_ctor(struct nvkm_pci *pci) {} +static inline void nvkm_agp_dtor(struct nvkm_pci *pci) {} +static inline void nvkm_agp_preinit(struct nvkm_pci *pci) {} +static inline int nvkm_agp_init(struct nvkm_pci *pci) { return -ENOSYS; } +static inline void nvkm_agp_fini(struct nvkm_pci *pci) {} +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c new file mode 100644 index 000000000..d671dcfaf --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -0,0 +1,193 @@ +/* + * Copyright 2015 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" +#include "agp.h" + +#include <core/option.h> +#include <core/pci.h> +#include <subdev/mc.h> + +u32 +nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr) +{ + return pci->func->rd32(pci, addr); +} + +void +nvkm_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data) +{ + pci->func->wr08(pci, addr, data); +} + +void +nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) +{ + pci->func->wr32(pci, addr, data); +} + +u32 +nvkm_pci_mask(struct nvkm_pci *pci, u16 addr, u32 mask, u32 value) +{ + u32 data = pci->func->rd32(pci, addr); + pci->func->wr32(pci, addr, (data & ~mask) | value); + return data; +} + +void +nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) +{ + u32 data = nvkm_pci_rd32(pci, 0x0050); + if (shadow) + data |= 0x00000001; + else + data &= ~0x00000001; + nvkm_pci_wr32(pci, 0x0050, data); +} + +static irqreturn_t +nvkm_pci_intr(int irq, void *arg) +{ + struct nvkm_pci *pci = arg; + struct nvkm_mc *mc = pci->subdev.device->mc; + bool handled = false; + if (likely(mc)) { + nvkm_mc_intr_unarm(mc); + if (pci->msi) + pci->func->msi_rearm(pci); + nvkm_mc_intr(mc, &handled); + nvkm_mc_intr_rearm(mc); + } + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static int +nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + + if (pci->irq >= 0) { + free_irq(pci->irq, pci); + pci->irq = -1; + }; + + if (pci->agp.bridge) + nvkm_agp_fini(pci); + + return 0; +} + +static int +nvkm_pci_preinit(struct nvkm_subdev *subdev) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + if (pci->agp.bridge) + nvkm_agp_preinit(pci); + return 0; +} + +static int +nvkm_pci_init(struct nvkm_subdev *subdev) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + struct pci_dev *pdev = pci->pdev; + int ret; + + if (pci->agp.bridge) { + ret = nvkm_agp_init(pci); + if (ret) + return ret; + } + + if (pci->func->init) + pci->func->init(pci); + + ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci); + if (ret) + return ret; + + pci->irq = pdev->irq; + return ret; +} + +static void * +nvkm_pci_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + nvkm_agp_dtor(pci); + if (pci->msi) + pci_disable_msi(pci->pdev); + return nvkm_pci(subdev); +} + +static const struct nvkm_subdev_func +nvkm_pci_func = { + .dtor = nvkm_pci_dtor, + .preinit = nvkm_pci_preinit, + .init = nvkm_pci_init, + .fini = nvkm_pci_fini, +}; + +int +nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, + int index, struct nvkm_pci **ppci) +{ + struct nvkm_pci *pci; + + if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_pci_func, device, index, 0, &pci->subdev); + pci->func = func; + pci->pdev = device->func->pci(device)->pdev; + pci->irq = -1; + + if (device->type == NVKM_DEVICE_AGP) + nvkm_agp_ctor(pci); + + switch (pci->pdev->device & 0x0ff0) { + case 0x00f0: + case 0x02e0: + /* BR02? NFI how these would be handled yet exactly */ + break; + default: + switch (device->chipset) { + case 0xaa: + /* reported broken, nv also disable it */ + break; + default: + pci->msi = true; + break; + } + } + + pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi); + if (pci->msi && func->msi_rearm) { + pci->msi = pci_enable_msi(pci->pdev) == 0; + if (pci->msi) + nvkm_debug(&pci->subdev, "MSI enabled\n"); + } else { + pci->msi = false; + } + + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c new file mode 100644 index 000000000..3faa6bfb8 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g84.c @@ -0,0 +1,64 @@ +/* + * Copyright 2015 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" + +#include <core/pci.h> + +void +g84_pci_init(struct nvkm_pci *pci) +{ + /* The following only concerns PCIe cards. */ + if (!pci_is_pcie(pci->pdev)) + return; + + /* Tag field is 8-bit long, regardless of EXT_TAG. + * However, if EXT_TAG is disabled, only the lower 5 bits of the tag + * field should be used, limiting the number of request to 32. + * + * Apparently, 0x041c stores some limit on the number of requests + * possible, so if EXT_TAG is disabled, limit that requests number to + * 32 + * + * Fixes fdo#86537 + */ + if (nvkm_pci_rd32(pci, 0x007c) & 0x00000020) + nvkm_pci_mask(pci, 0x0080, 0x00000100, 0x00000100); + else + nvkm_pci_mask(pci, 0x041c, 0x00000060, 0x00000000); +} + +static const struct nvkm_pci_func +g84_pci_func = { + .init = g84_pci_init, + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv46_pci_msi_rearm, +}; + +int +g84_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&g84_pci_func, device, index, ppci); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c new file mode 100644 index 000000000..cd311ee31 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/g94.c @@ -0,0 +1,39 @@ +/* + * Copyright 2015 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_pci_func +g94_pci_func = { + .init = g84_pci_init, + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv40_pci_msi_rearm, +}; + +int +g94_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&g94_pci_func, device, index, ppci); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c new file mode 100644 index 000000000..25e1ae708 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c @@ -0,0 +1,45 @@ +/* + * Copyright 2015 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 void +gf100_pci_msi_rearm(struct nvkm_pci *pci) +{ + nvkm_pci_wr08(pci, 0x0704, 0xff); +} + +static const struct nvkm_pci_func +gf100_pci_func = { + .init = g84_pci_init, + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = gf100_pci_msi_rearm, +}; + +int +gf100_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&gf100_pci_func, device, index, ppci); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv04.c new file mode 100644 index 000000000..5b1ed42cb --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv04.c @@ -0,0 +1,58 @@ +/* + * Copyright 2015 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 u32 +nv04_pci_rd32(struct nvkm_pci *pci, u16 addr) +{ + struct nvkm_device *device = pci->subdev.device; + return nvkm_rd32(device, 0x001800 + addr); +} + +static void +nv04_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr08(device, 0x001800 + addr, data); +} + +static void +nv04_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr32(device, 0x001800 + addr, data); +} + +static const struct nvkm_pci_func +nv04_pci_func = { + .rd32 = nv04_pci_rd32, + .wr08 = nv04_pci_wr08, + .wr32 = nv04_pci_wr32, +}; + +int +nv04_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv04_pci_func, device, index, ppci); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv40.c new file mode 100644 index 000000000..6eb417765 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv40.c @@ -0,0 +1,65 @@ +/* + * Copyright 2015 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" + +u32 +nv40_pci_rd32(struct nvkm_pci *pci, u16 addr) +{ + struct nvkm_device *device = pci->subdev.device; + return nvkm_rd32(device, 0x088000 + addr); +} + +void +nv40_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr08(device, 0x088000 + addr, data); +} + +void +nv40_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr32(device, 0x088000 + addr, data); +} + +void +nv40_pci_msi_rearm(struct nvkm_pci *pci) +{ + nvkm_pci_wr08(pci, 0x0068, 0xff); +} + +static const struct nvkm_pci_func +nv40_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv40_pci_msi_rearm, +}; + +int +nv40_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv40_pci_func, device, index, ppci); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv46.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv46.c new file mode 100644 index 000000000..fc617e4c0 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv46.c @@ -0,0 +1,51 @@ +/* + * Copyright 2015 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" + +#include <core/pci.h> + +/* MSI re-arm through the PRI appears to be broken on NV46/NV50/G84/G86/G92, + * so we access it via alternate PCI config space mechanisms. + */ +void +nv46_pci_msi_rearm(struct nvkm_pci *pci) +{ + struct nvkm_device *device = pci->subdev.device; + struct pci_dev *pdev = device->func->pci(device)->pdev; + pci_write_config_byte(pdev, 0x68, 0xff); +} + +static const struct nvkm_pci_func +nv46_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv46_pci_msi_rearm, +}; + +int +nv46_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv46_pci_func, device, index, ppci); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c new file mode 100644 index 000000000..1f1b26b5f --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c @@ -0,0 +1,37 @@ +/* + * Copyright 2015 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_pci_func +nv4c_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, +}; + +int +nv4c_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv4c_pci_func, device, index, ppci); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h new file mode 100644 index 000000000..cf46d38d0 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h @@ -0,0 +1,25 @@ +#ifndef __NVKM_PCI_PRIV_H__ +#define __NVKM_PCI_PRIV_H__ +#define nvkm_pci(p) container_of((p), struct nvkm_pci, subdev) +#include <subdev/pci.h> + +int nvkm_pci_new_(const struct nvkm_pci_func *, struct nvkm_device *, + int index, struct nvkm_pci **); + +struct nvkm_pci_func { + void (*init)(struct nvkm_pci *); + u32 (*rd32)(struct nvkm_pci *, u16 addr); + void (*wr08)(struct nvkm_pci *, u16 addr, u8 data); + void (*wr32)(struct nvkm_pci *, u16 addr, u32 data); + void (*msi_rearm)(struct nvkm_pci *); +}; + +u32 nv40_pci_rd32(struct nvkm_pci *, u16); +void nv40_pci_wr08(struct nvkm_pci *, u16, u8); +void nv40_pci_wr32(struct nvkm_pci *, u16, u32); +void nv40_pci_msi_rearm(struct nvkm_pci *); + +void nv46_pci_msi_rearm(struct nvkm_pci *); + +void g84_pci_init(struct nvkm_pci *pci); +#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild index 7081d6a9b..88b643b86 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild @@ -2,8 +2,9 @@ nvkm-y += nvkm/subdev/pmu/base.o nvkm-y += nvkm/subdev/pmu/memx.o nvkm-y += nvkm/subdev/pmu/gt215.o nvkm-y += nvkm/subdev/pmu/gf100.o -nvkm-y += nvkm/subdev/pmu/gf110.o +nvkm-y += nvkm/subdev/pmu/gf119.o nvkm-y += nvkm/subdev/pmu/gk104.o nvkm-y += nvkm/subdev/pmu/gk110.o nvkm-y += nvkm/subdev/pmu/gk208.o nvkm-y += nvkm/subdev/pmu/gk20a.o +nvkm-y += nvkm/subdev/pmu/gm107.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index 054b2d2ee..d95eb8659 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -28,21 +28,25 @@ void nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { - const struct nvkm_pmu_impl *impl = (void *)nv_oclass(pmu); - if (impl->pgob) - impl->pgob(pmu, enable); + if (pmu && pmu->func->pgob) + pmu->func->pgob(pmu, enable); } -static int +int nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], u32 process, u32 message, u32 data0, u32 data1) { - struct nvkm_subdev *subdev = nv_subdev(pmu); + struct nvkm_subdev *subdev = &pmu->subdev; + struct nvkm_device *device = subdev->device; u32 addr; /* wait for a free slot in the fifo */ - addr = nv_rd32(pmu, 0x10a4a0); - if (!nv_wait_ne(pmu, 0x10a4b0, 0xffffffff, addr ^ 8)) + addr = nvkm_rd32(device, 0x10a4a0); + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x10a4b0); + if (tmp != (addr ^ 8)) + break; + ) < 0) return -EBUSY; /* we currently only support a single process at a time waiting @@ -57,20 +61,20 @@ nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], /* acquire data segment access */ do { - nv_wr32(pmu, 0x10a580, 0x00000001); - } while (nv_rd32(pmu, 0x10a580) != 0x00000001); + nvkm_wr32(device, 0x10a580, 0x00000001); + } while (nvkm_rd32(device, 0x10a580) != 0x00000001); /* write the packet */ - nv_wr32(pmu, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) + + nvkm_wr32(device, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) + pmu->send.base)); - nv_wr32(pmu, 0x10a1c4, process); - nv_wr32(pmu, 0x10a1c4, message); - nv_wr32(pmu, 0x10a1c4, data0); - nv_wr32(pmu, 0x10a1c4, data1); - nv_wr32(pmu, 0x10a4a0, (addr + 1) & 0x0f); + nvkm_wr32(device, 0x10a1c4, process); + nvkm_wr32(device, 0x10a1c4, message); + nvkm_wr32(device, 0x10a1c4, data0); + nvkm_wr32(device, 0x10a1c4, data1); + nvkm_wr32(device, 0x10a4a0, (addr + 1) & 0x0f); /* release data segment access */ - nv_wr32(pmu, 0x10a580, 0x00000000); + nvkm_wr32(device, 0x10a580, 0x00000000); /* wait for reply, if requested */ if (reply) { @@ -87,29 +91,31 @@ static void nvkm_pmu_recv(struct work_struct *work) { struct nvkm_pmu *pmu = container_of(work, struct nvkm_pmu, recv.work); + struct nvkm_subdev *subdev = &pmu->subdev; + struct nvkm_device *device = subdev->device; u32 process, message, data0, data1; /* nothing to do if GET == PUT */ - u32 addr = nv_rd32(pmu, 0x10a4cc); - if (addr == nv_rd32(pmu, 0x10a4c8)) + u32 addr = nvkm_rd32(device, 0x10a4cc); + if (addr == nvkm_rd32(device, 0x10a4c8)) return; /* acquire data segment access */ do { - nv_wr32(pmu, 0x10a580, 0x00000002); - } while (nv_rd32(pmu, 0x10a580) != 0x00000002); + nvkm_wr32(device, 0x10a580, 0x00000002); + } while (nvkm_rd32(device, 0x10a580) != 0x00000002); /* read the packet */ - nv_wr32(pmu, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) + + nvkm_wr32(device, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) + pmu->recv.base)); - process = nv_rd32(pmu, 0x10a1c4); - message = nv_rd32(pmu, 0x10a1c4); - data0 = nv_rd32(pmu, 0x10a1c4); - data1 = nv_rd32(pmu, 0x10a1c4); - nv_wr32(pmu, 0x10a4cc, (addr + 1) & 0x0f); + process = nvkm_rd32(device, 0x10a1c4); + message = nvkm_rd32(device, 0x10a1c4); + data0 = nvkm_rd32(device, 0x10a1c4); + data1 = nvkm_rd32(device, 0x10a1c4); + nvkm_wr32(device, 0x10a4cc, (addr + 1) & 0x0f); /* release data segment access */ - nv_wr32(pmu, 0x10a580, 0x00000000); + nvkm_wr32(device, 0x10a580, 0x00000000); /* wake process if it's waiting on a synchronous reply */ if (pmu->recv.process) { @@ -126,143 +132,149 @@ nvkm_pmu_recv(struct work_struct *work) /* right now there's no other expected responses from the engine, * so assume that any unexpected message is an error. */ - nv_warn(pmu, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n", - (char)((process & 0x000000ff) >> 0), - (char)((process & 0x0000ff00) >> 8), - (char)((process & 0x00ff0000) >> 16), - (char)((process & 0xff000000) >> 24), - process, message, data0, data1); + nvkm_warn(subdev, "%c%c%c%c %08x %08x %08x %08x\n", + (char)((process & 0x000000ff) >> 0), + (char)((process & 0x0000ff00) >> 8), + (char)((process & 0x00ff0000) >> 16), + (char)((process & 0xff000000) >> 24), + process, message, data0, data1); } static void nvkm_pmu_intr(struct nvkm_subdev *subdev) { - struct nvkm_pmu *pmu = (void *)subdev; - u32 disp = nv_rd32(pmu, 0x10a01c); - u32 intr = nv_rd32(pmu, 0x10a008) & disp & ~(disp >> 16); + struct nvkm_pmu *pmu = nvkm_pmu(subdev); + struct nvkm_device *device = pmu->subdev.device; + u32 disp = nvkm_rd32(device, 0x10a01c); + u32 intr = nvkm_rd32(device, 0x10a008) & disp & ~(disp >> 16); if (intr & 0x00000020) { - u32 stat = nv_rd32(pmu, 0x10a16c); + u32 stat = nvkm_rd32(device, 0x10a16c); if (stat & 0x80000000) { - nv_error(pmu, "UAS fault at 0x%06x addr 0x%08x\n", - stat & 0x00ffffff, nv_rd32(pmu, 0x10a168)); - nv_wr32(pmu, 0x10a16c, 0x00000000); + nvkm_error(subdev, "UAS fault at %06x addr %08x\n", + stat & 0x00ffffff, + nvkm_rd32(device, 0x10a168)); + nvkm_wr32(device, 0x10a16c, 0x00000000); intr &= ~0x00000020; } } if (intr & 0x00000040) { schedule_work(&pmu->recv.work); - nv_wr32(pmu, 0x10a004, 0x00000040); + nvkm_wr32(device, 0x10a004, 0x00000040); intr &= ~0x00000040; } if (intr & 0x00000080) { - nv_info(pmu, "wr32 0x%06x 0x%08x\n", nv_rd32(pmu, 0x10a7a0), - nv_rd32(pmu, 0x10a7a4)); - nv_wr32(pmu, 0x10a004, 0x00000080); + nvkm_info(subdev, "wr32 %06x %08x\n", + nvkm_rd32(device, 0x10a7a0), + nvkm_rd32(device, 0x10a7a4)); + nvkm_wr32(device, 0x10a004, 0x00000080); intr &= ~0x00000080; } if (intr) { - nv_error(pmu, "intr 0x%08x\n", intr); - nv_wr32(pmu, 0x10a004, intr); + nvkm_error(subdev, "intr %08x\n", intr); + nvkm_wr32(device, 0x10a004, intr); } } -int -_nvkm_pmu_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_pmu_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_pmu *pmu = (void *)object; + struct nvkm_pmu *pmu = nvkm_pmu(subdev); + struct nvkm_device *device = pmu->subdev.device; - nv_wr32(pmu, 0x10a014, 0x00000060); + nvkm_wr32(device, 0x10a014, 0x00000060); flush_work(&pmu->recv.work); - - return nvkm_subdev_fini(&pmu->base, suspend); + return 0; } -int -_nvkm_pmu_init(struct nvkm_object *object) +static int +nvkm_pmu_init(struct nvkm_subdev *subdev) { - const struct nvkm_pmu_impl *impl = (void *)object->oclass; - struct nvkm_pmu *pmu = (void *)object; - int ret, i; - - ret = nvkm_subdev_init(&pmu->base); - if (ret) - return ret; - - nv_subdev(pmu)->intr = nvkm_pmu_intr; - pmu->message = nvkm_pmu_send; - pmu->pgob = nvkm_pmu_pgob; + struct nvkm_pmu *pmu = nvkm_pmu(subdev); + struct nvkm_device *device = pmu->subdev.device; + int i; /* prevent previous ucode from running, wait for idle, reset */ - nv_wr32(pmu, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */ - nv_wait(pmu, 0x10a04c, 0xffffffff, 0x00000000); - nv_mask(pmu, 0x000200, 0x00002000, 0x00000000); - nv_mask(pmu, 0x000200, 0x00002000, 0x00002000); - nv_rd32(pmu, 0x000200); - nv_wait(pmu, 0x10a10c, 0x00000006, 0x00000000); + nvkm_wr32(device, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */ + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x10a04c)) + break; + ); + nvkm_mask(device, 0x000200, 0x00002000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00002000, 0x00002000); + nvkm_rd32(device, 0x000200); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x10a10c) & 0x00000006)) + break; + ); /* upload data segment */ - nv_wr32(pmu, 0x10a1c0, 0x01000000); - for (i = 0; i < impl->data.size / 4; i++) - nv_wr32(pmu, 0x10a1c4, impl->data.data[i]); + nvkm_wr32(device, 0x10a1c0, 0x01000000); + for (i = 0; i < pmu->func->data.size / 4; i++) + nvkm_wr32(device, 0x10a1c4, pmu->func->data.data[i]); /* upload code segment */ - nv_wr32(pmu, 0x10a180, 0x01000000); - for (i = 0; i < impl->code.size / 4; i++) { + nvkm_wr32(device, 0x10a180, 0x01000000); + for (i = 0; i < pmu->func->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(pmu, 0x10a188, i >> 6); - nv_wr32(pmu, 0x10a184, impl->code.data[i]); + nvkm_wr32(device, 0x10a188, i >> 6); + nvkm_wr32(device, 0x10a184, pmu->func->code.data[i]); } /* start it running */ - nv_wr32(pmu, 0x10a10c, 0x00000000); - nv_wr32(pmu, 0x10a104, 0x00000000); - nv_wr32(pmu, 0x10a100, 0x00000002); + nvkm_wr32(device, 0x10a10c, 0x00000000); + nvkm_wr32(device, 0x10a104, 0x00000000); + nvkm_wr32(device, 0x10a100, 0x00000002); /* wait for valid host->pmu ring configuration */ - if (!nv_wait_ne(pmu, 0x10a4d0, 0xffffffff, 0x00000000)) + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x10a4d0)) + break; + ) < 0) return -EBUSY; - pmu->send.base = nv_rd32(pmu, 0x10a4d0) & 0x0000ffff; - pmu->send.size = nv_rd32(pmu, 0x10a4d0) >> 16; + pmu->send.base = nvkm_rd32(device, 0x10a4d0) & 0x0000ffff; + pmu->send.size = nvkm_rd32(device, 0x10a4d0) >> 16; /* wait for valid pmu->host ring configuration */ - if (!nv_wait_ne(pmu, 0x10a4dc, 0xffffffff, 0x00000000)) + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x10a4dc)) + break; + ) < 0) return -EBUSY; - pmu->recv.base = nv_rd32(pmu, 0x10a4dc) & 0x0000ffff; - pmu->recv.size = nv_rd32(pmu, 0x10a4dc) >> 16; + pmu->recv.base = nvkm_rd32(device, 0x10a4dc) & 0x0000ffff; + pmu->recv.size = nvkm_rd32(device, 0x10a4dc) >> 16; - nv_wr32(pmu, 0x10a010, 0x000000e0); + nvkm_wr32(device, 0x10a010, 0x000000e0); return 0; } -int -nvkm_pmu_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +static void * +nvkm_pmu_dtor(struct nvkm_subdev *subdev) { - struct nvkm_pmu *pmu; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PMU", - "pmu", length, pobject); - pmu = *pobject; - if (ret) - return ret; - - INIT_WORK(&pmu->recv.work, nvkm_pmu_recv); - init_waitqueue_head(&pmu->recv.wait); - return 0; + return nvkm_pmu(subdev); } +static const struct nvkm_subdev_func +nvkm_pmu = { + .dtor = nvkm_pmu_dtor, + .init = nvkm_pmu_init, + .fini = nvkm_pmu_fini, + .intr = nvkm_pmu_intr, +}; + int -_nvkm_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_pmu_new_(const struct nvkm_pmu_func *func, struct nvkm_device *device, + int index, struct nvkm_pmu **ppmu) { struct nvkm_pmu *pmu; - int ret = nvkm_pmu_create(parent, engine, oclass, &pmu); - *pobject = nv_object(pmu); - return ret; + if (!(pmu = *ppmu = kzalloc(sizeof(*pmu), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_pmu, device, index, 0, &pmu->subdev); + pmu->func = func; + INIT_WORK(&pmu->recv.work, nvkm_pmu_recv); + init_waitqueue_head(&pmu->recv.wait); + return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4 b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4 index ae9c3f18a..2f28c7e26 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4 +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4 @@ -32,7 +32,7 @@ #include "macros.fuc" -.section #gf110_pmu_data +.section #gf119_pmu_data #define INCLUDE_PROC #include "kernel.fuc" #include "arith.fuc" @@ -56,7 +56,7 @@ #undef INCLUDE_DATA .align 256 -.section #gf110_pmu_code +.section #gf119_pmu_code #define INCLUDE_CODE #include "kernel.fuc" #include "arith.fuc" diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h index a0c499e45..31552af9b 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h @@ -1,4 +1,4 @@ -uint32_t gf110_pmu_data[] = { +uint32_t gf119_pmu_data[] = { /* 0x0000: proc_kern */ 0x52544e49, 0x00000000, @@ -915,7 +915,7 @@ uint32_t gf110_pmu_data[] = { 0x00000000, }; -uint32_t gf110_pmu_code[] = { +uint32_t gf119_pmu_code[] = { 0x034d0ef5, /* 0x0004: rd32 */ 0x07a007f1, diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c index 78a4ea010..aeb8ccd89 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c @@ -24,17 +24,16 @@ #include "priv.h" #include "fuc/gf100.fuc3.h" -struct nvkm_oclass * -gf100_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gf100_pmu = { .code.data = gf100_pmu_code, .code.size = sizeof(gf100_pmu_code), .data.data = gf100_pmu_data, .data.size = sizeof(gf100_pmu_data), -}.base; +}; + +int +gf100_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gf100_pmu, device, index, ppmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c index 6b3a23839..fbc88d8ec 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c @@ -22,19 +22,18 @@ * Authors: Ben Skeggs */ #include "priv.h" -#include "fuc/gf110.fuc4.h" +#include "fuc/gf119.fuc4.h" -struct nvkm_oclass * -gf110_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, - .code.data = gf110_pmu_code, - .code.size = sizeof(gf110_pmu_code), - .data.data = gf110_pmu_data, - .data.size = sizeof(gf110_pmu_data), -}.base; +static const struct nvkm_pmu_func +gf119_pmu = { + .code.data = gf119_pmu_code, + .code.size = sizeof(gf119_pmu_code), + .data.data = gf119_pmu_data, + .data.size = sizeof(gf119_pmu_data), +}; + +int +gf119_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gf119_pmu, device, index, ppmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 28fdb8ea9..86f9f3b13 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -21,47 +21,99 @@ * * Authors: Ben Skeggs */ -#define gf110_pmu_code gk104_pmu_code -#define gf110_pmu_data gk104_pmu_data +#define gf119_pmu_code gk104_pmu_code +#define gf119_pmu_data gk104_pmu_data #include "priv.h" -#include "fuc/gf110.fuc4.h" +#include "fuc/gf119.fuc4.h" + +#include <core/option.h> +#include <subdev/fuse.h> +#include <subdev/timer.h> + +static void +magic_(struct nvkm_device *device, u32 ctrl, int size) +{ + nvkm_wr32(device, 0x00c800, 0x00000000); + nvkm_wr32(device, 0x00c808, 0x00000000); + nvkm_wr32(device, 0x00c800, ctrl); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x00c800) & 0x40000000) { + while (size--) + nvkm_wr32(device, 0x00c804, 0x00000000); + break; + } + ); + nvkm_wr32(device, 0x00c800, 0x00000000); +} + +static void +magic(struct nvkm_device *device, u32 ctrl) +{ + magic_(device, 0x8000a41f | ctrl, 6); + magic_(device, 0x80000421 | ctrl, 1); +} static void gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { - nv_mask(pmu, 0x000200, 0x00001000, 0x00000000); - nv_rd32(pmu, 0x000200); - nv_mask(pmu, 0x000200, 0x08000000, 0x08000000); + struct nvkm_device *device = pmu->subdev.device; + + if (!(nvkm_fuse_read(device->fuse, 0x31c) & 0x00000001)) + return; + + nvkm_mask(device, 0x000200, 0x00001000, 0x00000000); + nvkm_rd32(device, 0x000200); + nvkm_mask(device, 0x000200, 0x08000000, 0x08000000); msleep(50); - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000002); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000002); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); - nv_mask(pmu, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000); + nvkm_mask(device, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000); msleep(50); - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000000); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); + + nvkm_mask(device, 0x000200, 0x08000000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00001000, 0x00001000); + nvkm_rd32(device, 0x000200); - nv_mask(pmu, 0x000200, 0x08000000, 0x00000000); - nv_mask(pmu, 0x000200, 0x00001000, 0x00001000); - nv_rd32(pmu, 0x000200); + if (nvkm_boolopt(device->cfgopt, "War00C800_0", true)) { + switch (device->chipset) { + case 0xe4: + magic(device, 0x04000000); + magic(device, 0x06000000); + magic(device, 0x0c000000); + magic(device, 0x0e000000); + break; + case 0xe6: + magic(device, 0x02000000); + magic(device, 0x04000000); + magic(device, 0x0a000000); + break; + case 0xe7: + magic(device, 0x02000000); + break; + default: + break; + } + } } -struct nvkm_oclass * -gk104_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gk104_pmu = { .code.data = gk104_pmu_code, .code.size = sizeof(gk104_pmu_code), .data.data = gk104_pmu_data, .data.size = sizeof(gk104_pmu_data), .pgob = gk104_pmu_pgob, -}.base; +}; + +int +gk104_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gk104_pmu, device, index, ppmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c index 89bb94b0a..ae255247c 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c @@ -21,16 +21,17 @@ * * Authors: Ben Skeggs */ -#define gf110_pmu_code gk110_pmu_code -#define gf110_pmu_data gk110_pmu_data +#define gf119_pmu_code gk110_pmu_code +#define gf119_pmu_data gk110_pmu_data #include "priv.h" -#include "fuc/gf110.fuc4.h" +#include "fuc/gf119.fuc4.h" #include <subdev/timer.h> void gk110_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { + struct nvkm_device *device = pmu->subdev.device; static const struct { u32 addr; u32 data; @@ -54,42 +55,44 @@ gk110_pmu_pgob(struct nvkm_pmu *pmu, bool enable) }; int i; - nv_mask(pmu, 0x000200, 0x00001000, 0x00000000); - nv_rd32(pmu, 0x000200); - nv_mask(pmu, 0x000200, 0x08000000, 0x08000000); + nvkm_mask(device, 0x000200, 0x00001000, 0x00000000); + nvkm_rd32(device, 0x000200); + nvkm_mask(device, 0x000200, 0x08000000, 0x08000000); msleep(50); - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000002); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000002); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); - nv_mask(pmu, 0x0206b4, 0x00000000, 0x00000000); + nvkm_mask(device, 0x0206b4, 0x00000000, 0x00000000); for (i = 0; i < ARRAY_SIZE(magic); i++) { - nv_wr32(pmu, magic[i].addr, magic[i].data); - nv_wait(pmu, magic[i].addr, 0x80000000, 0x00000000); + nvkm_wr32(device, magic[i].addr, magic[i].data); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, magic[i].addr) & 0x80000000)) + break; + ); } - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000000); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); - nv_mask(pmu, 0x000200, 0x08000000, 0x00000000); - nv_mask(pmu, 0x000200, 0x00001000, 0x00001000); - nv_rd32(pmu, 0x000200); + nvkm_mask(device, 0x000200, 0x08000000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00001000, 0x00001000); + nvkm_rd32(device, 0x000200); } -struct nvkm_oclass * -gk110_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xf0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gk110_pmu = { .code.data = gk110_pmu_code, .code.size = sizeof(gk110_pmu_code), .data.data = gk110_pmu_data, .data.size = sizeof(gk110_pmu_data), .pgob = gk110_pmu_pgob, -}.base; +}; + +int +gk110_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gk110_pmu, device, index, ppmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c index b14134ef9..3b4917637 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c @@ -24,18 +24,17 @@ #include "priv.h" #include "fuc/gk208.fuc5.h" -struct nvkm_oclass * -gk208_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0x00), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gk208_pmu = { .code.data = gk208_pmu_code, .code.size = sizeof(gk208_pmu_code), .data.data = gk208_pmu_data, .data.size = sizeof(gk208_pmu_data), .pgob = gk110_pmu_pgob, -}.base; +}; + +int +gk208_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gk208_pmu, device, index, ppmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 594f746e6..6689d0290 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -19,6 +19,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +#define gk20a_pmu(p) container_of((p), struct gk20a_pmu, base.subdev) #include "priv.h" #include <subdev/clk.h> @@ -35,7 +36,7 @@ struct gk20a_pmu_dvfs_data { unsigned int avg_load; }; -struct gk20a_pmu_priv { +struct gk20a_pmu { struct nvkm_pmu base; struct nvkm_alarm alarm; struct gk20a_pmu_dvfs_data *data; @@ -48,28 +49,28 @@ struct gk20a_pmu_dvfs_dev_status { }; static int -gk20a_pmu_dvfs_target(struct gk20a_pmu_priv *priv, int *state) +gk20a_pmu_dvfs_target(struct gk20a_pmu *pmu, int *state) { - struct nvkm_clk *clk = nvkm_clk(priv); + struct nvkm_clk *clk = pmu->base.subdev.device->clk; return nvkm_clk_astate(clk, *state, 0, false); } static int -gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu_priv *priv, int *state) +gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu *pmu, int *state) { - struct nvkm_clk *clk = nvkm_clk(priv); + struct nvkm_clk *clk = pmu->base.subdev.device->clk; *state = clk->pstate; return 0; } static int -gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv, +gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu *pmu, int *state, int load) { - struct gk20a_pmu_dvfs_data *data = priv->data; - struct nvkm_clk *clk = nvkm_clk(priv); + struct gk20a_pmu_dvfs_data *data = pmu->data; + struct nvkm_clk *clk = pmu->base.subdev.device->clk; int cur_level, level; /* For GK20A, the performance level is directly mapped to pstate */ @@ -84,7 +85,8 @@ gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv, level = min(clk->state_nr - 1, level); } - nv_trace(priv, "cur level = %d, new level = %d\n", cur_level, level); + nvkm_trace(&pmu->base.subdev, "cur level = %d, new level = %d\n", + cur_level, level); *state = level; @@ -95,30 +97,35 @@ gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv, } static int -gk20a_pmu_dvfs_get_dev_status(struct gk20a_pmu_priv *priv, +gk20a_pmu_dvfs_get_dev_status(struct gk20a_pmu *pmu, struct gk20a_pmu_dvfs_dev_status *status) { - status->busy = nv_rd32(priv, 0x10a508 + (BUSY_SLOT * 0x10)); - status->total= nv_rd32(priv, 0x10a508 + (CLK_SLOT * 0x10)); + struct nvkm_device *device = pmu->base.subdev.device; + status->busy = nvkm_rd32(device, 0x10a508 + (BUSY_SLOT * 0x10)); + status->total= nvkm_rd32(device, 0x10a508 + (CLK_SLOT * 0x10)); return 0; } static void -gk20a_pmu_dvfs_reset_dev_status(struct gk20a_pmu_priv *priv) +gk20a_pmu_dvfs_reset_dev_status(struct gk20a_pmu *pmu) { - nv_wr32(priv, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000); - nv_wr32(priv, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000); + struct nvkm_device *device = pmu->base.subdev.device; + nvkm_wr32(device, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000); + nvkm_wr32(device, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000); } static void gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) { - struct gk20a_pmu_priv *priv = - container_of(alarm, struct gk20a_pmu_priv, alarm); - struct gk20a_pmu_dvfs_data *data = priv->data; + struct gk20a_pmu *pmu = + container_of(alarm, struct gk20a_pmu, alarm); + struct gk20a_pmu_dvfs_data *data = pmu->data; struct gk20a_pmu_dvfs_dev_status status; - struct nvkm_clk *clk = nvkm_clk(priv); - struct nvkm_volt *volt = nvkm_volt(priv); + struct nvkm_subdev *subdev = &pmu->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_clk *clk = device->clk; + struct nvkm_timer *tmr = device->timer; + struct nvkm_volt *volt = device->volt; u32 utilization = 0; int state, ret; @@ -129,9 +136,9 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) if (!clk || !volt) goto resched; - ret = gk20a_pmu_dvfs_get_dev_status(priv, &status); + ret = gk20a_pmu_dvfs_get_dev_status(pmu, &status); if (ret) { - nv_warn(priv, "failed to get device status\n"); + nvkm_warn(subdev, "failed to get device status\n"); goto resched; } @@ -140,56 +147,52 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) data->avg_load = (data->p_smooth * data->avg_load) + utilization; data->avg_load /= data->p_smooth + 1; - nv_trace(priv, "utilization = %d %%, avg_load = %d %%\n", - utilization, data->avg_load); + nvkm_trace(subdev, "utilization = %d %%, avg_load = %d %%\n", + utilization, data->avg_load); - ret = gk20a_pmu_dvfs_get_cur_state(priv, &state); + ret = gk20a_pmu_dvfs_get_cur_state(pmu, &state); if (ret) { - nv_warn(priv, "failed to get current state\n"); + nvkm_warn(subdev, "failed to get current state\n"); goto resched; } - if (gk20a_pmu_dvfs_get_target_state(priv, &state, data->avg_load)) { - nv_trace(priv, "set new state to %d\n", state); - gk20a_pmu_dvfs_target(priv, &state); + if (gk20a_pmu_dvfs_get_target_state(pmu, &state, data->avg_load)) { + nvkm_trace(subdev, "set new state to %d\n", state); + gk20a_pmu_dvfs_target(pmu, &state); } resched: - gk20a_pmu_dvfs_reset_dev_status(priv); - nvkm_timer_alarm(priv, 100000000, alarm); + gk20a_pmu_dvfs_reset_dev_status(pmu); + nvkm_timer_alarm(tmr, 100000000, alarm); } static int -gk20a_pmu_fini(struct nvkm_object *object, bool suspend) +gk20a_pmu_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_pmu *pmu = (void *)object; - struct gk20a_pmu_priv *priv = (void *)pmu; - - nvkm_timer_alarm_cancel(priv, &priv->alarm); + struct gk20a_pmu *pmu = gk20a_pmu(subdev); + nvkm_timer_alarm_cancel(subdev->device->timer, &pmu->alarm); + return 0; +} - return nvkm_subdev_fini(&pmu->base, suspend); +static void * +gk20a_pmu_dtor(struct nvkm_subdev *subdev) +{ + return gk20a_pmu(subdev); } static int -gk20a_pmu_init(struct nvkm_object *object) +gk20a_pmu_init(struct nvkm_subdev *subdev) { - struct nvkm_pmu *pmu = (void *)object; - struct gk20a_pmu_priv *priv = (void *)pmu; - int ret; - - ret = nvkm_subdev_init(&pmu->base); - if (ret) - return ret; - - pmu->pgob = nvkm_pmu_pgob; + struct gk20a_pmu *pmu = gk20a_pmu(subdev); + struct nvkm_device *device = pmu->base.subdev.device; /* init pwr perf counter */ - nv_wr32(pmu, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001); - nv_wr32(pmu, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002); - nv_wr32(pmu, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); + nvkm_wr32(device, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001); + nvkm_wr32(device, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002); + nvkm_wr32(device, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); - nvkm_timer_alarm(pmu, 2000000000, &priv->alarm); - return ret; + nvkm_timer_alarm(device->timer, 2000000000, &pmu->alarm); + return 0; } static struct gk20a_pmu_dvfs_data @@ -199,32 +202,26 @@ gk20a_dvfs_data= { .p_smooth = 1, }; -static int -gk20a_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk20a_pmu_priv *priv; - int ret; +static const struct nvkm_subdev_func +gk20a_pmu = { + .init = gk20a_pmu_init, + .fini = gk20a_pmu_fini, + .dtor = gk20a_pmu_dtor, +}; - ret = nvkm_pmu_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +int +gk20a_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + static const struct nvkm_pmu_func func = {}; + struct gk20a_pmu *pmu; - priv->data = &gk20a_dvfs_data; + if (!(pmu = kzalloc(sizeof(*pmu), GFP_KERNEL))) + return -ENOMEM; + pmu->base.func = &func; + *ppmu = &pmu->base; - nvkm_alarm_init(&priv->alarm, gk20a_pmu_dvfs_work); + nvkm_subdev_ctor(&gk20a_pmu, device, index, 0, &pmu->base.subdev); + pmu->data = &gk20a_dvfs_data; + nvkm_alarm_init(&pmu->alarm, gk20a_pmu_dvfs_work); return 0; } - -struct nvkm_oclass * -gk20a_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = gk20a_pmu_init, - .fini = gk20a_pmu_fini, - }, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c index b7613059d..31b8692b4 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat Inc. + * 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"), @@ -21,24 +21,21 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" +#define gk208_pmu_code gm107_pmu_code +#define gk208_pmu_data gm107_pmu_data +#include "fuc/gk208.fuc5.h" -void -nv40_mc_msi_rearm(struct nvkm_mc *pmc) +static const struct nvkm_pmu_func +gm107_pmu = { + .code.data = gm107_pmu_code, + .code.size = sizeof(gm107_pmu_code), + .data.data = gm107_pmu_data, + .data.size = sizeof(gm107_pmu_data), +}; + +int +gm107_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) { - struct nv04_mc_priv *priv = (void *)pmc; - nv_wr08(priv, 0x088068, 0xff); + return nvkm_pmu_new_(&gm107_pmu, device, index, ppmu); } - -struct nvkm_oclass * -nv40_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x40), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv04_mc_init, - .fini = _nvkm_mc_fini, - }, - .intr = nv04_mc_intr, - .msi_rearm = nv40_mc_msi_rearm, -}.base; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c index 30aaeb21d..8ba7fa4ca 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c @@ -24,26 +24,25 @@ #include "priv.h" #include "fuc/gt215.fuc3.h" -static int -gt215_pmu_init(struct nvkm_object *object) +static void +gt215_pmu_reset(struct nvkm_pmu *pmu) { - struct nvkm_pmu *pmu = (void *)object; - nv_mask(pmu, 0x022210, 0x00000001, 0x00000000); - nv_mask(pmu, 0x022210, 0x00000001, 0x00000001); - return nvkm_pmu_init(pmu); + struct nvkm_device *device = pmu->subdev.device; + nvkm_mask(device, 0x022210, 0x00000001, 0x00000000); + nvkm_mask(device, 0x022210, 0x00000001, 0x00000001); } -struct nvkm_oclass * -gt215_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xa3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = gt215_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gt215_pmu = { + .reset = gt215_pmu_reset, .code.data = gt215_pmu_code, .code.size = sizeof(gt215_pmu_code), .data.data = gt215_pmu_data, .data.size = sizeof(gt215_pmu_data), -}.base; +}; + +int +gt215_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(>215_pmu, device, index, ppmu); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index b75c5b885..e6f741682 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -2,8 +2,6 @@ #define __NVKM_PMU_MEMX_H__ #include "priv.h" -#include <core/device.h> - struct nvkm_memx { struct nvkm_pmu *pmu; u32 base; @@ -18,13 +16,13 @@ struct nvkm_memx { static void memx_out(struct nvkm_memx *memx) { - struct nvkm_pmu *pmu = memx->pmu; + struct nvkm_device *device = memx->pmu->subdev.device; int i; if (memx->c.mthd) { - nv_wr32(pmu, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd); + nvkm_wr32(device, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd); for (i = 0; i < memx->c.size; i++) - nv_wr32(pmu, 0x10a1c4, memx->c.data[i]); + nvkm_wr32(device, 0x10a1c4, memx->c.data[i]); memx->c.mthd = 0; memx->c.size = 0; } @@ -44,12 +42,13 @@ memx_cmd(struct nvkm_memx *memx, u32 mthd, u32 size, u32 data[]) int nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx) { + struct nvkm_device *device = pmu->subdev.device; struct nvkm_memx *memx; u32 reply[2]; int ret; - ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, - MEMX_INFO_DATA, 0); + ret = nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, + MEMX_INFO_DATA, 0); if (ret) return ret; @@ -62,9 +61,9 @@ nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx) /* acquire data segment access */ do { - nv_wr32(pmu, 0x10a580, 0x00000003); - } while (nv_rd32(pmu, 0x10a580) != 0x00000003); - nv_wr32(pmu, 0x10a1c0, 0x01000000 | memx->base); + nvkm_wr32(device, 0x10a580, 0x00000003); + } while (nvkm_rd32(device, 0x10a580) != 0x00000003); + nvkm_wr32(device, 0x10a1c0, 0x01000000 | memx->base); return 0; } @@ -73,23 +72,25 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) { struct nvkm_memx *memx = *pmemx; struct nvkm_pmu *pmu = memx->pmu; + struct nvkm_subdev *subdev = &pmu->subdev; + struct nvkm_device *device = subdev->device; u32 finish, reply[2]; /* flush the cache... */ memx_out(memx); /* release data segment access */ - finish = nv_rd32(pmu, 0x10a1c0) & 0x00ffffff; - nv_wr32(pmu, 0x10a580, 0x00000000); + finish = nvkm_rd32(device, 0x10a1c0) & 0x00ffffff; + nvkm_wr32(device, 0x10a580, 0x00000000); /* call MEMX process to execute the script, and wait for reply */ if (exec) { - pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC, - memx->base, finish); + nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC, + memx->base, finish); } - nv_debug(memx->pmu, "Exec took %uns, PMU_IN %08x\n", - reply[0], reply[1]); + nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", + reply[0], reply[1]); kfree(memx); return 0; } @@ -97,7 +98,7 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) void nvkm_memx_wr32(struct nvkm_memx *memx, u32 addr, u32 data) { - nv_debug(memx->pmu, "R[%06x] = 0x%08x\n", addr, data); + nvkm_debug(&memx->pmu->subdev, "R[%06x] = %08x\n", addr, data); memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data }); } @@ -105,8 +106,8 @@ void nvkm_memx_wait(struct nvkm_memx *memx, u32 addr, u32 mask, u32 data, u32 nsec) { - nv_debug(memx->pmu, "R[%06x] & 0x%08x == 0x%08x, %d us\n", - addr, mask, data, nsec); + nvkm_debug(&memx->pmu->subdev, "R[%06x] & %08x == %08x, %d us\n", + addr, mask, data, nsec); memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec }); memx_out(memx); /* fuc can't handle multiple */ } @@ -114,7 +115,7 @@ nvkm_memx_wait(struct nvkm_memx *memx, void nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec) { - nv_debug(memx->pmu, " DELAY = %d ns\n", nsec); + nvkm_debug(&memx->pmu->subdev, " DELAY = %d ns\n", nsec); memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec }); memx_out(memx); /* fuc can't handle multiple */ } @@ -122,16 +123,17 @@ nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec) void nvkm_memx_wait_vblank(struct nvkm_memx *memx) { - struct nvkm_pmu *pmu = memx->pmu; + struct nvkm_subdev *subdev = &memx->pmu->subdev; + struct nvkm_device *device = subdev->device; u32 heads, x, y, px = 0; int i, head_sync; - if (nv_device(pmu)->chipset < 0xd0) { - heads = nv_rd32(pmu, 0x610050); + if (device->chipset < 0xd0) { + heads = nvkm_rd32(device, 0x610050); for (i = 0; i < 2; i++) { /* Heuristic: sync to head with biggest resolution */ if (heads & (2 << (i << 3))) { - x = nv_rd32(pmu, 0x610b40 + (0x540 * i)); + x = nvkm_rd32(device, 0x610b40 + (0x540 * i)); y = (x & 0xffff0000) >> 16; x &= 0x0000ffff; if ((x * y) > px) { @@ -143,11 +145,11 @@ nvkm_memx_wait_vblank(struct nvkm_memx *memx) } if (px == 0) { - nv_debug(memx->pmu, "WAIT VBLANK !NO ACTIVE HEAD\n"); + nvkm_debug(subdev, "WAIT VBLANK !NO ACTIVE HEAD\n"); return; } - nv_debug(memx->pmu, "WAIT VBLANK HEAD%d\n", head_sync); + nvkm_debug(subdev, "WAIT VBLANK HEAD%d\n", head_sync); memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync }); memx_out(memx); /* fuc can't handle multiple */ } @@ -155,18 +157,19 @@ nvkm_memx_wait_vblank(struct nvkm_memx *memx) void nvkm_memx_train(struct nvkm_memx *memx) { - nv_debug(memx->pmu, " MEM TRAIN\n"); + nvkm_debug(&memx->pmu->subdev, " MEM TRAIN\n"); memx_cmd(memx, MEMX_TRAIN, 0, NULL); } int nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) { + struct nvkm_device *device = pmu->subdev.device; u32 reply[2], base, size, i; int ret; - ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, - MEMX_INFO_TRAIN, 0); + ret = nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, + MEMX_INFO_TRAIN, 0); if (ret) return ret; @@ -176,10 +179,10 @@ nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) return -ENOMEM; /* read the packet */ - nv_wr32(pmu, 0x10a1c0, 0x02000000 | base); + nvkm_wr32(device, 0x10a1c0, 0x02000000 | base); for (i = 0; i < size; i++) - res[i] = nv_rd32(pmu, 0x10a1c4); + res[i] = nvkm_rd32(device, 0x10a1c4); return 0; } @@ -187,14 +190,14 @@ nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) void nvkm_memx_block(struct nvkm_memx *memx) { - nv_debug(memx->pmu, " HOST BLOCKED\n"); + nvkm_debug(&memx->pmu->subdev, " HOST BLOCKED\n"); memx_cmd(memx, MEMX_ENTER, 0, NULL); } void nvkm_memx_unblock(struct nvkm_memx *memx) { - nv_debug(memx->pmu, " HOST UNBLOCKED\n"); + nvkm_debug(&memx->pmu->subdev, " HOST UNBLOCKED\n"); memx_cmd(memx, MEMX_LEAVE, 0, NULL); } #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index 799e7c8b8..f38c88fae 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -1,38 +1,20 @@ #ifndef __NVKM_PMU_PRIV_H__ #define __NVKM_PMU_PRIV_H__ +#define nvkm_pmu(p) container_of((p), struct nvkm_pmu, subdev) #include <subdev/pmu.h> #include <subdev/pmu/fuc/os.h> -#define nvkm_pmu_create(p, e, o, d) \ - nvkm_pmu_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_pmu_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) -#define nvkm_pmu_init(p) ({ \ - struct nvkm_pmu *_pmu = (p); \ - _nvkm_pmu_init(nv_object(_pmu)); \ -}) -#define nvkm_pmu_fini(p,s) ({ \ - struct nvkm_pmu *_pmu = (p); \ - _nvkm_pmu_fini(nv_object(_pmu), (s)); \ -}) +int nvkm_pmu_new_(const struct nvkm_pmu_func *, struct nvkm_device *, + int index, struct nvkm_pmu **); -int nvkm_pmu_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); +struct nvkm_pmu_func { + void (*reset)(struct nvkm_pmu *); -int _nvkm_pmu_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_pmu_dtor _nvkm_subdev_dtor -int _nvkm_pmu_init(struct nvkm_object *); -int _nvkm_pmu_fini(struct nvkm_object *, bool); -void nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable); - -struct nvkm_pmu_impl { - struct nvkm_oclass base; struct { u32 *data; u32 size; } code; + struct { u32 *data; u32 size; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild index 5837cf129..135758ba3 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild @@ -9,5 +9,5 @@ nvkm-y += nvkm/subdev/therm/nv40.o nvkm-y += nvkm/subdev/therm/nv50.o nvkm-y += nvkm/subdev/therm/g84.o nvkm-y += nvkm/subdev/therm/gt215.o -nvkm-y += nvkm/subdev/therm/gf110.o +nvkm-y += nvkm/subdev/therm/gf119.o nvkm-y += nvkm/subdev/therm/gm107.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index ec327cb64..949dc6101 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -23,21 +23,26 @@ */ #include "priv.h" -#include <core/device.h> +int +nvkm_therm_temp_get(struct nvkm_therm *therm) +{ + if (therm->func->temp_get) + return therm->func->temp_get(therm); + return -ENODEV; +} static int nvkm_therm_update_trip(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_trip_point *trip = priv->fan->bios.trip, + struct nvbios_therm_trip_point *trip = therm->fan->bios.trip, *cur_trip = NULL, - *last_trip = priv->last_trip; - u8 temp = therm->temp_get(therm); + *last_trip = therm->last_trip; + u8 temp = therm->func->temp_get(therm); u16 duty, i; /* look for the trip point corresponding to the current temperature */ cur_trip = NULL; - for (i = 0; i < priv->fan->bios.nr_fan_trip; i++) { + for (i = 0; i < therm->fan->bios.nr_fan_trip; i++) { if (temp >= trip[i].temp) cur_trip = &trip[i]; } @@ -49,10 +54,10 @@ nvkm_therm_update_trip(struct nvkm_therm *therm) if (cur_trip) { duty = cur_trip->fan_duty; - priv->last_trip = cur_trip; + therm->last_trip = cur_trip; } else { duty = 0; - priv->last_trip = NULL; + therm->last_trip = NULL; } return duty; @@ -61,51 +66,50 @@ nvkm_therm_update_trip(struct nvkm_therm *therm) static int nvkm_therm_update_linear(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - u8 linear_min_temp = priv->fan->bios.linear_min_temp; - u8 linear_max_temp = priv->fan->bios.linear_max_temp; - u8 temp = therm->temp_get(therm); + u8 linear_min_temp = therm->fan->bios.linear_min_temp; + u8 linear_max_temp = therm->fan->bios.linear_max_temp; + u8 temp = therm->func->temp_get(therm); u16 duty; /* handle the non-linear part first */ if (temp < linear_min_temp) - return priv->fan->bios.min_duty; + return therm->fan->bios.min_duty; else if (temp > linear_max_temp) - return priv->fan->bios.max_duty; + return therm->fan->bios.max_duty; /* we are in the linear zone */ duty = (temp - linear_min_temp); - duty *= (priv->fan->bios.max_duty - priv->fan->bios.min_duty); + duty *= (therm->fan->bios.max_duty - therm->fan->bios.min_duty); duty /= (linear_max_temp - linear_min_temp); - duty += priv->fan->bios.min_duty; + duty += therm->fan->bios.min_duty; return duty; } static void nvkm_therm_update(struct nvkm_therm *therm, int mode) { - struct nvkm_timer *ptimer = nvkm_timer(therm); - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_timer *tmr = subdev->device->timer; unsigned long flags; bool immd = true; bool poll = true; int duty = -1; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&therm->lock, flags); if (mode < 0) - mode = priv->mode; - priv->mode = mode; + mode = therm->mode; + therm->mode = mode; switch (mode) { case NVKM_THERM_CTRL_MANUAL: - ptimer->alarm_cancel(ptimer, &priv->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->alarm); duty = nvkm_therm_fan_get(therm); if (duty < 0) duty = 100; poll = false; break; case NVKM_THERM_CTRL_AUTO: - switch(priv->fan->bios.fan_mode) { + switch(therm->fan->bios.fan_mode) { case NVBIOS_THERM_FAN_TRIP: duty = nvkm_therm_update_trip(therm); break; @@ -113,8 +117,8 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) duty = nvkm_therm_update_linear(therm); break; case NVBIOS_THERM_FAN_OTHER: - if (priv->cstate) - duty = priv->cstate; + if (therm->cstate) + duty = therm->cstate; poll = false; break; } @@ -122,29 +126,29 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) break; case NVKM_THERM_CTRL_NONE: default: - ptimer->alarm_cancel(ptimer, &priv->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->alarm); poll = false; } - if (list_empty(&priv->alarm.head) && poll) - ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); - spin_unlock_irqrestore(&priv->lock, flags); + if (list_empty(&therm->alarm.head) && poll) + nvkm_timer_alarm(tmr, 1000000000ULL, &therm->alarm); + spin_unlock_irqrestore(&therm->lock, flags); if (duty >= 0) { - nv_debug(therm, "FAN target request: %d%%\n", duty); + nvkm_debug(subdev, "FAN target request: %d%%\n", duty); nvkm_therm_fan_set(therm, immd, duty); } } int -nvkm_therm_cstate(struct nvkm_therm *ptherm, int fan, int dir) +nvkm_therm_cstate(struct nvkm_therm *therm, int fan, int dir) { - struct nvkm_therm_priv *priv = (void *)ptherm; - if (!dir || (dir < 0 && fan < priv->cstate) || - (dir > 0 && fan > priv->cstate)) { - nv_debug(ptherm, "default fan speed -> %d%%\n", fan); - priv->cstate = fan; - nvkm_therm_update(ptherm, -1); + struct nvkm_subdev *subdev = &therm->subdev; + if (!dir || (dir < 0 && fan < therm->cstate) || + (dir > 0 && fan > therm->cstate)) { + nvkm_debug(subdev, "default fan speed -> %d%%\n", fan); + therm->cstate = fan; + nvkm_therm_update(therm, -1); } return 0; } @@ -152,16 +156,16 @@ nvkm_therm_cstate(struct nvkm_therm *ptherm, int fan, int dir) static void nvkm_therm_alarm(struct nvkm_alarm *alarm) { - struct nvkm_therm_priv *priv = - container_of(alarm, struct nvkm_therm_priv, alarm); - nvkm_therm_update(&priv->base, -1); + struct nvkm_therm *therm = + container_of(alarm, struct nvkm_therm, alarm); + nvkm_therm_update(therm, -1); } int nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_device *device = nv_device(therm); + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; static const char *name[] = { "disabled", "manual", @@ -171,51 +175,49 @@ nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode) /* The default PPWR ucode on fermi interferes with fan management */ if ((mode >= ARRAY_SIZE(name)) || (mode != NVKM_THERM_CTRL_NONE && device->card_type >= NV_C0 && - !nvkm_subdev(device, NVDEV_SUBDEV_PMU))) + !device->pmu)) return -EINVAL; /* do not allow automatic fan management if the thermal sensor is * not available */ - if (mode == NVKM_THERM_CTRL_AUTO && therm->temp_get(therm) < 0) + if (mode == NVKM_THERM_CTRL_AUTO && + therm->func->temp_get(therm) < 0) return -EINVAL; - if (priv->mode == mode) + if (therm->mode == mode) return 0; - nv_info(therm, "fan management: %s\n", name[mode]); + nvkm_debug(subdev, "fan management: %s\n", name[mode]); nvkm_therm_update(therm, mode); return 0; } int -nvkm_therm_attr_get(struct nvkm_therm *therm, - enum nvkm_therm_attr_type type) +nvkm_therm_attr_get(struct nvkm_therm *therm, enum nvkm_therm_attr_type type) { - struct nvkm_therm_priv *priv = (void *)therm; - switch (type) { case NVKM_THERM_ATTR_FAN_MIN_DUTY: - return priv->fan->bios.min_duty; + return therm->fan->bios.min_duty; case NVKM_THERM_ATTR_FAN_MAX_DUTY: - return priv->fan->bios.max_duty; + return therm->fan->bios.max_duty; case NVKM_THERM_ATTR_FAN_MODE: - return priv->mode; + return therm->mode; case NVKM_THERM_ATTR_THRS_FAN_BOOST: - return priv->bios_sensor.thrs_fan_boost.temp; + return therm->bios_sensor.thrs_fan_boost.temp; case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST: - return priv->bios_sensor.thrs_fan_boost.hysteresis; + return therm->bios_sensor.thrs_fan_boost.hysteresis; case NVKM_THERM_ATTR_THRS_DOWN_CLK: - return priv->bios_sensor.thrs_down_clock.temp; + return therm->bios_sensor.thrs_down_clock.temp; case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST: - return priv->bios_sensor.thrs_down_clock.hysteresis; + return therm->bios_sensor.thrs_down_clock.hysteresis; case NVKM_THERM_ATTR_THRS_CRITICAL: - return priv->bios_sensor.thrs_critical.temp; + return therm->bios_sensor.thrs_critical.temp; case NVKM_THERM_ATTR_THRS_CRITICAL_HYST: - return priv->bios_sensor.thrs_critical.hysteresis; + return therm->bios_sensor.thrs_critical.hysteresis; case NVKM_THERM_ATTR_THRS_SHUTDOWN: - return priv->bios_sensor.thrs_shutdown.temp; + return therm->bios_sensor.thrs_shutdown.temp; case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST: - return priv->bios_sensor.thrs_shutdown.hysteresis; + return therm->bios_sensor.thrs_shutdown.hysteresis; } return -EINVAL; @@ -225,143 +227,156 @@ int nvkm_therm_attr_set(struct nvkm_therm *therm, enum nvkm_therm_attr_type type, int value) { - struct nvkm_therm_priv *priv = (void *)therm; - switch (type) { case NVKM_THERM_ATTR_FAN_MIN_DUTY: if (value < 0) value = 0; - if (value > priv->fan->bios.max_duty) - value = priv->fan->bios.max_duty; - priv->fan->bios.min_duty = value; + if (value > therm->fan->bios.max_duty) + value = therm->fan->bios.max_duty; + therm->fan->bios.min_duty = value; return 0; case NVKM_THERM_ATTR_FAN_MAX_DUTY: if (value < 0) value = 0; - if (value < priv->fan->bios.min_duty) - value = priv->fan->bios.min_duty; - priv->fan->bios.max_duty = value; + if (value < therm->fan->bios.min_duty) + value = therm->fan->bios.min_duty; + therm->fan->bios.max_duty = value; return 0; case NVKM_THERM_ATTR_FAN_MODE: return nvkm_therm_fan_mode(therm, value); case NVKM_THERM_ATTR_THRS_FAN_BOOST: - priv->bios_sensor.thrs_fan_boost.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_fan_boost.temp = value; + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST: - priv->bios_sensor.thrs_fan_boost.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_fan_boost.hysteresis = value; + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_DOWN_CLK: - priv->bios_sensor.thrs_down_clock.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_down_clock.temp = value; + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST: - priv->bios_sensor.thrs_down_clock.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_down_clock.hysteresis = value; + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_CRITICAL: - priv->bios_sensor.thrs_critical.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_critical.temp = value; + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_CRITICAL_HYST: - priv->bios_sensor.thrs_critical.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_critical.hysteresis = value; + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_SHUTDOWN: - priv->bios_sensor.thrs_shutdown.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_shutdown.temp = value; + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST: - priv->bios_sensor.thrs_shutdown.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_shutdown.hysteresis = value; + therm->func->program_alarms(therm); return 0; } return -EINVAL; } -int -_nvkm_therm_init(struct nvkm_object *object) +static void +nvkm_therm_intr(struct nvkm_subdev *subdev) { - struct nvkm_therm *therm = (void *)object; - struct nvkm_therm_priv *priv = (void *)therm; - int ret; - - ret = nvkm_subdev_init(&therm->base); - if (ret) - return ret; - - if (priv->suspend >= 0) { - /* restore the pwm value only when on manual or auto mode */ - if (priv->suspend > 0) - nvkm_therm_fan_set(therm, true, priv->fan->percent); - - nvkm_therm_fan_mode(therm, priv->suspend); - } - nvkm_therm_sensor_init(therm); - nvkm_therm_fan_init(therm); - return 0; + struct nvkm_therm *therm = nvkm_therm(subdev); + if (therm->func->intr) + therm->func->intr(therm); } -int -_nvkm_therm_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_therm_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_therm *therm = (void *)object; - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm *therm = nvkm_therm(subdev); + + if (therm->func->fini) + therm->func->fini(therm); nvkm_therm_fan_fini(therm, suspend); nvkm_therm_sensor_fini(therm, suspend); + if (suspend) { - priv->suspend = priv->mode; - priv->mode = NVKM_THERM_CTRL_NONE; + therm->suspend = therm->mode; + therm->mode = NVKM_THERM_CTRL_NONE; } - return nvkm_subdev_fini(&therm->base, suspend); -} - -int -nvkm_therm_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) -{ - struct nvkm_therm_priv *priv; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PTHERM", - "therm", length, pobject); - priv = *pobject; - if (ret) - return ret; - - nvkm_alarm_init(&priv->alarm, nvkm_therm_alarm); - spin_lock_init(&priv->lock); - spin_lock_init(&priv->sensor.alarm_program_lock); - - priv->base.fan_get = nvkm_therm_fan_user_get; - priv->base.fan_set = nvkm_therm_fan_user_set; - priv->base.fan_sense = nvkm_therm_fan_sense; - priv->base.attr_get = nvkm_therm_attr_get; - priv->base.attr_set = nvkm_therm_attr_set; - priv->mode = priv->suspend = -1; /* undefined */ return 0; } -int -nvkm_therm_preinit(struct nvkm_therm *therm) +static int +nvkm_therm_oneinit(struct nvkm_subdev *subdev) { + struct nvkm_therm *therm = nvkm_therm(subdev); nvkm_therm_sensor_ctor(therm); nvkm_therm_ic_ctor(therm); nvkm_therm_fan_ctor(therm); - nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO); nvkm_therm_sensor_preinit(therm); return 0; } -void -_nvkm_therm_dtor(struct nvkm_object *object) +static int +nvkm_therm_init(struct nvkm_subdev *subdev) +{ + struct nvkm_therm *therm = nvkm_therm(subdev); + + therm->func->init(therm); + + if (therm->suspend >= 0) { + /* restore the pwm value only when on manual or auto mode */ + if (therm->suspend > 0) + nvkm_therm_fan_set(therm, true, therm->fan->percent); + + nvkm_therm_fan_mode(therm, therm->suspend); + } + + nvkm_therm_sensor_init(therm); + nvkm_therm_fan_init(therm); + return 0; +} + +static void * +nvkm_therm_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_therm *therm = nvkm_therm(subdev); + kfree(therm->fan); + return therm; +} + +static const struct nvkm_subdev_func +nvkm_therm = { + .dtor = nvkm_therm_dtor, + .oneinit = nvkm_therm_oneinit, + .init = nvkm_therm_init, + .fini = nvkm_therm_fini, + .intr = nvkm_therm_intr, +}; + +int +nvkm_therm_new_(const struct nvkm_therm_func *func, struct nvkm_device *device, + int index, struct nvkm_therm **ptherm) { - struct nvkm_therm_priv *priv = (void *)object; - kfree(priv->fan); - nvkm_subdev_destroy(&priv->base.base); + struct nvkm_therm *therm; + + if (!(therm = *ptherm = kzalloc(sizeof(*therm), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_therm, device, index, 0, &therm->subdev); + therm->func = func; + + nvkm_alarm_init(&therm->alarm, nvkm_therm_alarm); + spin_lock_init(&therm->lock); + spin_lock_init(&therm->sensor.alarm_program_lock); + + therm->fan_get = nvkm_therm_fan_user_get; + therm->fan_set = nvkm_therm_fan_user_set; + therm->attr_get = nvkm_therm_attr_get; + therm->attr_set = nvkm_therm_attr_set; + therm->mode = therm->suspend = -1; /* undefined */ + return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index 434fa745c..91198d793 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -32,8 +32,8 @@ static int nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) { struct nvkm_therm *therm = fan->parent; - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_timer *ptimer = nvkm_timer(priv); + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_timer *tmr = subdev->device->timer; unsigned long flags; int ret = 0; int duty; @@ -45,7 +45,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) target = max_t(u8, target, fan->bios.min_duty); target = min_t(u8, target, fan->bios.max_duty); if (fan->percent != target) { - nv_debug(therm, "FAN target: %d\n", target); + nvkm_debug(subdev, "FAN target: %d\n", target); fan->percent = target; } @@ -70,7 +70,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) duty = target; } - nv_debug(therm, "FAN update: %d\n", duty); + nvkm_debug(subdev, "FAN update: %d\n", duty); ret = fan->set(therm, duty); if (ret) { spin_unlock_irqrestore(&fan->lock, flags); @@ -95,7 +95,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) else delay = bump_period; - ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm); + nvkm_timer_alarm(tmr, delay * 1000 * 1000, &fan->alarm); } return ret; @@ -111,48 +111,51 @@ nvkm_fan_alarm(struct nvkm_alarm *alarm) int nvkm_therm_fan_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - return priv->fan->get(therm); + return therm->fan->get(therm); } int nvkm_therm_fan_set(struct nvkm_therm *therm, bool immediate, int percent) { - struct nvkm_therm_priv *priv = (void *)therm; - return nvkm_fan_update(priv->fan, immediate, percent); + return nvkm_fan_update(therm->fan, immediate, percent); } int nvkm_therm_fan_sense(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_timer *ptimer = nvkm_timer(therm); - struct nvkm_gpio *gpio = nvkm_gpio(therm); + struct nvkm_device *device = therm->subdev.device; + struct nvkm_timer *tmr = device->timer; + struct nvkm_gpio *gpio = device->gpio; u32 cycles, cur, prev; u64 start, end, tach; - if (priv->fan->tach.func == DCB_GPIO_UNUSED) + if (therm->func->fan_sense) + return therm->func->fan_sense(therm); + + if (therm->fan->tach.func == DCB_GPIO_UNUSED) return -ENODEV; /* Time a complete rotation and extrapolate to RPM: * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ - start = ptimer->read(ptimer); - prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); + start = nvkm_timer_read(tmr); + prev = nvkm_gpio_get(gpio, 0, therm->fan->tach.func, + therm->fan->tach.line); cycles = 0; do { usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ - cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); + cur = nvkm_gpio_get(gpio, 0, therm->fan->tach.func, + therm->fan->tach.line); if (prev != cur) { if (!start) - start = ptimer->read(ptimer); + start = nvkm_timer_read(tmr); cycles++; prev = cur; } - } while (cycles < 5 && ptimer->read(ptimer) - start < 250000000); - end = ptimer->read(ptimer); + } while (cycles < 5 && nvkm_timer_read(tmr) - start < 250000000); + end = nvkm_timer_read(tmr); if (cycles == 5) { tach = (u64)60000000000ULL; @@ -171,9 +174,7 @@ nvkm_therm_fan_user_get(struct nvkm_therm *therm) int nvkm_therm_fan_user_set(struct nvkm_therm *therm, int percent) { - struct nvkm_therm_priv *priv = (void *)therm; - - if (priv->mode != NVKM_THERM_CTRL_MANUAL) + if (therm->mode != NVKM_THERM_CTRL_MANUAL) return -EINVAL; return nvkm_therm_fan_set(therm, true, percent); @@ -182,29 +183,25 @@ nvkm_therm_fan_user_set(struct nvkm_therm *therm, int percent) static void nvkm_therm_fan_set_defaults(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - - priv->fan->bios.pwm_freq = 0; - priv->fan->bios.min_duty = 0; - priv->fan->bios.max_duty = 100; - priv->fan->bios.bump_period = 500; - priv->fan->bios.slow_down_period = 2000; - priv->fan->bios.linear_min_temp = 40; - priv->fan->bios.linear_max_temp = 85; + therm->fan->bios.pwm_freq = 0; + therm->fan->bios.min_duty = 0; + therm->fan->bios.max_duty = 100; + therm->fan->bios.bump_period = 500; + therm->fan->bios.slow_down_period = 2000; + therm->fan->bios.linear_min_temp = 40; + therm->fan->bios.linear_max_temp = 85; } static void nvkm_therm_fan_safety_checks(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; + if (therm->fan->bios.min_duty > 100) + therm->fan->bios.min_duty = 100; + if (therm->fan->bios.max_duty > 100) + therm->fan->bios.max_duty = 100; - if (priv->fan->bios.min_duty > 100) - priv->fan->bios.min_duty = 100; - if (priv->fan->bios.max_duty > 100) - priv->fan->bios.max_duty = 100; - - if (priv->fan->bios.min_duty > priv->fan->bios.max_duty) - priv->fan->bios.min_duty = priv->fan->bios.max_duty; + if (therm->fan->bios.min_duty > therm->fan->bios.max_duty) + therm->fan->bios.min_duty = therm->fan->bios.max_duty; } int @@ -216,29 +213,28 @@ nvkm_therm_fan_init(struct nvkm_therm *therm) int nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_timer *ptimer = nvkm_timer(therm); - + struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - ptimer->alarm_cancel(ptimer, &priv->fan->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->fan->alarm); return 0; } int nvkm_therm_fan_ctor(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_gpio *gpio = nvkm_gpio(therm); - struct nvkm_bios *bios = nvkm_bios(therm); + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_gpio *gpio = device->gpio; + struct nvkm_bios *bios = device->bios; struct dcb_gpio_func func; int ret; /* attempt to locate a drivable fan, and determine control method */ - ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); + ret = nvkm_gpio_find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); if (ret == 0) { /* FIXME: is this really the place to perform such checks ? */ if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) { - nv_debug(therm, "GPIO_FAN is in input mode\n"); + nvkm_debug(subdev, "GPIO_FAN is in input mode\n"); ret = -EINVAL; } else { ret = nvkm_fanpwm_create(therm, &func); @@ -254,28 +250,29 @@ nvkm_therm_fan_ctor(struct nvkm_therm *therm) return ret; } - nv_info(therm, "FAN control: %s\n", priv->fan->type); + nvkm_debug(subdev, "FAN control: %s\n", therm->fan->type); /* read the current speed, it is useful when resuming */ - priv->fan->percent = nvkm_therm_fan_get(therm); + therm->fan->percent = nvkm_therm_fan_get(therm); /* attempt to detect a tachometer connection */ - ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach); + ret = nvkm_gpio_find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, + &therm->fan->tach); if (ret) - priv->fan->tach.func = DCB_GPIO_UNUSED; + therm->fan->tach.func = DCB_GPIO_UNUSED; /* initialise fan bump/slow update handling */ - priv->fan->parent = therm; - nvkm_alarm_init(&priv->fan->alarm, nvkm_fan_alarm); - spin_lock_init(&priv->fan->lock); + therm->fan->parent = therm; + nvkm_alarm_init(&therm->fan->alarm, nvkm_fan_alarm); + spin_lock_init(&therm->fan->lock); /* other random init... */ nvkm_therm_fan_set_defaults(therm); - nvbios_perf_fan_parse(bios, &priv->fan->perf); - if (!nvbios_fan_parse(bios, &priv->fan->bios)) { - nv_debug(therm, "parsing the fan table failed\n"); - if (nvbios_therm_fan_parse(bios, &priv->fan->bios)) - nv_error(therm, "parsing both fan tables failed\n"); + nvbios_perf_fan_parse(bios, &therm->fan->perf); + if (!nvbios_fan_parse(bios, &therm->fan->bios)) { + nvkm_debug(subdev, "parsing the fan table failed\n"); + if (nvbios_therm_fan_parse(bios, &therm->fan->bios)) + nvkm_error(subdev, "parsing both fan tables failed\n"); } nvkm_therm_fan_safety_checks(therm); return 0; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c index 534e5970e..8ae300f91 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c @@ -38,11 +38,10 @@ nvkm_fannil_set(struct nvkm_therm *therm, int percent) int nvkm_fannil_create(struct nvkm_therm *therm) { - struct nvkm_therm_priv *tpriv = (void *)therm; struct nvkm_fan *priv; priv = kzalloc(sizeof(*priv), GFP_KERNEL); - tpriv->fan = priv; + therm->fan = priv; if (!priv) return -ENOMEM; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c index bde5ceaeb..340f37a29 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c @@ -24,13 +24,12 @@ */ #include "priv.h" -#include <core/device.h> #include <core/option.h> #include <subdev/bios.h> #include <subdev/bios/fan.h> #include <subdev/gpio.h> -struct nvkm_fanpwm_priv { +struct nvkm_fanpwm { struct nvkm_fan base; struct dcb_gpio_func func; }; @@ -38,76 +37,74 @@ struct nvkm_fanpwm_priv { static int nvkm_fanpwm_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan; - struct nvkm_gpio *gpio = nvkm_gpio(therm); - int card_type = nv_device(therm)->card_type; + struct nvkm_fanpwm *fan = (void *)therm->fan; + struct nvkm_device *device = therm->subdev.device; + struct nvkm_gpio *gpio = device->gpio; + int card_type = device->card_type; u32 divs, duty; int ret; - ret = therm->pwm_get(therm, priv->func.line, &divs, &duty); + ret = therm->func->pwm_get(therm, fan->func.line, &divs, &duty); if (ret == 0 && divs) { divs = max(divs, duty); - if (card_type <= NV_40 || (priv->func.log[0] & 1)) + if (card_type <= NV_40 || (fan->func.log[0] & 1)) duty = divs - duty; return (duty * 100) / divs; } - return gpio->get(gpio, 0, priv->func.func, priv->func.line) * 100; + return nvkm_gpio_get(gpio, 0, fan->func.func, fan->func.line) * 100; } static int nvkm_fanpwm_set(struct nvkm_therm *therm, int percent) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan; - int card_type = nv_device(therm)->card_type; + struct nvkm_fanpwm *fan = (void *)therm->fan; + int card_type = therm->subdev.device->card_type; u32 divs, duty; int ret; - divs = priv->base.perf.pwm_divisor; - if (priv->base.bios.pwm_freq) { + divs = fan->base.perf.pwm_divisor; + if (fan->base.bios.pwm_freq) { divs = 1; - if (therm->pwm_clock) - divs = therm->pwm_clock(therm, priv->func.line); - divs /= priv->base.bios.pwm_freq; + if (therm->func->pwm_clock) + divs = therm->func->pwm_clock(therm, fan->func.line); + divs /= fan->base.bios.pwm_freq; } duty = ((divs * percent) + 99) / 100; - if (card_type <= NV_40 || (priv->func.log[0] & 1)) + if (card_type <= NV_40 || (fan->func.log[0] & 1)) duty = divs - duty; - ret = therm->pwm_set(therm, priv->func.line, divs, duty); + ret = therm->func->pwm_set(therm, fan->func.line, divs, duty); if (ret == 0) - ret = therm->pwm_ctrl(therm, priv->func.line, true); + ret = therm->func->pwm_ctrl(therm, fan->func.line, true); return ret; } int nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) { - struct nvkm_device *device = nv_device(therm); - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_bios *bios = nvkm_bios(therm); - struct nvkm_fanpwm_priv *priv; - struct nvbios_therm_fan fan; + struct nvkm_device *device = therm->subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_fanpwm *fan; + struct nvbios_therm_fan info = {}; u32 divs, duty; - nvbios_fan_parse(bios, &fan); + nvbios_fan_parse(bios, &info); if (!nvkm_boolopt(device->cfgopt, "NvFanPWM", func->param) || - !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE || - therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV) + !therm->func->pwm_ctrl || info.type == NVBIOS_THERM_FAN_TOGGLE || + therm->func->pwm_get(therm, func->line, &divs, &duty) == -ENODEV) return -ENODEV; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - tpriv->fan = &priv->base; - if (!priv) + fan = kzalloc(sizeof(*fan), GFP_KERNEL); + therm->fan = &fan->base; + if (!fan) return -ENOMEM; - priv->base.type = "PWM"; - priv->base.get = nvkm_fanpwm_get; - priv->base.set = nvkm_fanpwm_set; - priv->func = *func; + fan->base.type = "PWM"; + fan->base.get = nvkm_fanpwm_get; + fan->base.set = nvkm_fanpwm_set; + fan->func = *func; return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index 4ce041e81..59701b7a6 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -26,7 +26,7 @@ #include <subdev/gpio.h> #include <subdev/timer.h> -struct nvkm_fantog_priv { +struct nvkm_fantog { struct nvkm_fan base; struct nvkm_alarm alarm; spinlock_t lock; @@ -36,83 +36,81 @@ struct nvkm_fantog_priv { }; static void -nvkm_fantog_update(struct nvkm_fantog_priv *priv, int percent) +nvkm_fantog_update(struct nvkm_fantog *fan, int percent) { - struct nvkm_therm_priv *tpriv = (void *)priv->base.parent; - struct nvkm_timer *ptimer = nvkm_timer(tpriv); - struct nvkm_gpio *gpio = nvkm_gpio(tpriv); + struct nvkm_therm *therm = fan->base.parent; + struct nvkm_device *device = therm->subdev.device; + struct nvkm_timer *tmr = device->timer; + struct nvkm_gpio *gpio = device->gpio; unsigned long flags; int duty; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&fan->lock, flags); if (percent < 0) - percent = priv->percent; - priv->percent = percent; + percent = fan->percent; + fan->percent = percent; - duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff); - gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty); + duty = !nvkm_gpio_get(gpio, 0, DCB_GPIO_FAN, 0xff); + nvkm_gpio_set(gpio, 0, DCB_GPIO_FAN, 0xff, duty); - if (list_empty(&priv->alarm.head) && percent != (duty * 100)) { - u64 next_change = (percent * priv->period_us) / 100; + if (list_empty(&fan->alarm.head) && percent != (duty * 100)) { + u64 next_change = (percent * fan->period_us) / 100; if (!duty) - next_change = priv->period_us - next_change; - ptimer->alarm(ptimer, next_change * 1000, &priv->alarm); + next_change = fan->period_us - next_change; + nvkm_timer_alarm(tmr, next_change * 1000, &fan->alarm); } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&fan->lock, flags); } static void nvkm_fantog_alarm(struct nvkm_alarm *alarm) { - struct nvkm_fantog_priv *priv = - container_of(alarm, struct nvkm_fantog_priv, alarm); - nvkm_fantog_update(priv, -1); + struct nvkm_fantog *fan = + container_of(alarm, struct nvkm_fantog, alarm); + nvkm_fantog_update(fan, -1); } static int nvkm_fantog_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fantog_priv *priv = (void *)tpriv->fan; - return priv->percent; + struct nvkm_fantog *fan = (void *)therm->fan; + return fan->percent; } static int nvkm_fantog_set(struct nvkm_therm *therm, int percent) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fantog_priv *priv = (void *)tpriv->fan; - if (therm->pwm_ctrl) - therm->pwm_ctrl(therm, priv->func.line, false); - nvkm_fantog_update(priv, percent); + struct nvkm_fantog *fan = (void *)therm->fan; + if (therm->func->pwm_ctrl) + therm->func->pwm_ctrl(therm, fan->func.line, false); + nvkm_fantog_update(fan, percent); return 0; } int nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fantog_priv *priv; + struct nvkm_fantog *fan; int ret; - if (therm->pwm_ctrl) { - ret = therm->pwm_ctrl(therm, func->line, false); + if (therm->func->pwm_ctrl) { + ret = therm->func->pwm_ctrl(therm, func->line, false); if (ret) return ret; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - tpriv->fan = &priv->base; - if (!priv) + fan = kzalloc(sizeof(*fan), GFP_KERNEL); + therm->fan = &fan->base; + if (!fan) return -ENOMEM; - priv->base.type = "toggle"; - priv->base.get = nvkm_fantog_get; - priv->base.set = nvkm_fantog_set; - nvkm_alarm_init(&priv->alarm, nvkm_fantog_alarm); - priv->period_us = 100000; /* 10Hz */ - priv->percent = 100; - priv->func = *func; - spin_lock_init(&priv->lock); + fan->base.type = "toggle"; + fan->base.get = nvkm_fantog_get; + fan->base.set = nvkm_fantog_set; + nvkm_alarm_init(&fan->alarm, nvkm_fantog_alarm); + fan->period_us = 100000; /* 10Hz */ + fan->percent = 100; + fan->func = *func; + spin_lock_init(&fan->lock); return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index 85b5d0c18..86e81930d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -26,17 +26,13 @@ #include <subdev/fuse.h> -struct g84_therm_priv { - struct nvkm_therm_priv base; -}; - int g84_temp_get(struct nvkm_therm *therm) { - struct nvkm_fuse *fuse = nvkm_fuse(therm); + struct nvkm_device *device = therm->subdev.device; - if (nv_ro32(fuse, 0x1a8) == 1) - return nv_rd32(therm, 0x20400); + if (nvkm_fuse_read(device->fuse, 0x1a8) == 1) + return nvkm_rd32(device, 0x20400); else return -ENODEV; } @@ -44,12 +40,12 @@ g84_temp_get(struct nvkm_therm *therm) void g84_sensor_setup(struct nvkm_therm *therm) { - struct nvkm_fuse *fuse = nvkm_fuse(therm); + struct nvkm_device *device = therm->subdev.device; /* enable temperature reading for cards with insane defaults */ - if (nv_ro32(fuse, 0x1a8) == 1) { - nv_mask(therm, 0x20008, 0x80008000, 0x80000000); - nv_mask(therm, 0x2000c, 0x80000003, 0x00000000); + if (nvkm_fuse_read(device->fuse, 0x1a8) == 1) { + nvkm_mask(device, 0x20008, 0x80008000, 0x80000000); + nvkm_mask(device, 0x2000c, 0x80000003, 0x00000000); mdelay(20); /* wait for the temperature to stabilize */ } } @@ -57,36 +53,40 @@ g84_sensor_setup(struct nvkm_therm *therm) static void g84_therm_program_alarms(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; unsigned long flags; - spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); + spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); /* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */ - nv_wr32(therm, 0x20000, 0x000003ff); + nvkm_wr32(device, 0x20000, 0x000003ff); /* shutdown: The computer should be shutdown when reached */ - nv_wr32(therm, 0x20484, sensor->thrs_shutdown.hysteresis); - nv_wr32(therm, 0x20480, sensor->thrs_shutdown.temp); + nvkm_wr32(device, 0x20484, sensor->thrs_shutdown.hysteresis); + nvkm_wr32(device, 0x20480, sensor->thrs_shutdown.temp); /* THRS_1 : fan boost*/ - nv_wr32(therm, 0x204c4, sensor->thrs_fan_boost.temp); + nvkm_wr32(device, 0x204c4, sensor->thrs_fan_boost.temp); /* THRS_2 : critical */ - nv_wr32(therm, 0x204c0, sensor->thrs_critical.temp); + nvkm_wr32(device, 0x204c0, sensor->thrs_critical.temp); /* THRS_4 : down clock */ - nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp); - spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); - - nv_debug(therm, - "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", - sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis, - sensor->thrs_down_clock.temp, - sensor->thrs_down_clock.hysteresis, - sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis, - sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis); + nvkm_wr32(device, 0x20414, sensor->thrs_down_clock.temp); + spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); + + nvkm_debug(subdev, + "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", + sensor->thrs_fan_boost.temp, + sensor->thrs_fan_boost.hysteresis, + sensor->thrs_down_clock.temp, + sensor->thrs_down_clock.hysteresis, + sensor->thrs_critical.temp, + sensor->thrs_critical.hysteresis, + sensor->thrs_shutdown.temp, + sensor->thrs_shutdown.hysteresis); } @@ -97,24 +97,25 @@ g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm, const struct nvbios_therm_threshold *thrs, enum nvkm_therm_thrs thrs_name) { + struct nvkm_device *device = therm->subdev.device; enum nvkm_therm_thrs_direction direction; enum nvkm_therm_thrs_state prev_state, new_state; int temp, cur; prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name); - temp = nv_rd32(therm, thrs_reg); + temp = nvkm_rd32(device, thrs_reg); /* program the next threshold */ if (temp == thrs->temp) { - nv_wr32(therm, thrs_reg, thrs->temp - thrs->hysteresis); + nvkm_wr32(device, thrs_reg, thrs->temp - thrs->hysteresis); new_state = NVKM_THERM_THRS_HIGHER; } else { - nv_wr32(therm, thrs_reg, thrs->temp); + nvkm_wr32(device, thrs_reg, thrs->temp); new_state = NVKM_THERM_THRS_LOWER; } /* fix the state (in case someone reprogrammed the alarms) */ - cur = therm->temp_get(therm); + cur = therm->func->temp_get(therm); if (new_state == NVKM_THERM_THRS_LOWER && cur > thrs->temp) new_state = NVKM_THERM_THRS_HIGHER; else if (new_state == NVKM_THERM_THRS_HIGHER && @@ -135,17 +136,17 @@ g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm, } static void -g84_therm_intr(struct nvkm_subdev *subdev) +g84_therm_intr(struct nvkm_therm *therm) { - struct nvkm_therm *therm = nvkm_therm(subdev); - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; unsigned long flags; uint32_t intr; - spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); + spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); - intr = nv_rd32(therm, 0x20100) & 0x3ff; + intr = nvkm_rd32(device, 0x20100) & 0x3ff; /* THRS_4: downclock */ if (intr & 0x002) { @@ -180,87 +181,66 @@ g84_therm_intr(struct nvkm_subdev *subdev) } if (intr) - nv_error(therm, "unhandled intr 0x%08x\n", intr); + nvkm_error(subdev, "intr %08x\n", intr); /* ACK everything */ - nv_wr32(therm, 0x20100, 0xffffffff); - nv_wr32(therm, 0x1100, 0x10000); /* PBUS */ + nvkm_wr32(device, 0x20100, 0xffffffff); + nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */ - spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); + spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); } -static int -g84_therm_init(struct nvkm_object *object) +void +g84_therm_fini(struct nvkm_therm *therm) { - struct g84_therm_priv *priv = (void *)object; - int ret; + struct nvkm_device *device = therm->subdev.device; - ret = nvkm_therm_init(&priv->base.base); - if (ret) - return ret; + /* Disable PTherm IRQs */ + nvkm_wr32(device, 0x20000, 0x00000000); - g84_sensor_setup(&priv->base.base); - return 0; + /* ACK all PTherm IRQs */ + nvkm_wr32(device, 0x20100, 0xffffffff); + nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */ } -static int -g84_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void +g84_therm_init(struct nvkm_therm *therm) { - struct g84_therm_priv *priv; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; - priv->base.base.pwm_get = nv50_fan_pwm_get; - priv->base.base.pwm_set = nv50_fan_pwm_set; - priv->base.base.pwm_clock = nv50_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.sensor.program_alarms = g84_therm_program_alarms; - nv_subdev(priv)->intr = g84_therm_intr; - - /* init the thresholds */ - nvkm_therm_sensor_set_threshold_state(&priv->base.base, - NVKM_THERM_THRS_SHUTDOWN, - NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&priv->base.base, - NVKM_THERM_THRS_FANBOOST, - NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&priv->base.base, - NVKM_THERM_THRS_CRITICAL, - NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&priv->base.base, - NVKM_THERM_THRS_DOWNCLOCK, - NVKM_THERM_THRS_LOWER); - - return nvkm_therm_preinit(&priv->base.base); + g84_sensor_setup(therm); } +static const struct nvkm_therm_func +g84_therm = { + .init = g84_therm_init, + .fini = g84_therm_fini, + .intr = g84_therm_intr, + .pwm_ctrl = nv50_fan_pwm_ctrl, + .pwm_get = nv50_fan_pwm_get, + .pwm_set = nv50_fan_pwm_set, + .pwm_clock = nv50_fan_pwm_clock, + .temp_get = g84_temp_get, + .program_alarms = g84_therm_program_alarms, +}; + int -g84_therm_fini(struct nvkm_object *object, bool suspend) +g84_therm_new(struct nvkm_device *device, int index, struct nvkm_therm **ptherm) { - /* Disable PTherm IRQs */ - nv_wr32(object, 0x20000, 0x00000000); + struct nvkm_therm *therm; + int ret; - /* ACK all PTherm IRQs */ - nv_wr32(object, 0x20100, 0xffffffff); - nv_wr32(object, 0x1100, 0x10000); /* PBUS */ + ret = nvkm_therm_new_(&g84_therm, device, index, &therm); + *ptherm = therm; + if (ret) + return ret; - return _nvkm_therm_fini(object, suspend); + /* init the thresholds */ + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_SHUTDOWN, + NVKM_THERM_THRS_LOWER); + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_FANBOOST, + NVKM_THERM_THRS_LOWER); + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_CRITICAL, + NVKM_THERM_THRS_LOWER); + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_DOWNCLOCK, + NVKM_THERM_THRS_LOWER); + return 0; } - -struct nvkm_oclass -g84_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = g84_therm_init, - .fini = g84_therm_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c deleted file mode 100644 index 46b7e656a..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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/device.h> - -struct gf110_therm_priv { - struct nvkm_therm_priv base; -}; - -static int -pwm_info(struct nvkm_therm *therm, int line) -{ - u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); - - switch (gpio & 0x000000c0) { - case 0x00000000: /* normal mode, possibly pwm forced off by us */ - case 0x00000040: /* nvio special */ - switch (gpio & 0x0000001f) { - case 0x00: return 2; - case 0x19: return 1; - case 0x1c: return 0; - case 0x1e: return 2; - default: - break; - } - default: - break; - } - - nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio); - return -ENODEV; -} - -static int -gf110_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) -{ - u32 data = enable ? 0x00000040 : 0x00000000; - int indx = pwm_info(therm, line); - if (indx < 0) - return indx; - else if (indx < 2) - nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); - /* nothing to do for indx == 2, it seems hardwired to PTHERM */ - return 0; -} - -static int -gf110_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) -{ - int indx = pwm_info(therm, line); - if (indx < 0) - return indx; - else if (indx < 2) { - if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { - *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); - *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); - return 0; - } - } else if (indx == 2) { - *divs = nv_rd32(therm, 0x0200d8) & 0x1fff; - *duty = nv_rd32(therm, 0x0200dc) & 0x1fff; - return 0; - } - - return -EINVAL; -} - -static int -gf110_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) -{ - int indx = pwm_info(therm, line); - if (indx < 0) - return indx; - else if (indx < 2) { - nv_wr32(therm, 0x00e114 + (indx * 8), divs); - nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); - } else if (indx == 2) { - nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */ - nv_wr32(therm, 0x0200dc, duty | 0x40000000); - } - return 0; -} - -static int -gf110_fan_pwm_clock(struct nvkm_therm *therm, int line) -{ - int indx = pwm_info(therm, line); - if (indx < 0) - return 0; - else if (indx < 2) - return (nv_device(therm)->crystal * 1000) / 20; - else - return nv_device(therm)->crystal * 1000 / 10; -} - -int -gf110_therm_init(struct nvkm_object *object) -{ - struct gf110_therm_priv *priv = (void *)object; - int ret; - - ret = nvkm_therm_init(&priv->base.base); - if (ret) - return ret; - - /* enable fan tach, count revolutions per-second */ - nv_mask(priv, 0x00e720, 0x00000003, 0x00000002); - if (priv->base.fan->tach.func != DCB_GPIO_UNUSED) { - nv_mask(priv, 0x00d79c, 0x000000ff, priv->base.fan->tach.line); - nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000); - nv_mask(priv, 0x00e720, 0x00000001, 0x00000001); - } - nv_mask(priv, 0x00e720, 0x00000002, 0x00000000); - - return 0; -} - -static int -gf110_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf110_therm_priv *priv; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - g84_sensor_setup(&priv->base.base); - - priv->base.base.pwm_ctrl = gf110_fan_pwm_ctrl; - priv->base.base.pwm_get = gf110_fan_pwm_get; - priv->base.base.pwm_set = gf110_fan_pwm_set; - priv->base.base.pwm_clock = gf110_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.base.fan_sense = gt215_therm_fan_sense; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&priv->base.base); -} - -struct nvkm_oclass -gf110_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0xd0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = gf110_therm_init, - .fini = g84_therm_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c new file mode 100644 index 000000000..06dcfd6ee --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c @@ -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 "priv.h" + +static int +pwm_info(struct nvkm_therm *therm, int line) +{ + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; + u32 gpio = nvkm_rd32(device, 0x00d610 + (line * 0x04)); + + switch (gpio & 0x000000c0) { + case 0x00000000: /* normal mode, possibly pwm forced off by us */ + case 0x00000040: /* nvio special */ + switch (gpio & 0x0000001f) { + case 0x00: return 2; + case 0x19: return 1; + case 0x1c: return 0; + case 0x1e: return 2; + default: + break; + } + default: + break; + } + + nvkm_error(subdev, "GPIO %d unknown PWM: %08x\n", line, gpio); + return -ENODEV; +} + +static int +gf119_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) +{ + struct nvkm_device *device = therm->subdev.device; + u32 data = enable ? 0x00000040 : 0x00000000; + int indx = pwm_info(therm, line); + if (indx < 0) + return indx; + else if (indx < 2) + nvkm_mask(device, 0x00d610 + (line * 0x04), 0x000000c0, data); + /* nothing to do for indx == 2, it seems hardwired to PTHERM */ + return 0; +} + +static int +gf119_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) +{ + struct nvkm_device *device = therm->subdev.device; + int indx = pwm_info(therm, line); + if (indx < 0) + return indx; + else if (indx < 2) { + if (nvkm_rd32(device, 0x00d610 + (line * 0x04)) & 0x00000040) { + *divs = nvkm_rd32(device, 0x00e114 + (indx * 8)); + *duty = nvkm_rd32(device, 0x00e118 + (indx * 8)); + return 0; + } + } else if (indx == 2) { + *divs = nvkm_rd32(device, 0x0200d8) & 0x1fff; + *duty = nvkm_rd32(device, 0x0200dc) & 0x1fff; + return 0; + } + + return -EINVAL; +} + +static int +gf119_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) +{ + struct nvkm_device *device = therm->subdev.device; + int indx = pwm_info(therm, line); + if (indx < 0) + return indx; + else if (indx < 2) { + nvkm_wr32(device, 0x00e114 + (indx * 8), divs); + nvkm_wr32(device, 0x00e118 + (indx * 8), duty | 0x80000000); + } else if (indx == 2) { + nvkm_mask(device, 0x0200d8, 0x1fff, divs); /* keep the high bits */ + nvkm_wr32(device, 0x0200dc, duty | 0x40000000); + } + return 0; +} + +static int +gf119_fan_pwm_clock(struct nvkm_therm *therm, int line) +{ + struct nvkm_device *device = therm->subdev.device; + int indx = pwm_info(therm, line); + if (indx < 0) + return 0; + else if (indx < 2) + return (device->crystal * 1000) / 20; + else + return device->crystal * 1000 / 10; +} + +void +gf119_therm_init(struct nvkm_therm *therm) +{ + struct nvkm_device *device = therm->subdev.device; + + g84_sensor_setup(therm); + + /* enable fan tach, count revolutions per-second */ + nvkm_mask(device, 0x00e720, 0x00000003, 0x00000002); + if (therm->fan->tach.func != DCB_GPIO_UNUSED) { + nvkm_mask(device, 0x00d79c, 0x000000ff, therm->fan->tach.line); + nvkm_wr32(device, 0x00e724, device->crystal * 1000); + nvkm_mask(device, 0x00e720, 0x00000001, 0x00000001); + } + nvkm_mask(device, 0x00e720, 0x00000002, 0x00000000); +} + +static const struct nvkm_therm_func +gf119_therm = { + .init = gf119_therm_init, + .fini = g84_therm_fini, + .pwm_ctrl = gf119_fan_pwm_ctrl, + .pwm_get = gf119_fan_pwm_get, + .pwm_set = gf119_fan_pwm_set, + .pwm_clock = gf119_fan_pwm_clock, + .temp_get = g84_temp_get, + .fan_sense = gt215_therm_fan_sense, + .program_alarms = nvkm_therm_program_alarms_polling, +}; + +int +gf119_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&gf119_therm, device, index, ptherm); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c index 2fd110f09..86848ece4 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c @@ -23,12 +23,6 @@ */ #include "priv.h" -#include <core/device.h> - -struct gm107_therm_priv { - struct nvkm_therm_priv base; -}; - static int gm107_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { @@ -39,55 +33,43 @@ gm107_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) static int gm107_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { - *divs = nv_rd32(therm, 0x10eb20) & 0x1fff; - *duty = nv_rd32(therm, 0x10eb24) & 0x1fff; + struct nvkm_device *device = therm->subdev.device; + *divs = nvkm_rd32(device, 0x10eb20) & 0x1fff; + *duty = nvkm_rd32(device, 0x10eb24) & 0x1fff; return 0; } static int gm107_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { - nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */ - nv_wr32(therm, 0x10eb14, duty | 0x80000000); + struct nvkm_device *device = therm->subdev.device; + nvkm_mask(device, 0x10eb10, 0x1fff, divs); /* keep the high bits */ + nvkm_wr32(device, 0x10eb14, duty | 0x80000000); return 0; } static int gm107_fan_pwm_clock(struct nvkm_therm *therm, int line) { - return nv_device(therm)->crystal * 1000; + return therm->subdev.device->crystal * 1000; } -static int -gm107_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gm107_therm_priv *priv; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_therm_func +gm107_therm = { + .init = gf119_therm_init, + .fini = g84_therm_fini, + .pwm_ctrl = gm107_fan_pwm_ctrl, + .pwm_get = gm107_fan_pwm_get, + .pwm_set = gm107_fan_pwm_set, + .pwm_clock = gm107_fan_pwm_clock, + .temp_get = g84_temp_get, + .fan_sense = gt215_therm_fan_sense, + .program_alarms = nvkm_therm_program_alarms_polling, +}; - priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl; - priv->base.base.pwm_get = gm107_fan_pwm_get; - priv->base.base.pwm_set = gm107_fan_pwm_set; - priv->base.base.pwm_clock = gm107_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.base.fan_sense = gt215_therm_fan_sense; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&priv->base.base); +int +gm107_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&gm107_therm, device, index, ptherm); } - -struct nvkm_oclass -gm107_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x117), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = gf110_therm_init, - .fini = g84_therm_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c index e99be2033..c08097f2a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c @@ -23,78 +23,53 @@ */ #include "priv.h" -#include <core/device.h> #include <subdev/gpio.h> -struct gt215_therm_priv { - struct nvkm_therm_priv base; -}; - int gt215_therm_fan_sense(struct nvkm_therm *therm) { - u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff; - u32 ctrl = nv_rd32(therm, 0x00e720); + struct nvkm_device *device = therm->subdev.device; + u32 tach = nvkm_rd32(device, 0x00e728) & 0x0000ffff; + u32 ctrl = nvkm_rd32(device, 0x00e720); if (ctrl & 0x00000001) return tach * 60 / 2; return -ENODEV; } -static int -gt215_therm_init(struct nvkm_object *object) +static void +gt215_therm_init(struct nvkm_therm *therm) { - struct gt215_therm_priv *priv = (void *)object; - struct dcb_gpio_func *tach = &priv->base.fan->tach; - int ret; - - ret = nvkm_therm_init(&priv->base.base); - if (ret) - return ret; + struct nvkm_device *device = therm->subdev.device; + struct dcb_gpio_func *tach = &therm->fan->tach; - g84_sensor_setup(&priv->base.base); + g84_sensor_setup(therm); /* enable fan tach, count revolutions per-second */ - nv_mask(priv, 0x00e720, 0x00000003, 0x00000002); + nvkm_mask(device, 0x00e720, 0x00000003, 0x00000002); if (tach->func != DCB_GPIO_UNUSED) { - nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000); - nv_mask(priv, 0x00e720, 0x001f0000, tach->line << 16); - nv_mask(priv, 0x00e720, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x00e724, device->crystal * 1000); + nvkm_mask(device, 0x00e720, 0x001f0000, tach->line << 16); + nvkm_mask(device, 0x00e720, 0x00000001, 0x00000001); } - nv_mask(priv, 0x00e720, 0x00000002, 0x00000000); - - return 0; + nvkm_mask(device, 0x00e720, 0x00000002, 0x00000000); } -static int -gt215_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gt215_therm_priv *priv; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_therm_func +gt215_therm = { + .init = gt215_therm_init, + .fini = g84_therm_fini, + .pwm_ctrl = nv50_fan_pwm_ctrl, + .pwm_get = nv50_fan_pwm_get, + .pwm_set = nv50_fan_pwm_set, + .pwm_clock = nv50_fan_pwm_clock, + .temp_get = g84_temp_get, + .fan_sense = gt215_therm_fan_sense, + .program_alarms = nvkm_therm_program_alarms_polling, +}; - priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; - priv->base.base.pwm_get = nv50_fan_pwm_get; - priv->base.base.pwm_set = nv50_fan_pwm_set; - priv->base.base.pwm_clock = nv50_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.base.fan_sense = gt215_therm_fan_sense; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&priv->base.base); +int +gt215_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(>215_therm, device, index, ptherm); } - -struct nvkm_oclass -gt215_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = gt215_therm_init, - .fini = g84_therm_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c index 09fc4605e..6e0ddc1bb 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c @@ -27,16 +27,16 @@ #include <subdev/i2c.h> static bool -probe_monitoring_device(struct nvkm_i2c_port *i2c, +probe_monitoring_device(struct nvkm_i2c_bus *bus, struct i2c_board_info *info, void *data) { - struct nvkm_therm_priv *priv = data; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_therm *therm = data; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; struct i2c_client *client; request_module("%s%s", I2C_MODULE_PREFIX, info->type); - client = i2c_new_device(&i2c->adapter, info); + client = i2c_new_device(&bus->i2c, info); if (!client) return false; @@ -46,15 +46,15 @@ probe_monitoring_device(struct nvkm_i2c_port *i2c, return false; } - nv_info(priv, - "Found an %s at address 0x%x (controlled by lm_sensors, " - "temp offset %+i C)\n", - info->type, info->addr, sensor->offset_constant); - priv->ic = client; + nvkm_debug(&therm->subdev, + "Found an %s at address 0x%x (controlled by lm_sensors, " + "temp offset %+i C)\n", + info->type, info->addr, sensor->offset_constant); + therm->ic = client; return true; } -static struct nvkm_i2c_board_info +static struct nvkm_i2c_bus_probe nv_board_infos[] = { { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 }, { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 }, @@ -82,38 +82,43 @@ nv_board_infos[] = { void nvkm_therm_ic_ctor(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_bios *bios = nvkm_bios(therm); - struct nvkm_i2c *i2c = nvkm_i2c(therm); + struct nvkm_device *device = therm->subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; + struct nvkm_i2c_bus *bus; struct nvbios_extdev_func extdev_entry; + bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_PRI); + if (!bus) + return; + if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { - struct nvkm_i2c_board_info board[] = { + struct nvkm_i2c_bus_probe board[] = { { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0}, { } }; - i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - board, probe_monitoring_device, therm); - if (priv->ic) + nvkm_i2c_bus_probe(bus, "monitoring device", board, + probe_monitoring_device, therm); + if (therm->ic) return; } if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { - struct nvkm_i2c_board_info board[] = { + struct nvkm_i2c_bus_probe board[] = { { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 }, { } }; - i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - board, probe_monitoring_device, therm); - if (priv->ic) + nvkm_i2c_bus_probe(bus, "monitoring device", board, + probe_monitoring_device, therm); + if (therm->ic) return; } /* The vbios doesn't provide the address of an exisiting monitoring device. Let's try our static list. */ - i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - nv_board_infos, probe_monitoring_device, therm); + nvkm_i2c_bus_probe(bus, "monitoring device", nv_board_infos, + probe_monitoring_device, therm); } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c index 8496fffd4..6326fdc5a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c @@ -24,26 +24,17 @@ */ #include "priv.h" -#include <core/device.h> - -struct nv40_therm_priv { - struct nvkm_therm_priv base; -}; - enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 }; static enum nv40_sensor_style nv40_sensor_style(struct nvkm_therm *therm) { - struct nvkm_device *device = nv_device(therm); - - switch (device->chipset) { + switch (therm->subdev.device->chipset) { case 0x43: case 0x44: case 0x4a: case 0x47: return OLD_STYLE; - case 0x46: case 0x49: case 0x4b: @@ -61,18 +52,19 @@ nv40_sensor_style(struct nvkm_therm *therm) static int nv40_sensor_setup(struct nvkm_therm *therm) { + struct nvkm_device *device = therm->subdev.device; enum nv40_sensor_style style = nv40_sensor_style(therm); /* enable ADC readout and disable the ALARM threshold */ if (style == NEW_STYLE) { - nv_mask(therm, 0x15b8, 0x80000000, 0); - nv_wr32(therm, 0x15b0, 0x80003fff); + nvkm_mask(device, 0x15b8, 0x80000000, 0); + nvkm_wr32(device, 0x15b0, 0x80003fff); mdelay(20); /* wait for the temperature to stabilize */ - return nv_rd32(therm, 0x15b4) & 0x3fff; + return nvkm_rd32(device, 0x15b4) & 0x3fff; } else if (style == OLD_STYLE) { - nv_wr32(therm, 0x15b0, 0xff); + nvkm_wr32(device, 0x15b0, 0xff); mdelay(20); /* wait for the temperature to stabilize */ - return nv_rd32(therm, 0x15b4) & 0xff; + return nvkm_rd32(device, 0x15b4) & 0xff; } else return -ENODEV; } @@ -80,17 +72,17 @@ nv40_sensor_setup(struct nvkm_therm *therm) static int nv40_temp_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_device *device = therm->subdev.device; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; enum nv40_sensor_style style = nv40_sensor_style(therm); int core_temp; if (style == NEW_STYLE) { - nv_wr32(therm, 0x15b0, 0x80003fff); - core_temp = nv_rd32(therm, 0x15b4) & 0x3fff; + nvkm_wr32(device, 0x15b0, 0x80003fff); + core_temp = nvkm_rd32(device, 0x15b4) & 0x3fff; } else if (style == OLD_STYLE) { - nv_wr32(therm, 0x15b0, 0xff); - core_temp = nv_rd32(therm, 0x15b4) & 0xff; + nvkm_wr32(device, 0x15b0, 0xff); + core_temp = nvkm_rd32(device, 0x15b4) & 0xff; } else return -ENODEV; @@ -113,11 +105,13 @@ nv40_temp_get(struct nvkm_therm *therm) static int nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; u32 mask = enable ? 0x80000000 : 0x0000000; - if (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask); - else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask); + if (line == 2) nvkm_mask(device, 0x0010f0, 0x80000000, mask); + else if (line == 9) nvkm_mask(device, 0x0015f4, 0x80000000, mask); else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; } return 0; @@ -126,8 +120,10 @@ nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) static int nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; if (line == 2) { - u32 reg = nv_rd32(therm, 0x0010f0); + u32 reg = nvkm_rd32(device, 0x0010f0); if (reg & 0x80000000) { *duty = (reg & 0x7fff0000) >> 16; *divs = (reg & 0x00007fff); @@ -135,14 +131,14 @@ nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) } } else if (line == 9) { - u32 reg = nv_rd32(therm, 0x0015f4); + u32 reg = nvkm_rd32(device, 0x0015f4); if (reg & 0x80000000) { - *divs = nv_rd32(therm, 0x0015f8); + *divs = nvkm_rd32(device, 0x0015f8); *duty = (reg & 0x7fffffff); return 0; } } else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; } @@ -152,14 +148,16 @@ nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) static int nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; if (line == 2) { - nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs); + nvkm_mask(device, 0x0010f0, 0x7fff7fff, (duty << 16) | divs); } else if (line == 9) { - nv_wr32(therm, 0x0015f8, divs); - nv_mask(therm, 0x0015f4, 0x7fffffff, duty); + nvkm_wr32(device, 0x0015f8, divs); + nvkm_mask(device, 0x0015f4, 0x7fffffff, duty); } else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; } @@ -167,59 +165,40 @@ nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) } void -nv40_therm_intr(struct nvkm_subdev *subdev) +nv40_therm_intr(struct nvkm_therm *therm) { - struct nvkm_therm *therm = nvkm_therm(subdev); - uint32_t stat = nv_rd32(therm, 0x1100); + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; + uint32_t stat = nvkm_rd32(device, 0x1100); /* traitement */ /* ack all IRQs */ - nv_wr32(therm, 0x1100, 0x70000); + nvkm_wr32(device, 0x1100, 0x70000); - nv_error(therm, "THERM received an IRQ: stat = %x\n", stat); + nvkm_error(subdev, "THERM received an IRQ: stat = %x\n", stat); } -static int -nv40_therm_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void +nv40_therm_init(struct nvkm_therm *therm) { - struct nv40_therm_priv *priv; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.base.pwm_ctrl = nv40_fan_pwm_ctrl; - priv->base.base.pwm_get = nv40_fan_pwm_get; - priv->base.base.pwm_set = nv40_fan_pwm_set; - priv->base.base.temp_get = nv40_temp_get; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - nv_subdev(priv)->intr = nv40_therm_intr; - return nvkm_therm_preinit(&priv->base.base); -} - -static int -nv40_therm_init(struct nvkm_object *object) -{ - struct nvkm_therm *therm = (void *)object; - nv40_sensor_setup(therm); - - return _nvkm_therm_init(object); } -struct nvkm_oclass -nv40_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = nv40_therm_init, - .fini = _nvkm_therm_fini, - }, +static const struct nvkm_therm_func +nv40_therm = { + .init = nv40_therm_init, + .intr = nv40_therm_intr, + .pwm_ctrl = nv40_fan_pwm_ctrl, + .pwm_get = nv40_fan_pwm_get, + .pwm_set = nv40_fan_pwm_set, + .temp_get = nv40_temp_get, + .program_alarms = nvkm_therm_program_alarms_polling, }; + +int +nv40_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&nv40_therm, device, index, ptherm); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c index 1ef59e892..9b57b433d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c @@ -24,15 +24,11 @@ */ #include "priv.h" -#include <core/device.h> - -struct nv50_therm_priv { - struct nvkm_therm_priv base; -}; - static int pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx) { + struct nvkm_subdev *subdev = &therm->subdev; + if (*line == 0x04) { *ctrl = 0x00e100; *line = 4; @@ -48,7 +44,7 @@ pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx) *line = 0; *indx = 0; } else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", *line); return -ENODEV; } @@ -58,23 +54,25 @@ pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx) int nv50_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { + struct nvkm_device *device = therm->subdev.device; u32 data = enable ? 0x00000001 : 0x00000000; int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); if (ret == 0) - nv_mask(therm, ctrl, 0x00010001 << line, data << line); + nvkm_mask(device, ctrl, 0x00010001 << line, data << line); return ret; } int nv50_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { + struct nvkm_device *device = therm->subdev.device; int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); if (ret) return ret; - if (nv_rd32(therm, ctrl) & (1 << line)) { - *divs = nv_rd32(therm, 0x00e114 + (id * 8)); - *duty = nv_rd32(therm, 0x00e118 + (id * 8)); + if (nvkm_rd32(device, ctrl) & (1 << line)) { + *divs = nvkm_rd32(device, 0x00e114 + (id * 8)); + *duty = nvkm_rd32(device, 0x00e118 + (id * 8)); return 0; } @@ -84,36 +82,36 @@ nv50_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) int nv50_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { + struct nvkm_device *device = therm->subdev.device; int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); if (ret) return ret; - nv_wr32(therm, 0x00e114 + (id * 8), divs); - nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000); + nvkm_wr32(device, 0x00e114 + (id * 8), divs); + nvkm_wr32(device, 0x00e118 + (id * 8), duty | 0x80000000); return 0; } int nv50_fan_pwm_clock(struct nvkm_therm *therm, int line) { - int chipset = nv_device(therm)->chipset; - int crystal = nv_device(therm)->crystal; + struct nvkm_device *device = therm->subdev.device; int pwm_clock; /* determine the PWM source clock */ - if (chipset > 0x50 && chipset < 0x94) { - u8 pwm_div = nv_rd32(therm, 0x410c); - if (nv_rd32(therm, 0xc040) & 0x800000) { + if (device->chipset > 0x50 && device->chipset < 0x94) { + u8 pwm_div = nvkm_rd32(device, 0x410c); + if (nvkm_rd32(device, 0xc040) & 0x800000) { /* Use the HOST clock (100 MHz) * Where does this constant(2.4) comes from? */ pwm_clock = (100000000 >> pwm_div) * 10 / 24; } else { /* Where does this constant(20) comes from? */ - pwm_clock = (crystal * 1000) >> pwm_div; + pwm_clock = (device->crystal * 1000) >> pwm_div; pwm_clock /= 20; } } else { - pwm_clock = (crystal * 1000) / 20; + pwm_clock = (device->crystal * 1000) / 20; } return pwm_clock; @@ -122,18 +120,19 @@ nv50_fan_pwm_clock(struct nvkm_therm *therm, int line) static void nv50_sensor_setup(struct nvkm_therm *therm) { - nv_mask(therm, 0x20010, 0x40000000, 0x0); + struct nvkm_device *device = therm->subdev.device; + nvkm_mask(device, 0x20010, 0x40000000, 0x0); mdelay(20); /* wait for the temperature to stabilize */ } static int nv50_temp_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_device *device = therm->subdev.device; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; int core_temp; - core_temp = nv_rd32(therm, 0x20014) & 0x3fff; + core_temp = nvkm_rd32(device, 0x20014) & 0x3fff; /* if the slope or the offset is unset, do no use the sensor */ if (!sensor->slope_div || !sensor->slope_mult || @@ -151,48 +150,27 @@ nv50_temp_get(struct nvkm_therm *therm) return core_temp; } -static int -nv50_therm_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_therm_priv *priv; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; - priv->base.base.pwm_get = nv50_fan_pwm_get; - priv->base.base.pwm_set = nv50_fan_pwm_set; - priv->base.base.pwm_clock = nv50_fan_pwm_clock; - priv->base.base.temp_get = nv50_temp_get; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - nv_subdev(priv)->intr = nv40_therm_intr; - - return nvkm_therm_preinit(&priv->base.base); -} - -static int -nv50_therm_init(struct nvkm_object *object) +static void +nv50_therm_init(struct nvkm_therm *therm) { - struct nvkm_therm *therm = (void *)object; - nv50_sensor_setup(therm); - - return _nvkm_therm_init(object); } -struct nvkm_oclass -nv50_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = nv50_therm_init, - .fini = _nvkm_therm_fini, - }, +static const struct nvkm_therm_func +nv50_therm = { + .init = nv50_therm_init, + .intr = nv40_therm_intr, + .pwm_ctrl = nv50_fan_pwm_ctrl, + .pwm_get = nv50_fan_pwm_get, + .pwm_set = nv50_fan_pwm_set, + .pwm_clock = nv50_fan_pwm_clock, + .temp_get = nv50_temp_get, + .program_alarms = nvkm_therm_program_alarms_polling, }; + +int +nv50_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&nv50_therm, device, index, ptherm); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h index 916a149ef..235a5d8da 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h @@ -1,5 +1,6 @@ #ifndef __NVTHERM_PRIV_H__ #define __NVTHERM_PRIV_H__ +#define nvkm_therm(p) container_of((p), struct nvkm_therm, subdev) /* * Copyright 2012 The Nouveau community * @@ -28,8 +29,9 @@ #include <subdev/bios/extdev.h> #include <subdev/bios/gpio.h> #include <subdev/bios/perf.h> -#include <subdev/bios/therm.h> -#include <subdev/timer.h> + +int nvkm_therm_new_(const struct nvkm_therm_func *, struct nvkm_device *, + int index, struct nvkm_therm **); struct nvkm_fan { struct nvkm_therm *parent; @@ -48,59 +50,6 @@ struct nvkm_fan { struct dcb_gpio_func tach; }; -enum nvkm_therm_thrs_direction { - NVKM_THERM_THRS_FALLING = 0, - NVKM_THERM_THRS_RISING = 1 -}; - -enum nvkm_therm_thrs_state { - NVKM_THERM_THRS_LOWER = 0, - NVKM_THERM_THRS_HIGHER = 1 -}; - -enum nvkm_therm_thrs { - NVKM_THERM_THRS_FANBOOST = 0, - NVKM_THERM_THRS_DOWNCLOCK = 1, - NVKM_THERM_THRS_CRITICAL = 2, - NVKM_THERM_THRS_SHUTDOWN = 3, - NVKM_THERM_THRS_NR -}; - -struct nvkm_therm_priv { - struct nvkm_therm base; - - /* automatic thermal management */ - struct nvkm_alarm alarm; - spinlock_t lock; - struct nvbios_therm_trip_point *last_trip; - int mode; - int cstate; - int suspend; - - /* bios */ - struct nvbios_therm_sensor bios_sensor; - - /* fan priv */ - struct nvkm_fan *fan; - - /* alarms priv */ - struct { - spinlock_t alarm_program_lock; - struct nvkm_alarm therm_poll_alarm; - enum nvkm_therm_thrs_state alarm_state[NVKM_THERM_THRS_NR]; - void (*program_alarms)(struct nvkm_therm *); - } sensor; - - /* what should be done if the card overheats */ - struct { - void (*downclock)(struct nvkm_therm *, bool active); - void (*pause)(struct nvkm_therm *, bool active); - } emergency; - - /* ic */ - struct i2c_client *ic; -}; - int nvkm_therm_fan_mode(struct nvkm_therm *, int mode); int nvkm_therm_attr_get(struct nvkm_therm *, enum nvkm_therm_attr_type); int nvkm_therm_attr_set(struct nvkm_therm *, enum nvkm_therm_attr_type, int); @@ -117,8 +66,6 @@ int nvkm_therm_fan_set(struct nvkm_therm *, bool now, int percent); int nvkm_therm_fan_user_get(struct nvkm_therm *); int nvkm_therm_fan_user_set(struct nvkm_therm *, int percent); -int nvkm_therm_fan_sense(struct nvkm_therm *); - int nvkm_therm_preinit(struct nvkm_therm *); int nvkm_therm_sensor_init(struct nvkm_therm *); @@ -134,18 +81,37 @@ void nvkm_therm_sensor_event(struct nvkm_therm *, enum nvkm_therm_thrs, enum nvkm_therm_thrs_direction); void nvkm_therm_program_alarms_polling(struct nvkm_therm *); -void nv40_therm_intr(struct nvkm_subdev *); +struct nvkm_therm_func { + void (*init)(struct nvkm_therm *); + void (*fini)(struct nvkm_therm *); + void (*intr)(struct nvkm_therm *); + + int (*pwm_ctrl)(struct nvkm_therm *, int line, bool); + int (*pwm_get)(struct nvkm_therm *, int line, u32 *, u32 *); + int (*pwm_set)(struct nvkm_therm *, int line, u32, u32); + int (*pwm_clock)(struct nvkm_therm *, int line); + + int (*temp_get)(struct nvkm_therm *); + + int (*fan_sense)(struct nvkm_therm *); + + void (*program_alarms)(struct nvkm_therm *); +}; + +void nv40_therm_intr(struct nvkm_therm *); + int nv50_fan_pwm_ctrl(struct nvkm_therm *, int, bool); int nv50_fan_pwm_get(struct nvkm_therm *, int, u32 *, u32 *); int nv50_fan_pwm_set(struct nvkm_therm *, int, u32, u32); int nv50_fan_pwm_clock(struct nvkm_therm *, int); + int g84_temp_get(struct nvkm_therm *); void g84_sensor_setup(struct nvkm_therm *); -int g84_therm_fini(struct nvkm_object *, bool suspend); +void g84_therm_fini(struct nvkm_therm *); int gt215_therm_fan_sense(struct nvkm_therm *); -int gf110_therm_init(struct nvkm_object *); +void gf119_therm_init(struct nvkm_therm *); int nvkm_fanpwm_create(struct nvkm_therm *, struct dcb_gpio_func *); int nvkm_fantog_create(struct nvkm_therm *, struct dcb_gpio_func *); diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index aa13744f3..b9703c02d 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -26,29 +26,25 @@ static void nvkm_therm_temp_set_defaults(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; + therm->bios_sensor.offset_constant = 0; - priv->bios_sensor.offset_constant = 0; + therm->bios_sensor.thrs_fan_boost.temp = 90; + therm->bios_sensor.thrs_fan_boost.hysteresis = 3; - priv->bios_sensor.thrs_fan_boost.temp = 90; - priv->bios_sensor.thrs_fan_boost.hysteresis = 3; + therm->bios_sensor.thrs_down_clock.temp = 95; + therm->bios_sensor.thrs_down_clock.hysteresis = 3; - priv->bios_sensor.thrs_down_clock.temp = 95; - priv->bios_sensor.thrs_down_clock.hysteresis = 3; + therm->bios_sensor.thrs_critical.temp = 105; + therm->bios_sensor.thrs_critical.hysteresis = 5; - priv->bios_sensor.thrs_critical.temp = 105; - priv->bios_sensor.thrs_critical.hysteresis = 5; - - priv->bios_sensor.thrs_shutdown.temp = 135; - priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */ + therm->bios_sensor.thrs_shutdown.temp = 135; + therm->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */ } - static void nvkm_therm_temp_safety_checks(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *s = &priv->bios_sensor; + struct nvbios_therm_sensor *s = &therm->bios_sensor; /* enforce a minimum hysteresis on thresholds */ s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2); @@ -63,8 +59,7 @@ nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, enum nvkm_therm_thrs_state st) { - struct nvkm_therm_priv *priv = (void *)therm; - priv->sensor.alarm_state[thrs] = st; + therm->sensor.alarm_state[thrs] = st; } /* must be called with alarm_program_lock taken ! */ @@ -72,8 +67,7 @@ enum nvkm_therm_thrs_state nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs) { - struct nvkm_therm_priv *priv = (void *)therm; - return priv->sensor.alarm_state[thrs]; + return therm->sensor.alarm_state[thrs]; } static void @@ -87,22 +81,23 @@ void nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, enum nvkm_therm_thrs_direction dir) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_subdev *subdev = &therm->subdev; bool active; const char *thresolds[] = { "fanboost", "downclock", "critical", "shutdown" }; - int temperature = therm->temp_get(therm); + int temperature = therm->func->temp_get(therm); if (thrs < 0 || thrs > 3) return; if (dir == NVKM_THERM_THRS_FALLING) - nv_info(therm, "temperature (%i C) went below the '%s' threshold\n", - temperature, thresolds[thrs]); + nvkm_info(subdev, + "temperature (%i C) went below the '%s' threshold\n", + temperature, thresolds[thrs]); else - nv_info(therm, "temperature (%i C) hit the '%s' threshold\n", - temperature, thresolds[thrs]); + nvkm_info(subdev, "temperature (%i C) hit the '%s' threshold\n", + temperature, thresolds[thrs]); active = (dir == NVKM_THERM_THRS_RISING); switch (thrs) { @@ -113,12 +108,12 @@ nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, } break; case NVKM_THERM_THRS_DOWNCLOCK: - if (priv->emergency.downclock) - priv->emergency.downclock(therm, active); + if (therm->emergency.downclock) + therm->emergency.downclock(therm, active); break; case NVKM_THERM_THRS_CRITICAL: - if (priv->emergency.pause) - priv->emergency.pause(therm, active); + if (therm->emergency.pause) + therm->emergency.pause(therm, active); break; case NVKM_THERM_THRS_SHUTDOWN: if (active) { @@ -145,7 +140,7 @@ nvkm_therm_threshold_hyst_polling(struct nvkm_therm *therm, { enum nvkm_therm_thrs_direction direction; enum nvkm_therm_thrs_state prev_state, new_state; - int temp = therm->temp_get(therm); + int temp = therm->func->temp_get(therm); prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name); @@ -166,19 +161,19 @@ nvkm_therm_threshold_hyst_polling(struct nvkm_therm *therm, static void alarm_timer_callback(struct nvkm_alarm *alarm) { - struct nvkm_therm_priv *priv = - container_of(alarm, struct nvkm_therm_priv, sensor.therm_poll_alarm); - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; - struct nvkm_timer *ptimer = nvkm_timer(priv); - struct nvkm_therm *therm = &priv->base; + struct nvkm_therm *therm = + container_of(alarm, struct nvkm_therm, sensor.therm_poll_alarm); + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; + struct nvkm_timer *tmr = therm->subdev.device->timer; unsigned long flags; - spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); + spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost, NVKM_THERM_THRS_FANBOOST); - nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock, + nvkm_therm_threshold_hyst_polling(therm, + &sensor->thrs_down_clock, NVKM_THERM_THRS_DOWNCLOCK); nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_critical, @@ -187,46 +182,45 @@ alarm_timer_callback(struct nvkm_alarm *alarm) nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown, NVKM_THERM_THRS_SHUTDOWN); - spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); + spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); /* schedule the next poll in one second */ - if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head)) - ptimer->alarm(ptimer, 1000000000ULL, alarm); + if (therm->func->temp_get(therm) >= 0 && list_empty(&alarm->head)) + nvkm_timer_alarm(tmr, 1000000000ULL, alarm); } void nvkm_therm_program_alarms_polling(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; - - nv_debug(therm, - "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", - sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis, - sensor->thrs_down_clock.temp, - sensor->thrs_down_clock.hysteresis, - sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis, - sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis); - - alarm_timer_callback(&priv->sensor.therm_poll_alarm); + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; + + nvkm_debug(&therm->subdev, + "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", + sensor->thrs_fan_boost.temp, + sensor->thrs_fan_boost.hysteresis, + sensor->thrs_down_clock.temp, + sensor->thrs_down_clock.hysteresis, + sensor->thrs_critical.temp, + sensor->thrs_critical.hysteresis, + sensor->thrs_shutdown.temp, + sensor->thrs_shutdown.hysteresis); + + alarm_timer_callback(&therm->sensor.therm_poll_alarm); } int nvkm_therm_sensor_init(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - priv->sensor.program_alarms(therm); + therm->func->program_alarms(therm); return 0; } int nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_timer *ptimer = nvkm_timer(therm); - + struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm); + nvkm_timer_alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); return 0; } @@ -235,24 +229,24 @@ nvkm_therm_sensor_preinit(struct nvkm_therm *therm) { const char *sensor_avail = "yes"; - if (therm->temp_get(therm) < 0) + if (therm->func->temp_get(therm) < 0) sensor_avail = "no"; - nv_info(therm, "internal sensor: %s\n", sensor_avail); + nvkm_debug(&therm->subdev, "internal sensor: %s\n", sensor_avail); } int nvkm_therm_sensor_ctor(struct nvkm_therm *therm) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_bios *bios = nvkm_bios(therm); + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_bios *bios = subdev->device->bios; - nvkm_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback); + nvkm_alarm_init(&therm->sensor.therm_poll_alarm, alarm_timer_callback); nvkm_therm_temp_set_defaults(therm); if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, - &priv->bios_sensor)) - nv_error(therm, "nvbios_therm_sensor_parse failed\n"); + &therm->bios_sensor)) + nvkm_error(subdev, "nvbios_therm_sensor_parse failed\n"); nvkm_therm_temp_safety_checks(therm); return 0; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild index d1d38b4ba..e436f0ffe 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild @@ -1,3 +1,5 @@ nvkm-y += nvkm/subdev/timer/base.o nvkm-y += nvkm/subdev/timer/nv04.o +nvkm-y += nvkm/subdev/timer/nv40.o +nvkm-y += nvkm/subdev/timer/nv41.o nvkm-y += nvkm/subdev/timer/gk20a.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index d894061ce..d4dae1f12 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -21,73 +21,131 @@ * * Authors: Ben Skeggs */ -#include <subdev/timer.h> +#include "priv.h" -bool -nvkm_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) +u64 +nvkm_timer_read(struct nvkm_timer *tmr) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - u64 time0; - - time0 = ptimer->read(ptimer); - do { - if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nv_rd32(obj, addr) & mask) == data) - return true; - } else { - if ((nv_ro32(obj, addr) & mask) == data) - return true; - } - } while (ptimer->read(ptimer) - time0 < nsec); + return tmr->func->read(tmr); +} + +void +nvkm_timer_alarm_trigger(struct nvkm_timer *tmr) +{ + struct nvkm_alarm *alarm, *atemp; + unsigned long flags; + LIST_HEAD(exec); + + /* move any due alarms off the pending list */ + spin_lock_irqsave(&tmr->lock, flags); + list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) { + if (alarm->timestamp <= nvkm_timer_read(tmr)) + list_move_tail(&alarm->head, &exec); + } - return false; + /* reschedule interrupt for next alarm time */ + if (!list_empty(&tmr->alarms)) { + alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head); + tmr->func->alarm_init(tmr, alarm->timestamp); + } else { + tmr->func->alarm_fini(tmr); + } + spin_unlock_irqrestore(&tmr->lock, flags); + + /* execute any pending alarm handlers */ + list_for_each_entry_safe(alarm, atemp, &exec, head) { + list_del_init(&alarm->head); + alarm->func(alarm); + } } -bool -nvkm_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) +void +nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - u64 time0; - - time0 = ptimer->read(ptimer); - do { - if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nv_rd32(obj, addr) & mask) != data) - return true; - } else { - if ((nv_ro32(obj, addr) & mask) != data) - return true; + struct nvkm_alarm *list; + unsigned long flags; + + alarm->timestamp = nvkm_timer_read(tmr) + nsec; + + /* append new alarm to list, in soonest-alarm-first order */ + spin_lock_irqsave(&tmr->lock, flags); + if (!nsec) { + if (!list_empty(&alarm->head)) + list_del(&alarm->head); + } else { + list_for_each_entry(list, &tmr->alarms, head) { + if (list->timestamp > alarm->timestamp) + break; } - } while (ptimer->read(ptimer) - time0 < nsec); + list_add_tail(&alarm->head, &list->head); + } + spin_unlock_irqrestore(&tmr->lock, flags); - return false; + /* process pending alarms */ + nvkm_timer_alarm_trigger(tmr); } -bool -nvkm_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data) +void +nvkm_timer_alarm_cancel(struct nvkm_timer *tmr, struct nvkm_alarm *alarm) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - u64 time0; + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); + list_del_init(&alarm->head); + spin_unlock_irqrestore(&tmr->lock, flags); +} - time0 = ptimer->read(ptimer); - do { - if (func(data) == true) - return true; - } while (ptimer->read(ptimer) - time0 < nsec); +static void +nvkm_timer_intr(struct nvkm_subdev *subdev) +{ + struct nvkm_timer *tmr = nvkm_timer(subdev); + tmr->func->intr(tmr); +} - return false; +static int +nvkm_timer_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_timer *tmr = nvkm_timer(subdev); + tmr->func->alarm_fini(tmr); + return 0; } -void -nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm) +static int +nvkm_timer_init(struct nvkm_subdev *subdev) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - ptimer->alarm(ptimer, nsec, alarm); + struct nvkm_timer *tmr = nvkm_timer(subdev); + if (tmr->func->init) + tmr->func->init(tmr); + tmr->func->time(tmr, ktime_to_ns(ktime_get())); + nvkm_timer_alarm_trigger(tmr); + return 0; } -void -nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm) +static void * +nvkm_timer_dtor(struct nvkm_subdev *subdev) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - ptimer->alarm_cancel(ptimer, alarm); + return nvkm_timer(subdev); +} + +static const struct nvkm_subdev_func +nvkm_timer = { + .dtor = nvkm_timer_dtor, + .init = nvkm_timer_init, + .fini = nvkm_timer_fini, + .intr = nvkm_timer_intr, +}; + +int +nvkm_timer_new_(const struct nvkm_timer_func *func, struct nvkm_device *device, + int index, struct nvkm_timer **ptmr) +{ + struct nvkm_timer *tmr; + + if (!(tmr = *ptmr = kzalloc(sizeof(*tmr), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_timer, device, index, 0, &tmr->subdev); + tmr->func = func; + INIT_LIST_HEAD(&tmr->alarms); + spin_lock_init(&tmr->lock); + return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c index 80e38063d..9ed5f6491 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c @@ -21,36 +21,19 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -static int -gk20a_timer_init(struct nvkm_object *object) -{ - struct nv04_timer_priv *priv = (void *)object; - u32 hi = upper_32_bits(priv->suspend_time); - u32 lo = lower_32_bits(priv->suspend_time); - int ret; - - ret = nvkm_timer_init(&priv->base); - if (ret) - return ret; - - nv_debug(priv, "time low : 0x%08x\n", lo); - nv_debug(priv, "time high : 0x%08x\n", hi); +static const struct nvkm_timer_func +gk20a_timer = { + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; - /* restore the time before suspend */ - nv_wr32(priv, NV04_PTIMER_TIME_1, hi); - nv_wr32(priv, NV04_PTIMER_TIME_0, lo); - return 0; +int +gk20a_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&gk20a_timer, device, index, ptmr); } - -struct nvkm_oclass -gk20a_timer_oclass = { - .handle = NV_SUBDEV(TIMER, 0xff), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_timer_ctor, - .dtor = nv04_timer_dtor, - .init = gk20a_timer_init, - .fini = nv04_timer_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c index 6b7facbe5..7b9ce87f0 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c @@ -21,165 +21,92 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" +#include "regsnv04.h" -#include <core/device.h> - -static u64 -nv04_timer_read(struct nvkm_timer *ptimer) +void +nv04_timer_time(struct nvkm_timer *tmr, u64 time) { - struct nv04_timer_priv *priv = (void *)ptimer; - u32 hi, lo; + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 hi = upper_32_bits(time); + u32 lo = lower_32_bits(time); - do { - hi = nv_rd32(priv, NV04_PTIMER_TIME_1); - lo = nv_rd32(priv, NV04_PTIMER_TIME_0); - } while (hi != nv_rd32(priv, NV04_PTIMER_TIME_1)); + nvkm_debug(subdev, "time low : %08x\n", lo); + nvkm_debug(subdev, "time high : %08x\n", hi); - return ((u64)hi << 32 | lo); + nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); + nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); } -static void -nv04_timer_alarm_trigger(struct nvkm_timer *ptimer) +u64 +nv04_timer_read(struct nvkm_timer *tmr) { - struct nv04_timer_priv *priv = (void *)ptimer; - struct nvkm_alarm *alarm, *atemp; - unsigned long flags; - LIST_HEAD(exec); - - /* move any due alarms off the pending list */ - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry_safe(alarm, atemp, &priv->alarms, head) { - if (alarm->timestamp <= ptimer->read(ptimer)) - list_move_tail(&alarm->head, &exec); - } + struct nvkm_device *device = tmr->subdev.device; + u32 hi, lo; - /* reschedule interrupt for next alarm time */ - if (!list_empty(&priv->alarms)) { - alarm = list_first_entry(&priv->alarms, typeof(*alarm), head); - nv_wr32(priv, NV04_PTIMER_ALARM_0, alarm->timestamp); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000001); - } else { - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); - } - spin_unlock_irqrestore(&priv->lock, flags); + do { + hi = nvkm_rd32(device, NV04_PTIMER_TIME_1); + lo = nvkm_rd32(device, NV04_PTIMER_TIME_0); + } while (hi != nvkm_rd32(device, NV04_PTIMER_TIME_1)); - /* execute any pending alarm handlers */ - list_for_each_entry_safe(alarm, atemp, &exec, head) { - list_del_init(&alarm->head); - alarm->func(alarm); - } + return ((u64)hi << 32 | lo); } -static void -nv04_timer_alarm(struct nvkm_timer *ptimer, u64 time, struct nvkm_alarm *alarm) +void +nv04_timer_alarm_fini(struct nvkm_timer *tmr) { - struct nv04_timer_priv *priv = (void *)ptimer; - struct nvkm_alarm *list; - unsigned long flags; - - alarm->timestamp = ptimer->read(ptimer) + time; - - /* append new alarm to list, in soonest-alarm-first order */ - spin_lock_irqsave(&priv->lock, flags); - if (!time) { - if (!list_empty(&alarm->head)) - list_del(&alarm->head); - } else { - list_for_each_entry(list, &priv->alarms, head) { - if (list->timestamp > alarm->timestamp) - break; - } - list_add_tail(&alarm->head, &list->head); - } - spin_unlock_irqrestore(&priv->lock, flags); - - /* process pending alarms */ - nv04_timer_alarm_trigger(ptimer); + struct nvkm_device *device = tmr->subdev.device; + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); } -static void -nv04_timer_alarm_cancel(struct nvkm_timer *ptimer, struct nvkm_alarm *alarm) +void +nv04_timer_alarm_init(struct nvkm_timer *tmr, u32 time) { - struct nv04_timer_priv *priv = (void *)ptimer; - unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - list_del_init(&alarm->head); - spin_unlock_irqrestore(&priv->lock, flags); + struct nvkm_device *device = tmr->subdev.device; + nvkm_wr32(device, NV04_PTIMER_ALARM_0, time); + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); } -static void -nv04_timer_intr(struct nvkm_subdev *subdev) +void +nv04_timer_intr(struct nvkm_timer *tmr) { - struct nv04_timer_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, NV04_PTIMER_INTR_0); + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0); if (stat & 0x00000001) { - nv04_timer_alarm_trigger(&priv->base); - nv_wr32(priv, NV04_PTIMER_INTR_0, 0x00000001); + nvkm_timer_alarm_trigger(tmr); + nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001); stat &= ~0x00000001; } if (stat) { - nv_error(priv, "unknown stat 0x%08x\n", stat); - nv_wr32(priv, NV04_PTIMER_INTR_0, stat); + nvkm_error(subdev, "intr %08x\n", stat); + nvkm_wr32(device, NV04_PTIMER_INTR_0, stat); } } -int -nv04_timer_fini(struct nvkm_object *object, bool suspend) -{ - struct nv04_timer_priv *priv = (void *)object; - if (suspend) - priv->suspend_time = nv04_timer_read(&priv->base); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); - return nvkm_timer_fini(&priv->base, suspend); -} - -static int -nv04_timer_init(struct nvkm_object *object) +static void +nv04_timer_init(struct nvkm_timer *tmr) { - struct nvkm_device *device = nv_device(object); - struct nv04_timer_priv *priv = (void *)object; - u32 m = 1, f, n, d, lo, hi; - int ret; - - ret = nvkm_timer_init(&priv->base); - if (ret) - return ret; + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 f = 0; /*XXX: nvclk */ + u32 n, d; /* aim for 31.25MHz, which gives us nanosecond timestamps */ d = 1000000 / 32; - - /* determine base clock for timer source */ -#if 0 /*XXX*/ - if (device->chipset < 0x40) { - n = nvkm_hw_get_clock(device, PLL_CORE); - } else -#endif - if (device->chipset <= 0x40) { - /*XXX: figure this out */ - f = -1; - n = 0; - } else { - f = device->crystal; - n = f; - while (n < (d * 2)) { - n += (n / m); - m++; - } - - nv_wr32(priv, 0x009220, m - 1); - } - - if (!n) { - nv_warn(priv, "unknown input clock freq\n"); - if (!nv_rd32(priv, NV04_PTIMER_NUMERATOR) || - !nv_rd32(priv, NV04_PTIMER_DENOMINATOR)) { - nv_wr32(priv, NV04_PTIMER_NUMERATOR, 1); - nv_wr32(priv, NV04_PTIMER_DENOMINATOR, 1); + n = f; + + if (!f) { + n = nvkm_rd32(device, NV04_PTIMER_NUMERATOR); + d = nvkm_rd32(device, NV04_PTIMER_DENOMINATOR); + if (!n || !d) { + n = 1; + d = 1; } - return 0; + nvkm_warn(subdev, "unknown input clock freq\n"); } /* reduce ratio to acceptable values */ @@ -198,65 +125,27 @@ nv04_timer_init(struct nvkm_object *object) d >>= 1; } - /* restore the time before suspend */ - lo = priv->suspend_time; - hi = (priv->suspend_time >> 32); + nvkm_debug(subdev, "input frequency : %dHz\n", f); + nvkm_debug(subdev, "numerator : %08x\n", n); + nvkm_debug(subdev, "denominator : %08x\n", d); + nvkm_debug(subdev, "timer frequency : %dHz\n", f * d / n); - nv_debug(priv, "input frequency : %dHz\n", f); - nv_debug(priv, "input multiplier: %d\n", m); - nv_debug(priv, "numerator : 0x%08x\n", n); - nv_debug(priv, "denominator : 0x%08x\n", d); - nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n); - nv_debug(priv, "time low : 0x%08x\n", lo); - nv_debug(priv, "time high : 0x%08x\n", hi); - - nv_wr32(priv, NV04_PTIMER_NUMERATOR, n); - nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d); - nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); - nv_wr32(priv, NV04_PTIMER_TIME_1, hi); - nv_wr32(priv, NV04_PTIMER_TIME_0, lo); - return 0; + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); } -void -nv04_timer_dtor(struct nvkm_object *object) -{ - struct nv04_timer_priv *priv = (void *)object; - return nvkm_timer_destroy(&priv->base); -} +static const struct nvkm_timer_func +nv04_timer = { + .init = nv04_timer_init, + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; int -nv04_timer_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) { - struct nv04_timer_priv *priv; - int ret; - - ret = nvkm_timer_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.base.intr = nv04_timer_intr; - priv->base.read = nv04_timer_read; - priv->base.alarm = nv04_timer_alarm; - priv->base.alarm_cancel = nv04_timer_alarm_cancel; - priv->suspend_time = 0; - - INIT_LIST_HEAD(&priv->alarms); - spin_lock_init(&priv->lock); - return 0; + return nvkm_timer_new_(&nv04_timer, device, index, ptmr); } - -struct nvkm_oclass -nv04_timer_oclass = { - .handle = NV_SUBDEV(TIMER, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_timer_ctor, - .dtor = nv04_timer_dtor, - .init = nv04_timer_init, - .fini = nv04_timer_fini, - } -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h deleted file mode 100644 index 89996a982..000000000 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __NVKM_TIMER_NV04_H__ -#define __NVKM_TIMER_NV04_H__ -#include "priv.h" - -#define NV04_PTIMER_INTR_0 0x009100 -#define NV04_PTIMER_INTR_EN_0 0x009140 -#define NV04_PTIMER_NUMERATOR 0x009200 -#define NV04_PTIMER_DENOMINATOR 0x009210 -#define NV04_PTIMER_TIME_0 0x009400 -#define NV04_PTIMER_TIME_1 0x009410 -#define NV04_PTIMER_ALARM_0 0x009420 - -struct nv04_timer_priv { - struct nvkm_timer base; - struct list_head alarms; - spinlock_t lock; - u64 suspend_time; -}; - -int nv04_timer_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv04_timer_dtor(struct nvkm_object *); -int nv04_timer_fini(struct nvkm_object *, bool); -#endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c new file mode 100644 index 000000000..bb99a152f --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c @@ -0,0 +1,88 @@ +/* + * 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 "regsnv04.h" + +static void +nv40_timer_init(struct nvkm_timer *tmr) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 f = 0; /*XXX: figure this out */ + u32 n, d; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + n = f; + + if (!f) { + n = nvkm_rd32(device, NV04_PTIMER_NUMERATOR); + d = nvkm_rd32(device, NV04_PTIMER_DENOMINATOR); + if (!n || !d) { + n = 1; + d = 1; + } + nvkm_warn(subdev, "unknown input clock freq\n"); + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; + } + + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + nvkm_debug(subdev, "input frequency : %dHz\n", f); + nvkm_debug(subdev, "numerator : %08x\n", n); + nvkm_debug(subdev, "denominator : %08x\n", d); + nvkm_debug(subdev, "timer frequency : %dHz\n", f * d / n); + + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); +} + +static const struct nvkm_timer_func +nv40_timer = { + .init = nv40_timer_init, + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; + +int +nv40_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&nv40_timer, device, index, ptmr); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c new file mode 100644 index 000000000..3cf9ec1b1 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c @@ -0,0 +1,85 @@ +/* + * 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 "regsnv04.h" + +static void +nv41_timer_init(struct nvkm_timer *tmr) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 f = device->crystal; + u32 m = 1, n, d; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + n = f; + + while (n < (d * 2)) { + n += (n / m); + m++; + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; + } + + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + nvkm_debug(subdev, "input frequency : %dHz\n", f); + nvkm_debug(subdev, "input multiplier: %d\n", m); + nvkm_debug(subdev, "numerator : %08x\n", n); + nvkm_debug(subdev, "denominator : %08x\n", d); + nvkm_debug(subdev, "timer frequency : %dHz\n", (f * m) * d / n); + + nvkm_wr32(device, 0x009220, m - 1); + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); +} + +static const struct nvkm_timer_func +nv41_timer = { + .init = nv41_timer_init, + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; + +int +nv41_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&nv41_timer, device, index, ptmr); +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h index 08e29a3da..f820ca2ae 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h @@ -1,4 +1,26 @@ #ifndef __NVKM_TIMER_PRIV_H__ #define __NVKM_TIMER_PRIV_H__ +#define nvkm_timer(p) container_of((p), struct nvkm_timer, subdev) #include <subdev/timer.h> + +int nvkm_timer_new_(const struct nvkm_timer_func *, struct nvkm_device *, + int index, struct nvkm_timer **); + +struct nvkm_timer_func { + void (*init)(struct nvkm_timer *); + void (*intr)(struct nvkm_timer *); + u64 (*read)(struct nvkm_timer *); + void (*time)(struct nvkm_timer *, u64 time); + void (*alarm_init)(struct nvkm_timer *, u32 time); + void (*alarm_fini)(struct nvkm_timer *); +}; + +void nvkm_timer_alarm_trigger(struct nvkm_timer *); + +void nv04_timer_fini(struct nvkm_timer *); +void nv04_timer_intr(struct nvkm_timer *); +void nv04_timer_time(struct nvkm_timer *, u64); +u64 nv04_timer_read(struct nvkm_timer *); +void nv04_timer_alarm_init(struct nvkm_timer *, u32); +void nv04_timer_alarm_fini(struct nvkm_timer *); #endif diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h new file mode 100644 index 000000000..10bef85b4 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h @@ -0,0 +1,7 @@ +#define NV04_PTIMER_INTR_0 0x009100 +#define NV04_PTIMER_INTR_EN_0 0x009140 +#define NV04_PTIMER_NUMERATOR 0x009200 +#define NV04_PTIMER_DENOMINATOR 0x009210 +#define NV04_PTIMER_TIME_0 0x009400 +#define NV04_PTIMER_TIME_1 0x009410 +#define NV04_PTIMER_ALARM_0 0x009420 diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild index 6b46ff421..b035c6e28 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild @@ -1,4 +1,5 @@ nvkm-y += nvkm/subdev/volt/base.o nvkm-y += nvkm/subdev/volt/gpio.o nvkm-y += nvkm/subdev/volt/nv40.o +nvkm-y += nvkm/subdev/volt/gk104.o nvkm-y += nvkm/subdev/volt/gk20a.o diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 39f15803f..50b5649ad 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -21,49 +21,54 @@ * * Authors: Ben Skeggs */ -#include <subdev/volt.h> +#include "priv.h" + #include <subdev/bios.h> #include <subdev/bios/vmap.h> #include <subdev/bios/volt.h> -static int +int nvkm_volt_get(struct nvkm_volt *volt) { - if (volt->vid_get) { - int ret = volt->vid_get(volt), i; - if (ret >= 0) { - for (i = 0; i < volt->vid_nr; i++) { - if (volt->vid[i].vid == ret) - return volt->vid[i].uv; - } - ret = -EINVAL; + int ret, i; + + if (volt->func->volt_get) + return volt->func->volt_get(volt); + + ret = volt->func->vid_get(volt); + if (ret >= 0) { + for (i = 0; i < volt->vid_nr; i++) { + if (volt->vid[i].vid == ret) + return volt->vid[i].uv; } - return ret; + ret = -EINVAL; } - return -ENODEV; + return ret; } static int nvkm_volt_set(struct nvkm_volt *volt, u32 uv) { - if (volt->vid_set) { - int i, ret = -EINVAL; - for (i = 0; i < volt->vid_nr; i++) { - if (volt->vid[i].uv == uv) { - ret = volt->vid_set(volt, volt->vid[i].vid); - nv_debug(volt, "set %duv: %d\n", uv, ret); - break; - } + struct nvkm_subdev *subdev = &volt->subdev; + int i, ret = -EINVAL; + + if (volt->func->volt_set) + return volt->func->volt_set(volt, uv); + + for (i = 0; i < volt->vid_nr; i++) { + if (volt->vid[i].uv == uv) { + ret = volt->func->vid_set(volt, volt->vid[i].vid); + nvkm_debug(subdev, "set %duv: %d\n", uv, ret); + break; } - return ret; } - return -ENODEV; + return ret; } static int nvkm_volt_map(struct nvkm_volt *volt, u8 id) { - struct nvkm_bios *bios = nvkm_bios(volt); + struct nvkm_bios *bios = volt->subdev.device->bios; struct nvbios_vmap_entry info; u8 ver, len; u16 vmap; @@ -82,10 +87,15 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id) return id ? id * 10000 : -ENODEV; } -static int +int nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) { - int ret = nvkm_volt_map(volt, id); + int ret; + + if (volt->func->set_id) + return volt->func->set_id(volt, id, condition); + + ret = nvkm_volt_map(volt, id); if (ret >= 0) { int prev = nvkm_volt_get(volt); if (!condition || prev < 0 || @@ -134,51 +144,41 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) } } -int -_nvkm_volt_init(struct nvkm_object *object) +static int +nvkm_volt_init(struct nvkm_subdev *subdev) { - struct nvkm_volt *volt = (void *)object; - int ret; - - ret = nvkm_subdev_init(&volt->base); - if (ret) - return ret; - - ret = volt->get(volt); + struct nvkm_volt *volt = nvkm_volt(subdev); + int ret = nvkm_volt_get(volt); if (ret < 0) { if (ret != -ENODEV) - nv_debug(volt, "current voltage unknown\n"); + nvkm_debug(subdev, "current voltage unknown\n"); return 0; } - - nv_info(volt, "GPU voltage: %duv\n", ret); + nvkm_debug(subdev, "current voltage: %duv\n", ret); return 0; } -void -_nvkm_volt_dtor(struct nvkm_object *object) +static void * +nvkm_volt_dtor(struct nvkm_subdev *subdev) { - struct nvkm_volt *volt = (void *)object; - nvkm_subdev_destroy(&volt->base); + return nvkm_volt(subdev); } -int -nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) -{ - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_volt *volt; - int ret, i; +static const struct nvkm_subdev_func +nvkm_volt = { + .dtor = nvkm_volt_dtor, + .init = nvkm_volt_init, +}; - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "VOLT", - "voltage", length, pobject); - volt = *pobject; - if (ret) - return ret; +void +nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, + int index, struct nvkm_volt *volt) +{ + struct nvkm_bios *bios = device->bios; + int i; - volt->get = nvkm_volt_get; - volt->set = nvkm_volt_set; - volt->set_id = nvkm_volt_set_id; + nvkm_subdev_ctor(&nvkm_volt, device, index, 0, &volt->subdev); + volt->func = func; /* Assuming the non-bios device should build the voltage table later */ if (bios) @@ -186,19 +186,18 @@ nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (volt->vid_nr) { for (i = 0; i < volt->vid_nr; i++) { - nv_debug(volt, "VID %02x: %duv\n", - volt->vid[i].vid, volt->vid[i].uv); - } - - /*XXX: this is an assumption.. there probably exists boards - * out there with i2c-connected voltage controllers too.. - */ - ret = nvkm_voltgpio_init(volt); - if (ret == 0) { - volt->vid_get = nvkm_voltgpio_get; - volt->vid_set = nvkm_voltgpio_set; + nvkm_debug(&volt->subdev, "VID %02x: %duv\n", + volt->vid[i].vid, volt->vid[i].uv); } } +} - return ret; +int +nvkm_volt_new_(const struct nvkm_volt_func *func, struct nvkm_device *device, + int index, struct nvkm_volt **pvolt) +{ + if (!(*pvolt = kzalloc(sizeof(**pvolt), GFP_KERNEL))) + return -ENOMEM; + nvkm_volt_ctor(func, device, index, *pvolt); + return 0; } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c new file mode 100644 index 000000000..b735173a1 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c @@ -0,0 +1,119 @@ +/* + * Copyright 2015 Martin Peres + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Martin Peres + */ +#include "priv.h" + +#include <subdev/volt.h> +#include <subdev/gpio.h> +#include <subdev/bios.h> +#include <subdev/bios/volt.h> + +#define gk104_volt(p) container_of((p), struct gk104_volt, base) +struct gk104_volt { + struct nvkm_volt base; + struct nvbios_volt bios; +}; + +int +gk104_volt_get(struct nvkm_volt *base) +{ + struct nvbios_volt *bios = &gk104_volt(base)->bios; + struct nvkm_device *device = base->subdev.device; + u32 div, duty; + + div = nvkm_rd32(device, 0x20340); + duty = nvkm_rd32(device, 0x20344); + + return bios->base + bios->pwm_range * duty / div; +} + +int +gk104_volt_set(struct nvkm_volt *base, u32 uv) +{ + struct nvbios_volt *bios = &gk104_volt(base)->bios; + struct nvkm_device *device = base->subdev.device; + u32 div, duty; + + /* the blob uses this crystal frequency, let's use it too. */ + div = 27648000 / bios->pwm_freq; + duty = (uv - bios->base) * div / bios->pwm_range; + + nvkm_wr32(device, 0x20340, div); + nvkm_wr32(device, 0x20344, 0x80000000 | duty); + + return 0; +} + +static const struct nvkm_volt_func +gk104_volt_pwm = { + .volt_get = gk104_volt_get, + .volt_set = gk104_volt_set, +}, gk104_volt_gpio = { + .vid_get = nvkm_voltgpio_get, + .vid_set = nvkm_voltgpio_set, +}; + +int +gk104_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) +{ + const struct nvkm_volt_func *volt_func = &gk104_volt_gpio; + struct dcb_gpio_func gpio; + struct nvbios_volt bios; + struct gk104_volt *volt; + u8 ver, hdr, cnt, len; + const char *mode; + + if (!nvbios_volt_parse(device->bios, &ver, &hdr, &cnt, &len, &bios)) + return 0; + + if (!nvkm_gpio_find(device->gpio, 0, DCB_GPIO_VID_PWM, 0xff, &gpio) && + bios.type == NVBIOS_VOLT_PWM) { + volt_func = &gk104_volt_pwm; + } + + if (!(volt = kzalloc(sizeof(*volt), GFP_KERNEL))) + return -ENOMEM; + nvkm_volt_ctor(volt_func, device, index, &volt->base); + *pvolt = &volt->base; + volt->bios = bios; + + /* now that we have a subdev, we can show an error if we found through + * the voltage table that we were supposed to use the PWN mode but we + * did not find the right GPIO for it. + */ + if (bios.type == NVBIOS_VOLT_PWM && volt_func != &gk104_volt_pwm) { + nvkm_error(&volt->base.subdev, + "Type mismatch between the voltage table type and " + "the GPIO table. Fallback to GPIO mode.\n"); + } + + if (volt_func == &gk104_volt_gpio) { + nvkm_voltgpio_init(&volt->base); + mode = "GPIO"; + } else + mode = "PWM"; + + nvkm_debug(&volt->base.subdev, "Using %s mode\n", mode); + + return 0; +} diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 871fd5101..fd56c6476 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -19,10 +19,10 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <subdev/volt.h> -#ifdef __KERNEL__ -#include <nouveau_platform.h> -#endif +#define gk20a_volt(p) container_of((p), struct gk20a_volt, base) +#include "priv.h" + +#include <core/tegra.h> struct cvb_coef { int c0; @@ -33,7 +33,7 @@ struct cvb_coef { int c5; }; -struct gk20a_volt_priv { +struct gk20a_volt { struct nvkm_volt base; struct regulator *vdd; }; @@ -101,43 +101,45 @@ gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo) } static int -gk20a_volt_vid_get(struct nvkm_volt *volt) +gk20a_volt_vid_get(struct nvkm_volt *base) { - struct gk20a_volt_priv *priv = (void *)volt; + struct gk20a_volt *volt = gk20a_volt(base); int i, uv; - uv = regulator_get_voltage(priv->vdd); + uv = regulator_get_voltage(volt->vdd); - for (i = 0; i < volt->vid_nr; i++) - if (volt->vid[i].uv >= uv) + for (i = 0; i < volt->base.vid_nr; i++) + if (volt->base.vid[i].uv >= uv) return i; return -EINVAL; } static int -gk20a_volt_vid_set(struct nvkm_volt *volt, u8 vid) +gk20a_volt_vid_set(struct nvkm_volt *base, u8 vid) { - struct gk20a_volt_priv *priv = (void *)volt; + struct gk20a_volt *volt = gk20a_volt(base); + struct nvkm_subdev *subdev = &volt->base.subdev; - nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv); - return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000); + nvkm_debug(subdev, "set voltage as %duv\n", volt->base.vid[vid].uv); + return regulator_set_voltage(volt->vdd, volt->base.vid[vid].uv, 1200000); } static int -gk20a_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) +gk20a_volt_set_id(struct nvkm_volt *base, u8 id, int condition) { - struct gk20a_volt_priv *priv = (void *)volt; - int prev_uv = regulator_get_voltage(priv->vdd); - int target_uv = volt->vid[id].uv; + struct gk20a_volt *volt = gk20a_volt(base); + struct nvkm_subdev *subdev = &volt->base.subdev; + int prev_uv = regulator_get_voltage(volt->vdd); + int target_uv = volt->base.vid[id].uv; int ret; - nv_debug(volt, "prev=%d, target=%d, condition=%d\n", - prev_uv, target_uv, condition); + nvkm_debug(subdev, "prev=%d, target=%d, condition=%d\n", + prev_uv, target_uv, condition); if (!condition || (condition < 0 && target_uv < prev_uv) || (condition > 0 && target_uv > prev_uv)) { - ret = gk20a_volt_vid_set(volt, volt->vid[id].vid); + ret = gk20a_volt_vid_set(&volt->base, volt->base.vid[id].vid); } else { ret = 0; } @@ -145,53 +147,42 @@ gk20a_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) return ret; } -static int -gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_volt_func +gk20a_volt = { + .vid_get = gk20a_volt_vid_get, + .vid_set = gk20a_volt_vid_set, + .set_id = gk20a_volt_set_id, +}; + +int +gk20a_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) { - struct gk20a_volt_priv *priv; - struct nvkm_volt *volt; - struct nouveau_platform_device *plat; - int i, ret, uv; - - ret = nvkm_volt_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - volt = &priv->base; - - plat = nv_device_to_platform(nv_device(parent)); - - uv = regulator_get_voltage(plat->gpu->vdd); - nv_info(priv, "The default voltage is %duV\n", uv); - - priv->vdd = plat->gpu->vdd; - priv->base.vid_get = gk20a_volt_vid_get; - priv->base.vid_set = gk20a_volt_vid_set; - priv->base.set_id = gk20a_volt_set_id; - - volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef); - nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr); - for (i = 0; i < volt->vid_nr; i++) { - volt->vid[i].vid = i; - volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], - plat->gpu_speedo); - nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid, - volt->vid[i].uv); + struct nvkm_device_tegra *tdev = device->func->tegra(device); + struct gk20a_volt *volt; + int i, uv; + + if (!(volt = kzalloc(sizeof(*volt), GFP_KERNEL))) + return -ENOMEM; + + nvkm_volt_ctor(&gk20a_volt, device, index, &volt->base); + *pvolt = &volt->base; + + uv = regulator_get_voltage(tdev->vdd); + nvkm_info(&volt->base.subdev, "The default voltage is %duV\n", uv); + + volt->vdd = tdev->vdd; + + volt->base.vid_nr = ARRAY_SIZE(gk20a_cvb_coef); + nvkm_debug(&volt->base.subdev, "%s - vid_nr = %d\n", __func__, + volt->base.vid_nr); + for (i = 0; i < volt->base.vid_nr; i++) { + volt->base.vid[i].vid = i; + volt->base.vid[i].uv = + gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], + tdev->gpu_speedo); + nvkm_debug(&volt->base.subdev, "%2d: vid=%d, uv=%d\n", i, + volt->base.vid[i].vid, volt->base.vid[i].uv); } return 0; } - -struct nvkm_oclass -gk20a_volt_oclass = { - .handle = NV_SUBDEV(VOLT, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_volt_ctor, - .dtor = _nvkm_volt_dtor, - .init = _nvkm_volt_init, - .fini = _nvkm_volt_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c index b778deb32..d2bac1d77 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c @@ -34,13 +34,13 @@ static const u8 tags[] = { int nvkm_voltgpio_get(struct nvkm_volt *volt) { - struct nvkm_gpio *gpio = nvkm_gpio(volt); + struct nvkm_gpio *gpio = volt->subdev.device->gpio; u8 vid = 0; int i; for (i = 0; i < ARRAY_SIZE(tags); i++) { if (volt->vid_mask & (1 << i)) { - int ret = gpio->get(gpio, 0, tags[i], 0xff); + int ret = nvkm_gpio_get(gpio, 0, tags[i], 0xff); if (ret < 0) return ret; vid |= ret << i; @@ -53,12 +53,12 @@ nvkm_voltgpio_get(struct nvkm_volt *volt) int nvkm_voltgpio_set(struct nvkm_volt *volt, u8 vid) { - struct nvkm_gpio *gpio = nvkm_gpio(volt); + struct nvkm_gpio *gpio = volt->subdev.device->gpio; int i; for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) { if (volt->vid_mask & (1 << i)) { - int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1); + int ret = nvkm_gpio_set(gpio, 0, tags[i], 0xff, vid & 1); if (ret < 0) return ret; } @@ -70,7 +70,8 @@ nvkm_voltgpio_set(struct nvkm_volt *volt, u8 vid) int nvkm_voltgpio_init(struct nvkm_volt *volt) { - struct nvkm_gpio *gpio = nvkm_gpio(volt); + struct nvkm_subdev *subdev = &volt->subdev; + struct nvkm_gpio *gpio = subdev->device->gpio; struct dcb_gpio_func func; int i; @@ -82,11 +83,11 @@ nvkm_voltgpio_init(struct nvkm_volt *volt) */ for (i = 0; i < ARRAY_SIZE(tags); i++) { if (volt->vid_mask & (1 << i)) { - int ret = gpio->find(gpio, 0, tags[i], 0xff, &func); + int ret = nvkm_gpio_find(gpio, 0, tags[i], 0xff, &func); if (ret) { if (ret != -ENOENT) return ret; - nv_debug(volt, "VID bit %d has no GPIO\n", i); + nvkm_debug(subdev, "VID bit %d has no GPIO\n", i); volt->vid_mask &= ~(1 << i); } } diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c index 0ac5a3f8c..23409387a 100644 --- a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c @@ -21,35 +21,24 @@ * * Authors: Ben Skeggs */ -#include <subdev/volt.h> +#include "priv.h" -struct nv40_volt_priv { - struct nvkm_volt base; +static const struct nvkm_volt_func +nv40_volt = { + .vid_get = nvkm_voltgpio_get, + .vid_set = nvkm_voltgpio_set, }; -static int -nv40_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv40_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) { - struct nv40_volt_priv *priv; + struct nvkm_volt *volt; int ret; - ret = nvkm_volt_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_volt_new_(&nv40_volt, device, index, &volt); + *pvolt = volt; if (ret) return ret; - return 0; + return nvkm_voltgpio_init(volt); } - -struct nvkm_oclass -nv40_volt_oclass = { - .handle = NV_SUBDEV(VOLT, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_volt_ctor, - .dtor = _nvkm_volt_dtor, - .init = _nvkm_volt_init, - .fini = _nvkm_volt_fini, - }, -}; diff --git a/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h new file mode 100644 index 000000000..d5140d991 --- /dev/null +++ b/kernel/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h @@ -0,0 +1,26 @@ +#ifndef __NVKM_VOLT_PRIV_H__ +#define __NVKM_VOLT_PRIV_H__ +#define nvkm_volt(p) container_of((p), struct nvkm_volt, subdev) +#include <subdev/volt.h> + +void nvkm_volt_ctor(const struct nvkm_volt_func *, struct nvkm_device *, + int index, struct nvkm_volt *); +int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *, + int index, struct nvkm_volt **); + +struct nvkm_volt_func { + int (*volt_get)(struct nvkm_volt *); + int (*volt_set)(struct nvkm_volt *, u32 uv); + int (*vid_get)(struct nvkm_volt *); + int (*vid_set)(struct nvkm_volt *, u8 vid); + int (*set_id)(struct nvkm_volt *, u8 id, int condition); +}; + +int nvkm_voltgpio_init(struct nvkm_volt *); +int nvkm_voltgpio_get(struct nvkm_volt *); +int nvkm_voltgpio_set(struct nvkm_volt *, u8); + +int nvkm_voltpwm_init(struct nvkm_volt *volt); +int nvkm_voltpwm_get(struct nvkm_volt *volt); +int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv); +#endif |