diff options
author | Linus Torvalds | 2015-02-17 00:48:00 +0100 |
---|---|---|
committer | Linus Torvalds | 2015-02-17 00:48:00 +0100 |
commit | 796e1c55717e9a6ff5c81b12289ffa1ffd919b6f (patch) | |
tree | 27ce45cb1227156b72c641dbcbf2b399d23ba63d /drivers/gpu/drm/nouveau/nvkm/subdev/instmem | |
parent | Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/ke... (diff) | |
parent | Merge branch 'drm-next-3.20' of git://people.freedesktop.org/~agd5f/linux int... (diff) | |
download | kernel-qcow2-linux-796e1c55717e9a6ff5c81b12289ffa1ffd919b6f.tar.gz kernel-qcow2-linux-796e1c55717e9a6ff5c81b12289ffa1ffd919b6f.tar.xz kernel-qcow2-linux-796e1c55717e9a6ff5c81b12289ffa1ffd919b6f.zip |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"This is the main drm pull, it has a shared branch with some alsa
crossover but everything should be acked by relevant people.
New drivers:
- ATMEL HLCDC driver
- designware HDMI core support (used in multiple SoCs).
core:
- lots more atomic modesetting work, properties and atomic ioctl
(hidden under option)
- bridge rework allows support for Samsung exynos chromebooks to
work finally.
- some more panels supported
i915:
- atomic plane update support
- DSI uses shared DSI infrastructure
- Skylake basic support is all merged now
- component framework used for i915/snd-hda interactions
- write-combine cpu memory mappings
- engine init code refactored
- full ppgtt enabled where execlists are enabled.
- cherryview rps/gpu turbo and pipe CRC support.
radeon:
- indirect draw support for evergreen/cayman
- SMC and manual fan control for SI/CI
- Displayport audio support
amdkfd:
- SDMA usermode queue support
- replace suballocator usage with more suitable one
- rework for allowing interfacing to more than radeon
nouveau:
- major renaming in prep for later splitting work
- merge arm platform driver into nouveau
- GK20A reclocking support
msm:
- conversion to atomic modesetting
- YUV support for mdp4/5
- eDP support
- hw cursor for mdp5
tegra:
- conversion to atomic modesetting
- better suspend/resume support for child devices
rcar-du:
- interlaced support
imx:
- move to using dw_hdmi shared support
- mode_fixup support
sti:
- DVO support
- HDMI infoframe support
exynos:
- refactoring and cleanup, removed lots of internal unnecessary
abstraction
- exynos7 DECON display controller support
Along with the usual bunch of fixes, cleanups etc"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (724 commits)
drm/radeon: fix voltage setup on hawaii
drm/radeon/dp: Set EDP_CONFIGURATION_SET for bridge chips if necessary
drm/radeon: only enable kv/kb dpm interrupts once v3
drm/radeon: workaround for CP HW bug on CIK
drm/radeon: Don't try to enable write-combining without PAT
drm/radeon: use 0-255 rather than 0-100 for pwm fan range
drm/i915: Clamp efficient frequency to valid range
drm/i915: Really ignore long HPD pulses on eDP
drm/exynos: Add DECON driver
drm/i915: Correct the base value while updating LP_OUTPUT_HOLD in MIPI_PORT_CTRL
drm/i915: Insert a command barrier on BLT/BSD cache flushes
drm/i915: Drop vblank wait from intel_dp_link_down
drm/exynos: fix NULL pointer reference
drm/exynos: remove exynos_plane_dpms
drm/exynos: remove mode property of exynos crtc
drm/exynos: Remove exynos_plane_dpms() call with no effect
drm/i915: Squelch overzealous uncore reset WARN_ON
drm/i915: Take runtime pm reference on hangcheck_info
drm/i915: Correct the IOSF Dev_FN field for IOSF transfers
drm/exynos: fix DMA_ATTR_NO_KERNEL_MAPPING usage
...
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/instmem')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c | 146 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c | 185 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c | 136 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c | 169 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h | 54 |
7 files changed, 730 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild new file mode 100644 index 000000000000..e6f35abe7879 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild @@ -0,0 +1,4 @@ +nvkm-y += nvkm/subdev/instmem/base.o +nvkm-y += nvkm/subdev/instmem/nv04.o +nvkm-y += nvkm/subdev/instmem/nv40.o +nvkm-y += nvkm/subdev/instmem/nv50.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c new file mode 100644 index 000000000000..d16358cc6cbb --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -0,0 +1,146 @@ +/* + * 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/engine.h> + +/****************************************************************************** + * instmem object base implementation + *****************************************************************************/ + +void +_nvkm_instobj_dtor(struct nvkm_object *object) +{ + struct nvkm_instmem *imem = nvkm_instmem(object); + struct nvkm_instobj *iobj = (void *)object; + + mutex_lock(&nv_subdev(imem)->mutex); + list_del(&iobj->head); + mutex_unlock(&nv_subdev(imem)->mutex); + + return nvkm_object_destroy(&iobj->base); +} + +int +nvkm_instobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, int length, void **pobject) +{ + struct nvkm_instmem *imem = nvkm_instmem(parent); + struct nvkm_instobj *iobj; + int ret; + + ret = nvkm_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS, + length, pobject); + iobj = *pobject; + if (ret) + return ret; + + mutex_lock(&imem->base.mutex); + list_add(&iobj->head, &imem->list); + mutex_unlock(&imem->base.mutex); + return 0; +} + +/****************************************************************************** + * 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) +{ + 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); +} + +int +_nvkm_instmem_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_instmem *imem = (void *)object; + struct nvkm_instobj *iobj; + int i, ret = 0; + + 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); + } + mutex_unlock(&imem->base.mutex); + if (ret) + return ret; + } + + return nvkm_subdev_fini(&imem->base, suspend); +} + +int +_nvkm_instmem_init(struct nvkm_object *object) +{ + struct nvkm_instmem *imem = (void *)object; + struct nvkm_instobj *iobj; + int ret, i; + + ret = nvkm_subdev_init(&imem->base); + if (ret) + return ret; + + mutex_lock(&imem->base.mutex); + list_for_each_entry(iobj, &imem->list, head) { + if (iobj->suspend) { + for (i = 0; i < iobj->size; i += 4) + nv_wo32(iobj, i, iobj->suspend[i / 4]); + vfree(iobj->suspend); + iobj->suspend = NULL; + } + } + mutex_unlock(&imem->base.mutex); + return 0; +} + +int +nvkm_instmem_create_(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, int length, void **pobject) +{ + struct nvkm_instmem *imem; + int ret; + + ret = nvkm_subdev_create_(parent, engine, oclass, 0, "INSTMEM", + "instmem", length, pobject); + imem = *pobject; + if (ret) + return ret; + + INIT_LIST_HEAD(&imem->list); + imem->alloc = nvkm_instmem_alloc; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c new file mode 100644 index 000000000000..80614f1b2074 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -0,0 +1,185 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "nv04.h" + +#include <core/ramht.h> + +/****************************************************************************** + * instmem object implementation + *****************************************************************************/ + +static u32 +nv04_instobj_rd32(struct nvkm_object *object, u64 addr) +{ + struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); + struct nv04_instobj_priv *node = (void *)object; + return nv_ro32(priv, node->mem->offset + addr); +} + +static void +nv04_instobj_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); + struct nv04_instobj_priv *node = (void *)object; + nv_wo32(priv, node->mem->offset + addr, data); +} + +static void +nv04_instobj_dtor(struct nvkm_object *object) +{ + struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); + struct nv04_instobj_priv *node = (void *)object; + nvkm_mm_free(&priv->heap, &node->mem); + nvkm_instobj_destroy(&node->base); +} + +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) +{ + struct nv04_instmem_priv *priv = (void *)nvkm_instmem(parent); + struct nv04_instobj_priv *node; + struct nvkm_instobj_args *args = data; + int ret; + + if (!args->align) + args->align = 1; + + ret = nvkm_instobj_create(parent, engine, oclass, &node); + *pobject = nv_object(node); + if (ret) + return ret; + + ret = nvkm_mm_head(&priv->heap, 0, 1, args->size, args->size, + args->align, &node->mem); + if (ret) + return ret; + + node->base.addr = node->mem->offset; + node->base.size = node->mem->length; + return 0; +} + +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) +{ + return nv_rd32(object, 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) +{ + 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); +} + +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) +{ + struct nv04_instmem_priv *priv; + 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; + + ret = nvkm_mm_init(&priv->heap, 0, priv->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); + if (ret) + return ret; + + /* 0x10000-0x18000: reserve for RAMHT */ + ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->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); + if (ret) + return ret; + + /* 0x18800-0x18a00: reserve for RAMRO */ + ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00200, 0, 0, + &priv->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; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h new file mode 100644 index 000000000000..42b6c928047c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h @@ -0,0 +1,36 @@ +#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/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c new file mode 100644 index 000000000000..b42b8588fc0e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -0,0 +1,136 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "nv04.h" + +#include <core/ramht.h> +#include <engine/gr/nv40.h> + +/****************************************************************************** + * instmem subdev implementation + *****************************************************************************/ + +static u32 +nv40_instmem_rd32(struct nvkm_object *object, u64 addr) +{ + struct nv04_instmem_priv *priv = (void *)object; + return ioread32_native(priv->iomem + addr); +} + +static void +nv40_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nv04_instmem_priv *priv = (void *)object; + iowrite32_native(data, priv->iomem + addr); +} + +static int +nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_device *device = nv_device(parent); + struct nv04_instmem_priv *priv; + int ret, bar, vs; + + ret = nvkm_instmem_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + /* map bar */ + if (nv_device_resource_len(device, 2)) + bar = 2; + else + bar = 3; + + 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; + } + + /* 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); + if (ret) + return ret; + + /* 0x00000-0x10000: reserve for probable vbios image */ + ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0, + &priv->vbios); + if (ret) + return ret; + + /* 0x10000-0x18000: reserve for RAMHT */ + ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->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); + 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); + 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; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c new file mode 100644 index 000000000000..8404143f93ee --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -0,0 +1,169 @@ +/* + * 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 <subdev/fb.h> + +struct nv50_instmem_priv { + struct nvkm_instmem base; + spinlock_t lock; + u64 addr; +}; + +struct nv50_instobj_priv { + struct nvkm_instobj base; + struct nvkm_mem *mem; +}; + +/****************************************************************************** + * instmem object implementation + *****************************************************************************/ + +static u32 +nv50_instobj_rd32(struct nvkm_object *object, u64 offset) +{ + 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; + u32 data; + + spin_lock_irqsave(&priv->lock, flags); + if (unlikely(priv->addr != base)) { + nv_wr32(priv, 0x001700, base >> 16); + priv->addr = base; + } + data = nv_rd32(priv, 0x700000 + addr); + spin_unlock_irqrestore(&priv->lock, flags); + return data; +} + +static void +nv50_instobj_wr32(struct nvkm_object *object, 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; + } + nv_wr32(priv, 0x700000 + addr, data); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void +nv50_instobj_dtor(struct nvkm_object *object) +{ + 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); +} + +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) +{ + struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_instobj_args *args = data; + struct nv50_instobj_priv *node; + int ret; + + args->size = max((args->size + 4095) & ~4095, (u32)4096); + args->align = max((args->align + 4095) & ~4095, (u32)4096); + + ret = nvkm_instobj_create(parent, engine, oclass, &node); + *pobject = nv_object(node); + if (ret) + return ret; + + ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem); + if (ret) + return ret; + + node->base.addr = node->mem->offset; + node->base.size = node->mem->size << 12; + node->mem->page_shift = 12; + return 0; +} + +static struct 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) +{ + struct nv50_instmem_priv *priv = (void *)object; + priv->addr = ~0ULL; + return nvkm_instmem_fini(&priv->base, suspend); +} + +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; + + ret = nvkm_instmem_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + spin_lock_init(&priv->lock); + 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/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h new file mode 100644 index 000000000000..b10e292e5607 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -0,0 +1,54 @@ +#ifndef __NVKM_INSTMEM_PRIV_H__ +#define __NVKM_INSTMEM_PRIV_H__ +#include <subdev/instmem.h> + +struct nvkm_instobj_impl { + struct nvkm_oclass base; +}; + +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); +#endif |