diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine')
298 files changed, 26754 insertions, 20782 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild index 6bd3d756f32c..36f724763fde 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild @@ -6,7 +6,7 @@ include $(src)/nvkm/engine/ce/Kbuild include $(src)/nvkm/engine/cipher/Kbuild include $(src)/nvkm/engine/device/Kbuild include $(src)/nvkm/engine/disp/Kbuild -include $(src)/nvkm/engine/dmaobj/Kbuild +include $(src)/nvkm/engine/dma/Kbuild include $(src)/nvkm/engine/fifo/Kbuild include $(src)/nvkm/engine/gr/Kbuild include $(src)/nvkm/engine/mpeg/Kbuild diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c index a0b1fd80fa93..3ef01071f073 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c @@ -22,72 +22,23 @@ * Authors: Ben Skeggs, Ilia Mirkin */ #include <engine/bsp.h> -#include <engine/xtensa.h> -#include <core/engctx.h> - -/******************************************************************************* - * BSP object classes - ******************************************************************************/ - -static struct nvkm_oclass -g84_bsp_sclass[] = { - { 0x74b0, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * BSP context - ******************************************************************************/ - -static struct nvkm_oclass -g84_bsp_cclass = { - .handle = NV_ENGCTX(BSP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_xtensa_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, - }, +#include <nvif/class.h> + +static const struct nvkm_xtensa_func +g84_bsp = { + .pmc_enable = 0x04008000, + .fifo_val = 0x1111, + .unkd28 = 0x90044, + .sclass = { + { -1, -1, NV74_BSP }, + {} + } }; -/******************************************************************************* - * BSP engine/subdev functions - ******************************************************************************/ - -static int -g84_bsp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_bsp_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine) { - struct nvkm_xtensa *priv; - int ret; - - ret = nvkm_xtensa_create(parent, engine, oclass, 0x103000, true, - "PBSP", "bsp", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x04008000; - nv_engine(priv)->cclass = &g84_bsp_cclass; - nv_engine(priv)->sclass = g84_bsp_sclass; - priv->fifo_val = 0x1111; - priv->unkd28 = 0x90044; - return 0; + return nvkm_xtensa_new_(&g84_bsp, device, index, + true, 0x103000, pengine); } - -struct nvkm_oclass -g84_bsp_oclass = { - .handle = NV_ENGINE(BSP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_bsp_ctor, - .dtor = _nvkm_xtensa_dtor, - .init = _nvkm_xtensa_init, - .fini = _nvkm_xtensa_fini, - .rd32 = _nvkm_xtensa_rd32, - .wr32 = _nvkm_xtensa_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc index a558dfa4d76a..6226bcd98ca9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc @@ -24,9 +24,9 @@ */ #ifdef GT215 -.section #gt215_pce_data +.section #gt215_ce_data #else -.section #gf100_pce_data +.section #gf100_ce_data #endif ctx_object: .b32 0 @@ -128,9 +128,9 @@ dispatch_dma: .b16 0x800 0 #ifdef GT215 -.section #gt215_pce_code +.section #gt215_ce_code #else -.section #gf100_pce_code +.section #gf100_ce_code #endif main: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h index d9af6e4e4585..05bb65608dfe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf100_pce_data[] = { +uint32_t gf100_ce_data[] = { /* 0x0000: ctx_object */ 0x00000000, /* 0x0004: ctx_query_address_high */ @@ -171,7 +171,7 @@ uint32_t gf100_pce_data[] = { 0x00000800, }; -uint32_t gf100_pce_code[] = { +uint32_t gf100_ce_code[] = { /* 0x0000: main */ 0x04fe04bd, 0x3517f000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h index f42c0d0d6cee..972281d10f38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gt215_pce_data[] = { +uint32_t gt215_ce_data[] = { /* 0x0000: ctx_object */ 0x00000000, /* 0x0004: ctx_dma */ @@ -183,7 +183,7 @@ uint32_t gt215_pce_data[] = { 0x00000800, }; -uint32_t gt215_pce_code[] = { +uint32_t gt215_ce_code[] = { /* 0x0000: main */ 0x04fe04bd, 0x3517f000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index 2d2e549c2e34..92a9f35df1a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -21,146 +21,60 @@ * * Authors: Ben Skeggs */ -#include <engine/ce.h> -#include <engine/falcon.h> +#include "priv.h" #include "fuc/gf100.fuc3.h" -struct gf100_ce_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_ce0_sclass[] = { - { 0x90b5, &nvkm_object_ofuncs }, - {}, -}; - -static struct nvkm_oclass -gf100_ce1_sclass[] = { - { 0x90b8, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_ofuncs -gf100_ce_context_ofuncs = { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, -}; - -static struct nvkm_oclass -gf100_ce0_cclass = { - .handle = NV_ENGCTX(CE0, 0xc0), - .ofuncs = &gf100_ce_context_ofuncs, -}; - -static struct nvkm_oclass -gf100_ce1_cclass = { - .handle = NV_ENGCTX(CE1, 0xc0), - .ofuncs = &gf100_ce_context_ofuncs, -}; - -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> -static int -gf100_ce_init(struct nvkm_object *object) +static void +gf100_ce_init(struct nvkm_falcon *ce) { - struct gf100_ce_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wo32(priv, 0x084, nv_engidx(&priv->base.base) - NVDEV_ENGINE_CE0); - return 0; + struct nvkm_device *device = ce->engine.subdev.device; + const int index = ce->engine.subdev.index - NVKM_ENGINE_CE0; + nvkm_wr32(device, ce->addr + 0x084, index); } -static int -gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_ce_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, true, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_falcon_func +gf100_ce0 = { + .code.data = gf100_ce_code, + .code.size = sizeof(gf100_ce_code), + .data.data = gf100_ce_data, + .data.size = sizeof(gf100_ce_data), + .pmc_enable = 0x00000040, + .init = gf100_ce_init, + .intr = gt215_ce_intr, + .sclass = { + { -1, -1, FERMI_DMA }, + {} + } +}; - nv_subdev(priv)->unit = 0x00000040; - nv_subdev(priv)->intr = gt215_ce_intr; - nv_engine(priv)->cclass = &gf100_ce0_cclass; - nv_engine(priv)->sclass = gf100_ce0_sclass; - nv_falcon(priv)->code.data = gf100_pce_code; - nv_falcon(priv)->code.size = sizeof(gf100_pce_code); - nv_falcon(priv)->data.data = gf100_pce_data; - nv_falcon(priv)->data.size = sizeof(gf100_pce_data); - return 0; -} +static const struct nvkm_falcon_func +gf100_ce1 = { + .code.data = gf100_ce_code, + .code.size = sizeof(gf100_ce_code), + .data.data = gf100_ce_data, + .data.size = sizeof(gf100_ce_data), + .pmc_enable = 0x00000080, + .init = gf100_ce_init, + .intr = gt215_ce_intr, + .sclass = { + { -1, -1, FERMI_DECOMPRESS }, + {} + } +}; -static int -gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct gf100_ce_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x105000, true, - "PCE1", "ce1", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000080; - nv_subdev(priv)->intr = gt215_ce_intr; - nv_engine(priv)->cclass = &gf100_ce1_cclass; - nv_engine(priv)->sclass = gf100_ce1_sclass; - nv_falcon(priv)->code.data = gf100_pce_code; - nv_falcon(priv)->code.size = sizeof(gf100_pce_code); - nv_falcon(priv)->data.data = gf100_pce_data; - nv_falcon(priv)->data.size = sizeof(gf100_pce_data); - return 0; + if (index == NVKM_ENGINE_CE0) { + return nvkm_falcon_new_(&gf100_ce0, device, index, true, + 0x104000, pengine); + } else + if (index == NVKM_ENGINE_CE1) { + return nvkm_falcon_new_(&gf100_ce1, device, index, true, + 0x105000, pengine); + } + return -ENODEV; } - -struct nvkm_oclass -gf100_ce0_oclass = { - .handle = NV_ENGINE(CE0, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ce0_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_ce_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; - -struct nvkm_oclass -gf100_ce1_oclass = { - .handle = NV_ENGINE(CE1, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ce1_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_ce_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c index a998932fae45..c541a1c012dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c @@ -21,153 +21,47 @@ * * Authors: Ben Skeggs */ -#include <engine/ce.h> +#include "priv.h" -#include <core/engctx.h> +#include <nvif/class.h> -struct gk104_ce_priv { - struct nvkm_engine base; -}; - -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_ce_sclass[] = { - { 0xa0b5, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_ofuncs -gk104_ce_context_ofuncs = { - .ctor = _nvkm_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, -}; - -static struct nvkm_oclass -gk104_ce_cclass = { - .handle = NV_ENGCTX(CE0, 0xc0), - .ofuncs = &gk104_ce_context_ofuncs, -}; - -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ - -static void -gk104_ce_intr(struct nvkm_subdev *subdev) +void +gk104_ce_intr(struct nvkm_engine *ce) { - const int ce = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - struct gk104_ce_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000)); - + const u32 base = (ce->subdev.index - NVKM_ENGINE_CE0) * 0x1000; + struct nvkm_subdev *subdev = &ce->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x104908 + base); if (stat) { - nv_warn(priv, "unhandled intr 0x%08x\n", stat); - nv_wr32(priv, 0x104908 + (ce * 0x1000), stat); + nvkm_warn(subdev, "intr %08x\n", stat); + nvkm_wr32(device, 0x104908 + base, stat); } } -static int -gk104_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk104_ce_priv *priv; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000040; - nv_subdev(priv)->intr = gk104_ce_intr; - nv_engine(priv)->cclass = &gk104_ce_cclass; - nv_engine(priv)->sclass = gk104_ce_sclass; - return 0; -} - -static int -gk104_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk104_ce_priv *priv; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE1", "ce1", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000080; - nv_subdev(priv)->intr = gk104_ce_intr; - nv_engine(priv)->cclass = &gk104_ce_cclass; - nv_engine(priv)->sclass = gk104_ce_sclass; - return 0; -} +static const struct nvkm_engine_func +gk104_ce = { + .intr = gk104_ce_intr, + .sclass = { + { -1, -1, KEPLER_DMA_COPY_A }, + {} + } +}; -static int -gk104_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct gk104_ce_priv *priv; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE2", "ce2", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00200000; - nv_subdev(priv)->intr = gk104_ce_intr; - nv_engine(priv)->cclass = &gk104_ce_cclass; - nv_engine(priv)->sclass = gk104_ce_sclass; - return 0; + if (index == NVKM_ENGINE_CE0) { + return nvkm_engine_new_(&gk104_ce, device, index, + 0x00000040, true, pengine); + } else + if (index == NVKM_ENGINE_CE1) { + return nvkm_engine_new_(&gk104_ce, device, index, + 0x00000080, true, pengine); + } else + if (index == NVKM_ENGINE_CE2) { + return nvkm_engine_new_(&gk104_ce, device, index, + 0x00200000, true, pengine); + } + return -ENODEV; } - -struct nvkm_oclass -gk104_ce0_oclass = { - .handle = NV_ENGINE(CE0, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ce0_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gk104_ce1_oclass = { - .handle = NV_ENGINE(CE1, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ce1_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gk104_ce2_oclass = { - .handle = NV_ENGINE(CE2, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ce2_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c index 577eb2eead05..8eaa72a59f40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c @@ -21,153 +21,34 @@ * * Authors: Ben Skeggs */ -#include <engine/ce.h> +#include "priv.h" -#include <core/engctx.h> +#include <nvif/class.h> -struct gm204_ce_priv { - struct nvkm_engine base; -}; - -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gm204_ce_sclass[] = { - { 0xb0b5, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_ofuncs -gm204_ce_context_ofuncs = { - .ctor = _nvkm_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, -}; - -static struct nvkm_oclass -gm204_ce_cclass = { - .handle = NV_ENGCTX(CE0, 0x24), - .ofuncs = &gm204_ce_context_ofuncs, +static const struct nvkm_engine_func +gm204_ce = { + .intr = gk104_ce_intr, + .sclass = { + { -1, -1, MAXWELL_DMA_COPY_A }, + {} + } }; -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ - -static void -gm204_ce_intr(struct nvkm_subdev *subdev) +int +gm204_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - const int ce = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - struct gm204_ce_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000)); - - if (stat) { - nv_warn(priv, "unhandled intr 0x%08x\n", stat); - nv_wr32(priv, 0x104908 + (ce * 0x1000), stat); + if (index == NVKM_ENGINE_CE0) { + return nvkm_engine_new_(&gm204_ce, device, index, + 0x00000040, true, pengine); + } else + if (index == NVKM_ENGINE_CE1) { + return nvkm_engine_new_(&gm204_ce, device, index, + 0x00000080, true, pengine); + } else + if (index == NVKM_ENGINE_CE2) { + return nvkm_engine_new_(&gm204_ce, device, index, + 0x00200000, true, pengine); } + return -ENODEV; } - -static int -gm204_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gm204_ce_priv *priv; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000040; - nv_subdev(priv)->intr = gm204_ce_intr; - nv_engine(priv)->cclass = &gm204_ce_cclass; - nv_engine(priv)->sclass = gm204_ce_sclass; - return 0; -} - -static int -gm204_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gm204_ce_priv *priv; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE1", "ce1", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000080; - nv_subdev(priv)->intr = gm204_ce_intr; - nv_engine(priv)->cclass = &gm204_ce_cclass; - nv_engine(priv)->sclass = gm204_ce_sclass; - return 0; -} - -static int -gm204_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gm204_ce_priv *priv; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE2", "ce2", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00200000; - nv_subdev(priv)->intr = gm204_ce_intr; - nv_engine(priv)->cclass = &gm204_ce_cclass; - nv_engine(priv)->sclass = gm204_ce_sclass; - return 0; -} - -struct nvkm_oclass -gm204_ce0_oclass = { - .handle = NV_ENGINE(CE0, 0x24), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_ce0_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gm204_ce1_oclass = { - .handle = NV_ENGINE(CE1, 0x24), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_ce1_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gm204_ce2_oclass = { - .handle = NV_ENGINE(CE2, 0x24), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_ce2_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index d8bb4293bc11..402dcbcc2192 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -21,50 +21,15 @@ * * Authors: Ben Skeggs */ -#include <engine/ce.h> -#include <engine/falcon.h> -#include <engine/fifo.h> +#include "priv.h" #include "fuc/gt215.fuc3.h" #include <core/client.h> -#include <core/device.h> #include <core/enum.h> +#include <core/gpuobj.h> +#include <engine/fifo.h> -struct gt215_ce_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gt215_ce_sclass[] = { - { 0x85b5, &nvkm_object_ofuncs }, - {} -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_oclass -gt215_ce_cclass = { - .handle = NV_ENGCTX(CE0, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - - }, -}; - -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> static const struct nvkm_enum gt215_ce_isr_error_name[] = { @@ -75,78 +40,45 @@ gt215_ce_isr_error_name[] = { }; void -gt215_ce_intr(struct nvkm_subdev *subdev) +gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_falcon *falcon = (void *)subdev; - struct nvkm_object *engctx; - u32 dispatch = nv_ro32(falcon, 0x01c); - u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); - u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff; - u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff; - u32 addr = nv_ro32(falcon, 0x040) >> 16; + struct nvkm_subdev *subdev = &ce->engine.subdev; + struct nvkm_device *device = subdev->device; + const u32 base = (subdev->index - NVKM_ENGINE_CE0) * 0x1000; + u32 ssta = nvkm_rd32(device, 0x104040 + base) & 0x0000ffff; + u32 addr = nvkm_rd32(device, 0x104040 + base) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_ro32(falcon, 0x044); - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); - - if (stat & 0x00000040) { - nv_error(falcon, "DISPATCH_ERROR ["); - nvkm_enum_print(gt215_ce_isr_error_name, ssta); - pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), subc, - mthd, data); - nv_wo32(falcon, 0x004, 0x00000040); - stat &= ~0x00000040; - } + u32 data = nvkm_rd32(device, 0x104044 + base); + const struct nvkm_enum *en = + nvkm_enum_find(gt215_ce_isr_error_name, ssta); + + nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", ssta, + en ? en->name : "", chan ? chan->chid : -1, + chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", + subc, mthd, data); +} - if (stat) { - nv_error(falcon, "unhandled intr 0x%08x\n", stat); - nv_wo32(falcon, 0x004, stat); +static const struct nvkm_falcon_func +gt215_ce = { + .code.data = gt215_ce_code, + .code.size = sizeof(gt215_ce_code), + .data.data = gt215_ce_data, + .data.size = sizeof(gt215_ce_data), + .pmc_enable = 0x00802000, + .intr = gt215_ce_intr, + .sclass = { + { -1, -1, GT212_DMA }, + {} } +}; - nvkm_engctx_put(engctx); -} - -static int -gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt215_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - bool enable = (nv_device(parent)->chipset != 0xaf); - struct gt215_ce_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, enable, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00802000; - nv_subdev(priv)->intr = gt215_ce_intr; - nv_engine(priv)->cclass = >215_ce_cclass; - nv_engine(priv)->sclass = gt215_ce_sclass; - nv_falcon(priv)->code.data = gt215_pce_code; - nv_falcon(priv)->code.size = sizeof(gt215_pce_code); - nv_falcon(priv)->data.data = gt215_pce_data; - nv_falcon(priv)->data.size = sizeof(gt215_pce_data); - return 0; + return nvkm_falcon_new_(>215_ce, device, index, + (device->chipset != 0xaf), 0x104000, pengine); } - -struct nvkm_oclass -gt215_ce_oclass = { - .handle = NV_ENGINE(CE0, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_ce_ctor, - .dtor = _nvkm_falcon_dtor, - .init = _nvkm_falcon_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h new file mode 100644 index 000000000000..e2fa8b161943 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h @@ -0,0 +1,7 @@ +#ifndef __NVKM_CE_PRIV_H__ +#define __NVKM_CE_PRIV_H__ +#include <engine/ce.h> + +void gt215_ce_intr(struct nvkm_falcon *, struct nvkm_fifo_chan *); +void gk104_ce_intr(struct nvkm_engine *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index 13f30428a305..bfd01625ec7f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -25,76 +25,47 @@ #include <engine/fifo.h> #include <core/client.h> -#include <core/engctx.h> #include <core/enum.h> +#include <core/gpuobj.h> -struct g84_cipher_priv { - struct nvkm_engine base; -}; - -/******************************************************************************* - * Crypt object classes - ******************************************************************************/ +#include <nvif/class.h> static int -g84_cipher_object_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +g84_cipher_oclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); - return 0; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, + align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_ofuncs -g84_cipher_ofuncs = { - .ctor = g84_cipher_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, +static const struct nvkm_object_func +g84_cipher_oclass_func = { + .bind = g84_cipher_oclass_bind, }; -static struct nvkm_oclass -g84_cipher_sclass[] = { - { 0x74c1, &g84_cipher_ofuncs }, - {} -}; +static int +g84_cipher_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + return nvkm_gpuobj_new(object->engine->subdev.device, 256, + align, true, parent, pgpuobj); -/******************************************************************************* - * PCIPHER context - ******************************************************************************/ +} -static struct nvkm_oclass +static const struct nvkm_object_func g84_cipher_cclass = { - .handle = NV_ENGCTX(CIPHER, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, - }, + .bind = g84_cipher_cclass_bind, }; -/******************************************************************************* - * PCIPHER engine/subdev functions - ******************************************************************************/ - static const struct nvkm_bitfield g84_cipher_intr_mask[] = { { 0x00000001, "INVALID_STATE" }, @@ -106,79 +77,59 @@ g84_cipher_intr_mask[] = { }; static void -g84_cipher_intr(struct nvkm_subdev *subdev) +g84_cipher_intr(struct nvkm_engine *cipher) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct g84_cipher_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x102130); - u32 mthd = nv_rd32(priv, 0x102190); - u32 data = nv_rd32(priv, 0x102194); - u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff; - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); - + struct nvkm_subdev *subdev = &cipher->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_fifo *fifo = device->fifo; + struct nvkm_fifo_chan *chan; + u32 stat = nvkm_rd32(device, 0x102130); + u32 mthd = nvkm_rd32(device, 0x102190); + u32 data = nvkm_rd32(device, 0x102194); + u32 inst = nvkm_rd32(device, 0x102188) & 0x7fffffff; + unsigned long flags; + char msg[128]; + + chan = nvkm_fifo_chan_inst(fifo, (u64)inst << 12, &flags); if (stat) { - nv_error(priv, "%s", ""); - nvkm_bitfield_print(g84_cipher_intr_mask, stat); - pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n", - chid, (u64)inst << 12, nvkm_client_name(engctx), - mthd, data); + nvkm_snprintbf(msg, sizeof(msg), g84_cipher_intr_mask, stat); + nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] " + "mthd %04x data %08x\n", stat, msg, + chan ? chan->chid : -1, (u64)inst << 12, + chan ? chan->object.client->name : "unknown", + mthd, data); } + nvkm_fifo_chan_put(fifo, flags, &chan); - nv_wr32(priv, 0x102130, stat); - nv_wr32(priv, 0x10200c, 0x10); - - nvkm_engctx_put(engctx); + nvkm_wr32(device, 0x102130, stat); + nvkm_wr32(device, 0x10200c, 0x10); } static int -g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +g84_cipher_init(struct nvkm_engine *cipher) { - struct g84_cipher_priv *priv; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCIPHER", "cipher", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00004000; - nv_subdev(priv)->intr = g84_cipher_intr; - nv_engine(priv)->cclass = &g84_cipher_cclass; - nv_engine(priv)->sclass = g84_cipher_sclass; + struct nvkm_device *device = cipher->subdev.device; + nvkm_wr32(device, 0x102130, 0xffffffff); + nvkm_wr32(device, 0x102140, 0xffffffbf); + nvkm_wr32(device, 0x10200c, 0x00000010); return 0; } -static int -g84_cipher_init(struct nvkm_object *object) -{ - struct g84_cipher_priv *priv = (void *)object; - int ret; - - ret = nvkm_engine_init(&priv->base); - if (ret) - return ret; +static const struct nvkm_engine_func +g84_cipher = { + .init = g84_cipher_init, + .intr = g84_cipher_intr, + .cclass = &g84_cipher_cclass, + .sclass = { + { -1, -1, NV74_CIPHER, &g84_cipher_oclass_func }, + {} + } +}; - nv_wr32(priv, 0x102130, 0xffffffff); - nv_wr32(priv, 0x102140, 0xffffffbf); - nv_wr32(priv, 0x10200c, 0x00000010); - return 0; +int +g84_cipher_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_engine_new_(&g84_cipher, device, index, + 0x00004000, true, pengine); } - -struct nvkm_oclass -g84_cipher_oclass = { - .handle = NV_ENGINE(CIPHER, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_cipher_ctor, - .dtor = _nvkm_engine_dtor, - .init = g84_cipher_init, - .fini = _nvkm_engine_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild index de1bf092b2b2..09032ba36000 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild @@ -1,12 +1,6 @@ nvkm-y += nvkm/engine/device/acpi.o nvkm-y += nvkm/engine/device/base.o nvkm-y += nvkm/engine/device/ctrl.o -nvkm-y += nvkm/engine/device/nv04.o -nvkm-y += nvkm/engine/device/nv10.o -nvkm-y += nvkm/engine/device/nv20.o -nvkm-y += nvkm/engine/device/nv30.o -nvkm-y += nvkm/engine/device/nv40.o -nvkm-y += nvkm/engine/device/nv50.o -nvkm-y += nvkm/engine/device/gf100.o -nvkm-y += nvkm/engine/device/gk104.o -nvkm-y += nvkm/engine/device/gm100.o +nvkm-y += nvkm/engine/device/pci.o +nvkm-y += nvkm/engine/device/tegra.o +nvkm-y += nvkm/engine/device/user.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c index f42706e1d5db..fdca90bc8f0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c @@ -40,21 +40,19 @@ nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data) } #endif -int -nvkm_acpi_fini(struct nvkm_device *device, bool suspend) +void +nvkm_acpi_fini(struct nvkm_device *device) { #ifdef CONFIG_ACPI unregister_acpi_notifier(&device->acpi.nb); #endif - return 0; } -int +void nvkm_acpi_init(struct nvkm_device *device) { #ifdef CONFIG_ACPI device->acpi.nb.notifier_call = nvkm_acpi_ntfy; register_acpi_notifier(&device->acpi.nb); #endif - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h index 82dd359ddfa4..1bbe76e0740a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h @@ -3,6 +3,6 @@ #include <core/os.h> struct nvkm_device; -int nvkm_acpi_init(struct nvkm_device *); -int nvkm_acpi_fini(struct nvkm_device *, bool); +void nvkm_acpi_init(struct nvkm_device *); +void nvkm_acpi_fini(struct nvkm_device *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 63d8e52f4b22..94a906b8cb88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -24,33 +24,33 @@ #include "priv.h" #include "acpi.h" -#include <core/client.h> -#include <core/option.h> #include <core/notify.h> -#include <core/parent.h> -#include <subdev/bios.h> -#include <subdev/fb.h> -#include <subdev/instmem.h> +#include <core/option.h> -#include <nvif/class.h> -#include <nvif/unpack.h> +#include <subdev/bios.h> static DEFINE_MUTEX(nv_devices_mutex); static LIST_HEAD(nv_devices); -struct nvkm_device * -nvkm_device_find(u64 name) +static struct nvkm_device * +nvkm_device_find_locked(u64 handle) { - struct nvkm_device *device, *match = NULL; - mutex_lock(&nv_devices_mutex); + struct nvkm_device *device; list_for_each_entry(device, &nv_devices, head) { - if (device->handle == name) { - match = device; - break; - } + if (device->handle == handle) + return device; } + return NULL; +} + +struct nvkm_device * +nvkm_device_find(u64 handle) +{ + struct nvkm_device *device; + mutex_lock(&nv_devices_mutex); + device = nvkm_device_find_locked(handle); mutex_unlock(&nv_devices_mutex); - return match; + return device; } int @@ -67,280 +67,2272 @@ nvkm_device_list(u64 *name, int size) return nr; } -/****************************************************************************** - * nvkm_devobj (0x0080): class implementation - *****************************************************************************/ +static const struct nvkm_device_chip +null_chipset = { + .name = "NULL", + .bios = nvkm_bios_new, +}; + +static const struct nvkm_device_chip +nv4_chipset = { + .name = "NV04", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv04_devinit_new, + .fb = nv04_fb_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv04_fifo_new, + .gr = nv04_gr_new, + .sw = nv04_sw_new, +}; + +static const struct nvkm_device_chip +nv5_chipset = { + .name = "NV05", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv05_devinit_new, + .fb = nv04_fb_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv04_fifo_new, + .gr = nv04_gr_new, + .sw = nv04_sw_new, +}; + +static const struct nvkm_device_chip +nv10_chipset = { + .name = "NV10", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv10_devinit_new, + .fb = nv10_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .gr = nv10_gr_new, +}; + +static const struct nvkm_device_chip +nv11_chipset = { + .name = "NV11", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv10_devinit_new, + .fb = nv10_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv10_fifo_new, + .gr = nv15_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv15_chipset = { + .name = "NV15", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv10_devinit_new, + .fb = nv10_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv10_fifo_new, + .gr = nv15_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv17_chipset = { + .name = "NV17", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv10_devinit_new, + .fb = nv10_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv17_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv18_chipset = { + .name = "NV18", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv10_devinit_new, + .fb = nv10_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv17_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv1a_chipset = { + .name = "nForce", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv1a_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv10_fifo_new, + .gr = nv15_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv1f_chipset = { + .name = "nForce2", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv1a_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv17_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv20_chipset = { + .name = "NV20", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv20_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv20_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv25_chipset = { + .name = "NV25", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv25_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv25_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv28_chipset = { + .name = "NV28", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv25_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv25_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv2a_chipset = { + .name = "NV2A", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv25_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv2a_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv30_chipset = { + .name = "NV30", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv30_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv30_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv31_chipset = { + .name = "NV31", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv30_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv30_gr_new, + .mpeg = nv31_mpeg_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv34_chipset = { + .name = "NV34", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv04_clk_new, + .devinit = nv10_devinit_new, + .fb = nv10_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv34_gr_new, + .mpeg = nv31_mpeg_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv35_chipset = { + .name = "NV35", + .bios = nvkm_bios_new, + .bus = nv04_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv35_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv35_gr_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv36_chipset = { + .name = "NV36", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv04_clk_new, + .devinit = nv20_devinit_new, + .fb = nv36_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv04_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv04_pci_new, + .timer = nv04_timer_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv17_fifo_new, + .gr = nv35_gr_new, + .mpeg = nv31_mpeg_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv40_chipset = { + .name = "NV40", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv40_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv40_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv40_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv41_chipset = { + .name = "NV41", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv41_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv41_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv40_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv42_chipset = { + .name = "NV42", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv41_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv41_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv40_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv43_chipset = { + .name = "NV43", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv41_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv41_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv40_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv44_chipset = { + .name = "NV44", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv44_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv45_chipset = { + .name = "NV45", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv40_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv04_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv46_chipset = { + .name = "G72", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv46_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv47_chipset = { + .name = "G70", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv47_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv41_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv49_chipset = { + .name = "G71", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv49_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv41_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4a_chipset = { + .name = "NV44A", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv44_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4b_chipset = { + .name = "G73", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv49_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv04_mc_new, + .mmu = nv41_mmu_new, + .pci = nv40_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv40_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4c_chipset = { + .name = "C61", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv46_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4e_chipset = { + .name = "C51", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv4e_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv4e_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv50_chipset = { + .name = "G80", + .bar = nv50_bar_new, + .bios = nvkm_bios_new, + .bus = nv50_bus_new, + .clk = nv50_clk_new, + .devinit = nv50_devinit_new, + .fb = nv50_fb_new, + .fuse = nv50_fuse_new, + .gpio = nv50_gpio_new, + .i2c = nv50_i2c_new, + .imem = nv50_instmem_new, + .mc = nv50_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv50_pci_new, + .therm = nv50_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv50_disp_new, + .dma = nv50_dma_new, + .fifo = nv50_fifo_new, + .gr = nv50_gr_new, + .mpeg = nv50_mpeg_new, + .pm = nv50_pm_new, + .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nv63_chipset = { + .name = "C73", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv46_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv67_chipset = { + .name = "C67", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv46_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv68_chipset = { + .name = "C68", + .bios = nvkm_bios_new, + .bus = nv31_bus_new, + .clk = nv40_clk_new, + .devinit = nv1a_devinit_new, + .fb = nv46_fb_new, + .gpio = nv10_gpio_new, + .i2c = nv04_i2c_new, + .imem = nv40_instmem_new, + .mc = nv44_mc_new, + .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, + .therm = nv40_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = nv04_disp_new, + .dma = nv04_dma_new, + .fifo = nv40_fifo_new, + .gr = nv44_gr_new, + .mpeg = nv44_mpeg_new, + .pm = nv40_pm_new, + .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv84_chipset = { + .name = "G84", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = nv50_bus_new, + .clk = g84_clk_new, + .devinit = g84_devinit_new, + .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = nv50_gpio_new, + .i2c = nv50_i2c_new, + .imem = nv50_instmem_new, + .mc = nv50_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv50_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .bsp = g84_bsp_new, + .cipher = g84_cipher_new, + .disp = g84_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = g84_gr_new, + .mpeg = g84_mpeg_new, + .pm = g84_pm_new, + .sw = nv50_sw_new, + .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv86_chipset = { + .name = "G86", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = nv50_bus_new, + .clk = g84_clk_new, + .devinit = g84_devinit_new, + .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = nv50_gpio_new, + .i2c = nv50_i2c_new, + .imem = nv50_instmem_new, + .mc = nv50_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv50_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .bsp = g84_bsp_new, + .cipher = g84_cipher_new, + .disp = g84_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = g84_gr_new, + .mpeg = g84_mpeg_new, + .pm = g84_pm_new, + .sw = nv50_sw_new, + .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv92_chipset = { + .name = "G92", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = nv50_bus_new, + .clk = g84_clk_new, + .devinit = g84_devinit_new, + .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = nv50_gpio_new, + .i2c = nv50_i2c_new, + .imem = nv50_instmem_new, + .mc = nv50_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv50_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .bsp = g84_bsp_new, + .cipher = g84_cipher_new, + .disp = g84_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = g84_gr_new, + .mpeg = g84_mpeg_new, + .pm = g84_pm_new, + .sw = nv50_sw_new, + .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv94_chipset = { + .name = "G94", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = g84_clk_new, + .devinit = g84_devinit_new, + .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = nv50_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .bsp = g84_bsp_new, + .cipher = g84_cipher_new, + .disp = g94_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = g84_gr_new, + .mpeg = g84_mpeg_new, + .pm = g84_pm_new, + .sw = nv50_sw_new, + .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv96_chipset = { + .name = "G96", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = g84_clk_new, + .devinit = g84_devinit_new, + .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = nv50_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .bsp = g84_bsp_new, + .cipher = g84_cipher_new, + .disp = g94_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = g84_gr_new, + .mpeg = g84_mpeg_new, + .pm = g84_pm_new, + .sw = nv50_sw_new, + .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv98_chipset = { + .name = "G98", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = g84_clk_new, + .devinit = g98_devinit_new, + .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = g94_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = g84_gr_new, + .mspdec = g98_mspdec_new, + .msppp = g98_msppp_new, + .msvld = g98_msvld_new, + .pm = g84_pm_new, + .sec = g98_sec_new, + .sw = nv50_sw_new, +}; -struct nvkm_devobj { - struct nvkm_parent base; - struct nvkm_object *subdev[NVDEV_SUBDEV_NR]; +static const struct nvkm_device_chip +nva0_chipset = { + .name = "GT200", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = g84_clk_new, + .devinit = g84_devinit_new, + .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = nv50_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .bsp = g84_bsp_new, + .cipher = g84_cipher_new, + .disp = gt200_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = gt200_gr_new, + .mpeg = g84_mpeg_new, + .pm = gt200_pm_new, + .sw = nv50_sw_new, + .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nva3_chipset = { + .name = "GT215", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = gt215_clk_new, + .devinit = gt215_devinit_new, + .fb = gt215_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gt215_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gt215_ce_new, + .disp = gt215_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = gt215_gr_new, + .mpeg = g84_mpeg_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = gt215_msvld_new, + .pm = gt215_pm_new, + .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nva5_chipset = { + .name = "GT216", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = gt215_clk_new, + .devinit = gt215_devinit_new, + .fb = gt215_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gt215_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gt215_ce_new, + .disp = gt215_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = gt215_gr_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = gt215_msvld_new, + .pm = gt215_pm_new, + .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nva8_chipset = { + .name = "GT218", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = gt215_clk_new, + .devinit = gt215_devinit_new, + .fb = gt215_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gt215_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gt215_ce_new, + .disp = gt215_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = gt215_gr_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = gt215_msvld_new, + .pm = gt215_pm_new, + .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvaa_chipset = { + .name = "MCP77/MCP78", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = mcp77_clk_new, + .devinit = g98_devinit_new, + .fb = mcp77_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = g94_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = gt200_gr_new, + .mspdec = g98_mspdec_new, + .msppp = g98_msppp_new, + .msvld = g98_msvld_new, + .pm = g84_pm_new, + .sec = g98_sec_new, + .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvac_chipset = { + .name = "MCP79/MCP7A", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = mcp77_clk_new, + .devinit = g98_devinit_new, + .fb = mcp77_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .disp = g94_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = mcp79_gr_new, + .mspdec = g98_mspdec_new, + .msppp = g98_msppp_new, + .msvld = g98_msvld_new, + .pm = g84_pm_new, + .sec = g98_sec_new, + .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvaf_chipset = { + .name = "MCP89", + .bar = g84_bar_new, + .bios = nvkm_bios_new, + .bus = g94_bus_new, + .clk = gt215_clk_new, + .devinit = mcp89_devinit_new, + .fb = mcp89_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .imem = nv50_instmem_new, + .mc = g98_mc_new, + .mmu = nv50_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gt215_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gt215_ce_new, + .disp = gt215_disp_new, + .dma = nv50_dma_new, + .fifo = g84_fifo_new, + .gr = mcp89_gr_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = mcp89_msvld_new, + .pm = gt215_pm_new, + .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvc0_chipset = { + .name = "GF100", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = gf100_pci_new, + .pmu = gf100_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, + .disp = gt215_disp_new, + .dma = gf100_dma_new, + .fifo = gf100_fifo_new, + .gr = gf100_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf100_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc1_chipset = { + .name = "GF108", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gf100_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .disp = gt215_disp_new, + .dma = gf100_dma_new, + .fifo = gf100_fifo_new, + .gr = gf108_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf108_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc3_chipset = { + .name = "GF106", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gf100_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .disp = gt215_disp_new, + .dma = gf100_dma_new, + .fifo = gf100_fifo_new, + .gr = gf104_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf100_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc4_chipset = { + .name = "GF104", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = gf100_pci_new, + .pmu = gf100_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, + .disp = gt215_disp_new, + .dma = gf100_dma_new, + .fifo = gf100_fifo_new, + .gr = gf104_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf100_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc8_chipset = { + .name = "GF110", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = gf100_pci_new, + .pmu = gf100_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, + .disp = gt215_disp_new, + .dma = gf100_dma_new, + .fifo = gf100_fifo_new, + .gr = gf110_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf100_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvce_chipset = { + .name = "GF114", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = gf100_pci_new, + .pmu = gf100_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, + .disp = gt215_disp_new, + .dma = gf100_dma_new, + .fifo = gf100_fifo_new, + .gr = gf104_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf100_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvcf_chipset = { + .name = "GF116", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gf100_pmu_new, + .therm = gt215_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .disp = gt215_disp_new, + .dma = gf100_dma_new, + .fifo = gf100_fifo_new, + .gr = gf104_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf100_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvd7_chipset = { + .name = "GF117", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = gf119_gpio_new, + .i2c = gf117_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .ce[0] = gf100_ce_new, + .disp = gf119_disp_new, + .dma = gf119_dma_new, + .fifo = gf100_fifo_new, + .gr = gf117_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf117_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvd9_chipset = { + .name = "GF119", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gf100_clk_new, + .devinit = gf100_devinit_new, + .fb = gf100_fb_new, + .fuse = gf100_fuse_new, + .gpio = gf119_gpio_new, + .i2c = gf119_i2c_new, + .ibus = gf100_ibus_new, + .imem = nv50_instmem_new, + .ltc = gf100_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gf119_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gf100_ce_new, + .disp = gf119_disp_new, + .dma = gf119_dma_new, + .fifo = gf100_fifo_new, + .gr = gf119_gr_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, + .pm = gf117_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nve4_chipset = { + .name = "GK104", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gf100_devinit_new, + .fb = gk104_fb_new, + .fuse = gf100_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gk104_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gk104_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gk104_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gk104_disp_new, + .dma = gf119_dma_new, + .fifo = gk104_fifo_new, + .gr = gk104_gr_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, + .pm = gk104_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nve6_chipset = { + .name = "GK106", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gf100_devinit_new, + .fb = gk104_fb_new, + .fuse = gf100_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gk104_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gk104_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gk104_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gk104_disp_new, + .dma = gf119_dma_new, + .fifo = gk104_fifo_new, + .gr = gk104_gr_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, + .pm = gk104_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nve7_chipset = { + .name = "GK107", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gf100_devinit_new, + .fb = gk104_fb_new, + .fuse = gf100_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gk104_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gk104_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gf119_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gk104_disp_new, + .dma = gf119_dma_new, + .fifo = gk104_fifo_new, + .gr = gk104_gr_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, + .pm = gk104_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvea_chipset = { + .name = "GK20A", + .bar = gk20a_bar_new, + .bus = gf100_bus_new, + .clk = gk20a_clk_new, + .fb = gk20a_fb_new, + .fuse = gf100_fuse_new, + .ibus = gk20a_ibus_new, + .imem = gk20a_instmem_new, + .ltc = gk104_ltc_new, + .mc = gk20a_mc_new, + .mmu = gf100_mmu_new, + .pmu = gk20a_pmu_new, + .timer = gk20a_timer_new, + .volt = gk20a_volt_new, + .ce[2] = gk104_ce_new, + .dma = gf119_dma_new, + .fifo = gk20a_fifo_new, + .gr = gk20a_gr_new, + .pm = gk104_pm_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvf0_chipset = { + .name = "GK110", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gf100_devinit_new, + .fb = gk104_fb_new, + .fuse = gf100_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gk104_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gk104_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gk110_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gk110_disp_new, + .dma = gf119_dma_new, + .fifo = gk104_fifo_new, + .gr = gk110_gr_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvf1_chipset = { + .name = "GK110B", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gf100_devinit_new, + .fb = gk104_fb_new, + .fuse = gf100_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gf119_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gk104_ltc_new, + .mc = gf100_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gk110_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gk110_disp_new, + .dma = gf119_dma_new, + .fifo = gk104_fifo_new, + .gr = gk110b_gr_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv106_chipset = { + .name = "GK208B", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gf100_devinit_new, + .fb = gk104_fb_new, + .fuse = gf100_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gk104_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gk104_ltc_new, + .mc = gk20a_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gk208_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gk110_disp_new, + .dma = gf119_dma_new, + .fifo = gk208_fifo_new, + .gr = gk208_gr_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv108_chipset = { + .name = "GK208", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gf100_devinit_new, + .fb = gk104_fb_new, + .fuse = gf100_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gk104_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gk104_ltc_new, + .mc = gk20a_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gk208_pmu_new, + .therm = gf119_therm_new, + .timer = nv41_timer_new, + .volt = nv40_volt_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gk110_disp_new, + .dma = gf119_dma_new, + .fifo = gk208_fifo_new, + .gr = gk208_gr_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv117_chipset = { + .name = "GM107", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .clk = gk104_clk_new, + .devinit = gm107_devinit_new, + .fb = gm107_fb_new, + .fuse = gm107_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gf119_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gm107_ltc_new, + .mc = gk20a_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gm107_pmu_new, + .therm = gm107_therm_new, + .timer = gk20a_timer_new, + .ce[0] = gk104_ce_new, + .ce[2] = gk104_ce_new, + .disp = gm107_disp_new, + .dma = gf119_dma_new, + .fifo = gk208_fifo_new, + .gr = gm107_gr_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv124_chipset = { + .name = "GM204", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .devinit = gm204_devinit_new, + .fb = gm107_fb_new, + .fuse = gm107_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gm204_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gm107_ltc_new, + .mc = gk20a_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gm107_pmu_new, + .timer = gk20a_timer_new, + .ce[0] = gm204_ce_new, + .ce[1] = gm204_ce_new, + .ce[2] = gm204_ce_new, + .disp = gm204_disp_new, + .dma = gf119_dma_new, + .fifo = gm204_fifo_new, + .gr = gm204_gr_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv126_chipset = { + .name = "GM206", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .devinit = gm204_devinit_new, + .fb = gm107_fb_new, + .fuse = gm107_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gm204_i2c_new, + .ibus = gk104_ibus_new, + .imem = nv50_instmem_new, + .ltc = gm107_ltc_new, + .mc = gk20a_mc_new, + .mmu = gf100_mmu_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .pmu = gm107_pmu_new, + .timer = gk20a_timer_new, + .ce[0] = gm204_ce_new, + .ce[1] = gm204_ce_new, + .ce[2] = gm204_ce_new, + .disp = gm204_disp_new, + .dma = gf119_dma_new, + .fifo = gm204_fifo_new, + .gr = gm206_gr_new, + .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv12b_chipset = { + .name = "GM20B", + .bar = gk20a_bar_new, + .bus = gf100_bus_new, + .fb = gk20a_fb_new, + .fuse = gm107_fuse_new, + .ibus = gk20a_ibus_new, + .imem = gk20a_instmem_new, + .ltc = gm107_ltc_new, + .mc = gk20a_mc_new, + .mmu = gf100_mmu_new, + .timer = gk20a_timer_new, + .ce[2] = gm204_ce_new, + .dma = gf119_dma_new, + .fifo = gm20b_fifo_new, + .gr = gm20b_gr_new, + .sw = gf100_sw_new, }; static int -nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size) +nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size, + struct nvkm_notify *notify) { - struct nvkm_device *device = nv_device(object); - struct nvkm_fb *pfb = nvkm_fb(device); - struct nvkm_instmem *imem = nvkm_instmem(device); - union { - struct nv_device_info_v0 v0; - } *args = data; - int ret; - - nv_ioctl(object, "device info size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "device info vers %d\n", args->v0.version); - } else - return ret; + if (!WARN_ON(size != 0)) { + notify->size = 0; + notify->types = 1; + notify->index = 0; + return 0; + } + return -EINVAL; +} - switch (device->chipset) { - case 0x01a: - case 0x01f: - case 0x04c: - case 0x04e: - case 0x063: - case 0x067: - case 0x068: - case 0x0aa: - case 0x0ac: - case 0x0af: - args->v0.platform = NV_DEVICE_INFO_V0_IGP; - break; +static const struct nvkm_event_func +nvkm_device_event_func = { + .ctor = nvkm_device_event_ctor, +}; + +struct nvkm_subdev * +nvkm_device_subdev(struct nvkm_device *device, int index) +{ + struct nvkm_engine *engine; + + if (device->disable_mask & (1ULL << index)) + return NULL; + + switch (index) { +#define _(n,p,m) case NVKM_SUBDEV_##n: if (p) return (m); break + _(BAR , device->bar , &device->bar->subdev); + _(VBIOS , device->bios , &device->bios->subdev); + _(BUS , device->bus , &device->bus->subdev); + _(CLK , device->clk , &device->clk->subdev); + _(DEVINIT, device->devinit, &device->devinit->subdev); + _(FB , device->fb , &device->fb->subdev); + _(FUSE , device->fuse , &device->fuse->subdev); + _(GPIO , device->gpio , &device->gpio->subdev); + _(I2C , device->i2c , &device->i2c->subdev); + _(IBUS , device->ibus , device->ibus); + _(INSTMEM, device->imem , &device->imem->subdev); + _(LTC , device->ltc , &device->ltc->subdev); + _(MC , device->mc , &device->mc->subdev); + _(MMU , device->mmu , &device->mmu->subdev); + _(MXM , device->mxm , device->mxm); + _(PCI , device->pci , &device->pci->subdev); + _(PMU , device->pmu , &device->pmu->subdev); + _(THERM , device->therm , &device->therm->subdev); + _(TIMER , device->timer , &device->timer->subdev); + _(VOLT , device->volt , &device->volt->subdev); +#undef _ default: - if (device->pdev) { - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP)) - args->v0.platform = NV_DEVICE_INFO_V0_AGP; - else - if (pci_is_pcie(device->pdev)) - args->v0.platform = NV_DEVICE_INFO_V0_PCIE; - else - args->v0.platform = NV_DEVICE_INFO_V0_PCI; - } else { - args->v0.platform = NV_DEVICE_INFO_V0_SOC; - } + engine = nvkm_device_engine(device, index); + if (engine) + return &engine->subdev; break; } + return NULL; +} - switch (device->card_type) { - case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break; - case NV_10: - case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break; - case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break; - case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break; - case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break; - case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break; - case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break; - case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break; - case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break; +struct nvkm_engine * +nvkm_device_engine(struct nvkm_device *device, int index) +{ + if (device->disable_mask & (1ULL << index)) + return NULL; + + switch (index) { +#define _(n,p,m) case NVKM_ENGINE_##n: if (p) return (m); break + _(BSP , device->bsp , device->bsp); + _(CE0 , device->ce[0] , device->ce[0]); + _(CE1 , device->ce[1] , device->ce[1]); + _(CE2 , device->ce[2] , device->ce[2]); + _(CIPHER , device->cipher , device->cipher); + _(DISP , device->disp , &device->disp->engine); + _(DMAOBJ , device->dma , &device->dma->engine); + _(FIFO , device->fifo , &device->fifo->engine); + _(GR , device->gr , &device->gr->engine); + _(IFB , device->ifb , device->ifb); + _(ME , device->me , device->me); + _(MPEG , device->mpeg , device->mpeg); + _(MSENC , device->msenc , device->msenc); + _(MSPDEC , device->mspdec , device->mspdec); + _(MSPPP , device->msppp , device->msppp); + _(MSVLD , device->msvld , device->msvld); + _(PM , device->pm , &device->pm->engine); + _(SEC , device->sec , device->sec); + _(SW , device->sw , &device->sw->engine); + _(VIC , device->vic , device->vic); + _(VP , device->vp , device->vp); +#undef _ default: - args->v0.family = 0; + WARN_ON(1); break; } + return NULL; +} + +int +nvkm_device_fini(struct nvkm_device *device, bool suspend) +{ + const char *action = suspend ? "suspend" : "fini"; + struct nvkm_subdev *subdev; + int ret, i; + s64 time; + + nvdev_trace(device, "%s running...\n", action); + time = ktime_to_us(ktime_get()); + + nvkm_acpi_fini(device); + + for (i = NVKM_SUBDEV_NR - 1; i >= 0; i--) { + if ((subdev = nvkm_device_subdev(device, i))) { + ret = nvkm_subdev_fini(subdev, suspend); + if (ret && suspend) + goto fail; + } + } - args->v0.chipset = device->chipset; - args->v0.revision = device->chiprev; - if (pfb && pfb->ram) - args->v0.ram_size = args->v0.ram_user = pfb->ram->size; - else - args->v0.ram_size = args->v0.ram_user = 0; - if (imem && args->v0.ram_size > 0) - args->v0.ram_user = args->v0.ram_user - imem->reserved; + if (device->func->fini) + device->func->fini(device, suspend); + + time = ktime_to_us(ktime_get()) - time; + nvdev_trace(device, "%s completed in %lldus...\n", action, time); return 0; + +fail: + do { + if ((subdev = nvkm_device_subdev(device, i))) { + int rret = nvkm_subdev_init(subdev); + if (rret) + nvkm_fatal(subdev, "failed restart, %d\n", ret); + } + } while (++i < NVKM_SUBDEV_NR); + + nvdev_trace(device, "%s failed with %d\n", action, ret); + return ret; } static int -nvkm_devobj_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +nvkm_device_preinit(struct nvkm_device *device) { - switch (mthd) { - case NV_DEVICE_V0_INFO: - return nvkm_devobj_info(object, data, size); - default: - break; + struct nvkm_subdev *subdev; + int ret, i; + s64 time; + + nvdev_trace(device, "preinit running...\n"); + time = ktime_to_us(ktime_get()); + + if (device->func->preinit) { + ret = device->func->preinit(device); + if (ret) + goto fail; } - return -EINVAL; -} -static u8 -nvkm_devobj_rd08(struct nvkm_object *object, u64 addr) -{ - return nv_rd08(object->engine, addr); -} + for (i = 0; i < NVKM_SUBDEV_NR; i++) { + if ((subdev = nvkm_device_subdev(device, i))) { + ret = nvkm_subdev_preinit(subdev); + if (ret) + goto fail; + } + } -static u16 -nvkm_devobj_rd16(struct nvkm_object *object, u64 addr) -{ - return nv_rd16(object->engine, addr); -} + ret = nvkm_devinit_post(device->devinit, &device->disable_mask); + if (ret) + goto fail; -static u32 -nvkm_devobj_rd32(struct nvkm_object *object, u64 addr) -{ - return nv_rd32(object->engine, addr); -} + time = ktime_to_us(ktime_get()) - time; + nvdev_trace(device, "preinit completed in %lldus\n", time); + return 0; -static void -nvkm_devobj_wr08(struct nvkm_object *object, u64 addr, u8 data) -{ - nv_wr08(object->engine, addr, data); +fail: + nvdev_error(device, "preinit failed with %d\n", ret); + return ret; } -static void -nvkm_devobj_wr16(struct nvkm_object *object, u64 addr, u16 data) +int +nvkm_device_init(struct nvkm_device *device) { - nv_wr16(object->engine, addr, data); -} + struct nvkm_subdev *subdev; + int ret, i; + s64 time; -static void -nvkm_devobj_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - nv_wr32(object->engine, addr, data); -} + ret = nvkm_device_preinit(device); + if (ret) + return ret; -static int -nvkm_devobj_map(struct nvkm_object *object, u64 *addr, u32 *size) -{ - struct nvkm_device *device = nv_device(object); - *addr = nv_device_resource_start(device, 0); - *size = nv_device_resource_len(device, 0); + nvkm_device_fini(device, false); + + nvdev_trace(device, "init running...\n"); + time = ktime_to_us(ktime_get()); + + if (device->func->init) { + ret = device->func->init(device); + if (ret) + goto fail; + } + + for (i = 0; i < NVKM_SUBDEV_NR; i++) { + if ((subdev = nvkm_device_subdev(device, i))) { + ret = nvkm_subdev_init(subdev); + if (ret) + goto fail_subdev; + } + } + + nvkm_acpi_init(device); + + time = ktime_to_us(ktime_get()) - time; + nvdev_trace(device, "init completed in %lldus\n", time); return 0; + +fail_subdev: + do { + if ((subdev = nvkm_device_subdev(device, i))) + nvkm_subdev_fini(subdev, false); + } while (--i >= 0); + +fail: + nvdev_error(device, "init failed with %d\n", ret); + return ret; } -static const u64 disable_map[] = { - [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS, - [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_CLK ] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_LTC] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_MMU] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_PMU] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_FUSE] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_ENGINE_PM ] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO, - [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO, - [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GR, - [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG, - [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME, - [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP, - [NVDEV_ENGINE_CIPHER] = NV_DEVICE_V0_DISABLE_CIPHER, - [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP, - [NVDEV_ENGINE_MSPPP] = NV_DEVICE_V0_DISABLE_MSPPP, - [NVDEV_ENGINE_CE0] = NV_DEVICE_V0_DISABLE_CE0, - [NVDEV_ENGINE_CE1] = NV_DEVICE_V0_DISABLE_CE1, - [NVDEV_ENGINE_CE2] = NV_DEVICE_V0_DISABLE_CE2, - [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC, - [NVDEV_ENGINE_MSENC] = NV_DEVICE_V0_DISABLE_MSENC, - [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP, - [NVDEV_ENGINE_MSVLD] = NV_DEVICE_V0_DISABLE_MSVLD, - [NVDEV_ENGINE_SEC] = NV_DEVICE_V0_DISABLE_SEC, - [NVDEV_SUBDEV_NR] = 0, -}; - -static void -nvkm_devobj_dtor(struct nvkm_object *object) +void +nvkm_device_del(struct nvkm_device **pdevice) { - struct nvkm_devobj *devobj = (void *)object; + struct nvkm_device *device = *pdevice; int i; + if (device) { + mutex_lock(&nv_devices_mutex); + device->disable_mask = 0; + for (i = NVKM_SUBDEV_NR - 1; i >= 0; i--) { + struct nvkm_subdev *subdev = + nvkm_device_subdev(device, i); + nvkm_subdev_del(&subdev); + } - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) - nvkm_object_ref(NULL, &devobj->subdev[i]); + nvkm_event_fini(&device->event); - nvkm_parent_destroy(&devobj->base); -} + if (device->pri) + iounmap(device->pri); + list_del(&device->head); -static struct nvkm_oclass -nvkm_devobj_oclass_super = { - .handle = NV_DEVICE, - .ofuncs = &(struct nvkm_ofuncs) { - .dtor = nvkm_devobj_dtor, - .init = _nvkm_parent_init, - .fini = _nvkm_parent_fini, - .mthd = nvkm_devobj_mthd, - .map = nvkm_devobj_map, - .rd08 = nvkm_devobj_rd08, - .rd16 = nvkm_devobj_rd16, - .rd32 = nvkm_devobj_rd32, - .wr08 = nvkm_devobj_wr08, - .wr16 = nvkm_devobj_wr16, - .wr32 = nvkm_devobj_wr32, + if (device->func->dtor) + *pdevice = device->func->dtor(device); + mutex_unlock(&nv_devices_mutex); + + kfree(*pdevice); + *pdevice = NULL; } -}; +} -static int -nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nvkm_device_ctor(const struct nvkm_device_func *func, + const struct nvkm_device_quirk *quirk, + struct device *dev, enum nvkm_device_type type, u64 handle, + const char *name, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device *device) { - union { - struct nv_device_v0 v0; - } *args = data; - struct nvkm_client *client = nv_client(parent); - struct nvkm_device *device; - struct nvkm_devobj *devobj; + struct nvkm_subdev *subdev; + u64 mmio_base, mmio_size; u32 boot0, strap; - u64 disable, mmio_base, mmio_size; void __iomem *map; - int ret, i, c; - - nv_ioctl(parent, "create device size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create device v%d device %016llx " - "disable %016llx debug0 %016llx\n", - args->v0.version, args->v0.device, - args->v0.disable, args->v0.debug0); - } else - return ret; + int ret = -EEXIST; + int i; - /* give priviledged clients register access */ - if (client->super) - oclass = &nvkm_devobj_oclass_super; + mutex_lock(&nv_devices_mutex); + if (nvkm_device_find_locked(handle)) + goto done; - /* find the device subdev that matches what the client requested */ - device = nv_device(client->device); - if (args->v0.device != ~0) { - device = nvkm_device_find(args->v0.device); - if (!device) - return -ENODEV; - } + device->func = func; + device->quirk = quirk; + device->dev = dev; + device->type = type; + device->handle = handle; + device->cfgopt = cfg; + device->dbgopt = dbg; + device->name = name; + list_add_tail(&device->head, &nv_devices); + device->debug = nvkm_dbgopt(device->dbgopt, "device"); - ret = nvkm_parent_create(parent, nv_object(device), oclass, 0, - nvkm_control_oclass, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_FIFO) | - (1ULL << NVDEV_ENGINE_DISP) | - (1ULL << NVDEV_ENGINE_PM), &devobj); - *pobject = nv_object(devobj); + ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); if (ret) - return ret; - - mmio_base = nv_device_resource_start(device, 0); - mmio_size = nv_device_resource_len(device, 0); + goto done; - /* translate api disable mask into internal mapping */ - disable = args->v0.debug0; - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if (args->v0.disable & disable_map[i]) - disable |= (1ULL << i); - } + mmio_base = device->func->resource_addr(device, 0); + mmio_size = device->func->resource_size(device, 0); /* identify the chipset, and determine classes of subdev/engines */ - if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) && - !device->card_type) { + if (detect) { map = ioremap(mmio_base, 0x102000); - if (map == NULL) - return -ENOMEM; + if (ret = -ENOMEM, map == NULL) + goto done; /* switch mmio to cpu's native endianness */ #ifndef __BIG_ENDIAN @@ -397,31 +2389,83 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, device->card_type = NV_04; } - switch (device->card_type) { - case NV_04: ret = nv04_identify(device); break; - case NV_10: - case NV_11: ret = nv10_identify(device); break; - case NV_20: ret = nv20_identify(device); break; - case NV_30: ret = nv30_identify(device); break; - case NV_40: ret = nv40_identify(device); break; - case NV_50: ret = nv50_identify(device); break; - case NV_C0: ret = gf100_identify(device); break; - case NV_E0: ret = gk104_identify(device); break; - case GM100: ret = gm100_identify(device); break; + switch (device->chipset) { + case 0x004: device->chip = &nv4_chipset; break; + case 0x005: device->chip = &nv5_chipset; break; + case 0x010: device->chip = &nv10_chipset; break; + case 0x011: device->chip = &nv11_chipset; break; + case 0x015: device->chip = &nv15_chipset; break; + case 0x017: device->chip = &nv17_chipset; break; + case 0x018: device->chip = &nv18_chipset; break; + case 0x01a: device->chip = &nv1a_chipset; break; + case 0x01f: device->chip = &nv1f_chipset; break; + case 0x020: device->chip = &nv20_chipset; break; + case 0x025: device->chip = &nv25_chipset; break; + case 0x028: device->chip = &nv28_chipset; break; + case 0x02a: device->chip = &nv2a_chipset; break; + case 0x030: device->chip = &nv30_chipset; break; + case 0x031: device->chip = &nv31_chipset; break; + case 0x034: device->chip = &nv34_chipset; break; + case 0x035: device->chip = &nv35_chipset; break; + case 0x036: device->chip = &nv36_chipset; break; + case 0x040: device->chip = &nv40_chipset; break; + case 0x041: device->chip = &nv41_chipset; break; + case 0x042: device->chip = &nv42_chipset; break; + case 0x043: device->chip = &nv43_chipset; break; + case 0x044: device->chip = &nv44_chipset; break; + case 0x045: device->chip = &nv45_chipset; break; + case 0x046: device->chip = &nv46_chipset; break; + case 0x047: device->chip = &nv47_chipset; break; + case 0x049: device->chip = &nv49_chipset; break; + case 0x04a: device->chip = &nv4a_chipset; break; + case 0x04b: device->chip = &nv4b_chipset; break; + case 0x04c: device->chip = &nv4c_chipset; break; + case 0x04e: device->chip = &nv4e_chipset; break; + case 0x050: device->chip = &nv50_chipset; break; + case 0x063: device->chip = &nv63_chipset; break; + case 0x067: device->chip = &nv67_chipset; break; + case 0x068: device->chip = &nv68_chipset; break; + case 0x084: device->chip = &nv84_chipset; break; + case 0x086: device->chip = &nv86_chipset; break; + case 0x092: device->chip = &nv92_chipset; break; + case 0x094: device->chip = &nv94_chipset; break; + case 0x096: device->chip = &nv96_chipset; break; + case 0x098: device->chip = &nv98_chipset; break; + case 0x0a0: device->chip = &nva0_chipset; break; + case 0x0a3: device->chip = &nva3_chipset; break; + case 0x0a5: device->chip = &nva5_chipset; break; + case 0x0a8: device->chip = &nva8_chipset; break; + case 0x0aa: device->chip = &nvaa_chipset; break; + case 0x0ac: device->chip = &nvac_chipset; break; + case 0x0af: device->chip = &nvaf_chipset; break; + case 0x0c0: device->chip = &nvc0_chipset; break; + case 0x0c1: device->chip = &nvc1_chipset; break; + case 0x0c3: device->chip = &nvc3_chipset; break; + case 0x0c4: device->chip = &nvc4_chipset; break; + case 0x0c8: device->chip = &nvc8_chipset; break; + case 0x0ce: device->chip = &nvce_chipset; break; + case 0x0cf: device->chip = &nvcf_chipset; break; + case 0x0d7: device->chip = &nvd7_chipset; break; + case 0x0d9: device->chip = &nvd9_chipset; break; + case 0x0e4: device->chip = &nve4_chipset; break; + case 0x0e6: device->chip = &nve6_chipset; break; + case 0x0e7: device->chip = &nve7_chipset; break; + case 0x0ea: device->chip = &nvea_chipset; break; + case 0x0f0: device->chip = &nvf0_chipset; break; + case 0x0f1: device->chip = &nvf1_chipset; break; + case 0x106: device->chip = &nv106_chipset; break; + case 0x108: device->chip = &nv108_chipset; break; + case 0x117: device->chip = &nv117_chipset; break; + case 0x124: device->chip = &nv124_chipset; break; + case 0x126: device->chip = &nv126_chipset; break; + case 0x12b: device->chip = &nv12b_chipset; break; default: - ret = -EINVAL; - break; - } - - if (ret) { - nv_error(device, "unknown chipset, 0x%08x\n", boot0); - return ret; + nvdev_error(device, "unknown chipset (%08x)\n", boot0); + goto done; } - nv_info(device, "BOOT0 : 0x%08x\n", boot0); - nv_info(device, "Chipset: %s (NV%02X)\n", - device->cname, device->chipset); - nv_info(device, "Family : NV%02X\n", device->card_type); + nvdev_info(device, "NVIDIA %s (%08x)\n", + device->chip->name, boot0); /* determine frequency of timing crystal */ if ( device->card_type <= NV_10 || device->chipset < 0x17 || @@ -436,300 +2480,89 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, case 0x00400000: device->crystal = 27000; break; case 0x00400040: device->crystal = 25000; break; } - - nv_debug(device, "crystal freq: %dKHz\n", device->crystal); - } else - if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) { - device->cname = "NULL"; - device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass; - } - - if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && - !nv_subdev(device)->mmio) { - nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size); - if (!nv_subdev(device)->mmio) { - nv_error(device, "unable to map device registers\n"); - return -ENOMEM; - } - } - - /* ensure requested subsystems are available for use */ - for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) { - if (!(oclass = device->oclass[i]) || (disable & (1ULL << i))) - continue; - - if (device->subdev[i]) { - nvkm_object_ref(device->subdev[i], &devobj->subdev[i]); - continue; - } - - ret = nvkm_object_ctor(nv_object(device), NULL, oclass, - NULL, i, &devobj->subdev[i]); - if (ret == -ENODEV) - continue; - if (ret) - return ret; - - device->subdev[i] = devobj->subdev[i]; - - /* note: can't init *any* subdevs until devinit has been run - * due to not knowing exactly what the vbios init tables will - * mess with. devinit also can't be run until all of its - * dependencies have been created. - * - * this code delays init of any subdev until all of devinit's - * dependencies have been created, and then initialises each - * subdev in turn as they're created. - */ - while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) { - struct nvkm_object *subdev = devobj->subdev[c++]; - if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_inc(subdev); - if (ret) - return ret; - atomic_dec(&nv_object(device)->usecount); - } else - if (subdev) { - nvkm_subdev_reset(subdev); - } - } - } - - return 0; -} - -static struct nvkm_ofuncs -nvkm_devobj_ofuncs = { - .ctor = nvkm_devobj_ctor, - .dtor = nvkm_devobj_dtor, - .init = _nvkm_parent_init, - .fini = _nvkm_parent_fini, - .mthd = nvkm_devobj_mthd, -}; - -/****************************************************************************** - * nvkm_device: engine functions - *****************************************************************************/ - -struct nvkm_device * -nv_device(void *obj) -{ - struct nvkm_object *device = nv_object(obj); - if (device->engine == NULL) { - while (device && device->parent) - device = device->parent; } else { - device = &nv_object(obj)->engine->subdev.object; - if (device && device->parent) - device = device->parent; + device->chip = &null_chipset; } -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!device)) - nv_assert("BAD CAST -> NvDevice, 0x%08x\n", nv_hclass(obj)); -#endif - return (void *)device; -} -static struct nvkm_oclass -nvkm_device_sclass[] = { - { 0x0080, &nvkm_devobj_ofuncs }, - {} -}; + if (!device->name) + device->name = device->chip->name; -static int -nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - if (!WARN_ON(size != 0)) { - notify->size = 0; - notify->types = 1; - notify->index = 0; - return 0; - } - return -EINVAL; -} - -static const struct nvkm_event_func -nvkm_device_event_func = { - .ctor = nvkm_device_event_ctor, -}; - -static int -nvkm_device_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_device *device = (void *)object; - struct nvkm_object *subdev; - int ret, i; - - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_dec(subdev, suspend); - if (ret && suspend) - goto fail; - } - } - } - - ret = nvkm_acpi_fini(device, suspend); -fail: - for (; ret && i < NVDEV_SUBDEV_NR; i++) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_inc(subdev); - if (ret) { - /* XXX */ - } - } + if (mmio) { + device->pri = ioremap(mmio_base, mmio_size); + if (!device->pri) { + nvdev_error(device, "unable to map PRI\n"); + return -ENOMEM; } } - return ret; -} - -static int -nvkm_device_init(struct nvkm_object *object) -{ - struct nvkm_device *device = (void *)object; - struct nvkm_object *subdev; - int ret, i = 0; - - ret = nvkm_acpi_init(device); - if (ret) - goto fail; - - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_inc(subdev); - if (ret) - goto fail; - } else { - nvkm_subdev_reset(subdev); - } + mutex_init(&device->mutex); + + for (i = 0; i < NVKM_SUBDEV_NR; i++) { +#define _(s,m) case s: \ + if (device->chip->m && (subdev_mask & (1ULL << (s)))) { \ + ret = device->chip->m(device, (s), &device->m); \ + if (ret) { \ + subdev = nvkm_device_subdev(device, (s)); \ + nvkm_subdev_del(&subdev); \ + device->m = NULL; \ + if (ret != -ENODEV) { \ + nvdev_error(device, "%s ctor failed, %d\n", \ + nvkm_subdev_name[s], ret); \ + goto done; \ + } \ + } \ + } \ + break + switch (i) { + _(NVKM_SUBDEV_BAR , bar); + _(NVKM_SUBDEV_VBIOS , bios); + _(NVKM_SUBDEV_BUS , bus); + _(NVKM_SUBDEV_CLK , clk); + _(NVKM_SUBDEV_DEVINIT, devinit); + _(NVKM_SUBDEV_FB , fb); + _(NVKM_SUBDEV_FUSE , fuse); + _(NVKM_SUBDEV_GPIO , gpio); + _(NVKM_SUBDEV_I2C , i2c); + _(NVKM_SUBDEV_IBUS , ibus); + _(NVKM_SUBDEV_INSTMEM, imem); + _(NVKM_SUBDEV_LTC , ltc); + _(NVKM_SUBDEV_MC , mc); + _(NVKM_SUBDEV_MMU , mmu); + _(NVKM_SUBDEV_MXM , mxm); + _(NVKM_SUBDEV_PCI , pci); + _(NVKM_SUBDEV_PMU , pmu); + _(NVKM_SUBDEV_THERM , therm); + _(NVKM_SUBDEV_TIMER , timer); + _(NVKM_SUBDEV_VOLT , volt); + _(NVKM_ENGINE_BSP , bsp); + _(NVKM_ENGINE_CE0 , ce[0]); + _(NVKM_ENGINE_CE1 , ce[1]); + _(NVKM_ENGINE_CE2 , ce[2]); + _(NVKM_ENGINE_CIPHER , cipher); + _(NVKM_ENGINE_DISP , disp); + _(NVKM_ENGINE_DMAOBJ , dma); + _(NVKM_ENGINE_FIFO , fifo); + _(NVKM_ENGINE_GR , gr); + _(NVKM_ENGINE_IFB , ifb); + _(NVKM_ENGINE_ME , me); + _(NVKM_ENGINE_MPEG , mpeg); + _(NVKM_ENGINE_MSENC , msenc); + _(NVKM_ENGINE_MSPDEC , mspdec); + _(NVKM_ENGINE_MSPPP , msppp); + _(NVKM_ENGINE_MSVLD , msvld); + _(NVKM_ENGINE_PM , pm); + _(NVKM_ENGINE_SEC , sec); + _(NVKM_ENGINE_SW , sw); + _(NVKM_ENGINE_VIC , vic); + _(NVKM_ENGINE_VP , vp); + default: + WARN_ON(1); + continue; } +#undef _ } ret = 0; -fail: - for (--i; ret && i >= 0; i--) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) - nvkm_object_dec(subdev, false); - } - } - - if (ret) - nvkm_acpi_fini(device, false); - return ret; -} - -static void -nvkm_device_dtor(struct nvkm_object *object) -{ - struct nvkm_device *device = (void *)object; - - nvkm_event_fini(&device->event); - - mutex_lock(&nv_devices_mutex); - list_del(&device->head); - mutex_unlock(&nv_devices_mutex); - - if (nv_subdev(device)->mmio) - iounmap(nv_subdev(device)->mmio); - - nvkm_engine_destroy(&device->engine); -} - -resource_size_t -nv_device_resource_start(struct nvkm_device *device, unsigned int bar) -{ - if (nv_device_is_pci(device)) { - return pci_resource_start(device->pdev, bar); - } else { - struct resource *res; - res = platform_get_resource(device->platformdev, - IORESOURCE_MEM, bar); - if (!res) - return 0; - return res->start; - } -} - -resource_size_t -nv_device_resource_len(struct nvkm_device *device, unsigned int bar) -{ - if (nv_device_is_pci(device)) { - return pci_resource_len(device->pdev, bar); - } else { - struct resource *res; - res = platform_get_resource(device->platformdev, - IORESOURCE_MEM, bar); - if (!res) - return 0; - return resource_size(res); - } -} - -int -nv_device_get_irq(struct nvkm_device *device, bool stall) -{ - if (nv_device_is_pci(device)) { - return device->pdev->irq; - } else { - return platform_get_irq_byname(device->platformdev, - stall ? "stall" : "nonstall"); - } -} - -static struct nvkm_oclass -nvkm_device_oclass = { - .handle = NV_ENGINE(DEVICE, 0x00), - .ofuncs = &(struct nvkm_ofuncs) { - .dtor = nvkm_device_dtor, - .init = nvkm_device_init, - .fini = nvkm_device_fini, - }, -}; - -int -nvkm_device_create_(void *dev, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - int length, void **pobject) -{ - struct nvkm_device *device; - int ret = -EEXIST; - - mutex_lock(&nv_devices_mutex); - list_for_each_entry(device, &nv_devices, head) { - if (device->handle == name) - goto done; - } - - ret = nvkm_engine_create_(NULL, NULL, &nvkm_device_oclass, true, - "DEVICE", "device", length, pobject); - device = *pobject; - if (ret) - goto done; - - switch (type) { - case NVKM_BUS_PCI: - device->pdev = dev; - break; - case NVKM_BUS_PLATFORM: - device->platformdev = dev; - break; - } - device->handle = name; - device->cfgopt = cfg; - device->dbgopt = dbg; - device->name = sname; - - nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE"); - nv_engine(device)->sclass = nvkm_device_sclass; - list_add(&device->head, &nv_devices); - - ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); done: mutex_unlock(&nv_devices_mutex); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c index 0b794b13cec3..cf8bc068e9b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "priv.h" +#include "ctrl.h" #include <core/client.h> #include <subdev/clk.h> @@ -31,18 +31,18 @@ #include <nvif/unpack.h> static int -nvkm_control_mthd_pstate_info(struct nvkm_object *object, void *data, u32 size) +nvkm_control_mthd_pstate_info(struct nvkm_control *ctrl, void *data, u32 size) { union { struct nvif_control_pstate_info_v0 v0; } *args = data; - struct nvkm_clk *clk = nvkm_clk(object); + struct nvkm_clk *clk = ctrl->device->clk; int ret; - nv_ioctl(object, "control pstate info size %d\n", size); + nvif_ioctl(&ctrl->object, "control pstate info size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "control pstate info vers %d\n", - args->v0.version); + nvif_ioctl(&ctrl->object, "control pstate info vers %d\n", + args->v0.version); } else return ret; @@ -64,24 +64,24 @@ nvkm_control_mthd_pstate_info(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size) +nvkm_control_mthd_pstate_attr(struct nvkm_control *ctrl, void *data, u32 size) { union { struct nvif_control_pstate_attr_v0 v0; } *args = data; - struct nvkm_clk *clk = nvkm_clk(object); - struct nvkm_domain *domain; + struct nvkm_clk *clk = ctrl->device->clk; + const struct nvkm_domain *domain; struct nvkm_pstate *pstate; struct nvkm_cstate *cstate; int i = 0, j = -1; u32 lo, hi; int ret; - nv_ioctl(object, "control pstate attr size %d\n", size); + nvif_ioctl(&ctrl->object, "control pstate attr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "control pstate attr vers %d state %d " - "index %d\n", - args->v0.version, args->v0.state, args->v0.index); + nvif_ioctl(&ctrl->object, + "control pstate attr vers %d state %d index %d\n", + args->v0.version, args->v0.state, args->v0.index); if (!clk) return -ENODEV; if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) @@ -116,7 +116,7 @@ nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size) args->v0.state = pstate->pstate; } else { - lo = max(clk->read(clk, domain->name), 0); + lo = max(nvkm_clk_read(clk, domain->name), 0); hi = lo; } @@ -137,19 +137,19 @@ nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_control_mthd_pstate_user(struct nvkm_object *object, void *data, u32 size) +nvkm_control_mthd_pstate_user(struct nvkm_control *ctrl, void *data, u32 size) { union { struct nvif_control_pstate_user_v0 v0; } *args = data; - struct nvkm_clk *clk = nvkm_clk(object); + struct nvkm_clk *clk = ctrl->device->clk; int ret; - nv_ioctl(object, "control pstate user size %d\n", size); + nvif_ioctl(&ctrl->object, "control pstate user size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "control pstate user vers %d ustate %d " - "pwrsrc %d\n", args->v0.version, - args->v0.ustate, args->v0.pwrsrc); + nvif_ioctl(&ctrl->object, + "control pstate user vers %d ustate %d pwrsrc %d\n", + args->v0.version, args->v0.ustate, args->v0.pwrsrc); if (!clk) return -ENODEV; } else @@ -168,32 +168,44 @@ nvkm_control_mthd_pstate_user(struct nvkm_object *object, void *data, u32 size) static int nvkm_control_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { + struct nvkm_control *ctrl = nvkm_control(object); switch (mthd) { case NVIF_CONTROL_PSTATE_INFO: - return nvkm_control_mthd_pstate_info(object, data, size); + return nvkm_control_mthd_pstate_info(ctrl, data, size); case NVIF_CONTROL_PSTATE_ATTR: - return nvkm_control_mthd_pstate_attr(object, data, size); + return nvkm_control_mthd_pstate_attr(ctrl, data, size); case NVIF_CONTROL_PSTATE_USER: - return nvkm_control_mthd_pstate_user(object, data, size); + return nvkm_control_mthd_pstate_user(ctrl, data, size); default: break; } return -EINVAL; } -static struct nvkm_ofuncs -nvkm_control_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, +static const struct nvkm_object_func +nvkm_control = { .mthd = nvkm_control_mthd, }; -struct nvkm_oclass -nvkm_control_oclass[] = { - { .handle = NVIF_IOCTL_NEW_V0_CONTROL, - .ofuncs = &nvkm_control_ofuncs - }, - {} +static int +nvkm_control_new(struct nvkm_device *device, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_control *ctrl; + + if (!(ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL))) + return -ENOMEM; + *pobject = &ctrl->object; + ctrl->device = device; + + nvkm_object_ctor(&nvkm_control, oclass, &ctrl->object); + return 0; +} + +const struct nvkm_device_oclass +nvkm_control_oclass = { + .base.oclass = NVIF_IOCTL_NEW_V0_CONTROL, + .base.minver = -1, + .base.maxver = -1, + .ctor = nvkm_control_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h new file mode 100644 index 000000000000..20249d8e444d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h @@ -0,0 +1,12 @@ +#ifndef __NVKM_DEVICE_CTRL_H__ +#define __NVKM_DEVICE_CTRL_H__ +#define nvkm_control(p) container_of((p), struct nvkm_control, object) +#include <core/device.h> + +struct nvkm_control { + struct nvkm_object object; + struct nvkm_device *device; +}; + +extern const struct nvkm_device_oclass nvkm_control_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c deleted file mode 100644 index 82b38d7e9730..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ /dev/null @@ -1,358 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/fuse.h> -#include <subdev/clk.h> -#include <subdev/therm.h> -#include <subdev/mxm.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/ltc.h> -#include <subdev/ibus.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> -#include <subdev/bar.h> -#include <subdev/pmu.h> -#include <subdev/volt.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/mspdec.h> -#include <engine/bsp.h> -#include <engine/msvld.h> -#include <engine/msppp.h> -#include <engine/ce.h> -#include <engine/disp.h> -#include <engine/pm.h> - -int -gf100_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0xc0: - device->cname = "GF100"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf100_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xc4: - device->cname = "GF104"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xc3: - device->cname = "GF106"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xce: - device->cname = "GF114"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xcf: - device->cname = "GF116"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xc1: - device->cname = "GF108"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf108_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xc8: - device->cname = "GF110"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf110_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xd9: - device->cname = "GF119"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf119_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - case 0xd7: - device->cname = "GF117"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf117_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; - break; - default: - nv_fatal(device, "unknown Fermi chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c deleted file mode 100644 index 6a9483f65d83..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ /dev/null @@ -1,326 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/fuse.h> -#include <subdev/clk.h> -#include <subdev/therm.h> -#include <subdev/mxm.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/ltc.h> -#include <subdev/ibus.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> -#include <subdev/bar.h> -#include <subdev/pmu.h> -#include <subdev/volt.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/disp.h> -#include <engine/ce.h> -#include <engine/bsp.h> -#include <engine/msvld.h> -#include <engine/mspdec.h> -#include <engine/msppp.h> -#include <engine/pm.h> - -int -gk104_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0xe4: - device->cname = "GK104"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; - break; - case 0xe7: - device->cname = "GK107"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; - break; - case 0xe6: - device->cname = "GK106"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; - break; - case 0xea: - device->cname = "GK20A"; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk20a_clk_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass; - break; - case 0xf0: - device->cname = "GK110"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk110_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; - break; - case 0xf1: - device->cname = "GK110B"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk110b_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; - break; - case 0x106: - device->cname = "GK208B"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - break; - case 0x108: - device->cname = "GK208"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - break; - default: - nv_fatal(device, "unknown Kepler chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c deleted file mode 100644 index 70abf1ec7c98..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ /dev/null @@ -1,190 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/fuse.h> -#include <subdev/clk.h> -#include <subdev/therm.h> -#include <subdev/mxm.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/ltc.h> -#include <subdev/ibus.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> -#include <subdev/bar.h> -#include <subdev/pmu.h> -#include <subdev/volt.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/disp.h> -#include <engine/ce.h> -#include <engine/bsp.h> -#include <engine/msvld.h> -#include <engine/mspdec.h> -#include <engine/msppp.h> -#include <engine/pm.h> - -int -gm100_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x117: - device->cname = "GM107"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; - -#if 0 - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; -#endif - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; -#if 0 - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; -#endif - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; -#if 0 - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; -#endif - break; - case 0x124: - device->cname = "GM204"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; -#if 0 - /* looks to be some non-trivial changes */ - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - /* priv ring says no to 0x10eb14 writes */ - device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; -#endif - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; -#if 0 - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; -#endif - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gm204_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gm204_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gm204_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; -#if 0 - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; -#endif - break; - case 0x126: - device->cname = "GM206"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; -#if 0 - /* looks to be some non-trivial changes */ - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; - /* priv ring says no to 0x10eb14 writes */ - device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; -#endif - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; -#if 0 - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; -#endif - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gm206_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gm204_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gm204_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; -#if 0 - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; -#endif - break; - default: - nv_fatal(device, "unknown Maxwell chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c deleted file mode 100644 index 5a2ae043b478..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ /dev/null @@ -1,89 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/i2c.h> -#include <subdev/clk.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/disp.h> - -int -nv04_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x04: - device->cname = "NV04"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x05: - device->cname = "NV05"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - default: - nv_fatal(device, "unknown RIVA chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c deleted file mode 100644 index 94a1ca45e94a..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ /dev/null @@ -1,204 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/clk.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/disp.h> - -int -nv10_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x10: - device->cname = "NV10"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x15: - device->cname = "NV15"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x16: - device->cname = "NV16"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x1a: - device->cname = "nForce"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x11: - device->cname = "NV11"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x17: - device->cname = "NV17"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x1f: - device->cname = "nForce2"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x18: - device->cname = "NV18"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - default: - nv_fatal(device, "unknown Celsius chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c deleted file mode 100644 index d5ec8937df68..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ /dev/null @@ -1,131 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/clk.h> -#include <subdev/therm.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/disp.h> - -int -nv20_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x20: - device->cname = "NV20"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv20_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv20_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x25: - device->cname = "NV25"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x28: - device->cname = "NV28"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x2a: - device->cname = "NV2A"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv2a_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - default: - nv_fatal(device, "unknown Kelvin chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c deleted file mode 100644 index dda09621e898..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ /dev/null @@ -1,153 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/clk.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/mpeg.h> -#include <engine/disp.h> - -int -nv30_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x30: - device->cname = "NV30"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x35: - device->cname = "NV35"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv35_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x31: - device->cname = "NV31"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x36: - device->cname = "NV36"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv36_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - case 0x34: - device->cname = "NV34"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv34_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - break; - default: - nv_fatal(device, "unknown Rankine chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c deleted file mode 100644 index c6301361d14f..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ /dev/null @@ -1,427 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/mmu.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/clk.h> -#include <subdev/therm.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> -#include <subdev/volt.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/mpeg.h> -#include <engine/disp.h> -#include <engine/pm.h> - -int -nv40_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x40: - device->cname = "NV40"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x41: - device->cname = "NV41"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x42: - device->cname = "NV42"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x43: - device->cname = "NV43"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x45: - device->cname = "NV45"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x47: - device->cname = "G70"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv47_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x49: - device->cname = "G71"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x4b: - device->cname = "G73"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x44: - device->cname = "NV44"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x46: - device->cname = "G72"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x4a: - device->cname = "NV44A"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x4c: - device->cname = "C61"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x4e: - device->cname = "C51"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x63: - device->cname = "C73"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x67: - device->cname = "C67"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - case 0x68: - device->cname = "C68"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; - break; - default: - nv_fatal(device, "unknown Curie chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c deleted file mode 100644 index 249b84454612..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ /dev/null @@ -1,478 +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 <subdev/bios.h> -#include <subdev/bus.h> -#include <subdev/gpio.h> -#include <subdev/i2c.h> -#include <subdev/fuse.h> -#include <subdev/clk.h> -#include <subdev/therm.h> -#include <subdev/mxm.h> -#include <subdev/devinit.h> -#include <subdev/mc.h> -#include <subdev/timer.h> -#include <subdev/fb.h> -#include <subdev/instmem.h> -#include <subdev/mmu.h> -#include <subdev/bar.h> -#include <subdev/pmu.h> -#include <subdev/volt.h> - -#include <engine/dmaobj.h> -#include <engine/fifo.h> -#include <engine/sw.h> -#include <engine/gr.h> -#include <engine/mpeg.h> -#include <engine/vp.h> -#include <engine/cipher.h> -#include <engine/sec.h> -#include <engine/bsp.h> -#include <engine/msvld.h> -#include <engine/mspdec.h> -#include <engine/msppp.h> -#include <engine/ce.h> -#include <engine/disp.h> -#include <engine/pm.h> - -int -nv50_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x50: - device->cname = "G80"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv50_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv50_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv50_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; - break; - case 0x84: - device->cname = "G84"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0x86: - device->cname = "G86"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0x92: - device->cname = "G92"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0x94: - device->cname = "G94"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0x96: - device->cname = "G96"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0x98: - device->cname = "G98"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0xa0: - device->cname = "G200"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt200_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0xaa: - device->cname = "MCP77/MCP78"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0xac: - device->cname = "MCP79/MCP7A"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; - break; - case 0xa3: - device->cname = "GT215"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; - break; - case 0xa5: - device->cname = "GT216"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; - break; - case 0xa8: - device->cname = "GT218"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; - break; - case 0xaf: - device->cname = "MCP89"; - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = mcp89_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = mcp89_fb_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; - break; - default: - nv_fatal(device, "unknown Tesla chipset\n"); - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c new file mode 100644 index 000000000000..e8eb14e438f4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -0,0 +1,1686 @@ +/* + * 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 <core/pci.h> +#include "priv.h" + +struct nvkm_device_pci_device { + u16 device; + const char *name; + const struct nvkm_device_pci_vendor *vendor; +}; + +struct nvkm_device_pci_vendor { + u16 vendor; + u16 device; + const char *name; + const struct nvkm_device_quirk quirk; +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0189[] = { + /* Apple iMac G4 NV18 */ + { 0x10de, 0x0010, NULL, { .tv_gpio = 4 } }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_01f0[] = { + /* MSI nForce2 IGP */ + { 0x1462, 0x5710, NULL, { .tv_pin_mask = 0xc } }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0322[] = { + /* Zotac FX5200 */ + { 0x19da, 0x1035, NULL, { .tv_pin_mask = 0xc } }, + { 0x19da, 0x2035, NULL, { .tv_pin_mask = 0xc } }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_05e7[] = { + { 0x10de, 0x0595, "Tesla T10 Processor" }, + { 0x10de, 0x068f, "Tesla T10 Processor" }, + { 0x10de, 0x0697, "Tesla M1060" }, + { 0x10de, 0x0714, "Tesla M1060" }, + { 0x10de, 0x0743, "Tesla M1060" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0609[] = { + { 0x106b, 0x00a7, "GeForce 8800 GS" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_062e[] = { + { 0x106b, 0x0605, "GeForce GT 130" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0649[] = { + { 0x1043, 0x202d, "GeForce GT 220M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0652[] = { + { 0x152d, 0x0850, "GeForce GT 240M LE" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0654[] = { + { 0x1043, 0x14a2, "GeForce GT 320M" }, + { 0x1043, 0x14d2, "GeForce GT 320M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0655[] = { + { 0x106b, 0x0633, "GeForce GT 120" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0656[] = { + { 0x106b, 0x0693, "GeForce GT 120" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06d1[] = { + { 0x10de, 0x0771, "Tesla C2050" }, + { 0x10de, 0x0772, "Tesla C2070" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06d2[] = { + { 0x10de, 0x088f, "Tesla X2070" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06de[] = { + { 0x10de, 0x0773, "Tesla S2050" }, + { 0x10de, 0x082f, "Tesla M2050" }, + { 0x10de, 0x0840, "Tesla X2070" }, + { 0x10de, 0x0842, "Tesla M2050" }, + { 0x10de, 0x0846, "Tesla M2050" }, + { 0x10de, 0x0866, "Tesla M2050" }, + { 0x10de, 0x0907, "Tesla M2050" }, + { 0x10de, 0x091e, "Tesla M2050" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06e8[] = { + { 0x103c, 0x360b, "GeForce 9200M GE" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06f9[] = { + { 0x10de, 0x060d, "Quadro FX 370 Low Profile" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06ff[] = { + { 0x10de, 0x0711, "HICx8 + Graphics" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0866[] = { + { 0x106b, 0x00b1, "GeForce 9400M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0872[] = { + { 0x1043, 0x1c42, "GeForce G205M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0873[] = { + { 0x1043, 0x1c52, "GeForce G205M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a6e[] = { + { 0x17aa, 0x3607, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a70[] = { + { 0x17aa, 0x3605, "Second Generation ION" }, + { 0x17aa, 0x3617, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a73[] = { + { 0x17aa, 0x3607, "Second Generation ION" }, + { 0x17aa, 0x3610, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a74[] = { + { 0x17aa, 0x903a, "GeForce G210" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a75[] = { + { 0x17aa, 0x3605, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a7a[] = { + { 0x1462, 0xaa51, "GeForce 405" }, + { 0x1462, 0xaa58, "GeForce 405" }, + { 0x1462, 0xac71, "GeForce 405" }, + { 0x1462, 0xac82, "GeForce 405" }, + { 0x1642, 0x3980, "GeForce 405" }, + { 0x17aa, 0x3950, "GeForce 405M" }, + { 0x17aa, 0x397d, "GeForce 405M" }, + { 0x1b0a, 0x90b4, "GeForce 405" }, + { 0x1bfd, 0x0003, "GeForce 405" }, + { 0x1bfd, 0x8006, "GeForce 405" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0dd8[] = { + { 0x10de, 0x0914, "Quadro 2000D" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0de9[] = { + { 0x1025, 0x0692, "GeForce GT 620M" }, + { 0x1025, 0x0725, "GeForce GT 620M" }, + { 0x1025, 0x0728, "GeForce GT 620M" }, + { 0x1025, 0x072b, "GeForce GT 620M" }, + { 0x1025, 0x072e, "GeForce GT 620M" }, + { 0x1025, 0x0753, "GeForce GT 620M" }, + { 0x1025, 0x0754, "GeForce GT 620M" }, + { 0x17aa, 0x3977, "GeForce GT 640M LE" }, + { 0x1b0a, 0x2210, "GeForce GT 635M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0dea[] = { + { 0x17aa, 0x365a, "GeForce 615" }, + { 0x17aa, 0x365b, "GeForce 615" }, + { 0x17aa, 0x365e, "GeForce 615" }, + { 0x17aa, 0x3660, "GeForce 615" }, + { 0x17aa, 0x366c, "GeForce 615" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0df4[] = { + { 0x152d, 0x0952, "GeForce GT 630M" }, + { 0x152d, 0x0953, "GeForce GT 630M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0fd2[] = { + { 0x1028, 0x0595, "GeForce GT 640M LE" }, + { 0x1028, 0x05b2, "GeForce GT 640M LE" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0fe3[] = { + { 0x103c, 0x2b16, "GeForce GT 745A" }, + { 0x17aa, 0x3675, "GeForce GT 745A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_104b[] = { + { 0x1043, 0x844c, "GeForce GT 625" }, + { 0x1043, 0x846b, "GeForce GT 625" }, + { 0x1462, 0xb590, "GeForce GT 625" }, + { 0x174b, 0x0625, "GeForce GT 625" }, + { 0x174b, 0xa625, "GeForce GT 625" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1058[] = { + { 0x103c, 0x2af1, "GeForce 610" }, + { 0x17aa, 0x3682, "GeForce 800A" }, + { 0x17aa, 0x3692, "GeForce 705A" }, + { 0x17aa, 0x3695, "GeForce 800A" }, + { 0x17aa, 0x36a8, "GeForce 800A" }, + { 0x17aa, 0x36ac, "GeForce 800A" }, + { 0x17aa, 0x36ad, "GeForce 800A" }, + { 0x705a, 0x3682, "GeForce 800A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_105b[] = { + { 0x103c, 0x2afb, "GeForce 705A" }, + { 0x17aa, 0x36a1, "GeForce 800A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1091[] = { + { 0x10de, 0x088e, "Tesla X2090" }, + { 0x10de, 0x0891, "Tesla X2090" }, + { 0x10de, 0x0974, "Tesla X2090" }, + { 0x10de, 0x098d, "Tesla X2090" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1096[] = { + { 0x10de, 0x0911, "Tesla C2050" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1140[] = { + { 0x1019, 0x999f, "GeForce GT 720M" }, + { 0x1025, 0x0600, "GeForce GT 620M" }, + { 0x1025, 0x0606, "GeForce GT 620M" }, + { 0x1025, 0x064a, "GeForce GT 620M" }, + { 0x1025, 0x064c, "GeForce GT 620M" }, + { 0x1025, 0x067a, "GeForce GT 620M" }, + { 0x1025, 0x0680, "GeForce GT 620M" }, + { 0x1025, 0x0686, "GeForce 710M" }, + { 0x1025, 0x0689, "GeForce 710M" }, + { 0x1025, 0x068b, "GeForce 710M" }, + { 0x1025, 0x068d, "GeForce 710M" }, + { 0x1025, 0x068e, "GeForce 710M" }, + { 0x1025, 0x0691, "GeForce 710M" }, + { 0x1025, 0x0692, "GeForce GT 620M" }, + { 0x1025, 0x0694, "GeForce GT 620M" }, + { 0x1025, 0x0702, "GeForce GT 620M" }, + { 0x1025, 0x0719, "GeForce GT 620M" }, + { 0x1025, 0x0725, "GeForce GT 620M" }, + { 0x1025, 0x0728, "GeForce GT 620M" }, + { 0x1025, 0x072b, "GeForce GT 620M" }, + { 0x1025, 0x072e, "GeForce GT 620M" }, + { 0x1025, 0x0732, "GeForce GT 620M" }, + { 0x1025, 0x0763, "GeForce GT 720M" }, + { 0x1025, 0x0773, "GeForce 710M" }, + { 0x1025, 0x0774, "GeForce 710M" }, + { 0x1025, 0x0776, "GeForce GT 720M" }, + { 0x1025, 0x077a, "GeForce 710M" }, + { 0x1025, 0x077b, "GeForce 710M" }, + { 0x1025, 0x077c, "GeForce 710M" }, + { 0x1025, 0x077d, "GeForce 710M" }, + { 0x1025, 0x077e, "GeForce 710M" }, + { 0x1025, 0x077f, "GeForce 710M" }, + { 0x1025, 0x0781, "GeForce GT 720M" }, + { 0x1025, 0x0798, "GeForce GT 720M" }, + { 0x1025, 0x0799, "GeForce GT 720M" }, + { 0x1025, 0x079b, "GeForce GT 720M" }, + { 0x1025, 0x079c, "GeForce GT 720M" }, + { 0x1025, 0x0807, "GeForce GT 720M" }, + { 0x1025, 0x0821, "GeForce 820M" }, + { 0x1025, 0x0823, "GeForce GT 720M" }, + { 0x1025, 0x0830, "GeForce GT 720M" }, + { 0x1025, 0x0833, "GeForce GT 720M" }, + { 0x1025, 0x0837, "GeForce GT 720M" }, + { 0x1025, 0x083e, "GeForce 820M" }, + { 0x1025, 0x0841, "GeForce 710M" }, + { 0x1025, 0x0853, "GeForce 820M" }, + { 0x1025, 0x0854, "GeForce 820M" }, + { 0x1025, 0x0855, "GeForce 820M" }, + { 0x1025, 0x0856, "GeForce 820M" }, + { 0x1025, 0x0857, "GeForce 820M" }, + { 0x1025, 0x0858, "GeForce 820M" }, + { 0x1025, 0x0863, "GeForce 820M" }, + { 0x1025, 0x0868, "GeForce 820M" }, + { 0x1025, 0x0869, "GeForce 810M" }, + { 0x1025, 0x0873, "GeForce 820M" }, + { 0x1025, 0x0878, "GeForce 820M" }, + { 0x1025, 0x087b, "GeForce 820M" }, + { 0x1025, 0x087f, "GeForce 820M" }, + { 0x1025, 0x0881, "GeForce 820M" }, + { 0x1025, 0x0885, "GeForce 820M" }, + { 0x1025, 0x088a, "GeForce 820M" }, + { 0x1025, 0x089b, "GeForce 820M" }, + { 0x1025, 0x0921, "GeForce 820M" }, + { 0x1025, 0x092e, "GeForce 810M" }, + { 0x1025, 0x092f, "GeForce 820M" }, + { 0x1025, 0x0932, "GeForce 820M" }, + { 0x1025, 0x093a, "GeForce 820M" }, + { 0x1025, 0x093c, "GeForce 820M" }, + { 0x1025, 0x093f, "GeForce 820M" }, + { 0x1025, 0x0941, "GeForce 820M" }, + { 0x1025, 0x0945, "GeForce 820M" }, + { 0x1025, 0x0954, "GeForce 820M" }, + { 0x1025, 0x0965, "GeForce 820M" }, + { 0x1028, 0x054d, "GeForce GT 630M" }, + { 0x1028, 0x054e, "GeForce GT 630M" }, + { 0x1028, 0x0554, "GeForce GT 620M" }, + { 0x1028, 0x0557, "GeForce GT 620M" }, + { 0x1028, 0x0562, "GeForce GT625M" }, + { 0x1028, 0x0565, "GeForce GT 630M" }, + { 0x1028, 0x0568, "GeForce GT 630M" }, + { 0x1028, 0x0590, "GeForce GT 630M" }, + { 0x1028, 0x0592, "GeForce GT625M" }, + { 0x1028, 0x0594, "GeForce GT625M" }, + { 0x1028, 0x0595, "GeForce GT625M" }, + { 0x1028, 0x05a2, "GeForce GT625M" }, + { 0x1028, 0x05b1, "GeForce GT625M" }, + { 0x1028, 0x05b3, "GeForce GT625M" }, + { 0x1028, 0x05da, "GeForce GT 630M" }, + { 0x1028, 0x05de, "GeForce GT 720M" }, + { 0x1028, 0x05e0, "GeForce GT 720M" }, + { 0x1028, 0x05e8, "GeForce GT 630M" }, + { 0x1028, 0x05f4, "GeForce GT 720M" }, + { 0x1028, 0x060f, "GeForce GT 720M" }, + { 0x1028, 0x062f, "GeForce GT 720M" }, + { 0x1028, 0x064e, "GeForce 820M" }, + { 0x1028, 0x0652, "GeForce 820M" }, + { 0x1028, 0x0653, "GeForce 820M" }, + { 0x1028, 0x0655, "GeForce 820M" }, + { 0x1028, 0x065e, "GeForce 820M" }, + { 0x1028, 0x0662, "GeForce 820M" }, + { 0x1028, 0x068d, "GeForce 820M" }, + { 0x1028, 0x06ad, "GeForce 820M" }, + { 0x1028, 0x06ae, "GeForce 820M" }, + { 0x1028, 0x06af, "GeForce 820M" }, + { 0x1028, 0x06b0, "GeForce 820M" }, + { 0x1028, 0x06c0, "GeForce 820M" }, + { 0x1028, 0x06c1, "GeForce 820M" }, + { 0x103c, 0x18ef, "GeForce GT 630M" }, + { 0x103c, 0x18f9, "GeForce GT 630M" }, + { 0x103c, 0x18fb, "GeForce GT 630M" }, + { 0x103c, 0x18fd, "GeForce GT 630M" }, + { 0x103c, 0x18ff, "GeForce GT 630M" }, + { 0x103c, 0x218a, "GeForce 820M" }, + { 0x103c, 0x21bb, "GeForce 820M" }, + { 0x103c, 0x21bc, "GeForce 820M" }, + { 0x103c, 0x220e, "GeForce 820M" }, + { 0x103c, 0x2210, "GeForce 820M" }, + { 0x103c, 0x2212, "GeForce 820M" }, + { 0x103c, 0x2214, "GeForce 820M" }, + { 0x103c, 0x2218, "GeForce 820M" }, + { 0x103c, 0x225b, "GeForce 820M" }, + { 0x103c, 0x225d, "GeForce 820M" }, + { 0x103c, 0x226d, "GeForce 820M" }, + { 0x103c, 0x226f, "GeForce 820M" }, + { 0x103c, 0x22d2, "GeForce 820M" }, + { 0x103c, 0x22d9, "GeForce 820M" }, + { 0x103c, 0x2335, "GeForce 820M" }, + { 0x103c, 0x2337, "GeForce 820M" }, + { 0x103c, 0x2aef, "GeForce GT 720A" }, + { 0x103c, 0x2af9, "GeForce 710A" }, + { 0x1043, 0x10dd, "NVS 5200M" }, + { 0x1043, 0x10ed, "NVS 5200M" }, + { 0x1043, 0x11fd, "GeForce GT 720M" }, + { 0x1043, 0x124d, "GeForce GT 720M" }, + { 0x1043, 0x126d, "GeForce GT 720M" }, + { 0x1043, 0x131d, "GeForce GT 720M" }, + { 0x1043, 0x13fd, "GeForce GT 720M" }, + { 0x1043, 0x14c7, "GeForce GT 720M" }, + { 0x1043, 0x1507, "GeForce GT 620M" }, + { 0x1043, 0x15ad, "GeForce 820M" }, + { 0x1043, 0x15ed, "GeForce 820M" }, + { 0x1043, 0x160d, "GeForce 820M" }, + { 0x1043, 0x163d, "GeForce 820M" }, + { 0x1043, 0x165d, "GeForce 820M" }, + { 0x1043, 0x166d, "GeForce 820M" }, + { 0x1043, 0x16cd, "GeForce 820M" }, + { 0x1043, 0x16dd, "GeForce 820M" }, + { 0x1043, 0x170d, "GeForce 820M" }, + { 0x1043, 0x176d, "GeForce 820M" }, + { 0x1043, 0x178d, "GeForce 820M" }, + { 0x1043, 0x179d, "GeForce 820M" }, + { 0x1043, 0x2132, "GeForce GT 620M" }, + { 0x1043, 0x2136, "NVS 5200M" }, + { 0x1043, 0x21ba, "GeForce GT 720M" }, + { 0x1043, 0x21fa, "GeForce GT 720M" }, + { 0x1043, 0x220a, "GeForce GT 720M" }, + { 0x1043, 0x221a, "GeForce GT 720M" }, + { 0x1043, 0x223a, "GeForce GT 710M" }, + { 0x1043, 0x224a, "GeForce GT 710M" }, + { 0x1043, 0x227a, "GeForce 820M" }, + { 0x1043, 0x228a, "GeForce 820M" }, + { 0x1043, 0x22fa, "GeForce 820M" }, + { 0x1043, 0x232a, "GeForce 820M" }, + { 0x1043, 0x233a, "GeForce 820M" }, + { 0x1043, 0x235a, "GeForce 820M" }, + { 0x1043, 0x236a, "GeForce 820M" }, + { 0x1043, 0x238a, "GeForce 820M" }, + { 0x1043, 0x8595, "GeForce GT 720M" }, + { 0x1043, 0x85ea, "GeForce GT 720M" }, + { 0x1043, 0x85eb, "GeForce 820M" }, + { 0x1043, 0x85ec, "GeForce 820M" }, + { 0x1043, 0x85ee, "GeForce GT 720M" }, + { 0x1043, 0x85f3, "GeForce 820M" }, + { 0x1043, 0x860e, "GeForce 820M" }, + { 0x1043, 0x861a, "GeForce 820M" }, + { 0x1043, 0x861b, "GeForce 820M" }, + { 0x1043, 0x8628, "GeForce 820M" }, + { 0x1043, 0x8643, "GeForce 820M" }, + { 0x1043, 0x864c, "GeForce 820M" }, + { 0x1043, 0x8652, "GeForce 820M" }, + { 0x1043, 0x8660, "GeForce 820M" }, + { 0x1043, 0x8661, "GeForce 820M" }, + { 0x105b, 0x0dac, "GeForce GT 720M" }, + { 0x105b, 0x0dad, "GeForce GT 720M" }, + { 0x105b, 0x0ef3, "GeForce GT 720M" }, + { 0x10cf, 0x17f5, "GeForce GT 720M" }, + { 0x1179, 0xfa01, "GeForce 710M" }, + { 0x1179, 0xfa02, "GeForce 710M" }, + { 0x1179, 0xfa03, "GeForce 710M" }, + { 0x1179, 0xfa05, "GeForce 710M" }, + { 0x1179, 0xfa11, "GeForce 710M" }, + { 0x1179, 0xfa13, "GeForce 710M" }, + { 0x1179, 0xfa18, "GeForce 710M" }, + { 0x1179, 0xfa19, "GeForce 710M" }, + { 0x1179, 0xfa21, "GeForce 710M" }, + { 0x1179, 0xfa23, "GeForce 710M" }, + { 0x1179, 0xfa2a, "GeForce 710M" }, + { 0x1179, 0xfa32, "GeForce 710M" }, + { 0x1179, 0xfa33, "GeForce 710M" }, + { 0x1179, 0xfa36, "GeForce 710M" }, + { 0x1179, 0xfa38, "GeForce 710M" }, + { 0x1179, 0xfa42, "GeForce 710M" }, + { 0x1179, 0xfa43, "GeForce 710M" }, + { 0x1179, 0xfa45, "GeForce 710M" }, + { 0x1179, 0xfa47, "GeForce 710M" }, + { 0x1179, 0xfa49, "GeForce 710M" }, + { 0x1179, 0xfa58, "GeForce 710M" }, + { 0x1179, 0xfa59, "GeForce 710M" }, + { 0x1179, 0xfa88, "GeForce 710M" }, + { 0x1179, 0xfa89, "GeForce 710M" }, + { 0x144d, 0xb092, "GeForce GT 620M" }, + { 0x144d, 0xc0d5, "GeForce GT 630M" }, + { 0x144d, 0xc0d7, "GeForce GT 620M" }, + { 0x144d, 0xc0e2, "NVS 5200M" }, + { 0x144d, 0xc0e3, "NVS 5200M" }, + { 0x144d, 0xc0e4, "NVS 5200M" }, + { 0x144d, 0xc10d, "GeForce 820M" }, + { 0x144d, 0xc652, "GeForce GT 620M" }, + { 0x144d, 0xc709, "GeForce 710M" }, + { 0x144d, 0xc711, "GeForce 710M" }, + { 0x144d, 0xc736, "GeForce 710M" }, + { 0x144d, 0xc737, "GeForce 710M" }, + { 0x144d, 0xc745, "GeForce 820M" }, + { 0x144d, 0xc750, "GeForce 820M" }, + { 0x1462, 0x10b8, "GeForce GT 710M" }, + { 0x1462, 0x10e9, "GeForce GT 720M" }, + { 0x1462, 0x1116, "GeForce 820M" }, + { 0x1462, 0xaa33, "GeForce 720M" }, + { 0x1462, 0xaaa2, "GeForce GT 720M" }, + { 0x1462, 0xaaa3, "GeForce 820M" }, + { 0x1462, 0xacb2, "GeForce GT 720M" }, + { 0x1462, 0xacc1, "GeForce GT 720M" }, + { 0x1462, 0xae61, "GeForce 720M" }, + { 0x1462, 0xae65, "GeForce GT 720M" }, + { 0x1462, 0xae6a, "GeForce 820M" }, + { 0x1462, 0xae71, "GeForce GT 720M" }, + { 0x14c0, 0x0083, "GeForce 820M" }, + { 0x152d, 0x0926, "GeForce 620M" }, + { 0x152d, 0x0982, "GeForce GT 630M" }, + { 0x152d, 0x0983, "GeForce GT 630M" }, + { 0x152d, 0x1005, "GeForce GT820M" }, + { 0x152d, 0x1012, "GeForce 710M" }, + { 0x152d, 0x1019, "GeForce 820M" }, + { 0x152d, 0x1030, "GeForce GT 630M" }, + { 0x152d, 0x1055, "GeForce 710M" }, + { 0x152d, 0x1067, "GeForce GT 720M" }, + { 0x152d, 0x1092, "GeForce 820M" }, + { 0x17aa, 0x2200, "NVS 5200M" }, + { 0x17aa, 0x2213, "GeForce GT 720M" }, + { 0x17aa, 0x2220, "GeForce GT 720M" }, + { 0x17aa, 0x309c, "GeForce GT 720A" }, + { 0x17aa, 0x30b4, "GeForce 820A" }, + { 0x17aa, 0x30b7, "GeForce 720A" }, + { 0x17aa, 0x30e4, "GeForce 820A" }, + { 0x17aa, 0x361b, "GeForce 820A" }, + { 0x17aa, 0x361c, "GeForce 820A" }, + { 0x17aa, 0x361d, "GeForce 820A" }, + { 0x17aa, 0x3656, "GeForce GT620M" }, + { 0x17aa, 0x365a, "GeForce 705M" }, + { 0x17aa, 0x365e, "GeForce 800M" }, + { 0x17aa, 0x3661, "GeForce 820A" }, + { 0x17aa, 0x366c, "GeForce 800M" }, + { 0x17aa, 0x3685, "GeForce 800M" }, + { 0x17aa, 0x3686, "GeForce 800M" }, + { 0x17aa, 0x3687, "GeForce 705A" }, + { 0x17aa, 0x3696, "GeForce 820A" }, + { 0x17aa, 0x369b, "GeForce 820A" }, + { 0x17aa, 0x369c, "GeForce 820A" }, + { 0x17aa, 0x369d, "GeForce 820A" }, + { 0x17aa, 0x369e, "GeForce 820A" }, + { 0x17aa, 0x36a6, "GeForce 820A" }, + { 0x17aa, 0x36a7, "GeForce 820A" }, + { 0x17aa, 0x36a9, "GeForce 820A" }, + { 0x17aa, 0x36af, "GeForce 820A" }, + { 0x17aa, 0x36b0, "GeForce 820A" }, + { 0x17aa, 0x36b6, "GeForce 820A" }, + { 0x17aa, 0x3800, "GeForce GT 720M" }, + { 0x17aa, 0x3801, "GeForce GT 720M" }, + { 0x17aa, 0x3802, "GeForce GT 720M" }, + { 0x17aa, 0x3803, "GeForce GT 720M" }, + { 0x17aa, 0x3804, "GeForce GT 720M" }, + { 0x17aa, 0x3806, "GeForce GT 720M" }, + { 0x17aa, 0x3808, "GeForce GT 720M" }, + { 0x17aa, 0x380d, "GeForce 820M" }, + { 0x17aa, 0x380e, "GeForce 820M" }, + { 0x17aa, 0x380f, "GeForce 820M" }, + { 0x17aa, 0x3811, "GeForce 820M" }, + { 0x17aa, 0x3812, "GeForce 820M" }, + { 0x17aa, 0x3813, "GeForce 820M" }, + { 0x17aa, 0x3816, "GeForce 820M" }, + { 0x17aa, 0x3817, "GeForce 820M" }, + { 0x17aa, 0x3818, "GeForce 820M" }, + { 0x17aa, 0x381a, "GeForce 820M" }, + { 0x17aa, 0x381c, "GeForce 820M" }, + { 0x17aa, 0x381d, "GeForce 820M" }, + { 0x17aa, 0x3901, "GeForce 610M" }, + { 0x17aa, 0x3902, "GeForce 710M" }, + { 0x17aa, 0x3903, "GeForce 710M" }, + { 0x17aa, 0x3904, "GeForce GT 625M" }, + { 0x17aa, 0x3905, "GeForce GT 720M" }, + { 0x17aa, 0x3907, "GeForce 820M" }, + { 0x17aa, 0x3910, "GeForce GT 720M" }, + { 0x17aa, 0x3912, "GeForce GT 720M" }, + { 0x17aa, 0x3913, "GeForce 820M" }, + { 0x17aa, 0x3915, "GeForce 820M" }, + { 0x17aa, 0x3983, "GeForce 610M" }, + { 0x17aa, 0x5001, "GeForce 610M" }, + { 0x17aa, 0x5003, "GeForce GT 720M" }, + { 0x17aa, 0x5005, "GeForce 705M" }, + { 0x17aa, 0x500d, "GeForce GT 620M" }, + { 0x17aa, 0x5014, "GeForce 710M" }, + { 0x17aa, 0x5017, "GeForce 710M" }, + { 0x17aa, 0x5019, "GeForce 710M" }, + { 0x17aa, 0x501a, "GeForce 710M" }, + { 0x17aa, 0x501f, "GeForce GT 720M" }, + { 0x17aa, 0x5025, "GeForce 710M" }, + { 0x17aa, 0x5027, "GeForce 710M" }, + { 0x17aa, 0x502a, "GeForce 710M" }, + { 0x17aa, 0x502b, "GeForce GT 720M" }, + { 0x17aa, 0x502d, "GeForce 710M" }, + { 0x17aa, 0x502e, "GeForce GT 720M" }, + { 0x17aa, 0x502f, "GeForce GT 720M" }, + { 0x17aa, 0x5030, "GeForce 705M" }, + { 0x17aa, 0x5031, "GeForce 705M" }, + { 0x17aa, 0x5032, "GeForce 820M" }, + { 0x17aa, 0x5033, "GeForce 820M" }, + { 0x17aa, 0x503e, "GeForce 710M" }, + { 0x17aa, 0x503f, "GeForce 820M" }, + { 0x17aa, 0x5040, "GeForce 820M" }, + { 0x1854, 0x0177, "GeForce 710M" }, + { 0x1854, 0x0180, "GeForce 710M" }, + { 0x1854, 0x0190, "GeForce GT 720M" }, + { 0x1854, 0x0192, "GeForce GT 720M" }, + { 0x1854, 0x0224, "GeForce 820M" }, + { 0x1b0a, 0x20dd, "GeForce GT 620M" }, + { 0x1b0a, 0x20df, "GeForce GT 620M" }, + { 0x1b0a, 0x210e, "GeForce 820M" }, + { 0x1b0a, 0x2202, "GeForce GT 720M" }, + { 0x1b0a, 0x90d7, "GeForce 820M" }, + { 0x1b0a, 0x90dd, "GeForce 820M" }, + { 0x1b50, 0x5530, "GeForce 820M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1185[] = { + { 0x10de, 0x106f, "GeForce GTX 760" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1189[] = { + { 0x10de, 0x1074, "GeForce GTX 760 Ti OEM" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1199[] = { + { 0x1458, 0xd001, "GeForce GTX 760" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_11e3[] = { + { 0x17aa, 0x3683, "GeForce GTX 760A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_11fc[] = { + { 0x1179, 0x0001, NULL, { .War00C800_0 = true } }, /* Toshiba Tecra W50 */ + { 0x17aa, 0x2211, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ + { 0x17aa, 0x221e, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1247[] = { + { 0x1043, 0x212a, "GeForce GT 635M" }, + { 0x1043, 0x212b, "GeForce GT 635M" }, + { 0x1043, 0x212c, "GeForce GT 635M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_124d[] = { + { 0x1462, 0x10cc, "GeForce GT 635M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1290[] = { + { 0x103c, 0x2afa, "GeForce 730A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1292[] = { + { 0x17aa, 0x3675, "GeForce GT 740A" }, + { 0x17aa, 0x367c, "GeForce GT 740A" }, + { 0x17aa, 0x3684, "GeForce GT 740A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1295[] = { + { 0x103c, 0x2b0d, "GeForce 710A" }, + { 0x103c, 0x2b0f, "GeForce 710A" }, + { 0x103c, 0x2b20, "GeForce 810A" }, + { 0x103c, 0x2b21, "GeForce 810A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1299[] = { + { 0x17aa, 0x369b, "GeForce 920A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1340[] = { + { 0x103c, 0x2b2b, "GeForce 830A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1341[] = { + { 0x17aa, 0x3697, "GeForce 840A" }, + { 0x17aa, 0x3699, "GeForce 840A" }, + { 0x17aa, 0x369c, "GeForce 840A" }, + { 0x17aa, 0x36af, "GeForce 840A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1346[] = { + { 0x17aa, 0x30ba, "GeForce 930A" }, + { 0x17aa, 0x362c, "GeForce 930A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1347[] = { + { 0x17aa, 0x36b9, "GeForce 940A" }, + { 0x17aa, 0x36ba, "GeForce 940A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_137a[] = { + { 0x17aa, 0x2225, "Quadro K620M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_137d[] = { + { 0x17aa, 0x3699, "GeForce 940A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1391[] = { + { 0x17aa, 0x3697, "GeForce GTX 850A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1392[] = { + { 0x1028, 0x066a, "GeForce GPU" }, + { 0x1043, 0x861e, "GeForce GTX 750 Ti" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_139a[] = { + { 0x17aa, 0x36b9, "GeForce GTX 950A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_139b[] = { + { 0x1028, 0x06a3, "GeForce GTX 860M" }, + { 0x19da, 0xc248, "GeForce GTX 750 Ti" }, + {} +}; + +static const struct nvkm_device_pci_device +nvkm_device_pci_10de[] = { + { 0x0020, "RIVA TNT" }, + { 0x0028, "RIVA TNT2/TNT2 Pro" }, + { 0x0029, "RIVA TNT2 Ultra" }, + { 0x002c, "Vanta/Vanta LT" }, + { 0x002d, "RIVA TNT2 Model 64/Model 64 Pro" }, + { 0x0040, "GeForce 6800 Ultra" }, + { 0x0041, "GeForce 6800" }, + { 0x0042, "GeForce 6800 LE" }, + { 0x0043, "GeForce 6800 XE" }, + { 0x0044, "GeForce 6800 XT" }, + { 0x0045, "GeForce 6800 GT" }, + { 0x0046, "GeForce 6800 GT" }, + { 0x0047, "GeForce 6800 GS" }, + { 0x0048, "GeForce 6800 XT" }, + { 0x004e, "Quadro FX 4000" }, + { 0x0090, "GeForce 7800 GTX" }, + { 0x0091, "GeForce 7800 GTX" }, + { 0x0092, "GeForce 7800 GT" }, + { 0x0093, "GeForce 7800 GS" }, + { 0x0095, "GeForce 7800 SLI" }, + { 0x0098, "GeForce Go 7800" }, + { 0x0099, "GeForce Go 7800 GTX" }, + { 0x009d, "Quadro FX 4500" }, + { 0x00a0, "Aladdin TNT2" }, + { 0x00c0, "GeForce 6800 GS" }, + { 0x00c1, "GeForce 6800" }, + { 0x00c2, "GeForce 6800 LE" }, + { 0x00c3, "GeForce 6800 XT" }, + { 0x00c8, "GeForce Go 6800" }, + { 0x00c9, "GeForce Go 6800 Ultra" }, + { 0x00cc, "Quadro FX Go1400" }, + { 0x00cd, "Quadro FX 3450/4000 SDI" }, + { 0x00ce, "Quadro FX 1400" }, + { 0x00f1, "GeForce 6600 GT" }, + { 0x00f2, "GeForce 6600" }, + { 0x00f3, "GeForce 6200" }, + { 0x00f4, "GeForce 6600 LE" }, + { 0x00f5, "GeForce 7800 GS" }, + { 0x00f6, "GeForce 6800 GS" }, + { 0x00f8, "Quadro FX 3400/Quadro FX 4000" }, + { 0x00f9, "GeForce 6800 Ultra" }, + { 0x00fa, "GeForce PCX 5750" }, + { 0x00fb, "GeForce PCX 5900" }, + { 0x00fc, "Quadro FX 330/GeForce PCX 5300" }, + { 0x00fd, "Quadro FX 330/Quadro NVS 280 PCI-E" }, + { 0x00fe, "Quadro FX 1300" }, + { 0x0100, "GeForce 256" }, + { 0x0101, "GeForce DDR" }, + { 0x0103, "Quadro" }, + { 0x0110, "GeForce2 MX/MX 400" }, + { 0x0111, "GeForce2 MX 100/200" }, + { 0x0112, "GeForce2 Go" }, + { 0x0113, "Quadro2 MXR/EX/Go" }, + { 0x0140, "GeForce 6600 GT" }, + { 0x0141, "GeForce 6600" }, + { 0x0142, "GeForce 6600 LE" }, + { 0x0143, "GeForce 6600 VE" }, + { 0x0144, "GeForce Go 6600" }, + { 0x0145, "GeForce 6610 XL" }, + { 0x0146, "GeForce Go 6600 TE/6200 TE" }, + { 0x0147, "GeForce 6700 XL" }, + { 0x0148, "GeForce Go 6600" }, + { 0x0149, "GeForce Go 6600 GT" }, + { 0x014a, "Quadro NVS 440" }, + { 0x014c, "Quadro FX 540M" }, + { 0x014d, "Quadro FX 550" }, + { 0x014e, "Quadro FX 540" }, + { 0x014f, "GeForce 6200" }, + { 0x0150, "GeForce2 GTS/GeForce2 Pro" }, + { 0x0151, "GeForce2 Ti" }, + { 0x0152, "GeForce2 Ultra" }, + { 0x0153, "Quadro2 Pro" }, + { 0x0160, "GeForce 6500" }, + { 0x0161, "GeForce 6200 TurboCache(TM)" }, + { 0x0162, "GeForce 6200SE TurboCache(TM)" }, + { 0x0163, "GeForce 6200 LE" }, + { 0x0164, "GeForce Go 6200" }, + { 0x0165, "Quadro NVS 285" }, + { 0x0166, "GeForce Go 6400" }, + { 0x0167, "GeForce Go 6200" }, + { 0x0168, "GeForce Go 6400" }, + { 0x0169, "GeForce 6250" }, + { 0x016a, "GeForce 7100 GS" }, + { 0x0170, "GeForce4 MX 460" }, + { 0x0171, "GeForce4 MX 440" }, + { 0x0172, "GeForce4 MX 420" }, + { 0x0173, "GeForce4 MX 440-SE" }, + { 0x0174, "GeForce4 440 Go" }, + { 0x0175, "GeForce4 420 Go" }, + { 0x0176, "GeForce4 420 Go 32M" }, + { 0x0177, "GeForce4 460 Go" }, + { 0x0178, "Quadro4 550 XGL" }, + { 0x0179, "GeForce4 440 Go 64M" }, + { 0x017a, "Quadro NVS 400" }, + { 0x017c, "Quadro4 500 GoGL" }, + { 0x017d, "GeForce4 410 Go 16M" }, + { 0x0181, "GeForce4 MX 440 with AGP8X" }, + { 0x0182, "GeForce4 MX 440SE with AGP8X" }, + { 0x0183, "GeForce4 MX 420 with AGP8X" }, + { 0x0185, "GeForce4 MX 4000" }, + { 0x0188, "Quadro4 580 XGL" }, + { 0x0189, "GeForce4 MX with AGP8X (Mac)", nvkm_device_pci_10de_0189 }, + { 0x018a, "Quadro NVS 280 SD" }, + { 0x018b, "Quadro4 380 XGL" }, + { 0x018c, "Quadro NVS 50 PCI" }, + { 0x0191, "GeForce 8800 GTX" }, + { 0x0193, "GeForce 8800 GTS" }, + { 0x0194, "GeForce 8800 Ultra" }, + { 0x0197, "Tesla C870" }, + { 0x019d, "Quadro FX 5600" }, + { 0x019e, "Quadro FX 4600" }, + { 0x01a0, "GeForce2 Integrated GPU" }, + { 0x01d0, "GeForce 7350 LE" }, + { 0x01d1, "GeForce 7300 LE" }, + { 0x01d2, "GeForce 7550 LE" }, + { 0x01d3, "GeForce 7300 SE/7200 GS" }, + { 0x01d6, "GeForce Go 7200" }, + { 0x01d7, "GeForce Go 7300" }, + { 0x01d8, "GeForce Go 7400" }, + { 0x01da, "Quadro NVS 110M" }, + { 0x01db, "Quadro NVS 120M" }, + { 0x01dc, "Quadro FX 350M" }, + { 0x01dd, "GeForce 7500 LE" }, + { 0x01de, "Quadro FX 350" }, + { 0x01df, "GeForce 7300 GS" }, + { 0x01f0, "GeForce4 MX Integrated GPU", nvkm_device_pci_10de_01f0 }, + { 0x0200, "GeForce3" }, + { 0x0201, "GeForce3 Ti 200" }, + { 0x0202, "GeForce3 Ti 500" }, + { 0x0203, "Quadro DCC" }, + { 0x0211, "GeForce 6800" }, + { 0x0212, "GeForce 6800 LE" }, + { 0x0215, "GeForce 6800 GT" }, + { 0x0218, "GeForce 6800 XT" }, + { 0x0221, "GeForce 6200" }, + { 0x0222, "GeForce 6200 A-LE" }, + { 0x0240, "GeForce 6150" }, + { 0x0241, "GeForce 6150 LE" }, + { 0x0242, "GeForce 6100" }, + { 0x0244, "GeForce Go 6150" }, + { 0x0245, "Quadro NVS 210S / GeForce 6150LE" }, + { 0x0247, "GeForce Go 6100" }, + { 0x0250, "GeForce4 Ti 4600" }, + { 0x0251, "GeForce4 Ti 4400" }, + { 0x0253, "GeForce4 Ti 4200" }, + { 0x0258, "Quadro4 900 XGL" }, + { 0x0259, "Quadro4 750 XGL" }, + { 0x025b, "Quadro4 700 XGL" }, + { 0x0280, "GeForce4 Ti 4800" }, + { 0x0281, "GeForce4 Ti 4200 with AGP8X" }, + { 0x0282, "GeForce4 Ti 4800 SE" }, + { 0x0286, "GeForce4 4200 Go" }, + { 0x0288, "Quadro4 980 XGL" }, + { 0x0289, "Quadro4 780 XGL" }, + { 0x028c, "Quadro4 700 GoGL" }, + { 0x0290, "GeForce 7900 GTX" }, + { 0x0291, "GeForce 7900 GT/GTO" }, + { 0x0292, "GeForce 7900 GS" }, + { 0x0293, "GeForce 7950 GX2" }, + { 0x0294, "GeForce 7950 GX2" }, + { 0x0295, "GeForce 7950 GT" }, + { 0x0297, "GeForce Go 7950 GTX" }, + { 0x0298, "GeForce Go 7900 GS" }, + { 0x0299, "Quadro NVS 510M" }, + { 0x029a, "Quadro FX 2500M" }, + { 0x029b, "Quadro FX 1500M" }, + { 0x029c, "Quadro FX 5500" }, + { 0x029d, "Quadro FX 3500" }, + { 0x029e, "Quadro FX 1500" }, + { 0x029f, "Quadro FX 4500 X2" }, + { 0x02e0, "GeForce 7600 GT" }, + { 0x02e1, "GeForce 7600 GS" }, + { 0x02e2, "GeForce 7300 GT" }, + { 0x02e3, "GeForce 7900 GS" }, + { 0x02e4, "GeForce 7950 GT" }, + { 0x0301, "GeForce FX 5800 Ultra" }, + { 0x0302, "GeForce FX 5800" }, + { 0x0308, "Quadro FX 2000" }, + { 0x0309, "Quadro FX 1000" }, + { 0x0311, "GeForce FX 5600 Ultra" }, + { 0x0312, "GeForce FX 5600" }, + { 0x0314, "GeForce FX 5600XT" }, + { 0x031a, "GeForce FX Go5600" }, + { 0x031b, "GeForce FX Go5650" }, + { 0x031c, "Quadro FX Go700" }, + { 0x0320, "GeForce FX 5200" }, + { 0x0321, "GeForce FX 5200 Ultra" }, + { 0x0322, "GeForce FX 5200", nvkm_device_pci_10de_0322 }, + { 0x0323, "GeForce FX 5200LE" }, + { 0x0324, "GeForce FX Go5200" }, + { 0x0325, "GeForce FX Go5250" }, + { 0x0326, "GeForce FX 5500" }, + { 0x0327, "GeForce FX 5100" }, + { 0x0328, "GeForce FX Go5200 32M/64M" }, + { 0x032a, "Quadro NVS 55/280 PCI" }, + { 0x032b, "Quadro FX 500/FX 600" }, + { 0x032c, "GeForce FX Go53xx" }, + { 0x032d, "GeForce FX Go5100" }, + { 0x0330, "GeForce FX 5900 Ultra" }, + { 0x0331, "GeForce FX 5900" }, + { 0x0332, "GeForce FX 5900XT" }, + { 0x0333, "GeForce FX 5950 Ultra" }, + { 0x0334, "GeForce FX 5900ZT" }, + { 0x0338, "Quadro FX 3000" }, + { 0x033f, "Quadro FX 700" }, + { 0x0341, "GeForce FX 5700 Ultra" }, + { 0x0342, "GeForce FX 5700" }, + { 0x0343, "GeForce FX 5700LE" }, + { 0x0344, "GeForce FX 5700VE" }, + { 0x0347, "GeForce FX Go5700" }, + { 0x0348, "GeForce FX Go5700" }, + { 0x034c, "Quadro FX Go1000" }, + { 0x034e, "Quadro FX 1100" }, + { 0x038b, "GeForce 7650 GS" }, + { 0x0390, "GeForce 7650 GS" }, + { 0x0391, "GeForce 7600 GT" }, + { 0x0392, "GeForce 7600 GS" }, + { 0x0393, "GeForce 7300 GT" }, + { 0x0394, "GeForce 7600 LE" }, + { 0x0395, "GeForce 7300 GT" }, + { 0x0397, "GeForce Go 7700" }, + { 0x0398, "GeForce Go 7600" }, + { 0x0399, "GeForce Go 7600 GT" }, + { 0x039c, "Quadro FX 560M" }, + { 0x039e, "Quadro FX 560" }, + { 0x03d0, "GeForce 6150SE nForce 430" }, + { 0x03d1, "GeForce 6100 nForce 405" }, + { 0x03d2, "GeForce 6100 nForce 400" }, + { 0x03d5, "GeForce 6100 nForce 420" }, + { 0x03d6, "GeForce 7025 / nForce 630a" }, + { 0x0400, "GeForce 8600 GTS" }, + { 0x0401, "GeForce 8600 GT" }, + { 0x0402, "GeForce 8600 GT" }, + { 0x0403, "GeForce 8600 GS" }, + { 0x0404, "GeForce 8400 GS" }, + { 0x0405, "GeForce 9500M GS" }, + { 0x0406, "GeForce 8300 GS" }, + { 0x0407, "GeForce 8600M GT" }, + { 0x0408, "GeForce 9650M GS" }, + { 0x0409, "GeForce 8700M GT" }, + { 0x040a, "Quadro FX 370" }, + { 0x040b, "Quadro NVS 320M" }, + { 0x040c, "Quadro FX 570M" }, + { 0x040d, "Quadro FX 1600M" }, + { 0x040e, "Quadro FX 570" }, + { 0x040f, "Quadro FX 1700" }, + { 0x0410, "GeForce GT 330" }, + { 0x0420, "GeForce 8400 SE" }, + { 0x0421, "GeForce 8500 GT" }, + { 0x0422, "GeForce 8400 GS" }, + { 0x0423, "GeForce 8300 GS" }, + { 0x0424, "GeForce 8400 GS" }, + { 0x0425, "GeForce 8600M GS" }, + { 0x0426, "GeForce 8400M GT" }, + { 0x0427, "GeForce 8400M GS" }, + { 0x0428, "GeForce 8400M G" }, + { 0x0429, "Quadro NVS 140M" }, + { 0x042a, "Quadro NVS 130M" }, + { 0x042b, "Quadro NVS 135M" }, + { 0x042c, "GeForce 9400 GT" }, + { 0x042d, "Quadro FX 360M" }, + { 0x042e, "GeForce 9300M G" }, + { 0x042f, "Quadro NVS 290" }, + { 0x0531, "GeForce 7150M / nForce 630M" }, + { 0x0533, "GeForce 7000M / nForce 610M" }, + { 0x053a, "GeForce 7050 PV / nForce 630a" }, + { 0x053b, "GeForce 7050 PV / nForce 630a" }, + { 0x053e, "GeForce 7025 / nForce 630a" }, + { 0x05e0, "GeForce GTX 295" }, + { 0x05e1, "GeForce GTX 280" }, + { 0x05e2, "GeForce GTX 260" }, + { 0x05e3, "GeForce GTX 285" }, + { 0x05e6, "GeForce GTX 275" }, + { 0x05e7, "Tesla C1060", nvkm_device_pci_10de_05e7 }, + { 0x05ea, "GeForce GTX 260" }, + { 0x05eb, "GeForce GTX 295" }, + { 0x05ed, "Quadroplex 2200 D2" }, + { 0x05f8, "Quadroplex 2200 S4" }, + { 0x05f9, "Quadro CX" }, + { 0x05fd, "Quadro FX 5800" }, + { 0x05fe, "Quadro FX 4800" }, + { 0x05ff, "Quadro FX 3800" }, + { 0x0600, "GeForce 8800 GTS 512" }, + { 0x0601, "GeForce 9800 GT" }, + { 0x0602, "GeForce 8800 GT" }, + { 0x0603, "GeForce GT 230" }, + { 0x0604, "GeForce 9800 GX2" }, + { 0x0605, "GeForce 9800 GT" }, + { 0x0606, "GeForce 8800 GS" }, + { 0x0607, "GeForce GTS 240" }, + { 0x0608, "GeForce 9800M GTX" }, + { 0x0609, "GeForce 8800M GTS", nvkm_device_pci_10de_0609 }, + { 0x060a, "GeForce GTX 280M" }, + { 0x060b, "GeForce 9800M GT" }, + { 0x060c, "GeForce 8800M GTX" }, + { 0x060d, "GeForce 8800 GS" }, + { 0x060f, "GeForce GTX 285M" }, + { 0x0610, "GeForce 9600 GSO" }, + { 0x0611, "GeForce 8800 GT" }, + { 0x0612, "GeForce 9800 GTX/9800 GTX+" }, + { 0x0613, "GeForce 9800 GTX+" }, + { 0x0614, "GeForce 9800 GT" }, + { 0x0615, "GeForce GTS 250" }, + { 0x0617, "GeForce 9800M GTX" }, + { 0x0618, "GeForce GTX 260M" }, + { 0x0619, "Quadro FX 4700 X2" }, + { 0x061a, "Quadro FX 3700" }, + { 0x061b, "Quadro VX 200" }, + { 0x061c, "Quadro FX 3600M" }, + { 0x061d, "Quadro FX 2800M" }, + { 0x061e, "Quadro FX 3700M" }, + { 0x061f, "Quadro FX 3800M" }, + { 0x0621, "GeForce GT 230" }, + { 0x0622, "GeForce 9600 GT" }, + { 0x0623, "GeForce 9600 GS" }, + { 0x0625, "GeForce 9600 GSO 512" }, + { 0x0626, "GeForce GT 130" }, + { 0x0627, "GeForce GT 140" }, + { 0x0628, "GeForce 9800M GTS" }, + { 0x062a, "GeForce 9700M GTS" }, + { 0x062b, "GeForce 9800M GS" }, + { 0x062c, "GeForce 9800M GTS" }, + { 0x062d, "GeForce 9600 GT" }, + { 0x062e, "GeForce 9600 GT", nvkm_device_pci_10de_062e }, + { 0x0630, "GeForce 9700 S" }, + { 0x0631, "GeForce GTS 160M" }, + { 0x0632, "GeForce GTS 150M" }, + { 0x0635, "GeForce 9600 GSO" }, + { 0x0637, "GeForce 9600 GT" }, + { 0x0638, "Quadro FX 1800" }, + { 0x063a, "Quadro FX 2700M" }, + { 0x0640, "GeForce 9500 GT" }, + { 0x0641, "GeForce 9400 GT" }, + { 0x0643, "GeForce 9500 GT" }, + { 0x0644, "GeForce 9500 GS" }, + { 0x0645, "GeForce 9500 GS" }, + { 0x0646, "GeForce GT 120" }, + { 0x0647, "GeForce 9600M GT" }, + { 0x0648, "GeForce 9600M GS" }, + { 0x0649, "GeForce 9600M GT", nvkm_device_pci_10de_0649 }, + { 0x064a, "GeForce 9700M GT" }, + { 0x064b, "GeForce 9500M G" }, + { 0x064c, "GeForce 9650M GT" }, + { 0x0651, "GeForce G 110M" }, + { 0x0652, "GeForce GT 130M", nvkm_device_pci_10de_0652 }, + { 0x0653, "GeForce GT 120M" }, + { 0x0654, "GeForce GT 220M", nvkm_device_pci_10de_0654 }, + { 0x0655, NULL, nvkm_device_pci_10de_0655 }, + { 0x0656, NULL, nvkm_device_pci_10de_0656 }, + { 0x0658, "Quadro FX 380" }, + { 0x0659, "Quadro FX 580" }, + { 0x065a, "Quadro FX 1700M" }, + { 0x065b, "GeForce 9400 GT" }, + { 0x065c, "Quadro FX 770M" }, + { 0x06c0, "GeForce GTX 480" }, + { 0x06c4, "GeForce GTX 465" }, + { 0x06ca, "GeForce GTX 480M" }, + { 0x06cd, "GeForce GTX 470" }, + { 0x06d1, "Tesla C2050 / C2070", nvkm_device_pci_10de_06d1 }, + { 0x06d2, "Tesla M2070", nvkm_device_pci_10de_06d2 }, + { 0x06d8, "Quadro 6000" }, + { 0x06d9, "Quadro 5000" }, + { 0x06da, "Quadro 5000M" }, + { 0x06dc, "Quadro 6000" }, + { 0x06dd, "Quadro 4000" }, + { 0x06de, "Tesla T20 Processor", nvkm_device_pci_10de_06de }, + { 0x06df, "Tesla M2070-Q" }, + { 0x06e0, "GeForce 9300 GE" }, + { 0x06e1, "GeForce 9300 GS" }, + { 0x06e2, "GeForce 8400" }, + { 0x06e3, "GeForce 8400 SE" }, + { 0x06e4, "GeForce 8400 GS" }, + { 0x06e5, "GeForce 9300M GS" }, + { 0x06e6, "GeForce G100" }, + { 0x06e7, "GeForce 9300 SE" }, + { 0x06e8, "GeForce 9200M GS", nvkm_device_pci_10de_06e8 }, + { 0x06e9, "GeForce 9300M GS" }, + { 0x06ea, "Quadro NVS 150M" }, + { 0x06eb, "Quadro NVS 160M" }, + { 0x06ec, "GeForce G 105M" }, + { 0x06ef, "GeForce G 103M" }, + { 0x06f1, "GeForce G105M" }, + { 0x06f8, "Quadro NVS 420" }, + { 0x06f9, "Quadro FX 370 LP", nvkm_device_pci_10de_06f9 }, + { 0x06fa, "Quadro NVS 450" }, + { 0x06fb, "Quadro FX 370M" }, + { 0x06fd, "Quadro NVS 295" }, + { 0x06ff, "HICx16 + Graphics", nvkm_device_pci_10de_06ff }, + { 0x07e0, "GeForce 7150 / nForce 630i" }, + { 0x07e1, "GeForce 7100 / nForce 630i" }, + { 0x07e2, "GeForce 7050 / nForce 630i" }, + { 0x07e3, "GeForce 7050 / nForce 610i" }, + { 0x07e5, "GeForce 7050 / nForce 620i" }, + { 0x0840, "GeForce 8200M" }, + { 0x0844, "GeForce 9100M G" }, + { 0x0845, "GeForce 8200M G" }, + { 0x0846, "GeForce 9200" }, + { 0x0847, "GeForce 9100" }, + { 0x0848, "GeForce 8300" }, + { 0x0849, "GeForce 8200" }, + { 0x084a, "nForce 730a" }, + { 0x084b, "GeForce 9200" }, + { 0x084c, "nForce 980a/780a SLI" }, + { 0x084d, "nForce 750a SLI" }, + { 0x084f, "GeForce 8100 / nForce 720a" }, + { 0x0860, "GeForce 9400" }, + { 0x0861, "GeForce 9400" }, + { 0x0862, "GeForce 9400M G" }, + { 0x0863, "GeForce 9400M" }, + { 0x0864, "GeForce 9300" }, + { 0x0865, "ION" }, + { 0x0866, "GeForce 9400M G", nvkm_device_pci_10de_0866 }, + { 0x0867, "GeForce 9400" }, + { 0x0868, "nForce 760i SLI" }, + { 0x0869, "GeForce 9400" }, + { 0x086a, "GeForce 9400" }, + { 0x086c, "GeForce 9300 / nForce 730i" }, + { 0x086d, "GeForce 9200" }, + { 0x086e, "GeForce 9100M G" }, + { 0x086f, "GeForce 8200M G" }, + { 0x0870, "GeForce 9400M" }, + { 0x0871, "GeForce 9200" }, + { 0x0872, "GeForce G102M", nvkm_device_pci_10de_0872 }, + { 0x0873, "GeForce G102M", nvkm_device_pci_10de_0873 }, + { 0x0874, "ION" }, + { 0x0876, "ION" }, + { 0x087a, "GeForce 9400" }, + { 0x087d, "ION" }, + { 0x087e, "ION LE" }, + { 0x087f, "ION LE" }, + { 0x08a0, "GeForce 320M" }, + { 0x08a2, "GeForce 320M" }, + { 0x08a3, "GeForce 320M" }, + { 0x08a4, "GeForce 320M" }, + { 0x08a5, "GeForce 320M" }, + { 0x0a20, "GeForce GT 220" }, + { 0x0a22, "GeForce 315" }, + { 0x0a23, "GeForce 210" }, + { 0x0a26, "GeForce 405" }, + { 0x0a27, "GeForce 405" }, + { 0x0a28, "GeForce GT 230M" }, + { 0x0a29, "GeForce GT 330M" }, + { 0x0a2a, "GeForce GT 230M" }, + { 0x0a2b, "GeForce GT 330M" }, + { 0x0a2c, "NVS 5100M" }, + { 0x0a2d, "GeForce GT 320M" }, + { 0x0a32, "GeForce GT 415" }, + { 0x0a34, "GeForce GT 240M" }, + { 0x0a35, "GeForce GT 325M" }, + { 0x0a38, "Quadro 400" }, + { 0x0a3c, "Quadro FX 880M" }, + { 0x0a60, "GeForce G210" }, + { 0x0a62, "GeForce 205" }, + { 0x0a63, "GeForce 310" }, + { 0x0a64, "Second Generation ION" }, + { 0x0a65, "GeForce 210" }, + { 0x0a66, "GeForce 310" }, + { 0x0a67, "GeForce 315" }, + { 0x0a68, "GeForce G105M" }, + { 0x0a69, "GeForce G105M" }, + { 0x0a6a, "NVS 2100M" }, + { 0x0a6c, "NVS 3100M" }, + { 0x0a6e, "GeForce 305M", nvkm_device_pci_10de_0a6e }, + { 0x0a6f, "Second Generation ION" }, + { 0x0a70, "GeForce 310M", nvkm_device_pci_10de_0a70 }, + { 0x0a71, "GeForce 305M" }, + { 0x0a72, "GeForce 310M" }, + { 0x0a73, "GeForce 305M", nvkm_device_pci_10de_0a73 }, + { 0x0a74, "GeForce G210M", nvkm_device_pci_10de_0a74 }, + { 0x0a75, "GeForce 310M", nvkm_device_pci_10de_0a75 }, + { 0x0a76, "Second Generation ION" }, + { 0x0a78, "Quadro FX 380 LP" }, + { 0x0a7a, "GeForce 315M", nvkm_device_pci_10de_0a7a }, + { 0x0a7c, "Quadro FX 380M" }, + { 0x0ca0, "GeForce GT 330" }, + { 0x0ca2, "GeForce GT 320" }, + { 0x0ca3, "GeForce GT 240" }, + { 0x0ca4, "GeForce GT 340" }, + { 0x0ca5, "GeForce GT 220" }, + { 0x0ca7, "GeForce GT 330" }, + { 0x0ca8, "GeForce GTS 260M" }, + { 0x0ca9, "GeForce GTS 250M" }, + { 0x0cac, "GeForce GT 220" }, + { 0x0caf, "GeForce GT 335M" }, + { 0x0cb0, "GeForce GTS 350M" }, + { 0x0cb1, "GeForce GTS 360M" }, + { 0x0cbc, "Quadro FX 1800M" }, + { 0x0dc0, "GeForce GT 440" }, + { 0x0dc4, "GeForce GTS 450" }, + { 0x0dc5, "GeForce GTS 450" }, + { 0x0dc6, "GeForce GTS 450" }, + { 0x0dcd, "GeForce GT 555M" }, + { 0x0dce, "GeForce GT 555M" }, + { 0x0dd1, "GeForce GTX 460M" }, + { 0x0dd2, "GeForce GT 445M" }, + { 0x0dd3, "GeForce GT 435M" }, + { 0x0dd6, "GeForce GT 550M" }, + { 0x0dd8, "Quadro 2000", nvkm_device_pci_10de_0dd8 }, + { 0x0dda, "Quadro 2000M" }, + { 0x0de0, "GeForce GT 440" }, + { 0x0de1, "GeForce GT 430" }, + { 0x0de2, "GeForce GT 420" }, + { 0x0de3, "GeForce GT 635M" }, + { 0x0de4, "GeForce GT 520" }, + { 0x0de5, "GeForce GT 530" }, + { 0x0de7, "GeForce GT 610" }, + { 0x0de8, "GeForce GT 620M" }, + { 0x0de9, "GeForce GT 630M", nvkm_device_pci_10de_0de9 }, + { 0x0dea, "GeForce 610M", nvkm_device_pci_10de_0dea }, + { 0x0deb, "GeForce GT 555M" }, + { 0x0dec, "GeForce GT 525M" }, + { 0x0ded, "GeForce GT 520M" }, + { 0x0dee, "GeForce GT 415M" }, + { 0x0def, "NVS 5400M" }, + { 0x0df0, "GeForce GT 425M" }, + { 0x0df1, "GeForce GT 420M" }, + { 0x0df2, "GeForce GT 435M" }, + { 0x0df3, "GeForce GT 420M" }, + { 0x0df4, "GeForce GT 540M", nvkm_device_pci_10de_0df4 }, + { 0x0df5, "GeForce GT 525M" }, + { 0x0df6, "GeForce GT 550M" }, + { 0x0df7, "GeForce GT 520M" }, + { 0x0df8, "Quadro 600" }, + { 0x0df9, "Quadro 500M" }, + { 0x0dfa, "Quadro 1000M" }, + { 0x0dfc, "NVS 5200M" }, + { 0x0e22, "GeForce GTX 460" }, + { 0x0e23, "GeForce GTX 460 SE" }, + { 0x0e24, "GeForce GTX 460" }, + { 0x0e30, "GeForce GTX 470M" }, + { 0x0e31, "GeForce GTX 485M" }, + { 0x0e3a, "Quadro 3000M" }, + { 0x0e3b, "Quadro 4000M" }, + { 0x0f00, "GeForce GT 630" }, + { 0x0f01, "GeForce GT 620" }, + { 0x0f02, "GeForce GT 730" }, + { 0x0fc0, "GeForce GT 640" }, + { 0x0fc1, "GeForce GT 640" }, + { 0x0fc2, "GeForce GT 630" }, + { 0x0fc6, "GeForce GTX 650" }, + { 0x0fc8, "GeForce GT 740" }, + { 0x0fc9, "GeForce GT 730" }, + { 0x0fcd, "GeForce GT 755M" }, + { 0x0fce, "GeForce GT 640M LE" }, + { 0x0fd1, "GeForce GT 650M" }, + { 0x0fd2, "GeForce GT 640M", nvkm_device_pci_10de_0fd2 }, + { 0x0fd3, "GeForce GT 640M LE" }, + { 0x0fd4, "GeForce GTX 660M" }, + { 0x0fd5, "GeForce GT 650M" }, + { 0x0fd8, "GeForce GT 640M" }, + { 0x0fd9, "GeForce GT 645M" }, + { 0x0fdf, "GeForce GT 740M" }, + { 0x0fe0, "GeForce GTX 660M" }, + { 0x0fe1, "GeForce GT 730M" }, + { 0x0fe2, "GeForce GT 745M" }, + { 0x0fe3, "GeForce GT 745M", nvkm_device_pci_10de_0fe3 }, + { 0x0fe4, "GeForce GT 750M" }, + { 0x0fe9, "GeForce GT 750M" }, + { 0x0fea, "GeForce GT 755M" }, + { 0x0fec, "GeForce 710A" }, + { 0x0fef, "GRID K340" }, + { 0x0ff2, "GRID K1" }, + { 0x0ff3, "Quadro K420" }, + { 0x0ff6, "Quadro K1100M" }, + { 0x0ff8, "Quadro K500M" }, + { 0x0ff9, "Quadro K2000D" }, + { 0x0ffa, "Quadro K600" }, + { 0x0ffb, "Quadro K2000M" }, + { 0x0ffc, "Quadro K1000M" }, + { 0x0ffd, "NVS 510" }, + { 0x0ffe, "Quadro K2000" }, + { 0x0fff, "Quadro 410" }, + { 0x1001, "GeForce GTX TITAN Z" }, + { 0x1004, "GeForce GTX 780" }, + { 0x1005, "GeForce GTX TITAN" }, + { 0x1007, "GeForce GTX 780" }, + { 0x1008, "GeForce GTX 780 Ti" }, + { 0x100a, "GeForce GTX 780 Ti" }, + { 0x100c, "GeForce GTX TITAN Black" }, + { 0x1021, "Tesla K20Xm" }, + { 0x1022, "Tesla K20c" }, + { 0x1023, "Tesla K40m" }, + { 0x1024, "Tesla K40c" }, + { 0x1026, "Tesla K20s" }, + { 0x1027, "Tesla K40st" }, + { 0x1028, "Tesla K20m" }, + { 0x1029, "Tesla K40s" }, + { 0x102a, "Tesla K40t" }, + { 0x102d, "Tesla K80" }, + { 0x103a, "Quadro K6000" }, + { 0x103c, "Quadro K5200" }, + { 0x1040, "GeForce GT 520" }, + { 0x1042, "GeForce 510" }, + { 0x1048, "GeForce 605" }, + { 0x1049, "GeForce GT 620" }, + { 0x104a, "GeForce GT 610" }, + { 0x104b, "GeForce GT 625 (OEM)", nvkm_device_pci_10de_104b }, + { 0x104c, "GeForce GT 705" }, + { 0x1050, "GeForce GT 520M" }, + { 0x1051, "GeForce GT 520MX" }, + { 0x1052, "GeForce GT 520M" }, + { 0x1054, "GeForce 410M" }, + { 0x1055, "GeForce 410M" }, + { 0x1056, "NVS 4200M" }, + { 0x1057, "NVS 4200M" }, + { 0x1058, "GeForce 610M", nvkm_device_pci_10de_1058 }, + { 0x1059, "GeForce 610M" }, + { 0x105a, "GeForce 610M" }, + { 0x105b, "GeForce 705M", nvkm_device_pci_10de_105b }, + { 0x107c, "NVS 315" }, + { 0x107d, "NVS 310" }, + { 0x1080, "GeForce GTX 580" }, + { 0x1081, "GeForce GTX 570" }, + { 0x1082, "GeForce GTX 560 Ti" }, + { 0x1084, "GeForce GTX 560" }, + { 0x1086, "GeForce GTX 570" }, + { 0x1087, "GeForce GTX 560 Ti" }, + { 0x1088, "GeForce GTX 590" }, + { 0x1089, "GeForce GTX 580" }, + { 0x108b, "GeForce GTX 580" }, + { 0x1091, "Tesla M2090", nvkm_device_pci_10de_1091 }, + { 0x1094, "Tesla M2075" }, + { 0x1096, "Tesla C2075", nvkm_device_pci_10de_1096 }, + { 0x109a, "Quadro 5010M" }, + { 0x109b, "Quadro 7000" }, + { 0x10c0, "GeForce 9300 GS" }, + { 0x10c3, "GeForce 8400GS" }, + { 0x10c5, "GeForce 405" }, + { 0x10d8, "NVS 300" }, + { 0x1140, NULL, nvkm_device_pci_10de_1140 }, + { 0x1180, "GeForce GTX 680" }, + { 0x1183, "GeForce GTX 660 Ti" }, + { 0x1184, "GeForce GTX 770" }, + { 0x1185, "GeForce GTX 660", nvkm_device_pci_10de_1185 }, + { 0x1187, "GeForce GTX 760" }, + { 0x1188, "GeForce GTX 690" }, + { 0x1189, "GeForce GTX 670", nvkm_device_pci_10de_1189 }, + { 0x118a, "GRID K520" }, + { 0x118e, "GeForce GTX 760 (192-bit)" }, + { 0x118f, "Tesla K10" }, + { 0x1193, "GeForce GTX 760 Ti OEM" }, + { 0x1194, "Tesla K8" }, + { 0x1195, "GeForce GTX 660" }, + { 0x1198, "GeForce GTX 880M" }, + { 0x1199, "GeForce GTX 870M", nvkm_device_pci_10de_1199 }, + { 0x119a, "GeForce GTX 860M" }, + { 0x119d, "GeForce GTX 775M" }, + { 0x119e, "GeForce GTX 780M" }, + { 0x119f, "GeForce GTX 780M" }, + { 0x11a0, "GeForce GTX 680M" }, + { 0x11a1, "GeForce GTX 670MX" }, + { 0x11a2, "GeForce GTX 675MX" }, + { 0x11a3, "GeForce GTX 680MX" }, + { 0x11a7, "GeForce GTX 675MX" }, + { 0x11b4, "Quadro K4200" }, + { 0x11b6, "Quadro K3100M" }, + { 0x11b7, "Quadro K4100M" }, + { 0x11b8, "Quadro K5100M" }, + { 0x11ba, "Quadro K5000" }, + { 0x11bc, "Quadro K5000M" }, + { 0x11bd, "Quadro K4000M" }, + { 0x11be, "Quadro K3000M" }, + { 0x11bf, "GRID K2" }, + { 0x11c0, "GeForce GTX 660" }, + { 0x11c2, "GeForce GTX 650 Ti BOOST" }, + { 0x11c3, "GeForce GTX 650 Ti" }, + { 0x11c4, "GeForce GTX 645" }, + { 0x11c5, "GeForce GT 740" }, + { 0x11c6, "GeForce GTX 650 Ti" }, + { 0x11c8, "GeForce GTX 650" }, + { 0x11cb, "GeForce GT 740" }, + { 0x11e0, "GeForce GTX 770M" }, + { 0x11e1, "GeForce GTX 765M" }, + { 0x11e2, "GeForce GTX 765M" }, + { 0x11e3, "GeForce GTX 760M", nvkm_device_pci_10de_11e3 }, + { 0x11fa, "Quadro K4000" }, + { 0x11fc, "Quadro K2100M", nvkm_device_pci_10de_11fc }, + { 0x1200, "GeForce GTX 560 Ti" }, + { 0x1201, "GeForce GTX 560" }, + { 0x1203, "GeForce GTX 460 SE v2" }, + { 0x1205, "GeForce GTX 460 v2" }, + { 0x1206, "GeForce GTX 555" }, + { 0x1207, "GeForce GT 645" }, + { 0x1208, "GeForce GTX 560 SE" }, + { 0x1210, "GeForce GTX 570M" }, + { 0x1211, "GeForce GTX 580M" }, + { 0x1212, "GeForce GTX 675M" }, + { 0x1213, "GeForce GTX 670M" }, + { 0x1241, "GeForce GT 545" }, + { 0x1243, "GeForce GT 545" }, + { 0x1244, "GeForce GTX 550 Ti" }, + { 0x1245, "GeForce GTS 450" }, + { 0x1246, "GeForce GT 550M" }, + { 0x1247, "GeForce GT 555M", nvkm_device_pci_10de_1247 }, + { 0x1248, "GeForce GT 555M" }, + { 0x1249, "GeForce GTS 450" }, + { 0x124b, "GeForce GT 640" }, + { 0x124d, "GeForce GT 555M", nvkm_device_pci_10de_124d }, + { 0x1251, "GeForce GTX 560M" }, + { 0x1280, "GeForce GT 635" }, + { 0x1281, "GeForce GT 710" }, + { 0x1282, "GeForce GT 640" }, + { 0x1284, "GeForce GT 630" }, + { 0x1286, "GeForce GT 720" }, + { 0x1287, "GeForce GT 730" }, + { 0x1288, "GeForce GT 720" }, + { 0x1289, "GeForce GT 710" }, + { 0x1290, "GeForce GT 730M", nvkm_device_pci_10de_1290 }, + { 0x1291, "GeForce GT 735M" }, + { 0x1292, "GeForce GT 740M", nvkm_device_pci_10de_1292 }, + { 0x1293, "GeForce GT 730M" }, + { 0x1295, "GeForce 710M", nvkm_device_pci_10de_1295 }, + { 0x1296, "GeForce 825M" }, + { 0x1298, "GeForce GT 720M" }, + { 0x1299, "GeForce 920M", nvkm_device_pci_10de_1299 }, + { 0x129a, "GeForce 910M" }, + { 0x12b9, "Quadro K610M" }, + { 0x12ba, "Quadro K510M" }, + { 0x1340, "GeForce 830M", nvkm_device_pci_10de_1340 }, + { 0x1341, "GeForce 840M", nvkm_device_pci_10de_1341 }, + { 0x1344, "GeForce 845M" }, + { 0x1346, "GeForce 930M", nvkm_device_pci_10de_1346 }, + { 0x1347, "GeForce 940M", nvkm_device_pci_10de_1347 }, + { 0x137a, NULL, nvkm_device_pci_10de_137a }, + { 0x137d, NULL, nvkm_device_pci_10de_137d }, + { 0x1380, "GeForce GTX 750 Ti" }, + { 0x1381, "GeForce GTX 750" }, + { 0x1382, "GeForce GTX 745" }, + { 0x1390, "GeForce 845M" }, + { 0x1391, "GeForce GTX 850M", nvkm_device_pci_10de_1391 }, + { 0x1392, "GeForce GTX 860M", nvkm_device_pci_10de_1392 }, + { 0x1393, "GeForce 840M" }, + { 0x1398, "GeForce 845M" }, + { 0x139a, "GeForce GTX 950M", nvkm_device_pci_10de_139a }, + { 0x139b, "GeForce GTX 960M", nvkm_device_pci_10de_139b }, + { 0x139c, "GeForce 940M" }, + { 0x13b3, "Quadro K2200M" }, + { 0x13ba, "Quadro K2200" }, + { 0x13bb, "Quadro K620" }, + { 0x13bc, "Quadro K1200" }, + { 0x13c0, "GeForce GTX 980" }, + { 0x13c2, "GeForce GTX 970" }, + { 0x13d7, "GeForce GTX 980M" }, + { 0x13d8, "GeForce GTX 970M" }, + { 0x13d9, "GeForce GTX 965M" }, + { 0x1401, "GeForce GTX 960" }, + { 0x1617, "GeForce GTX 980M" }, + { 0x1618, "GeForce GTX 970M" }, + { 0x1619, "GeForce GTX 965M" }, + { 0x17c2, "GeForce GTX TITAN X" }, + { 0x17c8, "GeForce GTX 980 Ti" }, + { 0x17f0, "Quadro M6000" }, + {} +}; + +static struct nvkm_device_pci * +nvkm_device_pci(struct nvkm_device *device) +{ + return container_of(device, struct nvkm_device_pci, device); +} + +static resource_size_t +nvkm_device_pci_resource_addr(struct nvkm_device *device, unsigned bar) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + return pci_resource_start(pdev->pdev, bar); +} + +static resource_size_t +nvkm_device_pci_resource_size(struct nvkm_device *device, unsigned bar) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + return pci_resource_len(pdev->pdev, bar); +} + +static void +nvkm_device_pci_fini(struct nvkm_device *device, bool suspend) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + if (suspend) { + pci_disable_device(pdev->pdev); + pdev->suspend = true; + } +} + +static int +nvkm_device_pci_preinit(struct nvkm_device *device) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + if (pdev->suspend) { + int ret = pci_enable_device(pdev->pdev); + if (ret) + return ret; + pci_set_master(pdev->pdev); + pdev->suspend = false; + } + return 0; +} + +static void * +nvkm_device_pci_dtor(struct nvkm_device *device) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + pci_disable_device(pdev->pdev); + return pdev; +} + +static const struct nvkm_device_func +nvkm_device_pci_func = { + .pci = nvkm_device_pci, + .dtor = nvkm_device_pci_dtor, + .preinit = nvkm_device_pci_preinit, + .fini = nvkm_device_pci_fini, + .resource_addr = nvkm_device_pci_resource_addr, + .resource_size = nvkm_device_pci_resource_size, + .cpu_coherent = !IS_ENABLED(CONFIG_ARM), +}; + +int +nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + const struct nvkm_device_quirk *quirk = NULL; + const struct nvkm_device_pci_device *pcid; + const struct nvkm_device_pci_vendor *pciv; + const char *name = NULL; + struct nvkm_device_pci *pdev; + int ret; + + ret = pci_enable_device(pci_dev); + if (ret) + return ret; + + switch (pci_dev->vendor) { + case 0x10de: pcid = nvkm_device_pci_10de; break; + default: + pcid = NULL; + break; + } + + while (pcid && pcid->device) { + if (pciv = pcid->vendor, pcid->device == pci_dev->device) { + while (pciv && pciv->vendor) { + if (pciv->vendor == pci_dev->subsystem_vendor && + pciv->device == pci_dev->subsystem_device) { + quirk = &pciv->quirk; + name = pciv->name; + break; + } + pciv++; + } + if (!name) + name = pcid->name; + break; + } + pcid++; + } + + if (!(pdev = kzalloc(sizeof(*pdev), GFP_KERNEL))) { + pci_disable_device(pci_dev); + return -ENOMEM; + } + *pdevice = &pdev->device; + pdev->pdev = pci_dev; + + return nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev, + pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE : + pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ? + NVKM_DEVICE_AGP : NVKM_DEVICE_PCI, + (u64)pci_domain_nr(pci_dev->bus) << 32 | + pci_dev->bus->number << 16 | + PCI_SLOT(pci_dev->devfn) << 8 | + PCI_FUNC(pci_dev->devfn), name, + cfg, dbg, detect, mmio, subdev_mask, + &pdev->device); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 8d3590e7bd87..ed3ad2c30e17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -2,15 +2,49 @@ #define __NVKM_DEVICE_PRIV_H__ #include <core/device.h> -extern struct nvkm_oclass nvkm_control_oclass[]; +#include <subdev/bar.h> +#include <subdev/bios.h> +#include <subdev/bus.h> +#include <subdev/clk.h> +#include <subdev/devinit.h> +#include <subdev/fb.h> +#include <subdev/fuse.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/ibus.h> +#include <subdev/instmem.h> +#include <subdev/ltc.h> +#include <subdev/mc.h> +#include <subdev/mmu.h> +#include <subdev/mxm.h> +#include <subdev/pci.h> +#include <subdev/pmu.h> +#include <subdev/therm.h> +#include <subdev/timer.h> +#include <subdev/volt.h> -int nv04_identify(struct nvkm_device *); -int nv10_identify(struct nvkm_device *); -int nv20_identify(struct nvkm_device *); -int nv30_identify(struct nvkm_device *); -int nv40_identify(struct nvkm_device *); -int nv50_identify(struct nvkm_device *); -int gf100_identify(struct nvkm_device *); -int gk104_identify(struct nvkm_device *); -int gm100_identify(struct nvkm_device *); +#include <engine/bsp.h> +#include <engine/ce.h> +#include <engine/cipher.h> +#include <engine/disp.h> +#include <engine/dma.h> +#include <engine/fifo.h> +#include <engine/gr.h> +#include <engine/mpeg.h> +#include <engine/mspdec.h> +#include <engine/msppp.h> +#include <engine/msvld.h> +#include <engine/pm.h> +#include <engine/sec.h> +#include <engine/sw.h> +#include <engine/vp.h> + +int nvkm_device_ctor(const struct nvkm_device_func *, + const struct nvkm_device_quirk *, + struct device *, enum nvkm_device_type, u64 handle, + const char *name, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device *); +int nvkm_device_init(struct nvkm_device *); +int nvkm_device_fini(struct nvkm_device *, bool suspend); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c new file mode 100644 index 000000000000..da57c8a60608 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include <core/tegra.h> +#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER +#include "priv.h" + +static int +nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) +{ + int ret; + + ret = regulator_enable(tdev->vdd); + if (ret) + goto err_power; + + ret = clk_prepare_enable(tdev->clk); + if (ret) + goto err_clk; + ret = clk_prepare_enable(tdev->clk_pwr); + if (ret) + goto err_clk_pwr; + clk_set_rate(tdev->clk_pwr, 204000000); + udelay(10); + + reset_control_assert(tdev->rst); + udelay(10); + + ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); + if (ret) + goto err_clamp; + udelay(10); + + reset_control_deassert(tdev->rst); + udelay(10); + + return 0; + +err_clamp: + clk_disable_unprepare(tdev->clk_pwr); +err_clk_pwr: + clk_disable_unprepare(tdev->clk); +err_clk: + regulator_disable(tdev->vdd); +err_power: + return ret; +} + +static int +nvkm_device_tegra_power_down(struct nvkm_device_tegra *tdev) +{ + reset_control_assert(tdev->rst); + udelay(10); + + clk_disable_unprepare(tdev->clk_pwr); + clk_disable_unprepare(tdev->clk); + udelay(10); + + return regulator_disable(tdev->vdd); +} + +static void +nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev) +{ +#if IS_ENABLED(CONFIG_IOMMU_API) + struct device *dev = &tdev->pdev->dev; + unsigned long pgsize_bitmap; + int ret; + + mutex_init(&tdev->iommu.mutex); + + if (iommu_present(&platform_bus_type)) { + tdev->iommu.domain = iommu_domain_alloc(&platform_bus_type); + if (IS_ERR(tdev->iommu.domain)) + goto error; + + /* + * A IOMMU is only usable if it supports page sizes smaller + * or equal to the system's PAGE_SIZE, with a preference if + * both are equal. + */ + pgsize_bitmap = tdev->iommu.domain->ops->pgsize_bitmap; + if (pgsize_bitmap & PAGE_SIZE) { + tdev->iommu.pgshift = PAGE_SHIFT; + } else { + tdev->iommu.pgshift = fls(pgsize_bitmap & ~PAGE_MASK); + if (tdev->iommu.pgshift == 0) { + dev_warn(dev, "unsupported IOMMU page size\n"); + goto free_domain; + } + tdev->iommu.pgshift -= 1; + } + + ret = iommu_attach_device(tdev->iommu.domain, dev); + if (ret) + goto free_domain; + + ret = nvkm_mm_init(&tdev->iommu.mm, 0, + (1ULL << 40) >> tdev->iommu.pgshift, 1); + if (ret) + goto detach_device; + } + + return; + +detach_device: + iommu_detach_device(tdev->iommu.domain, dev); + +free_domain: + iommu_domain_free(tdev->iommu.domain); + +error: + tdev->iommu.domain = NULL; + tdev->iommu.pgshift = 0; + dev_err(dev, "cannot initialize IOMMU MM\n"); +#endif +} + +static void +nvkm_device_tegra_remove_iommu(struct nvkm_device_tegra *tdev) +{ +#if IS_ENABLED(CONFIG_IOMMU_API) + if (tdev->iommu.domain) { + nvkm_mm_fini(&tdev->iommu.mm); + iommu_detach_device(tdev->iommu.domain, tdev->device.dev); + iommu_domain_free(tdev->iommu.domain); + } +#endif +} + +static struct nvkm_device_tegra * +nvkm_device_tegra(struct nvkm_device *device) +{ + return container_of(device, struct nvkm_device_tegra, device); +} + +static struct resource * +nvkm_device_tegra_resource(struct nvkm_device *device, unsigned bar) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + return platform_get_resource(tdev->pdev, IORESOURCE_MEM, bar); +} + +static resource_size_t +nvkm_device_tegra_resource_addr(struct nvkm_device *device, unsigned bar) +{ + struct resource *res = nvkm_device_tegra_resource(device, bar); + return res ? res->start : 0; +} + +static resource_size_t +nvkm_device_tegra_resource_size(struct nvkm_device *device, unsigned bar) +{ + struct resource *res = nvkm_device_tegra_resource(device, bar); + return res ? resource_size(res) : 0; +} + +static irqreturn_t +nvkm_device_tegra_intr(int irq, void *arg) +{ + struct nvkm_device_tegra *tdev = arg; + struct nvkm_mc *mc = tdev->device.mc; + bool handled = false; + if (likely(mc)) { + nvkm_mc_intr_unarm(mc); + nvkm_mc_intr(mc, &handled); + nvkm_mc_intr_rearm(mc); + } + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static void +nvkm_device_tegra_fini(struct nvkm_device *device, bool suspend) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + if (tdev->irq) { + free_irq(tdev->irq, tdev); + tdev->irq = 0; + }; +} + +static int +nvkm_device_tegra_init(struct nvkm_device *device) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + int irq, ret; + + irq = platform_get_irq_byname(tdev->pdev, "stall"); + if (irq < 0) + return irq; + + ret = request_irq(irq, nvkm_device_tegra_intr, + IRQF_SHARED, "nvkm", tdev); + if (ret) + return ret; + + tdev->irq = irq; + return 0; +} + +static void * +nvkm_device_tegra_dtor(struct nvkm_device *device) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + nvkm_device_tegra_power_down(tdev); + nvkm_device_tegra_remove_iommu(tdev); + return tdev; +} + +static const struct nvkm_device_func +nvkm_device_tegra_func = { + .tegra = nvkm_device_tegra, + .dtor = nvkm_device_tegra_dtor, + .init = nvkm_device_tegra_init, + .fini = nvkm_device_tegra_fini, + .resource_addr = nvkm_device_tegra_resource_addr, + .resource_size = nvkm_device_tegra_resource_size, + .cpu_coherent = false, +}; + +int +nvkm_device_tegra_new(struct platform_device *pdev, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + struct nvkm_device_tegra *tdev; + int ret; + + if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL))) + return -ENOMEM; + *pdevice = &tdev->device; + tdev->pdev = pdev; + tdev->irq = -1; + + tdev->vdd = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(tdev->vdd)) + return PTR_ERR(tdev->vdd); + + tdev->rst = devm_reset_control_get(&pdev->dev, "gpu"); + if (IS_ERR(tdev->rst)) + return PTR_ERR(tdev->rst); + + tdev->clk = devm_clk_get(&pdev->dev, "gpu"); + if (IS_ERR(tdev->clk)) + return PTR_ERR(tdev->clk); + + tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); + if (IS_ERR(tdev->clk_pwr)) + return PTR_ERR(tdev->clk_pwr); + + nvkm_device_tegra_probe_iommu(tdev); + + ret = nvkm_device_tegra_power_up(tdev); + if (ret) + return ret; + + tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value; + ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev, + NVKM_DEVICE_TEGRA, pdev->id, NULL, + cfg, dbg, detect, mmio, subdev_mask, + &tdev->device); + if (ret) + return ret; + + return 0; +} +#else +int +nvkm_device_tegra_new(struct platform_device *pdev, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + return -ENOSYS; +} +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c new file mode 100644 index 000000000000..1ae48f27029d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -0,0 +1,371 @@ +/* + * 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 + */ +#define nvkm_udevice(p) container_of((p), struct nvkm_udevice, object) +#include "priv.h" +#include "ctrl.h" + +#include <core/client.h> +#include <subdev/fb.h> +#include <subdev/instmem.h> +#include <subdev/timer.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +struct nvkm_udevice { + struct nvkm_object object; + struct nvkm_device *device; +}; + +static int +nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size) +{ + struct nvkm_object *object = &udev->object; + struct nvkm_device *device = udev->device; + struct nvkm_fb *fb = device->fb; + struct nvkm_instmem *imem = device->imem; + union { + struct nv_device_info_v0 v0; + } *args = data; + int ret; + + nvif_ioctl(object, "device info size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "device info vers %d\n", args->v0.version); + } else + return ret; + + switch (device->chipset) { + case 0x01a: + case 0x01f: + case 0x04c: + case 0x04e: + case 0x063: + case 0x067: + case 0x068: + case 0x0aa: + case 0x0ac: + case 0x0af: + args->v0.platform = NV_DEVICE_INFO_V0_IGP; + break; + default: + switch (device->type) { + case NVKM_DEVICE_PCI: + args->v0.platform = NV_DEVICE_INFO_V0_PCI; + break; + case NVKM_DEVICE_AGP: + args->v0.platform = NV_DEVICE_INFO_V0_AGP; + break; + case NVKM_DEVICE_PCIE: + args->v0.platform = NV_DEVICE_INFO_V0_PCIE; + break; + case NVKM_DEVICE_TEGRA: + args->v0.platform = NV_DEVICE_INFO_V0_SOC; + break; + default: + WARN_ON(1); + break; + } + break; + } + + switch (device->card_type) { + case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break; + case NV_10: + case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break; + case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break; + case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break; + case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break; + case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break; + case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break; + case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break; + case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break; + default: + args->v0.family = 0; + break; + } + + args->v0.chipset = device->chipset; + args->v0.revision = device->chiprev; + if (fb && fb->ram) + args->v0.ram_size = args->v0.ram_user = fb->ram->size; + else + args->v0.ram_size = args->v0.ram_user = 0; + if (imem && args->v0.ram_size > 0) + args->v0.ram_user = args->v0.ram_user - imem->reserved; + + strncpy(args->v0.chip, device->chip->name, sizeof(args->v0.chip)); + strncpy(args->v0.name, device->name, sizeof(args->v0.name)); + return 0; +} + +static int +nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size) +{ + struct nvkm_device *device = udev->device; + union { + struct nv_device_time_v0 v0; + } *args = data; + int ret; + + if (nvif_unpack(args->v0, 0, 0, false)) { + args->v0.time = nvkm_timer_read(device->timer); + } + + return ret; +} + +static int +nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + switch (mthd) { + case NV_DEVICE_V0_INFO: + return nvkm_udevice_info(udev, data, size); + case NV_DEVICE_V0_TIME: + return nvkm_udevice_time(udev, data, size); + default: + break; + } + return -EINVAL; +} + +static int +nvkm_udevice_rd08(struct nvkm_object *object, u64 addr, u8 *data) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + *data = nvkm_rd08(udev->device, addr); + return 0; +} + +static int +nvkm_udevice_rd16(struct nvkm_object *object, u64 addr, u16 *data) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + *data = nvkm_rd16(udev->device, addr); + return 0; +} + +static int +nvkm_udevice_rd32(struct nvkm_object *object, u64 addr, u32 *data) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + *data = nvkm_rd32(udev->device, addr); + return 0; +} + +static int +nvkm_udevice_wr08(struct nvkm_object *object, u64 addr, u8 data) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + nvkm_wr08(udev->device, addr, data); + return 0; +} + +static int +nvkm_udevice_wr16(struct nvkm_object *object, u64 addr, u16 data) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + nvkm_wr16(udev->device, addr, data); + return 0; +} + +static int +nvkm_udevice_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + nvkm_wr32(udev->device, addr, data); + return 0; +} + +static int +nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + struct nvkm_device *device = udev->device; + *addr = device->func->resource_addr(device, 0); + *size = device->func->resource_size(device, 0); + return 0; +} + +static int +nvkm_udevice_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + struct nvkm_device *device = udev->device; + int ret = 0; + + mutex_lock(&device->mutex); + if (!--device->refcount) { + ret = nvkm_device_fini(device, suspend); + if (ret && suspend) { + device->refcount++; + goto done; + } + } + +done: + mutex_unlock(&device->mutex); + return ret; +} + +static int +nvkm_udevice_init(struct nvkm_object *object) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + struct nvkm_device *device = udev->device; + int ret = 0; + + mutex_lock(&device->mutex); + if (!device->refcount++) { + ret = nvkm_device_init(device); + if (ret) { + device->refcount--; + goto done; + } + } + +done: + mutex_unlock(&device->mutex); + return ret; +} + +static int +nvkm_udevice_child_new(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_udevice *udev = nvkm_udevice(oclass->parent); + const struct nvkm_device_oclass *sclass = oclass->priv; + return sclass->ctor(udev->device, oclass, data, size, pobject); +} + +static int +nvkm_udevice_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + struct nvkm_device *device = udev->device; + struct nvkm_engine *engine; + u64 mask = (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_FIFO) | + (1ULL << NVKM_ENGINE_DISP) | + (1ULL << NVKM_ENGINE_PM); + const struct nvkm_device_oclass *sclass = NULL; + int i; + + for (; i = __ffs64(mask), mask && !sclass; mask &= ~(1ULL << i)) { + if (!(engine = nvkm_device_engine(device, i)) || + !(engine->func->base.sclass)) + continue; + oclass->engine = engine; + + index -= engine->func->base.sclass(oclass, index, &sclass); + } + + if (!sclass) { + switch (index) { + case 0: sclass = &nvkm_control_oclass; break; + default: + return -EINVAL; + } + oclass->base = sclass->base; + } + + oclass->ctor = nvkm_udevice_child_new; + oclass->priv = sclass; + return 0; +} + +static const struct nvkm_object_func +nvkm_udevice_super = { + .init = nvkm_udevice_init, + .fini = nvkm_udevice_fini, + .mthd = nvkm_udevice_mthd, + .map = nvkm_udevice_map, + .rd08 = nvkm_udevice_rd08, + .rd16 = nvkm_udevice_rd16, + .rd32 = nvkm_udevice_rd32, + .wr08 = nvkm_udevice_wr08, + .wr16 = nvkm_udevice_wr16, + .wr32 = nvkm_udevice_wr32, + .sclass = nvkm_udevice_child_get, +}; + +static const struct nvkm_object_func +nvkm_udevice = { + .init = nvkm_udevice_init, + .fini = nvkm_udevice_fini, + .mthd = nvkm_udevice_mthd, + .sclass = nvkm_udevice_child_get, +}; + +int +nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv_device_v0 v0; + } *args = data; + struct nvkm_client *client = oclass->client; + struct nvkm_object *parent = &client->object; + const struct nvkm_object_func *func; + struct nvkm_udevice *udev; + int ret; + + nvif_ioctl(parent, "create device size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create device v%d device %016llx\n", + args->v0.version, args->v0.device); + } else + return ret; + + /* give priviledged clients register access */ + if (client->super) + func = &nvkm_udevice_super; + else + func = &nvkm_udevice; + + if (!(udev = kzalloc(sizeof(*udev), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(func, oclass, &udev->object); + *pobject = &udev->object; + + /* find the device that matches what the client requested */ + if (args->v0.device != ~0) + udev->device = nvkm_device_find(args->v0.device); + else + udev->device = nvkm_device_find(client->device); + if (!udev->device) + return -ENODEV; + + return 0; +} + +const struct nvkm_sclass +nvkm_udevice_sclass = { + .oclass = NV_DEVICE, + .minver = 0, + .maxver = 0, + .ctor = nvkm_udevice_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 16a4e2a37008..04f60452011e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -1,29 +1,93 @@ nvkm-y += nvkm/engine/disp/base.o -nvkm-y += nvkm/engine/disp/conn.o -nvkm-y += nvkm/engine/disp/outp.o -nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/nv04.o nvkm-y += nvkm/engine/disp/nv50.o nvkm-y += nvkm/engine/disp/g84.o nvkm-y += nvkm/engine/disp/g94.o nvkm-y += nvkm/engine/disp/gt200.o nvkm-y += nvkm/engine/disp/gt215.o -nvkm-y += nvkm/engine/disp/gf110.o +nvkm-y += nvkm/engine/disp/gf119.o nvkm-y += nvkm/engine/disp/gk104.o nvkm-y += nvkm/engine/disp/gk110.o nvkm-y += nvkm/engine/disp/gm107.o nvkm-y += nvkm/engine/disp/gm204.o + +nvkm-y += nvkm/engine/disp/outp.o +nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/dacnv50.o +nvkm-y += nvkm/engine/disp/piornv50.o +nvkm-y += nvkm/engine/disp/sornv50.o +nvkm-y += nvkm/engine/disp/sorg94.o +nvkm-y += nvkm/engine/disp/sorgf119.o +nvkm-y += nvkm/engine/disp/sorgm204.o nvkm-y += nvkm/engine/disp/dport.o + +nvkm-y += nvkm/engine/disp/conn.o + nvkm-y += nvkm/engine/disp/hdagt215.o -nvkm-y += nvkm/engine/disp/hdagf110.o +nvkm-y += nvkm/engine/disp/hdagf119.o + nvkm-y += nvkm/engine/disp/hdmig84.o nvkm-y += nvkm/engine/disp/hdmigt215.o -nvkm-y += nvkm/engine/disp/hdmigf110.o +nvkm-y += nvkm/engine/disp/hdmigf119.o nvkm-y += nvkm/engine/disp/hdmigk104.o -nvkm-y += nvkm/engine/disp/piornv50.o -nvkm-y += nvkm/engine/disp/sornv50.o -nvkm-y += nvkm/engine/disp/sorg94.o -nvkm-y += nvkm/engine/disp/sorgf110.o -nvkm-y += nvkm/engine/disp/sorgm204.o + nvkm-y += nvkm/engine/disp/vga.o + +nvkm-y += nvkm/engine/disp/rootnv04.o +nvkm-y += nvkm/engine/disp/rootnv50.o +nvkm-y += nvkm/engine/disp/rootg84.o +nvkm-y += nvkm/engine/disp/rootg94.o +nvkm-y += nvkm/engine/disp/rootgt200.o +nvkm-y += nvkm/engine/disp/rootgt215.o +nvkm-y += nvkm/engine/disp/rootgf119.o +nvkm-y += nvkm/engine/disp/rootgk104.o +nvkm-y += nvkm/engine/disp/rootgk110.o +nvkm-y += nvkm/engine/disp/rootgm107.o +nvkm-y += nvkm/engine/disp/rootgm204.o + +nvkm-y += nvkm/engine/disp/channv50.o +nvkm-y += nvkm/engine/disp/changf119.o + +nvkm-y += nvkm/engine/disp/dmacnv50.o +nvkm-y += nvkm/engine/disp/dmacgf119.o + +nvkm-y += nvkm/engine/disp/basenv50.o +nvkm-y += nvkm/engine/disp/baseg84.o +nvkm-y += nvkm/engine/disp/basegt200.o +nvkm-y += nvkm/engine/disp/basegt215.o +nvkm-y += nvkm/engine/disp/basegf119.o +nvkm-y += nvkm/engine/disp/basegk104.o +nvkm-y += nvkm/engine/disp/basegk110.o + +nvkm-y += nvkm/engine/disp/corenv50.o +nvkm-y += nvkm/engine/disp/coreg84.o +nvkm-y += nvkm/engine/disp/coreg94.o +nvkm-y += nvkm/engine/disp/coregt200.o +nvkm-y += nvkm/engine/disp/coregt215.o +nvkm-y += nvkm/engine/disp/coregf119.o +nvkm-y += nvkm/engine/disp/coregk104.o +nvkm-y += nvkm/engine/disp/coregk110.o +nvkm-y += nvkm/engine/disp/coregm107.o +nvkm-y += nvkm/engine/disp/coregm204.o + +nvkm-y += nvkm/engine/disp/ovlynv50.o +nvkm-y += nvkm/engine/disp/ovlyg84.o +nvkm-y += nvkm/engine/disp/ovlygt200.o +nvkm-y += nvkm/engine/disp/ovlygt215.o +nvkm-y += nvkm/engine/disp/ovlygf119.o +nvkm-y += nvkm/engine/disp/ovlygk104.o + +nvkm-y += nvkm/engine/disp/piocnv50.o +nvkm-y += nvkm/engine/disp/piocgf119.o + +nvkm-y += nvkm/engine/disp/cursnv50.o +nvkm-y += nvkm/engine/disp/cursg84.o +nvkm-y += nvkm/engine/disp/cursgt215.o +nvkm-y += nvkm/engine/disp/cursgf119.o +nvkm-y += nvkm/engine/disp/cursgk104.o + +nvkm-y += nvkm/engine/disp/oimmnv50.o +nvkm-y += nvkm/engine/disp/oimmg84.o +nvkm-y += nvkm/engine/disp/oimmgt215.o +nvkm-y += nvkm/engine/disp/oimmgf119.o +nvkm-y += nvkm/engine/disp/oimmgk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 23d1b5c0dc16..44b67719f64d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -25,7 +25,9 @@ #include "conn.h" #include "outp.h" +#include <core/client.h> #include <core/notify.h> +#include <core/oproxy.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -33,7 +35,21 @@ #include <nvif/event.h> #include <nvif/unpack.h> -int +static void +nvkm_disp_vblank_fini(struct nvkm_event *event, int type, int head) +{ + struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); + disp->func->head.vblank_fini(disp, head); +} + +static void +nvkm_disp_vblank_init(struct nvkm_event *event, int type, int head) +{ + struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); + disp->func->head.vblank_init(disp, head); +} + +static int nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) { @@ -56,6 +72,13 @@ nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size, return ret; } +static const struct nvkm_event_func +nvkm_disp_vblank_func = { + .ctor = nvkm_disp_vblank_ctor, + .init = nvkm_disp_vblank_init, + .fini = nvkm_disp_vblank_fini, +}; + void nvkm_disp_vblank(struct nvkm_disp *disp, int head) { @@ -100,7 +123,7 @@ nvkm_disp_hpd_func = { int nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event) { - struct nvkm_disp *disp = (void *)object->engine; + struct nvkm_disp *disp = nvkm_disp(object->engine); switch (type) { case NV04_DISP_NTFY_VBLANK: *event = &disp->vblank; @@ -114,127 +137,303 @@ nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event) return -EINVAL; } -int -_nvkm_disp_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_disp_class_del(struct nvkm_oproxy *oproxy) { - struct nvkm_disp *disp = (void *)object; - struct nvkm_output *outp; + struct nvkm_disp *disp = nvkm_disp(oproxy->base.engine); + mutex_lock(&disp->engine.subdev.mutex); + if (disp->client == oproxy) + disp->client = NULL; + mutex_unlock(&disp->engine.subdev.mutex); +} + +static const struct nvkm_oproxy_func +nvkm_disp_class = { + .dtor[1] = nvkm_disp_class_del, +}; + +static int +nvkm_disp_class_new(struct nvkm_device *device, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + const struct nvkm_disp_oclass *sclass = oclass->engn; + struct nvkm_disp *disp = nvkm_disp(oclass->engine); + struct nvkm_oproxy *oproxy; int ret; - list_for_each_entry(outp, &disp->outp, head) { - ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend); - if (ret && suspend) - goto fail_outp; + ret = nvkm_oproxy_new_(&nvkm_disp_class, oclass, &oproxy); + if (ret) + return ret; + *pobject = &oproxy->base; + + mutex_lock(&disp->engine.subdev.mutex); + if (disp->client) { + mutex_unlock(&disp->engine.subdev.mutex); + return -EBUSY; } + disp->client = oproxy; + mutex_unlock(&disp->engine.subdev.mutex); - return nvkm_engine_fini(&disp->base, suspend); + return sclass->ctor(disp, oclass, data, size, &oproxy->object); +} -fail_outp: - list_for_each_entry_continue_reverse(outp, &disp->outp, head) { - nv_ofuncs(outp)->init(nv_object(outp)); +static const struct nvkm_device_oclass +nvkm_disp_sclass = { + .ctor = nvkm_disp_class_new, +}; + +static int +nvkm_disp_class_get(struct nvkm_oclass *oclass, int index, + const struct nvkm_device_oclass **class) +{ + struct nvkm_disp *disp = nvkm_disp(oclass->engine); + if (index == 0) { + const struct nvkm_disp_oclass *root = disp->func->root(disp); + oclass->base = root->base; + oclass->engn = root; + *class = &nvkm_disp_sclass; + return 0; } + return 1; +} - return ret; +static void +nvkm_disp_intr(struct nvkm_engine *engine) +{ + struct nvkm_disp *disp = nvkm_disp(engine); + disp->func->intr(disp); } -int -_nvkm_disp_init(struct nvkm_object *object) +static int +nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_disp *disp = (void *)object; + struct nvkm_disp *disp = nvkm_disp(engine); + struct nvkm_connector *conn; struct nvkm_output *outp; - int ret; - - ret = nvkm_engine_init(&disp->base); - if (ret) - return ret; list_for_each_entry(outp, &disp->outp, head) { - ret = nv_ofuncs(outp)->init(nv_object(outp)); - if (ret) - goto fail_outp; + nvkm_output_fini(outp); } - return ret; + list_for_each_entry(conn, &disp->conn, head) { + nvkm_connector_fini(conn); + } + + return 0; +} + +static int +nvkm_disp_init(struct nvkm_engine *engine) +{ + struct nvkm_disp *disp = nvkm_disp(engine); + struct nvkm_connector *conn; + struct nvkm_output *outp; -fail_outp: - list_for_each_entry_continue_reverse(outp, &disp->outp, head) { - nv_ofuncs(outp)->fini(nv_object(outp), false); + list_for_each_entry(conn, &disp->conn, head) { + nvkm_connector_init(conn); } - return ret; + list_for_each_entry(outp, &disp->outp, head) { + nvkm_output_init(outp); + } + + return 0; } -void -_nvkm_disp_dtor(struct nvkm_object *object) +static void * +nvkm_disp_dtor(struct nvkm_engine *engine) { - struct nvkm_disp *disp = (void *)object; - struct nvkm_output *outp, *outt; + struct nvkm_disp *disp = nvkm_disp(engine); + struct nvkm_connector *conn; + struct nvkm_output *outp; + void *data = disp; + + if (disp->func->dtor) + data = disp->func->dtor(disp); nvkm_event_fini(&disp->vblank); nvkm_event_fini(&disp->hpd); - if (disp->outp.next) { - list_for_each_entry_safe(outp, outt, &disp->outp, head) { - nvkm_object_ref(NULL, (struct nvkm_object **)&outp); - } + while (!list_empty(&disp->outp)) { + outp = list_first_entry(&disp->outp, typeof(*outp), head); + list_del(&outp->head); + nvkm_output_del(&outp); } - nvkm_engine_destroy(&disp->base); + while (!list_empty(&disp->conn)) { + conn = list_first_entry(&disp->conn, typeof(*conn), head); + list_del(&conn->head); + nvkm_connector_del(&conn); + } + + return data; } +static const struct nvkm_engine_func +nvkm_disp = { + .dtor = nvkm_disp_dtor, + .init = nvkm_disp_init, + .fini = nvkm_disp_fini, + .intr = nvkm_disp_intr, + .base.sclass = nvkm_disp_class_get, +}; + int -nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int heads, const char *intname, - const char *extname, int length, void **pobject) +nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, + int index, int heads, struct nvkm_disp *disp) { - struct nvkm_disp_impl *impl = (void *)oclass; - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_disp *disp; - struct nvkm_oclass **sclass; - struct nvkm_object *object; + struct nvkm_bios *bios = device->bios; + struct nvkm_output *outp, *outt, *pair; + struct nvkm_connector *conn; + struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; u32 data; int ret, i; - ret = nvkm_engine_create_(parent, engine, oclass, true, intname, - extname, length, pobject); - disp = *pobject; + INIT_LIST_HEAD(&disp->outp); + INIT_LIST_HEAD(&disp->conn); + disp->func = func; + disp->head.nr = heads; + + ret = nvkm_engine_ctor(&nvkm_disp, device, index, 0, + true, &disp->engine); if (ret) return ret; - INIT_LIST_HEAD(&disp->outp); - /* create output objects for each display path in the vbios */ i = -1; while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { + const struct nvkm_disp_func_outp *outps; + int (*ctor)(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + if (dcbE.type == DCB_OUTPUT_UNUSED) continue; if (dcbE.type == DCB_OUTPUT_EOL) break; - data = dcbE.location << 4 | dcbE.type; + outp = NULL; + + switch (dcbE.location) { + case 0: outps = &disp->func->outp.internal; break; + case 1: outps = &disp->func->outp.external; break; + default: + nvkm_warn(&disp->engine.subdev, + "dcb %d locn %d unknown\n", i, dcbE.location); + continue; + } - oclass = nvkm_output_oclass; - sclass = impl->outp; - while (sclass && sclass[0]) { - if (sclass[0]->handle == data) { - oclass = sclass[0]; - break; + switch (dcbE.type) { + case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break; + case DCB_OUTPUT_TV : ctor = outps->tv ; break; + case DCB_OUTPUT_TMDS : ctor = outps->tmds; break; + case DCB_OUTPUT_LVDS : ctor = outps->lvds; break; + case DCB_OUTPUT_DP : ctor = outps->dp ; break; + default: + nvkm_warn(&disp->engine.subdev, + "dcb %d type %d unknown\n", i, dcbE.type); + continue; + } + + if (ctor) + ret = ctor(disp, i, &dcbE, &outp); + else + ret = -ENODEV; + + if (ret) { + if (ret == -ENODEV) { + nvkm_debug(&disp->engine.subdev, + "dcb %d %d/%d not supported\n", + i, dcbE.location, dcbE.type); + continue; } - sclass++; + nvkm_error(&disp->engine.subdev, + "failed to create output %d\n", i); + nvkm_output_del(&outp); + continue; } - nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object); + list_add_tail(&outp->head, &disp->outp); hpd = max(hpd, (u8)(dcbE.connector + 1)); } + /* create connector objects based on the outputs we support */ + list_for_each_entry_safe(outp, outt, &disp->outp, head) { + /* bios data *should* give us the most useful information */ + data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, + &connE); + + /* no bios connector data... */ + if (!data) { + /* heuristic: anything with the same ccb index is + * considered to be on the same connector, any + * output path without an associated ccb entry will + * be put on its own connector + */ + int ccb_index = outp->info.i2c_index; + if (ccb_index != 0xf) { + list_for_each_entry(pair, &disp->outp, head) { + if (pair->info.i2c_index == ccb_index) { + outp->conn = pair->conn; + break; + } + } + } + + /* connector shared with another output path */ + if (outp->conn) + continue; + + memset(&connE, 0x00, sizeof(connE)); + connE.type = DCB_CONNECTOR_NONE; + i = -1; + } else { + i = outp->info.connector; + } + + /* check that we haven't already created this connector */ + list_for_each_entry(conn, &disp->conn, head) { + if (conn->index == outp->info.connector) { + outp->conn = conn; + break; + } + } + + if (outp->conn) + continue; + + /* apparently we need to create a new one! */ + ret = nvkm_connector_new(disp, i, &connE, &outp->conn); + if (ret) { + nvkm_error(&disp->engine.subdev, + "failed to create output %d conn: %d\n", + outp->index, ret); + nvkm_connector_del(&outp->conn); + list_del(&outp->head); + nvkm_output_del(&outp); + continue; + } + + list_add_tail(&outp->conn->head, &disp->conn); + } + ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd); if (ret) return ret; - ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank); + ret = nvkm_event_init(&nvkm_disp_vblank_func, 1, heads, &disp->vblank); if (ret) return ret; return 0; } + +int +nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device, + int index, int heads, struct nvkm_disp **pdisp) +{ + if (!(*pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL))) + return -ENOMEM; + return nvkm_disp_ctor(func, device, index, heads, *pdisp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c new file mode 100644 index 000000000000..6d17630a3dee --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c @@ -0,0 +1,80 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_mthd_list +g84_disp_base_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00c4, 0x610800 }, + { 0x00c8, 0x61080c }, + { 0x00cc, 0x610818 }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x00fc, 0x610824 }, + { 0x0100, 0x610894 }, + { 0x0104, 0x61082c }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_chan_mthd +g84_disp_base_chan_mthd = { + .name = "Base", + .addr = 0x000540, + .prev = 0x000004, + .data = { + { "Global", 1, &g84_disp_base_mthd_base }, + { "Image", 2, &nv50_disp_base_mthd_image }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +g84_disp_base_oclass = { + .base.oclass = G82_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c new file mode 100644 index 000000000000..ebcb925e9d90 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c @@ -0,0 +1,114 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_mthd_list +gf119_disp_base_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x661080 }, + { 0x0084, 0x661084 }, + { 0x0088, 0x661088 }, + { 0x008c, 0x66108c }, + { 0x0090, 0x661090 }, + { 0x0094, 0x661094 }, + { 0x00a0, 0x6610a0 }, + { 0x00a4, 0x6610a4 }, + { 0x00c0, 0x6610c0 }, + { 0x00c4, 0x6610c4 }, + { 0x00c8, 0x6610c8 }, + { 0x00cc, 0x6610cc }, + { 0x00e0, 0x6610e0 }, + { 0x00e4, 0x6610e4 }, + { 0x00e8, 0x6610e8 }, + { 0x00ec, 0x6610ec }, + { 0x00fc, 0x6610fc }, + { 0x0100, 0x661100 }, + { 0x0104, 0x661104 }, + { 0x0108, 0x661108 }, + { 0x010c, 0x66110c }, + { 0x0110, 0x661110 }, + { 0x0114, 0x661114 }, + { 0x0118, 0x661118 }, + { 0x011c, 0x66111c }, + { 0x0130, 0x661130 }, + { 0x0134, 0x661134 }, + { 0x0138, 0x661138 }, + { 0x013c, 0x66113c }, + { 0x0140, 0x661140 }, + { 0x0144, 0x661144 }, + { 0x0148, 0x661148 }, + { 0x014c, 0x66114c }, + { 0x0150, 0x661150 }, + { 0x0154, 0x661154 }, + { 0x0158, 0x661158 }, + { 0x015c, 0x66115c }, + { 0x0160, 0x661160 }, + { 0x0164, 0x661164 }, + { 0x0168, 0x661168 }, + { 0x016c, 0x66116c }, + {} + } +}; + +static const struct nv50_disp_mthd_list +gf119_disp_base_mthd_image = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0400, 0x661400 }, + { 0x0404, 0x661404 }, + { 0x0408, 0x661408 }, + { 0x040c, 0x66140c }, + { 0x0410, 0x661410 }, + {} + } +}; + +const struct nv50_disp_chan_mthd +gf119_disp_base_chan_mthd = { + .name = "Base", + .addr = 0x001000, + .prev = -0x020000, + .data = { + { "Global", 1, &gf119_disp_base_mthd_base }, + { "Image", 2, &gf119_disp_base_mthd_image }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +gf119_disp_base_oclass = { + .base.oclass = GF110_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk104.c new file mode 100644 index 000000000000..780a1d973634 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk104.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gk104_disp_base_oclass = { + .base.oclass = GK104_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk110.c new file mode 100644 index 000000000000..d8bdd246c8ed --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk110.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gk110_disp_base_oclass = { + .base.oclass = GK110_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt200.c new file mode 100644 index 000000000000..93451e46570c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt200.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gt200_disp_base_oclass = { + .base.oclass = GT200_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt215.c new file mode 100644 index 000000000000..08e2b1fa3806 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt215.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gt215_disp_base_oclass = { + .base.oclass = GT214_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c new file mode 100644 index 000000000000..1fd89edefc26 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c @@ -0,0 +1,123 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <core/client.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +int +nv50_disp_base_new(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_base_channel_dma_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; + u64 push; + + nvif_ioctl(parent, "create disp base channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp base channel dma vers %d " + "pushbuf %016llx head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > disp->base.head.nr) + return -EINVAL; + push = args->v0.pushbuf; + head = args->v0.head; + } else + return ret; + + return nv50_disp_dmac_new_(func, mthd, root, chid + head, + head, push, oclass, pobject); +} + +static const struct nv50_disp_mthd_list +nv50_disp_base_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x0100, 0x610894 }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_base_mthd_image = { + .mthd = 0x0400, + .addr = 0x000000, + .data = { + { 0x0800, 0x6108f0 }, + { 0x0804, 0x6108fc }, + { 0x0808, 0x61090c }, + { 0x080c, 0x610914 }, + { 0x0810, 0x610904 }, + {} + } +}; + +static const struct nv50_disp_chan_mthd +nv50_disp_base_chan_mthd = { + .name = "Base", + .addr = 0x000540, + .prev = 0x000004, + .data = { + { "Global", 1, &nv50_disp_base_mthd_base }, + { "Image", 2, &nv50_disp_base_mthd_image }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +nv50_disp_base_oclass = { + .base.oclass = NV50_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &nv50_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c new file mode 100644 index 000000000000..17a3d835cb42 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c @@ -0,0 +1,49 @@ +/* + * 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 "channv50.h" + +static void +gf119_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000000 << index); + nvkm_wr32(device, 0x61008c, 0x00000001 << index); +} + +static void +gf119_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x61008c, 0x00000001 << index); + nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000001 << index); +} + +const struct nvkm_event_func +gf119_disp_chan_uevent = { + .ctor = nv50_disp_chan_uevent_ctor, + .init = gf119_disp_chan_uevent_init, + .fini = gf119_disp_chan_uevent_fini, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c new file mode 100644 index 000000000000..01803c0679b6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -0,0 +1,301 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <core/client.h> +#include <core/ramht.h> +#include <engine/dma.h> + +#include <nvif/class.h> +#include <nvif/event.h> +#include <nvif/unpack.h> + +static void +nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, + const struct nv50_disp_mthd_list *list, int inst) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int i; + + for (i = 0; list->data[i].mthd; i++) { + if (list->data[i].addr) { + u32 next = nvkm_rd32(device, list->data[i].addr + base + 0); + u32 prev = nvkm_rd32(device, list->data[i].addr + base + c); + u32 mthd = list->data[i].mthd + (list->mthd * inst); + const char *name = list->data[i].name; + char mods[16]; + + if (prev != next) + snprintf(mods, sizeof(mods), "-> %08x", next); + else + snprintf(mods, sizeof(mods), "%13c", ' '); + + nvkm_printk_(subdev, debug, info, + "\t%04x: %08x %s%s%s\n", + mthd, prev, mods, name ? " // " : "", + name ? name : ""); + } + } +} + +void +nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug) +{ + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + const struct nv50_disp_chan_mthd *mthd = chan->mthd; + const struct nv50_disp_mthd_list *list; + int i, j; + + if (debug > subdev->debug) + return; + + for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) { + u32 base = chan->head * mthd->addr; + for (j = 0; j < mthd->data[i].nr; j++, base += list->addr) { + const char *cname = mthd->name; + const char *sname = ""; + char cname_[16], sname_[16]; + + if (mthd->addr) { + snprintf(cname_, sizeof(cname_), "%s %d", + mthd->name, chan->chid); + cname = cname_; + } + + if (mthd->data[i].nr > 1) { + snprintf(sname_, sizeof(sname_), " - %s %d", + mthd->data[i].name, j); + sname = sname_; + } + + nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname); + nv50_disp_mthd_list(disp, debug, base, mthd->prev, + list, j); + } + } +} + +static void +nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000000 << index); + nvkm_wr32(device, 0x610020, 0x00000001 << index); +} + +static void +nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x610020, 0x00000001 << index); + nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000001 << index); +} + +void +nv50_disp_chan_uevent_send(struct nv50_disp *disp, int chid) +{ + struct nvif_notify_uevent_rep { + } rep; + + nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep)); +} + +int +nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + union { + struct nvif_notify_uevent_req none; + } *args = data; + int ret; + + if (nvif_unvers(args->none)) { + notify->size = sizeof(struct nvif_notify_uevent_rep); + notify->types = 1; + notify->index = chan->chid; + return 0; + } + + return ret; +} + +const struct nvkm_event_func +nv50_disp_chan_uevent = { + .ctor = nv50_disp_chan_uevent_ctor, + .init = nv50_disp_chan_uevent_init, + .fini = nv50_disp_chan_uevent_fini, +}; + +int +nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + *data = nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); + return 0; +} + +int +nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); + return 0; +} + +int +nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, + struct nvkm_event **pevent) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + switch (type) { + case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: + *pevent = &disp->uevent; + return 0; + default: + break; + } + return -EINVAL; +} + +int +nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + *addr = device->func->resource_addr(device, 0) + + 0x640000 + (chan->chid * 0x1000); + *size = 0x001000; + return 0; +} + +static int +nv50_disp_chan_child_new(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent); + return chan->func->child_new(chan, oclass, data, size, pobject); +} + +static int +nv50_disp_chan_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + if (chan->func->child_get) { + int ret = chan->func->child_get(chan, index, oclass); + if (ret == 0) + oclass->ctor = nv50_disp_chan_child_new; + return ret; + } + return -EINVAL; +} + +static int +nv50_disp_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + chan->func->fini(chan); + return 0; +} + +static int +nv50_disp_chan_init(struct nvkm_object *object) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + return chan->func->init(chan); +} + +static void * +nv50_disp_chan_dtor(struct nvkm_object *object) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + if (chan->chid >= 0) + disp->chan[chan->chid] = NULL; + return chan->func->dtor ? chan->func->dtor(chan) : chan; +} + +static const struct nvkm_object_func +nv50_disp_chan = { + .dtor = nv50_disp_chan_dtor, + .init = nv50_disp_chan_init, + .fini = nv50_disp_chan_fini, + .rd32 = nv50_disp_chan_rd32, + .wr32 = nv50_disp_chan_wr32, + .ntfy = nv50_disp_chan_ntfy, + .map = nv50_disp_chan_map, + .sclass = nv50_disp_chan_child_get, +}; + +int +nv50_disp_chan_ctor(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, + const struct nvkm_oclass *oclass, + struct nv50_disp_chan *chan) +{ + struct nv50_disp *disp = root->disp; + + nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object); + chan->func = func; + chan->mthd = mthd; + chan->root = root; + chan->chid = chid; + chan->head = head; + + if (disp->chan[chan->chid]) { + chan->chid = -1; + return -EBUSY; + } + disp->chan[chan->chid] = chan; + return 0; +} + +int +nv50_disp_chan_new_(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nv50_disp_chan *chan; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->object; + + return nv50_disp_chan_ctor(func, mthd, root, chid, head, oclass, chan); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h new file mode 100644 index 000000000000..aee374884c96 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h @@ -0,0 +1,127 @@ +#ifndef __NV50_DISP_CHAN_H__ +#define __NV50_DISP_CHAN_H__ +#define nv50_disp_chan(p) container_of((p), struct nv50_disp_chan, object) +#include "nv50.h" + +struct nv50_disp_chan { + const struct nv50_disp_chan_func *func; + const struct nv50_disp_chan_mthd *mthd; + struct nv50_disp_root *root; + int chid; + int head; + + struct nvkm_object object; +}; + +struct nv50_disp_chan_func { + void *(*dtor)(struct nv50_disp_chan *); + int (*init)(struct nv50_disp_chan *); + void (*fini)(struct nv50_disp_chan *); + int (*child_get)(struct nv50_disp_chan *, int index, + struct nvkm_oclass *); + int (*child_new)(struct nv50_disp_chan *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); +}; + +int nv50_disp_chan_ctor(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, int head, + const struct nvkm_oclass *, struct nv50_disp_chan *); +int nv50_disp_chan_new_(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, int head, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nv50_disp_chan_func nv50_disp_pioc_func; +extern const struct nv50_disp_chan_func gf119_disp_pioc_func; + +extern const struct nvkm_event_func nv50_disp_chan_uevent; +int nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32, + struct nvkm_notify *); +void nv50_disp_chan_uevent_send(struct nv50_disp *, int); + +extern const struct nvkm_event_func gf119_disp_chan_uevent; + +struct nv50_disp_mthd_list { + u32 mthd; + u32 addr; + struct { + u32 mthd; + u32 addr; + const char *name; + } data[]; +}; + +struct nv50_disp_chan_mthd { + const char *name; + u32 addr; + s32 prev; + struct { + const char *name; + int nr; + const struct nv50_disp_mthd_list *mthd; + } data[]; +}; + +void nv50_disp_chan_mthd(struct nv50_disp_chan *, int debug); + +extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base; +extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor; +extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior; +extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image; + +extern const struct nv50_disp_chan_mthd g84_disp_core_chan_mthd; +extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac; +extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head; +extern const struct nv50_disp_chan_mthd g84_disp_base_chan_mthd; +extern const struct nv50_disp_chan_mthd g84_disp_ovly_chan_mthd; + +extern const struct nv50_disp_chan_mthd g94_disp_core_chan_mthd; + +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_base; +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_dac; +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_sor; +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_pior; +extern const struct nv50_disp_chan_mthd gf119_disp_base_chan_mthd; + +extern const struct nv50_disp_chan_mthd gk104_disp_core_chan_mthd; + +struct nv50_disp_pioc_oclass { + int (*ctor)(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + struct nvkm_sclass base; + const struct nv50_disp_chan_func *func; + const struct nv50_disp_chan_mthd *mthd; + int chid; +}; + +extern const struct nv50_disp_pioc_oclass nv50_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass nv50_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass g84_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass g84_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass gt215_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass gt215_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass gf119_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass gf119_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass gk104_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass gk104_disp_curs_oclass; + + +int nv50_disp_curs_new(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_oimm_new(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index cf03e0240ced..c6910d644a3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -33,15 +33,15 @@ static int nvkm_connector_hpd(struct nvkm_notify *notify) { struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); - struct nvkm_disp *disp = nvkm_disp(conn); - struct nvkm_gpio *gpio = nvkm_gpio(conn); + struct nvkm_disp *disp = conn->disp; + struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; const struct nvkm_gpio_ntfy_rep *line = notify->data; struct nvif_notify_conn_rep_v0 rep; int index = conn->index; - DBG("HPD: %d\n", line->mask); + CONN_DBG(conn, "HPD: %d", line->mask); - if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) + if (!nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; else rep.mask = NVIF_NOTIFY_CONN_V0_PLUG; @@ -51,78 +51,58 @@ nvkm_connector_hpd(struct nvkm_notify *notify) return NVKM_NOTIFY_KEEP; } -int -_nvkm_connector_fini(struct nvkm_object *object, bool suspend) +void +nvkm_connector_fini(struct nvkm_connector *conn) { - struct nvkm_connector *conn = (void *)object; nvkm_notify_put(&conn->hpd); - return nvkm_object_fini(&conn->base, suspend); } -int -_nvkm_connector_init(struct nvkm_object *object) +void +nvkm_connector_init(struct nvkm_connector *conn) { - struct nvkm_connector *conn = (void *)object; - int ret = nvkm_object_init(&conn->base); - if (ret == 0) - nvkm_notify_get(&conn->hpd); - return ret; + nvkm_notify_get(&conn->hpd); } void -_nvkm_connector_dtor(struct nvkm_object *object) +nvkm_connector_del(struct nvkm_connector **pconn) { - struct nvkm_connector *conn = (void *)object; - nvkm_notify_fini(&conn->hpd); - nvkm_object_destroy(&conn->base); + struct nvkm_connector *conn = *pconn; + if (conn) { + nvkm_notify_fini(&conn->hpd); + kfree(*pconn); + *pconn = NULL; + } } -int -nvkm_connector_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct nvbios_connE *info, int index, - int length, void **pobject) +static void +nvkm_connector_ctor(struct nvkm_disp *disp, int index, + struct nvbios_connE *info, struct nvkm_connector *conn) { static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 }; - struct nvkm_disp *disp = nvkm_disp(parent); - struct nvkm_gpio *gpio = nvkm_gpio(parent); - struct nvkm_connector *conn; - struct nvkm_output *outp; + struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; struct dcb_gpio_func func; int ret; - list_for_each_entry(outp, &disp->outp, head) { - if (outp->conn && outp->conn->index == index) { - atomic_inc(&nv_object(outp->conn)->refcount); - *pobject = outp->conn; - return 1; - } - } - - ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); - conn = *pobject; - if (ret) - return ret; - - conn->info = *info; + conn->disp = disp; conn->index = index; + conn->info = *info; - DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n", - info->type, info->location, info->hpd, info->dp, - info->di, info->sr, info->lcdid); + CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x", + info->type, info->location, info->hpd, info->dp, + info->di, info->sr, info->lcdid); if ((info->hpd = ffs(info->hpd))) { if (--info->hpd >= ARRAY_SIZE(hpd)) { - ERR("hpd %02x unknown\n", info->hpd); - return 0; + CONN_ERR(conn, "hpd %02x unknown", info->hpd); + return; } info->hpd = hpd[info->hpd]; - ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); + ret = nvkm_gpio_find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); if (ret) { - ERR("func %02x lookup failed, %d\n", info->hpd, ret); - return 0; + CONN_ERR(conn, "func %02x lookup failed, %d", + info->hpd, ret); + return; } ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd, @@ -134,41 +114,19 @@ nvkm_connector_create_(struct nvkm_object *parent, sizeof(struct nvkm_gpio_ntfy_rep), &conn->hpd); if (ret) { - ERR("func %02x failed, %d\n", info->hpd, ret); + CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret); } else { - DBG("func %02x (HPD)\n", info->hpd); + CONN_DBG(conn, "func %02x (HPD)", info->hpd); } } - - return 0; } int -_nvkm_connector_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nvkm_connector_new(struct nvkm_disp *disp, int index, + struct nvbios_connE *info, struct nvkm_connector **pconn) { - struct nvkm_connector *conn; - int ret; - - ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn); - *pobject = nv_object(conn); - if (ret) - return ret; - + if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL))) + return -ENOMEM; + nvkm_connector_ctor(disp, index, info, *pconn); return 0; } - -struct nvkm_oclass * -nvkm_connector_oclass = &(struct nvkm_connector_impl) { - .base = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_connector_ctor, - .dtor = _nvkm_connector_dtor, - .init = _nvkm_connector_init, - .fini = _nvkm_connector_fini, - }, - }, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index c87a061f7f7d..ed32fe7f1864 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -1,58 +1,33 @@ #ifndef __NVKM_DISP_CONN_H__ #define __NVKM_DISP_CONN_H__ -#include <core/object.h> -#include <core/notify.h> +#include <engine/disp.h> +#include <core/notify.h> #include <subdev/bios.h> #include <subdev/bios/conn.h> struct nvkm_connector { - struct nvkm_object base; - struct list_head head; - - struct nvbios_connE info; + struct nvkm_disp *disp; int index; + struct nvbios_connE info; struct nvkm_notify hpd; -}; -#define nvkm_connector_create(p,e,c,b,i,d) \ - nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_connector_destroy(d) ({ \ - struct nvkm_connector *disp = (d); \ - _nvkm_connector_dtor(nv_object(disp)); \ -}) -#define nvkm_connector_init(d) ({ \ - struct nvkm_connector *disp = (d); \ - _nvkm_connector_init(nv_object(disp)); \ -}) -#define nvkm_connector_fini(d,s) ({ \ - struct nvkm_connector *disp = (d); \ - _nvkm_connector_fini(nv_object(disp), (s)); \ -}) - -int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct nvbios_connE *, - int, int, void **); - -int _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_connector_dtor(struct nvkm_object *); -int _nvkm_connector_init(struct nvkm_object *); -int _nvkm_connector_fini(struct nvkm_object *, bool); - -struct nvkm_connector_impl { - struct nvkm_oclass base; + struct list_head head; }; -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_connector *_conn = (void *)conn; \ - nv_##l(_conn, "%02x:%02x%02x: "f, _conn->index, \ - _conn->info.location, _conn->info.type, ##a); \ +int nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *, + struct nvkm_connector **); +void nvkm_connector_del(struct nvkm_connector **); +void nvkm_connector_init(struct nvkm_connector *); +void nvkm_connector_fini(struct nvkm_connector *); + +#define CONN_MSG(c,l,f,a...) do { \ + struct nvkm_connector *_conn = (c); \ + nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \ + _conn->index, _conn->info.location, _conn->info.type, ##a); \ } while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif +#define CONN_ERR(c,f,a...) CONN_MSG((c), error, f, ##a) +#define CONN_DBG(c,f,a...) CONN_MSG((c), debug, f, ##a) +#define CONN_TRACE(c,f,a...) CONN_MSG((c), trace, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c new file mode 100644 index 000000000000..1baa5c34b327 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c @@ -0,0 +1,117 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_mthd_list +g84_disp_core_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610bc4 }, + {} + } +}; + +const struct nv50_disp_mthd_list +g84_disp_core_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x085c, 0x610c5c }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0878, 0x610c50 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x089c, 0x610c68 }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + { 0x0910, 0x610c70 }, + { 0x0914, 0x610c78 }, + {} + } +}; + +const struct nv50_disp_chan_mthd +g84_disp_core_chan_mthd = { + .name = "Core", + .addr = 0x000000, + .prev = 0x000004, + .data = { + { "Global", 1, &nv50_disp_core_mthd_base }, + { "DAC", 3, &g84_disp_core_mthd_dac }, + { "SOR", 2, &nv50_disp_core_mthd_sor }, + { "PIOR", 3, &nv50_disp_core_mthd_pior }, + { "HEAD", 2, &g84_disp_core_mthd_head }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +g84_disp_core_oclass = { + .base.oclass = G82_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g84_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c new file mode 100644 index 000000000000..019379a3a01c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c @@ -0,0 +1,63 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_mthd_list +g94_disp_core_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610794 }, + {} + } +}; + +const struct nv50_disp_chan_mthd +g94_disp_core_chan_mthd = { + .name = "Core", + .addr = 0x000000, + .prev = 0x000004, + .data = { + { "Global", 1, &nv50_disp_core_mthd_base }, + { "DAC", 3, &g84_disp_core_mthd_dac }, + { "SOR", 4, &g94_disp_core_mthd_sor }, + { "PIOR", 3, &nv50_disp_core_mthd_pior }, + { "HEAD", 2, &g84_disp_core_mthd_head }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +g94_disp_core_oclass = { + .base.oclass = GT206_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g94_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c new file mode 100644 index 000000000000..6b1dc703dac7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c @@ -0,0 +1,244 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <core/client.h> +#include <subdev/timer.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x660080 }, + { 0x0084, 0x660084 }, + { 0x0088, 0x660088 }, + { 0x008c, 0x000000 }, + {} + } +}; + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_dac = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0180, 0x660180 }, + { 0x0184, 0x660184 }, + { 0x0188, 0x660188 }, + { 0x0190, 0x660190 }, + {} + } +}; + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_sor = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0200, 0x660200 }, + { 0x0204, 0x660204 }, + { 0x0208, 0x660208 }, + { 0x0210, 0x660210 }, + {} + } +}; + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_pior = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0300, 0x660300 }, + { 0x0304, 0x660304 }, + { 0x0308, 0x660308 }, + { 0x0310, 0x660310 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +gf119_disp_core_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +static const struct nv50_disp_chan_mthd +gf119_disp_core_chan_mthd = { + .name = "Core", + .addr = 0x000000, + .prev = -0x020000, + .data = { + { "Global", 1, &gf119_disp_core_mthd_base }, + { "DAC", 3, &gf119_disp_core_mthd_dac }, + { "SOR", 8, &gf119_disp_core_mthd_sor }, + { "PIOR", 4, &gf119_disp_core_mthd_pior }, + { "HEAD", 4, &gf119_disp_core_mthd_head }, + {} + } +}; + +static void +gf119_disp_core_fini(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + /* deactivate channel */ + nvkm_mask(device, 0x610490, 0x00000010, 0x00000000); + nvkm_mask(device, 0x610490, 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "core fini: %08x\n", + nvkm_rd32(device, 0x610490)); + } + + /* disable error reporting and completion notification */ + nvkm_mask(device, 0x610090, 0x00000001, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000000); +} + +static int +gf119_disp_core_init(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000001); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610494, chan->push); + nvkm_wr32(device, 0x610498, 0x00010000); + nvkm_wr32(device, 0x61049c, 0x00000001); + nvkm_mask(device, 0x610490, 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000, 0x00000000); + nvkm_wr32(device, 0x610490, 0x01000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "core init: %08x\n", + nvkm_rd32(device, 0x610490)); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_dmac_func +gf119_disp_core_func = { + .init = gf119_disp_core_init, + .fini = gf119_disp_core_fini, + .bind = gf119_disp_dmac_bind, +}; + +const struct nv50_disp_dmac_oclass +gf119_disp_core_oclass = { + .base.oclass = GF110_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gf119_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c new file mode 100644 index 000000000000..088ab222e823 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c @@ -0,0 +1,132 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_mthd_list +gk104_disp_core_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x047c, 0x66047c }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x0488, 0x660488 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04a0, 0x6604a0 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x0520, 0x660520 }, + { 0x0524, 0x660524 }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +const struct nv50_disp_chan_mthd +gk104_disp_core_chan_mthd = { + .name = "Core", + .addr = 0x000000, + .prev = -0x020000, + .data = { + { "Global", 1, &gf119_disp_core_mthd_base }, + { "DAC", 3, &gf119_disp_core_mthd_dac }, + { "SOR", 8, &gf119_disp_core_mthd_sor }, + { "PIOR", 4, &gf119_disp_core_mthd_pior }, + { "HEAD", 4, &gk104_disp_core_mthd_head }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +gk104_disp_core_oclass = { + .base.oclass = GK104_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk110.c new file mode 100644 index 000000000000..df0f45c20108 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk110.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gk110_disp_core_oclass = { + .base.oclass = GK110_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm107.c new file mode 100644 index 000000000000..9e27f8fd98b6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm107.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gm107_disp_core_oclass = { + .base.oclass = GM107_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm204.c new file mode 100644 index 000000000000..222f4a822f4d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm204.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gm204_disp_core_oclass = { + .base.oclass = GM204_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt200.c new file mode 100644 index 000000000000..b234547708fc --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt200.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gt200_disp_core_oclass = { + .base.oclass = GT200_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g84_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt215.c new file mode 100644 index 000000000000..8f5ba2018975 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt215.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gt215_disp_core_oclass = { + .base.oclass = GT214_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g94_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c new file mode 100644 index 000000000000..db4a9b3e0e09 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c @@ -0,0 +1,242 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <core/client.h> +#include <subdev/timer.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +int +nv50_disp_core_new(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_core_channel_dma_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + u64 push; + int ret; + + nvif_ioctl(parent, "create disp core channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp core channel dma vers %d " + "pushbuf %016llx\n", + args->v0.version, args->v0.pushbuf); + push = args->v0.pushbuf; + } else + return ret; + + return nv50_disp_dmac_new_(func, mthd, root, chid, 0, + push, oclass, pobject); +} + +const struct nv50_disp_mthd_list +nv50_disp_core_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x610bb8 }, + { 0x0088, 0x610b9c }, + { 0x008c, 0x000000 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_core_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610828 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_core_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610b70 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_core_mthd_pior = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0700, 0x610b80 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_core_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + {} + } +}; + +static const struct nv50_disp_chan_mthd +nv50_disp_core_chan_mthd = { + .name = "Core", + .addr = 0x000000, + .prev = 0x000004, + .data = { + { "Global", 1, &nv50_disp_core_mthd_base }, + { "DAC", 3, &nv50_disp_core_mthd_dac }, + { "SOR", 2, &nv50_disp_core_mthd_sor }, + { "PIOR", 3, &nv50_disp_core_mthd_pior }, + { "HEAD", 2, &nv50_disp_core_mthd_head }, + {} + } +}; + +static void +nv50_disp_core_fini(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + /* deactivate channel */ + nvkm_mask(device, 0x610200, 0x00000010, 0x00000000); + nvkm_mask(device, 0x610200, 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "core fini: %08x\n", + nvkm_rd32(device, 0x610200)); + } + + /* disable error reporting and completion notifications */ + nvkm_mask(device, 0x610028, 0x00010001, 0x00000000); +} + +static int +nv50_disp_core_init(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + /* enable error reporting */ + nvkm_mask(device, 0x610028, 0x00010000, 0x00010000); + + /* attempt to unstick channel from some unknown state */ + if ((nvkm_rd32(device, 0x610200) & 0x009f0000) == 0x00020000) + nvkm_mask(device, 0x610200, 0x00800000, 0x00800000); + if ((nvkm_rd32(device, 0x610200) & 0x003f0000) == 0x00030000) + nvkm_mask(device, 0x610200, 0x00600000, 0x00600000); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610204, chan->push); + nvkm_wr32(device, 0x610208, 0x00010000); + nvkm_wr32(device, 0x61020c, 0x00000000); + nvkm_mask(device, 0x610200, 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000, 0x00000000); + nvkm_wr32(device, 0x610200, 0x01000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "core init: %08x\n", + nvkm_rd32(device, 0x610200)); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_dmac_func +nv50_disp_core_func = { + .init = nv50_disp_core_init, + .fini = nv50_disp_core_fini, + .bind = nv50_disp_dmac_bind, +}; + +const struct nv50_disp_dmac_oclass +nv50_disp_core_oclass = { + .base.oclass = NV50_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &nv50_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c new file mode 100644 index 000000000000..dd99fc7060b1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +g84_disp_curs_oclass = { + .base.oclass = G82_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, + .chid = 7, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c new file mode 100644 index 000000000000..2a1574e06ad6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c @@ -0,0 +1,37 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +gf119_disp_curs_oclass = { + .base.oclass = GF110_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &gf119_disp_pioc_func, + .chid = 13, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c new file mode 100644 index 000000000000..28e8f06c9472 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c @@ -0,0 +1,37 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +gk104_disp_curs_oclass = { + .base.oclass = GK104_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &gf119_disp_pioc_func, + .chid = 13, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c new file mode 100644 index 000000000000..d8a4b9ca139c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +gt215_disp_curs_oclass = { + .base.oclass = GT214_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, + .chid = 7, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c new file mode 100644 index 000000000000..225858e62cf6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include <core/client.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +int +nv50_disp_curs_new(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_cursor_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; + + nvif_ioctl(parent, "create disp cursor size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp cursor vers %d head %d\n", + args->v0.version, args->v0.head); + if (args->v0.head > disp->base.head.nr) + return -EINVAL; + head = args->v0.head; + } else + return ret; + + return nv50_disp_chan_new_(func, mthd, root, chid + head, + head, oclass, pobject); +} + +const struct nv50_disp_pioc_oclass +nv50_disp_curs_oclass = { + .base.oclass = NV50_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, + .chid = 7, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 0f7d1ec4d37e..9bfa9e7dc161 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -33,6 +33,7 @@ int nv50_dac_power(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 doff = outp->or * 0x800; union { struct nv50_disp_dac_pwr_v0 v0; @@ -40,12 +41,12 @@ nv50_dac_power(NV50_DISP_MTHD_V1) u32 stat; int ret; - nv_ioctl(object, "disp dac pwr size %d\n", size); + nvif_ioctl(object, "disp dac pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp dac pwr vers %d state %d data %d " - "vsync %d hsync %d\n", - args->v0.version, args->v0.state, args->v0.data, - args->v0.vsync, args->v0.hsync); + nvif_ioctl(object, "disp dac pwr vers %d state %d data %d " + "vsync %d hsync %d\n", + args->v0.version, args->v0.state, args->v0.data, + args->v0.vsync, args->v0.hsync); stat = 0x00000040 * !args->v0.state; stat |= 0x00000010 * !args->v0.data; stat |= 0x00000004 * !args->v0.vsync; @@ -53,15 +54,23 @@ nv50_dac_power(NV50_DISP_MTHD_V1) } else return ret; - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); - nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); + nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); return 0; } int nv50_dac_sense(NV50_DISP_MTHD_V1) { + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; union { struct nv50_disp_dac_load_v0 v0; } *args = data; @@ -69,31 +78,49 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) u32 loadval; int ret; - nv_ioctl(object, "disp dac load size %d\n", size); + nvif_ioctl(object, "disp dac load size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp dac load vers %d data %08x\n", - args->v0.version, args->v0.data); + nvif_ioctl(object, "disp dac load vers %d data %08x\n", + args->v0.version, args->v0.data); if (args->v0.data & 0xfff00000) return -EINVAL; loadval = args->v0.data; } else return ret; - nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000); - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80150000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); - nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval); + nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval); mdelay(9); udelay(500); - loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000); + loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000); - nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000); - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80550000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); - nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval); + nvkm_debug(subdev, "DAC%d sense: %08x\n", outp->or, loadval); if (!(loadval & 0x80000000)) return -ETIMEDOUT; args->v0.load = (loadval & 0x38000000) >> 27; return 0; } + +static const struct nvkm_output_func +nv50_dac_output_func = { +}; + +int +nv50_dac_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&nv50_dac_output_func, disp, + index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c new file mode 100644 index 000000000000..876b14549a58 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c @@ -0,0 +1,100 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <core/ramht.h> +#include <subdev/timer.h> + +int +gf119_disp_dmac_bind(struct nv50_disp_dmac *chan, + struct nvkm_object *object, u32 handle) +{ + return nvkm_ramht_insert(chan->base.root->ramht, object, + chan->base.chid, -9, handle, + chan->base.chid << 27 | 0x00000001); +} + +static void +gf119_disp_dmac_fini(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->base.chid; + + /* deactivate channel */ + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d fini: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + } + + /* disable error reporting and completion notification */ + nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); +} + +static int +gf119_disp_dmac_init(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->base.chid; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610494 + (chid * 0x0010), chan->push); + nvkm_wr32(device, 0x610498 + (chid * 0x0010), 0x00010000); + nvkm_wr32(device, 0x61049c + (chid * 0x0010), 0x00000001); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); + nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d init: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_dmac_func +gf119_disp_dmac_func = { + .init = gf119_disp_dmac_init, + .fini = gf119_disp_dmac_fini, + .bind = gf119_disp_dmac_bind, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c new file mode 100644 index 000000000000..9c6645a357b9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c @@ -0,0 +1,247 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <core/client.h> +#include <core/oproxy.h> +#include <core/ramht.h> +#include <subdev/fb.h> +#include <subdev/timer.h> +#include <engine/dma.h> + +struct nv50_disp_dmac_object { + struct nvkm_oproxy oproxy; + struct nv50_disp_root *root; + int hash; +}; + +static void +nv50_disp_dmac_child_del_(struct nvkm_oproxy *base) +{ + struct nv50_disp_dmac_object *object = + container_of(base, typeof(*object), oproxy); + nvkm_ramht_remove(object->root->ramht, object->hash); +} + +static const struct nvkm_oproxy_func +nv50_disp_dmac_child_func_ = { + .dtor[0] = nv50_disp_dmac_child_del_, +}; + +static int +nv50_disp_dmac_child_new_(struct nv50_disp_chan *base, + const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + struct nv50_disp_root *root = chan->base.root; + struct nvkm_device *device = root->disp->base.engine.subdev.device; + const struct nvkm_device_oclass *sclass = oclass->priv; + struct nv50_disp_dmac_object *object; + int ret; + + if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) + return -ENOMEM; + nvkm_oproxy_ctor(&nv50_disp_dmac_child_func_, oclass, &object->oproxy); + object->root = root; + *pobject = &object->oproxy.base; + + ret = sclass->ctor(device, oclass, data, size, &object->oproxy.object); + if (ret) + return ret; + + object->hash = chan->func->bind(chan, object->oproxy.object, + oclass->handle); + if (object->hash < 0) + return object->hash; + + return 0; +} + +static int +nv50_disp_dmac_child_get_(struct nv50_disp_chan *base, int index, + struct nvkm_oclass *sclass) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + const struct nvkm_device_oclass *oclass = NULL; + + sclass->engine = nvkm_device_engine(device, NVKM_ENGINE_DMAOBJ); + if (sclass->engine && sclass->engine->func->base.sclass) { + sclass->engine->func->base.sclass(sclass, index, &oclass); + if (oclass) { + sclass->priv = oclass; + return 0; + } + } + + return -EINVAL; +} + +static void +nv50_disp_dmac_fini_(struct nv50_disp_chan *base) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + chan->func->fini(chan); +} + +static int +nv50_disp_dmac_init_(struct nv50_disp_chan *base) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + return chan->func->init(chan); +} + +static void * +nv50_disp_dmac_dtor_(struct nv50_disp_chan *base) +{ + return nv50_disp_dmac(base); +} + +static const struct nv50_disp_chan_func +nv50_disp_dmac_func_ = { + .dtor = nv50_disp_dmac_dtor_, + .init = nv50_disp_dmac_init_, + .fini = nv50_disp_dmac_fini_, + .child_get = nv50_disp_dmac_child_get_, + .child_new = nv50_disp_dmac_child_new_, +}; + +int +nv50_disp_dmac_new_(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, u64 push, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nvkm_device *device = root->disp->base.engine.subdev.device; + struct nvkm_client *client = oclass->client; + struct nvkm_dmaobj *dmaobj; + struct nv50_disp_dmac *chan; + int ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + chan->func = func; + + ret = nv50_disp_chan_ctor(&nv50_disp_dmac_func_, mthd, root, + chid, head, oclass, &chan->base); + if (ret) + return ret; + + dmaobj = nvkm_dma_search(device->dma, client, push); + if (!dmaobj) + return -ENOENT; + + if (dmaobj->limit - dmaobj->start != 0xfff) + return -EINVAL; + + switch (dmaobj->target) { + case NV_MEM_TARGET_VRAM: + chan->push = 0x00000001 | dmaobj->start >> 8; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + chan->push = 0x00000003 | dmaobj->start >> 8; + break; + default: + return -EINVAL; + } + + return 0; +} + +int +nv50_disp_dmac_bind(struct nv50_disp_dmac *chan, + struct nvkm_object *object, u32 handle) +{ + return nvkm_ramht_insert(chan->base.root->ramht, object, + chan->base.chid, -10, handle, + chan->base.chid << 28 | + chan->base.chid); +} + +static void +nv50_disp_dmac_fini(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->base.chid; + + /* deactivate channel */ + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d fini timeout, %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + } + + /* disable error reporting and completion notifications */ + nvkm_mask(device, 0x610028, 0x00010001 << chid, 0x00000000 << chid); +} + +static int +nv50_disp_dmac_init(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->base.chid; + + /* enable error reporting */ + nvkm_mask(device, 0x610028, 0x00010000 << chid, 0x00010000 << chid); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610204 + (chid * 0x0010), chan->push); + nvkm_wr32(device, 0x610208 + (chid * 0x0010), 0x00010000); + nvkm_wr32(device, 0x61020c + (chid * 0x0010), chid); + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); + nvkm_wr32(device, 0x610200 + (chid * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d init timeout, %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_dmac_func +nv50_disp_dmac_func = { + .init = nv50_disp_dmac_init, + .fini = nv50_disp_dmac_fini, + .bind = nv50_disp_dmac_bind, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h new file mode 100644 index 000000000000..c748ca23ab70 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h @@ -0,0 +1,91 @@ +#ifndef __NV50_DISP_DMAC_H__ +#define __NV50_DISP_DMAC_H__ +#define nv50_disp_dmac(p) container_of((p), struct nv50_disp_dmac, base) +#include "channv50.h" + +struct nv50_disp_dmac { + const struct nv50_disp_dmac_func *func; + struct nv50_disp_chan base; + u32 push; +}; + +struct nv50_disp_dmac_func { + int (*init)(struct nv50_disp_dmac *); + void (*fini)(struct nv50_disp_dmac *); + int (*bind)(struct nv50_disp_dmac *, struct nvkm_object *, u32 handle); +}; + +int nv50_disp_dmac_new_(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, int head, u64 push, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nv50_disp_dmac_func nv50_disp_dmac_func; +int nv50_disp_dmac_bind(struct nv50_disp_dmac *, struct nvkm_object *, u32); +extern const struct nv50_disp_dmac_func nv50_disp_core_func; + +extern const struct nv50_disp_dmac_func gf119_disp_dmac_func; +int gf119_disp_dmac_bind(struct nv50_disp_dmac *, struct nvkm_object *, u32); +extern const struct nv50_disp_dmac_func gf119_disp_core_func; + +struct nv50_disp_dmac_oclass { + int (*ctor)(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + struct nvkm_sclass base; + const struct nv50_disp_dmac_func *func; + const struct nv50_disp_chan_mthd *mthd; + int chid; +}; + +int nv50_disp_core_new(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_base_new(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_ovly_new(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **); + +extern const struct nv50_disp_dmac_oclass nv50_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass nv50_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass nv50_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass g84_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass g84_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass g84_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass g94_disp_core_oclass; + +extern const struct nv50_disp_dmac_oclass gt200_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gt200_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gt200_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gt215_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gt215_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gt215_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gf119_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gf119_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gf119_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gk104_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gk104_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gk104_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gk110_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gk110_disp_base_oclass; + +extern const struct nv50_disp_dmac_oclass gm107_disp_core_oclass; + +extern const struct nv50_disp_dmac_oclass gm204_disp_core_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index 68347661adca..74e2f7c6c07e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -48,12 +48,12 @@ struct dp_state { static int dp_set_link_config(struct dp_state *dp) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_init init = { - .subdev = nv_subdev(disp), + .subdev = subdev, .bios = bios, .offset = 0x0000, .outp = &outp->base.info, @@ -64,33 +64,33 @@ dp_set_link_config(struct dp_state *dp) u8 sink[2]; int ret; - DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); + OUTP_DBG(&outp->base, "%d lanes at %d KB/s", dp->link_nr, dp->link_bw); /* set desired link configuration on the source */ if ((lnkcmp = dp->outp->info.lnkcmp)) { if (outp->version < 0x30) { - while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) + while ((dp->link_bw / 10) < nvbios_rd16(bios, lnkcmp)) lnkcmp += 4; - init.offset = nv_ro16(bios, lnkcmp + 2); + init.offset = nvbios_rd16(bios, lnkcmp + 2); } else { - while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp)) + while ((dp->link_bw / 27000) < nvbios_rd08(bios, lnkcmp)) lnkcmp += 3; - init.offset = nv_ro16(bios, lnkcmp + 1); + init.offset = nvbios_rd16(bios, lnkcmp + 1); } nvbios_exec(&init); } - ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, - outp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); + ret = outp->func->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, + outp->dpcd[DPCD_RC02] & + DPCD_RC02_ENHANCED_FRAME_CAP); if (ret) { if (ret < 0) - ERR("lnk_ctl failed with %d\n", ret); + OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret); return ret; } - impl->lnk_pwr(outp, dp->link_nr); + outp->func->lnk_pwr(outp, dp->link_nr); /* set desired link configuration on the sink */ sink[0] = dp->link_bw / 27000; @@ -98,29 +98,27 @@ dp_set_link_config(struct dp_state *dp) if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; - return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2); + return nvkm_wraux(outp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); } static void dp_set_training_pattern(struct dp_state *dp, u8 pattern) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; u8 sink_tp; - DBG("training pattern %d\n", pattern); - impl->pattern(outp, pattern); + OUTP_DBG(&outp->base, "training pattern %d", pattern); + outp->func->pattern(outp, pattern); - nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1); + nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp |= pattern; - nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1); + nvkm_wraux(outp->aux, DPCD_LC02, &sink_tp, 1); } static int dp_link_train_commit(struct dp_state *dp, bool pc) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; int ret, i; @@ -146,16 +144,17 @@ dp_link_train_commit(struct dp_state *dp, bool pc) dp->conf[i] = (lpre << 3) | lvsw; dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4); - DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2); - impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); + OUTP_DBG(&outp->base, "config lane %d %02x %02x", + i, dp->conf[i], lpc2); + outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); } - ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4); + ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4); if (ret) return ret; if (pc) { - ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2); + ret = nvkm_wraux(outp->aux, DPCD_LC0F, dp->pc2conf, 2); if (ret) return ret; } @@ -174,17 +173,18 @@ dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) else udelay(delay); - ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6); + ret = nvkm_rdaux(outp->aux, DPCD_LS02, dp->stat, 6); if (ret) return ret; if (pc) { - ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1); + ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1); if (ret) dp->pc2stat = 0x00; - DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat); + OUTP_DBG(&outp->base, "status %6ph pc2 %02x", + dp->stat, dp->pc2stat); } else { - DBG("status %6ph\n", dp->stat); + OUTP_DBG(&outp->base, "status %6ph", dp->stat); } return 0; @@ -260,11 +260,11 @@ static void dp_link_train_init(struct dp_state *dp, bool spread) { struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->base.info, .crtc = -1, .execute = 1, @@ -286,11 +286,11 @@ static void dp_link_train_fini(struct dp_state *dp) { struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->base.info, .crtc = -1, .execute = 1, @@ -322,7 +322,7 @@ void nvkm_dp_train(struct work_struct *w) { struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = nv50_disp(outp->base.disp); const struct dp_rates *cfg = nvkm_dp_rates; struct dp_state _dp = { .outp = outp, @@ -330,11 +330,11 @@ nvkm_dp_train(struct work_struct *w) u32 datarate = 0; int ret; - if (!outp->base.info.location && priv->sor.magic) - priv->sor.magic(&outp->base); + if (!outp->base.info.location && disp->func->sor.magic) + disp->func->sor.magic(&outp->base); /* bring capabilities within encoder limits */ - if (nv_mclass(priv) < GF110_DISP) + if (disp->base.engine.subdev.device->chipset < 0xd0) outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; @@ -386,12 +386,12 @@ nvkm_dp_train(struct work_struct *w) /* finish link training and execute post-train script from vbios */ dp_set_training_pattern(dp, 0); if (ret < 0) - ERR("link training failed\n"); + OUTP_ERR(&outp->base, "link training failed"); dp_link_train_fini(dp); /* signal completion and enable link interrupt handling */ - DBG("training complete\n"); + OUTP_DBG(&outp->base, "training complete"); atomic_set(&outp->lt.done, 1); wake_up(&outp->lt.wait); nvkm_notify_get(&outp->irq); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index a0dcf534cb20..3e3e592cd09f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -22,251 +22,34 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include <nvif/class.h> - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -const struct nv50_disp_mthd_list -g84_disp_core_mthd_dac = { - .mthd = 0x0080, - .addr = 0x000008, - .data = { - { 0x0400, 0x610b58 }, - { 0x0404, 0x610bdc }, - { 0x0420, 0x610bc4 }, - {} - } -}; - -const struct nv50_disp_mthd_list -g84_disp_core_mthd_head = { - .mthd = 0x0400, - .addr = 0x000540, - .data = { - { 0x0800, 0x610ad8 }, - { 0x0804, 0x610ad0 }, - { 0x0808, 0x610a48 }, - { 0x080c, 0x610a78 }, - { 0x0810, 0x610ac0 }, - { 0x0814, 0x610af8 }, - { 0x0818, 0x610b00 }, - { 0x081c, 0x610ae8 }, - { 0x0820, 0x610af0 }, - { 0x0824, 0x610b08 }, - { 0x0828, 0x610b10 }, - { 0x082c, 0x610a68 }, - { 0x0830, 0x610a60 }, - { 0x0834, 0x000000 }, - { 0x0838, 0x610a40 }, - { 0x0840, 0x610a24 }, - { 0x0844, 0x610a2c }, - { 0x0848, 0x610aa8 }, - { 0x084c, 0x610ab0 }, - { 0x085c, 0x610c5c }, - { 0x0860, 0x610a84 }, - { 0x0864, 0x610a90 }, - { 0x0868, 0x610b18 }, - { 0x086c, 0x610b20 }, - { 0x0870, 0x610ac8 }, - { 0x0874, 0x610a38 }, - { 0x0878, 0x610c50 }, - { 0x0880, 0x610a58 }, - { 0x0884, 0x610a9c }, - { 0x089c, 0x610c68 }, - { 0x08a0, 0x610a70 }, - { 0x08a4, 0x610a50 }, - { 0x08a8, 0x610ae0 }, - { 0x08c0, 0x610b28 }, - { 0x08c4, 0x610b30 }, - { 0x08c8, 0x610b40 }, - { 0x08d4, 0x610b38 }, - { 0x08d8, 0x610b48 }, - { 0x08dc, 0x610b50 }, - { 0x0900, 0x610a18 }, - { 0x0904, 0x610ab8 }, - { 0x0910, 0x610c70 }, - { 0x0914, 0x610c78 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g84_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &nv50_disp_core_mthd_base }, - { "DAC", 3, &g84_disp_core_mthd_dac }, - { "SOR", 2, &nv50_disp_core_mthd_sor }, - { "PIOR", 3, &nv50_disp_core_mthd_pior }, - { "HEAD", 2, &g84_disp_core_mthd_head }, - {} - } -}; - -/******************************************************************************* - * EVO sync channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -g84_disp_base_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x0008c4 }, - { 0x0088, 0x0008d0 }, - { 0x008c, 0x0008dc }, - { 0x0090, 0x0008e4 }, - { 0x0094, 0x610884 }, - { 0x00a0, 0x6108a0 }, - { 0x00a4, 0x610878 }, - { 0x00c0, 0x61086c }, - { 0x00c4, 0x610800 }, - { 0x00c8, 0x61080c }, - { 0x00cc, 0x610818 }, - { 0x00e0, 0x610858 }, - { 0x00e4, 0x610860 }, - { 0x00e8, 0x6108ac }, - { 0x00ec, 0x6108b4 }, - { 0x00fc, 0x610824 }, - { 0x0100, 0x610894 }, - { 0x0104, 0x61082c }, - { 0x0110, 0x6108bc }, - { 0x0114, 0x61088c }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g84_disp_base_mthd_chan = { - .name = "Base", - .addr = 0x000540, - .data = { - { "Global", 1, &g84_disp_base_mthd_base }, - { "Image", 2, &nv50_disp_base_mthd_image }, - {} - } -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -g84_disp_ovly_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x6109a0 }, - { 0x0088, 0x6109c0 }, - { 0x008c, 0x6109c8 }, - { 0x0090, 0x6109b4 }, - { 0x0094, 0x610970 }, - { 0x00a0, 0x610998 }, - { 0x00a4, 0x610964 }, - { 0x00c0, 0x610958 }, - { 0x00e0, 0x6109a8 }, - { 0x00e4, 0x6109d0 }, - { 0x00e8, 0x6109d8 }, - { 0x0100, 0x61094c }, - { 0x0104, 0x610984 }, - { 0x0108, 0x61098c }, - { 0x0800, 0x6109f8 }, - { 0x0808, 0x610a08 }, - { 0x080c, 0x610a10 }, - { 0x0810, 0x610a00 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g84_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x000540, - .data = { - { "Global", 1, &g84_disp_ovly_mthd_base }, - {} - } -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -g84_disp_sclass[] = { - { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -g84_disp_main_oclass[] = { - { G82_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +#include "rootnv50.h" + +static const struct nv50_disp_func +g84_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, + .root = &g84_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 2, + .sor.power = nv50_sor_power, + .sor.hdmi = g84_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, +}; + +int +g84_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = g84_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = g84_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 2; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hdmi = g84_hdmi_ctrl; - priv->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(&g84_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -g84_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x82), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, - .mthd.core = &g84_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = &g84_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 1ab0d0ae3cc8..7a7af3b478f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -22,118 +22,35 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" - -#include <nvif/class.h> - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -const struct nv50_disp_mthd_list -g94_disp_core_mthd_sor = { - .mthd = 0x0040, - .addr = 0x000008, - .data = { - { 0x0600, 0x610794 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g94_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &nv50_disp_core_mthd_base }, - { "DAC", 3, &g84_disp_core_mthd_dac }, - { "SOR", 4, &g94_disp_core_mthd_sor }, - { "PIOR", 3, &nv50_disp_core_mthd_pior }, - { "HEAD", 2, &g84_disp_core_mthd_head }, - {} - } +#include "rootnv50.h" + +static const struct nv50_disp_func +g94_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, + .root = &g94_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = g94_sor_dp_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hdmi = g84_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -g94_disp_sclass[] = { - { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -g94_disp_main_oclass[] = { - { GT206_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g94_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = g94_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = g94_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hdmi = g84_hdmi_ctrl; - priv->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(&g94_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -g94_disp_outp_sclass[] = { - &nv50_pior_dp_impl.base.base, - &g94_sor_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * -g94_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x88), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &nv50_disp_vblank_func, - .base.outp = g94_disp_outp_sclass, - .mthd.core = &g94_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = &g84_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c deleted file mode 100644 index 9ef6728c528d..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ /dev/null @@ -1,1310 +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" -#include "outp.h" -#include "outpdp.h" - -#include <core/client.h> -#include <core/gpuobj.h> -#include <core/ramht.h> -#include <subdev/bios.h> -#include <subdev/bios/dcb.h> -#include <subdev/bios/disp.h> -#include <subdev/bios/init.h> -#include <subdev/bios/pll.h> -#include <subdev/devinit.h> -#include <subdev/timer.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -/******************************************************************************* - * EVO channel base class - ******************************************************************************/ - -static void -gf110_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index); - nv_wr32(priv, 0x61008c, 0x00000001 << index); -} - -static void -gf110_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) -{ - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_wr32(priv, 0x61008c, 0x00000001 << index); - nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index); -} - -const struct nvkm_event_func -gf110_disp_chan_uevent = { - .ctor = nv50_disp_chan_uevent_ctor, - .init = gf110_disp_chan_uevent_init, - .fini = gf110_disp_chan_uevent_fini, -}; - -/******************************************************************************* - * EVO DMA channel base class - ******************************************************************************/ - -static int -gf110_disp_dmac_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 name) -{ - struct nv50_disp_base *base = (void *)parent->parent; - struct nv50_disp_chan *chan = (void *)parent; - u32 addr = nv_gpuobj(object)->node->offset; - u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001; - return nvkm_ramht_insert(base->ramht, chan->chid, name, data); -} - -static void -gf110_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) -{ - struct nv50_disp_base *base = (void *)parent->parent; - nvkm_ramht_remove(base->ramht, cookie); -} - -static int -gf110_disp_dmac_init(struct nvkm_object *object) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - int chid = dmac->base.chid; - int ret; - - ret = nv50_disp_chan_init(&dmac->base); - if (ret) - return ret; - - /* enable error reporting */ - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); - - /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push); - nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000); - nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001); - nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000); - nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013); - - /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) { - nv_error(dmac, "init: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); - return -EBUSY; - } - - return 0; -} - -static int -gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - int chid = dmac->base.chid; - - /* deactivate channel */ - nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); - nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) { - nv_error(dmac, "fini: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notification */ - nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000); - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000); - - return nv50_disp_chan_fini(&dmac->base, suspend); -} - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x660080 }, - { 0x0084, 0x660084 }, - { 0x0088, 0x660088 }, - { 0x008c, 0x000000 }, - {} - } -}; - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_dac = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0180, 0x660180 }, - { 0x0184, 0x660184 }, - { 0x0188, 0x660188 }, - { 0x0190, 0x660190 }, - {} - } -}; - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_sor = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0200, 0x660200 }, - { 0x0204, 0x660204 }, - { 0x0208, 0x660208 }, - { 0x0210, 0x660210 }, - {} - } -}; - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_pior = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0300, 0x660300 }, - { 0x0304, 0x660304 }, - { 0x0308, 0x660308 }, - { 0x0310, 0x660310 }, - {} - } -}; - -static const struct nv50_disp_mthd_list -gf110_disp_core_mthd_head = { - .mthd = 0x0300, - .addr = 0x000300, - .data = { - { 0x0400, 0x660400 }, - { 0x0404, 0x660404 }, - { 0x0408, 0x660408 }, - { 0x040c, 0x66040c }, - { 0x0410, 0x660410 }, - { 0x0414, 0x660414 }, - { 0x0418, 0x660418 }, - { 0x041c, 0x66041c }, - { 0x0420, 0x660420 }, - { 0x0424, 0x660424 }, - { 0x0428, 0x660428 }, - { 0x042c, 0x66042c }, - { 0x0430, 0x660430 }, - { 0x0434, 0x660434 }, - { 0x0438, 0x660438 }, - { 0x0440, 0x660440 }, - { 0x0444, 0x660444 }, - { 0x0448, 0x660448 }, - { 0x044c, 0x66044c }, - { 0x0450, 0x660450 }, - { 0x0454, 0x660454 }, - { 0x0458, 0x660458 }, - { 0x045c, 0x66045c }, - { 0x0460, 0x660460 }, - { 0x0468, 0x660468 }, - { 0x046c, 0x66046c }, - { 0x0470, 0x660470 }, - { 0x0474, 0x660474 }, - { 0x0480, 0x660480 }, - { 0x0484, 0x660484 }, - { 0x048c, 0x66048c }, - { 0x0490, 0x660490 }, - { 0x0494, 0x660494 }, - { 0x0498, 0x660498 }, - { 0x04b0, 0x6604b0 }, - { 0x04b8, 0x6604b8 }, - { 0x04bc, 0x6604bc }, - { 0x04c0, 0x6604c0 }, - { 0x04c4, 0x6604c4 }, - { 0x04c8, 0x6604c8 }, - { 0x04d0, 0x6604d0 }, - { 0x04d4, 0x6604d4 }, - { 0x04e0, 0x6604e0 }, - { 0x04e4, 0x6604e4 }, - { 0x04e8, 0x6604e8 }, - { 0x04ec, 0x6604ec }, - { 0x04f0, 0x6604f0 }, - { 0x04f4, 0x6604f4 }, - { 0x04f8, 0x6604f8 }, - { 0x04fc, 0x6604fc }, - { 0x0500, 0x660500 }, - { 0x0504, 0x660504 }, - { 0x0508, 0x660508 }, - { 0x050c, 0x66050c }, - { 0x0510, 0x660510 }, - { 0x0514, 0x660514 }, - { 0x0518, 0x660518 }, - { 0x051c, 0x66051c }, - { 0x052c, 0x66052c }, - { 0x0530, 0x660530 }, - { 0x054c, 0x66054c }, - { 0x0550, 0x660550 }, - { 0x0554, 0x660554 }, - { 0x0558, 0x660558 }, - { 0x055c, 0x66055c }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -gf110_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &gf110_disp_core_mthd_base }, - { "DAC", 3, &gf110_disp_core_mthd_dac }, - { "SOR", 8, &gf110_disp_core_mthd_sor }, - { "PIOR", 4, &gf110_disp_core_mthd_pior }, - { "HEAD", 4, &gf110_disp_core_mthd_head }, - {} - } -}; - -static int -gf110_disp_core_init(struct nvkm_object *object) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - int ret; - - ret = nv50_disp_chan_init(&mast->base); - if (ret) - return ret; - - /* enable error reporting */ - nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001); - - /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610494, mast->push); - nv_wr32(priv, 0x610498, 0x00010000); - nv_wr32(priv, 0x61049c, 0x00000001); - nv_mask(priv, 0x610490, 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000, 0x00000000); - nv_wr32(priv, 0x610490, 0x01000013); - - /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) { - nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490)); - return -EBUSY; - } - - return 0; -} - -static int -gf110_disp_core_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - - /* deactivate channel */ - nv_mask(priv, 0x610490, 0x00000010, 0x00000000); - nv_mask(priv, 0x610490, 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) { - nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490)); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notification */ - nv_mask(priv, 0x610090, 0x00000001, 0x00000000); - nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000); - - return nv50_disp_chan_fini(&mast->base, suspend); -} - -struct nv50_disp_chan_impl -gf110_disp_core_ofuncs = { - .base.ctor = nv50_disp_core_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf110_disp_core_init, - .base.fini = gf110_disp_core_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 0, - .attach = gf110_disp_dmac_object_attach, - .detach = gf110_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO sync channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gf110_disp_base_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x661080 }, - { 0x0084, 0x661084 }, - { 0x0088, 0x661088 }, - { 0x008c, 0x66108c }, - { 0x0090, 0x661090 }, - { 0x0094, 0x661094 }, - { 0x00a0, 0x6610a0 }, - { 0x00a4, 0x6610a4 }, - { 0x00c0, 0x6610c0 }, - { 0x00c4, 0x6610c4 }, - { 0x00c8, 0x6610c8 }, - { 0x00cc, 0x6610cc }, - { 0x00e0, 0x6610e0 }, - { 0x00e4, 0x6610e4 }, - { 0x00e8, 0x6610e8 }, - { 0x00ec, 0x6610ec }, - { 0x00fc, 0x6610fc }, - { 0x0100, 0x661100 }, - { 0x0104, 0x661104 }, - { 0x0108, 0x661108 }, - { 0x010c, 0x66110c }, - { 0x0110, 0x661110 }, - { 0x0114, 0x661114 }, - { 0x0118, 0x661118 }, - { 0x011c, 0x66111c }, - { 0x0130, 0x661130 }, - { 0x0134, 0x661134 }, - { 0x0138, 0x661138 }, - { 0x013c, 0x66113c }, - { 0x0140, 0x661140 }, - { 0x0144, 0x661144 }, - { 0x0148, 0x661148 }, - { 0x014c, 0x66114c }, - { 0x0150, 0x661150 }, - { 0x0154, 0x661154 }, - { 0x0158, 0x661158 }, - { 0x015c, 0x66115c }, - { 0x0160, 0x661160 }, - { 0x0164, 0x661164 }, - { 0x0168, 0x661168 }, - { 0x016c, 0x66116c }, - {} - } -}; - -static const struct nv50_disp_mthd_list -gf110_disp_base_mthd_image = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0400, 0x661400 }, - { 0x0404, 0x661404 }, - { 0x0408, 0x661408 }, - { 0x040c, 0x66140c }, - { 0x0410, 0x661410 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -gf110_disp_base_mthd_chan = { - .name = "Base", - .addr = 0x001000, - .data = { - { "Global", 1, &gf110_disp_base_mthd_base }, - { "Image", 2, &gf110_disp_base_mthd_image }, - {} - } -}; - -struct nv50_disp_chan_impl -gf110_disp_base_ofuncs = { - .base.ctor = nv50_disp_base_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf110_disp_dmac_init, - .base.fini = gf110_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 1, - .attach = gf110_disp_dmac_object_attach, - .detach = gf110_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gf110_disp_ovly_mthd_base = { - .mthd = 0x0000, - .data = { - { 0x0080, 0x665080 }, - { 0x0084, 0x665084 }, - { 0x0088, 0x665088 }, - { 0x008c, 0x66508c }, - { 0x0090, 0x665090 }, - { 0x0094, 0x665094 }, - { 0x00a0, 0x6650a0 }, - { 0x00a4, 0x6650a4 }, - { 0x00b0, 0x6650b0 }, - { 0x00b4, 0x6650b4 }, - { 0x00b8, 0x6650b8 }, - { 0x00c0, 0x6650c0 }, - { 0x00e0, 0x6650e0 }, - { 0x00e4, 0x6650e4 }, - { 0x00e8, 0x6650e8 }, - { 0x0100, 0x665100 }, - { 0x0104, 0x665104 }, - { 0x0108, 0x665108 }, - { 0x010c, 0x66510c }, - { 0x0110, 0x665110 }, - { 0x0118, 0x665118 }, - { 0x011c, 0x66511c }, - { 0x0120, 0x665120 }, - { 0x0124, 0x665124 }, - { 0x0130, 0x665130 }, - { 0x0134, 0x665134 }, - { 0x0138, 0x665138 }, - { 0x013c, 0x66513c }, - { 0x0140, 0x665140 }, - { 0x0144, 0x665144 }, - { 0x0148, 0x665148 }, - { 0x014c, 0x66514c }, - { 0x0150, 0x665150 }, - { 0x0154, 0x665154 }, - { 0x0158, 0x665158 }, - { 0x015c, 0x66515c }, - { 0x0160, 0x665160 }, - { 0x0164, 0x665164 }, - { 0x0168, 0x665168 }, - { 0x016c, 0x66516c }, - { 0x0400, 0x665400 }, - { 0x0408, 0x665408 }, - { 0x040c, 0x66540c }, - { 0x0410, 0x665410 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -gf110_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x001000, - .data = { - { "Global", 1, &gf110_disp_ovly_mthd_base }, - {} - } -}; - -struct nv50_disp_chan_impl -gf110_disp_ovly_ofuncs = { - .base.ctor = nv50_disp_ovly_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf110_disp_dmac_init, - .base.fini = gf110_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 5, - .attach = gf110_disp_dmac_object_attach, - .detach = gf110_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO PIO channel base class - ******************************************************************************/ - -static int -gf110_disp_pioc_init(struct nvkm_object *object) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - int chid = pioc->base.chid; - int ret; - - ret = nv50_disp_chan_init(&pioc->base); - if (ret) - return ret; - - /* enable error reporting */ - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); - - /* activate channel */ - nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001); - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) { - nv_error(pioc, "init: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); - return -EBUSY; - } - - return 0; -} - -static int -gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - int chid = pioc->base.chid; - - nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) { - nv_error(pioc, "timeout: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notification */ - nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000); - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000); - - return nv50_disp_chan_fini(&pioc->base, suspend); -} - -/******************************************************************************* - * EVO immediate overlay channel objects - ******************************************************************************/ - -struct nv50_disp_chan_impl -gf110_disp_oimm_ofuncs = { - .base.ctor = nv50_disp_oimm_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = gf110_disp_pioc_init, - .base.fini = gf110_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 9, -}; - -/******************************************************************************* - * EVO cursor channel objects - ******************************************************************************/ - -struct nv50_disp_chan_impl -gf110_disp_curs_ofuncs = { - .base.ctor = nv50_disp_curs_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = gf110_disp_pioc_init, - .base.fini = gf110_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 13, -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -int -gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) -{ - const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300)); - const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300)); - const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300)); - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; - int ret; - - nv_ioctl(object, "disp scanoutpos size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); - args->v0.vblanke = (blanke & 0xffff0000) >> 16; - args->v0.hblanke = (blanke & 0x0000ffff); - args->v0.vblanks = (blanks & 0xffff0000) >> 16; - args->v0.hblanks = (blanks & 0x0000ffff); - args->v0.vtotal = ( total & 0xffff0000) >> 16; - args->v0.htotal = ( total & 0x0000ffff); - args->v0.time[0] = ktime_to_ns(ktime_get()); - args->v0.vline = /* vline read locks hline */ - nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = - nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; - } else - return ret; - - return 0; -} - -static int -gf110_disp_main_init(struct nvkm_object *object) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - int ret, i; - u32 tmp; - - ret = nvkm_parent_init(&base->base); - if (ret) - return ret; - - /* The below segments of code copying values from one register to - * another appear to inform EVO of the display capabilities or - * something similar. - */ - - /* ... CRTC caps */ - for (i = 0; i < priv->head.nr; i++) { - tmp = nv_rd32(priv, 0x616104 + (i * 0x800)); - nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp); - tmp = nv_rd32(priv, 0x616108 + (i * 0x800)); - nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp); - tmp = nv_rd32(priv, 0x61610c + (i * 0x800)); - nv_wr32(priv, 0x6101bc + (i * 0x800), tmp); - } - - /* ... DAC caps */ - for (i = 0; i < priv->dac.nr; i++) { - tmp = nv_rd32(priv, 0x61a000 + (i * 0x800)); - nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp); - } - - /* ... SOR caps */ - for (i = 0; i < priv->sor.nr; i++) { - tmp = nv_rd32(priv, 0x61c000 + (i * 0x800)); - nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp); - } - - /* steal display away from vbios, or something like that */ - if (nv_rd32(priv, 0x6100ac) & 0x00000100) { - nv_wr32(priv, 0x6100ac, 0x00000100); - nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) { - nv_error(priv, "timeout acquiring display\n"); - return -EBUSY; - } - } - - /* point at display engine memory area (hash table, objects) */ - nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); - - /* enable supervisor interrupts, disable everything else */ - nv_wr32(priv, 0x610090, 0x00000000); - nv_wr32(priv, 0x6100a0, 0x00000000); - nv_wr32(priv, 0x6100b0, 0x00000307); - - /* disable underflow reporting, preventing an intermittent issue - * on some gk104 boards where the production vbios left this - * setting enabled by default. - * - * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt - */ - for (i = 0; i < priv->head.nr; i++) - nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); - - return 0; -} - -static int -gf110_disp_main_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - - /* disable all interrupts */ - nv_wr32(priv, 0x6100b0, 0x00000000); - - return nvkm_parent_fini(&base->base, suspend); -} - -struct nvkm_ofuncs -gf110_disp_main_ofuncs = { - .ctor = nv50_disp_main_ctor, - .dtor = nv50_disp_main_dtor, - .init = gf110_disp_main_init, - .fini = gf110_disp_main_fini, - .mthd = nv50_disp_main_mthd, - .ntfy = nvkm_disp_ntfy, -}; - -static struct nvkm_oclass -gf110_disp_main_oclass[] = { - { GF110_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -static struct nvkm_oclass -gf110_disp_sclass[] = { - { GF110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GF110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GF110_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GF110_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GF110_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static void -gf110_disp_vblank_init(struct nvkm_event *event, int type, int head) -{ - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); -} - -static void -gf110_disp_vblank_fini(struct nvkm_event *event, int type, int head) -{ - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); -} - -const struct nvkm_event_func -gf110_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, - .init = gf110_disp_vblank_init, - .fini = gf110_disp_vblank_fini, -}; - -static struct nvkm_output * -exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, - u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, - struct nvbios_outp *info) -{ - struct nvkm_bios *bios = nvkm_bios(priv); - struct nvkm_output *outp; - u16 mask, type; - - if (or < 4) { - type = DCB_OUTPUT_ANALOG; - mask = 0; - } else { - or -= 4; - switch (ctrl & 0x00000f00) { - case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; - case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; - case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; - case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; - case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; - case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; - default: - nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); - return 0x0000; - } - } - - mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << or; - mask |= 0x0100 << head; - - list_for_each_entry(outp, &priv->base.outp, head) { - if ((outp->info.hasht & 0xff) == type && - (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, - outp->info.hashm, - ver, hdr, cnt, len, info); - if (!*data) - return NULL; - return outp; - } - } - - return NULL; -} - -static struct nvkm_output * -exec_script(struct nv50_disp_priv *priv, int head, int id) -{ - struct nvkm_bios *bios = nvkm_bios(priv); - struct nvkm_output *outp; - struct nvbios_outp info; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nv_rd32(priv, 0x640180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); - if (outp) { - struct nvbios_init init = { - .subdev = nv_subdev(priv), - .bios = bios, - .offset = info.script[id], - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - - return outp; -} - -static struct nvkm_output * -exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) -{ - struct nvkm_bios *bios = nvkm_bios(priv); - struct nvkm_output *outp; - struct nvbios_outp info1; - struct nvbios_ocfg info2; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nv_rd32(priv, 0x660180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); - if (!outp) - return NULL; - - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - *conf = (ctrl & 0x00000f00) >> 8; - if (pclk >= 165000) - *conf |= 0x0100; - break; - case DCB_OUTPUT_LVDS: - *conf = priv->sor.lvdsconf; - break; - case DCB_OUTPUT_DP: - *conf = (ctrl & 0x00000f00) >> 8; - break; - case DCB_OUTPUT_ANALOG: - default: - *conf = 0x00ff; - break; - } - - data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); - if (data && id < 0xff) { - data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); - if (data) { - struct nvbios_init init = { - .subdev = nv_subdev(priv), - .bios = bios, - .offset = data, - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - } - - return outp; -} - -static void -gf110_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head) -{ - exec_script(priv, head, 1); -} - -static void -gf110_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head) -{ - struct nvkm_output *outp = exec_script(priv, head, 2); - - /* see note in nv50_disp_intr_unk20_0() */ - if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = (void *)outp; - struct nvbios_init init = { - .subdev = nv_subdev(priv), - .bios = nvkm_bios(priv), - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; - - nvbios_exec(&init); - atomic_set(&outpdp->lt.done, 0); - } -} - -static void -gf110_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head) -{ - struct nvkm_devinit *devinit = nvkm_devinit(priv); - u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; - if (pclk) - devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); - nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000); -} - -static void -gf110_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, - struct dcb_output *outp) -{ - const int or = ffs(outp->or) - 1; - const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020)); - const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300)); - const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff; - const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff; - const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff; - const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; - const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; - const u32 hoff = (head * 0x800); - const u32 soff = ( or * 0x800); - const u32 loff = (link * 0x080) + soff; - const u32 symbol = 100000; - const u32 TU = 64; - u32 dpctrl = nv_rd32(priv, 0x61c10c + loff); - u32 clksor = nv_rd32(priv, 0x612300 + soff); - u32 datarate, link_nr, link_bw, bits; - u64 ratio, value; - - link_nr = hweight32(dpctrl & 0x000f0000); - link_bw = (clksor & 0x007c0000) >> 18; - link_bw *= 27000; - - /* symbols/hblank - algorithm taken from comments in tegra driver */ - value = vblanke + vactive - vblanks - 7; - value = value * link_bw; - do_div(value, pclk); - value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value); - - /* symbols/vblank - algorithm taken from comments in tegra driver */ - value = vblanks - vblanke - 25; - value = value * link_bw; - do_div(value, pclk); - value = value - ((36 / link_nr) + 3) - 1; - nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value); - - /* watermark */ - if ((conf & 0x3c0) == 0x180) bits = 30; - else if ((conf & 0x3c0) == 0x140) bits = 24; - else bits = 18; - datarate = (pclk * bits) / 8; - - ratio = datarate; - ratio *= symbol; - do_div(ratio, link_nr * link_bw); - - value = (symbol - ratio) * TU; - value *= ratio; - do_div(value, symbol); - do_div(value, symbol); - - value += 5; - value |= 0x08000000; - - nv_wr32(priv, 0x616610 + hoff, value); -} - -static void -gf110_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) -{ - struct nvkm_output *outp; - u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; - u32 conf, addr, data; - - outp = exec_clkcmp(priv, head, 0xff, pclk, &conf); - if (!outp) - return; - - /* see note in nv50_disp_intr_unk20_2() */ - if (outp->info.type == DCB_OUTPUT_DP) { - u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300)); - switch ((sync & 0x000003c0) >> 6) { - case 6: pclk = pclk * 30; break; - case 5: pclk = pclk * 24; break; - case 2: - default: - pclk = pclk * 18; - break; - } - - if (nvkm_output_dp_train(outp, pclk, true)) - ERR("link not trained before attach\n"); - } else { - if (priv->sor.magic) - priv->sor.magic(outp); - } - - exec_clkcmp(priv, head, 0, pclk, &conf); - - if (outp->info.type == DCB_OUTPUT_ANALOG) { - addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; - data = 0x00000000; - } else { - addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; - data = (conf & 0x0100) ? 0x00000101 : 0x00000000; - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - nv_mask(priv, addr, 0x007c0000, 0x00280000); - break; - case DCB_OUTPUT_DP: - gf110_disp_intr_unk2_2_tu(priv, head, &outp->info); - break; - default: - break; - } - } - - nv_mask(priv, addr, 0x00000707, data); -} - -static void -gf110_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) -{ - u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; - u32 conf; - - exec_clkcmp(priv, head, 1, pclk, &conf); -} - -void -gf110_disp_intr_supervisor(struct work_struct *work) -{ - struct nv50_disp_priv *priv = - container_of(work, struct nv50_disp_priv, supervisor); - struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; - u32 mask[4]; - int head; - - nv_debug(priv, "supervisor %d\n", ffs(priv->super)); - for (head = 0; head < priv->head.nr; head++) { - mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800)); - nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]); - } - - if (priv->super & 0x00000001) { - nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); - for (head = 0; head < priv->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nv_debug(priv, "supervisor 1.0 - head %d\n", head); - gf110_disp_intr_unk1_0(priv, head); - } - } else - if (priv->super & 0x00000002) { - for (head = 0; head < priv->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nv_debug(priv, "supervisor 2.0 - head %d\n", head); - gf110_disp_intr_unk2_0(priv, head); - } - for (head = 0; head < priv->head.nr; head++) { - if (!(mask[head] & 0x00010000)) - continue; - nv_debug(priv, "supervisor 2.1 - head %d\n", head); - gf110_disp_intr_unk2_1(priv, head); - } - for (head = 0; head < priv->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nv_debug(priv, "supervisor 2.2 - head %d\n", head); - gf110_disp_intr_unk2_2(priv, head); - } - } else - if (priv->super & 0x00000004) { - for (head = 0; head < priv->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nv_debug(priv, "supervisor 3.0 - head %d\n", head); - gf110_disp_intr_unk4_0(priv, head); - } - } - - for (head = 0; head < priv->head.nr; head++) - nv_wr32(priv, 0x6101d4 + (head * 0x800), 0x00000000); - nv_wr32(priv, 0x6101d0, 0x80000000); -} - -static void -gf110_disp_intr_error(struct nv50_disp_priv *priv, int chid) -{ - const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; - u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12)); - u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12)); - u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12)); - - nv_error(priv, "chid %d mthd 0x%04x data 0x%08x " - "0x%08x 0x%08x\n", - chid, (mthd & 0x0000ffc), data, mthd, unkn); - - if (chid == 0) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, - impl->mthd.core); - break; - default: - break; - } - } else - if (chid <= 4) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, - impl->mthd.base); - break; - default: - break; - } - } else - if (chid <= 8) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5, - impl->mthd.ovly); - break; - default: - break; - } - } - - nv_wr32(priv, 0x61009c, (1 << chid)); - nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000); -} - -void -gf110_disp_intr(struct nvkm_subdev *subdev) -{ - struct nv50_disp_priv *priv = (void *)subdev; - u32 intr = nv_rd32(priv, 0x610088); - int i; - - if (intr & 0x00000001) { - u32 stat = nv_rd32(priv, 0x61008c); - while (stat) { - int chid = __ffs(stat); stat &= ~(1 << chid); - nv50_disp_chan_uevent_send(priv, chid); - nv_wr32(priv, 0x61008c, 1 << chid); - } - intr &= ~0x00000001; - } - - if (intr & 0x00000002) { - u32 stat = nv_rd32(priv, 0x61009c); - int chid = ffs(stat) - 1; - if (chid >= 0) - gf110_disp_intr_error(priv, chid); - intr &= ~0x00000002; - } - - if (intr & 0x00100000) { - u32 stat = nv_rd32(priv, 0x6100ac); - if (stat & 0x00000007) { - priv->super = (stat & 0x00000007); - schedule_work(&priv->supervisor); - nv_wr32(priv, 0x6100ac, priv->super); - stat &= ~0x00000007; - } - - if (stat) { - nv_info(priv, "unknown intr24 0x%08x\n", stat); - nv_wr32(priv, 0x6100ac, stat); - } - - intr &= ~0x00100000; - } - - for (i = 0; i < priv->head.nr; i++) { - u32 mask = 0x01000000 << i; - if (mask & intr) { - u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); - if (stat & 0x00000001) - nvkm_disp_vblank(&priv->base, i); - nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); - nv_rd32(priv, 0x6100c0 + (i * 0x800)); - } - } -} - -static int -gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_disp_priv *priv; - int heads = nv_rd32(parent, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = gf110_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gf110_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gf110_hdmi_ctrl; - return 0; -} - -struct nvkm_oclass * -gf110_disp_outp_sclass[] = { - &gf110_sor_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * -gf110_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x90), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, - .mthd.core = &gf110_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, - .mthd.ovly = &gf110_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c new file mode 100644 index 000000000000..186fd3ac78f6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -0,0 +1,536 @@ +/* + * 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" +#include "rootnv50.h" + +#include <subdev/bios.h> +#include <subdev/bios/disp.h> +#include <subdev/bios/init.h> +#include <subdev/bios/pll.h> +#include <subdev/devinit.h> + +void +gf119_disp_vblank_init(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); +} + +void +gf119_disp_vblank_fini(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); +} + +static struct nvkm_output * +exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, + u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_outp *info) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; + struct nvkm_output *outp; + u16 mask, type; + + if (or < 4) { + type = DCB_OUTPUT_ANALOG; + mask = 0; + } else { + or -= 4; + switch (ctrl & 0x00000f00) { + case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; + case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; + case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; + case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; + case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; + case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; + default: + nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); + return NULL; + } + } + + mask = 0x00c0 & (mask << 6); + mask |= 0x0001 << or; + mask |= 0x0100 << head; + + list_for_each_entry(outp, &disp->base.outp, head) { + if ((outp->info.hasht & 0xff) == type && + (outp->info.hashm & mask) == mask) { + *data = nvbios_outp_match(bios, outp->info.hasht, + outp->info.hashm, + ver, hdr, cnt, len, info); + if (!*data) + return NULL; + return outp; + } + } + + return NULL; +} + +static struct nvkm_output * +exec_script(struct nv50_disp *disp, int head, int id) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvkm_output *outp; + struct nvbios_outp info; + u8 ver, hdr, cnt, len; + u32 data, ctrl = 0; + int or; + + for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { + ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20)); + if (ctrl & (1 << head)) + break; + } + + if (or == 8) + return NULL; + + outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); + if (outp) { + struct nvbios_init init = { + .subdev = subdev, + .bios = bios, + .offset = info.script[id], + .outp = &outp->info, + .crtc = head, + .execute = 1, + }; + + nvbios_exec(&init); + } + + return outp; +} + +static struct nvkm_output * +exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvkm_output *outp; + struct nvbios_outp info1; + struct nvbios_ocfg info2; + u8 ver, hdr, cnt, len; + u32 data, ctrl = 0; + int or; + + for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { + ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20)); + if (ctrl & (1 << head)) + break; + } + + if (or == 8) + return NULL; + + outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); + if (!outp) + return NULL; + + switch (outp->info.type) { + case DCB_OUTPUT_TMDS: + *conf = (ctrl & 0x00000f00) >> 8; + if (pclk >= 165000) + *conf |= 0x0100; + break; + case DCB_OUTPUT_LVDS: + *conf = disp->sor.lvdsconf; + break; + case DCB_OUTPUT_DP: + *conf = (ctrl & 0x00000f00) >> 8; + break; + case DCB_OUTPUT_ANALOG: + default: + *conf = 0x00ff; + break; + } + + data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); + if (data && id < 0xff) { + data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); + if (data) { + struct nvbios_init init = { + .subdev = subdev, + .bios = bios, + .offset = data, + .outp = &outp->info, + .crtc = head, + .execute = 1, + }; + + nvbios_exec(&init); + } + } + + return outp; +} + +static void +gf119_disp_intr_unk1_0(struct nv50_disp *disp, int head) +{ + exec_script(disp, head, 1); +} + +static void +gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_output *outp = exec_script(disp, head, 2); + + /* see note in nv50_disp_intr_unk20_0() */ + if (outp && outp->info.type == DCB_OUTPUT_DP) { + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + struct nvbios_init init = { + .subdev = subdev, + .bios = subdev->device->bios, + .outp = &outp->info, + .crtc = head, + .offset = outpdp->info.script[4], + .execute = 1, + }; + + nvbios_exec(&init); + atomic_set(&outpdp->lt.done, 0); + } +} + +static void +gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_devinit *devinit = device->devinit; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + if (pclk) + nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); + nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); +} + +static void +gf119_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, + struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const int or = ffs(outp->or) - 1; + const u32 ctrl = nvkm_rd32(device, 0x660200 + (or * 0x020)); + const u32 conf = nvkm_rd32(device, 0x660404 + (head * 0x300)); + const s32 vactive = nvkm_rd32(device, 0x660414 + (head * 0x300)) & 0xffff; + const s32 vblanke = nvkm_rd32(device, 0x66041c + (head * 0x300)) & 0xffff; + const s32 vblanks = nvkm_rd32(device, 0x660420 + (head * 0x300)) & 0xffff; + const u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; + const u32 hoff = (head * 0x800); + const u32 soff = ( or * 0x800); + const u32 loff = (link * 0x080) + soff; + const u32 symbol = 100000; + const u32 TU = 64; + u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); + u32 clksor = nvkm_rd32(device, 0x612300 + soff); + u32 datarate, link_nr, link_bw, bits; + u64 ratio, value; + + link_nr = hweight32(dpctrl & 0x000f0000); + link_bw = (clksor & 0x007c0000) >> 18; + link_bw *= 27000; + + /* symbols/hblank - algorithm taken from comments in tegra driver */ + value = vblanke + vactive - vblanks - 7; + value = value * link_bw; + do_div(value, pclk); + value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); + nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, value); + + /* symbols/vblank - algorithm taken from comments in tegra driver */ + value = vblanks - vblanke - 25; + value = value * link_bw; + do_div(value, pclk); + value = value - ((36 / link_nr) + 3) - 1; + nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, value); + + /* watermark */ + if ((conf & 0x3c0) == 0x180) bits = 30; + else if ((conf & 0x3c0) == 0x140) bits = 24; + else bits = 18; + datarate = (pclk * bits) / 8; + + ratio = datarate; + ratio *= symbol; + do_div(ratio, link_nr * link_bw); + + value = (symbol - ratio) * TU; + value *= ratio; + do_div(value, symbol); + do_div(value, symbol); + + value += 5; + value |= 0x08000000; + + nvkm_wr32(device, 0x616610 + hoff, value); +} + +static void +gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_output *outp; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + u32 conf, addr, data; + + outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); + if (!outp) + return; + + /* see note in nv50_disp_intr_unk20_2() */ + if (outp->info.type == DCB_OUTPUT_DP) { + u32 sync = nvkm_rd32(device, 0x660404 + (head * 0x300)); + switch ((sync & 0x000003c0) >> 6) { + case 6: pclk = pclk * 30; break; + case 5: pclk = pclk * 24; break; + case 2: + default: + pclk = pclk * 18; + break; + } + + if (nvkm_output_dp_train(outp, pclk, true)) + OUTP_ERR(outp, "link not trained before attach"); + } else { + if (disp->func->sor.magic) + disp->func->sor.magic(outp); + } + + exec_clkcmp(disp, head, 0, pclk, &conf); + + if (outp->info.type == DCB_OUTPUT_ANALOG) { + addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; + data = 0x00000000; + } else { + addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; + data = (conf & 0x0100) ? 0x00000101 : 0x00000000; + switch (outp->info.type) { + case DCB_OUTPUT_TMDS: + nvkm_mask(device, addr, 0x007c0000, 0x00280000); + break; + case DCB_OUTPUT_DP: + gf119_disp_intr_unk2_2_tu(disp, head, &outp->info); + break; + default: + break; + } + } + + nvkm_mask(device, addr, 0x00000707, data); +} + +static void +gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + u32 conf; + + exec_clkcmp(disp, head, 1, pclk, &conf); +} + +void +gf119_disp_intr_supervisor(struct work_struct *work) +{ + struct nv50_disp *disp = + container_of(work, struct nv50_disp, supervisor); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask[4]; + int head; + + nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); + for (head = 0; head < disp->base.head.nr; head++) { + mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); + nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); + } + + if (disp->super & 0x00000001) { + nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); + for (head = 0; head < disp->base.head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); + gf119_disp_intr_unk1_0(disp, head); + } + } else + if (disp->super & 0x00000002) { + for (head = 0; head < disp->base.head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); + gf119_disp_intr_unk2_0(disp, head); + } + for (head = 0; head < disp->base.head.nr; head++) { + if (!(mask[head] & 0x00010000)) + continue; + nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); + gf119_disp_intr_unk2_1(disp, head); + } + for (head = 0; head < disp->base.head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); + gf119_disp_intr_unk2_2(disp, head); + } + } else + if (disp->super & 0x00000004) { + for (head = 0; head < disp->base.head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); + gf119_disp_intr_unk4_0(disp, head); + } + } + + for (head = 0; head < disp->base.head.nr; head++) + nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); + nvkm_wr32(device, 0x6101d0, 0x80000000); +} + +static void +gf119_disp_intr_error(struct nv50_disp *disp, int chid) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12)); + u32 data = nvkm_rd32(device, 0x6101f4 + (chid * 12)); + u32 unkn = nvkm_rd32(device, 0x6101f8 + (chid * 12)); + + nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n", + chid, (mthd & 0x0000ffc), data, mthd, unkn); + + if (chid < ARRAY_SIZE(disp->chan)) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); + break; + default: + break; + } + } + + nvkm_wr32(device, 0x61009c, (1 << chid)); + nvkm_wr32(device, 0x6101f0 + (chid * 12), 0x90000000); +} + +void +gf119_disp_intr(struct nv50_disp *disp) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x610088); + int i; + + if (intr & 0x00000001) { + u32 stat = nvkm_rd32(device, 0x61008c); + while (stat) { + int chid = __ffs(stat); stat &= ~(1 << chid); + nv50_disp_chan_uevent_send(disp, chid); + nvkm_wr32(device, 0x61008c, 1 << chid); + } + intr &= ~0x00000001; + } + + if (intr & 0x00000002) { + u32 stat = nvkm_rd32(device, 0x61009c); + int chid = ffs(stat) - 1; + if (chid >= 0) + gf119_disp_intr_error(disp, chid); + intr &= ~0x00000002; + } + + if (intr & 0x00100000) { + u32 stat = nvkm_rd32(device, 0x6100ac); + if (stat & 0x00000007) { + disp->super = (stat & 0x00000007); + schedule_work(&disp->supervisor); + nvkm_wr32(device, 0x6100ac, disp->super); + stat &= ~0x00000007; + } + + if (stat) { + nvkm_warn(subdev, "intr24 %08x\n", stat); + nvkm_wr32(device, 0x6100ac, stat); + } + + intr &= ~0x00100000; + } + + for (i = 0; i < disp->base.head.nr; i++) { + u32 mask = 0x01000000 << i; + if (mask & intr) { + u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); + if (stat & 0x00000001) + nvkm_disp_vblank(&disp->base, i); + nvkm_mask(device, 0x6100bc + (i * 0x800), 0, 0); + nvkm_rd32(device, 0x6100c0 + (i * 0x800)); + } + } +} + +int +gf119_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, + int index, struct nvkm_disp **pdisp) +{ + u32 heads = nvkm_rd32(device, 0x022448); + return nv50_disp_new_(func, device, index, heads, pdisp); +} + +static const struct nv50_disp_func +gf119_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, + .root = &gf119_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gf119_hdmi_ctrl, +}; + +int +gf119_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) +{ + return gf119_disp_new_(&gf119_disp, device, index, pdisp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 6f4019ab4e65..a86384b8e388 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -22,247 +22,32 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include <nvif/class.h> - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gk104_disp_core_mthd_head = { - .mthd = 0x0300, - .addr = 0x000300, - .data = { - { 0x0400, 0x660400 }, - { 0x0404, 0x660404 }, - { 0x0408, 0x660408 }, - { 0x040c, 0x66040c }, - { 0x0410, 0x660410 }, - { 0x0414, 0x660414 }, - { 0x0418, 0x660418 }, - { 0x041c, 0x66041c }, - { 0x0420, 0x660420 }, - { 0x0424, 0x660424 }, - { 0x0428, 0x660428 }, - { 0x042c, 0x66042c }, - { 0x0430, 0x660430 }, - { 0x0434, 0x660434 }, - { 0x0438, 0x660438 }, - { 0x0440, 0x660440 }, - { 0x0444, 0x660444 }, - { 0x0448, 0x660448 }, - { 0x044c, 0x66044c }, - { 0x0450, 0x660450 }, - { 0x0454, 0x660454 }, - { 0x0458, 0x660458 }, - { 0x045c, 0x66045c }, - { 0x0460, 0x660460 }, - { 0x0468, 0x660468 }, - { 0x046c, 0x66046c }, - { 0x0470, 0x660470 }, - { 0x0474, 0x660474 }, - { 0x047c, 0x66047c }, - { 0x0480, 0x660480 }, - { 0x0484, 0x660484 }, - { 0x0488, 0x660488 }, - { 0x048c, 0x66048c }, - { 0x0490, 0x660490 }, - { 0x0494, 0x660494 }, - { 0x0498, 0x660498 }, - { 0x04a0, 0x6604a0 }, - { 0x04b0, 0x6604b0 }, - { 0x04b8, 0x6604b8 }, - { 0x04bc, 0x6604bc }, - { 0x04c0, 0x6604c0 }, - { 0x04c4, 0x6604c4 }, - { 0x04c8, 0x6604c8 }, - { 0x04d0, 0x6604d0 }, - { 0x04d4, 0x6604d4 }, - { 0x04e0, 0x6604e0 }, - { 0x04e4, 0x6604e4 }, - { 0x04e8, 0x6604e8 }, - { 0x04ec, 0x6604ec }, - { 0x04f0, 0x6604f0 }, - { 0x04f4, 0x6604f4 }, - { 0x04f8, 0x6604f8 }, - { 0x04fc, 0x6604fc }, - { 0x0500, 0x660500 }, - { 0x0504, 0x660504 }, - { 0x0508, 0x660508 }, - { 0x050c, 0x66050c }, - { 0x0510, 0x660510 }, - { 0x0514, 0x660514 }, - { 0x0518, 0x660518 }, - { 0x051c, 0x66051c }, - { 0x0520, 0x660520 }, - { 0x0524, 0x660524 }, - { 0x052c, 0x66052c }, - { 0x0530, 0x660530 }, - { 0x054c, 0x66054c }, - { 0x0550, 0x660550 }, - { 0x0554, 0x660554 }, - { 0x0558, 0x660558 }, - { 0x055c, 0x66055c }, - {} - } -}; - -const struct nv50_disp_mthd_chan -gk104_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &gf110_disp_core_mthd_base }, - { "DAC", 3, &gf110_disp_core_mthd_dac }, - { "SOR", 8, &gf110_disp_core_mthd_sor }, - { "PIOR", 4, &gf110_disp_core_mthd_pior }, - { "HEAD", 4, &gk104_disp_core_mthd_head }, - {} - } -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gk104_disp_ovly_mthd_base = { - .mthd = 0x0000, - .data = { - { 0x0080, 0x665080 }, - { 0x0084, 0x665084 }, - { 0x0088, 0x665088 }, - { 0x008c, 0x66508c }, - { 0x0090, 0x665090 }, - { 0x0094, 0x665094 }, - { 0x00a0, 0x6650a0 }, - { 0x00a4, 0x6650a4 }, - { 0x00b0, 0x6650b0 }, - { 0x00b4, 0x6650b4 }, - { 0x00b8, 0x6650b8 }, - { 0x00c0, 0x6650c0 }, - { 0x00c4, 0x6650c4 }, - { 0x00e0, 0x6650e0 }, - { 0x00e4, 0x6650e4 }, - { 0x00e8, 0x6650e8 }, - { 0x0100, 0x665100 }, - { 0x0104, 0x665104 }, - { 0x0108, 0x665108 }, - { 0x010c, 0x66510c }, - { 0x0110, 0x665110 }, - { 0x0118, 0x665118 }, - { 0x011c, 0x66511c }, - { 0x0120, 0x665120 }, - { 0x0124, 0x665124 }, - { 0x0130, 0x665130 }, - { 0x0134, 0x665134 }, - { 0x0138, 0x665138 }, - { 0x013c, 0x66513c }, - { 0x0140, 0x665140 }, - { 0x0144, 0x665144 }, - { 0x0148, 0x665148 }, - { 0x014c, 0x66514c }, - { 0x0150, 0x665150 }, - { 0x0154, 0x665154 }, - { 0x0158, 0x665158 }, - { 0x015c, 0x66515c }, - { 0x0160, 0x665160 }, - { 0x0164, 0x665164 }, - { 0x0168, 0x665168 }, - { 0x016c, 0x66516c }, - { 0x0400, 0x665400 }, - { 0x0404, 0x665404 }, - { 0x0408, 0x665408 }, - { 0x040c, 0x66540c }, - { 0x0410, 0x665410 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -gk104_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x001000, - .data = { - { "Global", 1, &gk104_disp_ovly_mthd_base }, - {} - } +#include "rootnv50.h" + +static const struct nv50_disp_func +gk104_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, + .root = &gk104_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, }; -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gk104_disp_sclass[] = { - { GK104_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK104_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gk104_disp_main_oclass[] = { - { GK104_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int heads = nv_rd32(parent, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = gk104_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gk104_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gk104_hdmi_ctrl; - return 0; + return gf119_disp_new_(&gk104_disp, device, index, pdisp); } - -struct nvkm_oclass * -gk104_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x91), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index daa4b460a6ba..0d574c7e594a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -22,82 +22,32 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include <nvif/class.h> - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gk110_disp_sclass[] = { - { GK110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gk110_disp_main_oclass[] = { - { GK110_DISP, &gf110_disp_main_ofuncs }, - {} +#include "rootnv50.h" + +static const struct nv50_disp_func +gk110_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, + .root = &gk110_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, }; -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk110_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int heads = nv_rd32(parent, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = gk110_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gk110_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gk104_hdmi_ctrl; - return 0; + return gf119_disp_new_(&gk110_disp, device, index, pdisp); } - -struct nvkm_oclass * -gk110_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x92), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk110_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 881cc94385a1..b6944142d616 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -22,82 +22,32 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include <nvif/class.h> - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gm107_disp_sclass[] = { - { GM107_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gm107_disp_main_oclass[] = { - { GM107_DISP, &gf110_disp_main_ofuncs }, - {} +#include "rootnv50.h" + +static const struct nv50_disp_func +gm107_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, + .root = &gm107_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, }; -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm107_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int heads = nv_rd32(parent, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = gm107_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gm107_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gk104_hdmi_ctrl; - return 0; + return gf119_disp_new_(&gm107_disp, device, index, pdisp); } - -struct nvkm_oclass * -gm107_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x07), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index 67004f8302b3..30f1987b5b40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -22,90 +22,33 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" - -#include <nvif/class.h> - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gm204_disp_sclass[] = { - { GM204_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} +#include "rootnv50.h" + +static const struct nv50_disp_func +gm204_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, + .root = &gm204_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gm204_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, + .sor.magic = gm204_sor_magic, }; -static struct nvkm_oclass -gm204_disp_main_oclass[] = { - { GM204_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm204_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int heads = nv_rd32(parent, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = gm204_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gm204_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gf110_hdmi_ctrl; - priv->sor.magic = gm204_sor_magic; - return 0; + return gf119_disp_new_(&gm204_disp, device, index, pdisp); } - -struct nvkm_oclass * -gm204_disp_outp_sclass[] = { - &gm204_sor_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * -gm204_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x07), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &gf110_disp_vblank_func, - .base.outp = gm204_disp_outp_sclass, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index a45307213f4b..6bc3bf096001 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -22,127 +22,34 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include <nvif/class.h> - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gt200_disp_ovly_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x6109a0 }, - { 0x0088, 0x6109c0 }, - { 0x008c, 0x6109c8 }, - { 0x0090, 0x6109b4 }, - { 0x0094, 0x610970 }, - { 0x00a0, 0x610998 }, - { 0x00a4, 0x610964 }, - { 0x00b0, 0x610c98 }, - { 0x00b4, 0x610ca4 }, - { 0x00b8, 0x610cac }, - { 0x00c0, 0x610958 }, - { 0x00e0, 0x6109a8 }, - { 0x00e4, 0x6109d0 }, - { 0x00e8, 0x6109d8 }, - { 0x0100, 0x61094c }, - { 0x0104, 0x610984 }, - { 0x0108, 0x61098c }, - { 0x0800, 0x6109f8 }, - { 0x0808, 0x610a08 }, - { 0x080c, 0x610a10 }, - { 0x0810, 0x610a00 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -gt200_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x000540, - .data = { - { "Global", 1, >200_disp_ovly_mthd_base }, - {} - } -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gt200_disp_sclass[] = { - { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} +#include "rootnv50.h" + +static const struct nv50_disp_func +gt200_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, + .root = >200_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 2, + .sor.power = nv50_sor_power, + .sor.hdmi = g84_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -static struct nvkm_oclass -gt200_disp_main_oclass[] = { - { GT200_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt200_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = gt200_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = gt200_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 2; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hdmi = g84_hdmi_ctrl; - priv->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(>200_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -gt200_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x83), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt200_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, - .mthd.core = &g84_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = >200_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 55f0d3ac591e..94026288ab4d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -22,83 +22,36 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include <nvif/class.h> - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gt215_disp_sclass[] = { - { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gt215_disp_main_oclass[] = { - { GT214_DISP, &nv50_disp_main_ofuncs }, - {} +#include "rootnv50.h" + +static const struct nv50_disp_func +gt215_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, + .root = >215_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = g94_sor_dp_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gt215_hda_eld, + .sor.hdmi = gt215_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static int -gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt215_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = gt215_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = gt215_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gt215_hda_eld; - priv->sor.hdmi = gt215_hdmi_ctrl; - priv->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(>215_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -gt215_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x85), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &nv50_disp_vblank_func, - .base.outp = g94_disp_outp_sclass, - .mthd.core = &g94_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = &g84_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c index b9813d246ba5..af99efbd63f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c @@ -33,8 +33,9 @@ #include <nvif/unpack.h> int -gf110_hda_eld(NV50_DISP_MTHD_V1) +gf119_hda_eld(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; union { struct nv50_disp_sor_hda_eld_v0 v0; } *args = data; @@ -42,9 +43,10 @@ gf110_hda_eld(NV50_DISP_MTHD_V1) const u32 hoff = head * 0x800; int ret, i; - nv_ioctl(object, "disp sor hda eld size %d\n", size); + nvif_ioctl(object, "disp sor hda eld size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version); + nvif_ioctl(object, "disp sor hda eld vers %d\n", + args->v0.version); if (size > 0x60) return -E2BIG; } else @@ -52,21 +54,29 @@ gf110_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001); - nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000); + nvkm_mask(device, 0x616618 + hoff, 0x8000000c, 0x80000001); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x616618 + hoff); + if (!(tmp & 0x80000000)) + break; + ); } - nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000); + nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); + nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); for (; i < 0x60; i++) - nv_wr32(priv, 0x10ec00 + soff, (i << 8)); - nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003); + nvkm_wr32(device, 0x10ec00 + soff, (i << 8)); + nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000003); } else { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000); - nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000); + nvkm_mask(device, 0x616618 + hoff, 0x80000001, 0x80000000); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x616618 + hoff); + if (!(tmp & 0x80000000)) + break; + ); } - nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); + nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c index 891d1e7bf7d2..c1590b746f13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c @@ -33,15 +33,17 @@ int gt215_hda_eld(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; union { struct nv50_disp_sor_hda_eld_v0 v0; } *args = data; const u32 soff = outp->or * 0x800; int ret, i; - nv_ioctl(object, "disp sor hda eld size %d\n", size); + nvif_ioctl(object, "disp sor hda eld size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version); + nvif_ioctl(object, "disp sor hda eld vers %d\n", + args->v0.version); if (size > 0x60) return -E2BIG; } else @@ -49,20 +51,28 @@ gt215_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001); - nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000); + nvkm_mask(device, 0x61c1e0 + soff, 0x8000000d, 0x80000001); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff); + if (!(tmp & 0x80000000)) + break; + ); } for (i = 0; i < size; i++) - nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]); + nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[0]); for (; i < 0x60; i++) - nv_wr32(priv, 0x61c440 + soff, (i << 8)); - nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003); + nvkm_wr32(device, 0x61c440 + soff, (i << 8)); + nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003); } else { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000); - nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000); + nvkm_mask(device, 0x61c1e0 + soff, 0x80000001, 0x80000000); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff); + if (!(tmp & 0x80000000)) + break; + ); } - nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); + nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index 621cb0b7ff19..ee9e800a8f06 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -31,6 +31,7 @@ int g84_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); union { struct nv50_disp_sor_hdmi_pwr_v0 v0; @@ -38,12 +39,12 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; @@ -54,38 +55,38 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000); - nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000); - nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x616528 + hoff, 0x000d0282); - nv_wr32(priv, 0x61652c + hoff, 0x0000006f); - nv_wr32(priv, 0x616530 + hoff, 0x00000000); - nv_wr32(priv, 0x616534 + hoff, 0x00000000); - nv_wr32(priv, 0x616538 + hoff, 0x00000000); - nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x616528 + hoff, 0x000d0282); + nvkm_wr32(device, 0x61652c + hoff, 0x0000006f); + nvkm_wr32(device, 0x616530 + hoff, 0x00000000); + nvkm_wr32(device, 0x616534 + hoff, 0x00000000); + nvkm_wr32(device, 0x616538 + hoff, 0x00000000); + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001); /* Audio InfoFrame */ - nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x616508 + hoff, 0x000a0184); - nv_wr32(priv, 0x61650c + hoff, 0x00000071); - nv_wr32(priv, 0x616510 + hoff, 0x00000000); - nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x616508 + hoff, 0x000a0184); + nvkm_wr32(device, 0x61650c + hoff, 0x00000071); + nvkm_wr32(device, 0x616510 + hoff, 0x00000000); + nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001); - nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ - nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ - nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ + nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ + nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ + nvkm_mask(device, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ /* ??? */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ - nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ + nvkm_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl); + nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c index c28449061bbd..b5af025d3b04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c @@ -29,8 +29,9 @@ #include <nvif/unpack.h> int -gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) +gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); union { struct nv50_disp_sor_hdmi_pwr_v0 v0; @@ -38,12 +39,12 @@ gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; @@ -53,27 +54,27 @@ gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); - nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000); - nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x61671c + hoff, 0x000d0282); - nv_wr32(priv, 0x616720 + hoff, 0x0000006f); - nv_wr32(priv, 0x616724 + hoff, 0x00000000); - nv_wr32(priv, 0x616728 + hoff, 0x00000000); - nv_wr32(priv, 0x61672c + hoff, 0x00000000); - nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x61671c + hoff, 0x000d0282); + nvkm_wr32(device, 0x616720 + hoff, 0x0000006f); + nvkm_wr32(device, 0x616724 + hoff, 0x00000000); + nvkm_wr32(device, 0x616728 + hoff, 0x00000000); + nvkm_wr32(device, 0x61672c + hoff, 0x00000000); + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001); /* ??? InfoFrame? */ - nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x6167ac + hoff, 0x00000010); - nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x6167ac + hoff, 0x00000010); + nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000001); /* HDMI_CTRL */ - nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl); + nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index ca34ff81ad7f..110dc19e4f67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -31,6 +31,7 @@ int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); const u32 hdmi = (head * 0x400); union { @@ -39,12 +40,12 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; @@ -54,30 +55,30 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); - nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); - nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); - nv_wr32(priv, 0x690008 + hdmi, 0x000d0282); - nv_wr32(priv, 0x69000c + hdmi, 0x0000006f); - nv_wr32(priv, 0x690010 + hdmi, 0x00000000); - nv_wr32(priv, 0x690014 + hdmi, 0x00000000); - nv_wr32(priv, 0x690018 + hdmi, 0x00000000); - nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001); + nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x690008 + hdmi, 0x000d0282); + nvkm_wr32(device, 0x69000c + hdmi, 0x0000006f); + nvkm_wr32(device, 0x690010 + hdmi, 0x00000000); + nvkm_wr32(device, 0x690014 + hdmi, 0x00000000); + nvkm_wr32(device, 0x690018 + hdmi, 0x00000000); + nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001); /* ??? InfoFrame? */ - nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); - nv_wr32(priv, 0x6900cc + hdmi, 0x00000010); - nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001); + nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x6900cc + hdmi, 0x00000010); + nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000001); /* ??? */ - nv_wr32(priv, 0x690080 + hdmi, 0x82000000); + nvkm_wr32(device, 0x690080 + hdmi, 0x82000000); /* HDMI_CTRL */ - nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl); + nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index b641c167dcfa..61237dbfa35a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -32,6 +32,7 @@ int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = outp->or * 0x800; union { struct nv50_disp_sor_hdmi_pwr_v0 v0; @@ -39,12 +40,12 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; @@ -55,38 +56,38 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000); - nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000); - nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x61c528 + soff, 0x000d0282); - nv_wr32(priv, 0x61c52c + soff, 0x0000006f); - nv_wr32(priv, 0x61c530 + soff, 0x00000000); - nv_wr32(priv, 0x61c534 + soff, 0x00000000); - nv_wr32(priv, 0x61c538 + soff, 0x00000000); - nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x61c528 + soff, 0x000d0282); + nvkm_wr32(device, 0x61c52c + soff, 0x0000006f); + nvkm_wr32(device, 0x61c530 + soff, 0x00000000); + nvkm_wr32(device, 0x61c534 + soff, 0x00000000); + nvkm_wr32(device, 0x61c538 + soff, 0x00000000); + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001); /* Audio InfoFrame */ - nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x61c508 + soff, 0x000a0184); - nv_wr32(priv, 0x61c50c + soff, 0x00000071); - nv_wr32(priv, 0x61c510 + soff, 0x00000000); - nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x61c508 + soff, 0x000a0184); + nvkm_wr32(device, 0x61c50c + soff, 0x00000071); + nvkm_wr32(device, 0x61c510 + soff, 0x00000000); + nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001); - nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ - nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ - nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ + nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ + nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ + nvkm_mask(device, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ /* ??? */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ - nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ + nvkm_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl); + nvkm_mask(device, 0x61c5a4 + soff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index ff09b2659c17..67254ce6f83f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -23,183 +23,63 @@ */ #include "priv.h" -#include <core/client.h> -#include <core/device.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -struct nv04_disp_priv { - struct nvkm_disp base; -}; - -static int -nv04_disp_scanoutpos(struct nvkm_object *object, struct nv04_disp_priv *priv, - void *data, u32 size, int head) +static const struct nvkm_disp_oclass * +nv04_disp_root(struct nvkm_disp *disp) { - const u32 hoff = head * 0x2000; - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; - u32 line; - int ret; - - nv_ioctl(object, "disp scanoutpos size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); - args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff; - args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff; - args->v0.vblanke = args->v0.vtotal - 1; - - args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff; - args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff; - args->v0.hblanke = args->v0.htotal - 1; - - /* - * If output is vga instead of digital then vtotal/htotal is - * invalid so we have to give up and trigger the timestamping - * fallback in the drm core. - */ - if (!args->v0.vtotal || !args->v0.htotal) - return -ENOTSUPP; - - args->v0.time[0] = ktime_to_ns(ktime_get()); - line = nv_rd32(priv, 0x600868 + hoff); - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = (line & 0xffff0000) >> 16; - args->v0.vline = (line & 0x0000ffff); - } else - return ret; - - return 0; + return &nv04_disp_root_oclass; } -static int -nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - union { - struct nv04_disp_mthd_v0 v0; - } *args = data; - struct nv04_disp_priv *priv = (void *)object->engine; - int head, ret; - - nv_ioctl(object, "disp mthd size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); - mthd = args->v0.method; - head = args->v0.head; - } else - return ret; - - if (head < 0 || head >= 2) - return -ENXIO; - - switch (mthd) { - case NV04_DISP_SCANOUTPOS: - return nv04_disp_scanoutpos(object, priv, data, size, head); - default: - break; - } - - return -EINVAL; -} - -static struct nvkm_ofuncs -nv04_disp_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, - .mthd = nv04_disp_mthd, - .ntfy = nvkm_disp_ntfy, -}; - -static struct nvkm_oclass -nv04_disp_sclass[] = { - { NV04_DISP, &nv04_disp_ofuncs }, - {}, -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - static void -nv04_disp_vblank_init(struct nvkm_event *event, int type, int head) +nv04_disp_vblank_init(struct nvkm_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000001); } static void -nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head) +nv04_disp_vblank_fini(struct nvkm_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000000); } -static const struct nvkm_event_func -nv04_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, - .init = nv04_disp_vblank_init, - .fini = nv04_disp_vblank_fini, -}; - static void -nv04_disp_intr(struct nvkm_subdev *subdev) +nv04_disp_intr(struct nvkm_disp *disp) { - struct nv04_disp_priv *priv = (void *)subdev; - u32 crtc0 = nv_rd32(priv, 0x600100); - u32 crtc1 = nv_rd32(priv, 0x602100); + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_device *device = subdev->device; + u32 crtc0 = nvkm_rd32(device, 0x600100); + u32 crtc1 = nvkm_rd32(device, 0x602100); u32 pvideo; if (crtc0 & 0x00000001) { - nvkm_disp_vblank(&priv->base, 0); - nv_wr32(priv, 0x600100, 0x00000001); + nvkm_disp_vblank(disp, 0); + nvkm_wr32(device, 0x600100, 0x00000001); } if (crtc1 & 0x00000001) { - nvkm_disp_vblank(&priv->base, 1); - nv_wr32(priv, 0x602100, 0x00000001); + nvkm_disp_vblank(disp, 1); + nvkm_wr32(device, 0x602100, 0x00000001); } - if (nv_device(priv)->chipset >= 0x10 && - nv_device(priv)->chipset <= 0x40) { - pvideo = nv_rd32(priv, 0x8100); + if (device->chipset >= 0x10 && device->chipset <= 0x40) { + pvideo = nvkm_rd32(device, 0x8100); if (pvideo & ~0x11) - nv_info(priv, "PVIDEO intr: %08x\n", pvideo); - nv_wr32(priv, 0x8100, pvideo); + nvkm_info(subdev, "PVIDEO intr: %08x\n", pvideo); + nvkm_wr32(device, 0x8100, pvideo); } } -static int -nv04_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv04_disp_priv *priv; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "DISPLAY", - "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_disp_func +nv04_disp = { + .intr = nv04_disp_intr, + .root = nv04_disp_root, + .head.vblank_init = nv04_disp_vblank_init, + .head.vblank_fini = nv04_disp_vblank_fini, +}; - nv_engine(priv)->sclass = nv04_disp_sclass; - nv_subdev(priv)->intr = nv04_disp_intr; - return 0; +int +nv04_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) +{ + return nvkm_disp_new_(&nv04_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -nv04_disp_oclass = &(struct nvkm_disp_impl) { - .base.handle = NV_ENGINE(DISP, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .vblank = &nv04_disp_vblank_func, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 8ba808df24ad..32e73a975b58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -22,1291 +22,158 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outp.h" -#include "outpdp.h" +#include "rootnv50.h" #include <core/client.h> -#include <core/device.h> -#include <core/engctx.h> #include <core/enum.h> -#include <core/handle.h> -#include <core/ramht.h> -#include <engine/dmaobj.h> +#include <core/gpuobj.h> #include <subdev/bios.h> -#include <subdev/bios/dcb.h> #include <subdev/bios/disp.h> #include <subdev/bios/init.h> #include <subdev/bios/pll.h> #include <subdev/devinit.h> -#include <subdev/fb.h> -#include <subdev/timer.h> -#include <nvif/class.h> -#include <nvif/event.h> -#include <nvif/unpack.h> - -/******************************************************************************* - * EVO channel base class - ******************************************************************************/ - -static int -nv50_disp_chan_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int head, - int length, void **pobject) -{ - const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs; - struct nv50_disp_base *base = (void *)parent; - struct nv50_disp_chan *chan; - int chid = impl->chid + head; - int ret; - - if (base->chan & (1 << chid)) - return -EBUSY; - base->chan |= (1 << chid); - - ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, - (1ULL << NVDEV_ENGINE_DMAOBJ), - length, pobject); - chan = *pobject; - if (ret) - return ret; - chan->chid = chid; - - nv_parent(chan)->object_attach = impl->attach; - nv_parent(chan)->object_detach = impl->detach; - return 0; -} - -static void -nv50_disp_chan_destroy(struct nv50_disp_chan *chan) -{ - struct nv50_disp_base *base = (void *)nv_object(chan)->parent; - base->chan &= ~(1 << chan->chid); - nvkm_namedb_destroy(&chan->base); -} - -static void -nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index); - nv_wr32(priv, 0x610020, 0x00000001 << index); -} - -static void -nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) -{ - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_wr32(priv, 0x610020, 0x00000001 << index); - nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index); -} - -void -nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid) -{ - struct nvif_notify_uevent_rep { - } rep; - - nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep)); -} - -int -nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - struct nv50_disp_dmac *dmac = (void *)object; - union { - struct nvif_notify_uevent_req none; - } *args = data; - int ret; - - if (nvif_unvers(args->none)) { - notify->size = sizeof(struct nvif_notify_uevent_rep); - notify->types = 1; - notify->index = dmac->base.chid; - return 0; - } - - return ret; -} - -const struct nvkm_event_func -nv50_disp_chan_uevent = { - .ctor = nv50_disp_chan_uevent_ctor, - .init = nv50_disp_chan_uevent_init, - .fini = nv50_disp_chan_uevent_fini, -}; - -int -nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, - struct nvkm_event **pevent) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - switch (type) { - case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: - *pevent = &priv->uevent; - return 0; - default: - break; - } - return -EINVAL; -} - -int -nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) +static const struct nvkm_disp_oclass * +nv50_disp_root_(struct nvkm_disp *base) { - struct nv50_disp_chan *chan = (void *)object; - *addr = nv_device_resource_start(nv_device(object), 0) + - 0x640000 + (chan->chid * 0x1000); - *size = 0x001000; - return 0; + return nv50_disp(base)->func->root; } -u32 -nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_chan *chan = (void *)object; - return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr); -} - -void -nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_chan *chan = (void *)object; - nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data); -} - -/******************************************************************************* - * EVO DMA channel base class - ******************************************************************************/ - static int -nv50_disp_dmac_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 name) -{ - struct nv50_disp_base *base = (void *)parent->parent; - struct nv50_disp_chan *chan = (void *)parent; - u32 addr = nv_gpuobj(object)->node->offset; - u32 chid = chan->chid; - u32 data = (chid << 28) | (addr << 10) | chid; - return nvkm_ramht_insert(base->ramht, chid, name, data); -} - -static void -nv50_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) +nv50_disp_outp_internal_crt_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, struct nvkm_output **poutp) { - struct nv50_disp_base *base = (void *)parent->parent; - nvkm_ramht_remove(base->ramht, cookie); + struct nv50_disp *disp = nv50_disp(base); + return disp->func->outp.internal.crt(base, index, dcb, poutp); } static int -nv50_disp_dmac_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 pushbuf, int head, - int length, void **pobject) -{ - struct nv50_disp_dmac *dmac; - int ret; - - ret = nv50_disp_chan_create_(parent, engine, oclass, head, - length, pobject); - dmac = *pobject; - if (ret) - return ret; - - dmac->pushdma = (void *)nvkm_handle_ref(parent, pushbuf); - if (!dmac->pushdma) - return -ENOENT; - - switch (nv_mclass(dmac->pushdma)) { - case 0x0002: - case 0x003d: - if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff) - return -EINVAL; - - switch (dmac->pushdma->target) { - case NV_MEM_TARGET_VRAM: - dmac->push = 0x00000001 | dmac->pushdma->start >> 8; - break; - case NV_MEM_TARGET_PCI_NOSNOOP: - dmac->push = 0x00000003 | dmac->pushdma->start >> 8; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - return 0; -} - -void -nv50_disp_dmac_dtor(struct nvkm_object *object) +nv50_disp_outp_internal_tmds_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, + struct nvkm_output **poutp) { - struct nv50_disp_dmac *dmac = (void *)object; - nvkm_object_ref(NULL, (struct nvkm_object **)&dmac->pushdma); - nv50_disp_chan_destroy(&dmac->base); + struct nv50_disp *disp = nv50_disp(base); + return disp->func->outp.internal.tmds(base, index, dcb, poutp); } static int -nv50_disp_dmac_init(struct nvkm_object *object) +nv50_disp_outp_internal_lvds_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, + struct nvkm_output **poutp) { - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - int chid = dmac->base.chid; - int ret; - - ret = nv50_disp_chan_init(&dmac->base); - if (ret) - return ret; - - /* enable error reporting */ - nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid); - - /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push); - nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000); - nv_wr32(priv, 0x61020c + (chid * 0x0010), chid); - nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000); - nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013); - - /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) { - nv_error(dmac, "init timeout, 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); - return -EBUSY; - } - - return 0; + struct nv50_disp *disp = nv50_disp(base); + return disp->func->outp.internal.lvds(base, index, dcb, poutp); } static int -nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) +nv50_disp_outp_internal_dp_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, struct nvkm_output **poutp) { - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - int chid = dmac->base.chid; - - /* deactivate channel */ - nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); - nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) { - nv_error(dmac, "fini timeout, 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notifications */ - nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid); - - return nv50_disp_chan_fini(&dmac->base, suspend); -} - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -static void -nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c, - const struct nv50_disp_mthd_list *list, int inst) -{ - struct nvkm_object *disp = nv_object(priv); - int i; - - for (i = 0; list->data[i].mthd; i++) { - if (list->data[i].addr) { - u32 next = nv_rd32(priv, list->data[i].addr + base + 0); - u32 prev = nv_rd32(priv, list->data[i].addr + base + c); - u32 mthd = list->data[i].mthd + (list->mthd * inst); - const char *name = list->data[i].name; - char mods[16]; - - if (prev != next) - snprintf(mods, sizeof(mods), "-> 0x%08x", next); - else - snprintf(mods, sizeof(mods), "%13c", ' '); - - nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n", - mthd, prev, mods, name ? " // " : "", - name ? name : ""); - } - } -} - -void -nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head, - const struct nv50_disp_mthd_chan *chan) -{ - struct nvkm_object *disp = nv_object(priv); - const struct nv50_disp_impl *impl = (void *)disp->oclass; - const struct nv50_disp_mthd_list *list; - int i, j; - - if (debug > nv_subdev(priv)->debug) - return; - - for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { - u32 base = head * chan->addr; - for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { - const char *cname = chan->name; - const char *sname = ""; - char cname_[16], sname_[16]; - - if (chan->addr) { - snprintf(cname_, sizeof(cname_), "%s %d", - chan->name, head); - cname = cname_; - } - - if (chan->data[i].nr > 1) { - snprintf(sname_, sizeof(sname_), " - %s %d", - chan->data[i].name, j); - sname = sname_; - } - - nv_printk_(disp, debug, "%s%s:\n", cname, sname); - nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev, - list, j); - } - } -} - -const struct nv50_disp_mthd_list -nv50_disp_core_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x610bb8 }, - { 0x0088, 0x610b9c }, - { 0x008c, 0x000000 }, - {} - } -}; - -static const struct nv50_disp_mthd_list -nv50_disp_core_mthd_dac = { - .mthd = 0x0080, - .addr = 0x000008, - .data = { - { 0x0400, 0x610b58 }, - { 0x0404, 0x610bdc }, - { 0x0420, 0x610828 }, - {} - } -}; - -const struct nv50_disp_mthd_list -nv50_disp_core_mthd_sor = { - .mthd = 0x0040, - .addr = 0x000008, - .data = { - { 0x0600, 0x610b70 }, - {} - } -}; - -const struct nv50_disp_mthd_list -nv50_disp_core_mthd_pior = { - .mthd = 0x0040, - .addr = 0x000008, - .data = { - { 0x0700, 0x610b80 }, - {} - } -}; - -static const struct nv50_disp_mthd_list -nv50_disp_core_mthd_head = { - .mthd = 0x0400, - .addr = 0x000540, - .data = { - { 0x0800, 0x610ad8 }, - { 0x0804, 0x610ad0 }, - { 0x0808, 0x610a48 }, - { 0x080c, 0x610a78 }, - { 0x0810, 0x610ac0 }, - { 0x0814, 0x610af8 }, - { 0x0818, 0x610b00 }, - { 0x081c, 0x610ae8 }, - { 0x0820, 0x610af0 }, - { 0x0824, 0x610b08 }, - { 0x0828, 0x610b10 }, - { 0x082c, 0x610a68 }, - { 0x0830, 0x610a60 }, - { 0x0834, 0x000000 }, - { 0x0838, 0x610a40 }, - { 0x0840, 0x610a24 }, - { 0x0844, 0x610a2c }, - { 0x0848, 0x610aa8 }, - { 0x084c, 0x610ab0 }, - { 0x0860, 0x610a84 }, - { 0x0864, 0x610a90 }, - { 0x0868, 0x610b18 }, - { 0x086c, 0x610b20 }, - { 0x0870, 0x610ac8 }, - { 0x0874, 0x610a38 }, - { 0x0880, 0x610a58 }, - { 0x0884, 0x610a9c }, - { 0x08a0, 0x610a70 }, - { 0x08a4, 0x610a50 }, - { 0x08a8, 0x610ae0 }, - { 0x08c0, 0x610b28 }, - { 0x08c4, 0x610b30 }, - { 0x08c8, 0x610b40 }, - { 0x08d4, 0x610b38 }, - { 0x08d8, 0x610b48 }, - { 0x08dc, 0x610b50 }, - { 0x0900, 0x610a18 }, - { 0x0904, 0x610ab8 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -nv50_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &nv50_disp_core_mthd_base }, - { "DAC", 3, &nv50_disp_core_mthd_dac }, - { "SOR", 2, &nv50_disp_core_mthd_sor }, - { "PIOR", 3, &nv50_disp_core_mthd_pior }, - { "HEAD", 2, &nv50_disp_core_mthd_head }, - {} - } -}; - -int -nv50_disp_core_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_core_channel_dma_v0 v0; - } *args = data; - struct nv50_disp_dmac *mast; - int ret; - - nv_ioctl(parent, "create disp core channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp core channel dma vers %d " - "pushbuf %08x\n", - args->v0.version, args->v0.pushbuf); - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - 0, sizeof(*mast), (void **)&mast); - *pobject = nv_object(mast); - if (ret) - return ret; - - return 0; + struct nv50_disp *disp = nv50_disp(base); + if (disp->func->outp.internal.dp) + return disp->func->outp.internal.dp(base, index, dcb, poutp); + return -ENODEV; } static int -nv50_disp_core_init(struct nvkm_object *object) +nv50_disp_outp_external_tmds_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, + struct nvkm_output **poutp) { - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - int ret; - - ret = nv50_disp_chan_init(&mast->base); - if (ret) - return ret; - - /* enable error reporting */ - nv_mask(priv, 0x610028, 0x00010000, 0x00010000); - - /* attempt to unstick channel from some unknown state */ - if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000) - nv_mask(priv, 0x610200, 0x00800000, 0x00800000); - if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000) - nv_mask(priv, 0x610200, 0x00600000, 0x00600000); - - /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610204, mast->push); - nv_wr32(priv, 0x610208, 0x00010000); - nv_wr32(priv, 0x61020c, 0x00000000); - nv_mask(priv, 0x610200, 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000, 0x00000000); - nv_wr32(priv, 0x610200, 0x01000013); - - /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) { - nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200)); - return -EBUSY; - } - - return 0; + struct nv50_disp *disp = nv50_disp(base); + if (disp->func->outp.external.tmds) + return disp->func->outp.external.tmds(base, index, dcb, poutp); + return -ENODEV; } static int -nv50_disp_core_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - - /* deactivate channel */ - nv_mask(priv, 0x610200, 0x00000010, 0x00000000); - nv_mask(priv, 0x610200, 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) { - nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200)); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notifications */ - nv_mask(priv, 0x610028, 0x00010001, 0x00000000); - - return nv50_disp_chan_fini(&mast->base, suspend); -} - -struct nv50_disp_chan_impl -nv50_disp_core_ofuncs = { - .base.ctor = nv50_disp_core_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_core_init, - .base.fini = nv50_disp_core_fini, - .base.map = nv50_disp_chan_map, - .base.ntfy = nv50_disp_chan_ntfy, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 0, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO sync channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -nv50_disp_base_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x0008c4 }, - { 0x0088, 0x0008d0 }, - { 0x008c, 0x0008dc }, - { 0x0090, 0x0008e4 }, - { 0x0094, 0x610884 }, - { 0x00a0, 0x6108a0 }, - { 0x00a4, 0x610878 }, - { 0x00c0, 0x61086c }, - { 0x00e0, 0x610858 }, - { 0x00e4, 0x610860 }, - { 0x00e8, 0x6108ac }, - { 0x00ec, 0x6108b4 }, - { 0x0100, 0x610894 }, - { 0x0110, 0x6108bc }, - { 0x0114, 0x61088c }, - {} - } -}; - -const struct nv50_disp_mthd_list -nv50_disp_base_mthd_image = { - .mthd = 0x0400, - .addr = 0x000000, - .data = { - { 0x0800, 0x6108f0 }, - { 0x0804, 0x6108fc }, - { 0x0808, 0x61090c }, - { 0x080c, 0x610914 }, - { 0x0810, 0x610904 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -nv50_disp_base_mthd_chan = { - .name = "Base", - .addr = 0x000540, - .data = { - { "Global", 1, &nv50_disp_base_mthd_base }, - { "Image", 2, &nv50_disp_base_mthd_image }, - {} - } -}; - -int -nv50_disp_base_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_disp_outp_external_dp_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, struct nvkm_output **poutp) { - union { - struct nv50_disp_base_channel_dma_v0 v0; - } *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - nv_ioctl(parent, "create disp base channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp base channel dma vers %d " - "pushbuf %08x head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > priv->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - args->v0.head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - return 0; + struct nv50_disp *disp = nv50_disp(base); + if (disp->func->outp.external.dp) + return disp->func->outp.external.dp(base, index, dcb, poutp); + return -ENODEV; } -struct nv50_disp_chan_impl -nv50_disp_base_ofuncs = { - .base.ctor = nv50_disp_base_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_dmac_init, - .base.fini = nv50_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 1, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -const struct nv50_disp_mthd_list -nv50_disp_ovly_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x0009a0 }, - { 0x0088, 0x0009c0 }, - { 0x008c, 0x0009c8 }, - { 0x0090, 0x6109b4 }, - { 0x0094, 0x610970 }, - { 0x00a0, 0x610998 }, - { 0x00a4, 0x610964 }, - { 0x00c0, 0x610958 }, - { 0x00e0, 0x6109a8 }, - { 0x00e4, 0x6109d0 }, - { 0x00e8, 0x6109d8 }, - { 0x0100, 0x61094c }, - { 0x0104, 0x610984 }, - { 0x0108, 0x61098c }, - { 0x0800, 0x6109f8 }, - { 0x0808, 0x610a08 }, - { 0x080c, 0x610a10 }, - { 0x0810, 0x610a00 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -nv50_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x000540, - .data = { - { "Global", 1, &nv50_disp_ovly_mthd_base }, - {} - } -}; - -int -nv50_disp_ovly_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_overlay_channel_dma_v0 v0; - } *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - nv_ioctl(parent, "create disp overlay channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp overlay channel dma vers %d " - "pushbuf %08x head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > priv->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - args->v0.head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - return 0; -} - -struct nv50_disp_chan_impl -nv50_disp_ovly_ofuncs = { - .base.ctor = nv50_disp_ovly_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_dmac_init, - .base.fini = nv50_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 3, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO PIO channel base class - ******************************************************************************/ - -static int -nv50_disp_pioc_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int head, - int length, void **pobject) -{ - return nv50_disp_chan_create_(parent, engine, oclass, head, - length, pobject); -} - -void -nv50_disp_pioc_dtor(struct nvkm_object *object) -{ - struct nv50_disp_pioc *pioc = (void *)object; - nv50_disp_chan_destroy(&pioc->base); -} - -static int -nv50_disp_pioc_init(struct nvkm_object *object) +static void +nv50_disp_vblank_fini_(struct nvkm_disp *base, int head) { - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - int chid = pioc->base.chid; - int ret; - - ret = nv50_disp_chan_init(&pioc->base); - if (ret) - return ret; - - nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) { - nv_error(pioc, "timeout0: 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); - return -EBUSY; - } - - nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) { - nv_error(pioc, "timeout1: 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); - return -EBUSY; - } - - return 0; + struct nv50_disp *disp = nv50_disp(base); + disp->func->head.vblank_fini(disp, head); } -static int -nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) +static void +nv50_disp_vblank_init_(struct nvkm_disp *base, int head) { - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - int chid = pioc->base.chid; - - nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) { - nv_error(pioc, "timeout: 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - return nv50_disp_chan_fini(&pioc->base, suspend); + struct nv50_disp *disp = nv50_disp(base); + disp->func->head.vblank_init(disp, head); } -/******************************************************************************* - * EVO immediate overlay channel objects - ******************************************************************************/ - -int -nv50_disp_oimm_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void +nv50_disp_intr_(struct nvkm_disp *base) { - union { - struct nv50_disp_overlay_v0 v0; - } *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; - - nv_ioctl(parent, "create disp overlay size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp overlay vers %d head %d\n", - args->v0.version, args->v0.head); - if (args->v0.head > priv->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; + struct nv50_disp *disp = nv50_disp(base); + disp->func->intr(disp); } -struct nv50_disp_chan_impl -nv50_disp_oimm_ofuncs = { - .base.ctor = nv50_disp_oimm_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = nv50_disp_pioc_init, - .base.fini = nv50_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 5, -}; - -/******************************************************************************* - * EVO cursor channel objects - ******************************************************************************/ - -int -nv50_disp_curs_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void * +nv50_disp_dtor_(struct nvkm_disp *base) { - union { - struct nv50_disp_cursor_v0 v0; - } *args = data; - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; - - nv_ioctl(parent, "create disp cursor size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp cursor vers %d head %d\n", - args->v0.version, args->v0.head); - if (args->v0.head > priv->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; + struct nv50_disp *disp = nv50_disp(base); + nvkm_event_fini(&disp->uevent); + return disp; } -struct nv50_disp_chan_impl -nv50_disp_curs_ofuncs = { - .base.ctor = nv50_disp_curs_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = nv50_disp_pioc_init, - .base.fini = nv50_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 7, +static const struct nvkm_disp_func +nv50_disp_ = { + .dtor = nv50_disp_dtor_, + .intr = nv50_disp_intr_, + .root = nv50_disp_root_, + .outp.internal.crt = nv50_disp_outp_internal_crt_, + .outp.internal.tmds = nv50_disp_outp_internal_tmds_, + .outp.internal.lvds = nv50_disp_outp_internal_lvds_, + .outp.internal.dp = nv50_disp_outp_internal_dp_, + .outp.external.tmds = nv50_disp_outp_external_tmds_, + .outp.external.dp = nv50_disp_outp_external_dp_, + .head.vblank_init = nv50_disp_vblank_init_, + .head.vblank_fini = nv50_disp_vblank_fini_, }; -/******************************************************************************* - * Base display object - ******************************************************************************/ - int -nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0) +nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, + int index, int heads, struct nvkm_disp **pdisp) { - const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540)); - const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540)); - const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540)); - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; + struct nv50_disp *disp; int ret; - nv_ioctl(object, "disp scanoutpos size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); - args->v0.vblanke = (blanke & 0xffff0000) >> 16; - args->v0.hblanke = (blanke & 0x0000ffff); - args->v0.vblanks = (blanks & 0xffff0000) >> 16; - args->v0.hblanks = (blanks & 0x0000ffff); - args->v0.vtotal = ( total & 0xffff0000) >> 16; - args->v0.htotal = ( total & 0x0000ffff); - args->v0.time[0] = ktime_to_ns(ktime_get()); - args->v0.vline = /* vline read locks hline */ - nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = - nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; - } else - return ret; - - return 0; -} - -int -nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); - union { - struct nv50_disp_mthd_v0 v0; - struct nv50_disp_mthd_v1 v1; - } *args = data; - struct nv50_disp_priv *priv = (void *)object->engine; - struct nvkm_output *outp = NULL; - struct nvkm_output *temp; - u16 type, mask = 0; - int head, ret; - - if (mthd != NV50_DISP_MTHD) - return -EINVAL; - - nv_ioctl(object, "disp mthd size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); - mthd = args->v0.method; - head = args->v0.head; - } else - if (nvif_unpack(args->v1, 1, 1, true)) { - nv_ioctl(object, "disp mthd vers %d mthd %02x " - "type %04x mask %04x\n", - args->v1.version, args->v1.method, - args->v1.hasht, args->v1.hashm); - mthd = args->v1.method; - type = args->v1.hasht; - mask = args->v1.hashm; - head = ffs((mask >> 8) & 0x0f) - 1; - } else - return ret; - - if (head < 0 || head >= priv->head.nr) - return -ENXIO; - - if (mask) { - list_for_each_entry(temp, &priv->base.outp, head) { - if ((temp->info.hasht == type) && - (temp->info.hashm & mask) == mask) { - outp = temp; - break; - } - } - if (outp == NULL) - return -ENXIO; - } - - switch (mthd) { - case NV50_DISP_SCANOUTPOS: - return impl->head.scanoutpos(object, priv, data, size, head); - default: - break; - } - - switch (mthd * !!outp) { - case NV50_DISP_MTHD_V1_DAC_PWR: - return priv->dac.power(object, priv, data, size, head, outp); - case NV50_DISP_MTHD_V1_DAC_LOAD: - return priv->dac.sense(object, priv, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_PWR: - return priv->sor.power(object, priv, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_HDA_ELD: - if (!priv->sor.hda_eld) - return -ENODEV; - return priv->sor.hda_eld(object, priv, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: - if (!priv->sor.hdmi) - return -ENODEV; - return priv->sor.hdmi(object, priv, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { - union { - struct nv50_disp_sor_lvds_script_v0 v0; - } *args = data; - nv_ioctl(object, "disp sor lvds script size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor lvds script " - "vers %d name %04x\n", - args->v0.version, args->v0.script); - priv->sor.lvdsconf = args->v0.script; - return 0; - } else - return ret; - } - break; - case NV50_DISP_MTHD_V1_SOR_DP_PWR: { - struct nvkm_output_dp *outpdp = (void *)outp; - union { - struct nv50_disp_sor_dp_pwr_v0 v0; - } *args = data; - nv_ioctl(object, "disp sor dp pwr size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor dp pwr vers %d state %d\n", - args->v0.version, args->v0.state); - if (args->v0.state == 0) { - nvkm_notify_put(&outpdp->irq); - ((struct nvkm_output_dp_impl *)nv_oclass(outp)) - ->lnk_pwr(outpdp, 0); - atomic_set(&outpdp->lt.done, 0); - return 0; - } else - if (args->v0.state != 0) { - nvkm_output_dp_train(&outpdp->base, 0, true); - return 0; - } - } else - return ret; - } - break; - case NV50_DISP_MTHD_V1_PIOR_PWR: - if (!priv->pior.power) - return -ENODEV; - return priv->pior.power(object, priv, data, size, head, outp); - default: - break; - } - - return -EINVAL; -} - -int -nv50_disp_main_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_disp_priv *priv = (void *)engine; - struct nv50_disp_base *base; - int ret; + if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL))) + return -ENOMEM; + INIT_WORK(&disp->supervisor, func->super); + disp->func = func; + *pdisp = &disp->base; - ret = nvkm_parent_create(parent, engine, oclass, 0, - priv->sclass, 0, &base); - *pobject = nv_object(base); + ret = nvkm_disp_ctor(&nv50_disp_, device, index, heads, &disp->base); if (ret) return ret; - return nvkm_ramht_new(nv_object(base), nv_object(base), 0x1000, 0, - &base->ramht); + return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); } void -nv50_disp_main_dtor(struct nvkm_object *object) -{ - struct nv50_disp_base *base = (void *)object; - nvkm_ramht_ref(NULL, &base->ramht); - nvkm_parent_destroy(&base->base); -} - -static int -nv50_disp_main_init(struct nvkm_object *object) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - int ret, i; - u32 tmp; - - ret = nvkm_parent_init(&base->base); - if (ret) - return ret; - - /* The below segments of code copying values from one register to - * another appear to inform EVO of the display capabilities or - * something similar. NFI what the 0x614004 caps are for.. - */ - tmp = nv_rd32(priv, 0x614004); - nv_wr32(priv, 0x610184, tmp); - - /* ... CRTC caps */ - for (i = 0; i < priv->head.nr; i++) { - tmp = nv_rd32(priv, 0x616100 + (i * 0x800)); - nv_wr32(priv, 0x610190 + (i * 0x10), tmp); - tmp = nv_rd32(priv, 0x616104 + (i * 0x800)); - nv_wr32(priv, 0x610194 + (i * 0x10), tmp); - tmp = nv_rd32(priv, 0x616108 + (i * 0x800)); - nv_wr32(priv, 0x610198 + (i * 0x10), tmp); - tmp = nv_rd32(priv, 0x61610c + (i * 0x800)); - nv_wr32(priv, 0x61019c + (i * 0x10), tmp); - } - - /* ... DAC caps */ - for (i = 0; i < priv->dac.nr; i++) { - tmp = nv_rd32(priv, 0x61a000 + (i * 0x800)); - nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp); - } - - /* ... SOR caps */ - for (i = 0; i < priv->sor.nr; i++) { - tmp = nv_rd32(priv, 0x61c000 + (i * 0x800)); - nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp); - } - - /* ... PIOR caps */ - for (i = 0; i < priv->pior.nr; i++) { - tmp = nv_rd32(priv, 0x61e000 + (i * 0x800)); - nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp); - } - - /* steal display away from vbios, or something like that */ - if (nv_rd32(priv, 0x610024) & 0x00000100) { - nv_wr32(priv, 0x610024, 0x00000100); - nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) { - nv_error(priv, "timeout acquiring display\n"); - return -EBUSY; - } - } - - /* point at display engine memory area (hash table, objects) */ - nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); - - /* enable supervisor interrupts, disable everything else */ - nv_wr32(priv, 0x61002c, 0x00000370); - nv_wr32(priv, 0x610028, 0x00000000); - return 0; -} - -static int -nv50_disp_main_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp_priv *priv = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - - /* disable all interrupts */ - nv_wr32(priv, 0x610024, 0x00000000); - nv_wr32(priv, 0x610020, 0x00000000); - - return nvkm_parent_fini(&base->base, suspend); -} - -struct nvkm_ofuncs -nv50_disp_main_ofuncs = { - .ctor = nv50_disp_main_ctor, - .dtor = nv50_disp_main_dtor, - .init = nv50_disp_main_init, - .fini = nv50_disp_main_fini, - .mthd = nv50_disp_main_mthd, - .ntfy = nvkm_disp_ntfy, -}; - -static struct nvkm_oclass -nv50_disp_main_oclass[] = { - { NV50_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -static struct nvkm_oclass -nv50_disp_sclass[] = { - { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -/******************************************************************************* - * Display context, tracks instmem allocation and prevents more than one - * client using the display hardware at any time. - ******************************************************************************/ - -static int -nv50_disp_data_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_disp_priv *priv = (void *)engine; - struct nvkm_engctx *ectx; - int ret = -EBUSY; - - /* no context needed for channel objects... */ - if (nv_mclass(parent) != NV_DEVICE) { - atomic_inc(&parent->refcount); - *pobject = parent; - return 1; - } - - /* allocate display hardware to client */ - mutex_lock(&nv_subdev(priv)->mutex); - if (list_empty(&nv_engine(priv)->contexts)) { - ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, - 0x10000, NVOBJ_FLAG_HEAP, &ectx); - *pobject = nv_object(ectx); - } - mutex_unlock(&nv_subdev(priv)->mutex); - return ret; -} - -struct nvkm_oclass -nv50_disp_cclass = { - .handle = NV_ENGCTX(DISP, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_disp_data_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, - }, -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static void -nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) +nv50_disp_vblank_fini(struct nv50_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x61002c, (4 << head), 0); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head), 0); } -static void -nv50_disp_vblank_init(struct nvkm_event *event, int type, int head) +void +nv50_disp_vblank_init(struct nv50_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x61002c, (4 << head), (4 << head)); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head), (4 << head)); } -const struct nvkm_event_func -nv50_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, - .init = nv50_disp_vblank_init, - .fini = nv50_disp_vblank_fini, -}; - static const struct nvkm_enum nv50_disp_intr_error_type[] = { { 3, "ILLEGAL_MTHD" }, @@ -1323,70 +190,46 @@ nv50_disp_intr_error_code[] = { }; static void -nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) +nv50_disp_intr_error(struct nv50_disp *disp, int chid) { - struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; - u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08)); - u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08)); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08)); + u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08)); u32 code = (addr & 0x00ff0000) >> 16; u32 type = (addr & 0x00007000) >> 12; u32 mthd = (addr & 0x00000ffc); const struct nvkm_enum *ec, *et; - char ecunk[6], etunk[6]; et = nvkm_enum_find(nv50_disp_intr_error_type, type); - if (!et) - snprintf(etunk, sizeof(etunk), "UNK%02X", type); - ec = nvkm_enum_find(nv50_disp_intr_error_code, code); - if (!ec) - snprintf(ecunk, sizeof(ecunk), "UNK%02X", code); - nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n", - et ? et->name : etunk, ec ? ec->name : ecunk, - chid, mthd, data); + nvkm_error(subdev, + "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n", + type, et ? et->name : "", code, ec ? ec->name : "", + chid, mthd, data); - if (chid == 0) { - switch (mthd) { - case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, - impl->mthd.core); - break; - default: - break; - } - } else - if (chid <= 2) { - switch (mthd) { - case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, - impl->mthd.base); - break; - default: - break; - } - } else - if (chid <= 4) { + if (chid < ARRAY_SIZE(disp->chan)) { switch (mthd) { case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3, - impl->mthd.ovly); + nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); break; default: break; } } - nv_wr32(priv, 0x610020, 0x00010000 << chid); - nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); + nvkm_wr32(device, 0x610020, 0x00010000 << chid); + nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000); } static struct nvkm_output * -exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, +exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvkm_output *outp; u16 mask, type; @@ -1403,7 +246,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; default: - nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); + nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); return NULL; } or -= 4; @@ -1412,9 +255,9 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, type = 0x0010; mask = 0; switch (ctrl & 0x00000f00) { - case 0x00000000: type |= priv->pior.type[or]; break; + case 0x00000000: type |= disp->pior.type[or]; break; default: - nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl); + nvkm_error(subdev, "unknown PIOR mc %08x\n", ctrl); return NULL; } } @@ -1423,7 +266,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, mask |= 0x0001 << or; mask |= 0x0100 << head; - list_for_each_entry(outp, &priv->base.outp, head) { + list_for_each_entry(outp, &disp->base.outp, head) { if ((outp->info.hasht & 0xff) == type && (outp->info.hashm & mask) == mask) { *data = nvbios_outp_match(bios, outp->info.hasht, @@ -1439,9 +282,11 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, } static struct nvkm_output * -exec_script(struct nv50_disp_priv *priv, int head, int id) +exec_script(struct nv50_disp *disp, int head, int id) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info; u8 ver, hdr, cnt, len; @@ -1450,27 +295,27 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) int i; /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) - ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++) + ctrl = nvkm_rd32(device, 0x610b5c + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { - if (nv_device(priv)->chipset < 0x90 || - nv_device(priv)->chipset == 0x92 || - nv_device(priv)->chipset == 0xa0) { + if (device->chipset < 0x90 || + device->chipset == 0x92 || + device->chipset == 0xa0) { reg = 0x610b74; } else { reg = 0x610798; } - for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) - ctrl = nv_rd32(priv, reg + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++) + ctrl = nvkm_rd32(device, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) - ctrl = nv_rd32(priv, 0x610b84 + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) + ctrl = nvkm_rd32(device, 0x610b84 + (i * 8)); i += 8; } @@ -1478,10 +323,10 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) return NULL; i--; - outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); + outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); if (outp) { struct nvbios_init init = { - .subdev = nv_subdev(priv), + .subdev = subdev, .bios = bios, .offset = info.script[id], .outp = &outp->info, @@ -1496,9 +341,11 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) } static struct nvkm_output * -exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) +exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info1; struct nvbios_ocfg info2; @@ -1508,27 +355,27 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) int i; /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) - ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++) + ctrl = nvkm_rd32(device, 0x610b58 + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { - if (nv_device(priv)->chipset < 0x90 || - nv_device(priv)->chipset == 0x92 || - nv_device(priv)->chipset == 0xa0) { + if (device->chipset < 0x90 || + device->chipset == 0x92 || + device->chipset == 0xa0) { reg = 0x610b70; } else { reg = 0x610794; } - for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) - ctrl = nv_rd32(priv, reg + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++) + ctrl = nvkm_rd32(device, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) - ctrl = nv_rd32(priv, 0x610b80 + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) + ctrl = nvkm_rd32(device, 0x610b80 + (i * 8)); i += 8; } @@ -1536,7 +383,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) return NULL; i--; - outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); + outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); if (!outp) return NULL; @@ -1548,7 +395,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) *conf |= 0x0100; break; case DCB_OUTPUT_LVDS: - *conf = priv->sor.lvdsconf; + *conf = disp->sor.lvdsconf; break; case DCB_OUTPUT_DP: *conf = (ctrl & 0x00000f00) >> 8; @@ -1568,7 +415,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { - .subdev = nv_subdev(priv), + .subdev = subdev, .bios = bios, .offset = data, .outp = &outp->info, @@ -1584,15 +431,16 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) } static void -nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) { - exec_script(priv, head, 1); + exec_script(disp, head, 1); } static void -nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) { - struct nvkm_output *outp = exec_script(priv, head, 2); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_output *outp = exec_script(disp, head, 2); /* the binary driver does this outside of the supervisor handling * (after the third supervisor from a detach). we (currently?) @@ -1608,10 +456,10 @@ nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) * in a blank screen (SOR_PWR off/on can restore it) */ if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = (void *)outp; + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); struct nvbios_init init = { - .subdev = nv_subdev(priv), - .bios = nvkm_bios(priv), + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->info, .crtc = head, .offset = outpdp->info.script[4], @@ -1624,29 +472,32 @@ nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) } static void -nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) { - struct nvkm_devinit *devinit = nvkm_devinit(priv); - u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_devinit *devinit = device->devinit; + u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; if (pclk) - devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); + nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); } static void -nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, +nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, struct dcb_output *outp, u32 pclk) { + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; const int link = !(outp->sorconf.link & 1); const int or = ffs(outp->or) - 1; const u32 soff = ( or * 0x800); const u32 loff = (link * 0x080) + soff; - const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8)); + const u32 ctrl = nvkm_rd32(device, 0x610794 + (or * 8)); const u32 symbol = 100000; - const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff; - const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff; - const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff; - u32 dpctrl = nv_rd32(priv, 0x61c10c + loff); - u32 clksor = nv_rd32(priv, 0x614300 + soff); + const s32 vactive = nvkm_rd32(device, 0x610af8 + (head * 0x540)) & 0xffff; + const s32 vblanke = nvkm_rd32(device, 0x610ae8 + (head * 0x540)) & 0xffff; + const s32 vblanks = nvkm_rd32(device, 0x610af0 + (head * 0x540)) & 0xffff; + u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); + u32 clksor = nvkm_rd32(device, 0x614300 + soff); int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; int TU, VTUi, VTUf, VTUa; u64 link_data_rate, link_ratio, unk; @@ -1662,14 +513,14 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, value = value * link_bw; do_div(value, pclk); value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value); + nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, value); /* symbols/vblank - algorithm taken from comments in tegra driver */ value = vblanks - vblanke - 25; value = value * link_bw; do_div(value, pclk); value = value - ((36 / link_nr) + 3) - 1; - nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value); + nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, value); /* watermark / activesym */ if ((ctrl & 0xf0000) == 0x60000) bits = 30; @@ -1734,7 +585,7 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, } if (!bestTU) { - nv_error(priv, "unable to find suitable dp config\n"); + nvkm_error(subdev, "unable to find suitable dp config\n"); return; } @@ -1745,22 +596,23 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, do_div(unk, symbol); unk += 6; - nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2); - nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | + nvkm_mask(device, 0x61c10c + loff, 0x000001fc, bestTU << 2); + nvkm_mask(device, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | bestVTUf << 16 | bestVTUi << 8 | unk); } static void -nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) { + struct nvkm_device *device = disp->base.engine.subdev.device; struct nvkm_output *outp; - u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; + u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 hval, hreg = 0x614200 + (head * 0x800); u32 oval, oreg; u32 mask, conf; - outp = exec_clkcmp(priv, head, 0xff, pclk, &conf); + outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); if (!outp) return; @@ -1787,10 +639,10 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) u32 ctrl, datarate; if (outp->info.location == 0) { - ctrl = nv_rd32(priv, 0x610794 + soff); + ctrl = nvkm_rd32(device, 0x610794 + soff); soff = 1; } else { - ctrl = nv_rd32(priv, 0x610b80 + soff); + ctrl = nvkm_rd32(device, 0x610b80 + soff); soff = 2; } @@ -1804,10 +656,10 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) } if (nvkm_output_dp_train(outp, datarate / soff, true)) - ERR("link not trained before attach\n"); + OUTP_ERR(outp, "link not trained before attach"); } - exec_clkcmp(priv, head, 0, pclk, &conf); + exec_clkcmp(disp, head, 0, pclk, &conf); if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) { oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800; @@ -1817,7 +669,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) } else if (!outp->info.location) { if (outp->info.type == DCB_OUTPUT_DP) - nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk); + nv50_disp_intr_unk20_2_dp(disp, head, &outp->info, pclk); oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800; oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; hval = 0x00000000; @@ -1829,8 +681,8 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) mask = 0x00000707; } - nv_mask(priv, hreg, 0x0000000f, hval); - nv_mask(priv, oreg, mask, oval); + nvkm_mask(device, hreg, 0x0000000f, hval); + nvkm_mask(device, oreg, mask, oval); } /* If programming a TMDS output on a SOR that can also be configured for @@ -1842,10 +694,11 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) * programmed for DisplayPort. */ static void -nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, +nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, struct dcb_output *outp) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; const int link = !(outp->sorconf.link & 1); const int or = ffs(outp->or) - 1; const u32 loff = (or * 0x800) + (link * 0x80); @@ -1854,166 +707,136 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, u8 ver, hdr; if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) - nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000); } static void -nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) { + struct nvkm_device *device = disp->base.engine.subdev.device; struct nvkm_output *outp; - u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; + u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 conf; - outp = exec_clkcmp(priv, head, 1, pclk, &conf); + outp = exec_clkcmp(disp, head, 1, pclk, &conf); if (!outp) return; if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) - nv50_disp_intr_unk40_0_tmds(priv, &outp->info); + nv50_disp_intr_unk40_0_tmds(disp, &outp->info); } void nv50_disp_intr_supervisor(struct work_struct *work) { - struct nv50_disp_priv *priv = - container_of(work, struct nv50_disp_priv, supervisor); - struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; - u32 super = nv_rd32(priv, 0x610030); + struct nv50_disp *disp = + container_of(work, struct nv50_disp, supervisor); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 super = nvkm_rd32(device, 0x610030); int head; - nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super); + nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super); - if (priv->super & 0x00000010) { - nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000010) { + nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000020 << head))) continue; if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk10_0(priv, head); + nv50_disp_intr_unk10_0(disp, head); } } else - if (priv->super & 0x00000020) { - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000020) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk20_0(priv, head); + nv50_disp_intr_unk20_0(disp, head); } - for (head = 0; head < priv->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000200 << head))) continue; - nv50_disp_intr_unk20_1(priv, head); + nv50_disp_intr_unk20_1(disp, head); } - for (head = 0; head < priv->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk20_2(priv, head); + nv50_disp_intr_unk20_2(disp, head); } } else - if (priv->super & 0x00000040) { - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000040) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk40_0(priv, head); + nv50_disp_intr_unk40_0(disp, head); } } - nv_wr32(priv, 0x610030, 0x80000000); + nvkm_wr32(device, 0x610030, 0x80000000); } void -nv50_disp_intr(struct nvkm_subdev *subdev) +nv50_disp_intr(struct nv50_disp *disp) { - struct nv50_disp_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0x610020); - u32 intr1 = nv_rd32(priv, 0x610024); + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 intr0 = nvkm_rd32(device, 0x610020); + u32 intr1 = nvkm_rd32(device, 0x610024); while (intr0 & 0x001f0000) { u32 chid = __ffs(intr0 & 0x001f0000) - 16; - nv50_disp_intr_error(priv, chid); + nv50_disp_intr_error(disp, chid); intr0 &= ~(0x00010000 << chid); } while (intr0 & 0x0000001f) { u32 chid = __ffs(intr0 & 0x0000001f); - nv50_disp_chan_uevent_send(priv, chid); + nv50_disp_chan_uevent_send(disp, chid); intr0 &= ~(0x00000001 << chid); } if (intr1 & 0x00000004) { - nvkm_disp_vblank(&priv->base, 0); - nv_wr32(priv, 0x610024, 0x00000004); - intr1 &= ~0x00000004; + nvkm_disp_vblank(&disp->base, 0); + nvkm_wr32(device, 0x610024, 0x00000004); } if (intr1 & 0x00000008) { - nvkm_disp_vblank(&priv->base, 1); - nv_wr32(priv, 0x610024, 0x00000008); - intr1 &= ~0x00000008; + nvkm_disp_vblank(&disp->base, 1); + nvkm_wr32(device, 0x610024, 0x00000008); } if (intr1 & 0x00000070) { - priv->super = (intr1 & 0x00000070); - schedule_work(&priv->supervisor); - nv_wr32(priv, 0x610024, priv->super); - intr1 &= ~0x00000070; - } -} + disp->super = (intr1 & 0x00000070); + schedule_work(&disp->supervisor); + nvkm_wr32(device, 0x610024, disp->super); + } +} + +static const struct nv50_disp_func +nv50_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, + .root = &nv50_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 2, + .sor.power = nv50_sor_power, + .pior.nr = 3, + .pior.power = nv50_pior_power, +}; -static int -nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp_priv *priv; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); - if (ret) - return ret; - - nv_engine(priv)->sclass = nv50_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = nv50_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 2; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(&nv50_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -nv50_disp_outp_sclass[] = { - &nv50_pior_dp_impl.base.base, - NULL -}; - -struct nvkm_oclass * -nv50_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x50), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, - .mthd.core = &nv50_disp_core_mthd_chan, - .mthd.base = &nv50_disp_base_mthd_chan, - .mthd.ovly = &nv50_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index b4ed620070fa..aecebd8717e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -1,17 +1,18 @@ #ifndef __NV50_DISP_H__ #define __NV50_DISP_H__ +#define nv50_disp(p) container_of((p), struct nv50_disp, base) #include "priv.h" struct nvkm_output; struct nvkm_output_dp; #define NV50_DISP_MTHD_ struct nvkm_object *object, \ - struct nv50_disp_priv *priv, void *data, u32 size + struct nv50_disp *disp, void *data, u32 size #define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head #define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp -struct nv50_disp_priv { +struct nv50_disp { + const struct nv50_disp_func *func; struct nvkm_disp base; - struct nvkm_oclass *sclass; struct work_struct supervisor; u32 super; @@ -19,208 +20,98 @@ struct nv50_disp_priv { struct nvkm_event uevent; struct { - int nr; - } head; - struct { - int nr; - int (*power)(NV50_DISP_MTHD_V1); - int (*sense)(NV50_DISP_MTHD_V1); - } dac; - struct { - int nr; - int (*power)(NV50_DISP_MTHD_V1); - int (*hda_eld)(NV50_DISP_MTHD_V1); - int (*hdmi)(NV50_DISP_MTHD_V1); u32 lvdsconf; - void (*magic)(struct nvkm_output *); } sor; + struct { - int nr; - int (*power)(NV50_DISP_MTHD_V1); u8 type[3]; } pior; -}; -struct nv50_disp_impl { - struct nvkm_disp_impl base; - struct { - const struct nv50_disp_mthd_chan *core; - const struct nv50_disp_mthd_chan *base; - const struct nv50_disp_mthd_chan *ovly; - int prev; - } mthd; - struct { - int (*scanoutpos)(NV50_DISP_MTHD_V0); - } head; + struct nv50_disp_chan *chan[17]; }; -int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0); -int nv50_disp_main_mthd(struct nvkm_object *, u32, void *, u32); +int nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0); -int gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0); +int gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0); int nv50_dac_power(NV50_DISP_MTHD_V1); int nv50_dac_sense(NV50_DISP_MTHD_V1); int gt215_hda_eld(NV50_DISP_MTHD_V1); -int gf110_hda_eld(NV50_DISP_MTHD_V1); +int gf119_hda_eld(NV50_DISP_MTHD_V1); int g84_hdmi_ctrl(NV50_DISP_MTHD_V1); int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1); -int gf110_hdmi_ctrl(NV50_DISP_MTHD_V1); +int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1); int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1); int nv50_sor_power(NV50_DISP_MTHD_V1); int nv50_pior_power(NV50_DISP_MTHD_V1); -#include <core/parent.h> - -struct nv50_disp_base { - struct nvkm_parent base; - struct nvkm_ramht *ramht; - u32 chan; -}; - -struct nv50_disp_chan_impl { - struct nvkm_ofuncs base; - int chid; - int (*attach)(struct nvkm_object *, struct nvkm_object *, u32); - void (*detach)(struct nvkm_object *, int); +int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, + int index, int heads, struct nvkm_disp **); +int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, + int index, struct nvkm_disp **); + +struct nv50_disp_func_outp { + int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* tv)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* dp)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); }; -#include <core/namedb.h> +struct nv50_disp_func { + void (*intr)(struct nv50_disp *); -struct nv50_disp_chan { - struct nvkm_namedb base; - int chid; -}; + const struct nvkm_event_func *uevent; + void (*super)(struct work_struct *); -int nv50_disp_chan_ntfy(struct nvkm_object *, u32, struct nvkm_event **); -int nv50_disp_chan_map(struct nvkm_object *, u64 *, u32 *); -u32 nv50_disp_chan_rd32(struct nvkm_object *, u64); -void nv50_disp_chan_wr32(struct nvkm_object *, u64, u32); -extern const struct nvkm_event_func nv50_disp_chan_uevent; -int nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32, - struct nvkm_notify *); -void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int); - -extern const struct nvkm_event_func gf110_disp_chan_uevent; - -#define nv50_disp_chan_init(a) \ - nvkm_namedb_init(&(a)->base) -#define nv50_disp_chan_fini(a,b) \ - nvkm_namedb_fini(&(a)->base, (b)) - -struct nv50_disp_dmac { - struct nv50_disp_chan base; - struct nvkm_dmaobj *pushdma; - u32 push; -}; + const struct nvkm_disp_oclass *root; -void nv50_disp_dmac_dtor(struct nvkm_object *); + struct { + void (*vblank_init)(struct nv50_disp *, int head); + void (*vblank_fini)(struct nv50_disp *, int head); + int (*scanoutpos)(NV50_DISP_MTHD_V0); + } head; -struct nv50_disp_pioc { - struct nv50_disp_chan base; -}; + struct { + const struct nv50_disp_func_outp internal; + const struct nv50_disp_func_outp external; + } outp; -void nv50_disp_pioc_dtor(struct nvkm_object *); + struct { + int nr; + int (*power)(NV50_DISP_MTHD_V1); + int (*sense)(NV50_DISP_MTHD_V1); + } dac; -struct nv50_disp_mthd_list { - u32 mthd; - u32 addr; struct { - u32 mthd; - u32 addr; - const char *name; - } data[]; -}; + int nr; + int (*power)(NV50_DISP_MTHD_V1); + int (*hda_eld)(NV50_DISP_MTHD_V1); + int (*hdmi)(NV50_DISP_MTHD_V1); + void (*magic)(struct nvkm_output *); + } sor; -struct nv50_disp_mthd_chan { - const char *name; - u32 addr; struct { - const char *name; int nr; - const struct nv50_disp_mthd_list *mthd; - } data[]; + int (*power)(NV50_DISP_MTHD_V1); + } pior; }; -extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs; -int nv50_disp_core_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base; -extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor; -extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior; -extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs; -int nv50_disp_base_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image; -extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs; -int nv50_disp_ovly_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; -extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs; -int nv50_disp_oimm_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs; -int nv50_disp_curs_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern struct nvkm_ofuncs nv50_disp_main_ofuncs; -int nv50_disp_main_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv50_disp_main_dtor(struct nvkm_object *); -extern struct nvkm_omthds nv50_disp_main_omthds[]; -extern struct nvkm_oclass nv50_disp_cclass; -void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head, - const struct nv50_disp_mthd_chan *); +void nv50_disp_vblank_init(struct nv50_disp *, int); +void nv50_disp_vblank_fini(struct nv50_disp *, int); +void nv50_disp_intr(struct nv50_disp *); void nv50_disp_intr_supervisor(struct work_struct *); -void nv50_disp_intr(struct nvkm_subdev *); -extern const struct nvkm_event_func nv50_disp_vblank_func; - -extern const struct nv50_disp_mthd_chan g84_disp_core_mthd_chan; -extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac; -extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head; -extern const struct nv50_disp_mthd_chan g84_disp_base_mthd_chan; -extern const struct nv50_disp_mthd_chan g84_disp_ovly_mthd_chan; - -extern const struct nv50_disp_mthd_chan g94_disp_core_mthd_chan; - -extern struct nv50_disp_chan_impl gf110_disp_core_ofuncs; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_base; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_dac; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_sor; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_pior; -extern struct nv50_disp_chan_impl gf110_disp_base_ofuncs; -extern struct nv50_disp_chan_impl gf110_disp_ovly_ofuncs; -extern const struct nv50_disp_mthd_chan gf110_disp_base_mthd_chan; -extern struct nv50_disp_chan_impl gf110_disp_oimm_ofuncs; -extern struct nv50_disp_chan_impl gf110_disp_curs_ofuncs; -extern struct nvkm_ofuncs gf110_disp_main_ofuncs; -extern struct nvkm_oclass gf110_disp_cclass; -void gf110_disp_intr_supervisor(struct work_struct *); -void gf110_disp_intr(struct nvkm_subdev *); -extern const struct nvkm_event_func gf110_disp_vblank_func; - -extern const struct nv50_disp_mthd_chan gk104_disp_core_mthd_chan; -extern const struct nv50_disp_mthd_chan gk104_disp_ovly_mthd_chan; - -extern struct nvkm_output_dp_impl nv50_pior_dp_impl; -extern struct nvkm_oclass *nv50_disp_outp_sclass[]; - -extern struct nvkm_output_dp_impl g94_sor_dp_impl; -int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); -extern struct nvkm_oclass *g94_disp_outp_sclass[]; - -extern struct nvkm_output_dp_impl gf110_sor_dp_impl; -int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); -extern struct nvkm_oclass *gf110_disp_outp_sclass[]; - -void gm204_sor_magic(struct nvkm_output *outp); -extern struct nvkm_output_dp_impl gm204_sor_dp_impl; + +void gf119_disp_vblank_init(struct nv50_disp *, int); +void gf119_disp_vblank_fini(struct nv50_disp *, int); +void gf119_disp_intr(struct nv50_disp *); +void gf119_disp_intr_supervisor(struct work_struct *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c new file mode 100644 index 000000000000..54a4ae8d66c6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c @@ -0,0 +1,37 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +g84_disp_oimm_oclass = { + .base.oclass = G82_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c new file mode 100644 index 000000000000..c658db54afc5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c @@ -0,0 +1,37 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +gf119_disp_oimm_oclass = { + .base.oclass = GF110_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &gf119_disp_pioc_func, + .chid = 9, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c new file mode 100644 index 000000000000..b1fde8c125d6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c @@ -0,0 +1,37 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +gk104_disp_oimm_oclass = { + .base.oclass = GK104_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &gf119_disp_pioc_func, + .chid = 9, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c new file mode 100644 index 000000000000..f4e7eb3d1177 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c @@ -0,0 +1,37 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_pioc_oclass +gt215_disp_oimm_oclass = { + .base.oclass = GT214_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c new file mode 100644 index 000000000000..cd888a1e443c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include <core/client.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +int +nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_overlay_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; + + nvif_ioctl(parent, "create disp overlay size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp overlay vers %d head %d\n", + args->v0.version, args->v0.head); + if (args->v0.head > disp->base.head.nr) + return -EINVAL; + head = args->v0.head; + } else + return ret; + + return nv50_disp_chan_new_(func, mthd, root, chid + head, + head, oclass, pobject); +} + +const struct nv50_disp_pioc_oclass +nv50_disp_oimm_oclass = { + .base.oclass = NV50_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 9224bcbf0159..bbe5ec0dedb2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,121 +22,66 @@ * Authors: Ben Skeggs */ #include "outp.h" -#include "priv.h" #include <subdev/bios.h> -#include <subdev/bios/conn.h> #include <subdev/bios/dcb.h> #include <subdev/i2c.h> -int -_nvkm_output_fini(struct nvkm_object *object, bool suspend) +void +nvkm_output_fini(struct nvkm_output *outp) { - struct nvkm_output *outp = (void *)object; - nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend); - return nvkm_object_fini(&outp->base, suspend); + if (outp->func->fini) + outp->func->fini(outp); } -int -_nvkm_output_init(struct nvkm_object *object) +void +nvkm_output_init(struct nvkm_output *outp) { - struct nvkm_output *outp = (void *)object; - int ret = nvkm_object_init(&outp->base); - if (ret == 0) - nv_ofuncs(outp->conn)->init(nv_object(outp->conn)); - return 0; + if (outp->func->init) + outp->func->init(outp); } void -_nvkm_output_dtor(struct nvkm_object *object) +nvkm_output_del(struct nvkm_output **poutp) { - struct nvkm_output *outp = (void *)object; - list_del(&outp->head); - nvkm_object_ref(NULL, (void *)&outp->conn); - nvkm_object_destroy(&outp->base); + struct nvkm_output *outp = *poutp; + if (outp && !WARN_ON(!outp->func)) { + if (outp->func->dtor) + *poutp = outp->func->dtor(outp); + kfree(*poutp); + *poutp = NULL; + } } -int -nvkm_output_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct dcb_output *dcbE, int index, - int length, void **pobject) +void +nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp, + int index, struct dcb_output *dcbE, struct nvkm_output *outp) { - struct nvkm_disp *disp = nvkm_disp(parent); - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvbios_connE connE; - struct nvkm_output *outp; - u8 ver, hdr; - u32 data; - int ret; + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; - ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); - outp = *pobject; - if (ret) - return ret; - - outp->info = *dcbE; + outp->func = func; + outp->disp = disp; outp->index = index; + outp->info = *dcbE; + outp->i2c = nvkm_i2c_bus_find(i2c, dcbE->i2c_index); outp->or = ffs(outp->info.or) - 1; - DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n", - dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ? - dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index, - dcbE->bus, dcbE->heads); - - if (outp->info.type != DCB_OUTPUT_DP) - outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index)); - else - outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index)); - outp->edid = outp->port; - - data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); - if (!data) { - DBG("vbios connector data not found\n"); - memset(&connE, 0x00, sizeof(connE)); - connE.type = DCB_CONNECTOR_NONE; - } - - ret = nvkm_object_ctor(parent, NULL, nvkm_connector_oclass, - &connE, outp->info.connector, - (struct nvkm_object **)&outp->conn); - if (ret < 0) { - ERR("error %d creating connector, disabling\n", ret); - return ret; - } - - list_add_tail(&outp->head, &disp->outp); - return 0; + OUTP_DBG(outp, "type %02x loc %d or %d link %d con %x " + "edid %x bus %d head %x", + outp->info.type, outp->info.location, outp->info.or, + outp->info.type >= 2 ? outp->info.sorconf.link : 0, + outp->info.connector, outp->info.i2c_index, + outp->info.bus, outp->info.heads); } int -_nvkm_output_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *dcbE, u32 index, - struct nvkm_object **pobject) +nvkm_output_new_(const struct nvkm_output_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { - struct nvkm_output *outp; - int ret; - - ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp); - *pobject = nv_object(outp); - if (ret) - return ret; + if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) + return -ENOMEM; + nvkm_output_ctor(func, disp, index, dcbE, *poutp); return 0; } - -struct nvkm_oclass * -nvkm_output_oclass = &(struct nvkm_output_impl) { - .base = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_ctor, - .dtor = _nvkm_output_dtor, - .init = _nvkm_output_init, - .fini = _nvkm_output_fini, - }, - }, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index d9253d26c31b..2590fec67ca9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -1,61 +1,55 @@ #ifndef __NVKM_DISP_OUTP_H__ #define __NVKM_DISP_OUTP_H__ -#include <core/object.h> +#include <engine/disp.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> struct nvkm_output { - struct nvkm_object base; - struct list_head head; - - struct dcb_output info; + const struct nvkm_output_func *func; + struct nvkm_disp *disp; int index; - int or; + struct dcb_output info; - struct nvkm_i2c_port *port; - struct nvkm_i2c_port *edid; + // whatever (if anything) is pointed at by the dcb device entry + struct nvkm_i2c_bus *i2c; + int or; + struct list_head head; struct nvkm_connector *conn; }; -#define nvkm_output_create(p,e,c,b,i,d) \ - nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_output_destroy(d) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_dtor(nv_object(_outp)); \ -}) -#define nvkm_output_init(d) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_init(nv_object(_outp)); \ -}) -#define nvkm_output_fini(d,s) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_fini(nv_object(_outp), (s)); \ -}) - -int nvkm_output_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct dcb_output *, - int, int, void **); - -int _nvkm_output_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_output_dtor(struct nvkm_object *); -int _nvkm_output_init(struct nvkm_object *); -int _nvkm_output_fini(struct nvkm_object *, bool); - -struct nvkm_output_impl { - struct nvkm_oclass base; +struct nvkm_output_func { + void *(*dtor)(struct nvkm_output *); + void (*init)(struct nvkm_output *); + void (*fini)(struct nvkm_output *); }; -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_output *_outp = (void *)outp; \ - nv_##l(_outp, "%02x:%04x:%04x: "f, _outp->index, \ - _outp->info.hasht, _outp->info.hashm, ##a); \ +void nvkm_output_ctor(const struct nvkm_output_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output *); +int nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output **); +void nvkm_output_del(struct nvkm_output **); +void nvkm_output_init(struct nvkm_output *); +void nvkm_output_fini(struct nvkm_output *); + +int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); + +void gm204_sor_magic(struct nvkm_output *outp); + +#define OUTP_MSG(o,l,f,a...) do { \ + struct nvkm_output *_outp = (o); \ + nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ + _outp->index, _outp->info.hasht, _outp->info.hashm, ##a); \ } while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif +#define OUTP_ERR(o,f,a...) OUTP_MSG((o), error, f, ##a) +#define OUTP_DBG(o,f,a...) OUTP_MSG((o), debug, f, ##a) +#define OUTP_TRACE(o,f,a...) OUTP_MSG((o), trace, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c index 0bde0fa5b59d..3b7a9e7a1ea8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c @@ -33,16 +33,17 @@ int nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) { - struct nvkm_output_dp *outp = (void *)base; + struct nvkm_output_dp *outp = nvkm_output_dp(base); bool retrain = true; u8 link[2], stat[3]; u32 linkrate; int ret, i; /* check that the link is trained at a high enough rate */ - ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2); + ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); if (ret) { - DBG("failed to read link config, assuming no sink\n"); + OUTP_DBG(&outp->base, + "failed to read link config, assuming no sink"); goto done; } @@ -50,14 +51,15 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ datarate = (datarate + 9) / 10; /* -> decakilobits */ if (linkrate < datarate) { - DBG("link not trained at sufficient rate\n"); + OUTP_DBG(&outp->base, "link not trained at sufficient rate"); goto done; } /* check that link is still trained */ - ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3); + ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3); if (ret) { - DBG("failed to read link status, assuming no sink\n"); + OUTP_DBG(&outp->base, + "failed to read link status, assuming no sink"); goto done; } @@ -67,13 +69,14 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) if (!(lane & DPCD_LS02_LANE0_CR_DONE) || !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { - DBG("lane %d not equalised\n", lane); + OUTP_DBG(&outp->base, + "lane %d not equalised", lane); goto done; } } retrain = false; } else { - DBG("no inter-lane alignment\n"); + OUTP_DBG(&outp->base, "no inter-lane alignment"); } done: @@ -102,150 +105,138 @@ done: } static void -nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present) +nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) { - struct nvkm_i2c_port *port = outp->base.edid; - if (present) { + struct nvkm_i2c_aux *aux = outp->aux; + + if (enable) { if (!outp->present) { - nvkm_i2c(port)->acquire_pad(port, 0); - DBG("aux power -> always\n"); + OUTP_DBG(&outp->base, "aux power -> always"); + nvkm_i2c_aux_monitor(aux, true); outp->present = true; } - nvkm_output_dp_train(&outp->base, 0, true); - } else { - if (outp->present) { - nvkm_i2c(port)->release_pad(port); - DBG("aux power -> demand\n"); - outp->present = false; + + if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dpcd, + sizeof(outp->dpcd))) { + nvkm_output_dp_train(&outp->base, 0, true); + return; } - atomic_set(&outp->lt.done, 0); } -} -static void -nvkm_output_dp_detect(struct nvkm_output_dp *outp) -{ - struct nvkm_i2c_port *port = outp->base.edid; - int ret = nvkm_i2c(port)->acquire_pad(port, 0); - if (ret == 0) { - ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV, - outp->dpcd, sizeof(outp->dpcd)); - nvkm_output_dp_enable(outp, ret == 0); - nvkm_i2c(port)->release_pad(port); + if (outp->present) { + OUTP_DBG(&outp->base, "aux power -> demand"); + nvkm_i2c_aux_monitor(aux, false); + outp->present = false; } + + atomic_set(&outp->lt.done, 0); } static int nvkm_output_dp_hpd(struct nvkm_notify *notify) { - struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); - struct nvkm_output_dp *outp; - struct nvkm_disp *disp = nvkm_disp(conn); const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; struct nvif_notify_conn_rep_v0 rep = {}; - list_for_each_entry(outp, &disp->outp, base.head) { - if (outp->base.conn == conn && - outp->info.type == DCB_OUTPUT_DP) { - DBG("HPD: %d\n", line->mask); - nvkm_output_dp_detect(outp); + OUTP_DBG(&outp->base, "HPD: %d", line->mask); + nvkm_output_dp_enable(outp, true); - if (line->mask & NVKM_I2C_UNPLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; - if (line->mask & NVKM_I2C_PLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; + if (line->mask & NVKM_I2C_UNPLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; + if (line->mask & NVKM_I2C_PLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; - nvkm_event_send(&disp->hpd, rep.mask, conn->index, - &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; - } - } - - WARN_ON(1); - return NVKM_NOTIFY_DROP; + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; } static int nvkm_output_dp_irq(struct nvkm_notify *notify) { - struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); - struct nvkm_disp *disp = nvkm_disp(outp); const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; struct nvif_notify_conn_rep_v0 rep = { .mask = NVIF_NOTIFY_CONN_V0_IRQ, }; - int index = outp->base.info.connector; - DBG("IRQ: %d\n", line->mask); + OUTP_DBG(&outp->base, "IRQ: %d", line->mask); nvkm_output_dp_train(&outp->base, 0, true); - nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); return NVKM_NOTIFY_DROP; } -int -_nvkm_output_dp_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_output_dp_fini(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->hpd); nvkm_notify_put(&outp->irq); + flush_work(&outp->lt.work); nvkm_output_dp_enable(outp, false); - return nvkm_output_fini(&outp->base, suspend); } -int -_nvkm_output_dp_init(struct nvkm_object *object) +static void +nvkm_output_dp_init(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; - nvkm_output_dp_detect(outp); - return nvkm_output_init(&outp->base); + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->base.conn->hpd); + nvkm_output_dp_enable(outp, true); + nvkm_notify_get(&outp->hpd); } -void -_nvkm_output_dp_dtor(struct nvkm_object *object) +static void * +nvkm_output_dp_dtor(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_fini(&outp->hpd); nvkm_notify_fini(&outp->irq); - nvkm_output_destroy(&outp->base); + return outp; } +static const struct nvkm_output_func +nvkm_output_dp_func = { + .dtor = nvkm_output_dp_dtor, + .init = nvkm_output_dp_init, + .fini = nvkm_output_dp_fini, +}; + int -nvkm_output_dp_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct dcb_output *info, int index, - int length, void **pobject) +nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp) { - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_output_dp *outp; + struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; u8 hdr, cnt, len; u32 data; int ret; - ret = nvkm_output_create_(parent, engine, oclass, info, index, - length, pobject); - outp = *pobject; - if (ret) - return ret; - - nvkm_notify_fini(&outp->base.conn->hpd); - - /* access to the aux channel is not optional... */ - if (!outp->base.edid) { - ERR("aux channel not found\n"); + nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); + outp->func = func; + outp->aux = aux; + if (!outp->aux) { + OUTP_ERR(&outp->base, "no aux"); return -ENODEV; } - /* nor is the bios data for this output... */ + /* bios data is not optional */ data = nvbios_dpout_match(bios, outp->base.info.hasht, outp->base.info.hashm, &outp->version, &hdr, &cnt, &len, &outp->info); if (!data) { - ERR("no bios dp data\n"); + OUTP_ERR(&outp->base, "no bios dp data"); return -ENODEV; } - DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len); + OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x", + outp->version, hdr, cnt, len); /* link training */ INIT_WORK(&outp->lt.work, nvkm_dp_train); @@ -256,13 +247,13 @@ nvkm_output_dp_create_(struct nvkm_object *parent, ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true, &(struct nvkm_i2c_ntfy_req) { .mask = NVKM_I2C_IRQ, - .port = outp->base.edid->index, + .port = outp->aux->id, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), &outp->irq); if (ret) { - ERR("error monitoring aux irq event: %d\n", ret); + OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret); return ret; } @@ -270,13 +261,13 @@ nvkm_output_dp_create_(struct nvkm_object *parent, ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true, &(struct nvkm_i2c_ntfy_req) { .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, - .port = outp->base.edid->index, + .port = outp->aux->id, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), - &outp->base.conn->hpd); + &outp->hpd); if (ret) { - ERR("error monitoring aux hpd events: %d\n", ret); + OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret); return ret; } @@ -284,18 +275,17 @@ nvkm_output_dp_create_(struct nvkm_object *parent, } int -_nvkm_output_dp_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index); struct nvkm_output_dp *outp; - int ret; - ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); - if (ret) - return ret; + if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + return -ENOMEM; + *poutp = &outp->base; - return 0; + return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index 70c77aec4850..731136d660b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -1,5 +1,14 @@ #ifndef __NVKM_DISP_OUTP_DP_H__ #define __NVKM_DISP_OUTP_DP_H__ +#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base) +#ifndef MSG +#define MSG(l,f,a...) \ + nvkm_##l(&outp->base.disp->engine.subdev, "%02x:%04x:%04x: "f, \ + outp->base.index, outp->base.info.hasht, \ + outp->base.info.hashm, ##a) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif #include "outp.h" #include <core/notify.h> @@ -7,12 +16,16 @@ #include <subdev/bios/dp.h> struct nvkm_output_dp { + const struct nvkm_output_dp_func *func; struct nvkm_output base; struct nvbios_dpout info; u8 version; + struct nvkm_i2c_aux *aux; + struct nvkm_notify irq; + struct nvkm_notify hpd; bool present; u8 dpcd[16]; @@ -23,34 +36,7 @@ struct nvkm_output_dp { } lt; }; -#define nvkm_output_dp_create(p,e,c,b,i,d) \ - nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_output_dp_destroy(d) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_dtor(nv_object(_outp)); \ -}) -#define nvkm_output_dp_init(d) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_init(nv_object(_outp)); \ -}) -#define nvkm_output_dp_fini(d,s) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_fini(nv_object(_outp), (s)); \ -}) - -int nvkm_output_dp_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct dcb_output *, - int, int, void **); - -int _nvkm_output_dp_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_output_dp_dtor(struct nvkm_object *); -int _nvkm_output_dp_init(struct nvkm_object *); -int _nvkm_output_dp_fini(struct nvkm_object *, bool); - -struct nvkm_output_dp_impl { - struct nvkm_output_impl base; +struct nvkm_output_dp_func { int (*pattern)(struct nvkm_output_dp *, int); int (*lnk_pwr)(struct nvkm_output_dp *, int nr); int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); @@ -58,4 +44,25 @@ struct nvkm_output_dp_impl { }; int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait); + +int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_i2c_aux *, + struct nvkm_output_dp *); +int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, + struct nvkm_output **); + +int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); + +int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); + +int gm204_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c new file mode 100644 index 000000000000..db6234eebc61 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c @@ -0,0 +1,77 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_mthd_list +g84_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +const struct nv50_disp_chan_mthd +g84_disp_ovly_chan_mthd = { + .name = "Overlay", + .addr = 0x000540, + .prev = 0x000004, + .data = { + { "Global", 1, &g84_disp_ovly_mthd_base }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +g84_disp_ovly_oclass = { + .base.oclass = G82_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_ovly_chan_mthd, + .chid = 3, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c new file mode 100644 index 000000000000..5985879abd23 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c @@ -0,0 +1,101 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_mthd_list +gf119_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +static const struct nv50_disp_chan_mthd +gf119_disp_ovly_chan_mthd = { + .name = "Overlay", + .addr = 0x001000, + .prev = -0x020000, + .data = { + { "Global", 1, &gf119_disp_ovly_mthd_base }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +gf119_disp_ovly_oclass = { + .base.oclass = GF110_DISP_OVERLAY_CONTROL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_ovly_chan_mthd, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c new file mode 100644 index 000000000000..2e2dc0641ef2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c @@ -0,0 +1,103 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_mthd_list +gk104_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00c4, 0x6650c4 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0404, 0x665404 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +static const struct nv50_disp_chan_mthd +gk104_disp_ovly_chan_mthd = { + .name = "Overlay", + .addr = 0x001000, + .prev = -0x020000, + .data = { + { "Global", 1, &gk104_disp_ovly_mthd_base }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +gk104_disp_ovly_oclass = { + .base.oclass = GK104_DISP_OVERLAY_CONTROL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &gf119_disp_dmac_func, + .mthd = &gk104_disp_ovly_chan_mthd, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c new file mode 100644 index 000000000000..f858053db83d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c @@ -0,0 +1,80 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_mthd_list +gt200_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00b0, 0x610c98 }, + { 0x00b4, 0x610ca4 }, + { 0x00b8, 0x610cac }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +static const struct nv50_disp_chan_mthd +gt200_disp_ovly_chan_mthd = { + .name = "Overlay", + .addr = 0x000540, + .prev = 0x000004, + .data = { + { "Global", 1, >200_disp_ovly_mthd_base }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +gt200_disp_ovly_oclass = { + .base.oclass = GT200_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = >200_disp_ovly_chan_mthd, + .chid = 3, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt215.c new file mode 100644 index 000000000000..c947e1e16a37 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt215.c @@ -0,0 +1,38 @@ +/* + * 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 "dmacnv50.h" +#include "rootnv50.h" + +#include <nvif/class.h> + +const struct nv50_disp_dmac_oclass +gt215_disp_ovly_oclass = { + .base.oclass = GT214_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_ovly_chan_mthd, + .chid = 3, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c new file mode 100644 index 000000000000..6fa296c047b8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c @@ -0,0 +1,111 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include <core/client.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +int +nv50_disp_ovly_new(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_overlay_channel_dma_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; + u64 push; + + nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp overlay channel dma vers %d " + "pushbuf %016llx head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > disp->base.head.nr) + return -EINVAL; + push = args->v0.pushbuf; + head = args->v0.head; + } else + return ret; + + return nv50_disp_dmac_new_(func, mthd, root, chid + head, + head, push, oclass, pobject); +} + +static const struct nv50_disp_mthd_list +nv50_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0009a0 }, + { 0x0088, 0x0009c0 }, + { 0x008c, 0x0009c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +static const struct nv50_disp_chan_mthd +nv50_disp_ovly_chan_mthd = { + .name = "Overlay", + .addr = 0x000540, + .prev = 0x000004, + .data = { + { "Global", 1, &nv50_disp_ovly_mthd_base }, + {} + } +}; + +const struct nv50_disp_dmac_oclass +nv50_disp_ovly_oclass = { + .base.oclass = NV50_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = &nv50_disp_ovly_chan_mthd, + .chid = 3, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c new file mode 100644 index 000000000000..a625a9876e34 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c @@ -0,0 +1,81 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <subdev/timer.h> + +static void +gf119_disp_pioc_fini(struct nv50_disp_chan *chan) +{ + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->chid; + + nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d fini: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + } + + /* disable error reporting and completion notification */ + nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); +} + +static int +gf119_disp_pioc_init(struct nv50_disp_chan *chan) +{ + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->chid; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + + /* activate channel */ + nvkm_wr32(device, 0x610490 + (chid * 0x10), 0x00000001); + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x610490 + (chid * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { + nvkm_error(subdev, "ch %d init: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_chan_func +gf119_disp_pioc_func = { + .init = gf119_disp_pioc_init, + .fini = gf119_disp_pioc_fini, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c new file mode 100644 index 000000000000..9d2618dacf20 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c @@ -0,0 +1,83 @@ +/* + * 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 "channv50.h" +#include "rootnv50.h" + +#include <subdev/timer.h> + +static void +nv50_disp_pioc_fini(struct nv50_disp_chan *chan) +{ + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->chid; + + nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d timeout: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + } +} + +static int +nv50_disp_pioc_init(struct nv50_disp_chan *chan) +{ + struct nv50_disp *disp = chan->root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->chid; + + nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d timeout0: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00000001); + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x610200 + (chid * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { + nvkm_error(subdev, "ch %d timeout1: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_chan_func +nv50_disp_pioc_func = { + .init = nv50_disp_pioc_init, + .fini = nv50_disp_pioc_fini, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 2a1d8871bf82..ab524bde7795 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -21,8 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" #include "outpdp.h" +#include "nv50.h" #include <core/client.h> #include <subdev/i2c.h> @@ -31,140 +31,101 @@ #include <nvif/class.h> #include <nvif/unpack.h> -/****************************************************************************** - * TMDS - *****************************************************************************/ - -static int -nv50_pior_tmds_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +int +nv50_pior_power(NV50_DISP_MTHD_V1) { - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_output *outp; + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = outp->or * 0x800; + union { + struct nv50_disp_pior_pwr_v0 v0; + } *args = data; + u32 ctrl, type; int ret; - ret = nvkm_output_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); - if (ret) + nvif_ioctl(object, "disp pior pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", + args->v0.version, args->v0.state, args->v0.type); + if (args->v0.type > 0x0f) + return -EINVAL; + ctrl = !!args->v0.state; + type = args->v0.type; + } else return ret; - outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev)); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + disp->pior.type[outp->or] = type; return 0; } -struct nvkm_output_impl -nv50_pior_tmds_impl = { - .base.handle = DCB_OUTPUT_TMDS | 0x0100, - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_pior_tmds_ctor, - .dtor = _nvkm_output_dtor, - .init = _nvkm_output_init, - .fini = _nvkm_output_fini, - }, -}; - /****************************************************************************** - * DisplayPort + * TMDS *****************************************************************************/ +static const struct nvkm_output_func +nv50_pior_output_func = { +}; -static int -nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern) +int +nv50_pior_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) { - struct nvkm_i2c_port *port = outp->base.edid; - if (port && port->func->pattern) - return port->func->pattern(port, pattern); - return port ? 0 : -ENODEV; + return nvkm_output_new_(&nv50_pior_output_func, disp, + index, dcbE, poutp); } +/****************************************************************************** + * DisplayPort + *****************************************************************************/ static int -nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) +nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern) { return 0; } static int -nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) -{ - struct nvkm_i2c_port *port = outp->base.edid; - if (port && port->func->lnk_ctl) - return port->func->lnk_ctl(port, nr, bw, ef); - return port ? 0 : -ENODEV; -} - -static int -nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) +nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nvkm_i2c_port *port = outp->base.edid; - if (port && port->func->drv_ctl) - return port->func->drv_ctl(port, ln, vs, pe); - return port ? 0 : -ENODEV; + return 0; } static int -nv50_pior_dp_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nv50_pior_output_dp_lnk_ctl(struct nvkm_output_dp *outp, + int nr, int bw, bool ef) { - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_output_dp *outp; - int ret; - - ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); + int ret = nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); if (ret) return ret; - - outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX( - outp->base.info.extdev)); - return 0; + return 1; } -struct nvkm_output_dp_impl -nv50_pior_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP | 0x0010, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_pior_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, - .pattern = nv50_pior_dp_pattern, - .lnk_pwr = nv50_pior_dp_lnk_pwr, - .lnk_ctl = nv50_pior_dp_lnk_ctl, - .drv_ctl = nv50_pior_dp_drv_ctl, +static const struct nvkm_output_dp_func +nv50_pior_output_dp_func = { + .pattern = nv50_pior_output_dp_pattern, + .lnk_pwr = nv50_pior_output_dp_lnk_pwr, + .lnk_ctl = nv50_pior_output_dp_lnk_ctl, }; -/****************************************************************************** - * General PIOR handling - *****************************************************************************/ - int -nv50_pior_power(NV50_DISP_MTHD_V1) +nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { - const u32 soff = outp->or * 0x800; - union { - struct nv50_disp_pior_pwr_v0 v0; - } *args = data; - u32 ctrl, type; - int ret; + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + struct nvkm_i2c_aux *aux = + nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); + struct nvkm_output_dp *outp; - nv_ioctl(object, "disp pior pwr size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n", - args->v0.version, args->v0.state, args->v0.type); - if (args->v0.type > 0x0f) - return -EINVAL; - ctrl = !!args->v0.state; - type = args->v0.type; - } else - return ret; + if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + return -ENOMEM; + *poutp = &outp->base; - nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); - nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); - priv->pior.type[outp->or] = type; - return 0; + return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp, + index, dcbE, aux, outp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index 961ce8bb2135..c2452957fc57 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -1,42 +1,52 @@ #ifndef __NVKM_DISP_PRIV_H__ #define __NVKM_DISP_PRIV_H__ #include <engine/disp.h> +#include "outp.h" +#include "outpdp.h" -struct nvkm_disp_impl { - struct nvkm_oclass base; - struct nvkm_oclass **outp; - struct nvkm_oclass **conn; - const struct nvkm_event_func *vblank; +int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *, + int index, int heads, struct nvkm_disp *); +int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, + int index, int heads, struct nvkm_disp **); +void nvkm_disp_vblank(struct nvkm_disp *, int head); + +struct nvkm_disp_func_outp { + int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* tv)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* dp)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); +}; + +struct nvkm_disp_func { + void *(*dtor)(struct nvkm_disp *); + void (*intr)(struct nvkm_disp *); + + const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *); + + struct { + void (*vblank_init)(struct nvkm_disp *, int head); + void (*vblank_fini)(struct nvkm_disp *, int head); + } head; + + struct { + const struct nvkm_disp_func_outp internal; + const struct nvkm_disp_func_outp external; + } outp; }; -#define nvkm_disp_create(p,e,c,h,i,x,d) \ - nvkm_disp_create_((p), (e), (c), (h), (i), (x), \ - sizeof(**d), (void **)d) -#define nvkm_disp_destroy(d) ({ \ - struct nvkm_disp *disp = (d); \ - _nvkm_disp_dtor(nv_object(disp)); \ -}) -#define nvkm_disp_init(d) ({ \ - struct nvkm_disp *disp = (d); \ - _nvkm_disp_init(nv_object(disp)); \ -}) -#define nvkm_disp_fini(d,s) ({ \ - struct nvkm_disp *disp = (d); \ - _nvkm_disp_fini(nv_object(disp), (s)); \ -}) - -int nvkm_disp_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int heads, - const char *, const char *, int, void **); -void _nvkm_disp_dtor(struct nvkm_object *); -int _nvkm_disp_init(struct nvkm_object *); -int _nvkm_disp_fini(struct nvkm_object *, bool); - -extern struct nvkm_oclass *nvkm_output_oclass; -extern struct nvkm_oclass *nvkm_connector_oclass; - -int nvkm_disp_vblank_ctor(struct nvkm_object *, void *data, u32 size, - struct nvkm_notify *); -void nvkm_disp_vblank(struct nvkm_disp *, int head); int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **); + +extern const struct nvkm_disp_oclass nv04_disp_root_oclass; + +struct nvkm_disp_oclass { + int (*ctor)(struct nvkm_disp *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + struct nvkm_sclass base; +}; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c index 6820176e5f78..721e4f74d1fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c @@ -1,5 +1,5 @@ /* - * Copyright 2013 Red Hat Inc. + * 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"), @@ -21,37 +21,38 @@ * * Authors: Ben Skeggs */ -#include "gf100.h" +#include "rootnv50.h" +#include "dmacnv50.h" -static int -gk110_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_pm_priv *priv; - int ret; - - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +#include <nvif/class.h> - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr); - if (ret) - return ret; +static const struct nv50_disp_root_func +g84_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + &g84_disp_core_oclass, + &g84_disp_base_oclass, + &g84_disp_ovly_oclass, + }, + .pioc = { + &g84_disp_oimm_oclass, + &g84_disp_curs_oclass, + }, +}; - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; - return 0; +static int +g84_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&g84_disp_root, disp, oclass, + data, size, pobject); } -struct nvkm_oclass -gk110_pm_oclass = { - .handle = NV_ENGINE(PM, 0xf0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk110_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, +const struct nvkm_disp_oclass +g84_disp_root_oclass = { + .base.oclass = G82_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = g84_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c new file mode 100644 index 000000000000..9493f6edf62b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_root_func +g94_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + &g94_disp_core_oclass, + >200_disp_base_oclass, + >200_disp_ovly_oclass, + }, + .pioc = { + &g84_disp_oimm_oclass, + &g84_disp_curs_oclass, + }, +}; + +static int +g94_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&g94_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +g94_disp_root_oclass = { + .base.oclass = GT206_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = g94_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c new file mode 100644 index 000000000000..8591726871ac --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c @@ -0,0 +1,171 @@ +/* + * 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 "rootnv50.h" +#include "dmacnv50.h" + +#include <core/client.h> +#include <core/ramht.h> +#include <subdev/timer.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +int +gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 total = nvkm_rd32(device, 0x640414 + (head * 0x300)); + const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300)); + const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300)); + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + int ret; + + nvif_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); + args->v0.vblanke = (blanke & 0xffff0000) >> 16; + args->v0.hblanke = (blanke & 0x0000ffff); + args->v0.vblanks = (blanks & 0xffff0000) >> 16; + args->v0.hblanks = (blanks & 0x0000ffff); + args->v0.vtotal = ( total & 0xffff0000) >> 16; + args->v0.htotal = ( total & 0x0000ffff); + args->v0.time[0] = ktime_to_ns(ktime_get()); + args->v0.vline = /* vline read locks hline */ + nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = + nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; + } else + return ret; + + return 0; +} + +void +gf119_disp_root_fini(struct nv50_disp_root *root) +{ + struct nvkm_device *device = root->disp->base.engine.subdev.device; + /* disable all interrupts */ + nvkm_wr32(device, 0x6100b0, 0x00000000); +} + +int +gf119_disp_root_init(struct nv50_disp_root *root) +{ + struct nv50_disp *disp = root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 tmp; + int i; + + /* The below segments of code copying values from one register to + * another appear to inform EVO of the display capabilities or + * something similar. + */ + + /* ... CRTC caps */ + for (i = 0; i < disp->base.head.nr; i++) { + tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); + nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); + nvkm_wr32(device, 0x6101b8 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); + nvkm_wr32(device, 0x6101bc + (i * 0x800), tmp); + } + + /* ... DAC caps */ + for (i = 0; i < disp->func->dac.nr; i++) { + tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); + nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp); + } + + /* ... SOR caps */ + for (i = 0; i < disp->func->sor.nr; i++) { + tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); + nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp); + } + + /* steal display away from vbios, or something like that */ + if (nvkm_rd32(device, 0x6100ac) & 0x00000100) { + nvkm_wr32(device, 0x6100ac, 0x00000100); + nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) + break; + ) < 0) + return -EBUSY; + } + + /* point at display engine memory area (hash table, objects) */ + nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9); + + /* enable supervisor interrupts, disable everything else */ + nvkm_wr32(device, 0x610090, 0x00000000); + nvkm_wr32(device, 0x6100a0, 0x00000000); + nvkm_wr32(device, 0x6100b0, 0x00000307); + + /* disable underflow reporting, preventing an intermittent issue + * on some gk104 boards where the production vbios left this + * setting enabled by default. + * + * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt + */ + for (i = 0; i < disp->base.head.nr; i++) + nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); + + return 0; +} + +static const struct nv50_disp_root_func +gf119_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gf119_disp_core_oclass, + &gf119_disp_base_oclass, + &gf119_disp_ovly_oclass, + }, + .pioc = { + &gf119_disp_oimm_oclass, + &gf119_disp_curs_oclass, + }, +}; + +static int +gf119_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gf119_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gf119_disp_root_oclass = { + .base.oclass = GF110_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gf119_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c new file mode 100644 index 000000000000..0bfdb1d1c6ab --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_root_func +gk104_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gk104_disp_core_oclass, + &gk104_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, +}; + +static int +gk104_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gk104_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gk104_disp_root_oclass = { + .base.oclass = GK104_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gk104_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c new file mode 100644 index 000000000000..1e8dbed8a67c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_root_func +gk110_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gk110_disp_core_oclass, + &gk110_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, +}; + +static int +gk110_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gk110_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gk110_disp_root_oclass = { + .base.oclass = GK110_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gk110_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c new file mode 100644 index 000000000000..44c55be69e99 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_root_func +gm107_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gm107_disp_core_oclass, + &gk110_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, +}; + +static int +gm107_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gm107_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gm107_disp_root_oclass = { + .base.oclass = GM107_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gm107_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c new file mode 100644 index 000000000000..168bffe0643c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_root_func +gm204_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gm204_disp_core_oclass, + &gk110_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, +}; + +static int +gm204_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gm204_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gm204_disp_root_oclass = { + .base.oclass = GM204_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gm204_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c new file mode 100644 index 000000000000..124a0c24f92c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_root_func +gt200_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + >200_disp_core_oclass, + >200_disp_base_oclass, + >200_disp_ovly_oclass, + }, + .pioc = { + &g84_disp_oimm_oclass, + &g84_disp_curs_oclass, + }, +}; + +static int +gt200_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(>200_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gt200_disp_root_oclass = { + .base.oclass = GT200_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gt200_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c new file mode 100644 index 000000000000..dff52f30668b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include <nvif/class.h> + +static const struct nv50_disp_root_func +gt215_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + >215_disp_core_oclass, + >215_disp_base_oclass, + >215_disp_ovly_oclass, + }, + .pioc = { + >215_disp_oimm_oclass, + >215_disp_curs_oclass, + }, +}; + +static int +gt215_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(>215_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gt215_disp_root_oclass = { + .base.oclass = GT214_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gt215_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c new file mode 100644 index 000000000000..62d3fb66d0ec --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c @@ -0,0 +1,139 @@ +/* + * 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 + */ +#define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object) +#include "priv.h" + +#include <core/client.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +struct nv04_disp_root { + struct nvkm_object object; + struct nvkm_disp *disp; +}; + +static int +nv04_disp_scanoutpos(struct nv04_disp_root *root, + void *data, u32 size, int head) +{ + struct nvkm_device *device = root->disp->engine.subdev.device; + struct nvkm_object *object = &root->object; + const u32 hoff = head * 0x2000; + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + u32 line; + int ret; + + nvif_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); + args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff; + args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff; + args->v0.vblanke = args->v0.vtotal - 1; + + args->v0.hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0xffff; + args->v0.htotal = nvkm_rd32(device, 0x680824 + hoff) & 0xffff; + args->v0.hblanke = args->v0.htotal - 1; + + /* + * If output is vga instead of digital then vtotal/htotal is + * invalid so we have to give up and trigger the timestamping + * fallback in the drm core. + */ + if (!args->v0.vtotal || !args->v0.htotal) + return -ENOTSUPP; + + args->v0.time[0] = ktime_to_ns(ktime_get()); + line = nvkm_rd32(device, 0x600868 + hoff); + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = (line & 0xffff0000) >> 16; + args->v0.vline = (line & 0x0000ffff); + } else + return ret; + + return 0; +} + +static int +nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + struct nv04_disp_root *root = nv04_disp_root(object); + union { + struct nv04_disp_mthd_v0 v0; + } *args = data; + int head, ret; + + nvif_ioctl(object, "disp mthd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); + mthd = args->v0.method; + head = args->v0.head; + } else + return ret; + + if (head < 0 || head >= 2) + return -ENXIO; + + switch (mthd) { + case NV04_DISP_SCANOUTPOS: + return nv04_disp_scanoutpos(root, data, size, head); + default: + break; + } + + return -EINVAL; +} + +static struct nvkm_object_func +nv04_disp_root = { + .mthd = nv04_disp_mthd, + .ntfy = nvkm_disp_ntfy, +}; + +static int +nv04_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nv04_disp_root *root; + + if (!(root = kzalloc(sizeof(*root), GFP_KERNEL))) + return -ENOMEM; + root->disp = disp; + *pobject = &root->object; + + nvkm_object_ctor(&nv04_disp_root, oclass, &root->object); + return 0; +} + +const struct nvkm_disp_oclass +nv04_disp_root_oclass = { + .base.oclass = NV04_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = nv04_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c new file mode 100644 index 000000000000..06fb24d88702 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -0,0 +1,399 @@ +/* + * 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 "rootnv50.h" +#include "dmacnv50.h" + +#include <core/client.h> +#include <core/ramht.h> +#include <subdev/timer.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +int +nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540)); + const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540)); + const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540)); + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + int ret; + + nvif_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); + args->v0.vblanke = (blanke & 0xffff0000) >> 16; + args->v0.hblanke = (blanke & 0x0000ffff); + args->v0.vblanks = (blanks & 0xffff0000) >> 16; + args->v0.hblanks = (blanks & 0x0000ffff); + args->v0.vtotal = ( total & 0xffff0000) >> 16; + args->v0.htotal = ( total & 0x0000ffff); + args->v0.time[0] = ktime_to_ns(ktime_get()); + args->v0.vline = /* vline read locks hline */ + nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = + nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; + } else + return ret; + + return 0; +} + +int +nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + union { + struct nv50_disp_mthd_v0 v0; + struct nv50_disp_mthd_v1 v1; + } *args = data; + struct nv50_disp_root *root = nv50_disp_root(object); + struct nv50_disp *disp = root->disp; + const struct nv50_disp_func *func = disp->func; + struct nvkm_output *outp = NULL; + struct nvkm_output *temp; + u16 type, mask = 0; + int head, ret; + + if (mthd != NV50_DISP_MTHD) + return -EINVAL; + + nvif_ioctl(object, "disp mthd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); + mthd = args->v0.method; + head = args->v0.head; + } else + if (nvif_unpack(args->v1, 1, 1, true)) { + nvif_ioctl(object, "disp mthd vers %d mthd %02x " + "type %04x mask %04x\n", + args->v1.version, args->v1.method, + args->v1.hasht, args->v1.hashm); + mthd = args->v1.method; + type = args->v1.hasht; + mask = args->v1.hashm; + head = ffs((mask >> 8) & 0x0f) - 1; + } else + return ret; + + if (head < 0 || head >= disp->base.head.nr) + return -ENXIO; + + if (mask) { + list_for_each_entry(temp, &disp->base.outp, head) { + if ((temp->info.hasht == type) && + (temp->info.hashm & mask) == mask) { + outp = temp; + break; + } + } + if (outp == NULL) + return -ENXIO; + } + + switch (mthd) { + case NV50_DISP_SCANOUTPOS: + return func->head.scanoutpos(object, disp, data, size, head); + default: + break; + } + + switch (mthd * !!outp) { + case NV50_DISP_MTHD_V1_DAC_PWR: + return func->dac.power(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_DAC_LOAD: + return func->dac.sense(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_PWR: + return func->sor.power(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_HDA_ELD: + if (!func->sor.hda_eld) + return -ENODEV; + return func->sor.hda_eld(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: + if (!func->sor.hdmi) + return -ENODEV; + return func->sor.hdmi(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { + union { + struct nv50_disp_sor_lvds_script_v0 v0; + } *args = data; + nvif_ioctl(object, "disp sor lvds script size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp sor lvds script " + "vers %d name %04x\n", + args->v0.version, args->v0.script); + disp->sor.lvdsconf = args->v0.script; + return 0; + } else + return ret; + } + break; + case NV50_DISP_MTHD_V1_SOR_DP_PWR: { + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + union { + struct nv50_disp_sor_dp_pwr_v0 v0; + } *args = data; + nvif_ioctl(object, "disp sor dp pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n", + args->v0.version, args->v0.state); + if (args->v0.state == 0) { + nvkm_notify_put(&outpdp->irq); + outpdp->func->lnk_pwr(outpdp, 0); + atomic_set(&outpdp->lt.done, 0); + return 0; + } else + if (args->v0.state != 0) { + nvkm_output_dp_train(&outpdp->base, 0, true); + return 0; + } + } else + return ret; + } + break; + case NV50_DISP_MTHD_V1_PIOR_PWR: + if (!func->pior.power) + return -ENODEV; + return func->pior.power(object, disp, data, size, head, outp); + default: + break; + } + + return -EINVAL; +} + +static int +nv50_disp_root_dmac_new_(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + const struct nv50_disp_dmac_oclass *sclass = oclass->priv; + struct nv50_disp_root *root = nv50_disp_root(oclass->parent); + return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid, + oclass, data, size, pobject); +} + +static int +nv50_disp_root_pioc_new_(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + const struct nv50_disp_pioc_oclass *sclass = oclass->priv; + struct nv50_disp_root *root = nv50_disp_root(oclass->parent); + return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid, + oclass, data, size, pobject); +} + +static int +nv50_disp_root_child_get_(struct nvkm_object *object, int index, + struct nvkm_oclass *sclass) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + + if (index < ARRAY_SIZE(root->func->dmac)) { + sclass->base = root->func->dmac[index]->base; + sclass->priv = root->func->dmac[index]; + sclass->ctor = nv50_disp_root_dmac_new_; + return 0; + } + + index -= ARRAY_SIZE(root->func->dmac); + + if (index < ARRAY_SIZE(root->func->pioc)) { + sclass->base = root->func->pioc[index]->base; + sclass->priv = root->func->pioc[index]; + sclass->ctor = nv50_disp_root_pioc_new_; + return 0; + } + + return -EINVAL; +} + +static int +nv50_disp_root_fini_(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + root->func->fini(root); + return 0; +} + +static int +nv50_disp_root_init_(struct nvkm_object *object) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + return root->func->init(root); +} + +static void * +nv50_disp_root_dtor_(struct nvkm_object *object) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + nvkm_ramht_del(&root->ramht); + nvkm_gpuobj_del(&root->instmem); + return root; +} + +static const struct nvkm_object_func +nv50_disp_root_ = { + .dtor = nv50_disp_root_dtor_, + .init = nv50_disp_root_init_, + .fini = nv50_disp_root_fini_, + .mthd = nv50_disp_root_mthd_, + .ntfy = nvkm_disp_ntfy, + .sclass = nv50_disp_root_child_get_, +}; + +int +nv50_disp_root_new_(const struct nv50_disp_root_func *func, + struct nvkm_disp *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nv50_disp *disp = nv50_disp(base); + struct nv50_disp_root *root; + struct nvkm_device *device = disp->base.engine.subdev.device; + int ret; + + if (!(root = kzalloc(sizeof(*root), GFP_KERNEL))) + return -ENOMEM; + *pobject = &root->object; + + nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object); + root->func = func; + root->disp = disp; + + ret = nvkm_gpuobj_new(disp->base.engine.subdev.device, 0x10000, 0x10000, + false, NULL, &root->instmem); + if (ret) + return ret; + + return nvkm_ramht_new(device, 0x1000, 0, root->instmem, &root->ramht); +} + +void +nv50_disp_root_fini(struct nv50_disp_root *root) +{ + struct nvkm_device *device = root->disp->base.engine.subdev.device; + /* disable all interrupts */ + nvkm_wr32(device, 0x610024, 0x00000000); + nvkm_wr32(device, 0x610020, 0x00000000); +} + +int +nv50_disp_root_init(struct nv50_disp_root *root) +{ + struct nv50_disp *disp = root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 tmp; + int i; + + /* The below segments of code copying values from one register to + * another appear to inform EVO of the display capabilities or + * something similar. NFI what the 0x614004 caps are for.. + */ + tmp = nvkm_rd32(device, 0x614004); + nvkm_wr32(device, 0x610184, tmp); + + /* ... CRTC caps */ + for (i = 0; i < disp->base.head.nr; i++) { + tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); + nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); + nvkm_wr32(device, 0x610194 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); + nvkm_wr32(device, 0x610198 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); + nvkm_wr32(device, 0x61019c + (i * 0x10), tmp); + } + + /* ... DAC caps */ + for (i = 0; i < disp->func->dac.nr; i++) { + tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); + nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp); + } + + /* ... SOR caps */ + for (i = 0; i < disp->func->sor.nr; i++) { + tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); + nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp); + } + + /* ... PIOR caps */ + for (i = 0; i < disp->func->pior.nr; i++) { + tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800)); + nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp); + } + + /* steal display away from vbios, or something like that */ + if (nvkm_rd32(device, 0x610024) & 0x00000100) { + nvkm_wr32(device, 0x610024, 0x00000100); + nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) + break; + ) < 0) + return -EBUSY; + } + + /* point at display engine memory area (hash table, objects) */ + nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9); + + /* enable supervisor interrupts, disable everything else */ + nvkm_wr32(device, 0x61002c, 0x00000370); + nvkm_wr32(device, 0x610028, 0x00000000); + return 0; +} + +static const struct nv50_disp_root_func +nv50_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + &nv50_disp_core_oclass, + &nv50_disp_base_oclass, + &nv50_disp_ovly_oclass, + }, + .pioc = { + &nv50_disp_oimm_oclass, + &nv50_disp_curs_oclass, + }, +}; + +static int +nv50_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&nv50_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +nv50_disp_root_oclass = { + .base.oclass = NV50_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = nv50_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h new file mode 100644 index 000000000000..5b2c903ce9ee --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h @@ -0,0 +1,43 @@ +#ifndef __NV50_DISP_ROOT_H__ +#define __NV50_DISP_ROOT_H__ +#define nv50_disp_root(p) container_of((p), struct nv50_disp_root, object) +#include "nv50.h" +#include "channv50.h" +#include "dmacnv50.h" + +struct nv50_disp_root { + const struct nv50_disp_root_func *func; + struct nv50_disp *disp; + struct nvkm_object object; + + struct nvkm_gpuobj *instmem; + struct nvkm_ramht *ramht; +}; + +struct nv50_disp_root_func { + int (*init)(struct nv50_disp_root *); + void (*fini)(struct nv50_disp_root *); + const struct nv50_disp_dmac_oclass *dmac[3]; + const struct nv50_disp_pioc_oclass *pioc[2]; +}; + +int nv50_disp_root_new_(const struct nv50_disp_root_func *, struct nvkm_disp *, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_root_init(struct nv50_disp_root *); +void nv50_disp_root_fini(struct nv50_disp_root *); + +int gf119_disp_root_init(struct nv50_disp_root *); +void gf119_disp_root_fini(struct nv50_disp_root *); + +extern const struct nvkm_disp_oclass nv50_disp_root_oclass; +extern const struct nvkm_disp_oclass g84_disp_root_oclass; +extern const struct nvkm_disp_oclass g94_disp_root_oclass; +extern const struct nvkm_disp_oclass gt200_disp_root_oclass; +extern const struct nvkm_disp_oclass gt215_disp_root_oclass; +extern const struct nvkm_disp_oclass gf119_disp_root_oclass; +extern const struct nvkm_disp_oclass gk104_disp_root_oclass; +extern const struct nvkm_disp_oclass gk110_disp_root_oclass; +extern const struct nvkm_disp_oclass gm107_disp_root_oclass; +extern const struct nvkm_disp_oclass gm204_disp_root_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 8918da7ffdf2..1bb9d661e9b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -24,7 +24,6 @@ #include "nv50.h" #include "outpdp.h" -#include <core/device.h> #include <subdev/timer.h> static inline u32 @@ -39,12 +38,33 @@ g94_sor_loff(struct nvkm_output_dp *outp) return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } -static inline u32 -g94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) +/******************************************************************************* + * TMDS/LVDS + ******************************************************************************/ +static const struct nvkm_output_func +g94_sor_output_func = { +}; + +int +g94_sor_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&g94_sor_output_func, disp, + index, dcbE, poutp); +} + +/******************************************************************************* + * DisplayPort + ******************************************************************************/ +u32 +g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { + static const u8 gm100[] = { 0, 8, 16, 24 }; static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ - static const u8 g94[] = { 16, 8, 0, 24 }; - if (nv_device(priv)->chipset == 0xaf) + static const u8 g94[] = { 16, 8, 0, 24 }; + if (device->chipset >= 0x110) + return gm100[lane]; + if (device->chipset == 0xaf) return mcp89[lane]; return g94[lane]; } @@ -52,33 +72,36 @@ g94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) static int g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 loff = g94_sor_loff(outp); - nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); + nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); return 0; } int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (g94_sor_dp_lane_map(priv, i) >> 3); - - nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask); - nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000); - nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000); + mask |= 1 << (g94_sor_dp_lane_map(device, i) >> 3); + + nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); + nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) + break; + ); return 0; } static int g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -90,17 +113,17 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) if (bw > 0x06) clksor |= 0x00040000; - nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor); - nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); + nvkm_mask(device, 0x614300 + soff, 0x000c0000, clksor); + nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl); return 0; } static int g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(priv); - const u32 shift = g94_sor_dp_lane_map(priv, ln); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + const u32 shift = g94_sor_dp_lane_map(device, ln); const u32 loff = g94_sor_loff(outp); u32 addr, data[3]; u8 ver, hdr, cnt, len; @@ -109,37 +132,37 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) addr = nvbios_dpout_match(bios, outp->base.info.hasht, outp->base.info.hashm, - &ver, &hdr, &cnt, &len, &info); + &ver, &hdr, &cnt, &len, &info); if (!addr) return -ENODEV; addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, - &ver, &hdr, &cnt, &len, &ocfg); + &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; - data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(priv, 0x61c130 + loff); + data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nvkm_rd32(device, 0x61c130 + loff); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nvkm_wr32(device, 0x61c130 + loff, data[2]); return 0; } -struct nvkm_output_dp_impl -g94_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +g94_sor_dp_func = { .pattern = g94_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, .lnk_ctl = g94_sor_dp_lnk_ctl, .drv_ctl = g94_sor_dp_drv_ctl, }; + +int +g94_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&g94_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 52fbe4880e13..b4b41b135643 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -25,39 +25,32 @@ #include "outpdp.h" static inline u32 -gf110_sor_soff(struct nvkm_output_dp *outp) +gf119_sor_soff(struct nvkm_output_dp *outp) { return (ffs(outp->base.info.or) - 1) * 0x800; } static inline u32 -gf110_sor_loff(struct nvkm_output_dp *outp) +gf119_sor_loff(struct nvkm_output_dp *outp) { - return gf110_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; -} - -static inline u32 -gf110_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) -{ - static const u8 gf110[] = { 16, 8, 0, 24 }; - return gf110[lane]; + return gf119_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } static int -gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) +gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - const u32 loff = gf110_sor_loff(outp); - nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + const u32 loff = gf119_sor_loff(outp); + nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; } int -gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) +gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - const u32 soff = gf110_sor_soff(outp); - const u32 loff = gf110_sor_loff(outp); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + const u32 soff = gf119_sor_soff(outp); + const u32 loff = gf119_sor_loff(outp); u32 dpctrl = 0x00000000; u32 clksor = 0x00000000; @@ -66,19 +59,19 @@ gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) if (ef) dpctrl |= 0x00004000; - nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor); - nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); + nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); + nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl); return 0; } static int -gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, +gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(priv); - const u32 shift = gf110_sor_dp_lane_map(priv, ln); - const u32 loff = gf110_sor_loff(outp); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + const u32 shift = g94_sor_dp_lane_map(device, ln); + const u32 loff = gf119_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; struct nvbios_dpout info; @@ -95,30 +88,30 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, if (!addr) return -EINVAL; - data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(priv, 0x61c130 + loff); + data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nvkm_rd32(device, 0x61c130 + loff); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); - data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift); - nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nvkm_wr32(device, 0x61c130 + loff, data[2]); + data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift); + nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; } -struct nvkm_output_dp_impl -gf110_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, - .pattern = gf110_sor_dp_pattern, +static const struct nvkm_output_dp_func +gf119_sor_dp_func = { + .pattern = gf119_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, - .lnk_ctl = gf110_sor_dp_lnk_ctl, - .drv_ctl = gf110_sor_dp_drv_ctl, + .lnk_ctl = gf119_sor_dp_lnk_ctl, + .drv_ctl = gf119_sor_dp_drv_ctl, }; + +int +gf119_sor_dp_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index 1e40dfe11319..029e5f16c2a8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -41,17 +41,17 @@ gm204_sor_loff(struct nvkm_output_dp *outp) void gm204_sor_magic(struct nvkm_output *outp) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nvkm_device *device = outp->disp->engine.subdev.device; const u32 soff = outp->or * 0x100; const u32 data = outp->or + 1; if (outp->info.sorconf.link & 1) - nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data); + nvkm_mask(device, 0x612308 + soff, 0x0000001f, 0x00000000 | data); if (outp->info.sorconf.link & 2) - nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data); + nvkm_mask(device, 0x612388 + soff, 0x0000001f, 0x00000010 | data); } static inline u32 -gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) +gm204_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { return lane * 0x08; } @@ -59,30 +59,33 @@ gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) static int gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 data = 0x01010101 * pattern; if (outp->base.info.sorconf.link & 1) - nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data); + nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); else - nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data); + nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); return 0; } static int gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 loff = gm204_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3); + mask |= 1 << (gm204_sor_dp_lane_map(device, i) >> 3); - nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask); - nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000); - nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000); + nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); + nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) + break; + ); return 0; } @@ -90,9 +93,9 @@ static int gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(priv); - const u32 shift = gm204_sor_dp_lane_map(priv, ln); + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + const u32 shift = gm204_sor_dp_lane_map(device, ln); const u32 loff = gm204_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; @@ -109,31 +112,32 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; + ocfg.tx_pu &= 0x0f; - data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(priv, 0x61c130 + loff); - if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) - data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); - data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift); - nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); + data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nvkm_rd32(device, 0x61c130 + loff); + if ((data[2] & 0x00000f00) < (ocfg.tx_pu << 8) || ln == 0) + data[2] = (data[2] & ~0x00000f00) | (ocfg.tx_pu << 8); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nvkm_wr32(device, 0x61c130 + loff, data[2]); + data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift); + nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; } -struct nvkm_output_dp_impl -gm204_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +gm204_sor_dp_func = { .pattern = gm204_sor_dp_pattern, .lnk_pwr = gm204_sor_dp_lnk_pwr, - .lnk_ctl = gf110_sor_dp_lnk_ctl, + .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gm204_sor_dp_drv_ctl, }; + +int +gm204_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&gm204_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index b229a311c78c..29e0d2a9a839 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -33,6 +33,7 @@ int nv50_sor_power(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; union { struct nv50_disp_sor_pwr_v0 v0; } *args = data; @@ -40,17 +41,39 @@ nv50_sor_power(NV50_DISP_MTHD_V1) u32 stat; int ret; - nv_ioctl(object, "disp sor pwr size %d\n", size); + nvif_ioctl(object, "disp sor pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor pwr vers %d state %d\n", - args->v0.version, args->v0.state); + nvif_ioctl(object, "disp sor pwr vers %d state %d\n", + args->v0.version, args->v0.state); stat = !!args->v0.state; } else return ret; - nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); - nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); - nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); - nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000); + + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) + break; + ); + nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) + break; + ); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) + break; + ); return 0; } + +static const struct nvkm_output_func +nv50_sor_output_func = { +}; + +int +nv50_sor_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&nv50_sor_output_func, disp, + index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c index c4622c7388d0..8bff95c6343f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c @@ -23,131 +23,119 @@ */ #include <subdev/vga.h> -#include <core/device.h> - u8 -nv_rdport(void *obj, int head, u16 port) +nvkm_rdport(struct nvkm_device *device, int head, u16 port) { - struct nvkm_device *device = nv_device(obj); - if (device->card_type >= NV_50) - return nv_rd08(obj, 0x601000 + port); + return nvkm_rd08(device, 0x601000 + port); if (port == 0x03c0 || port == 0x03c1 || /* AR */ port == 0x03c2 || port == 0x03da || /* INP0 */ port == 0x03d4 || port == 0x03d5) /* CR */ - return nv_rd08(obj, 0x601000 + (head * 0x2000) + port); + return nvkm_rd08(device, 0x601000 + (head * 0x2000) + port); if (port == 0x03c2 || port == 0x03cc || /* MISC */ port == 0x03c4 || port == 0x03c5 || /* SR */ port == 0x03ce || port == 0x03cf) { /* GR */ if (device->card_type < NV_40) head = 0; /* CR44 selects head */ - return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port); + return nvkm_rd08(device, 0x0c0000 + (head * 0x2000) + port); } - nv_error(obj, "unknown vga port 0x%04x\n", port); return 0x00; } void -nv_wrport(void *obj, int head, u16 port, u8 data) +nvkm_wrport(struct nvkm_device *device, int head, u16 port, u8 data) { - struct nvkm_device *device = nv_device(obj); - if (device->card_type >= NV_50) - nv_wr08(obj, 0x601000 + port, data); + nvkm_wr08(device, 0x601000 + port, data); else if (port == 0x03c0 || port == 0x03c1 || /* AR */ port == 0x03c2 || port == 0x03da || /* INP0 */ port == 0x03d4 || port == 0x03d5) /* CR */ - nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data); + nvkm_wr08(device, 0x601000 + (head * 0x2000) + port, data); else if (port == 0x03c2 || port == 0x03cc || /* MISC */ port == 0x03c4 || port == 0x03c5 || /* SR */ port == 0x03ce || port == 0x03cf) { /* GR */ if (device->card_type < NV_40) head = 0; /* CR44 selects head */ - nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data); - } else - nv_error(obj, "unknown vga port 0x%04x\n", port); + nvkm_wr08(device, 0x0c0000 + (head * 0x2000) + port, data); + } } u8 -nv_rdvgas(void *obj, int head, u8 index) +nvkm_rdvgas(struct nvkm_device *device, int head, u8 index) { - nv_wrport(obj, head, 0x03c4, index); - return nv_rdport(obj, head, 0x03c5); + nvkm_wrport(device, head, 0x03c4, index); + return nvkm_rdport(device, head, 0x03c5); } void -nv_wrvgas(void *obj, int head, u8 index, u8 value) +nvkm_wrvgas(struct nvkm_device *device, int head, u8 index, u8 value) { - nv_wrport(obj, head, 0x03c4, index); - nv_wrport(obj, head, 0x03c5, value); + nvkm_wrport(device, head, 0x03c4, index); + nvkm_wrport(device, head, 0x03c5, value); } u8 -nv_rdvgag(void *obj, int head, u8 index) +nvkm_rdvgag(struct nvkm_device *device, int head, u8 index) { - nv_wrport(obj, head, 0x03ce, index); - return nv_rdport(obj, head, 0x03cf); + nvkm_wrport(device, head, 0x03ce, index); + return nvkm_rdport(device, head, 0x03cf); } void -nv_wrvgag(void *obj, int head, u8 index, u8 value) +nvkm_wrvgag(struct nvkm_device *device, int head, u8 index, u8 value) { - nv_wrport(obj, head, 0x03ce, index); - nv_wrport(obj, head, 0x03cf, value); + nvkm_wrport(device, head, 0x03ce, index); + nvkm_wrport(device, head, 0x03cf, value); } u8 -nv_rdvgac(void *obj, int head, u8 index) +nvkm_rdvgac(struct nvkm_device *device, int head, u8 index) { - nv_wrport(obj, head, 0x03d4, index); - return nv_rdport(obj, head, 0x03d5); + nvkm_wrport(device, head, 0x03d4, index); + return nvkm_rdport(device, head, 0x03d5); } void -nv_wrvgac(void *obj, int head, u8 index, u8 value) +nvkm_wrvgac(struct nvkm_device *device, int head, u8 index, u8 value) { - nv_wrport(obj, head, 0x03d4, index); - nv_wrport(obj, head, 0x03d5, value); + nvkm_wrport(device, head, 0x03d4, index); + nvkm_wrport(device, head, 0x03d5, value); } u8 -nv_rdvgai(void *obj, int head, u16 port, u8 index) +nvkm_rdvgai(struct nvkm_device *device, int head, u16 port, u8 index) { - if (port == 0x03c4) return nv_rdvgas(obj, head, index); - if (port == 0x03ce) return nv_rdvgag(obj, head, index); - if (port == 0x03d4) return nv_rdvgac(obj, head, index); - nv_error(obj, "unknown indexed vga port 0x%04x\n", port); + if (port == 0x03c4) return nvkm_rdvgas(device, head, index); + if (port == 0x03ce) return nvkm_rdvgag(device, head, index); + if (port == 0x03d4) return nvkm_rdvgac(device, head, index); return 0x00; } void -nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) +nvkm_wrvgai(struct nvkm_device *device, int head, u16 port, u8 index, u8 value) { - if (port == 0x03c4) nv_wrvgas(obj, head, index, value); - else if (port == 0x03ce) nv_wrvgag(obj, head, index, value); - else if (port == 0x03d4) nv_wrvgac(obj, head, index, value); - else nv_error(obj, "unknown indexed vga port 0x%04x\n", port); + if (port == 0x03c4) nvkm_wrvgas(device, head, index, value); + else if (port == 0x03ce) nvkm_wrvgag(device, head, index, value); + else if (port == 0x03d4) nvkm_wrvgac(device, head, index, value); } bool -nv_lockvgac(void *obj, bool lock) +nvkm_lockvgac(struct nvkm_device *device, bool lock) { - struct nvkm_device *dev = nv_device(obj); - - bool locked = !nv_rdvgac(obj, 0, 0x1f); + bool locked = !nvkm_rdvgac(device, 0, 0x1f); u8 data = lock ? 0x99 : 0x57; - if (dev->card_type < NV_50) - nv_wrvgac(obj, 0, 0x1f, data); + if (device->card_type < NV_50) + nvkm_wrvgac(device, 0, 0x1f, data); else - nv_wrvgac(obj, 0, 0x3f, data); - if (dev->chipset == 0x11) { - if (!(nv_rd32(obj, 0x001084) & 0x10000000)) - nv_wrvgac(obj, 1, 0x1f, data); + nvkm_wrvgac(device, 0, 0x3f, data); + if (device->chipset == 0x11) { + if (!(nvkm_rd32(device, 0x001084) & 0x10000000)) + nvkm_wrvgac(device, 1, 0x1f, data); } return locked; } @@ -171,16 +159,16 @@ nv_lockvgac(void *obj, bool lock) * other values are treated as literal values to set */ u8 -nv_rdvgaowner(void *obj) +nvkm_rdvgaowner(struct nvkm_device *device) { - if (nv_device(obj)->card_type < NV_50) { - if (nv_device(obj)->chipset == 0x11) { - u32 tied = nv_rd32(obj, 0x001084) & 0x10000000; + if (device->card_type < NV_50) { + if (device->chipset == 0x11) { + u32 tied = nvkm_rd32(device, 0x001084) & 0x10000000; if (tied == 0) { - u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80; - u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01; - u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80; - u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01; + u8 slA = nvkm_rdvgac(device, 0, 0x28) & 0x80; + u8 tvA = nvkm_rdvgac(device, 0, 0x33) & 0x01; + u8 slB = nvkm_rdvgac(device, 1, 0x28) & 0x80; + u8 tvB = nvkm_rdvgac(device, 1, 0x33) & 0x01; if (slA && !tvA) return 0x00; if (slB && !tvB) return 0x03; if (slA) return 0x00; @@ -190,30 +178,28 @@ nv_rdvgaowner(void *obj) return 0x04; } - return nv_rdvgac(obj, 0, 0x44); + return nvkm_rdvgac(device, 0, 0x44); } - nv_error(obj, "rdvgaowner after nv4x\n"); return 0x00; } void -nv_wrvgaowner(void *obj, u8 select) +nvkm_wrvgaowner(struct nvkm_device *device, u8 select) { - if (nv_device(obj)->card_type < NV_50) { + if (device->card_type < NV_50) { u8 owner = (select == 1) ? 3 : select; - if (nv_device(obj)->chipset == 0x11) { + if (device->chipset == 0x11) { /* workaround hw lockup bug */ - nv_rdvgac(obj, 0, 0x1f); - nv_rdvgac(obj, 1, 0x1f); + nvkm_rdvgac(device, 0, 0x1f); + nvkm_rdvgac(device, 1, 0x1f); } - nv_wrvgac(obj, 0, 0x44, owner); + nvkm_wrvgac(device, 0, 0x44, owner); - if (nv_device(obj)->chipset == 0x11) { - nv_wrvgac(obj, 0, 0x2e, owner); - nv_wrvgac(obj, 0, 0x2e, owner); + if (device->chipset == 0x11) { + nvkm_wrvgac(device, 0, 0x2e, owner); + nvkm_wrvgac(device, 0, 0x2e, owner); } - } else - nv_error(obj, "wrvgaowner after nv4x\n"); + } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild new file mode 100644 index 000000000000..c4a2ce9b0d71 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild @@ -0,0 +1,11 @@ +nvkm-y += nvkm/engine/dma/base.o +nvkm-y += nvkm/engine/dma/nv04.o +nvkm-y += nvkm/engine/dma/nv50.o +nvkm-y += nvkm/engine/dma/gf100.o +nvkm-y += nvkm/engine/dma/gf119.o + +nvkm-y += nvkm/engine/dma/user.o +nvkm-y += nvkm/engine/dma/usernv04.o +nvkm-y += nvkm/engine/dma/usernv50.o +nvkm-y += nvkm/engine/dma/usergf100.o +nvkm-y += nvkm/engine/dma/usergf119.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c new file mode 100644 index 000000000000..9769fc0d5351 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c @@ -0,0 +1,157 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" + +#include <core/client.h> +#include <engine/fifo.h> + +#include <nvif/class.h> + +struct nvkm_dmaobj * +nvkm_dma_search(struct nvkm_dma *dma, struct nvkm_client *client, u64 object) +{ + struct rb_node *node = client->dmaroot.rb_node; + while (node) { + struct nvkm_dmaobj *dmaobj = + container_of(node, typeof(*dmaobj), rb); + if (object < dmaobj->handle) + node = node->rb_left; + else + if (object > dmaobj->handle) + node = node->rb_right; + else + return dmaobj; + } + return NULL; +} + +static int +nvkm_dma_oclass_new(struct nvkm_device *device, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_dma *dma = nvkm_dma(oclass->engine); + struct nvkm_dmaobj *dmaobj = NULL; + struct nvkm_client *client = oclass->client; + struct rb_node **ptr = &client->dmaroot.rb_node; + struct rb_node *parent = NULL; + int ret; + + ret = dma->func->class_new(dma, oclass, data, size, &dmaobj); + if (dmaobj) + *pobject = &dmaobj->object; + if (ret) + return ret; + + dmaobj->handle = oclass->object; + + while (*ptr) { + struct nvkm_dmaobj *obj = container_of(*ptr, typeof(*obj), rb); + parent = *ptr; + if (dmaobj->handle < obj->handle) + ptr = &parent->rb_left; + else + if (dmaobj->handle > obj->handle) + ptr = &parent->rb_right; + else + return -EEXIST; + } + + rb_link_node(&dmaobj->rb, parent, ptr); + rb_insert_color(&dmaobj->rb, &client->dmaroot); + return 0; +} + +static const struct nvkm_device_oclass +nvkm_dma_oclass_base = { + .ctor = nvkm_dma_oclass_new, +}; + +static int +nvkm_dma_oclass_fifo_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + return nvkm_dma_oclass_new(oclass->engine->subdev.device, + oclass, data, size, pobject); +} + +static const struct nvkm_sclass +nvkm_dma_sclass[] = { + { 0, 0, NV_DMA_FROM_MEMORY, NULL, nvkm_dma_oclass_fifo_new }, + { 0, 0, NV_DMA_TO_MEMORY, NULL, nvkm_dma_oclass_fifo_new }, + { 0, 0, NV_DMA_IN_MEMORY, NULL, nvkm_dma_oclass_fifo_new }, +}; + +static int +nvkm_dma_oclass_base_get(struct nvkm_oclass *sclass, int index, + const struct nvkm_device_oclass **class) +{ + const int count = ARRAY_SIZE(nvkm_dma_sclass); + if (index < count) { + const struct nvkm_sclass *oclass = &nvkm_dma_sclass[index]; + sclass->base = oclass[0]; + sclass->engn = oclass; + *class = &nvkm_dma_oclass_base; + return index; + } + return count; +} + +static int +nvkm_dma_oclass_fifo_get(struct nvkm_oclass *oclass, int index) +{ + const int count = ARRAY_SIZE(nvkm_dma_sclass); + if (index < count) { + oclass->base = nvkm_dma_sclass[index]; + return index; + } + return count; +} + +static void * +nvkm_dma_dtor(struct nvkm_engine *engine) +{ + return nvkm_dma(engine); +} + +static const struct nvkm_engine_func +nvkm_dma = { + .dtor = nvkm_dma_dtor, + .base.sclass = nvkm_dma_oclass_base_get, + .fifo.sclass = nvkm_dma_oclass_fifo_get, +}; + +int +nvkm_dma_new_(const struct nvkm_dma_func *func, struct nvkm_device *device, + int index, struct nvkm_dma **pdma) +{ + struct nvkm_dma *dma; + + if (!(dma = *pdma = kzalloc(sizeof(*dma), GFP_KERNEL))) + return -ENOMEM; + dma->func = func; + + return nvkm_engine_ctor(&nvkm_dma, device, index, + 0, true, &dma->engine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c new file mode 100644 index 000000000000..efec5d322179 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c @@ -0,0 +1,36 @@ +/* + * 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 "user.h" + +static const struct nvkm_dma_func +gf100_dma = { + .class_new = gf100_dmaobj_new, +}; + +int +gf100_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&gf100_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf119.c new file mode 100644 index 000000000000..34c766039aed --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf119.c @@ -0,0 +1,36 @@ +/* + * 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 "user.h" + +static const struct nvkm_dma_func +gf119_dma = { + .class_new = gf119_dmaobj_new, +}; + +int +gf119_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&gf119_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c new file mode 100644 index 000000000000..30747a0ce488 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c @@ -0,0 +1,36 @@ +/* + * 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 "user.h" + +static const struct nvkm_dma_func +nv04_dma = { + .class_new = nv04_dmaobj_new, +}; + +int +nv04_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&nv04_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c new file mode 100644 index 000000000000..77aca7b71c83 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c @@ -0,0 +1,36 @@ +/* + * 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 "user.h" + +static const struct nvkm_dma_func +nv50_dma = { + .class_new = nv50_dmaobj_new, +}; + +int +nv50_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&nv50_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h new file mode 100644 index 000000000000..deb37ee55c0b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_DMA_PRIV_H__ +#define __NVKM_DMA_PRIV_H__ +#define nvkm_dma(p) container_of((p), struct nvkm_dma, engine) +#include <engine/dma.h> + +struct nvkm_dmaobj_func { + int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, int align, + struct nvkm_gpuobj **); +}; + +int nvkm_dma_new_(const struct nvkm_dma_func *, struct nvkm_device *, + int index, struct nvkm_dma **); + +struct nvkm_dma_func { + int (*class_new)(struct nvkm_dma *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_dmaobj **); +}; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c index a2b60d86baba..45ab062661a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "user.h" #include <core/client.h> -#include <core/device.h> +#include <core/gpuobj.h> #include <subdev/fb.h> #include <subdev/instmem.h> @@ -32,56 +32,56 @@ #include <nvif/unpack.h> static int -nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, - struct nvkm_gpuobj **pgpuobj) +nvkm_dmaobj_bind(struct nvkm_object *base, struct nvkm_gpuobj *gpuobj, + int align, struct nvkm_gpuobj **pgpuobj) { - const struct nvkm_dmaeng_impl *impl = (void *) - nv_oclass(nv_object(dmaobj)->engine); - int ret = 0; - - if (nv_object(dmaobj) == parent) { /* ctor bind */ - if (nv_mclass(parent->parent) == NV_DEVICE) { - /* delayed, or no, binding */ - return 0; - } - ret = impl->bind(dmaobj, parent, pgpuobj); - if (ret == 0) - nvkm_object_ref(NULL, &parent); - return ret; - } + struct nvkm_dmaobj *dmaobj = nvkm_dmaobj(base); + return dmaobj->func->bind(dmaobj, gpuobj, align, pgpuobj); +} - return impl->bind(dmaobj, parent, pgpuobj); +static void * +nvkm_dmaobj_dtor(struct nvkm_object *base) +{ + struct nvkm_dmaobj *dmaobj = nvkm_dmaobj(base); + if (!RB_EMPTY_NODE(&dmaobj->rb)) + rb_erase(&dmaobj->rb, &dmaobj->object.client->dmaroot); + return dmaobj; } +static const struct nvkm_object_func +nvkm_dmaobj_func = { + .dtor = nvkm_dmaobj_dtor, + .bind = nvkm_dmaobj_bind, +}; + int -nvkm_dmaobj_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void **pdata, u32 *psize, - int length, void **pobject) +nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *func, struct nvkm_dma *dma, + const struct nvkm_oclass *oclass, void **pdata, u32 *psize, + struct nvkm_dmaobj *dmaobj) { union { struct nv_dma_v0 v0; } *args = *pdata; - struct nvkm_instmem *instmem = nvkm_instmem(parent); - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_device *device = nv_device(parent); - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_dmaobj *dmaobj; + struct nvkm_device *device = dma->engine.subdev.device; + struct nvkm_client *client = oclass->client; + struct nvkm_object *parent = oclass->parent; + struct nvkm_instmem *instmem = device->imem; + struct nvkm_fb *fb = device->fb; void *data = *pdata; u32 size = *psize; int ret; - ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); - dmaobj = *pobject; - if (ret) - return ret; + nvkm_object_ctor(&nvkm_dmaobj_func, oclass, &dmaobj->object); + dmaobj->func = func; + dmaobj->dma = dma; + RB_CLEAR_NODE(&dmaobj->rb); - nv_ioctl(parent, "create dma size %d\n", *psize); + nvif_ioctl(parent, "create dma size %d\n", *psize); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(parent, "create dma vers %d target %d access %d " - "start %016llx limit %016llx\n", - args->v0.version, args->v0.target, args->v0.access, - args->v0.start, args->v0.limit); + nvif_ioctl(parent, "create dma vers %d target %d access %d " + "start %016llx limit %016llx\n", + args->v0.version, args->v0.target, args->v0.access, + args->v0.start, args->v0.limit); dmaobj->target = args->v0.target; dmaobj->access = args->v0.access; dmaobj->start = args->v0.start; @@ -101,7 +101,7 @@ nvkm_dmaobj_create_(struct nvkm_object *parent, break; case NV_DMA_V0_TARGET_VRAM: if (!client->super) { - if (dmaobj->limit >= pfb->ram->size - instmem->reserved) + if (dmaobj->limit >= fb->ram->size - instmem->reserved) return -EACCES; if (device->card_type >= NV_50) return -EACCES; @@ -142,23 +142,3 @@ nvkm_dmaobj_create_(struct nvkm_object *parent, return ret; } - -int -_nvkm_dmaeng_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - const struct nvkm_dmaeng_impl *impl = (void *)oclass; - struct nvkm_dmaeng *dmaeng; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, "DMAOBJ", - "dmaobj", &dmaeng); - *pobject = nv_object(dmaeng); - if (ret) - return ret; - - nv_engine(dmaeng)->sclass = impl->sclass; - dmaeng->bind = nvkm_dmaobj_bind; - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h new file mode 100644 index 000000000000..69a7f1034024 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_DMA_USER_H__ +#define __NVKM_DMA_USER_H__ +#define nvkm_dmaobj(p) container_of((p), struct nvkm_dmaobj, object) +#include "priv.h" + +int nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *, struct nvkm_dma *, + const struct nvkm_oclass *, void **data, u32 *size, + struct nvkm_dmaobj *); + +int nv04_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); +int nv50_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); +int gf100_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); +int gf119_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c new file mode 100644 index 000000000000..13e341cc4e32 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c @@ -0,0 +1,149 @@ +/* + * 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 + */ +#define gf100_dmaobj(p) container_of((p), struct gf100_dmaobj, base) +#include "user.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <subdev/fb.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +struct gf100_dmaobj { + struct nvkm_dmaobj base; + u32 flags0; + u32 flags5; +}; + +static int +gf100_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + struct gf100_dmaobj *dmaobj = gf100_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; + int ret; + + ret = nvkm_gpuobj_new(device, 24, align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); + nvkm_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); + nvkm_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | + upper_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_wo32(*pgpuobj, 0x14, dmaobj->flags5); + nvkm_done(*pgpuobj); + } + + return ret; +} + +static const struct nvkm_dmaobj_func +gf100_dmaobj_func = { + .bind = gf100_dmaobj_bind, +}; + +int +gf100_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) +{ + union { + struct gf100_dma_v0 v0; + } *args; + struct nvkm_object *parent = oclass->parent; + struct gf100_dmaobj *dmaobj; + u32 kind, user, unkn; + int ret; + + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&gf100_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); + if (ret) + return ret; + + args = data; + + nvif_ioctl(parent, "create gf100 dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, + "create gf100 dma vers %d priv %d kind %02x\n", + args->v0.version, args->v0.priv, args->v0.kind); + kind = args->v0.kind; + user = args->v0.priv; + unkn = 0; + } else + if (size == 0) { + if (dmaobj->base.target != NV_MEM_TARGET_VM) { + kind = GF100_DMA_V0_KIND_PITCH; + user = GF100_DMA_V0_PRIV_US; + unkn = 2; + } else { + kind = GF100_DMA_V0_KIND_VM; + user = GF100_DMA_V0_PRIV_VM; + unkn = 0; + } + } else + return ret; + + if (user > 2) + return -EINVAL; + dmaobj->flags0 |= (kind << 22) | (user << 20) | oclass->base.oclass; + dmaobj->flags5 |= (unkn << 16); + + switch (dmaobj->base.target) { + case NV_MEM_TARGET_VM: + dmaobj->flags0 |= 0x00000000; + break; + case NV_MEM_TARGET_VRAM: + dmaobj->flags0 |= 0x00010000; + break; + case NV_MEM_TARGET_PCI: + dmaobj->flags0 |= 0x00020000; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + dmaobj->flags0 |= 0x00030000; + break; + default: + return -EINVAL; + } + + switch (dmaobj->base.access) { + case NV_MEM_ACCESS_VM: + break; + case NV_MEM_ACCESS_RO: + dmaobj->flags0 |= 0x00040000; + break; + case NV_MEM_ACCESS_WO: + case NV_MEM_ACCESS_RW: + dmaobj->flags0 |= 0x00080000; + break; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c new file mode 100644 index 000000000000..0e1af8b4db84 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c @@ -0,0 +1,131 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#define gf119_dmaobj(p) container_of((p), struct gf119_dmaobj, base) +#include "user.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <subdev/fb.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +struct gf119_dmaobj { + struct nvkm_dmaobj base; + u32 flags0; +}; + +static int +gf119_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + struct gf119_dmaobj *dmaobj = gf119_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; + int ret; + + ret = nvkm_gpuobj_new(device, 24, align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); + nvkm_wo32(*pgpuobj, 0x04, dmaobj->base.start >> 8); + nvkm_wo32(*pgpuobj, 0x08, dmaobj->base.limit >> 8); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_wo32(*pgpuobj, 0x14, 0x00000000); + nvkm_done(*pgpuobj); + } + + return ret; +} + +static const struct nvkm_dmaobj_func +gf119_dmaobj_func = { + .bind = gf119_dmaobj_bind, +}; + +int +gf119_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) +{ + union { + struct gf119_dma_v0 v0; + } *args; + struct nvkm_object *parent = oclass->parent; + struct gf119_dmaobj *dmaobj; + u32 kind, page; + int ret; + + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&gf119_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); + if (ret) + return ret; + + args = data; + + nvif_ioctl(parent, "create gf119 dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, + "create gf100 dma vers %d page %d kind %02x\n", + args->v0.version, args->v0.page, args->v0.kind); + kind = args->v0.kind; + page = args->v0.page; + } else + if (size == 0) { + if (dmaobj->base.target != NV_MEM_TARGET_VM) { + kind = GF119_DMA_V0_KIND_PITCH; + page = GF119_DMA_V0_PAGE_SP; + } else { + kind = GF119_DMA_V0_KIND_VM; + page = GF119_DMA_V0_PAGE_LP; + } + } else + return ret; + + if (page > 1) + return -EINVAL; + dmaobj->flags0 = (kind << 20) | (page << 6); + + switch (dmaobj->base.target) { + case NV_MEM_TARGET_VRAM: + dmaobj->flags0 |= 0x00000009; + break; + case NV_MEM_TARGET_VM: + case NV_MEM_TARGET_PCI: + case NV_MEM_TARGET_PCI_NOSNOOP: + /* XXX: don't currently know how to construct a real one + * of these. we only use them to represent pushbufs + * on these chipsets, and the classes that use them + * deal with the target themselves. + */ + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c new file mode 100644 index 000000000000..c95942ef8216 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c @@ -0,0 +1,133 @@ +/* + * 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 + */ +#define nv04_dmaobj(p) container_of((p), struct nv04_dmaobj, base) +#include "user.h" + +#include <core/gpuobj.h> +#include <subdev/fb.h> +#include <subdev/mmu/nv04.h> + +#include <nvif/class.h> + +struct nv04_dmaobj { + struct nvkm_dmaobj base; + bool clone; + u32 flags0; + u32 flags2; +}; + +static int +nv04_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + struct nv04_dmaobj *dmaobj = nv04_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; + u64 offset = dmaobj->base.start & 0xfffff000; + u64 adjust = dmaobj->base.start & 0x00000fff; + u32 length = dmaobj->base.limit - dmaobj->base.start; + int ret; + + if (dmaobj->clone) { + struct nv04_mmu *mmu = nv04_mmu(device->mmu); + struct nvkm_memory *pgt = mmu->vm->pgt[0].mem[0]; + if (!dmaobj->base.start) + return nvkm_gpuobj_wrap(pgt, pgpuobj); + nvkm_kmap(pgt); + offset = nvkm_ro32(pgt, 8 + (offset >> 10)); + offset &= 0xfffff000; + nvkm_done(pgt); + } + + ret = nvkm_gpuobj_new(device, 16, align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | (adjust << 20)); + nvkm_wo32(*pgpuobj, 0x04, length); + nvkm_wo32(*pgpuobj, 0x08, dmaobj->flags2 | offset); + nvkm_wo32(*pgpuobj, 0x0c, dmaobj->flags2 | offset); + nvkm_done(*pgpuobj); + } + + return ret; +} + +static const struct nvkm_dmaobj_func +nv04_dmaobj_func = { + .bind = nv04_dmaobj_bind, +}; + +int +nv04_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) +{ + struct nvkm_device *device = dma->engine.subdev.device; + struct nv04_dmaobj *dmaobj; + int ret; + + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&nv04_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); + if (ret) + return ret; + + if (dmaobj->base.target == NV_MEM_TARGET_VM) { + if (device->mmu->func == &nv04_mmu) + dmaobj->clone = true; + dmaobj->base.target = NV_MEM_TARGET_PCI; + dmaobj->base.access = NV_MEM_ACCESS_RW; + } + + dmaobj->flags0 = oclass->base.oclass; + switch (dmaobj->base.target) { + case NV_MEM_TARGET_VRAM: + dmaobj->flags0 |= 0x00003000; + break; + case NV_MEM_TARGET_PCI: + dmaobj->flags0 |= 0x00023000; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + dmaobj->flags0 |= 0x00033000; + break; + default: + return -EINVAL; + } + + switch (dmaobj->base.access) { + case NV_MEM_ACCESS_RO: + dmaobj->flags0 |= 0x00004000; + break; + case NV_MEM_ACCESS_WO: + dmaobj->flags0 |= 0x00008000; + case NV_MEM_ACCESS_RW: + dmaobj->flags2 |= 0x00000002; + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c new file mode 100644 index 000000000000..5b7ce313ea14 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c @@ -0,0 +1,156 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#define nv50_dmaobj(p) container_of((p), struct nv50_dmaobj, base) +#include "user.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <subdev/fb.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +struct nv50_dmaobj { + struct nvkm_dmaobj base; + u32 flags0; + u32 flags5; +}; + +static int +nv50_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + struct nv50_dmaobj *dmaobj = nv50_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; + int ret; + + ret = nvkm_gpuobj_new(device, 24, align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); + nvkm_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); + nvkm_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | + upper_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_wo32(*pgpuobj, 0x14, dmaobj->flags5); + nvkm_done(*pgpuobj); + } + + return ret; +} + +static const struct nvkm_dmaobj_func +nv50_dmaobj_func = { + .bind = nv50_dmaobj_bind, +}; + +int +nv50_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) +{ + union { + struct nv50_dma_v0 v0; + } *args; + struct nvkm_object *parent = oclass->parent; + struct nv50_dmaobj *dmaobj; + u32 user, part, comp, kind; + int ret; + + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&nv50_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); + if (ret) + return ret; + + args = data; + + nvif_ioctl(parent, "create nv50 dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create nv50 dma vers %d priv %d part %d " + "comp %d kind %02x\n", args->v0.version, + args->v0.priv, args->v0.part, args->v0.comp, + args->v0.kind); + user = args->v0.priv; + part = args->v0.part; + comp = args->v0.comp; + kind = args->v0.kind; + } else + if (size == 0) { + if (dmaobj->base.target != NV_MEM_TARGET_VM) { + user = NV50_DMA_V0_PRIV_US; + part = NV50_DMA_V0_PART_256; + comp = NV50_DMA_V0_COMP_NONE; + kind = NV50_DMA_V0_KIND_PITCH; + } else { + user = NV50_DMA_V0_PRIV_VM; + part = NV50_DMA_V0_PART_VM; + comp = NV50_DMA_V0_COMP_VM; + kind = NV50_DMA_V0_KIND_VM; + } + } else + return ret; + + if (user > 2 || part > 2 || comp > 3 || kind > 0x7f) + return -EINVAL; + dmaobj->flags0 = (comp << 29) | (kind << 22) | (user << 20) | + oclass->base.oclass; + dmaobj->flags5 = (part << 16); + + switch (dmaobj->base.target) { + case NV_MEM_TARGET_VM: + dmaobj->flags0 |= 0x00000000; + break; + case NV_MEM_TARGET_VRAM: + dmaobj->flags0 |= 0x00010000; + break; + case NV_MEM_TARGET_PCI: + dmaobj->flags0 |= 0x00020000; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + dmaobj->flags0 |= 0x00030000; + break; + default: + return -EINVAL; + } + + switch (dmaobj->base.access) { + case NV_MEM_ACCESS_VM: + break; + case NV_MEM_ACCESS_RO: + dmaobj->flags0 |= 0x00040000; + break; + case NV_MEM_ACCESS_WO: + case NV_MEM_ACCESS_RW: + dmaobj->flags0 |= 0x00080000; + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild deleted file mode 100644 index 7529632dbedb..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild +++ /dev/null @@ -1,5 +0,0 @@ -nvkm-y += nvkm/engine/dmaobj/base.o -nvkm-y += nvkm/engine/dmaobj/nv04.o -nvkm-y += nvkm/engine/dmaobj/nv50.o -nvkm-y += nvkm/engine/dmaobj/gf100.o -nvkm-y += nvkm/engine/dmaobj/gf110.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c deleted file mode 100644 index f880e5167e45..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c +++ /dev/null @@ -1,176 +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/client.h> -#include <core/gpuobj.h> -#include <subdev/fb.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -struct gf100_dmaobj_priv { - struct nvkm_dmaobj base; - u32 flags0; - u32 flags5; -}; - -static int -gf100_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, - struct nvkm_gpuobj **pgpuobj) -{ - struct gf100_dmaobj_priv *priv = (void *)dmaobj; - int ret; - - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case GT214_DISP_CORE_CHANNEL_DMA: - case GT214_DISP_BASE_CHANNEL_DMA: - case GT214_DISP_OVERLAY_CHANNEL_DMA: - break; - default: - return -EINVAL; - } - } else - return 0; - - ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); - if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj)); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 | - upper_32_bits(priv->base.start)); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, priv->flags5); - } - - return ret; -} - -static int -gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_dmaeng *dmaeng = (void *)engine; - union { - struct gf100_dma_v0 v0; - } *args; - struct gf100_dmaobj_priv *priv; - u32 kind, user, unkn; - int ret; - - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - args = data; - - nv_ioctl(parent, "create gf100 dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n", - args->v0.version, args->v0.priv, args->v0.kind); - kind = args->v0.kind; - user = args->v0.priv; - unkn = 0; - } else - if (size == 0) { - if (priv->base.target != NV_MEM_TARGET_VM) { - kind = GF100_DMA_V0_KIND_PITCH; - user = GF100_DMA_V0_PRIV_US; - unkn = 2; - } else { - kind = GF100_DMA_V0_KIND_VM; - user = GF100_DMA_V0_PRIV_VM; - unkn = 0; - } - } else - return ret; - - if (user > 2) - return -EINVAL; - priv->flags0 |= (kind << 22) | (user << 20); - priv->flags5 |= (unkn << 16); - - switch (priv->base.target) { - case NV_MEM_TARGET_VM: - priv->flags0 |= 0x00000000; - break; - case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00010000; - break; - case NV_MEM_TARGET_PCI: - priv->flags0 |= 0x00020000; - break; - case NV_MEM_TARGET_PCI_NOSNOOP: - priv->flags0 |= 0x00030000; - break; - default: - return -EINVAL; - } - - switch (priv->base.access) { - case NV_MEM_ACCESS_VM: - break; - case NV_MEM_ACCESS_RO: - priv->flags0 |= 0x00040000; - break; - case NV_MEM_ACCESS_WO: - case NV_MEM_ACCESS_RW: - priv->flags0 |= 0x00080000; - break; - } - - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); -} - -static struct nvkm_ofuncs -gf100_dmaobj_ofuncs = { - .ctor = gf100_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -static struct nvkm_oclass -gf100_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &gf100_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &gf100_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &gf100_dmaobj_ofuncs }, - {} -}; - -struct nvkm_oclass * -gf100_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = gf100_dmaeng_sclass, - .bind = gf100_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c deleted file mode 100644 index bf8f0f20976c..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c +++ /dev/null @@ -1,165 +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/client.h> -#include <core/gpuobj.h> -#include <subdev/fb.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -struct gf110_dmaobj_priv { - struct nvkm_dmaobj base; - u32 flags0; -}; - -static int -gf110_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, - struct nvkm_gpuobj **pgpuobj) -{ - struct gf110_dmaobj_priv *priv = (void *)dmaobj; - int ret; - - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case GF110_DISP_CORE_CHANNEL_DMA: - case GK104_DISP_CORE_CHANNEL_DMA: - case GK110_DISP_CORE_CHANNEL_DMA: - case GM107_DISP_CORE_CHANNEL_DMA: - case GM204_DISP_CORE_CHANNEL_DMA: - case GF110_DISP_BASE_CHANNEL_DMA: - case GK104_DISP_BASE_CHANNEL_DMA: - case GK110_DISP_BASE_CHANNEL_DMA: - case GF110_DISP_OVERLAY_CONTROL_DMA: - case GK104_DISP_OVERLAY_CONTROL_DMA: - break; - default: - return -EINVAL; - } - } else - return 0; - - ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); - if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0); - nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8); - nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8); - nv_wo32(*pgpuobj, 0x0c, 0x00000000); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, 0x00000000); - } - - return ret; -} - -static int -gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_dmaeng *dmaeng = (void *)engine; - union { - struct gf110_dma_v0 v0; - } *args; - struct gf110_dmaobj_priv *priv; - u32 kind, page; - int ret; - - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - args = data; - - nv_ioctl(parent, "create gf110 dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n", - args->v0.version, args->v0.page, args->v0.kind); - kind = args->v0.kind; - page = args->v0.page; - } else - if (size == 0) { - if (priv->base.target != NV_MEM_TARGET_VM) { - kind = GF110_DMA_V0_KIND_PITCH; - page = GF110_DMA_V0_PAGE_SP; - } else { - kind = GF110_DMA_V0_KIND_VM; - page = GF110_DMA_V0_PAGE_LP; - } - } else - return ret; - - if (page > 1) - return -EINVAL; - priv->flags0 = (kind << 20) | (page << 6); - - switch (priv->base.target) { - case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00000009; - break; - case NV_MEM_TARGET_VM: - case NV_MEM_TARGET_PCI: - case NV_MEM_TARGET_PCI_NOSNOOP: - /* XXX: don't currently know how to construct a real one - * of these. we only use them to represent pushbufs - * on these chipsets, and the classes that use them - * deal with the target themselves. - */ - break; - default: - return -EINVAL; - } - - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); -} - -static struct nvkm_ofuncs -gf110_dmaobj_ofuncs = { - .ctor = gf110_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -static struct nvkm_oclass -gf110_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &gf110_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &gf110_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &gf110_dmaobj_ofuncs }, - {} -}; - -struct nvkm_oclass * -gf110_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = gf110_dmaeng_sclass, - .bind = gf110_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c deleted file mode 100644 index b4379c2a2fb5..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c +++ /dev/null @@ -1,163 +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/gpuobj.h> -#include <subdev/fb.h> -#include <subdev/mmu/nv04.h> - -#include <nvif/class.h> - -struct nv04_dmaobj_priv { - struct nvkm_dmaobj base; - bool clone; - u32 flags0; - u32 flags2; -}; - -static int -nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, - struct nvkm_gpuobj **pgpuobj) -{ - struct nv04_dmaobj_priv *priv = (void *)dmaobj; - struct nvkm_gpuobj *gpuobj; - u64 offset = priv->base.start & 0xfffff000; - u64 adjust = priv->base.start & 0x00000fff; - u32 length = priv->base.limit - priv->base.start; - int ret; - - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case NV03_CHANNEL_DMA: - case NV10_CHANNEL_DMA: - case NV17_CHANNEL_DMA: - case NV40_CHANNEL_DMA: - break; - default: - return -EINVAL; - } - } - - if (priv->clone) { - struct nv04_mmu_priv *mmu = nv04_mmu(dmaobj); - struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0]; - if (!dmaobj->start) - return nvkm_gpuobj_dup(parent, pgt, pgpuobj); - offset = nv_ro32(pgt, 8 + (offset >> 10)); - offset &= 0xfffff000; - } - - ret = nvkm_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); - *pgpuobj = gpuobj; - if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20)); - nv_wo32(*pgpuobj, 0x04, length); - nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset); - nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset); - } - - return ret; -} - -static int -nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_dmaeng *dmaeng = (void *)engine; - struct nv04_mmu_priv *mmu = nv04_mmu(engine); - struct nv04_dmaobj_priv *priv; - int ret; - - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); - if (ret || (ret = -ENOSYS, size)) - return ret; - - if (priv->base.target == NV_MEM_TARGET_VM) { - if (nv_object(mmu)->oclass == &nv04_mmu_oclass) - priv->clone = true; - priv->base.target = NV_MEM_TARGET_PCI; - priv->base.access = NV_MEM_ACCESS_RW; - } - - priv->flags0 = nv_mclass(priv); - switch (priv->base.target) { - case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00003000; - break; - case NV_MEM_TARGET_PCI: - priv->flags0 |= 0x00023000; - break; - case NV_MEM_TARGET_PCI_NOSNOOP: - priv->flags0 |= 0x00033000; - break; - default: - return -EINVAL; - } - - switch (priv->base.access) { - case NV_MEM_ACCESS_RO: - priv->flags0 |= 0x00004000; - break; - case NV_MEM_ACCESS_WO: - priv->flags0 |= 0x00008000; - case NV_MEM_ACCESS_RW: - priv->flags2 |= 0x00000002; - break; - default: - return -EINVAL; - } - - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); -} - -static struct nvkm_ofuncs -nv04_dmaobj_ofuncs = { - .ctor = nv04_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -static struct nvkm_oclass -nv04_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs }, - {} -}; - -struct nvkm_oclass * -nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = nv04_dmaeng_sclass, - .bind = nv04_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c deleted file mode 100644 index 4d3c828fe0e6..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c +++ /dev/null @@ -1,195 +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/client.h> -#include <core/gpuobj.h> -#include <subdev/fb.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -struct nv50_dmaobj_priv { - struct nvkm_dmaobj base; - u32 flags0; - u32 flags5; -}; - -static int -nv50_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, - struct nvkm_gpuobj **pgpuobj) -{ - struct nv50_dmaobj_priv *priv = (void *)dmaobj; - int ret; - - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case NV40_CHANNEL_DMA: - case NV50_CHANNEL_GPFIFO: - case G82_CHANNEL_GPFIFO: - case NV50_DISP_CORE_CHANNEL_DMA: - case G82_DISP_CORE_CHANNEL_DMA: - case GT206_DISP_CORE_CHANNEL_DMA: - case GT200_DISP_CORE_CHANNEL_DMA: - case GT214_DISP_CORE_CHANNEL_DMA: - case NV50_DISP_BASE_CHANNEL_DMA: - case G82_DISP_BASE_CHANNEL_DMA: - case GT200_DISP_BASE_CHANNEL_DMA: - case GT214_DISP_BASE_CHANNEL_DMA: - case NV50_DISP_OVERLAY_CHANNEL_DMA: - case G82_DISP_OVERLAY_CHANNEL_DMA: - case GT200_DISP_OVERLAY_CHANNEL_DMA: - case GT214_DISP_OVERLAY_CHANNEL_DMA: - break; - default: - return -EINVAL; - } - } - - ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); - if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj)); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 | - upper_32_bits(priv->base.start)); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, priv->flags5); - } - - return ret; -} - -static int -nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_dmaeng *dmaeng = (void *)engine; - union { - struct nv50_dma_v0 v0; - } *args; - struct nv50_dmaobj_priv *priv; - u32 user, part, comp, kind; - int ret; - - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - args = data; - - nv_ioctl(parent, "create nv50 dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d " - "comp %d kind %02x\n", args->v0.version, - args->v0.priv, args->v0.part, args->v0.comp, - args->v0.kind); - user = args->v0.priv; - part = args->v0.part; - comp = args->v0.comp; - kind = args->v0.kind; - } else - if (size == 0) { - if (priv->base.target != NV_MEM_TARGET_VM) { - user = NV50_DMA_V0_PRIV_US; - part = NV50_DMA_V0_PART_256; - comp = NV50_DMA_V0_COMP_NONE; - kind = NV50_DMA_V0_KIND_PITCH; - } else { - user = NV50_DMA_V0_PRIV_VM; - part = NV50_DMA_V0_PART_VM; - comp = NV50_DMA_V0_COMP_VM; - kind = NV50_DMA_V0_KIND_VM; - } - } else - return ret; - - if (user > 2 || part > 2 || comp > 3 || kind > 0x7f) - return -EINVAL; - priv->flags0 = (comp << 29) | (kind << 22) | (user << 20); - priv->flags5 = (part << 16); - - switch (priv->base.target) { - case NV_MEM_TARGET_VM: - priv->flags0 |= 0x00000000; - break; - case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00010000; - break; - case NV_MEM_TARGET_PCI: - priv->flags0 |= 0x00020000; - break; - case NV_MEM_TARGET_PCI_NOSNOOP: - priv->flags0 |= 0x00030000; - break; - default: - return -EINVAL; - } - - switch (priv->base.access) { - case NV_MEM_ACCESS_VM: - break; - case NV_MEM_ACCESS_RO: - priv->flags0 |= 0x00040000; - break; - case NV_MEM_ACCESS_WO: - case NV_MEM_ACCESS_RW: - priv->flags0 |= 0x00080000; - break; - default: - return -EINVAL; - } - - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); -} - -static struct nvkm_ofuncs -nv50_dmaobj_ofuncs = { - .ctor = nv50_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -static struct nvkm_oclass -nv50_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs }, - {} -}; - -struct nvkm_oclass * -nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = nv50_dmaeng_sclass, - .bind = nv50_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h deleted file mode 100644 index 44ae8a0ca65c..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NVKM_DMAOBJ_PRIV_H__ -#define __NVKM_DMAOBJ_PRIV_H__ -#include <engine/dmaobj.h> - -#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \ - nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d) - -int nvkm_dmaobj_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void **, u32 *, - int, void **); -#define _nvkm_dmaobj_dtor nvkm_object_destroy -#define _nvkm_dmaobj_init nvkm_object_init -#define _nvkm_dmaobj_fini nvkm_object_fini - -int _nvkm_dmaeng_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_dmaeng_dtor _nvkm_engine_dtor -#define _nvkm_dmaeng_init _nvkm_engine_init -#define _nvkm_dmaeng_fini _nvkm_engine_fini - -struct nvkm_dmaeng_impl { - struct nvkm_oclass base; - struct nvkm_oclass *sclass; - int (*bind)(struct nvkm_dmaobj *, struct nvkm_object *, - struct nvkm_gpuobj **); -}; -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 30958c19e61d..74000602fbb1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -21,40 +21,95 @@ */ #include <engine/falcon.h> -#include <core/device.h> +#include <core/gpuobj.h> #include <subdev/timer.h> +#include <engine/fifo.h> -void -nvkm_falcon_intr(struct nvkm_subdev *subdev) +static int +nvkm_falcon_oclass_get(struct nvkm_oclass *oclass, int index) { - struct nvkm_falcon *falcon = (void *)subdev; - u32 dispatch = nv_ro32(falcon, 0x01c); - u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); + struct nvkm_falcon *falcon = nvkm_falcon(oclass->engine); + int c = 0; + + while (falcon->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = falcon->func->sclass[index]; + return index; + } + } + + return c; +} + +static int +nvkm_falcon_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + return nvkm_gpuobj_new(object->engine->subdev.device, 256, + align, true, parent, pgpuobj); +} + +static const struct nvkm_object_func +nvkm_falcon_cclass = { + .bind = nvkm_falcon_cclass_bind, +}; + +static void +nvkm_falcon_intr(struct nvkm_engine *engine) +{ + struct nvkm_falcon *falcon = nvkm_falcon(engine); + struct nvkm_subdev *subdev = &falcon->engine.subdev; + struct nvkm_device *device = subdev->device; + const u32 base = falcon->addr; + u32 dest = nvkm_rd32(device, base + 0x01c); + u32 intr = nvkm_rd32(device, base + 0x008) & dest & ~(dest >> 16); + u32 inst = nvkm_rd32(device, base + 0x050) & 0x3fffffff; + struct nvkm_fifo_chan *chan; + unsigned long flags; + + chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + + if (intr & 0x00000040) { + if (falcon->func->intr) { + falcon->func->intr(falcon, chan); + nvkm_wr32(device, base + 0x004, 0x00000040); + intr &= ~0x00000040; + } + } if (intr & 0x00000010) { - nv_debug(falcon, "ucode halted\n"); - nv_wo32(falcon, 0x004, 0x00000010); + nvkm_debug(subdev, "ucode halted\n"); + nvkm_wr32(device, base + 0x004, 0x00000010); intr &= ~0x00000010; } if (intr) { - nv_error(falcon, "unhandled intr 0x%08x\n", intr); - nv_wo32(falcon, 0x004, intr); + nvkm_error(subdev, "intr %08x\n", intr); + nvkm_wr32(device, base + 0x004, intr); } -} -u32 -_nvkm_falcon_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_falcon *falcon = (void *)object; - return nv_rd32(falcon, falcon->addr + addr); + nvkm_fifo_chan_put(device->fifo, flags, &chan); } -void -_nvkm_falcon_wr32(struct nvkm_object *object, u64 addr, u32 data) +static int +nvkm_falcon_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_falcon *falcon = (void *)object; - nv_wr32(falcon, falcon->addr + addr, data); + struct nvkm_falcon *falcon = nvkm_falcon(engine); + struct nvkm_device *device = falcon->engine.subdev.device; + const u32 base = falcon->addr; + + if (!suspend) { + nvkm_memory_del(&falcon->core); + if (falcon->external) { + vfree(falcon->data.data); + vfree(falcon->code.data); + falcon->code.data = NULL; + } + } + + nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); + nvkm_wr32(device, base + 0x014, 0xffffffff); + return 0; } static void * @@ -67,51 +122,66 @@ vmemdup(const void *src, size_t len) return p; } -int -_nvkm_falcon_init(struct nvkm_object *object) +static int +nvkm_falcon_oneinit(struct nvkm_engine *engine) { - struct nvkm_device *device = nv_device(object); - struct nvkm_falcon *falcon = (void *)object; - const struct firmware *fw; - char name[32] = "internal"; - int ret, i; + struct nvkm_falcon *falcon = nvkm_falcon(engine); + struct nvkm_subdev *subdev = &falcon->engine.subdev; + struct nvkm_device *device = subdev->device; + const u32 base = falcon->addr; u32 caps; - /* enable engine, and determine its capabilities */ - ret = nvkm_engine_init(&falcon->base); - if (ret) - return ret; - + /* determine falcon capabilities */ if (device->chipset < 0xa3 || device->chipset == 0xaa || device->chipset == 0xac) { falcon->version = 0; falcon->secret = (falcon->addr == 0x087000) ? 1 : 0; } else { - caps = nv_ro32(falcon, 0x12c); + caps = nvkm_rd32(device, base + 0x12c); falcon->version = (caps & 0x0000000f); falcon->secret = (caps & 0x00000030) >> 4; } - caps = nv_ro32(falcon, 0x108); + caps = nvkm_rd32(device, base + 0x108); falcon->code.limit = (caps & 0x000001ff) << 8; falcon->data.limit = (caps & 0x0003fe00) >> 1; - nv_debug(falcon, "falcon version: %d\n", falcon->version); - nv_debug(falcon, "secret level: %d\n", falcon->secret); - nv_debug(falcon, "code limit: %d\n", falcon->code.limit); - nv_debug(falcon, "data limit: %d\n", falcon->data.limit); + nvkm_debug(subdev, "falcon version: %d\n", falcon->version); + nvkm_debug(subdev, "secret level: %d\n", falcon->secret); + nvkm_debug(subdev, "code limit: %d\n", falcon->code.limit); + nvkm_debug(subdev, "data limit: %d\n", falcon->data.limit); + return 0; +} + +static int +nvkm_falcon_init(struct nvkm_engine *engine) +{ + struct nvkm_falcon *falcon = nvkm_falcon(engine); + struct nvkm_subdev *subdev = &falcon->engine.subdev; + struct nvkm_device *device = subdev->device; + const struct firmware *fw; + char name[32] = "internal"; + const u32 base = falcon->addr; + int ret, i; /* wait for 'uc halted' to be signalled before continuing */ if (falcon->secret && falcon->version < 4) { - if (!falcon->version) - nv_wait(falcon, 0x008, 0x00000010, 0x00000010); - else - nv_wait(falcon, 0x180, 0x80000000, 0); - nv_wo32(falcon, 0x004, 0x00000010); + if (!falcon->version) { + nvkm_msec(device, 2000, + if (nvkm_rd32(device, base + 0x008) & 0x00000010) + break; + ); + } else { + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, base + 0x180) & 0x80000000)) + break; + ); + } + nvkm_wr32(device, base + 0x004, 0x00000010); } /* disable all interrupts */ - nv_wo32(falcon, 0x014, 0xffffffff); + nvkm_wr32(device, base + 0x014, 0xffffffff); /* no default ucode provided by the engine implementation, try and * locate a "self-bootstrapping" firmware image for the engine @@ -120,7 +190,7 @@ _nvkm_falcon_init(struct nvkm_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret == 0) { falcon->code.data = vmemdup(fw->data, fw->size); falcon->code.size = fw->size; @@ -139,10 +209,10 @@ _nvkm_falcon_init(struct nvkm_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret) { - nv_error(falcon, "unable to load firmware data\n"); - return ret; + nvkm_error(subdev, "unable to load firmware data\n"); + return -ENODEV; } falcon->data.data = vmemdup(fw->data, fw->size); @@ -154,10 +224,10 @@ _nvkm_falcon_init(struct nvkm_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret) { - nv_error(falcon, "unable to load firmware code\n"); - return ret; + nvkm_error(subdev, "unable to load firmware code\n"); + return -ENODEV; } falcon->code.data = vmemdup(fw->data, fw->size); @@ -167,111 +237,117 @@ _nvkm_falcon_init(struct nvkm_object *object) return -ENOMEM; } - nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ? - "static code/data segments" : "self-bootstrapping"); + nvkm_debug(subdev, "firmware: %s (%s)\n", name, falcon->data.data ? + "static code/data segments" : "self-bootstrapping"); /* ensure any "self-bootstrapping" firmware image is in vram */ if (!falcon->data.data && !falcon->core) { - ret = nvkm_gpuobj_new(object->parent, NULL, falcon->code.size, - 256, 0, &falcon->core); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + falcon->code.size, 256, false, + &falcon->core); if (ret) { - nv_error(falcon, "core allocation failed, %d\n", ret); + nvkm_error(subdev, "core allocation failed, %d\n", ret); return ret; } + nvkm_kmap(falcon->core); for (i = 0; i < falcon->code.size; i += 4) - nv_wo32(falcon->core, i, falcon->code.data[i / 4]); + nvkm_wo32(falcon->core, i, falcon->code.data[i / 4]); + nvkm_done(falcon->core); } /* upload firmware bootloader (or the full code segments) */ if (falcon->core) { + u64 addr = nvkm_memory_addr(falcon->core); if (device->card_type < NV_C0) - nv_wo32(falcon, 0x618, 0x04000000); + nvkm_wr32(device, base + 0x618, 0x04000000); else - nv_wo32(falcon, 0x618, 0x00000114); - nv_wo32(falcon, 0x11c, 0); - nv_wo32(falcon, 0x110, falcon->core->addr >> 8); - nv_wo32(falcon, 0x114, 0); - nv_wo32(falcon, 0x118, 0x00006610); + nvkm_wr32(device, base + 0x618, 0x00000114); + nvkm_wr32(device, base + 0x11c, 0); + nvkm_wr32(device, base + 0x110, addr >> 8); + nvkm_wr32(device, base + 0x114, 0); + nvkm_wr32(device, base + 0x118, 0x00006610); } else { if (falcon->code.size > falcon->code.limit || falcon->data.size > falcon->data.limit) { - nv_error(falcon, "ucode exceeds falcon limit(s)\n"); + nvkm_error(subdev, "ucode exceeds falcon limit(s)\n"); return -EINVAL; } if (falcon->version < 3) { - nv_wo32(falcon, 0xff8, 0x00100000); + nvkm_wr32(device, base + 0xff8, 0x00100000); for (i = 0; i < falcon->code.size / 4; i++) - nv_wo32(falcon, 0xff4, falcon->code.data[i]); + nvkm_wr32(device, base + 0xff4, falcon->code.data[i]); } else { - nv_wo32(falcon, 0x180, 0x01000000); + nvkm_wr32(device, base + 0x180, 0x01000000); for (i = 0; i < falcon->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wo32(falcon, 0x188, i >> 6); - nv_wo32(falcon, 0x184, falcon->code.data[i]); + nvkm_wr32(device, base + 0x188, i >> 6); + nvkm_wr32(device, base + 0x184, falcon->code.data[i]); } } } /* upload data segment (if necessary), zeroing the remainder */ if (falcon->version < 3) { - nv_wo32(falcon, 0xff8, 0x00000000); + nvkm_wr32(device, base + 0xff8, 0x00000000); for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) - nv_wo32(falcon, 0xff4, falcon->data.data[i]); + nvkm_wr32(device, base + 0xff4, falcon->data.data[i]); for (; i < falcon->data.limit; i += 4) - nv_wo32(falcon, 0xff4, 0x00000000); + nvkm_wr32(device, base + 0xff4, 0x00000000); } else { - nv_wo32(falcon, 0x1c0, 0x01000000); + nvkm_wr32(device, base + 0x1c0, 0x01000000); for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) - nv_wo32(falcon, 0x1c4, falcon->data.data[i]); + nvkm_wr32(device, base + 0x1c4, falcon->data.data[i]); for (; i < falcon->data.limit / 4; i++) - nv_wo32(falcon, 0x1c4, 0x00000000); + nvkm_wr32(device, base + 0x1c4, 0x00000000); } /* start it running */ - nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */ - nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */ - nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */ - nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */ + nvkm_wr32(device, base + 0x10c, 0x00000001); /* BLOCK_ON_FIFO */ + nvkm_wr32(device, base + 0x104, 0x00000000); /* ENTRY */ + nvkm_wr32(device, base + 0x100, 0x00000002); /* TRIGGER */ + nvkm_wr32(device, base + 0x048, 0x00000003); /* FIFO | CHSW */ + + if (falcon->func->init) + falcon->func->init(falcon); return 0; } -int -_nvkm_falcon_fini(struct nvkm_object *object, bool suspend) +static void * +nvkm_falcon_dtor(struct nvkm_engine *engine) { - struct nvkm_falcon *falcon = (void *)object; - - if (!suspend) { - nvkm_gpuobj_ref(NULL, &falcon->core); - if (falcon->external) { - vfree(falcon->data.data); - vfree(falcon->code.data); - falcon->code.data = NULL; - } - } - - nv_mo32(falcon, 0x048, 0x00000003, 0x00000000); - nv_wo32(falcon, 0x014, 0xffffffff); - - return nvkm_engine_fini(&falcon->base, suspend); + return nvkm_falcon(engine); } +static const struct nvkm_engine_func +nvkm_falcon = { + .dtor = nvkm_falcon_dtor, + .oneinit = nvkm_falcon_oneinit, + .init = nvkm_falcon_init, + .fini = nvkm_falcon_fini, + .intr = nvkm_falcon_intr, + .fifo.sclass = nvkm_falcon_oclass_get, + .cclass = &nvkm_falcon_cclass, +}; + int -nvkm_falcon_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 addr, bool enable, - const char *iname, const char *fname, - int length, void **pobject) +nvkm_falcon_new_(const struct nvkm_falcon_func *func, + struct nvkm_device *device, int index, bool enable, + u32 addr, struct nvkm_engine **pengine) { struct nvkm_falcon *falcon; - int ret; - - ret = nvkm_engine_create_(parent, engine, oclass, enable, iname, - fname, length, pobject); - falcon = *pobject; - if (ret) - return ret; + if (!(falcon = kzalloc(sizeof(*falcon), GFP_KERNEL))) + return -ENOMEM; + falcon->func = func; falcon->addr = addr; - return 0; + falcon->code.data = func->code.data; + falcon->code.size = func->code.size; + falcon->data.data = func->data.data; + falcon->data.size = func->data.size; + *pengine = &falcon->engine; + + return nvkm_engine_ctor(&nvkm_falcon, device, index, func->pmc_enable, + enable, &falcon->engine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 42891cb71ea3..74993c144a84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -7,6 +7,24 @@ nvkm-y += nvkm/engine/fifo/nv50.o nvkm-y += nvkm/engine/fifo/g84.o nvkm-y += nvkm/engine/fifo/gf100.o nvkm-y += nvkm/engine/fifo/gk104.o -nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gk208.o +nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gm204.o +nvkm-y += nvkm/engine/fifo/gm20b.o + +nvkm-y += nvkm/engine/fifo/chan.o +nvkm-y += nvkm/engine/fifo/channv50.o +nvkm-y += nvkm/engine/fifo/chang84.o + +nvkm-y += nvkm/engine/fifo/dmanv04.o +nvkm-y += nvkm/engine/fifo/dmanv10.o +nvkm-y += nvkm/engine/fifo/dmanv17.o +nvkm-y += nvkm/engine/fifo/dmanv40.o +nvkm-y += nvkm/engine/fifo/dmanv50.o +nvkm-y += nvkm/engine/fifo/dmag84.o + +nvkm-y += nvkm/engine/fifo/gpfifonv50.o +nvkm-y += nvkm/engine/fifo/gpfifog84.o +nvkm-y += nvkm/engine/fifo/gpfifogf100.o +nvkm-y += nvkm/engine/fifo/gpfifogk104.o +nvkm-y += nvkm/engine/fifo/gpfifogm204.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index fa223f88d25e..1fbbfbe6ca9c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -21,156 +21,108 @@ * * Authors: Ben Skeggs */ -#include <engine/fifo.h> +#include "priv.h" +#include "chan.h" #include <core/client.h> -#include <core/device.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <core/notify.h> -#include <engine/dmaobj.h> -#include <nvif/class.h> #include <nvif/event.h> #include <nvif/unpack.h> -static int -nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) +void +nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags) { - if (size == 0) { - notify->size = 0; - notify->types = 1; - notify->index = 0; - return 0; - } - return -ENOSYS; + return fifo->func->pause(fifo, flags); } -static const struct nvkm_event_func -nvkm_fifo_event_func = { - .ctor = nvkm_fifo_event_ctor, -}; - -int -nvkm_fifo_channel_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - int bar, u32 addr, u32 size, u32 pushbuf, - u64 engmask, int len, void **ptr) +void +nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags) { - struct nvkm_device *device = nv_device(engine); - struct nvkm_fifo *priv = (void *)engine; - struct nvkm_fifo_chan *chan; - struct nvkm_dmaeng *dmaeng; - unsigned long flags; - int ret; - - /* create base object class */ - ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, - engmask, len, ptr); - chan = *ptr; - if (ret) - return ret; + return fifo->func->start(fifo, flags); +} - /* validate dma object representing push buffer */ - chan->pushdma = (void *)nvkm_handle_ref(parent, pushbuf); - if (!chan->pushdma) - return -ENOENT; - - dmaeng = (void *)chan->pushdma->base.engine; - switch (chan->pushdma->base.oclass->handle) { - case NV_DMA_FROM_MEMORY: - case NV_DMA_IN_MEMORY: - break; - default: - return -EINVAL; +void +nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, + struct nvkm_fifo_chan **pchan) +{ + struct nvkm_fifo_chan *chan = *pchan; + if (likely(chan)) { + *pchan = NULL; + spin_unlock_irqrestore(&fifo->lock, flags); } +} - ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu); - if (ret) - return ret; - - /* find a free fifo channel */ - spin_lock_irqsave(&priv->lock, flags); - for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) { - if (!priv->channel[chan->chid]) { - priv->channel[chan->chid] = nv_object(chan); - break; +struct nvkm_fifo_chan * +nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags) +{ + struct nvkm_fifo_chan *chan; + unsigned long flags; + spin_lock_irqsave(&fifo->lock, flags); + list_for_each_entry(chan, &fifo->chan, head) { + if (chan->inst->addr == inst) { + list_del(&chan->head); + list_add(&chan->head, &fifo->chan); + *rflags = flags; + return chan; } } - spin_unlock_irqrestore(&priv->lock, flags); - - if (chan->chid == priv->max) { - nv_error(priv, "no free channels\n"); - return -ENOSPC; - } - - chan->addr = nv_device_resource_start(device, bar) + - addr + size * chan->chid; - chan->size = size; - nvkm_event_send(&priv->cevent, 1, 0, NULL, 0); - return 0; + spin_unlock_irqrestore(&fifo->lock, flags); + return NULL; } -void -nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan) +struct nvkm_fifo_chan * +nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags) { - struct nvkm_fifo *priv = (void *)nv_object(chan)->engine; + struct nvkm_fifo_chan *chan; unsigned long flags; - - if (chan->user) - iounmap(chan->user); - - spin_lock_irqsave(&priv->lock, flags); - priv->channel[chan->chid] = NULL; - spin_unlock_irqrestore(&priv->lock, flags); - - nvkm_gpuobj_ref(NULL, &chan->pushgpu); - nvkm_object_ref(NULL, (struct nvkm_object **)&chan->pushdma); - nvkm_namedb_destroy(&chan->namedb); + spin_lock_irqsave(&fifo->lock, flags); + list_for_each_entry(chan, &fifo->chan, head) { + if (chan->chid == chid) { + list_del(&chan->head); + list_add(&chan->head, &fifo->chan); + *rflags = flags; + return chan; + } + } + spin_unlock_irqrestore(&fifo->lock, flags); + return NULL; } -void -_nvkm_fifo_channel_dtor(struct nvkm_object *object) +static int +nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size, + struct nvkm_notify *notify) { - struct nvkm_fifo_chan *chan = (void *)object; - nvkm_fifo_channel_destroy(chan); + if (size == 0) { + notify->size = 0; + notify->types = 1; + notify->index = 0; + return 0; + } + return -ENOSYS; } -int -_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size) -{ - struct nvkm_fifo_chan *chan = (void *)object; - *addr = chan->addr; - *size = chan->size; - return 0; -} +static const struct nvkm_event_func +nvkm_fifo_event_func = { + .ctor = nvkm_fifo_event_ctor, +}; -u32 -_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr) +static void +nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { - struct nvkm_fifo_chan *chan = (void *)object; - if (unlikely(!chan->user)) { - chan->user = ioremap(chan->addr, chan->size); - if (WARN_ON_ONCE(chan->user == NULL)) - return 0; - } - return ioread32_native(chan->user + addr); + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + fifo->func->uevent_fini(fifo); } -void -_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data) +static void +nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index) { - struct nvkm_fifo_chan *chan = (void *)object; - if (unlikely(!chan->user)) { - chan->user = ioremap(chan->addr, chan->size); - if (WARN_ON_ONCE(chan->user == NULL)) - return; - } - iowrite32_native(data, chan->user + addr); + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + fifo->func->uevent_init(fifo); } -int +static int nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) { @@ -188,6 +140,13 @@ nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, return ret; } +static const struct nvkm_event_func +nvkm_fifo_uevent_func = { + .ctor = nvkm_fifo_uevent_ctor, + .init = nvkm_fifo_uevent_init, + .fini = nvkm_fifo_uevent_fini, +}; + void nvkm_fifo_uevent(struct nvkm_fifo *fifo) { @@ -196,87 +155,123 @@ nvkm_fifo_uevent(struct nvkm_fifo *fifo) nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); } -int -_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type, - struct nvkm_event **event) +static int +nvkm_fifo_class_new(struct nvkm_device *device, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { - struct nvkm_fifo *fifo = (void *)object->engine; - switch (type) { - case G82_CHANNEL_DMA_V0_NTFY_UEVENT: - if (nv_mclass(object) >= G82_CHANNEL_DMA) { - *event = &fifo->uevent; - return 0; - } - break; - default: - break; - } - return -EINVAL; + const struct nvkm_fifo_chan_oclass *sclass = oclass->engn; + struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); + return sclass->ctor(fifo, oclass, data, size, pobject); } +static const struct nvkm_device_oclass +nvkm_fifo_class = { + .ctor = nvkm_fifo_class_new, +}; + static int -nvkm_fifo_chid(struct nvkm_fifo *priv, struct nvkm_object *object) +nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, + const struct nvkm_device_oclass **class) { - int engidx = nv_hclass(priv) & 0xff; - - while (object && object->parent) { - if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) && - (nv_hclass(object->parent) & 0xff) == engidx) - return nvkm_fifo_chan(object)->chid; - object = object->parent; + struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); + const struct nvkm_fifo_chan_oclass *sclass; + int c = 0; + + while ((sclass = fifo->func->chan[c])) { + if (c++ == index) { + oclass->base = sclass->base; + oclass->engn = sclass; + *class = &nvkm_fifo_class; + return 0; + } } - return -1; + return c; } -const char * -nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid) +static void +nvkm_fifo_intr(struct nvkm_engine *engine) { - struct nvkm_fifo_chan *chan = NULL; - unsigned long flags; + struct nvkm_fifo *fifo = nvkm_fifo(engine); + fifo->func->intr(fifo); +} - spin_lock_irqsave(&fifo->lock, flags); - if (chid >= fifo->min && chid <= fifo->max) - chan = (void *)fifo->channel[chid]; - spin_unlock_irqrestore(&fifo->lock, flags); +static int +nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend) +{ + struct nvkm_fifo *fifo = nvkm_fifo(engine); + if (fifo->func->fini) + fifo->func->fini(fifo); + return 0; +} - return nvkm_client_name(chan); +static int +nvkm_fifo_oneinit(struct nvkm_engine *engine) +{ + struct nvkm_fifo *fifo = nvkm_fifo(engine); + if (fifo->func->oneinit) + return fifo->func->oneinit(fifo); + return 0; } -void -nvkm_fifo_destroy(struct nvkm_fifo *priv) +static int +nvkm_fifo_init(struct nvkm_engine *engine) { - kfree(priv->channel); - nvkm_event_fini(&priv->uevent); - nvkm_event_fini(&priv->cevent); - nvkm_engine_destroy(&priv->base); + struct nvkm_fifo *fifo = nvkm_fifo(engine); + fifo->func->init(fifo); + return 0; } +static void * +nvkm_fifo_dtor(struct nvkm_engine *engine) +{ + struct nvkm_fifo *fifo = nvkm_fifo(engine); + void *data = fifo; + if (fifo->func->dtor) + data = fifo->func->dtor(fifo); + nvkm_event_fini(&fifo->cevent); + nvkm_event_fini(&fifo->uevent); + return data; +} + +static const struct nvkm_engine_func +nvkm_fifo = { + .dtor = nvkm_fifo_dtor, + .oneinit = nvkm_fifo_oneinit, + .init = nvkm_fifo_init, + .fini = nvkm_fifo_fini, + .intr = nvkm_fifo_intr, + .base.sclass = nvkm_fifo_class_get, +}; + int -nvkm_fifo_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, - int min, int max, int length, void **pobject) +nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, int nr, struct nvkm_fifo *fifo) { - struct nvkm_fifo *priv; int ret; - ret = nvkm_engine_create_(parent, engine, oclass, true, "PFIFO", - "fifo", length, pobject); - priv = *pobject; - if (ret) - return ret; + fifo->func = func; + INIT_LIST_HEAD(&fifo->chan); + spin_lock_init(&fifo->lock); - priv->min = min; - priv->max = max; - priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL); - if (!priv->channel) - return -ENOMEM; + if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR)) + fifo->nr = NVKM_FIFO_CHID_NR; + else + fifo->nr = nr; + bitmap_clear(fifo->mask, 0, fifo->nr); - ret = nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &priv->cevent); + ret = nvkm_engine_ctor(&nvkm_fifo, device, index, 0x00000100, + true, &fifo->engine); if (ret) return ret; - priv->chid = nvkm_fifo_chid; - spin_lock_init(&priv->lock); - return 0; + if (func->uevent_init) { + ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1, + &fifo->uevent); + if (ret) + return ret; + } + + return nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &fifo->cevent); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c new file mode 100644 index 000000000000..dc6d4678f228 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -0,0 +1,415 @@ +/* + * 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 "chan.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <core/oproxy.h> +#include <subdev/mmu.h> +#include <engine/dma.h> + +struct nvkm_fifo_chan_object { + struct nvkm_oproxy oproxy; + struct nvkm_fifo_chan *chan; + int hash; +}; + +static int +nvkm_fifo_chan_child_fini(struct nvkm_oproxy *base, bool suspend) +{ + struct nvkm_fifo_chan_object *object = + container_of(base, typeof(*object), oproxy); + struct nvkm_engine *engine = object->oproxy.object->engine; + struct nvkm_fifo_chan *chan = object->chan; + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + const char *name = nvkm_subdev_name[engine->subdev.index]; + int ret = 0; + + if (--engn->usecount) + return 0; + + if (chan->func->engine_fini) { + ret = chan->func->engine_fini(chan, engine, suspend); + if (ret) { + nvif_error(&chan->object, + "detach %s failed, %d\n", name, ret); + return ret; + } + } + + if (engn->object) { + ret = nvkm_object_fini(engn->object, suspend); + if (ret && suspend) + return ret; + } + + nvif_trace(&chan->object, "detached %s\n", name); + return ret; +} + +static int +nvkm_fifo_chan_child_init(struct nvkm_oproxy *base) +{ + struct nvkm_fifo_chan_object *object = + container_of(base, typeof(*object), oproxy); + struct nvkm_engine *engine = object->oproxy.object->engine; + struct nvkm_fifo_chan *chan = object->chan; + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + const char *name = nvkm_subdev_name[engine->subdev.index]; + int ret; + + if (engn->usecount++) + return 0; + + if (engn->object) { + ret = nvkm_object_init(engn->object); + if (ret) + return ret; + } + + if (chan->func->engine_init) { + ret = chan->func->engine_init(chan, engine); + if (ret) { + nvif_error(&chan->object, + "attach %s failed, %d\n", name, ret); + return ret; + } + } + + nvif_trace(&chan->object, "attached %s\n", name); + return 0; +} + +static void +nvkm_fifo_chan_child_del(struct nvkm_oproxy *base) +{ + struct nvkm_fifo_chan_object *object = + container_of(base, typeof(*object), oproxy); + struct nvkm_engine *engine = object->oproxy.base.engine; + struct nvkm_fifo_chan *chan = object->chan; + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + + if (chan->func->object_dtor) + chan->func->object_dtor(chan, object->hash); + + if (!--engn->refcount) { + if (chan->func->engine_dtor) + chan->func->engine_dtor(chan, engine); + nvkm_object_del(&engn->object); + if (chan->vm) + atomic_dec(&chan->vm->engref[engine->subdev.index]); + } +} + +static const struct nvkm_oproxy_func +nvkm_fifo_chan_child_func = { + .dtor[0] = nvkm_fifo_chan_child_del, + .init[0] = nvkm_fifo_chan_child_init, + .fini[0] = nvkm_fifo_chan_child_fini, +}; + +static int +nvkm_fifo_chan_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_engine *engine = oclass->engine; + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(oclass->parent); + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + struct nvkm_fifo_chan_object *object; + int ret = 0; + + if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) + return -ENOMEM; + nvkm_oproxy_ctor(&nvkm_fifo_chan_child_func, oclass, &object->oproxy); + object->chan = chan; + *pobject = &object->oproxy.base; + + if (!engn->refcount++) { + struct nvkm_oclass cclass = { + .client = oclass->client, + .engine = oclass->engine, + }; + + if (chan->vm) + atomic_inc(&chan->vm->engref[engine->subdev.index]); + + if (engine->func->fifo.cclass) { + ret = engine->func->fifo.cclass(chan, &cclass, + &engn->object); + } else + if (engine->func->cclass) { + ret = nvkm_object_new_(engine->func->cclass, &cclass, + NULL, 0, &engn->object); + } + if (ret) + return ret; + + if (chan->func->engine_ctor) { + ret = chan->func->engine_ctor(chan, oclass->engine, + engn->object); + if (ret) + return ret; + } + } + + ret = oclass->base.ctor(&(const struct nvkm_oclass) { + .base = oclass->base, + .engn = oclass->engn, + .handle = oclass->handle, + .object = oclass->object, + .client = oclass->client, + .parent = engn->object ? + engn->object : + oclass->parent, + .engine = engine, + }, data, size, &object->oproxy.object); + if (ret) + return ret; + + if (chan->func->object_ctor) { + object->hash = + chan->func->object_ctor(chan, object->oproxy.object); + if (object->hash < 0) + return object->hash; + } + + return 0; +} + +static int +nvkm_fifo_chan_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + struct nvkm_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_engine *engine; + u64 mask = chan->engines; + int ret, i, c; + + for (; c = 0, i = __ffs64(mask), mask; mask &= ~(1ULL << i)) { + if (!(engine = nvkm_device_engine(device, i))) + continue; + oclass->engine = engine; + oclass->base.oclass = 0; + + if (engine->func->fifo.sclass) { + ret = engine->func->fifo.sclass(oclass, index); + if (oclass->base.oclass) { + if (!oclass->base.ctor) + oclass->base.ctor = nvkm_object_new; + oclass->ctor = nvkm_fifo_chan_child_new; + return 0; + } + + index -= ret; + continue; + } + + while (engine->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = engine->func->sclass[index]; + if (!oclass->base.ctor) + oclass->base.ctor = nvkm_object_new; + oclass->ctor = nvkm_fifo_chan_child_new; + return 0; + } + } + index -= c; + } + + return -EINVAL; +} + +static int +nvkm_fifo_chan_ntfy(struct nvkm_object *object, u32 type, + struct nvkm_event **pevent) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + if (chan->func->ntfy) + return chan->func->ntfy(chan, type, pevent); + return -ENODEV; +} + +static int +nvkm_fifo_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + *addr = chan->addr; + *size = chan->size; + return 0; +} + +static int +nvkm_fifo_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + if (unlikely(!chan->user)) { + chan->user = ioremap(chan->addr, chan->size); + if (!chan->user) + return -ENOMEM; + } + if (unlikely(addr + 4 > chan->size)) + return -EINVAL; + *data = ioread32_native(chan->user + addr); + return 0; +} + +static int +nvkm_fifo_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + if (unlikely(!chan->user)) { + chan->user = ioremap(chan->addr, chan->size); + if (!chan->user) + return -ENOMEM; + } + if (unlikely(addr + 4 > chan->size)) + return -EINVAL; + iowrite32_native(data, chan->user + addr); + return 0; +} + +static int +nvkm_fifo_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + chan->func->fini(chan); + return 0; +} + +static int +nvkm_fifo_chan_init(struct nvkm_object *object) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + chan->func->init(chan); + return 0; +} + +static void * +nvkm_fifo_chan_dtor(struct nvkm_object *object) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + struct nvkm_fifo *fifo = chan->fifo; + void *data = chan->func->dtor(chan); + unsigned long flags; + + spin_lock_irqsave(&fifo->lock, flags); + if (!list_empty(&chan->head)) { + __clear_bit(chan->chid, fifo->mask); + list_del(&chan->head); + } + spin_unlock_irqrestore(&fifo->lock, flags); + + if (chan->user) + iounmap(chan->user); + + nvkm_vm_ref(NULL, &chan->vm, NULL); + + nvkm_gpuobj_del(&chan->push); + nvkm_gpuobj_del(&chan->inst); + return data; +} + +static const struct nvkm_object_func +nvkm_fifo_chan_func = { + .dtor = nvkm_fifo_chan_dtor, + .init = nvkm_fifo_chan_init, + .fini = nvkm_fifo_chan_fini, + .ntfy = nvkm_fifo_chan_ntfy, + .map = nvkm_fifo_chan_map, + .rd32 = nvkm_fifo_chan_rd32, + .wr32 = nvkm_fifo_chan_wr32, + .sclass = nvkm_fifo_chan_child_get, +}; + +int +nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *func, + struct nvkm_fifo *fifo, u32 size, u32 align, bool zero, + u64 vm, u64 push, u64 engines, int bar, u32 base, u32 user, + const struct nvkm_oclass *oclass, + struct nvkm_fifo_chan *chan) +{ + struct nvkm_client *client = oclass->client; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_mmu *mmu = device->mmu; + struct nvkm_dmaobj *dmaobj; + unsigned long flags; + int ret; + + nvkm_object_ctor(&nvkm_fifo_chan_func, oclass, &chan->object); + chan->func = func; + chan->fifo = fifo; + chan->engines = engines; + INIT_LIST_HEAD(&chan->head); + + /* instance memory */ + ret = nvkm_gpuobj_new(device, size, align, zero, NULL, &chan->inst); + if (ret) + return ret; + + /* allocate push buffer ctxdma instance */ + if (push) { + dmaobj = nvkm_dma_search(device->dma, oclass->client, push); + if (!dmaobj) + return -ENOENT; + + ret = nvkm_object_bind(&dmaobj->object, chan->inst, -16, + &chan->push); + if (ret) + return ret; + } + + /* channel address space */ + if (!vm && mmu) { + if (!client->vm || client->vm->mmu == mmu) { + ret = nvkm_vm_ref(client->vm, &chan->vm, NULL); + if (ret) + return ret; + } else { + return -EINVAL; + } + } else { + return -ENOENT; + } + + /* allocate channel id */ + spin_lock_irqsave(&fifo->lock, flags); + chan->chid = find_first_zero_bit(fifo->mask, NVKM_FIFO_CHID_NR); + if (chan->chid >= NVKM_FIFO_CHID_NR) { + spin_unlock_irqrestore(&fifo->lock, flags); + return -ENOSPC; + } + list_add(&chan->head, &fifo->chan); + __set_bit(chan->chid, fifo->mask); + spin_unlock_irqrestore(&fifo->lock, flags); + + /* determine address of this channel's user registers */ + chan->addr = device->func->resource_addr(device, bar) + + base + user * chan->chid; + chan->size = user; + + nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h new file mode 100644 index 000000000000..55dc415c5c08 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h @@ -0,0 +1,33 @@ +#ifndef __NVKM_FIFO_CHAN_H__ +#define __NVKM_FIFO_CHAN_H__ +#define nvkm_fifo_chan(p) container_of((p), struct nvkm_fifo_chan, object) +#include "priv.h" + +struct nvkm_fifo_chan_func { + void *(*dtor)(struct nvkm_fifo_chan *); + void (*init)(struct nvkm_fifo_chan *); + void (*fini)(struct nvkm_fifo_chan *); + int (*ntfy)(struct nvkm_fifo_chan *, u32 type, struct nvkm_event **); + int (*engine_ctor)(struct nvkm_fifo_chan *, struct nvkm_engine *, + struct nvkm_object *); + void (*engine_dtor)(struct nvkm_fifo_chan *, struct nvkm_engine *); + int (*engine_init)(struct nvkm_fifo_chan *, struct nvkm_engine *); + int (*engine_fini)(struct nvkm_fifo_chan *, struct nvkm_engine *, + bool suspend); + int (*object_ctor)(struct nvkm_fifo_chan *, struct nvkm_object *); + void (*object_dtor)(struct nvkm_fifo_chan *, int); +}; + +int nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *, struct nvkm_fifo *, + u32 size, u32 align, bool zero, u64 vm, u64 push, + u64 engines, int bar, u32 base, u32 user, + const struct nvkm_oclass *, struct nvkm_fifo_chan *); + +struct nvkm_fifo_chan_oclass { + int (*ctor)(struct nvkm_fifo *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + struct nvkm_sclass base; +}; + +int g84_fifo_chan_ntfy(struct nvkm_fifo_chan *, u32, struct nvkm_event **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c new file mode 100644 index 000000000000..04305241ceed --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c @@ -0,0 +1,285 @@ +/* + * 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 "channv50.h" + +#include <core/client.h> +#include <core/ramht.h> +#include <subdev/mmu.h> +#include <subdev/timer.h> + +#include <nvif/class.h> + +int +g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type, + struct nvkm_event **pevent) +{ + switch (type) { + case G82_CHANNEL_DMA_V0_NTFY_UEVENT: + *pevent = &chan->fifo->uevent; + return 0; + default: + break; + } + return -EINVAL; +} + +static int +g84_fifo_chan_engine(struct nvkm_engine *engine) +{ + switch (engine->subdev.index) { + case NVKM_ENGINE_GR : return 0; + case NVKM_ENGINE_MPEG : + case NVKM_ENGINE_MSPPP : return 1; + case NVKM_ENGINE_CE0 : return 2; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: return 3; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : return 4; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : return 5; + default: + WARN_ON(1); + return 0; + } +} + +static int +g84_fifo_chan_engine_addr(struct nvkm_engine *engine) +{ + switch (engine->subdev.index) { + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : return -1; + case NVKM_ENGINE_GR : return 0x0020; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: return 0x0040; + case NVKM_ENGINE_MPEG : + case NVKM_ENGINE_MSPPP : return 0x0060; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : return 0x0080; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : return 0x00a0; + case NVKM_ENGINE_CE0 : return 0x00c0; + default: + WARN_ON(1); + return -1; + } +} + +static int +g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 engn, save; + int offset; + bool done; + + offset = g84_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; + + engn = g84_fifo_chan_engine(engine); + save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); + nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12); + done = nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ) >= 0; + nvkm_wr32(device, 0x002520, save); + if (!done) { + nvkm_error(subdev, "channel %d [%s] unload timeout\n", + chan->base.chid, chan->base.object.client->name); + if (suspend) + return -EBUSY; + } + + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x04, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x08, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); + return 0; +} + + +int +g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index]; + u64 limit, start; + int offset; + + offset = g84_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; + limit = engn->addr + engn->size - 1; + start = engn->addr; + + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00190000); + nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit)); + nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); + return 0; +} + +static int +g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + int engn = engine->subdev.index; + + if (g84_fifo_chan_engine_addr(engine) < 0) + return 0; + + return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); +} + +int +g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + u32 handle = object->handle; + u32 context; + + switch (object->engine->subdev.index) { + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context = 0x00000000; break; + case NVKM_ENGINE_GR : context = 0x00100000; break; + case NVKM_ENGINE_MPEG : + case NVKM_ENGINE_MSPPP : context = 0x00200000; break; + case NVKM_ENGINE_ME : + case NVKM_ENGINE_CE0 : context = 0x00300000; break; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: context = 0x00400000; break; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : + case NVKM_ENGINE_VIC : context = 0x00500000; break; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : context = 0x00600000; break; + default: + WARN_ON(1); + return -EINVAL; + } + + return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context); +} + +static void +g84_fifo_chan_init(struct nvkm_fifo_chan *base) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u64 addr = chan->ramfc->addr >> 8; + u32 chid = chan->base.chid; + + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr); + nv50_fifo_runlist_update(fifo); +} + +static const struct nvkm_fifo_chan_func +g84_fifo_chan_func = { + .dtor = nv50_fifo_chan_dtor, + .init = g84_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .ntfy = g84_fifo_chan_ntfy, + .engine_ctor = g84_fifo_chan_engine_ctor, + .engine_dtor = nv50_fifo_chan_engine_dtor, + .engine_init = g84_fifo_chan_engine_init, + .engine_fini = g84_fifo_chan_engine_fini, + .object_ctor = g84_fifo_chan_object_ctor, + .object_dtor = nv50_fifo_chan_object_dtor, +}; + +int +g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vm, u64 push, + const struct nvkm_oclass *oclass, + struct nv50_fifo_chan *chan) +{ + struct nvkm_device *device = fifo->base.engine.subdev.device; + int ret; + + ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base, + 0x10000, 0x1000, false, vm, push, + (1ULL << NVKM_ENGINE_BSP) | + (1ULL << NVKM_ENGINE_CE0) | + (1ULL << NVKM_ENGINE_CIPHER) | + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_ME) | + (1ULL << NVKM_ENGINE_MPEG) | + (1ULL << NVKM_ENGINE_MSPDEC) | + (1ULL << NVKM_ENGINE_MSPPP) | + (1ULL << NVKM_ENGINE_MSVLD) | + (1ULL << NVKM_ENGINE_SEC) | + (1ULL << NVKM_ENGINE_SW) | + (1ULL << NVKM_ENGINE_VIC) | + (1ULL << NVKM_ENGINE_VP), + 0, 0xc00000, 0x2000, oclass, &chan->base); + chan->fifo = fifo; + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->base.inst, + &chan->eng); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst, + &chan->pgd); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->base.inst, + &chan->cache); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->base.inst, + &chan->ramfc); + if (ret) + return ret; + + ret = nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht); + if (ret) + return ret; + + return nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h new file mode 100644 index 000000000000..7d697e2dce1a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h @@ -0,0 +1,24 @@ +#ifndef __GF100_FIFO_CHAN_H__ +#define __GF100_FIFO_CHAN_H__ +#define gf100_fifo_chan(p) container_of((p), struct gf100_fifo_chan, base) +#include "chan.h" +#include "gf100.h" + +struct gf100_fifo_chan { + struct nvkm_fifo_chan base; + struct gf100_fifo *fifo; + + struct list_head head; + bool killed; + + struct nvkm_gpuobj *pgd; + struct nvkm_vm *vm; + + struct { + struct nvkm_gpuobj *inst; + struct nvkm_vma vma; + } engn[NVKM_SUBDEV_NR]; +}; + +extern const struct nvkm_fifo_chan_oclass gf100_fifo_gpfifo_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h new file mode 100644 index 000000000000..97bdddb7644a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h @@ -0,0 +1,29 @@ +#ifndef __GK104_FIFO_CHAN_H__ +#define __GK104_FIFO_CHAN_H__ +#define gk104_fifo_chan(p) container_of((p), struct gk104_fifo_chan, base) +#include "chan.h" +#include "gk104.h" + +struct gk104_fifo_chan { + struct nvkm_fifo_chan base; + struct gk104_fifo *fifo; + int engine; + + struct list_head head; + bool killed; + + struct nvkm_gpuobj *pgd; + struct nvkm_vm *vm; + + struct { + struct nvkm_gpuobj *inst; + struct nvkm_vma vma; + } engn[NVKM_SUBDEV_NR]; +}; + +int gk104_fifo_gpfifo_new(struct nvkm_fifo *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + +extern const struct nvkm_fifo_chan_oclass gk104_fifo_gpfifo_oclass; +extern const struct nvkm_fifo_chan_oclass gm204_fifo_gpfifo_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h new file mode 100644 index 000000000000..3361a1fd0343 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h @@ -0,0 +1,24 @@ +#ifndef __NV04_FIFO_CHAN_H__ +#define __NV04_FIFO_CHAN_H__ +#define nv04_fifo_chan(p) container_of((p), struct nv04_fifo_chan, base) +#include "chan.h" +#include "nv04.h" + +struct nv04_fifo_chan { + struct nvkm_fifo_chan base; + struct nv04_fifo *fifo; + u32 ramfc; + struct nvkm_gpuobj *engn[NVKM_SUBDEV_NR]; +}; + +extern const struct nvkm_fifo_chan_func nv04_fifo_dma_func; +void *nv04_fifo_dma_dtor(struct nvkm_fifo_chan *); +void nv04_fifo_dma_init(struct nvkm_fifo_chan *); +void nv04_fifo_dma_fini(struct nvkm_fifo_chan *); +void nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *, int); + +extern const struct nvkm_fifo_chan_oclass nv04_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv10_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv17_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv40_fifo_dma_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c new file mode 100644 index 000000000000..25b60aff40e4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c @@ -0,0 +1,270 @@ +/* + * 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 "channv50.h" + +#include <core/client.h> +#include <core/ramht.h> +#include <subdev/mmu.h> +#include <subdev/timer.h> + +static int +nv50_fifo_chan_engine_addr(struct nvkm_engine *engine) +{ + switch (engine->subdev.index) { + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : return -1; + case NVKM_ENGINE_GR : return 0x0000; + case NVKM_ENGINE_MPEG : return 0x0060; + default: + WARN_ON(1); + return -1; + } +} + +static int +nv50_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int offset, ret = 0; + u32 me; + + offset = nv50_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; + + /* HW bug workaround: + * + * PFIFO will hang forever if the connected engines don't report + * that they've processed the context switch request. + * + * In order for the kickoff to work, we need to ensure all the + * connected engines are in a state where they can answer. + * + * Newer chipsets don't seem to suffer from this issue, and well, + * there's also a "ignore these engines" bitmask reg we can use + * if we hit the issue there.. + */ + me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001); + + /* do the kickoff... */ + nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ) < 0) { + nvkm_error(subdev, "channel %d [%s] unload timeout\n", + chan->base.chid, chan->base.object.client->name); + if (suspend) + ret = -EBUSY; + } + nvkm_wr32(device, 0x00b860, me); + + if (ret == 0) { + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x04, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x08, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); + } + + return ret; +} + +static int +nv50_fifo_chan_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index]; + u64 limit, start; + int offset; + + offset = nv50_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; + limit = engn->addr + engn->size - 1; + start = engn->addr; + + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00190000); + nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit)); + nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); + return 0; +} + +void +nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + nvkm_gpuobj_del(&chan->engn[engine->subdev.index]); +} + +static int +nv50_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + int engn = engine->subdev.index; + + if (nv50_fifo_chan_engine_addr(engine) < 0) + return 0; + + return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); +} + +void +nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *base, int cookie) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + nvkm_ramht_remove(chan->ramht, cookie); +} + +static int +nv50_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + u32 handle = object->handle; + u32 context; + + switch (object->engine->subdev.index) { + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context = 0x00000000; break; + case NVKM_ENGINE_GR : context = 0x00100000; break; + case NVKM_ENGINE_MPEG : context = 0x00200000; break; + default: + WARN_ON(1); + return -EINVAL; + } + + return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context); +} + +void +nv50_fifo_chan_fini(struct nvkm_fifo_chan *base) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + + /* remove channel from runlist, fifo will unload context */ + nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000); + nv50_fifo_runlist_update(fifo); + nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000); +} + +static void +nv50_fifo_chan_init(struct nvkm_fifo_chan *base) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u64 addr = chan->ramfc->addr >> 12; + u32 chid = chan->base.chid; + + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr); + nv50_fifo_runlist_update(fifo); +} + +void * +nv50_fifo_chan_dtor(struct nvkm_fifo_chan *base) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + nvkm_vm_ref(NULL, &chan->vm, chan->pgd); + nvkm_ramht_del(&chan->ramht); + nvkm_gpuobj_del(&chan->pgd); + nvkm_gpuobj_del(&chan->eng); + nvkm_gpuobj_del(&chan->cache); + nvkm_gpuobj_del(&chan->ramfc); + return chan; +} + +static const struct nvkm_fifo_chan_func +nv50_fifo_chan_func = { + .dtor = nv50_fifo_chan_dtor, + .init = nv50_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .engine_ctor = nv50_fifo_chan_engine_ctor, + .engine_dtor = nv50_fifo_chan_engine_dtor, + .engine_init = nv50_fifo_chan_engine_init, + .engine_fini = nv50_fifo_chan_engine_fini, + .object_ctor = nv50_fifo_chan_object_ctor, + .object_dtor = nv50_fifo_chan_object_dtor, +}; + +int +nv50_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vm, u64 push, + const struct nvkm_oclass *oclass, + struct nv50_fifo_chan *chan) +{ + struct nvkm_device *device = fifo->base.engine.subdev.device; + int ret; + + ret = nvkm_fifo_chan_ctor(&nv50_fifo_chan_func, &fifo->base, + 0x10000, 0x1000, false, vm, push, + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_SW) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MPEG), + 0, 0xc00000, 0x2000, oclass, &chan->base); + chan->fifo = fifo; + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, chan->base.inst, + &chan->ramfc); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x1200, 0, true, chan->base.inst, + &chan->eng); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst, + &chan->pgd); + if (ret) + return ret; + + ret = nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht); + if (ret) + return ret; + + return nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h new file mode 100644 index 000000000000..4b9da469b704 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h @@ -0,0 +1,35 @@ +#ifndef __NV50_FIFO_CHAN_H__ +#define __NV50_FIFO_CHAN_H__ +#define nv50_fifo_chan(p) container_of((p), struct nv50_fifo_chan, base) +#include "chan.h" +#include "nv50.h" + +struct nv50_fifo_chan { + struct nv50_fifo *fifo; + struct nvkm_fifo_chan base; + + struct nvkm_gpuobj *ramfc; + struct nvkm_gpuobj *cache; + struct nvkm_gpuobj *eng; + struct nvkm_gpuobj *pgd; + struct nvkm_ramht *ramht; + struct nvkm_vm *vm; + + struct nvkm_gpuobj *engn[NVKM_SUBDEV_NR]; +}; + +int nv50_fifo_chan_ctor(struct nv50_fifo *, u64 vm, u64 push, + const struct nvkm_oclass *, struct nv50_fifo_chan *); +void *nv50_fifo_chan_dtor(struct nvkm_fifo_chan *); +void nv50_fifo_chan_fini(struct nvkm_fifo_chan *); +void nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *, struct nvkm_engine *); +void nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *, int); + +int g84_fifo_chan_ctor(struct nv50_fifo *, u64 vm, u64 push, + const struct nvkm_oclass *, struct nv50_fifo_chan *); + +extern const struct nvkm_fifo_chan_oclass nv50_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv50_fifo_gpfifo_oclass; +extern const struct nvkm_fifo_chan_oclass g84_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass g84_fifo_gpfifo_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c new file mode 100644 index 000000000000..a5ca52c7b74f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c @@ -0,0 +1,93 @@ +/* + * 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 "channv50.h" + +#include <core/client.h> +#include <core/ramht.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static int +g84_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv50_channel_dma_v0 v0; + } *args = data; + struct nv50_fifo *fifo = nv50_fifo(base); + struct nv50_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d vm %llx " + "pushbuf %llx offset %016llx\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = g84_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10); + nvkm_wo32(chan->ramfc, 0x98, chan->base.inst->addr >> 12); + nvkm_done(chan->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +g84_fifo_dma_oclass = { + .base.oclass = G82_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = g84_fifo_dma_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c new file mode 100644 index 000000000000..bfcc6408a772 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c @@ -0,0 +1,220 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "channv04.h" +#include "regsnv04.h" + +#include <core/client.h> +#include <core/ramht.h> +#include <subdev/instmem.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +void +nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *base, int cookie) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; + nvkm_ramht_remove(imem->ramht, cookie); +} + +static int +nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; + u32 context = 0x80000000 | chan->base.chid << 24; + u32 handle = object->handle; + int hash; + + switch (object->engine->subdev.index) { + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context |= 0x00000000; break; + case NVKM_ENGINE_GR : context |= 0x00010000; break; + case NVKM_ENGINE_MPEG : context |= 0x00020000; break; + default: + WARN_ON(1); + return -EINVAL; + } + + mutex_lock(&chan->fifo->base.engine.subdev.mutex); + hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4, + handle, context); + mutex_unlock(&chan->fifo->base.engine.subdev.mutex); + return hash; +} + +void +nv04_fifo_dma_fini(struct nvkm_fifo_chan *base) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_memory *fctx = device->imem->ramfc; + const struct nv04_fifo_ramfc *c; + unsigned long flags; + u32 mask = fifo->base.nr - 1; + u32 data = chan->ramfc; + u32 chid; + + /* prevent fifo context switches */ + spin_lock_irqsave(&fifo->base.lock, flags); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0); + + /* if this channel is active, replace it with a null context */ + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & mask; + if (chid == chan->base.chid) { + nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); + + c = fifo->ramfc; + do { + u32 rm = ((1ULL << c->bits) - 1) << c->regs; + u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; + u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; + u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm); + nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); + } while ((++c)->bits); + + c = fifo->ramfc; + do { + nvkm_wr32(device, c->regp, 0x00000000); + } while ((++c)->bits); + + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, mask); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + } + + /* restore normal operation, after disabling dma mode */ + nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); + spin_unlock_irqrestore(&fifo->base.lock, flags); +} + +void +nv04_fifo_dma_init(struct nvkm_fifo_chan *base) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = 1 << chan->base.chid; + unsigned long flags; + spin_lock_irqsave(&fifo->base.lock, flags); + nvkm_mask(device, NV04_PFIFO_MODE, mask, mask); + spin_unlock_irqrestore(&fifo->base.lock, flags); +} + +void * +nv04_fifo_dma_dtor(struct nvkm_fifo_chan *base) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + const struct nv04_fifo_ramfc *c = fifo->ramfc; + + nvkm_kmap(imem->ramfc); + do { + nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000); + } while ((++c)->bits); + nvkm_done(imem->ramfc); + return chan; +} + +const struct nvkm_fifo_chan_func +nv04_fifo_dma_func = { + .dtor = nv04_fifo_dma_dtor, + .init = nv04_fifo_dma_init, + .fini = nv04_fifo_dma_fini, + .object_ctor = nv04_fifo_dma_object_ctor, + .object_dtor = nv04_fifo_dma_object_dtor, +}; + +static int +nv04_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_SW), + 0, 0x800000, 0x10000, oclass, &chan->base); + chan->fifo = fifo; + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + chan->ramfc = chan->base.chid * 32; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.push->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x10, + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(imem->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +nv04_fifo_dma_oclass = { + .base.oclass = NV03_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv04_fifo_dma_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c new file mode 100644 index 000000000000..34f68e5bd040 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c @@ -0,0 +1,96 @@ +/* + * 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 "channv04.h" +#include "regsnv04.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <subdev/instmem.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static int +nv10_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_SW), + 0, 0x800000, 0x10000, oclass, &chan->base); + chan->fifo = fifo; + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + chan->ramfc = chan->base.chid * 32; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(imem->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +nv10_fifo_dma_oclass = { + .base.oclass = NV10_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv10_fifo_dma_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c new file mode 100644 index 000000000000..ed7cc9f2b540 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c @@ -0,0 +1,97 @@ +/* + * 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 "channv04.h" +#include "regsnv04.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <subdev/instmem.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static int +nv17_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MPEG) | /* NV31- */ + (1ULL << NVKM_ENGINE_SW), + 0, 0x800000, 0x10000, oclass, &chan->base); + chan->fifo = fifo; + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + chan->ramfc = chan->base.chid * 64; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(imem->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +nv17_fifo_dma_oclass = { + .base.oclass = NV17_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv17_fifo_dma_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c new file mode 100644 index 000000000000..043b6c325949 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c @@ -0,0 +1,243 @@ +/* + * 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 "channv04.h" +#include "regsnv04.h" + +#include <core/client.h> +#include <core/ramht.h> +#include <subdev/instmem.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static bool +nv40_fifo_dma_engine(struct nvkm_engine *engine, u32 *reg, u32 *ctx) +{ + switch (engine->subdev.index) { + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW: + return false; + case NVKM_ENGINE_GR: + *reg = 0x0032e0; + *ctx = 0x38; + return true; + case NVKM_ENGINE_MPEG: + *reg = 0x00330c; + *ctx = 0x54; + return true; + default: + WARN_ON(1); + return false; + } +} + +static int +nv40_fifo_dma_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + unsigned long flags; + u32 reg, ctx; + int chid; + + if (!nv40_fifo_dma_engine(engine, ®, &ctx)) + return 0; + + spin_lock_irqsave(&fifo->base.lock, flags); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); + + chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1); + if (chid == chan->base.chid) + nvkm_wr32(device, reg, 0x00000000); + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + ctx, 0x00000000); + nvkm_done(imem->ramfc); + + nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&fifo->base.lock, flags); + return 0; +} + +static int +nv40_fifo_dma_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + unsigned long flags; + u32 inst, reg, ctx; + int chid; + + if (!nv40_fifo_dma_engine(engine, ®, &ctx)) + return 0; + inst = chan->engn[engine->subdev.index]->addr >> 4; + + spin_lock_irqsave(&fifo->base.lock, flags); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); + + chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1); + if (chid == chan->base.chid) + nvkm_wr32(device, reg, inst); + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + ctx, inst); + nvkm_done(imem->ramfc); + + nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&fifo->base.lock, flags); + return 0; +} + +static void +nv40_fifo_dma_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + nvkm_gpuobj_del(&chan->engn[engine->subdev.index]); +} + +static int +nv40_fifo_dma_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + const int engn = engine->subdev.index; + u32 reg, ctx; + + if (!nv40_fifo_dma_engine(engine, ®, &ctx)) + return 0; + + return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); +} + +static int +nv40_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; + u32 context = chan->base.chid << 23; + u32 handle = object->handle; + int hash; + + switch (object->engine->subdev.index) { + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context |= 0x00000000; break; + case NVKM_ENGINE_GR : context |= 0x00100000; break; + case NVKM_ENGINE_MPEG : context |= 0x00200000; break; + default: + WARN_ON(1); + return -EINVAL; + } + + mutex_lock(&chan->fifo->base.engine.subdev.mutex); + hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4, + handle, context); + mutex_unlock(&chan->fifo->base.engine.subdev.mutex); + return hash; +} + +static const struct nvkm_fifo_chan_func +nv40_fifo_dma_func = { + .dtor = nv04_fifo_dma_dtor, + .init = nv04_fifo_dma_init, + .fini = nv04_fifo_dma_fini, + .engine_ctor = nv40_fifo_dma_engine_ctor, + .engine_dtor = nv40_fifo_dma_engine_dtor, + .engine_init = nv40_fifo_dma_engine_init, + .engine_fini = nv40_fifo_dma_engine_fini, + .object_ctor = nv40_fifo_dma_object_ctor, + .object_dtor = nv04_fifo_dma_object_dtor, +}; + +static int +nv40_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv40_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MPEG) | + (1ULL << NVKM_ENGINE_SW), + 0, 0xc00000, 0x1000, oclass, &chan->base); + chan->fifo = fifo; + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + chan->ramfc = chan->base.chid * 128; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 | + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x3c, 0x0001ffff); + nvkm_done(imem->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +nv40_fifo_dma_oclass = { + .base.oclass = NV40_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv40_fifo_dma_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c new file mode 100644 index 000000000000..6b3b15f12c39 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c @@ -0,0 +1,91 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "channv50.h" + +#include <core/client.h> +#include <core/ramht.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static int +nv50_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv50_channel_dma_v0 v0; + } *args = data; + struct nv50_fifo *fifo = nv50_fifo(base); + struct nv50_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d vm %llx " + "pushbuf %llx offset %016llx\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nv50_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_done(chan->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +nv50_fifo_dma_oclass = { + .base.oclass = NV50_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_fifo_dma_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index a04920b3cf84..ff7b529764fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -22,466 +22,41 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "nv04.h" - -#include <core/client.h> -#include <core/engctx.h> -#include <core/ramht.h> -#include <subdev/bar.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) -{ - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *ectx = (void *)object; - u64 limit = ectx->addr + ectx->size - 1; - u64 start = ectx->addr; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0020; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: addr = 0x0040; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : addr = 0x0080; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : addr = 0x00a0; break; - case NVDEV_ENGINE_CE0 : addr = 0x00c0; break; - default: - return -EINVAL; - } - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - nv_wo32(base->eng, addr + 0x00, 0x00190000); - nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); - return 0; -} - -static int -g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) -{ - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_priv *priv = (void *)parent->engine; - struct nv50_fifo_base *base = (void *)parent->parent; - struct nv50_fifo_chan *chan = (void *)parent; - u32 addr, save, engn; - bool done; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: engn = 3; addr = 0x0040; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : engn = 5; addr = 0x0080; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : engn = 4; addr = 0x00a0; break; - case NVDEV_ENGINE_CE0 : engn = 2; addr = 0x00c0; break; - default: - return -EINVAL; - } - - save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn); - nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); - done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff); - nv_wr32(priv, 0x002520, save); - if (!done) { - nv_error(priv, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - return -EBUSY; - } - - nv_wo32(base->eng, addr + 0x00, 0x00000000); - nv_wo32(base->eng, addr + 0x04, 0x00000000); - nv_wo32(base->eng, addr + 0x08, 0x00000000); - nv_wo32(base->eng, addr + 0x0c, 0x00000000); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); - return 0; -} - -static int -g84_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv50_fifo_chan *chan = (void *)parent; - u32 context; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->node->offset >> 4; - else - context = 0x00000004; /* just non-zero */ - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : - case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break; - case NVDEV_ENGINE_ME : - case NVDEV_ENGINE_CE0 : context |= 0x00300000; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : - case NVDEV_ENGINE_VIC : context |= 0x00500000; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break; - default: - return -EINVAL; - } - - return nvkm_ramht_insert(chan->ramht, 0, handle, context); -} - -static int -g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; - int ret; - - nv_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_ME) | - (1ULL << NVDEV_ENGINE_VP) | - (1ULL << NVDEV_ENGINE_CIPHER) | - (1ULL << NVDEV_ENGINE_SEC) | - (1ULL << NVDEV_ENGINE_BSP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_VIC), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, - &chan->ramht); - if (ret) - return ret; - - nv_parent(chan)->context_attach = g84_fifo_context_attach; - nv_parent(chan)->context_detach = g84_fifo_context_detach; - nv_parent(chan)->object_attach = g84_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x3c, 0x003f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x4c, 0xffffffff); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); - nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - bar->flush(bar); - return 0; -} - -static int -g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_channel_gpfifo_v0 v0; - } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; - u64 ioffset, ilength; - int ret; - - nv_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_ME) | - (1ULL << NVDEV_ENGINE_VP) | - (1ULL << NVDEV_ENGINE_CIPHER) | - (1ULL << NVDEV_ENGINE_SEC) | - (1ULL << NVDEV_ENGINE_BSP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_VIC), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, - &chan->ramht); - if (ret) - return ret; - - nv_parent(chan)->context_attach = g84_fifo_context_attach; - nv_parent(chan)->context_detach = g84_fifo_context_detach; - nv_parent(chan)->object_attach = g84_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nv_wo32(base->ramfc, 0x3c, 0x403f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); - nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - bar->flush(bar); - return 0; -} - -static int -g84_fifo_chan_init(struct nvkm_object *object) -{ - struct nv50_fifo_priv *priv = (void *)object->engine; - struct nv50_fifo_base *base = (void *)object->parent; - struct nv50_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *ramfc = base->ramfc; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); - nv50_fifo_playlist_update(priv); - return 0; -} - -static struct nvkm_ofuncs -g84_fifo_ofuncs_dma = { - .ctor = g84_fifo_chan_ctor_dma, - .dtor = nv50_fifo_chan_dtor, - .init = g84_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_ofuncs -g84_fifo_ofuncs_ind = { - .ctor = g84_fifo_chan_ctor_ind, - .dtor = nv50_fifo_chan_dtor, - .init = g84_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -g84_fifo_sclass[] = { - { G82_CHANNEL_DMA, &g84_fifo_ofuncs_dma }, - { G82_CHANNEL_GPFIFO, &g84_fifo_ofuncs_ind }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -static int -g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0, - NVOBJ_FLAG_ZERO_ALLOC, &base->eng); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, - 0, &base->pgd); - if (ret) - return ret; - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1000, - 0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0100, - 0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); - if (ret) - return ret; - - return 0; -} - -static struct nvkm_oclass -g84_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_fifo_context_ctor, - .dtor = nv50_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ +#include "channv50.h" static void -g84_fifo_uevent_init(struct nvkm_event *event, int type, int index) +g84_fifo_uevent_fini(struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x40000000, 0x40000000); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x40000000, 0x00000000); } static void -g84_fifo_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x40000000, 0x00000000); -} - -static const struct nvkm_event_func -g84_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = g84_fifo_uevent_init, - .fini = g84_fifo_uevent_fini, +g84_fifo_uevent_init(struct nvkm_fifo *fifo) +{ + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x40000000, 0x40000000); +} + +static const struct nvkm_fifo_func +g84_fifo = { + .dtor = nv50_fifo_dtor, + .oneinit = nv50_fifo_oneinit, + .init = nv50_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .uevent_init = g84_fifo_uevent_init, + .uevent_fini = g84_fifo_uevent_fini, + .chan = { + &g84_fifo_dma_oclass, + &g84_fifo_gpfifo_oclass, + NULL + }, }; -static int -g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nv50_fifo_priv *priv; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[0]); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[1]); - if (ret) - return ret; - - ret = nvkm_event_init(&g84_fifo_uevent_func, 1, 1, &priv->base.uevent); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &g84_fifo_cclass; - nv_engine(priv)->sclass = g84_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - return 0; + return nv50_fifo_new_(&g84_fifo, device, index, pfifo); } - -struct nvkm_oclass * -g84_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_fifo_ctor, - .dtor = nv50_fifo_dtor, - .init = nv50_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index b745252f2261..ff6fcbda615b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -21,365 +21,72 @@ * * Authors: Ben Skeggs */ -#include <engine/fifo.h> +#include "gf100.h" +#include "changf100.h" #include <core/client.h> -#include <core/engctx.h> #include <core/enum.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <subdev/bar.h> -#include <subdev/fb.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> +#include <engine/sw.h> #include <nvif/class.h> -#include <nvif/unpack.h> - -struct gf100_fifo_priv { - struct nvkm_fifo base; - - struct work_struct fault; - u64 mask; - - struct { - struct nvkm_gpuobj *mem[2]; - int active; - wait_queue_head_t wait; - } runlist; - - struct { - struct nvkm_gpuobj *mem; - struct nvkm_vma bar; - } user; - int spoon_nr; -}; - -struct gf100_fifo_base { - struct nvkm_fifo_base base; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; - -struct gf100_fifo_chan { - struct nvkm_fifo_chan base; - enum { - STOPPED, - RUNNING, - KILLED - } state; -}; - -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ static void -gf100_fifo_runlist_update(struct gf100_fifo_priv *priv) +gf100_fifo_uevent_init(struct nvkm_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(priv); - struct nvkm_gpuobj *cur; - int i, p; - - mutex_lock(&nv_subdev(priv)->mutex); - cur = priv->runlist.mem[priv->runlist.active]; - priv->runlist.active = !priv->runlist.active; - - for (i = 0, p = 0; i < 128; i++) { - struct gf100_fifo_chan *chan = (void *)priv->base.channel[i]; - if (chan && chan->state == RUNNING) { - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000004); - p += 8; - } - } - bar->flush(bar); - - nv_wr32(priv, 0x002270, cur->addr >> 12); - nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); - - if (wait_event_timeout(priv->runlist.wait, - !(nv_rd32(priv, 0x00227c) & 0x00100000), - msecs_to_jiffies(2000)) == 0) - nv_error(priv, "runlist update timeout\n"); - mutex_unlock(&nv_subdev(priv)->mutex); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); } -static int -gf100_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) -{ - struct nvkm_bar *bar = nvkm_bar(parent); - struct gf100_fifo_base *base = (void *)parent->parent; - struct nvkm_engctx *ectx = (void *)object; - u32 addr; - int ret; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_CE0 : addr = 0x0230; break; - case NVDEV_ENGINE_CE1 : addr = 0x0240; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - if (!ectx->vma.node) { - ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); - if (ret) - return ret; - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - } - - nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset)); - bar->flush(bar); - return 0; -} - -static int -gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) +static void +gf100_fifo_uevent_fini(struct nvkm_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(parent); - struct gf100_fifo_priv *priv = (void *)parent->engine; - struct gf100_fifo_base *base = (void *)parent->parent; - struct gf100_fifo_chan *chan = (void *)parent; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_CE0 : addr = 0x0230; break; - case NVDEV_ENGINE_CE1 : addr = 0x0240; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - nv_wr32(priv, 0x002634, chan->base.chid); - if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { - nv_error(priv, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - return -EBUSY; - } - - nv_wo32(base, addr + 0x00, 0x00000000); - nv_wo32(base, addr + 0x04, 0x00000000); - bar->flush(bar); - return 0; + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); } -static int -gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +void +gf100_fifo_runlist_update(struct gf100_fifo *fifo) { - union { - struct nv50_channel_gpfifo_v0 v0; - } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); - struct gf100_fifo_priv *priv = (void *)engine; - struct gf100_fifo_base *base = (void *)parent; struct gf100_fifo_chan *chan; - u64 usermem, ioffset, ilength; - int ret, i; - - nv_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); - } else - return ret; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_memory *cur; + int nr = 0; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - priv->user.bar.offset, 0x1000, - args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_CE1) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + mutex_lock(&subdev->mutex); + cur = fifo->runlist.mem[fifo->runlist.active]; + fifo->runlist.active = !fifo->runlist.active; - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = gf100_fifo_context_attach; - nv_parent(chan)->context_detach = gf100_fifo_context_detach; - - usermem = chan->base.chid * 0x1000; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - for (i = 0; i < 0x1000; i += 4) - nv_wo32(priv->user.mem, usermem + i, 0x00000000); - - nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem)); - nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem)); - nv_wo32(base, 0x10, 0x0000face); - nv_wo32(base, 0x30, 0xfffff902); - nv_wo32(base, 0x48, lower_32_bits(ioffset)); - nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base, 0x54, 0x00000002); - nv_wo32(base, 0x84, 0x20400000); - nv_wo32(base, 0x94, 0x30000001); - nv_wo32(base, 0x9c, 0x00000100); - nv_wo32(base, 0xa4, 0x1f1f1f1f); - nv_wo32(base, 0xa8, 0x1f1f1f1f); - nv_wo32(base, 0xac, 0x0000001f); - nv_wo32(base, 0xb8, 0xf8000000); - nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */ - nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */ - bar->flush(bar); - return 0; -} - -static int -gf100_fifo_chan_init(struct nvkm_object *object) -{ - struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gf100_fifo_priv *priv = (void *)object->engine; - struct gf100_fifo_chan *chan = (void *)object; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); - - if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); - gf100_fifo_runlist_update(priv); - } - - return 0; -} - -static void gf100_fifo_intr_engine(struct gf100_fifo_priv *priv); - -static int -gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct gf100_fifo_priv *priv = (void *)object->engine; - struct gf100_fifo_chan *chan = (void *)object; - u32 chid = chan->base.chid; - - if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); - gf100_fifo_runlist_update(priv); + nvkm_kmap(cur); + list_for_each_entry(chan, &fifo->chan, head) { + nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid); + nvkm_wo32(cur, (nr * 8) + 4, 0x00000004); + nr++; } + nvkm_done(cur); - gf100_fifo_intr_engine(priv); - - nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -static struct nvkm_ofuncs -gf100_fifo_ofuncs = { - .ctor = gf100_fifo_chan_ctor, - .dtor = _nvkm_fifo_channel_dtor, - .init = gf100_fifo_chan_init, - .fini = gf100_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -gf100_fifo_sclass[] = { - { FERMI_CHANNEL_GPFIFO, &gf100_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - instmem heap and vm setup - ******************************************************************************/ - -static int -gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0, - &base->pgd); - if (ret) - return ret; - - nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0208, 0xffffffff); - nv_wo32(base, 0x020c, 0x000000ff); + nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); + nvkm_wr32(device, 0x002274, 0x01f00000 | nr); - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - - return 0; -} - -static void -gf100_fifo_context_dtor(struct nvkm_object *object) -{ - struct gf100_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_ref(NULL, &base->pgd); - nvkm_fifo_context_destroy(&base->base); + if (wait_event_timeout(fifo->runlist.wait, + !(nvkm_rd32(device, 0x00227c) & 0x00100000), + msecs_to_jiffies(2000)) == 0) + nvkm_error(subdev, "runlist update timeout\n"); + mutex_unlock(&subdev->mutex); } -static struct nvkm_oclass -gf100_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fifo_context_ctor, - .dtor = gf100_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - static inline int -gf100_fifo_engidx(struct gf100_fifo_priv *priv, u32 engn) +gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn) { switch (engn) { - case NVDEV_ENGINE_GR : engn = 0; break; - case NVDEV_ENGINE_MSVLD : engn = 1; break; - case NVDEV_ENGINE_MSPPP : engn = 2; break; - case NVDEV_ENGINE_MSPDEC: engn = 3; break; - case NVDEV_ENGINE_CE0 : engn = 4; break; - case NVDEV_ENGINE_CE1 : engn = 5; break; + case NVKM_ENGINE_GR : engn = 0; break; + case NVKM_ENGINE_MSVLD : engn = 1; break; + case NVKM_ENGINE_MSPPP : engn = 2; break; + case NVKM_ENGINE_MSPDEC: engn = 3; break; + case NVKM_ENGINE_CE0 : engn = 4; break; + case NVKM_ENGINE_CE1 : engn = 5; break; default: return -1; } @@ -388,95 +95,73 @@ gf100_fifo_engidx(struct gf100_fifo_priv *priv, u32 engn) } static inline struct nvkm_engine * -gf100_fifo_engine(struct gf100_fifo_priv *priv, u32 engn) +gf100_fifo_engine(struct gf100_fifo *fifo, u32 engn) { + struct nvkm_device *device = fifo->base.engine.subdev.device; + switch (engn) { - case 0: engn = NVDEV_ENGINE_GR; break; - case 1: engn = NVDEV_ENGINE_MSVLD; break; - case 2: engn = NVDEV_ENGINE_MSPPP; break; - case 3: engn = NVDEV_ENGINE_MSPDEC; break; - case 4: engn = NVDEV_ENGINE_CE0; break; - case 5: engn = NVDEV_ENGINE_CE1; break; + case 0: engn = NVKM_ENGINE_GR; break; + case 1: engn = NVKM_ENGINE_MSVLD; break; + case 2: engn = NVKM_ENGINE_MSPPP; break; + case 3: engn = NVKM_ENGINE_MSPDEC; break; + case 4: engn = NVKM_ENGINE_CE0; break; + case 5: engn = NVKM_ENGINE_CE1; break; default: return NULL; } - return nvkm_engine(priv, engn); + return nvkm_device_engine(device, engn); } static void gf100_fifo_recover_work(struct work_struct *work) { - struct gf100_fifo_priv *priv = container_of(work, typeof(*priv), fault); - struct nvkm_object *engine; + struct gf100_fifo *fifo = container_of(work, typeof(*fifo), fault); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_engine *engine; unsigned long flags; u32 engn, engm = 0; u64 mask, todo; - spin_lock_irqsave(&priv->base.lock, flags); - mask = priv->mask; - priv->mask = 0ULL; - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); + mask = fifo->mask; + fifo->mask = 0ULL; + spin_unlock_irqrestore(&fifo->base.lock, flags); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) - engm |= 1 << gf100_fifo_engidx(priv, engn); - nv_mask(priv, 0x002630, engm, engm); + engm |= 1 << gf100_fifo_engidx(fifo, engn); + nvkm_mask(device, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { - if ((engine = (void *)nvkm_engine(priv, engn))) { - nv_ofuncs(engine)->fini(engine, false); - WARN_ON(nv_ofuncs(engine)->init(engine)); + if ((engine = nvkm_device_engine(device, engn))) { + nvkm_subdev_fini(&engine->subdev, false); + WARN_ON(nvkm_subdev_init(&engine->subdev)); } } - gf100_fifo_runlist_update(priv); - nv_wr32(priv, 0x00262c, engm); - nv_mask(priv, 0x002630, engm, 0x00000000); + gf100_fifo_runlist_update(fifo); + nvkm_wr32(device, 0x00262c, engm); + nvkm_mask(device, 0x002630, engm, 0x00000000); } static void -gf100_fifo_recover(struct gf100_fifo_priv *priv, struct nvkm_engine *engine, +gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, struct gf100_fifo_chan *chan) { + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 chid = chan->base.chid; - unsigned long flags; - nv_error(priv, "%s engine fault on channel %d, recovering...\n", - nv_subdev(engine)->name, chid); + nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", + nvkm_subdev_name[engine->subdev.index], chid); + assert_spin_locked(&fifo->base.lock); - nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); - chan->state = KILLED; + nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); + list_del_init(&chan->head); + chan->killed = true; - spin_lock_irqsave(&priv->base.lock, flags); - priv->mask |= 1ULL << nv_engidx(engine); - spin_unlock_irqrestore(&priv->base.lock, flags); - schedule_work(&priv->fault); -} - -static int -gf100_fifo_swmthd(struct gf100_fifo_priv *priv, u32 chid, u32 mthd, u32 data) -{ - struct gf100_fifo_chan *chan = NULL; - struct nvkm_handle *bind; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; - if (unlikely(!chan)) - goto out; - - bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e); - if (likely(bind)) { - if (!mthd || !nv_call(bind->object, mthd, data)) - ret = 0; - nvkm_namedb_put(bind); - } - -out: - spin_unlock_irqrestore(&priv->base.lock, flags); - return ret; + fifo->mask |= 1ULL << engine->subdev.index; + schedule_work(&fifo->fault); } static const struct nvkm_enum @@ -486,14 +171,17 @@ gf100_fifo_sched_reason[] = { }; static void -gf100_fifo_intr_sched_ctxsw(struct gf100_fifo_priv *priv) +gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) { + struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; struct gf100_fifo_chan *chan; + unsigned long flags; u32 engn; + spin_lock_irqsave(&fifo->base.lock, flags); for (engn = 0; engn < 6; engn++) { - u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); u32 save = (stat & 0x00100000); /* maybe? */ u32 unk0 = (stat & 0x00040000); @@ -502,32 +190,36 @@ gf100_fifo_intr_sched_ctxsw(struct gf100_fifo_priv *priv) (void)save; if (busy && unk0 && unk1) { - if (!(chan = (void *)priv->base.channel[chid])) - continue; - if (!(engine = gf100_fifo_engine(priv, engn))) - continue; - gf100_fifo_recover(priv, engine, chan); + list_for_each_entry(chan, &fifo->chan, head) { + if (chan->base.chid == chid) { + engine = gf100_fifo_engine(fifo, engn); + if (!engine) + break; + gf100_fifo_recover(fifo, engine, chan); + break; + } + } } } + spin_unlock_irqrestore(&fifo->base.lock, flags); } static void -gf100_fifo_intr_sched(struct gf100_fifo_priv *priv) +gf100_fifo_intr_sched(struct gf100_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x00254c); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x00254c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; - char enunk[6] = ""; en = nvkm_enum_find(gf100_fifo_sched_reason, code); - if (!en) - snprintf(enunk, sizeof(enunk), "UNK%02x", code); - nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : ""); switch (code) { case 0x0a: - gf100_fifo_intr_sched_ctxsw(priv); + gf100_fifo_intr_sched_ctxsw(fifo); break; default: break; @@ -536,17 +228,17 @@ gf100_fifo_intr_sched(struct gf100_fifo_priv *priv) static const struct nvkm_enum gf100_fifo_fault_engine[] = { - { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR }, - { 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB }, - { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, - { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, - { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO }, - { 0x10, "PMSVLD", NULL, NVDEV_ENGINE_MSVLD }, - { 0x11, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP }, + { 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR }, + { 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM }, + { 0x07, "PFIFO", NULL, NVKM_ENGINE_FIFO }, + { 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD }, + { 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP }, { 0x13, "PCOUNTER" }, - { 0x14, "PMSPDEC", NULL, NVDEV_ENGINE_MSPDEC }, - { 0x15, "PCE0", NULL, NVDEV_ENGINE_CE0 }, - { 0x16, "PCE1", NULL, NVDEV_ENGINE_CE1 }, + { 0x14, "PMSPDEC", NULL, NVKM_ENGINE_MSPDEC }, + { 0x15, "PCE0", NULL, NVKM_ENGINE_CE0 }, + { 0x16, "PCE1", NULL, NVKM_ENGINE_CE1 }, { 0x17, "PDAEMON" }, {} }; @@ -594,79 +286,65 @@ gf100_fifo_fault_gpcclient[] = { }; static void -gf100_fifo_intr_fault(struct gf100_fifo_priv *priv, int unit) +gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) { - u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); - u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); - u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); - u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); + u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); + u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); + u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10)); u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; u32 write = (stat & 0x00000080); u32 hub = (stat & 0x00000040); u32 reason = (stat & 0x0000000f); - struct nvkm_object *engctx = NULL, *object; - struct nvkm_engine *engine = NULL; const struct nvkm_enum *er, *eu, *ec; - char erunk[6] = ""; - char euunk[6] = ""; - char ecunk[6] = ""; - char gpcid[3] = ""; + struct nvkm_engine *engine = NULL; + struct nvkm_fifo_chan *chan; + unsigned long flags; + char gpcid[8] = ""; er = nvkm_enum_find(gf100_fifo_fault_reason, reason); - if (!er) - snprintf(erunk, sizeof(erunk), "UNK%02X", reason); - eu = nvkm_enum_find(gf100_fifo_fault_engine, unit); + if (hub) { + ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client); + } else { + ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); + } + if (eu) { switch (eu->data2) { - case NVDEV_SUBDEV_BAR: - nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + case NVKM_SUBDEV_BAR: + nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); break; - case NVDEV_SUBDEV_INSTMEM: - nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + case NVKM_SUBDEV_INSTMEM: + nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); break; - case NVDEV_ENGINE_IFB: - nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + case NVKM_ENGINE_IFB: + nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: - engine = nvkm_engine(priv, eu->data2); - if (engine) - engctx = nvkm_engctx_get(engine, inst); + engine = nvkm_device_engine(device, eu->data2); break; } - } else { - snprintf(euunk, sizeof(euunk), "UNK%02x", unit); } - if (hub) { - ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client); - } else { - ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client); - snprintf(gpcid, sizeof(gpcid), "%d", gpc); - } + chan = nvkm_fifo_chan_inst(&fifo->base, (u64)inst << 12, &flags); - if (!ec) - snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); - - nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " - "channel 0x%010llx [%s]\n", write ? "write" : "read", - (u64)vahi << 32 | valo, er ? er->name : erunk, - eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", - ec ? ec->name : ecunk, (u64)inst << 12, - nvkm_client_name(engctx)); - - object = engctx; - while (object) { - switch (nv_mclass(object)) { - case FERMI_CHANNEL_GPFIFO: - gf100_fifo_recover(priv, engine, (void *)object); - break; - } - object = object->parent; - } + nvkm_error(subdev, + "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " + "reason %02x [%s] on channel %d [%010llx %s]\n", + write ? "write" : "read", (u64)vahi << 32 | valo, + unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", + reason, er ? er->name : "", chan ? chan->chid : -1, + (u64)inst << 12, + chan ? chan->object.client->name : "unknown"); - nvkm_engctx_put(engctx); + if (engine && chan) + gf100_fifo_recover(fifo, engine, (void *)chan); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } static const struct nvkm_bitfield @@ -678,290 +356,288 @@ gf100_fifo_pbdma_intr[] = { }; static void -gf100_fifo_intr_pbdma(struct gf100_fifo_priv *priv, int unit) +gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) { - u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); - u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)); + u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); + u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000)); + u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0x7f; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); - u32 show = stat; + struct nvkm_fifo_chan *chan; + unsigned long flags; + u32 show= stat; + char msg[128]; if (stat & 0x00800000) { - if (!gf100_fifo_swmthd(priv, chid, mthd, data)) - show &= ~0x00800000; + if (device->sw) { + if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) + show &= ~0x00800000; + } } if (show) { - nv_error(priv, "PBDMA%d:", unit); - nvkm_bitfield_print(gf100_fifo_pbdma_intr, show); - pr_cont("\n"); - nv_error(priv, - "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", - unit, chid, - nvkm_client_name_for_fifo_chid(&priv->base, chid), - subc, mthd, data); - } - - nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); - nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); + nvkm_snprintbf(msg, sizeof(msg), gf100_fifo_pbdma_intr, show); + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", + unit, show, msg, chid, chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", + subc, mthd, data); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); + } + + nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); + nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); } static void -gf100_fifo_intr_runlist(struct gf100_fifo_priv *priv) +gf100_fifo_intr_runlist(struct gf100_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x002a00); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x002a00); if (intr & 0x10000000) { - wake_up(&priv->runlist.wait); - nv_wr32(priv, 0x002a00, 0x10000000); + wake_up(&fifo->runlist.wait); + nvkm_wr32(device, 0x002a00, 0x10000000); intr &= ~0x10000000; } if (intr) { - nv_error(priv, "RUNLIST 0x%08x\n", intr); - nv_wr32(priv, 0x002a00, intr); + nvkm_error(subdev, "RUNLIST %08x\n", intr); + nvkm_wr32(device, 0x002a00, intr); } } static void -gf100_fifo_intr_engine_unit(struct gf100_fifo_priv *priv, int engn) +gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) { - u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04)); - u32 inte = nv_rd32(priv, 0x002628); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x0025a8 + (engn * 0x04)); + u32 inte = nvkm_rd32(device, 0x002628); u32 unkn; - nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); + nvkm_wr32(device, 0x0025a8 + (engn * 0x04), intr); for (unkn = 0; unkn < 8; unkn++) { u32 ints = (intr >> (unkn * 0x04)) & inte; if (ints & 0x1) { - nvkm_fifo_uevent(&priv->base); + nvkm_fifo_uevent(&fifo->base); ints &= ~1; } if (ints) { - nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints); - nv_mask(priv, 0x002628, ints, 0); + nvkm_error(subdev, "ENGINE %d %d %01x", + engn, unkn, ints); + nvkm_mask(device, 0x002628, ints, 0); } } } -static void -gf100_fifo_intr_engine(struct gf100_fifo_priv *priv) +void +gf100_fifo_intr_engine(struct gf100_fifo *fifo) { - u32 mask = nv_rd32(priv, 0x0025a4); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x0025a4); while (mask) { u32 unit = __ffs(mask); - gf100_fifo_intr_engine_unit(priv, unit); + gf100_fifo_intr_engine_unit(fifo, unit); mask &= ~(1 << unit); } } static void -gf100_fifo_intr(struct nvkm_subdev *subdev) +gf100_fifo_intr(struct nvkm_fifo *base) { - struct gf100_fifo_priv *priv = (void *)subdev; - u32 mask = nv_rd32(priv, 0x002140); - u32 stat = nv_rd32(priv, 0x002100) & mask; + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, 0x002140); + u32 stat = nvkm_rd32(device, 0x002100) & mask; if (stat & 0x00000001) { - u32 intr = nv_rd32(priv, 0x00252c); - nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr); - nv_wr32(priv, 0x002100, 0x00000001); + u32 intr = nvkm_rd32(device, 0x00252c); + nvkm_warn(subdev, "INTR 00000001: %08x\n", intr); + nvkm_wr32(device, 0x002100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000100) { - gf100_fifo_intr_sched(priv); - nv_wr32(priv, 0x002100, 0x00000100); + gf100_fifo_intr_sched(fifo); + nvkm_wr32(device, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x00010000) { - u32 intr = nv_rd32(priv, 0x00256c); - nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr); - nv_wr32(priv, 0x002100, 0x00010000); + u32 intr = nvkm_rd32(device, 0x00256c); + nvkm_warn(subdev, "INTR 00010000: %08x\n", intr); + nvkm_wr32(device, 0x002100, 0x00010000); stat &= ~0x00010000; } if (stat & 0x01000000) { - u32 intr = nv_rd32(priv, 0x00258c); - nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr); - nv_wr32(priv, 0x002100, 0x01000000); + u32 intr = nvkm_rd32(device, 0x00258c); + nvkm_warn(subdev, "INTR 01000000: %08x\n", intr); + nvkm_wr32(device, 0x002100, 0x01000000); stat &= ~0x01000000; } if (stat & 0x10000000) { - u32 mask = nv_rd32(priv, 0x00259c); + u32 mask = nvkm_rd32(device, 0x00259c); while (mask) { u32 unit = __ffs(mask); - gf100_fifo_intr_fault(priv, unit); - nv_wr32(priv, 0x00259c, (1 << unit)); + gf100_fifo_intr_fault(fifo, unit); + nvkm_wr32(device, 0x00259c, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 mask = nv_rd32(priv, 0x0025a0); + u32 mask = nvkm_rd32(device, 0x0025a0); while (mask) { u32 unit = __ffs(mask); - gf100_fifo_intr_pbdma(priv, unit); - nv_wr32(priv, 0x0025a0, (1 << unit)); + gf100_fifo_intr_pbdma(fifo, unit); + nvkm_wr32(device, 0x0025a0, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x20000000; } if (stat & 0x40000000) { - gf100_fifo_intr_runlist(priv); + gf100_fifo_intr_runlist(fifo); stat &= ~0x40000000; } if (stat & 0x80000000) { - gf100_fifo_intr_engine(priv); + gf100_fifo_intr_engine(fifo); stat &= ~0x80000000; } if (stat) { - nv_error(priv, "INTR 0x%08x\n", stat); - nv_mask(priv, 0x002140, stat, 0x00000000); - nv_wr32(priv, 0x002100, stat); + nvkm_error(subdev, "INTR %08x\n", stat); + nvkm_mask(device, 0x002140, stat, 0x00000000); + nvkm_wr32(device, 0x002100, stat); } } -static void -gf100_fifo_uevent_init(struct nvkm_event *event, int type, int index) -{ - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x80000000); -} - -static void -gf100_fifo_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x00000000); -} - -static const struct nvkm_event_func -gf100_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = gf100_fifo_uevent_init, - .fini = gf100_fifo_uevent_fini, -}; - static int -gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_fifo_oneinit(struct nvkm_fifo *base) { - struct gf100_fifo_priv *priv; + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 0, 127, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - INIT_WORK(&priv->fault, gf100_fifo_recover_work); - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->runlist.mem[0]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, + false, &fifo->runlist.mem[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->runlist.mem[1]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, + false, &fifo->runlist.mem[1]); if (ret) return ret; - init_waitqueue_head(&priv->runlist.wait); + init_waitqueue_head(&fifo->runlist.wait); - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0, - &priv->user.mem); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 0x1000, + 0x1000, false, &fifo->user.mem); if (ret) return ret; - ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, - &priv->user.bar); + ret = nvkm_bar_umap(device->bar, 128 * 0x1000, 12, &fifo->user.bar); if (ret) return ret; - ret = nvkm_event_init(&gf100_fifo_uevent_func, 1, 1, &priv->base.uevent); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = gf100_fifo_intr; - nv_engine(priv)->cclass = &gf100_fifo_cclass; - nv_engine(priv)->sclass = gf100_fifo_sclass; + nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); return 0; } static void -gf100_fifo_dtor(struct nvkm_object *object) +gf100_fifo_fini(struct nvkm_fifo *base) { - struct gf100_fifo_priv *priv = (void *)object; - - nvkm_gpuobj_unmap(&priv->user.bar); - nvkm_gpuobj_ref(NULL, &priv->user.mem); - nvkm_gpuobj_ref(NULL, &priv->runlist.mem[0]); - nvkm_gpuobj_ref(NULL, &priv->runlist.mem[1]); - - nvkm_fifo_destroy(&priv->base); + struct gf100_fifo *fifo = gf100_fifo(base); + flush_work(&fifo->fault); } -static int -gf100_fifo_init(struct nvkm_object *object) +static void +gf100_fifo_init(struct nvkm_fifo *base) { - struct gf100_fifo_priv *priv = (void *)object; - int ret, i; - - ret = nvkm_fifo_init(&priv->base); - if (ret) - return ret; + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int i; - nv_wr32(priv, 0x000204, 0xffffffff); - nv_wr32(priv, 0x002204, 0xffffffff); + nvkm_wr32(device, 0x000204, 0xffffffff); + nvkm_wr32(device, 0x002204, 0xffffffff); - priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204)); - nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr); + fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x002204)); + nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* assign engines to PBDMAs */ - if (priv->spoon_nr >= 3) { - nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */ - nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */ - nv_wr32(priv, 0x002210, ~(1 << 1)); /* PMSPP */ - nv_wr32(priv, 0x002214, ~(1 << 1)); /* PMSVLD */ - nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */ - nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */ + if (fifo->spoon_nr >= 3) { + nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */ + nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */ + nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */ + nvkm_wr32(device, 0x002214, ~(1 << 1)); /* PMSVLD */ + nvkm_wr32(device, 0x002218, ~(1 << 2)); /* PCE0 */ + nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */ } /* PBDMA[n] */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + for (i = 0; i < fifo->spoon_nr; i++) { + nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ } - nv_mask(priv, 0x002200, 0x00000001, 0x00000001); - nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + nvkm_mask(device, 0x002200, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); - nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x7fffffff); - nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ - return 0; + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0x7fffffff); + nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ +} + +static void * +gf100_fifo_dtor(struct nvkm_fifo *base) +{ + struct gf100_fifo *fifo = gf100_fifo(base); + nvkm_vm_put(&fifo->user.bar); + nvkm_memory_del(&fifo->user.mem); + nvkm_memory_del(&fifo->runlist.mem[0]); + nvkm_memory_del(&fifo->runlist.mem[1]); + return fifo; } -struct nvkm_oclass * -gf100_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fifo_ctor, - .dtor = gf100_fifo_dtor, - .init = gf100_fifo_init, - .fini = _nvkm_fifo_fini, +static const struct nvkm_fifo_func +gf100_fifo = { + .dtor = gf100_fifo_dtor, + .oneinit = gf100_fifo_oneinit, + .init = gf100_fifo_init, + .fini = gf100_fifo_fini, + .intr = gf100_fifo_intr, + .uevent_init = gf100_fifo_uevent_init, + .uevent_fini = gf100_fifo_uevent_fini, + .chan = { + &gf100_fifo_gpfifo_oclass, + NULL }, }; + +int +gf100_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + struct gf100_fifo *fifo; + + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + INIT_LIST_HEAD(&fifo->chan); + INIT_WORK(&fifo->fault, gf100_fifo_recover_work); + *pfifo = &fifo->base; + + return nvkm_fifo_ctor(&gf100_fifo, device, index, 128, &fifo->base); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h new file mode 100644 index 000000000000..c649ca9b53e3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h @@ -0,0 +1,31 @@ +#ifndef __GF100_FIFO_H__ +#define __GF100_FIFO_H__ +#define gf100_fifo(p) container_of((p), struct gf100_fifo, base) +#include "priv.h" + +#include <subdev/mmu.h> + +struct gf100_fifo { + struct nvkm_fifo base; + + struct list_head chan; + + struct work_struct fault; + u64 mask; + + struct { + struct nvkm_memory *mem[2]; + int active; + wait_queue_head_t wait; + } runlist; + + struct { + struct nvkm_memory *mem; + struct nvkm_vma bar; + } user; + int spoon_nr; +}; + +void gf100_fifo_intr_engine(struct gf100_fifo *); +void gf100_fifo_runlist_update(struct gf100_fifo *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index e10f9644140f..98970a0b7a66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -22,486 +22,121 @@ * Authors: Ben Skeggs */ #include "gk104.h" +#include "changk104.h" #include <core/client.h> -#include <core/engctx.h> #include <core/enum.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <subdev/bar.h> -#include <subdev/fb.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> +#include <engine/sw.h> #include <nvif/class.h> -#include <nvif/unpack.h> - -#define _(a,b) { (a), ((1ULL << (a)) | (b)) } -static const struct { - u64 subdev; - u64 mask; -} fifo_engine[] = { - _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_CE2)), - _(NVDEV_ENGINE_MSPDEC , 0), - _(NVDEV_ENGINE_MSPPP , 0), - _(NVDEV_ENGINE_MSVLD , 0), - _(NVDEV_ENGINE_CE0 , 0), - _(NVDEV_ENGINE_CE1 , 0), - _(NVDEV_ENGINE_MSENC , 0), -}; -#undef _ -#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) - -struct gk104_fifo_engn { - struct nvkm_gpuobj *runlist[2]; - int cur_runlist; - wait_queue_head_t wait; -}; - -struct gk104_fifo_priv { - struct nvkm_fifo base; - - struct work_struct fault; - u64 mask; - - struct gk104_fifo_engn engine[FIFO_ENGINE_NR]; - struct { - struct nvkm_gpuobj *mem; - struct nvkm_vma bar; - } user; - int spoon_nr; -}; - -struct gk104_fifo_base { - struct nvkm_fifo_base base; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; - -struct gk104_fifo_chan { - struct nvkm_fifo_chan base; - u32 engine; - enum { - STOPPED, - RUNNING, - KILLED - } state; -}; - -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static void -gk104_fifo_runlist_update(struct gk104_fifo_priv *priv, u32 engine) -{ - struct nvkm_bar *bar = nvkm_bar(priv); - struct gk104_fifo_engn *engn = &priv->engine[engine]; - struct nvkm_gpuobj *cur; - int i, p; - - mutex_lock(&nv_subdev(priv)->mutex); - cur = engn->runlist[engn->cur_runlist]; - engn->cur_runlist = !engn->cur_runlist; - - for (i = 0, p = 0; i < priv->base.max; i++) { - struct gk104_fifo_chan *chan = (void *)priv->base.channel[i]; - if (chan && chan->state == RUNNING && chan->engine == engine) { - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000000); - p += 8; - } - } - bar->flush(bar); - - nv_wr32(priv, 0x002270, cur->addr >> 12); - nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); - - if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 + - (engine * 0x08)) & 0x00100000), - msecs_to_jiffies(2000)) == 0) - nv_error(priv, "runlist %d update timeout\n", engine); - mutex_unlock(&nv_subdev(priv)->mutex); -} -static int -gk104_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) +void +gk104_fifo_uevent_fini(struct nvkm_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(parent); - struct gk104_fifo_base *base = (void *)parent->parent; - struct nvkm_engctx *ectx = (void *)object; - u32 addr; - int ret; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : - return 0; - case NVDEV_ENGINE_CE0: - case NVDEV_ENGINE_CE1: - case NVDEV_ENGINE_CE2: - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - if (!ectx->vma.node) { - ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); - if (ret) - return ret; - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - } - - nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset)); - bar->flush(bar); - return 0; + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); } -static int -gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) +void +gk104_fifo_uevent_init(struct nvkm_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(parent); - struct gk104_fifo_priv *priv = (void *)parent->engine; - struct gk104_fifo_base *base = (void *)parent->parent; - struct gk104_fifo_chan *chan = (void *)parent; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_CE0 : - case NVDEV_ENGINE_CE1 : - case NVDEV_ENGINE_CE2 : addr = 0x0000; break; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - nv_wr32(priv, 0x002634, chan->base.chid); - if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { - nv_error(priv, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - return -EBUSY; - } - - if (addr) { - nv_wo32(base, addr + 0x00, 0x00000000); - nv_wo32(base, addr + 0x04, 0x00000000); - bar->flush(bar); - } - - return 0; + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); } -static int -gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +void +gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) { - union { - struct kepler_channel_gpfifo_a_v0 v0; - } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); - struct gk104_fifo_priv *priv = (void *)engine; - struct gk104_fifo_base *base = (void *)parent; + struct gk104_fifo_engn *engn = &fifo->engine[engine]; struct gk104_fifo_chan *chan; - u64 usermem, ioffset, ilength; - int ret, i; - - nv_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x engine %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength, args->v0.engine); - } else - return ret; - - for (i = 0; i < FIFO_ENGINE_NR; i++) { - if (args->v0.engine & (1 << i)) { - if (nvkm_engine(parent, fifo_engine[i].subdev)) { - args->v0.engine = (1 << i); - break; - } - } - } - - if (i == FIFO_ENGINE_NR) { - nv_error(priv, "unsupported engines 0x%08x\n", args->v0.engine); - return -ENODEV; - } - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - priv->user.bar.offset, 0x200, - args->v0.pushbuf, - fifo_engine[i].mask, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = gk104_fifo_context_attach; - nv_parent(chan)->context_detach = gk104_fifo_context_detach; - chan->engine = i; - - usermem = chan->base.chid * 0x200; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - for (i = 0; i < 0x200; i += 4) - nv_wo32(priv->user.mem, usermem + i, 0x00000000); - - nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem)); - nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem)); - nv_wo32(base, 0x10, 0x0000face); - nv_wo32(base, 0x30, 0xfffff902); - nv_wo32(base, 0x48, lower_32_bits(ioffset)); - nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base, 0x84, 0x20400000); - nv_wo32(base, 0x94, 0x30000001); - nv_wo32(base, 0x9c, 0x00000100); - nv_wo32(base, 0xac, 0x0000001f); - nv_wo32(base, 0xe8, chan->base.chid); - nv_wo32(base, 0xb8, 0xf8000000); - nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */ - nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */ - bar->flush(bar); - return 0; -} - -static int -gk104_fifo_chan_init(struct nvkm_object *object) -{ - struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gk104_fifo_priv *priv = (void *)object->engine; - struct gk104_fifo_chan *chan = (void *)object; - u32 chid = chan->base.chid; - int ret; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_memory *cur; + int nr = 0; - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); - nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); - - if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); - gk104_fifo_runlist_update(priv, chan->engine); - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); - } - - return 0; -} - -static int -gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct gk104_fifo_priv *priv = (void *)object->engine; - struct gk104_fifo_chan *chan = (void *)object; - u32 chid = chan->base.chid; + mutex_lock(&subdev->mutex); + cur = engn->runlist[engn->cur_runlist]; + engn->cur_runlist = !engn->cur_runlist; - if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); - gk104_fifo_runlist_update(priv, chan->engine); + nvkm_kmap(cur); + list_for_each_entry(chan, &engn->chan, head) { + nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid); + nvkm_wo32(cur, (nr * 8) + 4, 0x00000000); + nr++; } + nvkm_done(cur); - nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -struct nvkm_ofuncs -gk104_fifo_chan_ofuncs = { - .ctor = gk104_fifo_chan_ctor, - .dtor = _nvkm_fifo_channel_dtor, - .init = gk104_fifo_chan_init, - .fini = gk104_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -gk104_fifo_sclass[] = { - { KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - instmem heap and vm setup - ******************************************************************************/ - -static int -gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk104_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0, - &base->pgd); - if (ret) - return ret; - - nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0208, 0xffffffff); - nv_wo32(base, 0x020c, 0x000000ff); - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - - return 0; -} - -static void -gk104_fifo_context_dtor(struct nvkm_object *object) -{ - struct gk104_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_ref(NULL, &base->pgd); - nvkm_fifo_context_destroy(&base->base); -} - -static struct nvkm_oclass -gk104_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_context_ctor, - .dtor = gk104_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; + nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); + nvkm_wr32(device, 0x002274, (engine << 20) | nr); -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - -static inline int -gk104_fifo_engidx(struct gk104_fifo_priv *priv, u32 engn) -{ - switch (engn) { - case NVDEV_ENGINE_GR : - case NVDEV_ENGINE_CE2 : engn = 0; break; - case NVDEV_ENGINE_MSVLD : engn = 1; break; - case NVDEV_ENGINE_MSPPP : engn = 2; break; - case NVDEV_ENGINE_MSPDEC: engn = 3; break; - case NVDEV_ENGINE_CE0 : engn = 4; break; - case NVDEV_ENGINE_CE1 : engn = 5; break; - case NVDEV_ENGINE_MSENC : engn = 6; break; - default: - return -1; - } - - return engn; + if (wait_event_timeout(engn->wait, !(nvkm_rd32(device, 0x002284 + + (engine * 0x08)) & 0x00100000), + msecs_to_jiffies(2000)) == 0) + nvkm_error(subdev, "runlist %d update timeout\n", engine); + mutex_unlock(&subdev->mutex); } static inline struct nvkm_engine * -gk104_fifo_engine(struct gk104_fifo_priv *priv, u32 engn) +gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn) { - if (engn >= ARRAY_SIZE(fifo_engine)) - return NULL; - return nvkm_engine(priv, fifo_engine[engn].subdev); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u64 subdevs = gk104_fifo_engine_subdev(engn); + if (subdevs) + return nvkm_device_engine(device, __ffs(subdevs)); + return NULL; } static void gk104_fifo_recover_work(struct work_struct *work) { - struct gk104_fifo_priv *priv = container_of(work, typeof(*priv), fault); - struct nvkm_object *engine; + struct gk104_fifo *fifo = container_of(work, typeof(*fifo), fault); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_engine *engine; unsigned long flags; u32 engn, engm = 0; u64 mask, todo; - spin_lock_irqsave(&priv->base.lock, flags); - mask = priv->mask; - priv->mask = 0ULL; - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); + mask = fifo->mask; + fifo->mask = 0ULL; + spin_unlock_irqrestore(&fifo->base.lock, flags); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) - engm |= 1 << gk104_fifo_engidx(priv, engn); - nv_mask(priv, 0x002630, engm, engm); + engm |= 1 << gk104_fifo_subdev_engine(engn); + nvkm_mask(device, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { - if ((engine = (void *)nvkm_engine(priv, engn))) { - nv_ofuncs(engine)->fini(engine, false); - WARN_ON(nv_ofuncs(engine)->init(engine)); + if ((engine = nvkm_device_engine(device, engn))) { + nvkm_subdev_fini(&engine->subdev, false); + WARN_ON(nvkm_subdev_init(&engine->subdev)); } - gk104_fifo_runlist_update(priv, gk104_fifo_engidx(priv, engn)); + gk104_fifo_runlist_update(fifo, gk104_fifo_subdev_engine(engn)); } - nv_wr32(priv, 0x00262c, engm); - nv_mask(priv, 0x002630, engm, 0x00000000); + nvkm_wr32(device, 0x00262c, engm); + nvkm_mask(device, 0x002630, engm, 0x00000000); } static void -gk104_fifo_recover(struct gk104_fifo_priv *priv, struct nvkm_engine *engine, +gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, struct gk104_fifo_chan *chan) { + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 chid = chan->base.chid; - unsigned long flags; - nv_error(priv, "%s engine fault on channel %d, recovering...\n", - nv_subdev(engine)->name, chid); + nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", + nvkm_subdev_name[engine->subdev.index], chid); + assert_spin_locked(&fifo->base.lock); - nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); - chan->state = KILLED; + nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); + list_del_init(&chan->head); + chan->killed = true; - spin_lock_irqsave(&priv->base.lock, flags); - priv->mask |= 1ULL << nv_engidx(engine); - spin_unlock_irqrestore(&priv->base.lock, flags); - schedule_work(&priv->fault); -} - -static int -gk104_fifo_swmthd(struct gk104_fifo_priv *priv, u32 chid, u32 mthd, u32 data) -{ - struct gk104_fifo_chan *chan = NULL; - struct nvkm_handle *bind; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; - if (unlikely(!chan)) - goto out; - - bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e); - if (likely(bind)) { - if (!mthd || !nv_call(bind->object, mthd, data)) - ret = 0; - nvkm_namedb_put(bind); - } - -out: - spin_unlock_irqrestore(&priv->base.lock, flags); - return ret; + fifo->mask |= 1ULL << engine->subdev.index; + schedule_work(&fifo->fault); } static const struct nvkm_enum @@ -516,18 +151,16 @@ gk104_fifo_bind_reason[] = { }; static void -gk104_fifo_intr_bind(struct gk104_fifo_priv *priv) +gk104_fifo_intr_bind(struct gk104_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x00252c); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x00252c); u32 code = intr & 0x000000ff; - const struct nvkm_enum *en; - char enunk[6] = ""; - - en = nvkm_enum_find(gk104_fifo_bind_reason, code); - if (!en) - snprintf(enunk, sizeof(enunk), "UNK%02x", code); + const struct nvkm_enum *en = + nvkm_enum_find(gk104_fifo_bind_reason, code); - nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk); + nvkm_error(subdev, "BIND_ERROR %02x [%s]\n", code, en ? en->name : ""); } static const struct nvkm_enum @@ -537,14 +170,17 @@ gk104_fifo_sched_reason[] = { }; static void -gk104_fifo_intr_sched_ctxsw(struct gk104_fifo_priv *priv) +gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) { + struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; struct gk104_fifo_chan *chan; + unsigned long flags; u32 engn; - for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { - u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + spin_lock_irqsave(&fifo->base.lock, flags); + for (engn = 0; engn < ARRAY_SIZE(fifo->engine); engn++) { + u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); u32 next = (stat & 0x07ff0000) >> 16; u32 chsw = (stat & 0x00008000); @@ -555,32 +191,35 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo_priv *priv) (void)save; if (busy && chsw) { - if (!(chan = (void *)priv->base.channel[chid])) - continue; - if (!(engine = gk104_fifo_engine(priv, engn))) - continue; - gk104_fifo_recover(priv, engine, chan); + list_for_each_entry(chan, &fifo->engine[engn].chan, head) { + if (chan->base.chid == chid) { + engine = gk104_fifo_engine(fifo, engn); + if (!engine) + break; + gk104_fifo_recover(fifo, engine, chan); + break; + } + } } } + spin_unlock_irqrestore(&fifo->base.lock, flags); } static void -gk104_fifo_intr_sched(struct gk104_fifo_priv *priv) +gk104_fifo_intr_sched(struct gk104_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x00254c); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x00254c); u32 code = intr & 0x000000ff; - const struct nvkm_enum *en; - char enunk[6] = ""; - - en = nvkm_enum_find(gk104_fifo_sched_reason, code); - if (!en) - snprintf(enunk, sizeof(enunk), "UNK%02x", code); + const struct nvkm_enum *en = + nvkm_enum_find(gk104_fifo_sched_reason, code); - nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : ""); switch (code) { case 0x0a: - gk104_fifo_intr_sched_ctxsw(priv); + gk104_fifo_intr_sched_ctxsw(fifo); break; default: break; @@ -588,38 +227,42 @@ gk104_fifo_intr_sched(struct gk104_fifo_priv *priv) } static void -gk104_fifo_intr_chsw(struct gk104_fifo_priv *priv) +gk104_fifo_intr_chsw(struct gk104_fifo *fifo) { - u32 stat = nv_rd32(priv, 0x00256c); - nv_error(priv, "CHSW_ERROR 0x%08x\n", stat); - nv_wr32(priv, 0x00256c, stat); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x00256c); + nvkm_error(subdev, "CHSW_ERROR %08x\n", stat); + nvkm_wr32(device, 0x00256c, stat); } static void -gk104_fifo_intr_dropped_fault(struct gk104_fifo_priv *priv) +gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo) { - u32 stat = nv_rd32(priv, 0x00259c); - nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x00259c); + nvkm_error(subdev, "DROPPED_MMU_FAULT %08x\n", stat); } static const struct nvkm_enum gk104_fifo_fault_engine[] = { - { 0x00, "GR", NULL, NVDEV_ENGINE_GR }, - { 0x03, "IFB", NULL, NVDEV_ENGINE_IFB }, - { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, - { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, - { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO }, - { 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO }, - { 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO }, - { 0x10, "MSVLD", NULL, NVDEV_ENGINE_MSVLD }, - { 0x11, "MSPPP", NULL, NVDEV_ENGINE_MSPPP }, + { 0x00, "GR", NULL, NVKM_ENGINE_GR }, + { 0x03, "IFB", NULL, NVKM_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM }, + { 0x07, "PBDMA0", NULL, NVKM_ENGINE_FIFO }, + { 0x08, "PBDMA1", NULL, NVKM_ENGINE_FIFO }, + { 0x09, "PBDMA2", NULL, NVKM_ENGINE_FIFO }, + { 0x10, "MSVLD", NULL, NVKM_ENGINE_MSVLD }, + { 0x11, "MSPPP", NULL, NVKM_ENGINE_MSPPP }, { 0x13, "PERF" }, - { 0x14, "MSPDEC", NULL, NVDEV_ENGINE_MSPDEC }, - { 0x15, "CE0", NULL, NVDEV_ENGINE_CE0 }, - { 0x16, "CE1", NULL, NVDEV_ENGINE_CE1 }, + { 0x14, "MSPDEC", NULL, NVKM_ENGINE_MSPDEC }, + { 0x15, "CE0", NULL, NVKM_ENGINE_CE0 }, + { 0x16, "CE1", NULL, NVKM_ENGINE_CE1 }, { 0x17, "PMU" }, - { 0x19, "MSENC", NULL, NVDEV_ENGINE_MSENC }, - { 0x1b, "CE2", NULL, NVDEV_ENGINE_CE2 }, + { 0x19, "MSENC", NULL, NVKM_ENGINE_MSENC }, + { 0x1b, "CE2", NULL, NVKM_ENGINE_CE2 }, {} }; @@ -708,80 +351,65 @@ gk104_fifo_fault_gpcclient[] = { }; static void -gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit) +gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) { - u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); - u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); - u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); - u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); + u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); + u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); + u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10)); u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; u32 write = (stat & 0x00000080); u32 hub = (stat & 0x00000040); u32 reason = (stat & 0x0000000f); - struct nvkm_object *engctx = NULL, *object; - struct nvkm_engine *engine = NULL; const struct nvkm_enum *er, *eu, *ec; - char erunk[6] = ""; - char euunk[6] = ""; - char ecunk[6] = ""; - char gpcid[3] = ""; + struct nvkm_engine *engine = NULL; + struct nvkm_fifo_chan *chan; + unsigned long flags; + char gpcid[8] = ""; er = nvkm_enum_find(gk104_fifo_fault_reason, reason); - if (!er) - snprintf(erunk, sizeof(erunk), "UNK%02X", reason); - eu = nvkm_enum_find(gk104_fifo_fault_engine, unit); + if (hub) { + ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client); + } else { + ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); + } + if (eu) { switch (eu->data2) { - case NVDEV_SUBDEV_BAR: - nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + case NVKM_SUBDEV_BAR: + nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); break; - case NVDEV_SUBDEV_INSTMEM: - nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + case NVKM_SUBDEV_INSTMEM: + nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); break; - case NVDEV_ENGINE_IFB: - nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + case NVKM_ENGINE_IFB: + nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: - engine = nvkm_engine(priv, eu->data2); - if (engine) - engctx = nvkm_engctx_get(engine, inst); + engine = nvkm_device_engine(device, eu->data2); break; } - } else { - snprintf(euunk, sizeof(euunk), "UNK%02x", unit); } - if (hub) { - ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client); - } else { - ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client); - snprintf(gpcid, sizeof(gpcid), "%d", gpc); - } + chan = nvkm_fifo_chan_inst(&fifo->base, (u64)inst << 12, &flags); - if (!ec) - snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); - - nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " - "channel 0x%010llx [%s]\n", write ? "write" : "read", - (u64)vahi << 32 | valo, er ? er->name : erunk, - eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", - ec ? ec->name : ecunk, (u64)inst << 12, - nvkm_client_name(engctx)); - - object = engctx; - while (object) { - switch (nv_mclass(object)) { - case KEPLER_CHANNEL_GPFIFO_A: - case MAXWELL_CHANNEL_GPFIFO_A: - gk104_fifo_recover(priv, engine, (void *)object); - break; - } - object = object->parent; - } + nvkm_error(subdev, + "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " + "reason %02x [%s] on channel %d [%010llx %s]\n", + write ? "write" : "read", (u64)vahi << 32 | valo, + unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", + reason, er ? er->name : "", chan ? chan->chid : -1, + (u64)inst << 12, + chan ? chan->object.client->name : "unknown"); - nvkm_engctx_put(engctx); + if (engine && chan) + gk104_fifo_recover(fifo, engine, (void *)chan); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { @@ -819,35 +447,42 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { }; static void -gk104_fifo_intr_pbdma_0(struct gk104_fifo_priv *priv, int unit) +gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) { - u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000)); - u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask; - u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, 0x04010c + (unit * 0x2000)); + u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)) & mask; + u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); + u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000)); + u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; + struct nvkm_fifo_chan *chan; + unsigned long flags; + char msg[128]; if (stat & 0x00800000) { - if (!gk104_fifo_swmthd(priv, chid, mthd, data)) - show &= ~0x00800000; - nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); + if (device->sw) { + if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) + show &= ~0x00800000; + } + nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); } if (show) { - nv_error(priv, "PBDMA%d:", unit); - nvkm_bitfield_print(gk104_fifo_pbdma_intr_0, show); - pr_cont("\n"); - nv_error(priv, - "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", - unit, chid, - nvkm_client_name_for_fifo_chid(&priv->base, chid), - subc, mthd, data); + nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_0, show); + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", + unit, show, msg, chid, chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", + subc, mthd, data); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } - nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); + nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); } static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { @@ -860,280 +495,266 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { }; static void -gk104_fifo_intr_pbdma_1(struct gk104_fifo_priv *priv, int unit) +gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit) { - u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000)); - u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask; - u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, 0x04014c + (unit * 0x2000)); + u32 stat = nvkm_rd32(device, 0x040148 + (unit * 0x2000)) & mask; + u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff; + char msg[128]; if (stat) { - nv_error(priv, "PBDMA%d:", unit); - nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat); - pr_cont("\n"); - nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid, - nv_rd32(priv, 0x040150 + (unit * 0x2000)), - nv_rd32(priv, 0x040154 + (unit * 0x2000))); + nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_1, stat); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d %08x %08x\n", + unit, stat, msg, chid, + nvkm_rd32(device, 0x040150 + (unit * 0x2000)), + nvkm_rd32(device, 0x040154 + (unit * 0x2000))); } - nv_wr32(priv, 0x040148 + (unit * 0x2000), stat); + nvkm_wr32(device, 0x040148 + (unit * 0x2000), stat); } static void -gk104_fifo_intr_runlist(struct gk104_fifo_priv *priv) +gk104_fifo_intr_runlist(struct gk104_fifo *fifo) { - u32 mask = nv_rd32(priv, 0x002a00); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x002a00); while (mask) { u32 engn = __ffs(mask); - wake_up(&priv->engine[engn].wait); - nv_wr32(priv, 0x002a00, 1 << engn); + wake_up(&fifo->engine[engn].wait); + nvkm_wr32(device, 0x002a00, 1 << engn); mask &= ~(1 << engn); } } static void -gk104_fifo_intr_engine(struct gk104_fifo_priv *priv) +gk104_fifo_intr_engine(struct gk104_fifo *fifo) { - nvkm_fifo_uevent(&priv->base); + nvkm_fifo_uevent(&fifo->base); } -static void -gk104_fifo_intr(struct nvkm_subdev *subdev) +void +gk104_fifo_intr(struct nvkm_fifo *base) { - struct gk104_fifo_priv *priv = (void *)subdev; - u32 mask = nv_rd32(priv, 0x002140); - u32 stat = nv_rd32(priv, 0x002100) & mask; + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, 0x002140); + u32 stat = nvkm_rd32(device, 0x002100) & mask; if (stat & 0x00000001) { - gk104_fifo_intr_bind(priv); - nv_wr32(priv, 0x002100, 0x00000001); + gk104_fifo_intr_bind(fifo); + nvkm_wr32(device, 0x002100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000010) { - nv_error(priv, "PIO_ERROR\n"); - nv_wr32(priv, 0x002100, 0x00000010); + nvkm_error(subdev, "PIO_ERROR\n"); + nvkm_wr32(device, 0x002100, 0x00000010); stat &= ~0x00000010; } if (stat & 0x00000100) { - gk104_fifo_intr_sched(priv); - nv_wr32(priv, 0x002100, 0x00000100); + gk104_fifo_intr_sched(fifo); + nvkm_wr32(device, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x00010000) { - gk104_fifo_intr_chsw(priv); - nv_wr32(priv, 0x002100, 0x00010000); + gk104_fifo_intr_chsw(fifo); + nvkm_wr32(device, 0x002100, 0x00010000); stat &= ~0x00010000; } if (stat & 0x00800000) { - nv_error(priv, "FB_FLUSH_TIMEOUT\n"); - nv_wr32(priv, 0x002100, 0x00800000); + nvkm_error(subdev, "FB_FLUSH_TIMEOUT\n"); + nvkm_wr32(device, 0x002100, 0x00800000); stat &= ~0x00800000; } if (stat & 0x01000000) { - nv_error(priv, "LB_ERROR\n"); - nv_wr32(priv, 0x002100, 0x01000000); + nvkm_error(subdev, "LB_ERROR\n"); + nvkm_wr32(device, 0x002100, 0x01000000); stat &= ~0x01000000; } if (stat & 0x08000000) { - gk104_fifo_intr_dropped_fault(priv); - nv_wr32(priv, 0x002100, 0x08000000); + gk104_fifo_intr_dropped_fault(fifo); + nvkm_wr32(device, 0x002100, 0x08000000); stat &= ~0x08000000; } if (stat & 0x10000000) { - u32 mask = nv_rd32(priv, 0x00259c); + u32 mask = nvkm_rd32(device, 0x00259c); while (mask) { u32 unit = __ffs(mask); - gk104_fifo_intr_fault(priv, unit); - nv_wr32(priv, 0x00259c, (1 << unit)); + gk104_fifo_intr_fault(fifo, unit); + nvkm_wr32(device, 0x00259c, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 mask = nv_rd32(priv, 0x0025a0); + u32 mask = nvkm_rd32(device, 0x0025a0); while (mask) { u32 unit = __ffs(mask); - gk104_fifo_intr_pbdma_0(priv, unit); - gk104_fifo_intr_pbdma_1(priv, unit); - nv_wr32(priv, 0x0025a0, (1 << unit)); + gk104_fifo_intr_pbdma_0(fifo, unit); + gk104_fifo_intr_pbdma_1(fifo, unit); + nvkm_wr32(device, 0x0025a0, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x20000000; } if (stat & 0x40000000) { - gk104_fifo_intr_runlist(priv); + gk104_fifo_intr_runlist(fifo); stat &= ~0x40000000; } if (stat & 0x80000000) { - nv_wr32(priv, 0x002100, 0x80000000); - gk104_fifo_intr_engine(priv); + nvkm_wr32(device, 0x002100, 0x80000000); + gk104_fifo_intr_engine(fifo); stat &= ~0x80000000; } if (stat) { - nv_error(priv, "INTR 0x%08x\n", stat); - nv_mask(priv, 0x002140, stat, 0x00000000); - nv_wr32(priv, 0x002100, stat); + nvkm_error(subdev, "INTR %08x\n", stat); + nvkm_mask(device, 0x002140, stat, 0x00000000); + nvkm_wr32(device, 0x002100, stat); } } -static void -gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index) +void +gk104_fifo_fini(struct nvkm_fifo *base) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x80000000); + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + flush_work(&fifo->fault); + /* allow mmu fault interrupts, even when we're not using fifo */ + nvkm_mask(device, 0x002140, 0x10000000, 0x10000000); } -static void -gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +int +gk104_fifo_oneinit(struct nvkm_fifo *base) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x00000000); -} + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + int ret, i; -static const struct nvkm_event_func -gk104_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = gk104_fifo_uevent_init, - .fini = gk104_fifo_uevent_fini, -}; + for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x8000, 0x1000, false, + &fifo->engine[i].runlist[0]); + if (ret) + return ret; -int -gk104_fifo_fini(struct nvkm_object *object, bool suspend) -{ - struct gk104_fifo_priv *priv = (void *)object; - int ret; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x8000, 0x1000, false, + &fifo->engine[i].runlist[1]); + if (ret) + return ret; + + init_waitqueue_head(&fifo->engine[i].wait); + INIT_LIST_HEAD(&fifo->engine[i].chan); + } - ret = nvkm_fifo_fini(&priv->base, suspend); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + fifo->base.nr * 0x200, 0x1000, true, + &fifo->user.mem); if (ret) return ret; - /* allow mmu fault interrupts, even when we're not using fifo */ - nv_mask(priv, 0x002140, 0x10000000, 0x10000000); + ret = nvkm_bar_umap(device->bar, fifo->base.nr * 0x200, 12, + &fifo->user.bar); + if (ret) + return ret; + + nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); return 0; } -int -gk104_fifo_init(struct nvkm_object *object) +void +gk104_fifo_init(struct nvkm_fifo *base) { - struct gk104_fifo_priv *priv = (void *)object; - int ret, i; - - ret = nvkm_fifo_init(&priv->base); - if (ret) - return ret; + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int i; /* enable all available PBDMA units */ - nv_wr32(priv, 0x000204, 0xffffffff); - priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204)); - nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr); + nvkm_wr32(device, 0x000204, 0xffffffff); + fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x000204)); + nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* PBDMA[n] */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + for (i = 0; i < fifo->spoon_nr; i++) { + nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ } /* PBDMA[n].HCE */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ + for (i = 0; i < fifo->spoon_nr; i++) { + nvkm_wr32(device, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ } - nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); - nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x7fffffff); - return 0; + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0x7fffffff); } -void -gk104_fifo_dtor(struct nvkm_object *object) +void * +gk104_fifo_dtor(struct nvkm_fifo *base) { - struct gk104_fifo_priv *priv = (void *)object; + struct gk104_fifo *fifo = gk104_fifo(base); int i; - nvkm_gpuobj_unmap(&priv->user.bar); - nvkm_gpuobj_ref(NULL, &priv->user.mem); + nvkm_vm_put(&fifo->user.bar); + nvkm_memory_del(&fifo->user.mem); - for (i = 0; i < FIFO_ENGINE_NR; i++) { - nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[1]); - nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[0]); + for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { + nvkm_memory_del(&fifo->engine[i].runlist[1]); + nvkm_memory_del(&fifo->engine[i].runlist[0]); } - nvkm_fifo_destroy(&priv->base); + return fifo; } int -gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gk104_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, int nr, struct nvkm_fifo **pfifo) { - struct gk104_fifo_impl *impl = (void *)oclass; - struct gk104_fifo_priv *priv; - int ret, i; + struct gk104_fifo *fifo; - ret = nvkm_fifo_create(parent, engine, oclass, 0, - impl->channels - 1, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - INIT_WORK(&priv->fault, gk104_fifo_recover_work); - - for (i = 0; i < FIFO_ENGINE_NR; i++) { - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, - 0, &priv->engine[i].runlist[0]); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, - 0, &priv->engine[i].runlist[1]); - if (ret) - return ret; - - init_waitqueue_head(&priv->engine[i].wait); - } - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); - if (ret) - return ret; + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + INIT_WORK(&fifo->fault, gk104_fifo_recover_work); + *pfifo = &fifo->base; - ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, - &priv->user.bar); - if (ret) - return ret; - - ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &priv->base.uevent); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = gk104_fifo_intr; - nv_engine(priv)->cclass = &gk104_fifo_cclass; - nv_engine(priv)->sclass = gk104_fifo_sclass; - return 0; + return nvkm_fifo_ctor(func, device, index, nr, &fifo->base); } -struct nvkm_oclass * -gk104_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = gk104_fifo_fini, +static const struct nvkm_fifo_func +gk104_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gk104_fifo_gpfifo_oclass, + NULL }, - .channels = 4096, -}.base; +}; + +int +gk104_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gk104_fifo, device, index, 4096, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index 318d30d6ee1a..5afd9b5ec5d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -1,18 +1,77 @@ -#ifndef __NVKM_FIFO_NVE0_H__ -#define __NVKM_FIFO_NVE0_H__ -#include <engine/fifo.h> - -int gk104_fifo_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gk104_fifo_dtor(struct nvkm_object *); -int gk104_fifo_init(struct nvkm_object *); -int gk104_fifo_fini(struct nvkm_object *, bool); - -struct gk104_fifo_impl { - struct nvkm_oclass base; - u32 channels; +#ifndef __GK104_FIFO_H__ +#define __GK104_FIFO_H__ +#define gk104_fifo(p) container_of((p), struct gk104_fifo, base) +#include "priv.h" + +#include <subdev/mmu.h> + +struct gk104_fifo_engn { + struct nvkm_memory *runlist[2]; + int cur_runlist; + wait_queue_head_t wait; + struct list_head chan; +}; + +struct gk104_fifo { + struct nvkm_fifo base; + + struct work_struct fault; + u64 mask; + + struct gk104_fifo_engn engine[7]; + struct { + struct nvkm_memory *mem; + struct nvkm_vma bar; + } user; + int spoon_nr; }; -extern struct nvkm_ofuncs gk104_fifo_chan_ofuncs; +int gk104_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, int nr, struct nvkm_fifo **); +void *gk104_fifo_dtor(struct nvkm_fifo *); +int gk104_fifo_oneinit(struct nvkm_fifo *); +void gk104_fifo_init(struct nvkm_fifo *); +void gk104_fifo_fini(struct nvkm_fifo *); +void gk104_fifo_intr(struct nvkm_fifo *); +void gk104_fifo_uevent_init(struct nvkm_fifo *); +void gk104_fifo_uevent_fini(struct nvkm_fifo *); +void gk104_fifo_runlist_update(struct gk104_fifo *, u32 engine); + +static inline u64 +gk104_fifo_engine_subdev(int engine) +{ + switch (engine) { + case 0: return (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_SW) | + (1ULL << NVKM_ENGINE_CE2); + case 1: return (1ULL << NVKM_ENGINE_MSPDEC); + case 2: return (1ULL << NVKM_ENGINE_MSPPP); + case 3: return (1ULL << NVKM_ENGINE_MSVLD); + case 4: return (1ULL << NVKM_ENGINE_CE0); + case 5: return (1ULL << NVKM_ENGINE_CE1); + case 6: return (1ULL << NVKM_ENGINE_MSENC); + default: + WARN_ON(1); + return 0; + } +} + +static inline int +gk104_fifo_subdev_engine(int subdev) +{ + switch (subdev) { + case NVKM_ENGINE_GR: + case NVKM_ENGINE_SW: + case NVKM_ENGINE_CE2 : return 0; + case NVKM_ENGINE_MSPDEC: return 1; + case NVKM_ENGINE_MSPPP : return 2; + case NVKM_ENGINE_MSVLD : return 3; + case NVKM_ENGINE_CE0 : return 4; + case NVKM_ENGINE_CE1 : return 5; + case NVKM_ENGINE_MSENC : return 6; + default: + WARN_ON(1); + return 0; + } +} #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c index 927092217a06..ce01c1a7d41c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c @@ -22,15 +22,25 @@ * Authors: Ben Skeggs */ #include "gk104.h" +#include "changk104.h" -struct nvkm_oclass * -gk208_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = _nvkm_fifo_fini, +static const struct nvkm_fifo_func +gk208_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gk104_fifo_gpfifo_oclass, + NULL }, - .channels = 1024, -}.base; +}; + +int +gk208_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gk208_fifo, device, index, 1024, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c index b30dc87a1357..b47fe98f4181 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c @@ -20,15 +20,25 @@ * DEALINGS IN THE SOFTWARE. */ #include "gk104.h" +#include "changk104.h" -struct nvkm_oclass * -gk20a_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = gk104_fifo_fini, +static const struct nvkm_fifo_func +gk20a_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gk104_fifo_gpfifo_oclass, + NULL }, - .channels = 128, -}.base; +}; + +int +gk20a_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gk20a_fifo, device, index, 128, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c index 749d525dd8e3..2db629f1bf7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c @@ -22,36 +22,25 @@ * Authors: Ben Skeggs */ #include "gk104.h" +#include "changk104.h" -#include <nvif/class.h> - -static struct nvkm_oclass -gm204_fifo_sclass[] = { - { MAXWELL_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, - {} +static const struct nvkm_fifo_func +gm204_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gm204_fifo_gpfifo_oclass, + NULL + }, }; -static int -gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm204_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - int ret = gk104_fifo_ctor(parent, engine, oclass, data, size, pobject); - if (ret == 0) { - struct gk104_fifo_priv *priv = (void *)*pobject; - nv_engine(priv)->sclass = gm204_fifo_sclass; - } - return ret; + return gk104_fifo_new_(&gm204_fifo, device, index, 4096, pfifo); } - -struct nvkm_oclass * -gm204_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = _nvkm_fifo_fini, - }, - .channels = 4096, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c new file mode 100644 index 000000000000..ae6375d9760f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "gk104.h" +#include "changk104.h" + +static const struct nvkm_fifo_func +gm20b_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gm204_fifo_gpfifo_oclass, + NULL + }, +}; + +int +gm20b_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gm20b_fifo, device, index, 512, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c new file mode 100644 index 000000000000..820132363f68 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c @@ -0,0 +1,94 @@ +/* + * 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 "channv50.h" + +#include <core/client.h> +#include <core/ramht.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static int +g84_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv50_channel_gpfifo_v0 v0; + } *args = data; + struct nv50_fifo *fifo = nv50_fifo(base); + struct nv50_fifo_chan *chan; + u64 ioffset, ilength; + int ret; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "pushbuf %llx ioffset %016llx " + "ilength %08x\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.ioffset, args->v0.ilength); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = g84_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10); + nvkm_wo32(chan->ramfc, 0x98, chan->base.inst->addr >> 12); + nvkm_done(chan->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +g84_fifo_gpfifo_oclass = { + .base.oclass = G82_CHANNEL_GPFIFO, + .base.minver = 0, + .base.maxver = 0, + .ctor = g84_fifo_gpfifo_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c new file mode 100644 index 000000000000..e7cbc139c1d4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c @@ -0,0 +1,293 @@ +/* + * 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 "changf100.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <subdev/fb.h> +#include <subdev/timer.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static u32 +gf100_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) +{ + switch (engine->subdev.index) { + case NVKM_ENGINE_SW : return 0; + case NVKM_ENGINE_GR : return 0x0210; + case NVKM_ENGINE_CE0 : return 0x0230; + case NVKM_ENGINE_CE1 : return 0x0240; + case NVKM_ENGINE_MSPDEC: return 0x0250; + case NVKM_ENGINE_MSPPP : return 0x0260; + case NVKM_ENGINE_MSVLD : return 0x0270; + default: + WARN_ON(1); + return 0; + } +} + +static int +gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + const u32 offset = gf100_fifo_gpfifo_engine_addr(engine); + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct nvkm_subdev *subdev = &chan->fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_gpuobj *inst = chan->base.inst; + int ret = 0; + + nvkm_wr32(device, 0x002634, chan->base.chid); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x002634) == chan->base.chid) + break; + ) < 0) { + nvkm_error(subdev, "channel %d [%s] kick timeout\n", + chan->base.chid, chan->base.object.client->name); + ret = -EBUSY; + if (suspend) + return ret; + } + + if (offset) { + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, 0x00000000); + nvkm_wo32(inst, offset + 0x04, 0x00000000); + nvkm_done(inst); + } + + return ret; +} + +static int +gf100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + const u32 offset = gf100_fifo_gpfifo_engine_addr(engine); + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct nvkm_gpuobj *inst = chan->base.inst; + + if (offset) { + u64 addr = chan->engn[engine->subdev.index].vma.offset; + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, lower_32_bits(addr) | 4); + nvkm_wo32(inst, offset + 0x04, upper_32_bits(addr)); + nvkm_done(inst); + } + + return 0; +} + +static void +gf100_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + nvkm_gpuobj_unmap(&chan->engn[engine->subdev.index].vma); + nvkm_gpuobj_del(&chan->engn[engine->subdev.index].inst); +} + +static int +gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) +{ + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + int engn = engine->subdev.index; + int ret; + + if (!gf100_fifo_gpfifo_engine_addr(engine)) + return 0; + + ret = nvkm_object_bind(object, NULL, 0, &chan->engn[engn].inst); + if (ret) + return ret; + + return nvkm_gpuobj_map(chan->engn[engn].inst, chan->vm, + NV_MEM_ACCESS_RW, &chan->engn[engn].vma); +} + +static void +gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) +{ + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct gf100_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 coff = chan->base.chid * 8; + + if (!list_empty(&chan->head) && !chan->killed) { + list_del_init(&chan->head); + nvkm_mask(device, 0x003004 + coff, 0x00000001, 0x00000000); + gf100_fifo_runlist_update(fifo); + } + + gf100_fifo_intr_engine(fifo); + + nvkm_wr32(device, 0x003000 + coff, 0x00000000); +} + +static void +gf100_fifo_gpfifo_init(struct nvkm_fifo_chan *base) +{ + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct gf100_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 addr = chan->base.inst->addr >> 12; + u32 coff = chan->base.chid * 8; + + nvkm_wr32(device, 0x003000 + coff, 0xc0000000 | addr); + + if (list_empty(&chan->head) && !chan->killed) { + list_add_tail(&chan->head, &fifo->chan); + nvkm_wr32(device, 0x003004 + coff, 0x001f0001); + gf100_fifo_runlist_update(fifo); + } +} + +static void * +gf100_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base) +{ + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + nvkm_vm_ref(NULL, &chan->vm, chan->pgd); + nvkm_gpuobj_del(&chan->pgd); + return chan; +} + +static const struct nvkm_fifo_chan_func +gf100_fifo_gpfifo_func = { + .dtor = gf100_fifo_gpfifo_dtor, + .init = gf100_fifo_gpfifo_init, + .fini = gf100_fifo_gpfifo_fini, + .ntfy = g84_fifo_chan_ntfy, + .engine_ctor = gf100_fifo_gpfifo_engine_ctor, + .engine_dtor = gf100_fifo_gpfifo_engine_dtor, + .engine_init = gf100_fifo_gpfifo_engine_init, + .engine_fini = gf100_fifo_gpfifo_engine_fini, +}; + +static int +gf100_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + union { + struct fermi_channel_gpfifo_v0 v0; + } *args = data; + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_object *parent = oclass->parent; + struct gf100_fifo_chan *chan; + u64 usermem, ioffset, ilength; + int ret, i; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.vm, args->v0.ioffset, + args->v0.ilength); + } else + return ret; + + /* allocate channel */ + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + chan->fifo = fifo; + INIT_LIST_HEAD(&chan->head); + + ret = nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func, &fifo->base, + 0x1000, 0x1000, true, args->v0.vm, 0, + (1ULL << NVKM_ENGINE_CE0) | + (1ULL << NVKM_ENGINE_CE1) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MSPDEC) | + (1ULL << NVKM_ENGINE_MSPPP) | + (1ULL << NVKM_ENGINE_MSVLD) | + (1ULL << NVKM_ENGINE_SW), + 1, fifo->user.bar.offset, 0x1000, + oclass, &chan->base); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + /* page directory */ + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &chan->pgd); + if (ret) + return ret; + + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x0200, lower_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0204, upper_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0208, 0xffffffff); + nvkm_wo32(chan->base.inst, 0x020c, 0x000000ff); + nvkm_done(chan->base.inst); + + ret = nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); + if (ret) + return ret; + + /* clear channel control registers */ + + usermem = chan->base.chid * 0x1000; + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(fifo->user.mem); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); + nvkm_done(fifo->user.mem); + usermem = nvkm_memory_addr(fifo->user.mem) + usermem; + + /* RAMFC */ + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x10, 0x0000face); + nvkm_wo32(chan->base.inst, 0x30, 0xfffff902); + nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) | + (ilength << 16)); + nvkm_wo32(chan->base.inst, 0x54, 0x00000002); + nvkm_wo32(chan->base.inst, 0x84, 0x20400000); + nvkm_wo32(chan->base.inst, 0x94, 0x30000001); + nvkm_wo32(chan->base.inst, 0x9c, 0x00000100); + nvkm_wo32(chan->base.inst, 0xa4, 0x1f1f1f1f); + nvkm_wo32(chan->base.inst, 0xa8, 0x1f1f1f1f); + nvkm_wo32(chan->base.inst, 0xac, 0x0000001f); + nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000); + nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(chan->base.inst); + return 0; +} + +const struct nvkm_fifo_chan_oclass +gf100_fifo_gpfifo_oclass = { + .base.oclass = FERMI_CHANNEL_GPFIFO, + .base.minver = 0, + .base.maxver = 0, + .ctor = gf100_fifo_gpfifo_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c new file mode 100644 index 000000000000..0b817540a9e4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -0,0 +1,323 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "changk104.h" + +#include <core/client.h> +#include <core/gpuobj.h> +#include <subdev/fb.h> +#include <subdev/mmu.h> +#include <subdev/timer.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static int +gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan) +{ + struct gk104_fifo *fifo = chan->fifo; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_client *client = chan->base.object.client; + + nvkm_wr32(device, 0x002634, chan->base.chid); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) + break; + ) < 0) { + nvkm_error(subdev, "channel %d [%s] kick timeout\n", + chan->base.chid, client->name); + return -EBUSY; + } + + return 0; +} + +static u32 +gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) +{ + switch (engine->subdev.index) { + case NVKM_ENGINE_SW : + case NVKM_ENGINE_CE0 : + case NVKM_ENGINE_CE1 : + case NVKM_ENGINE_CE2 : return 0x0000; + case NVKM_ENGINE_GR : return 0x0210; + case NVKM_ENGINE_MSPDEC: return 0x0250; + case NVKM_ENGINE_MSPPP : return 0x0260; + case NVKM_ENGINE_MSVLD : return 0x0270; + default: + WARN_ON(1); + return 0; + } +} + +static int +gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct nvkm_gpuobj *inst = chan->base.inst; + int ret; + + ret = gk104_fifo_gpfifo_kick(chan); + if (ret && suspend) + return ret; + + if (offset) { + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, 0x00000000); + nvkm_wo32(inst, offset + 0x04, 0x00000000); + nvkm_done(inst); + } + + return ret; +} + +static int +gk104_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct nvkm_gpuobj *inst = chan->base.inst; + + if (offset) { + u64 addr = chan->engn[engine->subdev.index].vma.offset; + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, lower_32_bits(addr) | 4); + nvkm_wo32(inst, offset + 0x04, upper_32_bits(addr)); + nvkm_done(inst); + } + + return 0; +} + +static void +gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + nvkm_gpuobj_unmap(&chan->engn[engine->subdev.index].vma); + nvkm_gpuobj_del(&chan->engn[engine->subdev.index].inst); +} + +static int +gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) +{ + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + int engn = engine->subdev.index; + int ret; + + if (!gk104_fifo_gpfifo_engine_addr(engine)) + return 0; + + ret = nvkm_object_bind(object, NULL, 0, &chan->engn[engn].inst); + if (ret) + return ret; + + return nvkm_gpuobj_map(chan->engn[engn].inst, chan->vm, + NV_MEM_ACCESS_RW, &chan->engn[engn].vma); +} + +static void +gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) +{ + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct gk104_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 coff = chan->base.chid * 8; + + if (!list_empty(&chan->head)) { + list_del_init(&chan->head); + nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800); + gk104_fifo_runlist_update(fifo, chan->engine); + } + + nvkm_wr32(device, 0x800000 + coff, 0x00000000); +} + +static void +gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base) +{ + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct gk104_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 addr = chan->base.inst->addr >> 12; + u32 coff = chan->base.chid * 8; + + nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->engine << 16); + nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr); + + if (list_empty(&chan->head) && !chan->killed) { + list_add_tail(&chan->head, &fifo->engine[chan->engine].chan); + nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); + gk104_fifo_runlist_update(fifo, chan->engine); + nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); + } +} + +static void * +gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base) +{ + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + nvkm_vm_ref(NULL, &chan->vm, chan->pgd); + nvkm_gpuobj_del(&chan->pgd); + return chan; +} + +static const struct nvkm_fifo_chan_func +gk104_fifo_gpfifo_func = { + .dtor = gk104_fifo_gpfifo_dtor, + .init = gk104_fifo_gpfifo_init, + .fini = gk104_fifo_gpfifo_fini, + .ntfy = g84_fifo_chan_ntfy, + .engine_ctor = gk104_fifo_gpfifo_engine_ctor, + .engine_dtor = gk104_fifo_gpfifo_engine_dtor, + .engine_init = gk104_fifo_gpfifo_engine_init, + .engine_fini = gk104_fifo_gpfifo_engine_fini, +}; + +int +gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + union { + struct kepler_channel_gpfifo_a_v0 v0; + } *args = data; + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_object *parent = oclass->parent; + struct gk104_fifo_chan *chan; + u64 usermem, ioffset, ilength; + u32 engines; + int ret, i; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "ioffset %016llx ilength %08x engine %08x\n", + args->v0.version, args->v0.vm, args->v0.ioffset, + args->v0.ilength, args->v0.engine); + } else + return ret; + + /* determine which downstream engines are present */ + for (i = 0, engines = 0; i < ARRAY_SIZE(fifo->engine); i++) { + u64 subdevs = gk104_fifo_engine_subdev(i); + if (!nvkm_device_engine(device, __ffs64(subdevs))) + continue; + engines |= (1 << i); + } + + /* if this is an engine mask query, we're done */ + if (!args->v0.engine) { + args->v0.engine = engines; + return nvkm_object_new(oclass, NULL, 0, pobject); + } + + /* check that we support a requested engine - note that the user + * argument is a mask in order to allow the user to request (for + * example) *any* copy engine, but doesn't matter which. + */ + args->v0.engine &= engines; + if (!args->v0.engine) { + nvif_ioctl(parent, "no supported engine\n"); + return -ENODEV; + } + + /* allocate the channel */ + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + chan->fifo = fifo; + chan->engine = __ffs(args->v0.engine); + INIT_LIST_HEAD(&chan->head); + + ret = nvkm_fifo_chan_ctor(&gk104_fifo_gpfifo_func, &fifo->base, + 0x1000, 0x1000, true, args->v0.vm, 0, + gk104_fifo_engine_subdev(chan->engine), + 1, fifo->user.bar.offset, 0x200, + oclass, &chan->base); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + /* page directory */ + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &chan->pgd); + if (ret) + return ret; + + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x0200, lower_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0204, upper_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0208, 0xffffffff); + nvkm_wo32(chan->base.inst, 0x020c, 0x000000ff); + nvkm_done(chan->base.inst); + + ret = nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); + if (ret) + return ret; + + /* clear channel control registers */ + usermem = chan->base.chid * 0x200; + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(fifo->user.mem); + for (i = 0; i < 0x200; i += 4) + nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); + nvkm_done(fifo->user.mem); + usermem = nvkm_memory_addr(fifo->user.mem) + usermem; + + /* RAMFC */ + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x10, 0x0000face); + nvkm_wo32(chan->base.inst, 0x30, 0xfffff902); + nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) | + (ilength << 16)); + nvkm_wo32(chan->base.inst, 0x84, 0x20400000); + nvkm_wo32(chan->base.inst, 0x94, 0x30000001); + nvkm_wo32(chan->base.inst, 0x9c, 0x00000100); + nvkm_wo32(chan->base.inst, 0xac, 0x0000001f); + nvkm_wo32(chan->base.inst, 0xe8, chan->base.chid); + nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000); + nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(chan->base.inst); + return 0; +} + +const struct nvkm_fifo_chan_oclass +gk104_fifo_gpfifo_oclass = { + .base.oclass = KEPLER_CHANNEL_GPFIFO_A, + .base.minver = 0, + .base.maxver = 0, + .ctor = gk104_fifo_gpfifo_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c new file mode 100644 index 000000000000..6511d6e21ecc --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c @@ -0,0 +1,34 @@ +/* + * 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 + */ +#include "changk104.h" + +#include <nvif/class.h> + +const struct nvkm_fifo_chan_oclass +gm204_fifo_gpfifo_oclass = { + .base.oclass = MAXWELL_CHANNEL_GPFIFO_A, + .base.minver = 0, + .base.maxver = 0, + .ctor = gk104_fifo_gpfifo_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c new file mode 100644 index 000000000000..a8c69f878221 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c @@ -0,0 +1,92 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "channv50.h" + +#include <core/client.h> +#include <core/ramht.h> + +#include <nvif/class.h> +#include <nvif/unpack.h> + +static int +nv50_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct nv50_channel_gpfifo_v0 v0; + } *args = data; + struct nv50_fifo *fifo = nv50_fifo(base); + struct nv50_fifo_chan *chan; + u64 ioffset, ilength; + int ret; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "pushbuf %llx ioffset %016llx " + "ilength %08x\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.ioffset, args->v0.ilength); + if (!args->v0.pushbuf) + return -EINVAL; + } else + return ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nv50_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_done(chan->ramfc); + return 0; +} + +const struct nvkm_fifo_chan_oclass +nv50_fifo_gpfifo_oclass = { + .base.oclass = NV50_CHANNEL_GPFIFO, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_fifo_gpfifo_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 043e4296084c..ad707ff176cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -22,20 +22,17 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "channv04.h" +#include "regsnv04.h" #include <core/client.h> -#include <core/device.h> -#include <core/engctx.h> -#include <core/handle.h> #include <core/ramht.h> -#include <subdev/instmem/nv04.h> +#include <subdev/instmem.h> #include <subdev/timer.h> +#include <engine/sw.h> -#include <nvif/class.h> -#include <nvif/unpack.h> - -static struct ramfc_desc -nv04_ramfc[] = { +static const struct nv04_fifo_ramfc +nv04_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, @@ -47,268 +44,19 @@ nv04_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -int -nv04_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv04_fifo_priv *priv = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - u32 context, chid = chan->base.chid; - int ret; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->addr >> 4; - else - context = 0x00000004; /* just non-zero */ - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00010000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00020000; - break; - default: - return -EINVAL; - } - - context |= 0x80000000; /* valid */ - context |= chid << 24; - - mutex_lock(&nv_subdev(priv)->mutex); - ret = nvkm_ramht_insert(priv->ramht, chid, handle, context); - mutex_unlock(&nv_subdev(priv)->mutex); - return ret; -} - -void -nv04_fifo_object_detach(struct nvkm_object *parent, int cookie) -{ - struct nv04_fifo_priv *priv = (void *)parent->engine; - mutex_lock(&nv_subdev(priv)->mutex); - nvkm_ramht_remove(priv->ramht, cookie); - mutex_unlock(&nv_subdev(priv)->mutex); -} - -int -nv04_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) -{ - nv_engctx(object)->addr = nvkm_fifo_chan(parent)->chid; - return 0; -} - -static int -nv04_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; - struct nv04_fifo_chan *chan; - int ret; - - nv_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; - chan->ramfc = chan->base.chid * 32; - - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x10, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - return 0; -} - -void -nv04_fifo_chan_dtor(struct nvkm_object *object) -{ - struct nv04_fifo_priv *priv = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; - struct ramfc_desc *c = priv->ramfc_desc; - - do { - nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000); - } while ((++c)->bits); - - nvkm_fifo_channel_destroy(&chan->base); -} - -int -nv04_fifo_chan_init(struct nvkm_object *object) -{ - struct nv04_fifo_priv *priv = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; - u32 mask = 1 << chan->base.chid; - unsigned long flags; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - spin_lock_irqsave(&priv->base.lock, flags); - nv_mask(priv, NV04_PFIFO_MODE, mask, mask); - spin_unlock_irqrestore(&priv->base.lock, flags); - return 0; -} - -int -nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct nv04_fifo_priv *priv = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *fctx = priv->ramfc; - struct ramfc_desc *c; - unsigned long flags; - u32 data = chan->ramfc; - u32 chid; - - /* prevent fifo context switches */ - spin_lock_irqsave(&priv->base.lock, flags); - nv_wr32(priv, NV03_PFIFO_CACHES, 0); - - /* if this channel is active, replace it with a null context */ - chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; - if (chid == chan->base.chid) { - nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0); - nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); - - c = priv->ramfc_desc; - do { - u32 rm = ((1ULL << c->bits) - 1) << c->regs; - u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; - u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs; - u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm); - nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); - } while ((++c)->bits); - - c = priv->ramfc_desc; - do { - nv_wr32(priv, c->regp, 0x00000000); - } while ((++c)->bits); - - nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); - } - - /* restore normal operation, after disabling dma mode */ - nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); - spin_unlock_irqrestore(&priv->base.lock, flags); - - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -static struct nvkm_ofuncs -nv04_fifo_ofuncs = { - .ctor = nv04_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv04_fifo_sclass[] = { - { NV03_CHANNEL_DMA, &nv04_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -int -nv04_fifo_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv04_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - return 0; -} - -static struct nvkm_oclass -nv04_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - void -nv04_fifo_pause(struct nvkm_fifo *pfifo, unsigned long *pflags) -__acquires(priv->base.lock) +nv04_fifo_pause(struct nvkm_fifo *base, unsigned long *pflags) +__acquires(fifo->base.lock) { - struct nv04_fifo_priv *priv = (void *)pfifo; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags; - spin_lock_irqsave(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); *pflags = flags; - nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000); - nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000000); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000); /* in some cases the puller may be left in an inconsistent state * if you try to stop it while it's busy translating handles. @@ -319,28 +67,31 @@ __acquires(priv->base.lock) * to avoid this, we invalidate the most recently calculated * instance. */ - if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0, - NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000)) - nv_warn(priv, "timeout idling puller\n"); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, NV04_PFIFO_CACHE1_PULL0); + if (!(tmp & NV04_PFIFO_CACHE1_PULL0_HASH_BUSY)) + break; + ); - if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) & + if (nvkm_rd32(device, NV04_PFIFO_CACHE1_PULL0) & NV04_PFIFO_CACHE1_PULL0_HASH_FAILED) - nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); + nvkm_wr32(device, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); - nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000); + nvkm_wr32(device, NV04_PFIFO_CACHE1_HASH, 0x00000000); } void -nv04_fifo_start(struct nvkm_fifo *pfifo, unsigned long *pflags) -__releases(priv->base.lock) +nv04_fifo_start(struct nvkm_fifo *base, unsigned long *pflags) +__releases(fifo->base.lock) { - struct nv04_fifo_priv *priv = (void *)pfifo; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags = *pflags; - nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); - nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000001); - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_unlock_irqrestore(&fifo->base.lock, flags); } static const char * @@ -354,61 +105,40 @@ nv_dma_state_err(u32 state) } static bool -nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data) +nv04_fifo_swmthd(struct nvkm_device *device, u32 chid, u32 addr, u32 data) { - struct nv04_fifo_chan *chan = NULL; - struct nvkm_handle *bind; - const int subc = (addr >> 13) & 0x7; - const int mthd = addr & 0x1ffc; + struct nvkm_sw *sw = device->sw; + const int subc = (addr & 0x0000e000) >> 13; + const int mthd = (addr & 0x00001ffc); + const u32 mask = 0x0000000f << (subc * 4); + u32 engine = nvkm_rd32(device, 0x003280); bool handled = false; - unsigned long flags; - u32 engine; - - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; - if (unlikely(!chan)) - goto out; switch (mthd) { - case 0x0000: - bind = nvkm_namedb_get(nv_namedb(chan), data); - if (unlikely(!bind)) - break; - - if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) { - engine = 0x0000000f << (subc * 4); - chan->subc[subc] = data; - handled = true; - - nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0); - } - - nvkm_namedb_put(bind); + case 0x0000 ... 0x0000: /* subchannel's engine -> software */ + nvkm_wr32(device, 0x003280, (engine &= ~mask)); + case 0x0180 ... 0x01fc: /* handle -> instance */ + data = nvkm_rd32(device, 0x003258) & 0x0000ffff; + case 0x0100 ... 0x017c: + case 0x0200 ... 0x1ffc: /* pass method down to sw */ + if (!(engine & mask) && sw) + handled = nvkm_sw_mthd(sw, chid, subc, mthd, data); break; default: - engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE); - if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) - break; - - bind = nvkm_namedb_get(nv_namedb(chan), chan->subc[subc]); - if (likely(bind)) { - if (!nv_call(bind->object, mthd, data)) - handled = true; - nvkm_namedb_put(bind); - } break; } -out: - spin_unlock_irqrestore(&priv->base.lock, flags); return handled; } static void -nv04_fifo_cache_error(struct nvkm_device *device, - struct nv04_fifo_priv *priv, u32 chid, u32 get) +nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) { + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_fifo_chan *chan; + unsigned long flags; + u32 pull0 = nvkm_rd32(device, 0x003250); u32 mthd, data; int ptr; @@ -420,216 +150,214 @@ nv04_fifo_cache_error(struct nvkm_device *device, ptr = (get & 0x7ff) >> 2; if (device->card_type < NV_40) { - mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr)); + mthd = nvkm_rd32(device, NV04_PFIFO_CACHE1_METHOD(ptr)); + data = nvkm_rd32(device, NV04_PFIFO_CACHE1_DATA(ptr)); } else { - mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr)); + mthd = nvkm_rd32(device, NV40_PFIFO_CACHE1_METHOD(ptr)); + data = nvkm_rd32(device, NV40_PFIFO_CACHE1_DATA(ptr)); } - if (!nv04_fifo_swmthd(priv, chid, mthd, data)) { - const char *client_name = - nvkm_client_name_for_fifo_chid(&priv->base, chid); - nv_error(priv, - "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", - chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc, - data); + if (!(pull0 & 0x00000100) || + !nv04_fifo_swmthd(device, chid, mthd, data)) { + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + nvkm_error(subdev, "CACHE_ERROR - " + "ch %d [%s] subc %d mthd %04x data %08x\n", + chid, chan ? chan->object.client->name : "unknown", + (mthd >> 13) & 7, mthd & 0x1ffc, data); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } - nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0); - nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); + nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0); + nvkm_wr32(device, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1); - nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, + nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH0) & ~1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, get + 4); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, + nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH0) | 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_HASH, 0); - nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, - nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, + nvkm_rd32(device, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); } static void -nv04_fifo_dma_pusher(struct nvkm_device *device, - struct nv04_fifo_priv *priv, u32 chid) +nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) { - const char *client_name; - u32 dma_get = nv_rd32(priv, 0x003244); - u32 dma_put = nv_rd32(priv, 0x003240); - u32 push = nv_rd32(priv, 0x003220); - u32 state = nv_rd32(priv, 0x003228); - - client_name = nvkm_client_name_for_fifo_chid(&priv->base, chid); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 dma_get = nvkm_rd32(device, 0x003244); + u32 dma_put = nvkm_rd32(device, 0x003240); + u32 push = nvkm_rd32(device, 0x003220); + u32 state = nvkm_rd32(device, 0x003228); + struct nvkm_fifo_chan *chan; + unsigned long flags; + const char *name; + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + name = chan ? chan->object.client->name : "unknown"; if (device->card_type == NV_50) { - u32 ho_get = nv_rd32(priv, 0x003328); - u32 ho_put = nv_rd32(priv, 0x003320); - u32 ib_get = nv_rd32(priv, 0x003334); - u32 ib_put = nv_rd32(priv, 0x003330); - - nv_error(priv, - "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", - chid, client_name, ho_get, dma_get, ho_put, dma_put, - ib_get, ib_put, state, nv_dma_state_err(state), push); + u32 ho_get = nvkm_rd32(device, 0x003328); + u32 ho_put = nvkm_rd32(device, 0x003320); + u32 ib_get = nvkm_rd32(device, 0x003334); + u32 ib_put = nvkm_rd32(device, 0x003330); + + nvkm_error(subdev, "DMA_PUSHER - " + "ch %d [%s] get %02x%08x put %02x%08x ib_get %08x " + "ib_put %08x state %08x (err: %s) push %08x\n", + chid, name, ho_get, dma_get, ho_put, dma_put, + ib_get, ib_put, state, nv_dma_state_err(state), + push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ - nv_wr32(priv, 0x003364, 0x00000000); + nvkm_wr32(device, 0x003364, 0x00000000); if (dma_get != dma_put || ho_get != ho_put) { - nv_wr32(priv, 0x003244, dma_put); - nv_wr32(priv, 0x003328, ho_put); + nvkm_wr32(device, 0x003244, dma_put); + nvkm_wr32(device, 0x003328, ho_put); } else if (ib_get != ib_put) - nv_wr32(priv, 0x003334, ib_put); + nvkm_wr32(device, 0x003334, ib_put); } else { - nv_error(priv, - "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", - chid, client_name, dma_get, dma_put, state, - nv_dma_state_err(state), push); + nvkm_error(subdev, "DMA_PUSHER - ch %d [%s] get %08x put %08x " + "state %08x (err: %s) push %08x\n", + chid, name, dma_get, dma_put, state, + nv_dma_state_err(state), push); if (dma_get != dma_put) - nv_wr32(priv, 0x003244, dma_put); + nvkm_wr32(device, 0x003244, dma_put); } + nvkm_fifo_chan_put(&fifo->base, flags, &chan); - nv_wr32(priv, 0x003228, 0x00000000); - nv_wr32(priv, 0x003220, 0x00000001); - nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); + nvkm_wr32(device, 0x003228, 0x00000000); + nvkm_wr32(device, 0x003220, 0x00000001); + nvkm_wr32(device, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); } void -nv04_fifo_intr(struct nvkm_subdev *subdev) +nv04_fifo_intr(struct nvkm_fifo *base) { - struct nvkm_device *device = nv_device(subdev); - struct nv04_fifo_priv *priv = (void *)subdev; - u32 mask = nv_rd32(priv, NV03_PFIFO_INTR_EN_0); - u32 stat = nv_rd32(priv, NV03_PFIFO_INTR_0) & mask; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, NV03_PFIFO_INTR_EN_0); + u32 stat = nvkm_rd32(device, NV03_PFIFO_INTR_0) & mask; u32 reassign, chid, get, sem; - reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1; - nv_wr32(priv, NV03_PFIFO_CACHES, 0); + reassign = nvkm_rd32(device, NV03_PFIFO_CACHES) & 1; + nvkm_wr32(device, NV03_PFIFO_CACHES, 0); - chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; - get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET); + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & (fifo->base.nr - 1); + get = nvkm_rd32(device, NV03_PFIFO_CACHE1_GET); if (stat & NV_PFIFO_INTR_CACHE_ERROR) { - nv04_fifo_cache_error(device, priv, chid, get); + nv04_fifo_cache_error(fifo, chid, get); stat &= ~NV_PFIFO_INTR_CACHE_ERROR; } if (stat & NV_PFIFO_INTR_DMA_PUSHER) { - nv04_fifo_dma_pusher(device, priv, chid); + nv04_fifo_dma_pusher(fifo, chid); stat &= ~NV_PFIFO_INTR_DMA_PUSHER; } if (stat & NV_PFIFO_INTR_SEMAPHORE) { stat &= ~NV_PFIFO_INTR_SEMAPHORE; - nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); + nvkm_wr32(device, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); - sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE); - nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + sem = nvkm_rd32(device, NV10_PFIFO_CACHE1_SEMAPHORE); + nvkm_wr32(device, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); - nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, get + 4); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); } if (device->card_type == NV_50) { if (stat & 0x00000010) { stat &= ~0x00000010; - nv_wr32(priv, 0x002100, 0x00000010); + nvkm_wr32(device, 0x002100, 0x00000010); } if (stat & 0x40000000) { - nv_wr32(priv, 0x002100, 0x40000000); - nvkm_fifo_uevent(&priv->base); + nvkm_wr32(device, 0x002100, 0x40000000); + nvkm_fifo_uevent(&fifo->base); stat &= ~0x40000000; } } if (stat) { - nv_warn(priv, "unknown intr 0x%08x\n", stat); - nv_mask(priv, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); - nv_wr32(priv, NV03_PFIFO_INTR_0, stat); + nvkm_warn(subdev, "intr %08x\n", stat); + nvkm_mask(device, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); + nvkm_wr32(device, NV03_PFIFO_INTR_0, stat); } - nv_wr32(priv, NV03_PFIFO_CACHES, reassign); -} - -static int -nv04_fifo_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 *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv04_fifo_cclass; - nv_engine(priv)->sclass = nv04_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv04_ramfc; - return 0; + nvkm_wr32(device, NV03_PFIFO_CACHES, reassign); } void -nv04_fifo_dtor(struct nvkm_object *object) +nv04_fifo_init(struct nvkm_fifo *base) { - struct nv04_fifo_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->ramfc); - nvkm_gpuobj_ref(NULL, &priv->ramro); - nvkm_ramht_ref(NULL, &priv->ramht); - nvkm_fifo_destroy(&priv->base); + struct nv04_fifo *fifo = nv04_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + struct nvkm_ramht *ramht = imem->ramht; + struct nvkm_memory *ramro = imem->ramro; + struct nvkm_memory *ramfc = imem->ramfc; + + nvkm_wr32(device, NV04_PFIFO_DELAY_0, 0x000000ff); + nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + + nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((ramht->bits - 9) << 16) | + (ramht->gpuobj->addr >> 8)); + nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8); + + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); + + nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); + + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); } int -nv04_fifo_init(struct nvkm_object *object) +nv04_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, int nr, const struct nv04_fifo_ramfc *ramfc, + struct nvkm_fifo **pfifo) { - struct nv04_fifo_priv *priv = (void *)object; + struct nv04_fifo *fifo; int ret; - ret = nvkm_fifo_init(&priv->base); + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + fifo->ramfc = ramfc; + *pfifo = &fifo->base; + + ret = nvkm_fifo_ctor(func, device, index, nr, &fifo->base); if (ret) return ret; - nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - - nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((priv->ramht->bits - 9) << 16) | - (priv->ramht->gpuobj.addr >> 8)); - nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8); - - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); - - nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); - - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); + set_bit(nr - 1, fifo->base.mask); /* inactive channel */ return 0; } -struct nvkm_oclass * -nv04_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv04_fifo_init, - .fini = _nvkm_fifo_fini, +static const struct nvkm_fifo_func +nv04_fifo = { + .init = nv04_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .chan = { + &nv04_fifo_dma_oclass, + NULL }, }; + +int +nv04_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return nv04_fifo_new_(&nv04_fifo, device, index, 16, + nv04_fifo_ramfc, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h index e0e0c47cb4ca..03f60004bf7c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h @@ -1,137 +1,9 @@ #ifndef __NV04_FIFO_H__ #define __NV04_FIFO_H__ -#include <engine/fifo.h> +#define nv04_fifo(p) container_of((p), struct nv04_fifo, base) +#include "priv.h" -#define NV04_PFIFO_DELAY_0 0x00002040 -#define NV04_PFIFO_DMA_TIMESLICE 0x00002044 -#define NV04_PFIFO_NEXT_CHANNEL 0x00002050 -#define NV03_PFIFO_INTR_0 0x00002100 -#define NV03_PFIFO_INTR_EN_0 0x00002140 -# define NV_PFIFO_INTR_CACHE_ERROR (1<<0) -# define NV_PFIFO_INTR_RUNOUT (1<<4) -# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8) -# define NV_PFIFO_INTR_DMA_PUSHER (1<<12) -# define NV_PFIFO_INTR_DMA_PT (1<<16) -# define NV_PFIFO_INTR_SEMAPHORE (1<<20) -# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24) -#define NV03_PFIFO_RAMHT 0x00002210 -#define NV03_PFIFO_RAMFC 0x00002214 -#define NV03_PFIFO_RAMRO 0x00002218 -#define NV40_PFIFO_RAMFC 0x00002220 -#define NV03_PFIFO_CACHES 0x00002500 -#define NV04_PFIFO_MODE 0x00002504 -#define NV04_PFIFO_DMA 0x00002508 -#define NV04_PFIFO_SIZE 0x0000250c -#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4) -#define NV50_PFIFO_CTX_TABLE__SIZE 128 -#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31) -#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30) -#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF -#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF -#define NV03_PFIFO_CACHE0_PUSH0 0x00003000 -#define NV03_PFIFO_CACHE0_PULL0 0x00003040 -#define NV04_PFIFO_CACHE0_PULL0 0x00003050 -#define NV04_PFIFO_CACHE0_PULL1 0x00003054 -#define NV03_PFIFO_CACHE1_PUSH0 0x00003200 -#define NV03_PFIFO_CACHE1_PUSH1 0x00003204 -#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8) -#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16) -#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f -#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f -#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f -#define NV03_PFIFO_CACHE1_PUT 0x00003210 -#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220 -#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000 -# define NV_PFIFO_CACHE1_ENDIAN 0x80000000 -# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF -# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000 -#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228 -#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c -#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230 -#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240 -#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244 -#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248 -#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C -#define NV03_PFIFO_CACHE1_PULL0 0x00003240 -#define NV04_PFIFO_CACHE1_PULL0 0x00003250 -# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010 -# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000 -#define NV03_PFIFO_CACHE1_PULL1 0x00003250 -#define NV04_PFIFO_CACHE1_PULL1 0x00003254 -#define NV04_PFIFO_CACHE1_HASH 0x00003258 -#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260 -#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264 -#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268 -#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C -#define NV03_PFIFO_CACHE1_GET 0x00003270 -#define NV04_PFIFO_CACHE1_ENGINE 0x00003280 -#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0 -#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0 -#define NV40_PFIFO_UNK32E4 0x000032E4 -#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8)) -#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8)) -#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8)) -#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8)) - -struct ramfc_desc { +struct nv04_fifo_ramfc { unsigned bits:6; unsigned ctxs:5; unsigned ctxp:8; @@ -139,37 +11,13 @@ struct ramfc_desc { unsigned regp; }; -struct nv04_fifo_priv { +struct nv04_fifo { struct nvkm_fifo base; - struct ramfc_desc *ramfc_desc; - struct nvkm_ramht *ramht; - struct nvkm_gpuobj *ramro; - struct nvkm_gpuobj *ramfc; -}; - -struct nv04_fifo_base { - struct nvkm_fifo_base base; -}; - -struct nv04_fifo_chan { - struct nvkm_fifo_chan base; - u32 subc[8]; - u32 ramfc; + const struct nv04_fifo_ramfc *ramfc; }; -int nv04_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); -void nv04_fifo_object_detach(struct nvkm_object *, int); - -void nv04_fifo_chan_dtor(struct nvkm_object *); -int nv04_fifo_chan_init(struct nvkm_object *); -int nv04_fifo_chan_fini(struct nvkm_object *, bool suspend); - -int nv04_fifo_context_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -void nv04_fifo_dtor(struct nvkm_object *); -int nv04_fifo_init(struct nvkm_object *); -void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); -void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); +int nv04_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, int nr, const struct nv04_fifo_ramfc *, + struct nvkm_fifo **); +void nv04_fifo_init(struct nvkm_fifo *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 48ce4af6f543..f9a87deb2b3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -22,17 +22,11 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "channv04.h" +#include "regsnv04.h" -#include <core/client.h> -#include <core/engctx.h> -#include <core/ramht.h> -#include <subdev/instmem/nv04.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -static struct ramfc_desc -nv10_ramfc[] = { +static const struct nv04_fifo_ramfc +nv10_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -45,134 +39,21 @@ nv10_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -nv10_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; - struct nv04_fifo_chan *chan; - int ret; - - nv_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; - chan->ramfc = chan->base.chid * 32; - - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x14, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - return 0; -} - -static struct nvkm_ofuncs -nv10_fifo_ofuncs = { - .ctor = nv10_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv10_fifo_sclass[] = { - { NV10_CHANNEL_DMA, &nv10_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -static struct nvkm_oclass -nv10_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, +static const struct nvkm_fifo_func +nv10_fifo = { + .init = nv04_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .chan = { + &nv10_fifo_dma_oclass, + NULL }, }; -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - -static int -nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv10_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nv04_instmem_priv *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv10_fifo_cclass; - nv_engine(priv)->sclass = nv10_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv10_ramfc; - return 0; + return nv04_fifo_new_(&nv10_fifo, device, index, 32, + nv10_fifo_ramfc, pfifo); } - -struct nvkm_oclass * -nv10_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv04_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 4a20a6fd3887..f6d383a21222 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -22,17 +22,14 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "channv04.h" +#include "regsnv04.h" -#include <core/client.h> -#include <core/engctx.h> #include <core/ramht.h> -#include <subdev/instmem/nv04.h> +#include <subdev/instmem.h> -#include <nvif/class.h> -#include <nvif/unpack.h> - -static struct ramfc_desc -nv17_ramfc[] = { +static const struct nv04_fifo_ramfc +nv17_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -50,166 +47,51 @@ nv17_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -nv17_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void +nv17_fifo_init(struct nvkm_fifo *base) { - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; - struct nv04_fifo_chan *chan; - int ret; - - nv_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */ - &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; - chan->ramfc = chan->base.chid * 64; - - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x14, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - return 0; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + struct nvkm_ramht *ramht = imem->ramht; + struct nvkm_memory *ramro = imem->ramro; + struct nvkm_memory *ramfc = imem->ramfc; + + nvkm_wr32(device, NV04_PFIFO_DELAY_0, 0x000000ff); + nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + + nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((ramht->bits - 9) << 16) | + (ramht->gpuobj->addr >> 8)); + nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 | + 0x00010000); + + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); + + nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); + + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); } -static struct nvkm_ofuncs -nv17_fifo_ofuncs = { - .ctor = nv17_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv17_fifo_sclass[] = { - { NV17_CHANNEL_DMA, &nv17_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -static struct nvkm_oclass -nv17_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x17), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, +static const struct nvkm_fifo_func +nv17_fifo = { + .init = nv17_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .chan = { + &nv17_fifo_dma_oclass, + NULL }, }; -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - -static int -nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv17_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nv04_instmem_priv *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv17_fifo_cclass; - nv_engine(priv)->sclass = nv17_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv17_ramfc; - return 0; -} - -static int -nv17_fifo_init(struct nvkm_object *object) -{ - struct nv04_fifo_priv *priv = (void *)object; - int ret; - - ret = nvkm_fifo_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - - nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((priv->ramht->bits - 9) << 16) | - (priv->ramht->gpuobj.addr >> 8)); - nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000); - - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); - - nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); - - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); - return 0; + return nv04_fifo_new_(&nv17_fifo, device, index, 32, + nv17_fifo_ramfc, pfifo); } - -struct nvkm_oclass * -nv17_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x17), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv17_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv17_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index 5bfc96265f3b..8c7ba32763c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -22,19 +22,15 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "channv04.h" +#include "regsnv04.h" -#include <core/client.h> -#include <core/device.h> -#include <core/engctx.h> #include <core/ramht.h> #include <subdev/fb.h> -#include <subdev/instmem/nv04.h> +#include <subdev/instmem.h> -#include <nvif/class.h> -#include <nvif/unpack.h> - -static struct ramfc_desc -nv40_ramfc[] = { +static const struct nv04_fifo_ramfc +nv40_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -60,297 +56,72 @@ nv40_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -nv40_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv04_fifo_priv *priv = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - u32 context, chid = chan->base.chid; - int ret; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->addr >> 4; - else - context = 0x00000004; /* just non-zero */ - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00100000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00200000; - break; - default: - return -EINVAL; - } - - context |= chid << 23; - - mutex_lock(&nv_subdev(priv)->mutex); - ret = nvkm_ramht_insert(priv->ramht, chid, handle, context); - mutex_unlock(&nv_subdev(priv)->mutex); - return ret; -} - -static int -nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) -{ - struct nv04_fifo_priv *priv = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - unsigned long flags; - u32 reg, ctx; - - switch (nv_engidx(engctx->engine)) { - case NVDEV_ENGINE_SW: - return 0; - case NVDEV_ENGINE_GR: - reg = 0x32e0; - ctx = 0x38; - break; - case NVDEV_ENGINE_MPEG: - reg = 0x330c; - ctx = 0x54; - break; - default: - return -EINVAL; - } - - spin_lock_irqsave(&priv->base.lock, flags); - nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4; - nv_mask(priv, 0x002500, 0x00000001, 0x00000000); - - if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid) - nv_wr32(priv, reg, nv_engctx(engctx)->addr); - nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); - - nv_mask(priv, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->base.lock, flags); - return 0; -} - -static int -nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *engctx) +static void +nv40_fifo_init(struct nvkm_fifo *base) { - struct nv04_fifo_priv *priv = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - unsigned long flags; - u32 reg, ctx; - - switch (nv_engidx(engctx->engine)) { - case NVDEV_ENGINE_SW: - return 0; - case NVDEV_ENGINE_GR: - reg = 0x32e0; - ctx = 0x38; - break; - case NVDEV_ENGINE_MPEG: - reg = 0x330c; - ctx = 0x54; - break; - default: - return -EINVAL; - } - - spin_lock_irqsave(&priv->base.lock, flags); - nv_mask(priv, 0x002500, 0x00000001, 0x00000000); - - if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid) - nv_wr32(priv, reg, 0x00000000); - nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000); - - nv_mask(priv, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->base.lock, flags); - return 0; -} - -static int -nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; - struct nv04_fifo_chan *chan; - int ret; - - nv_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x1000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = nv40_fifo_context_attach; - nv_parent(chan)->context_detach = nv40_fifo_context_detach; - nv_parent(chan)->object_attach = nv40_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - chan->ramfc = chan->base.chid * 128; - - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 | - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff); - return 0; -} - -static struct nvkm_ofuncs -nv40_fifo_ofuncs = { - .ctor = nv40_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv40_fifo_sclass[] = { - { NV40_CHANNEL_DMA, &nv40_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -static struct nvkm_oclass -nv40_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - -static int -nv40_fifo_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 *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv40_fifo_cclass; - nv_engine(priv)->sclass = nv40_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv40_ramfc; - return 0; -} - -static int -nv40_fifo_init(struct nvkm_object *object) -{ - struct nv04_fifo_priv *priv = (void *)object; - struct nvkm_fb *pfb = nvkm_fb(object); - int ret; - - ret = nvkm_fifo_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x002040, 0x000000ff); - nv_wr32(priv, 0x002044, 0x2101ffff); - nv_wr32(priv, 0x002058, 0x00000001); - - nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((priv->ramht->bits - 9) << 16) | - (priv->ramht->gpuobj.addr >> 8)); - nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - - switch (nv_device(priv)->chipset) { + struct nv04_fifo *fifo = nv04_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_fb *fb = device->fb; + struct nvkm_instmem *imem = device->imem; + struct nvkm_ramht *ramht = imem->ramht; + struct nvkm_memory *ramro = imem->ramro; + struct nvkm_memory *ramfc = imem->ramfc; + + nvkm_wr32(device, 0x002040, 0x000000ff); + nvkm_wr32(device, 0x002044, 0x2101ffff); + nvkm_wr32(device, 0x002058, 0x00000001); + + nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((ramht->bits - 9) << 16) | + (ramht->gpuobj->addr >> 8)); + nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); + + switch (device->chipset) { case 0x47: case 0x49: case 0x4b: - nv_wr32(priv, 0x002230, 0x00000001); + nvkm_wr32(device, 0x002230, 0x00000001); case 0x40: case 0x41: case 0x42: case 0x43: case 0x45: case 0x48: - nv_wr32(priv, 0x002220, 0x00030002); + nvkm_wr32(device, 0x002220, 0x00030002); break; default: - nv_wr32(priv, 0x002230, 0x00000000); - nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 + - priv->ramfc->addr) >> 16) | - 0x00030000); + nvkm_wr32(device, 0x002230, 0x00000000); + nvkm_wr32(device, 0x002220, ((fb->ram->size - 512 * 1024 + + nvkm_memory_addr(ramfc)) >> 16) | + 0x00030000); break; } - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); - nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); - return 0; + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); } -struct nvkm_oclass * -nv40_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv40_fifo_init, - .fini = _nvkm_fifo_fini, +static const struct nvkm_fifo_func +nv40_fifo = { + .init = nv40_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .chan = { + &nv40_fifo_dma_oclass, + NULL }, }; + +int +nv40_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return nv04_fifo_new_(&nv40_fifo, device, index, 32, + nv40_fifo_ramfc, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index f25f0fd0655d..66eb12c2b5ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -22,513 +22,126 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "nv04.h" +#include "channv50.h" -#include <core/client.h> -#include <core/engctx.h> -#include <core/ramht.h> -#include <subdev/bar.h> -#include <subdev/mmu.h> -#include <subdev/timer.h> - -#include <nvif/class.h> -#include <nvif/unpack.h> - -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ +#include <core/gpuobj.h> static void -nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv) +nv50_fifo_runlist_update_locked(struct nv50_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(priv); - struct nvkm_gpuobj *cur; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_memory *cur; int i, p; - cur = priv->playlist[priv->cur_playlist]; - priv->cur_playlist = !priv->cur_playlist; - - for (i = priv->base.min, p = 0; i < priv->base.max; i++) { - if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000) - nv_wo32(cur, p++ * 4, i); - } - - bar->flush(bar); - - nv_wr32(priv, 0x0032f4, cur->addr >> 12); - nv_wr32(priv, 0x0032ec, p); - nv_wr32(priv, 0x002500, 0x00000101); -} - -void -nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) -{ - mutex_lock(&nv_subdev(priv)->mutex); - nv50_fifo_playlist_update_locked(priv); - mutex_unlock(&nv_subdev(priv)->mutex); -} - -static int -nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) -{ - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *ectx = (void *)object; - u64 limit = ectx->addr + ectx->size - 1; - u64 start = ectx->addr; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0000; break; - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - default: - return -EINVAL; - } - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - nv_wo32(base->eng, addr + 0x00, 0x00190000); - nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); - return 0; -} - -static int -nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) -{ - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_priv *priv = (void *)parent->engine; - struct nv50_fifo_base *base = (void *)parent->parent; - struct nv50_fifo_chan *chan = (void *)parent; - u32 addr, me; - int ret = 0; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0000; break; - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - default: - return -EINVAL; - } - - /* HW bug workaround: - * - * PFIFO will hang forever if the connected engines don't report - * that they've processed the context switch request. - * - * In order for the kickoff to work, we need to ensure all the - * connected engines are in a state where they can answer. - * - * Newer chipsets don't seem to suffer from this issue, and well, - * there's also a "ignore these engines" bitmask reg we can use - * if we hit the issue there.. - */ - me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001); - - /* do the kickoff... */ - nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); - if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { - nv_error(priv, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - ret = -EBUSY; - } - nv_wr32(priv, 0x00b860, me); - - if (ret == 0) { - nv_wo32(base->eng, addr + 0x00, 0x00000000); - nv_wo32(base->eng, addr + 0x04, 0x00000000); - nv_wo32(base->eng, addr + 0x08, 0x00000000); - nv_wo32(base->eng, addr + 0x0c, 0x00000000); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); - } - - return ret; -} - -static int -nv50_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv50_fifo_chan *chan = (void *)parent; - u32 context; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->node->offset >> 4; - else - context = 0x00000004; /* just non-zero */ + cur = fifo->runlist[fifo->cur_runlist]; + fifo->cur_runlist = !fifo->cur_runlist; - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; - default: - return -EINVAL; + nvkm_kmap(cur); + for (i = 0, p = 0; i < fifo->base.nr; i++) { + if (nvkm_rd32(device, 0x002600 + (i * 4)) & 0x80000000) + nvkm_wo32(cur, p++ * 4, i); } + nvkm_done(cur); - return nvkm_ramht_insert(chan->ramht, 0, handle, context); + nvkm_wr32(device, 0x0032f4, nvkm_memory_addr(cur) >> 12); + nvkm_wr32(device, 0x0032ec, p); + nvkm_wr32(device, 0x002500, 0x00000101); } void -nv50_fifo_object_detach(struct nvkm_object *parent, int cookie) +nv50_fifo_runlist_update(struct nv50_fifo *fifo) { - struct nv50_fifo_chan *chan = (void *)parent; - nvkm_ramht_remove(chan->ramht, cookie); + mutex_lock(&fifo->base.engine.subdev.mutex); + nv50_fifo_runlist_update_locked(fifo); + mutex_unlock(&fifo->base.engine.subdev.mutex); } -static int -nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_fifo_oneinit(struct nvkm_fifo *base) { - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; + struct nv50_fifo *fifo = nv50_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret; - nv_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = nv50_fifo_context_attach; - nv_parent(chan)->context_detach = nv50_fifo_context_detach; - nv_parent(chan)->object_attach = nv50_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, - &chan->ramht); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->runlist[0]); if (ret) return ret; - nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x3c, 0x003f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x4c, 0xffffffff); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); - bar->flush(bar); - return 0; + return nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->runlist[1]); } -static int -nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +void +nv50_fifo_init(struct nvkm_fifo *base) { - union { - struct nv50_channel_gpfifo_v0 v0; - } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; - u64 ioffset, ilength; - int ret; + struct nv50_fifo *fifo = nv50_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + int i; - nv_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); + nvkm_wr32(device, 0x00250c, 0x6f3cfc34); + nvkm_wr32(device, 0x002044, 0x01003fff); - args->v0.chid = chan->base.chid; + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0xbfffffff); - nv_parent(chan)->context_attach = nv50_fifo_context_attach; - nv_parent(chan)->context_detach = nv50_fifo_context_detach; - nv_parent(chan)->object_attach = nv50_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, - &chan->ramht); - if (ret) - return ret; - - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); + for (i = 0; i < 128; i++) + nvkm_wr32(device, 0x002600 + (i * 4), 0x00000000); + nv50_fifo_runlist_update_locked(fifo); - nv_wo32(base->ramfc, 0x3c, 0x403f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); - bar->flush(bar); - return 0; + nvkm_wr32(device, 0x003200, 0x00000001); + nvkm_wr32(device, 0x003250, 0x00000001); + nvkm_wr32(device, 0x002500, 0x00000001); } -void -nv50_fifo_chan_dtor(struct nvkm_object *object) +void * +nv50_fifo_dtor(struct nvkm_fifo *base) { - struct nv50_fifo_chan *chan = (void *)object; - nvkm_ramht_ref(NULL, &chan->ramht); - nvkm_fifo_channel_destroy(&chan->base); -} - -static int -nv50_fifo_chan_init(struct nvkm_object *object) -{ - struct nv50_fifo_priv *priv = (void *)object->engine; - struct nv50_fifo_base *base = (void *)object->parent; - struct nv50_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *ramfc = base->ramfc; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); - nv50_fifo_playlist_update(priv); - return 0; + struct nv50_fifo *fifo = nv50_fifo(base); + nvkm_memory_del(&fifo->runlist[1]); + nvkm_memory_del(&fifo->runlist[0]); + return fifo; } int -nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_fifo_priv *priv = (void *)object->engine; - struct nv50_fifo_chan *chan = (void *)object; - u32 chid = chan->base.chid; - - /* remove channel from playlist, fifo will unload context */ - nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000); - nv50_fifo_playlist_update(priv); - nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000); - - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -static struct nvkm_ofuncs -nv50_fifo_ofuncs_dma = { - .ctor = nv50_fifo_chan_ctor_dma, - .dtor = nv50_fifo_chan_dtor, - .init = nv50_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_ofuncs -nv50_fifo_ofuncs_ind = { - .ctor = nv50_fifo_chan_ctor_ind, - .dtor = nv50_fifo_chan_dtor, - .init = nv50_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv50_fifo_sclass[] = { - { NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma }, - { NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -static int -nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, struct nvkm_fifo **pfifo) { - struct nv50_fifo_base *base; + struct nv50_fifo *fifo; int ret; - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + *pfifo = &fifo->base; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0, - NVOBJ_FLAG_ZERO_ALLOC, &base->eng); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0, - &base->pgd); - if (ret) - return ret; - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); + ret = nvkm_fifo_ctor(func, device, index, 128, &fifo->base); if (ret) return ret; + set_bit(0, fifo->base.mask); /* PIO channel */ + set_bit(127, fifo->base.mask); /* inactive channel */ return 0; } -void -nv50_fifo_context_dtor(struct nvkm_object *object) -{ - struct nv50_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_ref(NULL, &base->pgd); - nvkm_gpuobj_ref(NULL, &base->eng); - nvkm_gpuobj_ref(NULL, &base->ramfc); - nvkm_gpuobj_ref(NULL, &base->cache); - nvkm_fifo_context_destroy(&base->base); -} - -static struct nvkm_oclass -nv50_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fifo_context_ctor, - .dtor = nv50_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, +static const struct nvkm_fifo_func +nv50_fifo = { + .dtor = nv50_fifo_dtor, + .oneinit = nv50_fifo_oneinit, + .init = nv50_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .chan = { + &nv50_fifo_dma_oclass, + &nv50_fifo_gpfifo_oclass, + NULL }, }; -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - -static int -nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_fifo_priv *priv; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[0]); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[1]); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv50_fifo_cclass; - nv_engine(priv)->sclass = nv50_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - return 0; -} - -void -nv50_fifo_dtor(struct nvkm_object *object) -{ - struct nv50_fifo_priv *priv = (void *)object; - - nvkm_gpuobj_ref(NULL, &priv->playlist[1]); - nvkm_gpuobj_ref(NULL, &priv->playlist[0]); - - nvkm_fifo_destroy(&priv->base); -} - int -nv50_fifo_init(struct nvkm_object *object) +nv50_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nv50_fifo_priv *priv = (void *)object; - int ret, i; - - ret = nvkm_fifo_init(&priv->base); - if (ret) - return ret; - - nv_mask(priv, 0x000200, 0x00000100, 0x00000000); - nv_mask(priv, 0x000200, 0x00000100, 0x00000100); - nv_wr32(priv, 0x00250c, 0x6f3cfc34); - nv_wr32(priv, 0x002044, 0x01003fff); - - nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0xbfffffff); - - for (i = 0; i < 128; i++) - nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); - nv50_fifo_playlist_update_locked(priv); - - nv_wr32(priv, 0x003200, 0x00000001); - nv_wr32(priv, 0x003250, 0x00000001); - nv_wr32(priv, 0x002500, 0x00000001); - return 0; + return nv50_fifo_new_(&nv50_fifo, device, index, pfifo); } - -struct nvkm_oclass * -nv50_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fifo_ctor, - .dtor = nv50_fifo_dtor, - .init = nv50_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h index 09ed93c66567..8ab53948cbb4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h @@ -1,36 +1,19 @@ #ifndef __NV50_FIFO_H__ #define __NV50_FIFO_H__ -#include <engine/fifo.h> +#define nv50_fifo(p) container_of((p), struct nv50_fifo, base) +#include "priv.h" -struct nv50_fifo_priv { +struct nv50_fifo { struct nvkm_fifo base; - struct nvkm_gpuobj *playlist[2]; - int cur_playlist; + struct nvkm_memory *runlist[2]; + int cur_runlist; }; -struct nv50_fifo_base { - struct nvkm_fifo_base base; - struct nvkm_gpuobj *ramfc; - struct nvkm_gpuobj *cache; - struct nvkm_gpuobj *eng; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; - -struct nv50_fifo_chan { - struct nvkm_fifo_chan base; - u32 subc[8]; - struct nvkm_ramht *ramht; -}; - -void nv50_fifo_playlist_update(struct nv50_fifo_priv *); - -void nv50_fifo_object_detach(struct nvkm_object *, int); -void nv50_fifo_chan_dtor(struct nvkm_object *); -int nv50_fifo_chan_fini(struct nvkm_object *, bool); - -void nv50_fifo_context_dtor(struct nvkm_object *); +int nv50_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, struct nvkm_fifo **); -void nv50_fifo_dtor(struct nvkm_object *); -int nv50_fifo_init(struct nvkm_object *); +void *nv50_fifo_dtor(struct nvkm_fifo *); +int nv50_fifo_oneinit(struct nvkm_fifo *); +void nv50_fifo_init(struct nvkm_fifo *); +void nv50_fifo_runlist_update(struct nv50_fifo *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h new file mode 100644 index 000000000000..cb1432e9be08 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -0,0 +1,26 @@ +#ifndef __NVKM_FIFO_PRIV_H__ +#define __NVKM_FIFO_PRIV_H__ +#define nvkm_fifo(p) container_of((p), struct nvkm_fifo, engine) +#include <engine/fifo.h> + +int nvkm_fifo_ctor(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, int nr, struct nvkm_fifo *); +void nvkm_fifo_uevent(struct nvkm_fifo *); + +struct nvkm_fifo_func { + void *(*dtor)(struct nvkm_fifo *); + int (*oneinit)(struct nvkm_fifo *); + void (*init)(struct nvkm_fifo *); + void (*fini)(struct nvkm_fifo *); + void (*intr)(struct nvkm_fifo *); + void (*pause)(struct nvkm_fifo *, unsigned long *); + void (*start)(struct nvkm_fifo *, unsigned long *); + void (*uevent_init)(struct nvkm_fifo *); + void (*uevent_fini)(struct nvkm_fifo *); + const struct nvkm_fifo_chan_oclass *chan[]; +}; + +void nv04_fifo_intr(struct nvkm_fifo *); +void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); +void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h new file mode 100644 index 000000000000..92d56221197b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h @@ -0,0 +1,132 @@ +#ifndef __NV04_FIFO_REGS_H__ +#define __NV04_FIFO_REGS_H__ + +#define NV04_PFIFO_DELAY_0 0x00002040 +#define NV04_PFIFO_DMA_TIMESLICE 0x00002044 +#define NV04_PFIFO_NEXT_CHANNEL 0x00002050 +#define NV03_PFIFO_INTR_0 0x00002100 +#define NV03_PFIFO_INTR_EN_0 0x00002140 +# define NV_PFIFO_INTR_CACHE_ERROR (1<<0) +# define NV_PFIFO_INTR_RUNOUT (1<<4) +# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8) +# define NV_PFIFO_INTR_DMA_PUSHER (1<<12) +# define NV_PFIFO_INTR_DMA_PT (1<<16) +# define NV_PFIFO_INTR_SEMAPHORE (1<<20) +# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24) +#define NV03_PFIFO_RAMHT 0x00002210 +#define NV03_PFIFO_RAMFC 0x00002214 +#define NV03_PFIFO_RAMRO 0x00002218 +#define NV40_PFIFO_RAMFC 0x00002220 +#define NV03_PFIFO_CACHES 0x00002500 +#define NV04_PFIFO_MODE 0x00002504 +#define NV04_PFIFO_DMA 0x00002508 +#define NV04_PFIFO_SIZE 0x0000250c +#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4) +#define NV50_PFIFO_CTX_TABLE__SIZE 128 +#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31) +#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30) +#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF +#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF +#define NV03_PFIFO_CACHE0_PUSH0 0x00003000 +#define NV03_PFIFO_CACHE0_PULL0 0x00003040 +#define NV04_PFIFO_CACHE0_PULL0 0x00003050 +#define NV04_PFIFO_CACHE0_PULL1 0x00003054 +#define NV03_PFIFO_CACHE1_PUSH0 0x00003200 +#define NV03_PFIFO_CACHE1_PUSH1 0x00003204 +#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8) +#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16) +#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f +#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f +#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f +#define NV03_PFIFO_CACHE1_PUT 0x00003210 +#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220 +#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000 +# define NV_PFIFO_CACHE1_ENDIAN 0x80000000 +# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF +# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000 +#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228 +#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c +#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230 +#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240 +#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244 +#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248 +#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C +#define NV03_PFIFO_CACHE1_PULL0 0x00003240 +#define NV04_PFIFO_CACHE1_PULL0 0x00003250 +# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010 +# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000 +#define NV03_PFIFO_CACHE1_PULL1 0x00003250 +#define NV04_PFIFO_CACHE1_PULL1 0x00003254 +#define NV04_PFIFO_CACHE1_HASH 0x00003258 +#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260 +#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264 +#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268 +#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C +#define NV03_PFIFO_CACHE1_GET 0x00003270 +#define NV04_PFIFO_CACHE1_ENGINE 0x00003280 +#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0 +#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0 +#define NV40_PFIFO_UNK32E4 0x000032E4 +#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8)) +#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8)) +#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8)) +#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8)) +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild index 2e1b92f71d9e..9ad0d0e78a96 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild @@ -1,21 +1,8 @@ -nvkm-y += nvkm/engine/gr/ctxnv40.o -nvkm-y += nvkm/engine/gr/ctxnv50.o -nvkm-y += nvkm/engine/gr/ctxgf100.o -nvkm-y += nvkm/engine/gr/ctxgf108.o -nvkm-y += nvkm/engine/gr/ctxgf104.o -nvkm-y += nvkm/engine/gr/ctxgf110.o -nvkm-y += nvkm/engine/gr/ctxgf117.o -nvkm-y += nvkm/engine/gr/ctxgf119.o -nvkm-y += nvkm/engine/gr/ctxgk104.o -nvkm-y += nvkm/engine/gr/ctxgk20a.o -nvkm-y += nvkm/engine/gr/ctxgk110.o -nvkm-y += nvkm/engine/gr/ctxgk110b.o -nvkm-y += nvkm/engine/gr/ctxgk208.o -nvkm-y += nvkm/engine/gr/ctxgm107.o -nvkm-y += nvkm/engine/gr/ctxgm204.o -nvkm-y += nvkm/engine/gr/ctxgm206.o +nvkm-y += nvkm/engine/gr/base.o nvkm-y += nvkm/engine/gr/nv04.o nvkm-y += nvkm/engine/gr/nv10.o +nvkm-y += nvkm/engine/gr/nv15.o +nvkm-y += nvkm/engine/gr/nv17.o nvkm-y += nvkm/engine/gr/nv20.o nvkm-y += nvkm/engine/gr/nv25.o nvkm-y += nvkm/engine/gr/nv2a.o @@ -23,18 +10,43 @@ nvkm-y += nvkm/engine/gr/nv30.o nvkm-y += nvkm/engine/gr/nv34.o nvkm-y += nvkm/engine/gr/nv35.o nvkm-y += nvkm/engine/gr/nv40.o +nvkm-y += nvkm/engine/gr/nv44.o nvkm-y += nvkm/engine/gr/nv50.o +nvkm-y += nvkm/engine/gr/g84.o +nvkm-y += nvkm/engine/gr/gt200.o +nvkm-y += nvkm/engine/gr/mcp79.o +nvkm-y += nvkm/engine/gr/gt215.o +nvkm-y += nvkm/engine/gr/mcp89.o nvkm-y += nvkm/engine/gr/gf100.o -nvkm-y += nvkm/engine/gr/gf108.o nvkm-y += nvkm/engine/gr/gf104.o +nvkm-y += nvkm/engine/gr/gf108.o nvkm-y += nvkm/engine/gr/gf110.o nvkm-y += nvkm/engine/gr/gf117.o nvkm-y += nvkm/engine/gr/gf119.o nvkm-y += nvkm/engine/gr/gk104.o -nvkm-y += nvkm/engine/gr/gk20a.o nvkm-y += nvkm/engine/gr/gk110.o nvkm-y += nvkm/engine/gr/gk110b.o nvkm-y += nvkm/engine/gr/gk208.o +nvkm-y += nvkm/engine/gr/gk20a.o nvkm-y += nvkm/engine/gr/gm107.o nvkm-y += nvkm/engine/gr/gm204.o nvkm-y += nvkm/engine/gr/gm206.o +nvkm-y += nvkm/engine/gr/gm20b.o + +nvkm-y += nvkm/engine/gr/ctxnv40.o +nvkm-y += nvkm/engine/gr/ctxnv50.o +nvkm-y += nvkm/engine/gr/ctxgf100.o +nvkm-y += nvkm/engine/gr/ctxgf104.o +nvkm-y += nvkm/engine/gr/ctxgf108.o +nvkm-y += nvkm/engine/gr/ctxgf110.o +nvkm-y += nvkm/engine/gr/ctxgf117.o +nvkm-y += nvkm/engine/gr/ctxgf119.o +nvkm-y += nvkm/engine/gr/ctxgk104.o +nvkm-y += nvkm/engine/gr/ctxgk110.o +nvkm-y += nvkm/engine/gr/ctxgk110b.o +nvkm-y += nvkm/engine/gr/ctxgk208.o +nvkm-y += nvkm/engine/gr/ctxgk20a.o +nvkm-y += nvkm/engine/gr/ctxgm107.o +nvkm-y += nvkm/engine/gr/ctxgm204.o +nvkm-y += nvkm/engine/gr/ctxgm206.o +nvkm-y += nvkm/engine/gr/ctxgm20b.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c new file mode 100644 index 000000000000..090765ff070d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c @@ -0,0 +1,136 @@ +/* + * 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 <engine/fifo.h> + +static void +nvkm_gr_tile(struct nvkm_engine *engine, int region, struct nvkm_fb_tile *tile) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + if (gr->func->tile) + gr->func->tile(gr, region, tile); +} + +u64 +nvkm_gr_units(struct nvkm_gr *gr) +{ + if (gr->func->units) + return gr->func->units(gr); + return 0; +} + +int +nvkm_gr_tlb_flush(struct nvkm_gr *gr) +{ + if (gr->func->tlb_flush) + return gr->func->tlb_flush(gr); + return -ENODEV; +} + +static int +nvkm_gr_oclass_get(struct nvkm_oclass *oclass, int index) +{ + struct nvkm_gr *gr = nvkm_gr(oclass->engine); + int c = 0; + + if (gr->func->object_get) { + int ret = gr->func->object_get(gr, index, &oclass->base); + if (oclass->base.oclass) + return index; + return ret; + } + + while (gr->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = gr->func->sclass[index]; + return index; + } + } + + return c; +} + +static int +nvkm_gr_cclass_new(struct nvkm_fifo_chan *chan, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nvkm_gr *gr = nvkm_gr(oclass->engine); + if (gr->func->chan_new) + return gr->func->chan_new(gr, chan, oclass, pobject); + return 0; +} + +static void +nvkm_gr_intr(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + gr->func->intr(gr); +} + +static int +nvkm_gr_oneinit(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + if (gr->func->oneinit) + return gr->func->oneinit(gr); + return 0; +} + +static int +nvkm_gr_init(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + return gr->func->init(gr); +} + +static void * +nvkm_gr_dtor(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + if (gr->func->dtor) + return gr->func->dtor(gr); + return gr; +} + +static const struct nvkm_engine_func +nvkm_gr = { + .dtor = nvkm_gr_dtor, + .oneinit = nvkm_gr_oneinit, + .init = nvkm_gr_init, + .intr = nvkm_gr_intr, + .tile = nvkm_gr_tile, + .fifo.cclass = nvkm_gr_cclass_new, + .fifo.sclass = nvkm_gr_oclass_get, +}; + +int +nvkm_gr_ctor(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, u32 pmc_enable, bool enable, struct nvkm_gr *gr) +{ + gr->func = func; + return nvkm_engine_ctor(&nvkm_gr, device, index, pmc_enable, + enable, &gr->engine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index 57e2c5b13123..56f392d3d4fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -23,7 +23,6 @@ */ #include "ctxgf100.h" -#include <subdev/bar.h> #include <subdev/fb.h> #include <subdev/mc.h> #include <subdev/timer.h> @@ -1005,6 +1004,7 @@ void gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data, int shift, int buffer) { + struct nvkm_device *device = info->gr->base.engine.subdev.device; if (info->data) { if (shift >= 0) { info->mmio->addr = addr; @@ -1021,29 +1021,29 @@ gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data, return; } - nv_wr32(info->priv, addr, data); + nvkm_wr32(device, addr, data); } void gf100_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + const int b = mmio_vram(info, grctx->bundle_size, (1 << s), access); mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); mmio_refn(info, 0x418808, 0x00000000, s, b); - mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s)); } void gf100_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), access); mmio_refn(info, 0x40800c, 0x00000000, s, b); mmio_wr32(info, 0x408010, 0x80000000); mmio_refn(info, 0x419004, 0x00000000, s, b); @@ -1053,13 +1053,13 @@ gf100_grctx_generate_pagepool(struct gf100_grctx *info) void gf100_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv); - const u32 attrib = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 attrib = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); int gpc, tpc; u32 bo = 0; @@ -1067,91 +1067,95 @@ gf100_grctx_generate_attrib(struct gf100_grctx *info) mmio_refn(info, 0x419848, 0x10000000, s, b); mmio_wr32(info, 0x405830, (attrib << 16)); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { const u32 o = TPC_UNIT(gpc, tpc, 0x0520); mmio_skip(info, o, (attrib << 16) | ++bo); mmio_wr32(info, o, (attrib << 16) | --bo); - bo += impl->attrib_nr_max; + bo += grctx->attrib_nr_max; } } } void -gf100_grctx_generate_unkn(struct gf100_gr_priv *priv) +gf100_grctx_generate_unkn(struct gf100_gr *gr) { } void -gf100_grctx_generate_tpcid(struct gf100_gr_priv *priv) +gf100_grctx_generate_tpcid(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - if (tpc < priv->tpc_nr[gpc]) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + if (tpc < gr->tpc_nr[gpc]) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x698), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x4e8), id); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), id); id++; } - nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); } } } void -gf100_grctx_generate_r406028(struct gf100_gr_priv *priv) +gf100_grctx_generate_r406028(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 tmp[GPC_MAX / 8] = {}, i = 0; - for (i = 0; i < priv->gpc_nr; i++) - tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4); + for (i = 0; i < gr->gpc_nr; i++) + tmp[i / 8] |= gr->tpc_nr[i] << ((i % 8) * 4); for (i = 0; i < 4; i++) { - nv_wr32(priv, 0x406028 + (i * 4), tmp[i]); - nv_wr32(priv, 0x405870 + (i * 4), tmp[i]); + nvkm_wr32(device, 0x406028 + (i * 4), tmp[i]); + nvkm_wr32(device, 0x405870 + (i * 4), tmp[i]); } } void -gf100_grctx_generate_r4060a8(struct gf100_gr_priv *priv) +gf100_grctx_generate_r4060a8(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u8 tpcnr[GPC_MAX], data[TPC_MAX]; int gpc, tpc, i; - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); memset(data, 0x1f, sizeof(data)); gpc = -1; - for (tpc = 0; tpc < priv->tpc_total; tpc++) { + for (tpc = 0; tpc < gr->tpc_total; tpc++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; data[tpc] = gpc; } for (i = 0; i < 4; i++) - nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]); + nvkm_wr32(device, 0x4060a8 + (i * 4), ((u32 *)data)[i]); } void -gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv) +gf100_grctx_generate_r418bb8(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 data[6] = {}, data2[2] = {}; u8 tpcnr[GPC_MAX]; u8 shift, ntpcv; int gpc, tpc, i; /* calculate first set of magics */ - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); gpc = -1; - for (tpc = 0; tpc < priv->tpc_total; tpc++) { + for (tpc = 0; tpc < gr->tpc_total; tpc++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; @@ -1163,7 +1167,7 @@ gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv) /* and the second... */ shift = 0; - ntpcv = priv->tpc_total; + ntpcv = gr->tpc_total; while (!(ntpcv & (1 << 4))) { ntpcv <<= 1; shift++; @@ -1176,202 +1180,211 @@ gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* GPC_BROADCAST */ - nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nvkm_wr32(device, 0x418bb8, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x418b08 + (i * 4), data[i]); + nvkm_wr32(device, 0x418b08 + (i * 4), data[i]); /* GPC_BROADCAST.TP_BROADCAST */ - nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) | - priv->magic_not_rop_nr | data2[0]); - nv_wr32(priv, 0x419be4, data2[1]); + nvkm_wr32(device, 0x419bd0, (gr->tpc_total << 8) | + gr->magic_not_rop_nr | data2[0]); + nvkm_wr32(device, 0x419be4, data2[1]); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x419b00 + (i * 4), data[i]); + nvkm_wr32(device, 0x419b00 + (i * 4), data[i]); /* UNK78xx */ - nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nvkm_wr32(device, 0x4078bc, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x40780c + (i * 4), data[i]); + nvkm_wr32(device, 0x40780c + (i * 4), data[i]); } void -gf100_grctx_generate_r406800(struct gf100_gr_priv *priv) +gf100_grctx_generate_r406800(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u64 tpc_mask = 0, tpc_set = 0; u8 tpcnr[GPC_MAX]; int gpc, tpc; int i, a, b; - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) - tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) + tpc_mask |= ((1ULL << gr->tpc_nr[gpc]) - 1) << (gpc * 8); for (i = 0, gpc = -1, b = -1; i < 32; i++) { - a = (i * (priv->tpc_total - 1)) / 32; + a = (i * (gr->tpc_total - 1)) / 32; if (a != b) { b = a; do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; tpc_set |= 1ULL << ((gpc * 8) + tpc); } - nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); - nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask)); - if (priv->gpc_nr > 4) { - nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set)); - nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask)); + nvkm_wr32(device, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); + nvkm_wr32(device, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask)); + if (gr->gpc_nr > 4) { + nvkm_wr32(device, 0x406804 + (i * 0x20), upper_32_bits(tpc_set)); + nvkm_wr32(device, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask)); } } } void -gf100_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; - - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); - - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); - - nv_wr32(priv, 0x404154, 0x00000000); - - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(priv); - - gf100_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gf100_grctx_generate_r4060a8(priv); - gf100_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); - - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; + + nvkm_mc_unk260(device->mc, 0); + + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); + + nvkm_wr32(device, 0x404154, 0x00000000); + + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); + + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gf100_grctx_generate_r4060a8(gr); + gf100_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); + + gf100_gr_icmd(gr, grctx->icmd); + nvkm_wr32(device, 0x404154, 0x00000400); + gf100_gr_mthd(gr, grctx->mthd); + nvkm_mc_unk260(device->mc, 1); } int -gf100_grctx_generate(struct gf100_gr_priv *priv) +gf100_grctx_generate(struct gf100_gr *gr) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; - struct nvkm_bar *bar = nvkm_bar(priv); - struct nvkm_gpuobj *chan; + const struct gf100_grctx_func *grctx = gr->func->grctx; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_memory *chan; struct gf100_grctx info; int ret, i; + u64 addr; /* allocate memory to for a "channel", which we'll use to generate * the default context values */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x80000 + gr->size, + 0x1000, true, &chan); if (ret) { - nv_error(priv, "failed to allocate channel memory, %d\n", ret); + nvkm_error(subdev, "failed to allocate chan memory, %d\n", ret); return ret; } + addr = nvkm_memory_addr(chan); + /* PGD pointer */ - nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000)); - nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000)); - nv_wo32(chan, 0x0208, 0xffffffff); - nv_wo32(chan, 0x020c, 0x000000ff); + nvkm_kmap(chan); + nvkm_wo32(chan, 0x0200, lower_32_bits(addr + 0x1000)); + nvkm_wo32(chan, 0x0204, upper_32_bits(addr + 0x1000)); + nvkm_wo32(chan, 0x0208, 0xffffffff); + nvkm_wo32(chan, 0x020c, 0x000000ff); /* PGT[0] pointer */ - nv_wo32(chan, 0x1000, 0x00000000); - nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8); + nvkm_wo32(chan, 0x1000, 0x00000000); + nvkm_wo32(chan, 0x1004, 0x00000001 | (addr + 0x2000) >> 8); /* identity-map the whole "channel" into its own vm */ - for (i = 0; i < chan->size / 4096; i++) { - u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1; - nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr)); - nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr)); + for (i = 0; i < nvkm_memory_size(chan) / 4096; i++) { + u64 addr = ((nvkm_memory_addr(chan) + (i * 4096)) >> 8) | 1; + nvkm_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr)); + nvkm_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr)); } /* context pointer (virt) */ - nv_wo32(chan, 0x0210, 0x00080004); - nv_wo32(chan, 0x0214, 0x00000000); + nvkm_wo32(chan, 0x0210, 0x00080004); + nvkm_wo32(chan, 0x0214, 0x00000000); + nvkm_done(chan); - bar->flush(bar); - - nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8); - nv_wr32(priv, 0x100cbc, 0x80000001); - nv_wait(priv, 0x100c80, 0x00008000, 0x00008000); + nvkm_wr32(device, 0x100cb8, (addr + 0x1000) >> 8); + nvkm_wr32(device, 0x100cbc, 0x80000001); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100c80) & 0x00008000) + break; + ); /* setup default state for mmio list construction */ - info.priv = priv; - info.data = priv->mmio_data; - info.mmio = priv->mmio_list; + info.gr = gr; + info.data = gr->mmio_data; + info.mmio = gr->mmio_list; info.addr = 0x2000 + (i * 8); info.buffer_nr = 0; /* make channel current */ - if (priv->firmware) { - nv_wr32(priv, 0x409840, 0x00000030); - nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12); - nv_wr32(priv, 0x409504, 0x00000003); - if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010)) - nv_error(priv, "load_ctx timeout\n"); - - nv_wo32(chan, 0x8001c, 1); - nv_wo32(chan, 0x80020, 0); - nv_wo32(chan, 0x80028, 0); - nv_wo32(chan, 0x8002c, 0); - bar->flush(bar); + if (gr->firmware) { + nvkm_wr32(device, 0x409840, 0x00000030); + nvkm_wr32(device, 0x409500, 0x80000000 | addr >> 12); + nvkm_wr32(device, 0x409504, 0x00000003); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x00000010) + break; + ); + + nvkm_kmap(chan); + nvkm_wo32(chan, 0x8001c, 1); + nvkm_wo32(chan, 0x80020, 0); + nvkm_wo32(chan, 0x80028, 0); + nvkm_wo32(chan, 0x8002c, 0); + nvkm_done(chan); } else { - nv_wr32(priv, 0x409840, 0x80000000); - nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12); - nv_wr32(priv, 0x409504, 0x00000001); - if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) - nv_error(priv, "HUB_SET_CHAN timeout\n"); + nvkm_wr32(device, 0x409840, 0x80000000); + nvkm_wr32(device, 0x409500, 0x80000000 | addr >> 12); + nvkm_wr32(device, 0x409504, 0x00000001); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x80000000) + break; + ); } - oclass->main(priv, &info); + grctx->main(gr, &info); /* trigger a context unload by unsetting the "next channel valid" bit * and faking a context switch interrupt */ - nv_mask(priv, 0x409b04, 0x80000000, 0x00000000); - nv_wr32(priv, 0x409000, 0x00000100); - if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) { - nv_error(priv, "grctx template channel unload timeout\n"); + nvkm_mask(device, 0x409b04, 0x80000000, 0x00000000); + nvkm_wr32(device, 0x409000, 0x00000100); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x409b00) & 0x80000000)) + break; + ) < 0) { ret = -EBUSY; goto done; } - priv->data = kmalloc(priv->size, GFP_KERNEL); - if (priv->data) { - for (i = 0; i < priv->size; i += 4) - priv->data[i / 4] = nv_ro32(chan, 0x80000 + i); + gr->data = kmalloc(gr->size, GFP_KERNEL); + if (gr->data) { + nvkm_kmap(chan); + for (i = 0; i < gr->size; i += 4) + gr->data[i / 4] = nvkm_ro32(chan, 0x80000 + i); + nvkm_done(chan); ret = 0; } else { ret = -ENOMEM; } done: - nvkm_gpuobj_ref(NULL, &chan); + nvkm_memory_del(&chan); return ret; } -struct nvkm_oclass * -gf100_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf100_grctx = { .main = gf100_grctx_generate_main, .unkn = gf100_grctx_generate_unkn, .hub = gf100_grctx_pack_hub, @@ -1387,4 +1400,4 @@ gf100_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h index 3676a3342bc5..3c64040ec5a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h @@ -3,7 +3,7 @@ #include "gf100.h" struct gf100_grctx { - struct gf100_gr_priv *priv; + struct gf100_gr *gr; struct gf100_gr_data *data; struct gf100_gr_mmio *mmio; int buffer_nr; @@ -19,12 +19,11 @@ void gf100_grctx_mmio_item(struct gf100_grctx *, u32 addr, u32 data, int s, int) #define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1) #define mmio_wr32(a,b,c) mmio_refn((a), (b), (c), 0, -1) -struct gf100_grctx_oclass { - struct nvkm_oclass base; +struct gf100_grctx_func { /* main context generation function */ - void (*main)(struct gf100_gr_priv *, struct gf100_grctx *); + void (*main)(struct gf100_gr *, struct gf100_grctx *); /* context-specific modify-on-first-load list generation function */ - void (*unkn)(struct gf100_gr_priv *); + void (*unkn)(struct gf100_gr *); /* mmio context data */ const struct gf100_gr_pack *hub; const struct gf100_gr_pack *gpc; @@ -50,60 +49,61 @@ struct gf100_grctx_oclass { u32 alpha_nr; }; -static inline const struct gf100_grctx_oclass * -gf100_grctx_impl(struct gf100_gr_priv *priv) -{ - return (void *)nv_engine(priv)->cclass; -} - -extern struct nvkm_oclass *gf100_grctx_oclass; -int gf100_grctx_generate(struct gf100_gr_priv *); -void gf100_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *); +extern const struct gf100_grctx_func gf100_grctx; +int gf100_grctx_generate(struct gf100_gr *); +void gf100_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); void gf100_grctx_generate_bundle(struct gf100_grctx *); void gf100_grctx_generate_pagepool(struct gf100_grctx *); void gf100_grctx_generate_attrib(struct gf100_grctx *); -void gf100_grctx_generate_unkn(struct gf100_gr_priv *); -void gf100_grctx_generate_tpcid(struct gf100_gr_priv *); -void gf100_grctx_generate_r406028(struct gf100_gr_priv *); -void gf100_grctx_generate_r4060a8(struct gf100_gr_priv *); -void gf100_grctx_generate_r418bb8(struct gf100_gr_priv *); -void gf100_grctx_generate_r406800(struct gf100_gr_priv *); - -extern struct nvkm_oclass *gf108_grctx_oclass; +void gf100_grctx_generate_unkn(struct gf100_gr *); +void gf100_grctx_generate_tpcid(struct gf100_gr *); +void gf100_grctx_generate_r406028(struct gf100_gr *); +void gf100_grctx_generate_r4060a8(struct gf100_gr *); +void gf100_grctx_generate_r418bb8(struct gf100_gr *); +void gf100_grctx_generate_r406800(struct gf100_gr *); + +extern const struct gf100_grctx_func gf108_grctx; void gf108_grctx_generate_attrib(struct gf100_grctx *); -void gf108_grctx_generate_unkn(struct gf100_gr_priv *); +void gf108_grctx_generate_unkn(struct gf100_gr *); -extern struct nvkm_oclass *gf104_grctx_oclass; -extern struct nvkm_oclass *gf110_grctx_oclass; +extern const struct gf100_grctx_func gf104_grctx; +extern const struct gf100_grctx_func gf110_grctx; -extern struct nvkm_oclass *gf117_grctx_oclass; +extern const struct gf100_grctx_func gf117_grctx; void gf117_grctx_generate_attrib(struct gf100_grctx *); -extern struct nvkm_oclass *gf119_grctx_oclass; +extern const struct gf100_grctx_func gf119_grctx; -extern struct nvkm_oclass *gk104_grctx_oclass; -extern struct nvkm_oclass *gk20a_grctx_oclass; -void gk104_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *); +extern const struct gf100_grctx_func gk104_grctx; +extern const struct gf100_grctx_func gk20a_grctx; +void gk104_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); void gk104_grctx_generate_bundle(struct gf100_grctx *); void gk104_grctx_generate_pagepool(struct gf100_grctx *); -void gk104_grctx_generate_unkn(struct gf100_gr_priv *); -void gk104_grctx_generate_r418bb8(struct gf100_gr_priv *); -void gk104_grctx_generate_rop_active_fbps(struct gf100_gr_priv *); +void gk104_grctx_generate_unkn(struct gf100_gr *); +void gk104_grctx_generate_r418bb8(struct gf100_gr *); +void gk104_grctx_generate_rop_active_fbps(struct gf100_gr *); + +void gm107_grctx_generate_bundle(struct gf100_grctx *); +void gm107_grctx_generate_pagepool(struct gf100_grctx *); +void gm107_grctx_generate_attrib(struct gf100_grctx *); -extern struct nvkm_oclass *gk110_grctx_oclass; -extern struct nvkm_oclass *gk110b_grctx_oclass; -extern struct nvkm_oclass *gk208_grctx_oclass; +extern const struct gf100_grctx_func gk110_grctx; +extern const struct gf100_grctx_func gk110b_grctx; +extern const struct gf100_grctx_func gk208_grctx; -extern struct nvkm_oclass *gm107_grctx_oclass; +extern const struct gf100_grctx_func gm107_grctx; void gm107_grctx_generate_bundle(struct gf100_grctx *); void gm107_grctx_generate_pagepool(struct gf100_grctx *); void gm107_grctx_generate_attrib(struct gf100_grctx *); -extern struct nvkm_oclass *gm204_grctx_oclass; -void gm204_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *); +extern const struct gf100_grctx_func gm204_grctx; +void gm204_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); +void gm204_grctx_generate_tpcid(struct gf100_gr *); +void gm204_grctx_generate_405b60(struct gf100_gr *); -extern struct nvkm_oclass *gm206_grctx_oclass; +extern const struct gf100_grctx_func gm206_grctx; +extern const struct gf100_grctx_func gm20b_grctx; /* context init value lists */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c index c5a8d55e2cac..54fd74e9cca0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c @@ -79,17 +79,8 @@ gf104_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gf104_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf104_grctx = { .main = gf100_grctx_generate_main, .unkn = gf100_grctx_generate_unkn, .hub = gf100_grctx_pack_hub, @@ -105,4 +96,4 @@ gf104_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c index 87c844a5f34b..505cdcbfc085 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c @@ -730,18 +730,18 @@ gf108_grctx_pack_tpc[] = { void gf108_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv); - const u32 alpha = impl->alpha_nr; - const u32 beta = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 alpha = grctx->alpha_nr; + const u32 beta = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, tpc; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -749,43 +749,35 @@ gf108_grctx_generate_attrib(struct gf100_grctx *info) mmio_wr32(info, 0x405830, (beta << 16) | alpha); mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { const u32 a = alpha; const u32 b = beta; const u32 t = timeslice_mode; const u32 o = TPC_UNIT(gpc, tpc, 0x500); mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo); mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo); - bo += impl->attrib_nr_max; + bo += grctx->attrib_nr_max; mmio_wr32(info, o + 0x44, (a << 16) | ao); - ao += impl->alpha_nr_max; + ao += grctx->alpha_nr_max; } } } void -gf108_grctx_generate_unkn(struct gf100_gr_priv *priv) +gf108_grctx_generate_unkn(struct gf100_gr *gr) { - nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001); - nv_mask(priv, 0x41980c, 0x00000010, 0x00000010); - nv_mask(priv, 0x419814, 0x00000004, 0x00000004); - nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000); - nv_mask(priv, 0x405800, 0x08000000, 0x08000000); - nv_mask(priv, 0x419c00, 0x00000008, 0x00000008); + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_mask(device, 0x418c6c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x41980c, 0x00000010, 0x00000010); + nvkm_mask(device, 0x419814, 0x00000004, 0x00000004); + nvkm_mask(device, 0x4064c0, 0x80000000, 0x80000000); + nvkm_mask(device, 0x405800, 0x08000000, 0x08000000); + nvkm_mask(device, 0x419c00, 0x00000008, 0x00000008); } -struct nvkm_oclass * -gf108_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf108_grctx = { .main = gf100_grctx_generate_main, .unkn = gf108_grctx_generate_unkn, .hub = gf108_grctx_pack_hub, @@ -803,4 +795,4 @@ gf108_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x324, .alpha_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c index b3acd931b978..7df398b53f8f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c @@ -330,17 +330,8 @@ gf110_grctx_pack_gpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gf110_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc8), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf110_grctx = { .main = gf100_grctx_generate_main, .unkn = gf100_grctx_generate_unkn, .hub = gf100_grctx_pack_hub, @@ -356,4 +347,4 @@ gf110_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index 9bbe2c97552e..b5b875928aba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -182,18 +182,18 @@ gf117_grctx_pack_ppc[] = { void gf117_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv); - const u32 alpha = impl->alpha_nr; - const u32 beta = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 alpha = grctx->alpha_nr; + const u32 beta = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, ppc; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -201,68 +201,60 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info) mmio_wr32(info, 0x405830, (beta << 16) | alpha); mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) { - const u32 a = alpha * priv->ppc_tpc_nr[gpc][ppc]; - const u32 b = beta * priv->ppc_tpc_nr[gpc][ppc]; + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) { + const u32 a = alpha * gr->ppc_tpc_nr[gpc][ppc]; + const u32 b = beta * gr->ppc_tpc_nr[gpc][ppc]; const u32 t = timeslice_mode; const u32 o = PPC_UNIT(gpc, ppc, 0); mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo); mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo); - bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, o + 0xe4, (a << 16) | ao); - ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; } } } void -gf117_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; int i; - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); + nvkm_mc_unk260(device->mc, 0); - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(priv); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); - gf100_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gf100_grctx_generate_r4060a8(priv); - gk104_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gf100_grctx_generate_r4060a8(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + gf100_gr_icmd(gr, grctx->icmd); + nvkm_wr32(device, 0x404154, 0x00000400); + gf100_gr_mthd(gr, grctx->mthd); + nvkm_mc_unk260(device->mc, 1); } -struct nvkm_oclass * -gf117_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xd7), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf117_grctx = { .main = gf117_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gf117_grctx_pack_hub, @@ -281,4 +273,4 @@ gf117_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x324, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c index 8d8761443809..605185b078be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c @@ -498,17 +498,8 @@ gf119_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gf119_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xd9), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf119_grctx = { .main = gf100_grctx_generate_main, .unkn = gf108_grctx_generate_unkn, .hub = gf119_grctx_pack_hub, @@ -526,4 +517,4 @@ gf119_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x324, .alpha_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index b12f6a9fd926..a843e3689c3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -843,27 +843,27 @@ gk104_grctx_pack_ppc[] = { void gk104_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); - const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, - impl->bundle_size / 0x20); - const u32 token_limit = impl->bundle_token_limit; + const struct gf100_grctx_func *grctx = info->gr->func->grctx; + const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, + grctx->bundle_size / 0x20); + const u32 token_limit = grctx->bundle_token_limit; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + const int b = mmio_vram(info, grctx->bundle_size, (1 << s), access); mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); mmio_refn(info, 0x418808, 0x00000000, s, b); - mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s)); mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); } void gk104_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), access); mmio_refn(info, 0x40800c, 0x00000000, s, b); mmio_wr32(info, 0x408010, 0x80000000); mmio_refn(info, 0x419004, 0x00000000, s, b); @@ -872,31 +872,33 @@ gk104_grctx_generate_pagepool(struct gf100_grctx *info) } void -gk104_grctx_generate_unkn(struct gf100_gr_priv *priv) +gk104_grctx_generate_unkn(struct gf100_gr *gr) { - nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001); - nv_mask(priv, 0x41980c, 0x00000010, 0x00000010); - nv_mask(priv, 0x41be08, 0x00000004, 0x00000004); - nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000); - nv_mask(priv, 0x405800, 0x08000000, 0x08000000); - nv_mask(priv, 0x419c00, 0x00000008, 0x00000008); + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_mask(device, 0x418c6c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x41980c, 0x00000010, 0x00000010); + nvkm_mask(device, 0x41be08, 0x00000004, 0x00000004); + nvkm_mask(device, 0x4064c0, 0x80000000, 0x80000000); + nvkm_mask(device, 0x405800, 0x08000000, 0x08000000); + nvkm_mask(device, 0x419c00, 0x00000008, 0x00000008); } void -gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv) +gk104_grctx_generate_r418bb8(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 data[6] = {}, data2[2] = {}; u8 tpcnr[GPC_MAX]; u8 shift, ntpcv; int gpc, tpc, i; /* calculate first set of magics */ - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); gpc = -1; - for (tpc = 0; tpc < priv->tpc_total; tpc++) { + for (tpc = 0; tpc < gr->tpc_total; tpc++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; @@ -908,7 +910,7 @@ gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv) /* and the second... */ shift = 0; - ntpcv = priv->tpc_total; + ntpcv = gr->tpc_total; while (!(ntpcv & (1 << 4))) { ntpcv <<= 1; shift++; @@ -921,86 +923,79 @@ gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* GPC_BROADCAST */ - nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nvkm_wr32(device, 0x418bb8, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x418b08 + (i * 4), data[i]); + nvkm_wr32(device, 0x418b08 + (i * 4), data[i]); /* GPC_BROADCAST.TP_BROADCAST */ - nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) | - priv->magic_not_rop_nr | data2[0]); - nv_wr32(priv, 0x41bfe4, data2[1]); + nvkm_wr32(device, 0x41bfd0, (gr->tpc_total << 8) | + gr->magic_not_rop_nr | data2[0]); + nvkm_wr32(device, 0x41bfe4, data2[1]); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x41bf00 + (i * 4), data[i]); + nvkm_wr32(device, 0x41bf00 + (i * 4), data[i]); /* UNK78xx */ - nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nvkm_wr32(device, 0x4078bc, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x40780c + (i * 4), data[i]); + nvkm_wr32(device, 0x40780c + (i * 4), data[i]); } void -gk104_grctx_generate_rop_active_fbps(struct gf100_gr_priv *priv) +gk104_grctx_generate_rop_active_fbps(struct gf100_gr *gr) { - const u32 fbp_count = nv_rd32(priv, 0x120074); - nv_mask(priv, 0x408850, 0x0000000f, fbp_count); /* zrop */ - nv_mask(priv, 0x408958, 0x0000000f, fbp_count); /* crop */ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 fbp_count = nvkm_rd32(device, 0x120074); + nvkm_mask(device, 0x408850, 0x0000000f, fbp_count); /* zrop */ + nvkm_mask(device, 0x408958, 0x0000000f, fbp_count); /* crop */ } void -gk104_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; int i; - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); + nvkm_mc_unk260(device->mc, 0); - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(priv); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); - gf100_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); - gk104_grctx_generate_rop_active_fbps(priv); - nv_mask(priv, 0x419f78, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + gk104_grctx_generate_rop_active_fbps(gr); + nvkm_mask(device, 0x419f78, 0x00000001, 0x00000000); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + gf100_gr_icmd(gr, grctx->icmd); + nvkm_wr32(device, 0x404154, 0x00000400); + gf100_gr_mthd(gr, grctx->mthd); + nvkm_mc_unk260(device->mc, 1); - nv_mask(priv, 0x418800, 0x00200000, 0x00200000); - nv_mask(priv, 0x41be10, 0x00800000, 0x00800000); + nvkm_mask(device, 0x418800, 0x00200000, 0x00200000); + nvkm_mask(device, 0x41be10, 0x00800000, 0x00800000); } -struct nvkm_oclass * -gk104_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk104_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk104_grctx_pack_hub, @@ -1021,4 +1016,4 @@ gk104_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c index b3f58be04e9c..7b95ec2fe453 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c @@ -808,17 +808,8 @@ gk110_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gk110_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xf0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk110_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk110_grctx_pack_hub, @@ -839,4 +830,4 @@ gk110_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c index b11c26794fde..048b1152da44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c @@ -69,17 +69,8 @@ gk110b_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gk110b_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xf1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk110b_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk110_grctx_pack_hub, @@ -100,4 +91,4 @@ gk110b_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c index 6e8ce9fc311a..67b7a1b43617 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c @@ -530,17 +530,8 @@ gk208_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gk208_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk208_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk208_grctx_pack_hub, @@ -561,4 +552,4 @@ gk208_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c index 2f241f6f0f0a..ddaa16a71c84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,34 +20,60 @@ * DEALINGS IN THE SOFTWARE. */ #include "ctxgf100.h" +#include "gf100.h" -static const struct gf100_gr_pack -gk20a_grctx_pack_mthd[] = { - { gk104_grctx_init_a097_0, 0xa297 }, - { gf100_grctx_init_902d_0, 0x902d }, - {} -}; +#include <subdev/mc.h> + +static void +gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; + int idle_timeout_save; + int i; + + gf100_gr_mmio(gr, gr->fuc_sw_ctx); + + gf100_gr_wait_idle(gr); + + idle_timeout_save = nvkm_rd32(device, 0x404154); + nvkm_wr32(device, 0x404154, 0x00000000); + + grctx->attrib(info); + + grctx->unkn(gr); + + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); + + for (i = 0; i < 8; i++) + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); -struct nvkm_oclass * -gk20a_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, - .main = gk104_grctx_generate_main, + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + + gk104_grctx_generate_rop_active_fbps(gr); + + nvkm_mask(device, 0x5044b0, 0x8000000, 0x8000000); + + gf100_gr_wait_idle(gr); + + nvkm_wr32(device, 0x404154, idle_timeout_save); + gf100_gr_wait_idle(gr); + + gf100_gr_mthd(gr, gr->fuc_method); + gf100_gr_wait_idle(gr); + + gf100_gr_icmd(gr, gr->fuc_bundle); + grctx->pagepool(info); + grctx->bundle(info); +} + +const struct gf100_grctx_func +gk20a_grctx = { + .main = gk20a_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, - .hub = gk104_grctx_pack_hub, - .gpc = gk104_grctx_pack_gpc, - .zcull = gf100_grctx_pack_zcull, - .tpc = gk104_grctx_pack_tpc, - .ppc = gk104_grctx_pack_ppc, - .icmd = gk104_grctx_pack_icmd, - .mthd = gk20a_grctx_pack_mthd, .bundle = gk104_grctx_generate_bundle, .bundle_size = 0x1800, .bundle_min_gpm_fifo_depth = 0x62, @@ -59,4 +85,4 @@ gk20a_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x240, .alpha_nr_max = 0x648 + (0x648 / 2), .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index fbeaae3ae6ce..95f59e3169f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -863,27 +863,27 @@ gm107_grctx_pack_ppc[] = { void gm107_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); - const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, - impl->bundle_size / 0x20); - const u32 token_limit = impl->bundle_token_limit; + const struct gf100_grctx_func *grctx = info->gr->func->grctx; + const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, + grctx->bundle_size / 0x20); + const u32 token_limit = grctx->bundle_token_limit; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + const int b = mmio_vram(info, grctx->bundle_size, (1 << s), access); mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); mmio_refn(info, 0x418e24, 0x00000000, s, b); - mmio_wr32(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x418e28, 0x80000000 | (grctx->bundle_size >> s)); mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); } void gm107_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), access); mmio_refn(info, 0x40800c, 0x00000000, s, b); mmio_wr32(info, 0x408010, 0x80000000); mmio_refn(info, 0x419004, 0x00000000, s, b); @@ -895,17 +895,17 @@ gm107_grctx_generate_pagepool(struct gf100_grctx *info) void gm107_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = (void *)gf100_grctx_impl(priv); - const u32 alpha = impl->alpha_nr; - const u32 attrib = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 alpha = grctx->alpha_nr; + const u32 attrib = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, ppc, n = 0; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -914,97 +914,90 @@ gm107_grctx_generate_attrib(struct gf100_grctx *info) mmio_wr32(info, 0x405830, (attrib << 16) | alpha); mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++, n++) { - const u32 as = alpha * priv->ppc_tpc_nr[gpc][ppc]; - const u32 bs = attrib * priv->ppc_tpc_nr[gpc][ppc]; + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) { + const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc]; + const u32 bs = attrib * gr->ppc_tpc_nr[gpc][ppc]; const u32 u = 0x418ea0 + (n * 0x04); const u32 o = PPC_UNIT(gpc, ppc, 0); mmio_wr32(info, o + 0xc0, bs); mmio_wr32(info, o + 0xf4, bo); - bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, o + 0xe4, as); mmio_wr32(info, o + 0xf8, ao); - ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, u, ((bs / 3 /*XXX*/) << 16) | bs); } } } -static void -gm107_grctx_generate_tpcid(struct gf100_gr_priv *priv) +void +gm107_grctx_generate_tpcid(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - if (tpc < priv->tpc_nr[gpc]) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + if (tpc < gr->tpc_nr[gpc]) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x698), id); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), id); id++; } - nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); } } } static void -gm107_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; int i; - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(priv); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); - gm107_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); + gm107_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); - nv_wr32(priv, 0x4064d0, 0x00000001); + nvkm_wr32(device, 0x4064d0, 0x00000001); for (i = 1; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x406500, 0x00000001); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x406500, 0x00000001); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); - gk104_grctx_generate_rop_active_fbps(priv); + gk104_grctx_generate_rop_active_fbps(gr); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); + gf100_gr_icmd(gr, grctx->icmd); + nvkm_wr32(device, 0x404154, 0x00000400); + gf100_gr_mthd(gr, grctx->mthd); - nv_mask(priv, 0x419e00, 0x00808080, 0x00808080); - nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000); - nv_mask(priv, 0x419f80, 0x80000000, 0x80000000); - nv_mask(priv, 0x419f88, 0x80000000, 0x80000000); + nvkm_mask(device, 0x419e00, 0x00808080, 0x00808080); + nvkm_mask(device, 0x419ccc, 0x80000000, 0x80000000); + nvkm_mask(device, 0x419f80, 0x80000000, 0x80000000); + nvkm_mask(device, 0x419f88, 0x80000000, 0x80000000); } -struct nvkm_oclass * -gm107_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gm107_grctx = { .main = gm107_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gm107_grctx_pack_hub, @@ -1025,4 +1018,4 @@ gm107_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0xaa0, .alpha_nr_max = 0x1800, .alpha_nr = 0x1000, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c index ea8e66151aa8..170cbfdbe1ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c @@ -918,17 +918,18 @@ gm204_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -static void -gm204_grctx_generate_tpcid(struct gf100_gr_priv *priv) +void +gm204_grctx_generate_tpcid(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - if (tpc < priv->tpc_nr[gpc]) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + if (tpc < gr->tpc_nr[gpc]) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x698), id); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), id); id++; } } @@ -936,101 +937,95 @@ gm204_grctx_generate_tpcid(struct gf100_gr_priv *priv) } static void -gm204_grctx_generate_rop_active_fbps(struct gf100_gr_priv *priv) +gm204_grctx_generate_rop_active_fbps(struct gf100_gr *gr) { - const u32 fbp_count = nv_rd32(priv, 0x12006c); - nv_mask(priv, 0x408850, 0x0000000f, fbp_count); /* zrop */ - nv_mask(priv, 0x408958, 0x0000000f, fbp_count); /* crop */ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 fbp_count = nvkm_rd32(device, 0x12006c); + nvkm_mask(device, 0x408850, 0x0000000f, fbp_count); /* zrop */ + nvkm_mask(device, 0x408958, 0x0000000f, fbp_count); /* crop */ } -static void -gm204_grctx_generate_405b60(struct gf100_gr_priv *priv) +void +gm204_grctx_generate_405b60(struct gf100_gr *gr) { - const u32 dist_nr = DIV_ROUND_UP(priv->tpc_total, 4); - u32 dist[TPC_MAX] = {}; + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 dist_nr = DIV_ROUND_UP(gr->tpc_total, 4); + u32 dist[TPC_MAX / 4] = {}; u32 gpcs[GPC_MAX] = {}; u8 tpcnr[GPC_MAX]; int tpc, gpc, i; - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); /* won't result in the same distribution as the binary driver where * some of the gpcs have more tpcs than others, but this shall do * for the moment. the code for earlier gpus has this issue too. */ - for (gpc = -1, i = 0; i < priv->tpc_total; i++) { + for (gpc = -1, i = 0; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while(!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; dist[i / 4] |= ((gpc << 4) | tpc) << ((i % 4) * 8); gpcs[gpc] |= i << (tpc * 8); } for (i = 0; i < dist_nr; i++) - nv_wr32(priv, 0x405b60 + (i * 4), dist[i]); - for (i = 0; i < priv->gpc_nr; i++) - nv_wr32(priv, 0x405ba0 + (i * 4), gpcs[i]); + nvkm_wr32(device, 0x405b60 + (i * 4), dist[i]); + for (i = 0; i < gr->gpc_nr; i++) + nvkm_wr32(device, 0x405ba0 + (i * 4), gpcs[i]); } void -gm204_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gm204_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; u32 tmp; int i; - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(priv); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); - gm204_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); + gm204_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x406500, 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x406500, 0x00000000); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); - gm204_grctx_generate_rop_active_fbps(priv); + gm204_grctx_generate_rop_active_fbps(gr); - for (tmp = 0, i = 0; i < priv->gpc_nr; i++) - tmp |= ((1 << priv->tpc_nr[i]) - 1) << (i * 4); - nv_wr32(priv, 0x4041c4, tmp); + for (tmp = 0, i = 0; i < gr->gpc_nr; i++) + tmp |= ((1 << gr->tpc_nr[i]) - 1) << (i * 4); + nvkm_wr32(device, 0x4041c4, tmp); - gm204_grctx_generate_405b60(priv); + gm204_grctx_generate_405b60(gr); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000800); - gf100_gr_mthd(priv, oclass->mthd); + gf100_gr_icmd(gr, grctx->icmd); + nvkm_wr32(device, 0x404154, 0x00000800); + gf100_gr_mthd(gr, grctx->mthd); - nv_mask(priv, 0x418e94, 0xffffffff, 0xc4230000); - nv_mask(priv, 0x418e4c, 0xffffffff, 0x70000000); + nvkm_mask(device, 0x418e94, 0xffffffff, 0xc4230000); + nvkm_mask(device, 0x418e4c, 0xffffffff, 0x70000000); } -struct nvkm_oclass * -gm204_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gm204_grctx = { .main = gm204_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gm204_grctx_pack_hub, @@ -1051,4 +1046,4 @@ gm204_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x400, .alpha_nr_max = 0x1800, .alpha_nr = 0x1000, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c index 91ec41617943..d6be6034c2c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c @@ -49,17 +49,8 @@ gm206_grctx_pack_gpc[] = { {} }; -struct nvkm_oclass * -gm206_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x26), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gm206_grctx = { .main = gm204_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gm204_grctx_pack_hub, @@ -80,4 +71,4 @@ gm206_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x400, .alpha_nr_max = 0x1800, .alpha_nr = 0x1000, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c new file mode 100644 index 000000000000..670260402538 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "ctxgf100.h" + +static void +gm20b_grctx_generate_r406028(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 tpc_per_gpc = 0; + int i; + + for (i = 0; i < gr->gpc_nr; i++) + tpc_per_gpc |= gr->tpc_nr[i] << (4 * i); + + nvkm_wr32(device, 0x406028, tpc_per_gpc); + nvkm_wr32(device, 0x405870, tpc_per_gpc); +} + +static void +gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; + int idle_timeout_save; + int i, tmp; + + gf100_gr_mmio(gr, gr->fuc_sw_ctx); + + gf100_gr_wait_idle(gr); + + idle_timeout_save = nvkm_rd32(device, 0x404154); + nvkm_wr32(device, 0x404154, 0x00000000); + + grctx->attrib(info); + + grctx->unkn(gr); + + gm204_grctx_generate_tpcid(gr); + gm20b_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + + for (i = 0; i < 8; i++) + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); + + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + + gk104_grctx_generate_rop_active_fbps(gr); + nvkm_wr32(device, 0x408908, nvkm_rd32(device, 0x410108) | 0x80000000); + + for (tmp = 0, i = 0; i < gr->gpc_nr; i++) + tmp |= ((1 << gr->tpc_nr[i]) - 1) << (i * 4); + nvkm_wr32(device, 0x4041c4, tmp); + + gm204_grctx_generate_405b60(gr); + + gf100_gr_wait_idle(gr); + + nvkm_wr32(device, 0x404154, idle_timeout_save); + gf100_gr_wait_idle(gr); + + gf100_gr_mthd(gr, gr->fuc_method); + gf100_gr_wait_idle(gr); + + gf100_gr_icmd(gr, gr->fuc_bundle); + grctx->pagepool(info); + grctx->bundle(info); +} + +const struct gf100_grctx_func +gm20b_grctx = { + .main = gm20b_grctx_generate_main, + .unkn = gk104_grctx_generate_unkn, + .bundle = gm107_grctx_generate_bundle, + .bundle_size = 0x1800, + .bundle_min_gpm_fifo_depth = 0x182, + .bundle_token_limit = 0x1c0, + .pagepool = gm107_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = gm107_grctx_generate_attrib, + .attrib_nr_max = 0x600, + .attrib_nr = 0x400, + .alpha_nr_max = 0xc00, + .alpha_nr = 0x800, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c index dc31462afe65..80a6b017af64 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c @@ -111,7 +111,6 @@ #include "ctxnv40.h" #include "nv40.h" -#include <core/device.h> /* TODO: * - get vs count from 0x1540 @@ -583,13 +582,13 @@ nv40_gr_construct_shader(struct nvkm_grctx *ctx) offset += 0x0280/4; for (i = 0; i < 16; i++, offset += 2) - nv_wo32(obj, offset * 4, 0x3f800000); + nvkm_wo32(obj, offset * 4, 0x3f800000); for (vs = 0; vs < vs_nr; vs++, offset += vs_len) { for (i = 0; i < vs_nr_b0 * 6; i += 6) - nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001); + nvkm_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001); for (i = 0; i < vs_nr_b1 * 4; i += 4) - nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000); + nvkm_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000); } } @@ -675,7 +674,7 @@ nv40_grctx_init(struct nvkm_device *device, u32 *size) struct nvkm_grctx ctx = { .device = device, .mode = NVKM_GRCTX_PROG, - .data = ctxprog, + .ucode = ctxprog, .ctxprog_max = 256, }; @@ -684,9 +683,9 @@ nv40_grctx_init(struct nvkm_device *device, u32 *size) nv40_grctx_generate(&ctx); - nv_wr32(device, 0x400324, 0); + nvkm_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) - nv_wr32(device, 0x400328, ctxprog[i]); + nvkm_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; kfree(ctxprog); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h index 8a89961956af..50e808e9f926 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h @@ -9,7 +9,8 @@ struct nvkm_grctx { NVKM_GRCTX_PROG, NVKM_GRCTX_VALS } mode; - void *data; + u32 *ucode; + struct nvkm_gpuobj *data; u32 ctxprog_max; u32 ctxprog_len; @@ -22,7 +23,7 @@ struct nvkm_grctx { static inline void cp_out(struct nvkm_grctx *ctx, u32 inst) { - u32 *ctxprog = ctx->data; + u32 *ctxprog = ctx->ucode; if (ctx->mode != NVKM_GRCTX_PROG) return; @@ -56,7 +57,7 @@ cp_ctx(struct nvkm_grctx *ctx, u32 reg, u32 length) static inline void cp_name(struct nvkm_grctx *ctx, int name) { - u32 *ctxprog = ctx->data; + u32 *ctxprog = ctx->ucode; int i; if (ctx->mode != NVKM_GRCTX_PROG) @@ -124,6 +125,6 @@ gr_def(struct nvkm_grctx *ctx, u32 reg, u32 val) reg = (reg - 0x00400000) / 4; reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base; - nv_wo32(ctx->data, reg * 4, val); + nvkm_wo32(ctx->data, reg * 4, val); } #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index 9c9528d2cd90..1e13278cf306 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -107,7 +107,6 @@ #include "ctxnv40.h" -#include <core/device.h> #include <subdev/fb.h> #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) @@ -269,7 +268,7 @@ nv50_grctx_init(struct nvkm_device *device, u32 *size) struct nvkm_grctx ctx = { .device = device, .mode = NVKM_GRCTX_PROG, - .data = ctxprog, + .ucode = ctxprog, .ctxprog_max = 512, }; @@ -277,9 +276,9 @@ nv50_grctx_init(struct nvkm_device *device, u32 *size) return -ENOMEM; nv50_grctx_generate(&ctx); - nv_wr32(device, 0x400324, 0); + nvkm_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) - nv_wr32(device, 0x400328, ctxprog[i]); + nvkm_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; kfree(ctxprog); return 0; @@ -299,7 +298,7 @@ nv50_gr_construct_mmio(struct nvkm_grctx *ctx) struct nvkm_device *device = ctx->device; int i, j; int offset, base; - u32 units = nv_rd32 (ctx->device, 0x1540); + u32 units = nvkm_rd32(device, 0x1540); /* 0800: DISPATCH */ cp_ctx(ctx, 0x400808, 7); @@ -570,7 +569,7 @@ nv50_gr_construct_mmio(struct nvkm_grctx *ctx) else if (device->chipset < 0xa0) gr_def(ctx, 0x407d08, 0x00390040); else { - if (nvkm_fb(device)->ram->type != NV_MEM_TYPE_GDDR5) + if (device->fb->ram->type != NVKM_RAM_TYPE_GDDR5) gr_def(ctx, 0x407d08, 0x003d0040); else gr_def(ctx, 0x407d08, 0x003c0040); @@ -784,9 +783,10 @@ nv50_gr_construct_mmio(struct nvkm_grctx *ctx) static void dd_emit(struct nvkm_grctx *ctx, int num, u32 val) { int i; - if (val && ctx->mode == NVKM_GRCTX_VALS) + if (val && ctx->mode == NVKM_GRCTX_VALS) { for (i = 0; i < num; i++) - nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val); + nvkm_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val); + } ctx->ctxvals_pos += num; } @@ -1156,9 +1156,10 @@ nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx) static void xf_emit(struct nvkm_grctx *ctx, int num, u32 val) { int i; - if (val && ctx->mode == NVKM_GRCTX_VALS) + if (val && ctx->mode == NVKM_GRCTX_VALS) { for (i = 0; i < num; i++) - nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val); + nvkm_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val); + } ctx->ctxvals_pos += num << 3; } @@ -1190,7 +1191,7 @@ nv50_gr_construct_xfer1(struct nvkm_grctx *ctx) int i; int offset; int size = 0; - u32 units = nv_rd32 (ctx->device, 0x1540); + u32 units = nvkm_rd32(device, 0x1540); offset = (ctx->ctxvals_pos+0x3f)&~0x3f; ctx->ctxvals_base = offset; @@ -3273,7 +3274,7 @@ nv50_gr_construct_xfer2(struct nvkm_grctx *ctx) struct nvkm_device *device = ctx->device; int i; u32 offset; - u32 units = nv_rd32 (ctx->device, 0x1540); + u32 units = nvkm_rd32(device, 0x1540); int size = 0; offset = (ctx->ctxvals_pos+0x3f)&~0x3f; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c new file mode 100644 index 000000000000..ce913300539f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c @@ -0,0 +1,196 @@ +/* + * 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" + +#include <subdev/timer.h> + +static const struct nvkm_bitfield nv50_gr_status[] = { + { 0x00000001, "BUSY" }, /* set when any bit is set */ + { 0x00000002, "DISPATCH" }, + { 0x00000004, "UNK2" }, + { 0x00000008, "UNK3" }, + { 0x00000010, "UNK4" }, + { 0x00000020, "UNK5" }, + { 0x00000040, "M2MF" }, + { 0x00000080, "UNK7" }, + { 0x00000100, "CTXPROG" }, + { 0x00000200, "VFETCH" }, + { 0x00000400, "CCACHE_PREGEOM" }, + { 0x00000800, "STRMOUT_VATTR_POSTGEOM" }, + { 0x00001000, "VCLIP" }, + { 0x00002000, "RATTR_APLANE" }, + { 0x00004000, "TRAST" }, + { 0x00008000, "CLIPID" }, + { 0x00010000, "ZCULL" }, + { 0x00020000, "ENG2D" }, + { 0x00040000, "RMASK" }, + { 0x00080000, "TPC_RAST" }, + { 0x00100000, "TPC_PROP" }, + { 0x00200000, "TPC_TEX" }, + { 0x00400000, "TPC_GEOM" }, + { 0x00800000, "TPC_MP" }, + { 0x01000000, "ROP" }, + {} +}; + +static const struct nvkm_bitfield +nv50_gr_vstatus_0[] = { + { 0x01, "VFETCH" }, + { 0x02, "CCACHE" }, + { 0x04, "PREGEOM" }, + { 0x08, "POSTGEOM" }, + { 0x10, "VATTR" }, + { 0x20, "STRMOUT" }, + { 0x40, "VCLIP" }, + {} +}; + +static const struct nvkm_bitfield +nv50_gr_vstatus_1[] = { + { 0x01, "TPC_RAST" }, + { 0x02, "TPC_PROP" }, + { 0x04, "TPC_TEX" }, + { 0x08, "TPC_GEOM" }, + { 0x10, "TPC_MP" }, + {} +}; + +static const struct nvkm_bitfield +nv50_gr_vstatus_2[] = { + { 0x01, "RATTR" }, + { 0x02, "APLANE" }, + { 0x04, "TRAST" }, + { 0x08, "CLIPID" }, + { 0x10, "ZCULL" }, + { 0x20, "ENG2D" }, + { 0x40, "RMASK" }, + { 0x80, "ROP" }, + {} +}; + +static void +nvkm_gr_vstatus_print(struct nv50_gr *gr, int r, + const struct nvkm_bitfield *units, u32 status) +{ + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + u32 stat = status; + u8 mask = 0x00; + char msg[64]; + int i; + + for (i = 0; units[i].name && status; i++) { + if ((status & 7) == 1) + mask |= (1 << i); + status >>= 3; + } + + nvkm_snprintbf(msg, sizeof(msg), units, mask); + nvkm_error(subdev, "PGRAPH_VSTATUS%d: %08x [%s]\n", r, stat, msg); +} + +int +g84_gr_tlb_flush(struct nvkm_gr *base) +{ + struct nv50_gr *gr = nv50_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_timer *tmr = device->timer; + bool idle, timeout = false; + unsigned long flags; + char status[128]; + u64 start; + u32 tmp; + + spin_lock_irqsave(&gr->lock, flags); + nvkm_mask(device, 0x400500, 0x00000001, 0x00000000); + + start = nvkm_timer_read(tmr); + do { + idle = true; + + for (tmp = nvkm_rd32(device, 0x400380); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nvkm_rd32(device, 0x400384); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nvkm_rd32(device, 0x400388); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + } while (!idle && + !(timeout = nvkm_timer_read(tmr) - start > 2000000000)); + + if (timeout) { + nvkm_error(subdev, "PGRAPH TLB flush idle timeout fail\n"); + + tmp = nvkm_rd32(device, 0x400700); + nvkm_snprintbf(status, sizeof(status), nv50_gr_status, tmp); + nvkm_error(subdev, "PGRAPH_STATUS %08x [%s]\n", tmp, status); + + nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0, + nvkm_rd32(device, 0x400380)); + nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1, + nvkm_rd32(device, 0x400384)); + nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2, + nvkm_rd32(device, 0x400388)); + } + + + nvkm_wr32(device, 0x100c80, 0x00000001); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) + break; + ); + nvkm_mask(device, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); + return timeout ? -EBUSY : 0; +} + +static const struct nvkm_gr_func +g84_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8297, &nv50_gr_object }, + {} + } +}; + +int +g84_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&g84_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 5606c25e5d02..f1358a564e3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -26,13 +26,12 @@ #include "fuc/os.h" #include <core/client.h> -#include <core/device.h> -#include <core/handle.h> #include <core/option.h> -#include <engine/fifo.h> #include <subdev/fb.h> #include <subdev/mc.h> +#include <subdev/pmu.h> #include <subdev/timer.h> +#include <engine/fifo.h> #include <nvif/class.h> #include <nvif/unpack.h> @@ -42,35 +41,36 @@ ******************************************************************************/ static void -gf100_gr_zbc_clear_color(struct gf100_gr_priv *priv, int zbc) +gf100_gr_zbc_clear_color(struct gf100_gr *gr, int zbc) { - if (priv->zbc_color[zbc].format) { - nv_wr32(priv, 0x405804, priv->zbc_color[zbc].ds[0]); - nv_wr32(priv, 0x405808, priv->zbc_color[zbc].ds[1]); - nv_wr32(priv, 0x40580c, priv->zbc_color[zbc].ds[2]); - nv_wr32(priv, 0x405810, priv->zbc_color[zbc].ds[3]); - } - nv_wr32(priv, 0x405814, priv->zbc_color[zbc].format); - nv_wr32(priv, 0x405820, zbc); - nv_wr32(priv, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ + struct nvkm_device *device = gr->base.engine.subdev.device; + if (gr->zbc_color[zbc].format) { + nvkm_wr32(device, 0x405804, gr->zbc_color[zbc].ds[0]); + nvkm_wr32(device, 0x405808, gr->zbc_color[zbc].ds[1]); + nvkm_wr32(device, 0x40580c, gr->zbc_color[zbc].ds[2]); + nvkm_wr32(device, 0x405810, gr->zbc_color[zbc].ds[3]); + } + nvkm_wr32(device, 0x405814, gr->zbc_color[zbc].format); + nvkm_wr32(device, 0x405820, zbc); + nvkm_wr32(device, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ } static int -gf100_gr_zbc_color_get(struct gf100_gr_priv *priv, int format, +gf100_gr_zbc_color_get(struct gf100_gr *gr, int format, const u32 ds[4], const u32 l2[4]) { - struct nvkm_ltc *ltc = nvkm_ltc(priv); + struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int zbc = -ENOSPC, i; for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { - if (priv->zbc_color[i].format) { - if (priv->zbc_color[i].format != format) + if (gr->zbc_color[i].format) { + if (gr->zbc_color[i].format != format) continue; - if (memcmp(priv->zbc_color[i].ds, ds, sizeof( - priv->zbc_color[i].ds))) + if (memcmp(gr->zbc_color[i].ds, ds, sizeof( + gr->zbc_color[i].ds))) continue; - if (memcmp(priv->zbc_color[i].l2, l2, sizeof( - priv->zbc_color[i].l2))) { + if (memcmp(gr->zbc_color[i].l2, l2, sizeof( + gr->zbc_color[i].l2))) { WARN_ON(1); return -EINVAL; } @@ -83,38 +83,39 @@ gf100_gr_zbc_color_get(struct gf100_gr_priv *priv, int format, if (zbc < 0) return zbc; - memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds)); - memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2)); - priv->zbc_color[zbc].format = format; - ltc->zbc_color_get(ltc, zbc, l2); - gf100_gr_zbc_clear_color(priv, zbc); + memcpy(gr->zbc_color[zbc].ds, ds, sizeof(gr->zbc_color[zbc].ds)); + memcpy(gr->zbc_color[zbc].l2, l2, sizeof(gr->zbc_color[zbc].l2)); + gr->zbc_color[zbc].format = format; + nvkm_ltc_zbc_color_get(ltc, zbc, l2); + gf100_gr_zbc_clear_color(gr, zbc); return zbc; } static void -gf100_gr_zbc_clear_depth(struct gf100_gr_priv *priv, int zbc) +gf100_gr_zbc_clear_depth(struct gf100_gr *gr, int zbc) { - if (priv->zbc_depth[zbc].format) - nv_wr32(priv, 0x405818, priv->zbc_depth[zbc].ds); - nv_wr32(priv, 0x40581c, priv->zbc_depth[zbc].format); - nv_wr32(priv, 0x405820, zbc); - nv_wr32(priv, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ + struct nvkm_device *device = gr->base.engine.subdev.device; + if (gr->zbc_depth[zbc].format) + nvkm_wr32(device, 0x405818, gr->zbc_depth[zbc].ds); + nvkm_wr32(device, 0x40581c, gr->zbc_depth[zbc].format); + nvkm_wr32(device, 0x405820, zbc); + nvkm_wr32(device, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ } static int -gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format, +gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format, const u32 ds, const u32 l2) { - struct nvkm_ltc *ltc = nvkm_ltc(priv); + struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int zbc = -ENOSPC, i; for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { - if (priv->zbc_depth[i].format) { - if (priv->zbc_depth[i].format != format) + if (gr->zbc_depth[i].format) { + if (gr->zbc_depth[i].format != format) continue; - if (priv->zbc_depth[i].ds != ds) + if (gr->zbc_depth[i].ds != ds) continue; - if (priv->zbc_depth[i].l2 != l2) { + if (gr->zbc_depth[i].l2 != l2) { WARN_ON(1); return -EINVAL; } @@ -127,11 +128,11 @@ gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format, if (zbc < 0) return zbc; - priv->zbc_depth[zbc].format = format; - priv->zbc_depth[zbc].ds = ds; - priv->zbc_depth[zbc].l2 = l2; - ltc->zbc_depth_get(ltc, zbc, l2); - gf100_gr_zbc_clear_depth(priv, zbc); + gr->zbc_depth[zbc].format = format; + gr->zbc_depth[zbc].ds = ds; + gr->zbc_depth[zbc].l2 = l2; + nvkm_ltc_zbc_depth_get(ltc, zbc, l2); + gf100_gr_zbc_clear_depth(gr, zbc); return zbc; } @@ -142,7 +143,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format, static int gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) { - struct gf100_gr_priv *priv = (void *)object->engine; + struct gf100_gr *gr = (void *)object->engine; union { struct fermi_a_zbc_color_v0 v0; } *args = data; @@ -169,7 +170,7 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8: case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10: case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11: - ret = gf100_gr_zbc_color_get(priv, args->v0.format, + ret = gf100_gr_zbc_color_get(gr, args->v0.format, args->v0.ds, args->v0.l2); if (ret >= 0) { @@ -188,7 +189,7 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) static int gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size) { - struct gf100_gr_priv *priv = (void *)object->engine; + struct gf100_gr *gr = (void *)object->engine; union { struct fermi_a_zbc_depth_v0 v0; } *args = data; @@ -197,7 +198,7 @@ gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size) if (nvif_unpack(args->v0, 0, 0, false)) { switch (args->v0.format) { case FERMI_A_ZBC_DEPTH_V0_FMT_FP32: - ret = gf100_gr_zbc_depth_get(priv, args->v0.format, + ret = gf100_gr_zbc_depth_get(gr, args->v0.format, args->v0.ds, args->v0.l2); return (ret >= 0) ? 0 : -ENOSPC; @@ -223,106 +224,176 @@ gf100_fermi_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } -struct nvkm_ofuncs -gf100_fermi_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, +const struct nvkm_object_func +gf100_fermi = { .mthd = gf100_fermi_mthd, }; -static int -gf100_gr_set_shader_exceptions(struct nvkm_object *object, u32 mthd, - void *pdata, u32 size) +static void +gf100_gr_mthd_set_shader_exceptions(struct nvkm_device *device, u32 data) { - struct gf100_gr_priv *priv = (void *)object->engine; - if (size >= sizeof(u32)) { - u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000; - nv_wr32(priv, 0x419e44, data); - nv_wr32(priv, 0x419e4c, data); - return 0; + nvkm_wr32(device, 0x419e44, data ? 0xffffffff : 0x00000000); + nvkm_wr32(device, 0x419e4c, data ? 0xffffffff : 0x00000000); +} + +static bool +gf100_gr_mthd_sw(struct nvkm_device *device, u16 class, u32 mthd, u32 data) +{ + switch (class & 0x00ff) { + case 0x97: + case 0xc0: + switch (mthd) { + case 0x1528: + gf100_gr_mthd_set_shader_exceptions(device, data); + return true; + default: + break; + } + break; + default: + break; } - return -EINVAL; + return false; } -struct nvkm_omthds -gf100_gr_9097_omthds[] = { - { 0x1528, 0x1528, gf100_gr_set_shader_exceptions }, - {} -}; +static int +gf100_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass) +{ + struct gf100_gr *gr = gf100_gr(base); + int c = 0; -struct nvkm_omthds -gf100_gr_90c0_omthds[] = { - { 0x1528, 0x1528, gf100_gr_set_shader_exceptions }, - {} -}; + while (gr->func->sclass[c].oclass) { + if (c++ == index) { + *sclass = gr->func->sclass[index]; + return index; + } + } -struct nvkm_oclass -gf100_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} -}; + return c; +} /******************************************************************************* * PGRAPH context ******************************************************************************/ -int -gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *args, u32 size, - struct nvkm_object **pobject) +static int +gf100_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_vm *vm = nvkm_client(parent)->vm; - struct gf100_gr_priv *priv = (void *)engine; - struct gf100_gr_data *data = priv->mmio_data; - struct gf100_gr_mmio *mmio = priv->mmio_list; - struct gf100_gr_chan *chan; + struct gf100_gr_chan *chan = gf100_gr_chan(object); + struct gf100_gr *gr = chan->gr; int ret, i; - /* allocate memory for context, and fill with default values */ - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, - priv->size, 0x100, - NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size, + align, false, parent, pgpuobj); if (ret) return ret; + nvkm_kmap(*pgpuobj); + for (i = 0; i < gr->size; i += 4) + nvkm_wo32(*pgpuobj, i, gr->data[i / 4]); + + if (!gr->firmware) { + nvkm_wo32(*pgpuobj, 0x00, chan->mmio_nr / 2); + nvkm_wo32(*pgpuobj, 0x04, chan->mmio_vma.offset >> 8); + } else { + nvkm_wo32(*pgpuobj, 0xf4, 0); + nvkm_wo32(*pgpuobj, 0xf8, 0); + nvkm_wo32(*pgpuobj, 0x10, chan->mmio_nr / 2); + nvkm_wo32(*pgpuobj, 0x14, lower_32_bits(chan->mmio_vma.offset)); + nvkm_wo32(*pgpuobj, 0x18, upper_32_bits(chan->mmio_vma.offset)); + nvkm_wo32(*pgpuobj, 0x1c, 1); + nvkm_wo32(*pgpuobj, 0x20, 0); + nvkm_wo32(*pgpuobj, 0x28, 0); + nvkm_wo32(*pgpuobj, 0x2c, 0); + } + nvkm_done(*pgpuobj); + return 0; +} + +static void * +gf100_gr_chan_dtor(struct nvkm_object *object) +{ + struct gf100_gr_chan *chan = gf100_gr_chan(object); + int i; + + for (i = 0; i < ARRAY_SIZE(chan->data); i++) { + if (chan->data[i].vma.node) { + nvkm_vm_unmap(&chan->data[i].vma); + nvkm_vm_put(&chan->data[i].vma); + } + nvkm_memory_del(&chan->data[i].mem); + } + + if (chan->mmio_vma.node) { + nvkm_vm_unmap(&chan->mmio_vma); + nvkm_vm_put(&chan->mmio_vma); + } + nvkm_memory_del(&chan->mmio); + return chan; +} + +static const struct nvkm_object_func +gf100_gr_chan = { + .dtor = gf100_gr_chan_dtor, + .bind = gf100_gr_chan_bind, +}; + +static int +gf100_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct gf100_gr *gr = gf100_gr(base); + struct gf100_gr_data *data = gr->mmio_data; + struct gf100_gr_mmio *mmio = gr->mmio_list; + struct gf100_gr_chan *chan; + struct nvkm_device *device = gr->base.engine.subdev.device; + int ret, i; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&gf100_gr_chan, oclass, &chan->object); + chan->gr = gr; + *pobject = &chan->object; + /* allocate memory for a "mmio list" buffer that's used by the HUB * fuc to modify some per-context register settings on first load * of the context. */ - ret = nvkm_gpuobj_new(nv_object(chan), NULL, 0x1000, 0x100, 0, - &chan->mmio); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x100, + false, &chan->mmio); if (ret) return ret; - ret = nvkm_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm, - NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, - &chan->mmio_vma); + ret = nvkm_vm_get(fifoch->vm, 0x1000, 12, NV_MEM_ACCESS_RW | + NV_MEM_ACCESS_SYS, &chan->mmio_vma); if (ret) return ret; + nvkm_memory_map(chan->mmio, &chan->mmio_vma, 0); + /* allocate buffers referenced by mmio list */ - for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) { - ret = nvkm_gpuobj_new(nv_object(chan), NULL, data->size, - data->align, 0, &chan->data[i].mem); + for (i = 0; data->size && i < ARRAY_SIZE(gr->mmio_data); i++) { + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + data->size, data->align, false, + &chan->data[i].mem); if (ret) return ret; - ret = nvkm_gpuobj_map_vm(chan->data[i].mem, vm, data->access, - &chan->data[i].vma); + ret = nvkm_vm_get(fifoch->vm, + nvkm_memory_size(chan->data[i].mem), 12, + data->access, &chan->data[i].vma); if (ret) return ret; + nvkm_memory_map(chan->data[i].mem, &chan->data[i].vma, 0); data++; } /* finally, fill in the mmio list and point the context at it */ - for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) { + nvkm_kmap(chan->mmio); + for (i = 0; mmio->addr && i < ARRAY_SIZE(gr->mmio_list); i++) { u32 addr = mmio->addr; u32 data = mmio->data; @@ -331,49 +402,14 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, data |= info >> mmio->shift; } - nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); - nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data); + nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); + nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, data); mmio++; } - - for (i = 0; i < priv->size; i += 4) - nv_wo32(chan, i, priv->data[i / 4]); - - if (!priv->firmware) { - nv_wo32(chan, 0x00, chan->mmio_nr / 2); - nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8); - } else { - nv_wo32(chan, 0xf4, 0); - nv_wo32(chan, 0xf8, 0); - nv_wo32(chan, 0x10, chan->mmio_nr / 2); - nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset)); - nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset)); - nv_wo32(chan, 0x1c, 1); - nv_wo32(chan, 0x20, 0); - nv_wo32(chan, 0x28, 0); - nv_wo32(chan, 0x2c, 0); - } - + nvkm_done(chan->mmio); return 0; } -void -gf100_gr_context_dtor(struct nvkm_object *object) -{ - struct gf100_gr_chan *chan = (void *)object; - int i; - - for (i = 0; i < ARRAY_SIZE(chan->data); i++) { - nvkm_gpuobj_unmap(&chan->data[i].vma); - nvkm_gpuobj_ref(NULL, &chan->data[i].mem); - } - - nvkm_gpuobj_unmap(&chan->mmio_vma); - nvkm_gpuobj_ref(NULL, &chan->mmio); - - nvkm_gr_context_destroy(&chan->base); -} - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -635,7 +671,7 @@ gf100_gr_pack_mmio[] = { ******************************************************************************/ void -gf100_gr_zbc_init(struct gf100_gr_priv *priv) +gf100_gr_zbc_init(struct gf100_gr *gr) { const u32 zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; @@ -645,27 +681,62 @@ gf100_gr_zbc_init(struct gf100_gr_priv *priv) 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; - struct nvkm_ltc *ltc = nvkm_ltc(priv); + struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int index; - if (!priv->zbc_color[0].format) { - gf100_gr_zbc_color_get(priv, 1, & zero[0], &zero[4]); - gf100_gr_zbc_color_get(priv, 2, & one[0], &one[4]); - gf100_gr_zbc_color_get(priv, 4, &f32_0[0], &f32_0[4]); - gf100_gr_zbc_color_get(priv, 4, &f32_1[0], &f32_1[4]); - gf100_gr_zbc_depth_get(priv, 1, 0x00000000, 0x00000000); - gf100_gr_zbc_depth_get(priv, 1, 0x3f800000, 0x3f800000); + if (!gr->zbc_color[0].format) { + gf100_gr_zbc_color_get(gr, 1, & zero[0], &zero[4]); + gf100_gr_zbc_color_get(gr, 2, & one[0], &one[4]); + gf100_gr_zbc_color_get(gr, 4, &f32_0[0], &f32_0[4]); + gf100_gr_zbc_color_get(gr, 4, &f32_1[0], &f32_1[4]); + gf100_gr_zbc_depth_get(gr, 1, 0x00000000, 0x00000000); + gf100_gr_zbc_depth_get(gr, 1, 0x3f800000, 0x3f800000); } for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) - gf100_gr_zbc_clear_color(priv, index); + gf100_gr_zbc_clear_color(gr, index); for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) - gf100_gr_zbc_clear_depth(priv, index); + gf100_gr_zbc_clear_depth(gr, index); +} + +/** + * Wait until GR goes idle. GR is considered idle if it is disabled by the + * MC (0x200) register, or GR is not busy and a context switch is not in + * progress. + */ +int +gf100_gr_wait_idle(struct gf100_gr *gr) +{ + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000); + bool gr_enabled, ctxsw_active, gr_busy; + + do { + /* + * required to make sure FIFO_ENGINE_STATUS (0x2640) is + * up-to-date + */ + nvkm_rd32(device, 0x400700); + + gr_enabled = nvkm_rd32(device, 0x200) & 0x1000; + ctxsw_active = nvkm_rd32(device, 0x2640) & 0x8000; + gr_busy = nvkm_rd32(device, 0x40060c) & 0x1; + + if (!gr_enabled || (!gr_busy && !ctxsw_active)) + return 0; + } while (time_before(jiffies, end_jiffies)); + + nvkm_error(subdev, + "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n", + gr_enabled, ctxsw_active, gr_busy); + return -EAGAIN; } void -gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) +gf100_gr_mmio(struct gf100_gr *gr, const struct gf100_gr_pack *p) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; @@ -673,43 +744,54 @@ gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) u32 next = init->addr + init->count * init->pitch; u32 addr = init->addr; while (addr < next) { - nv_wr32(priv, addr, init->data); + nvkm_wr32(device, addr, init->data); addr += init->pitch; } } } void -gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) +gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; u32 data = 0; - nv_wr32(priv, 0x400208, 0x80000000); + nvkm_wr32(device, 0x400208, 0x80000000); pack_for_each_init(init, pack, p) { u32 next = init->addr + init->count * init->pitch; u32 addr = init->addr; if ((pack == p && init == p->init) || data != init->data) { - nv_wr32(priv, 0x400204, init->data); + nvkm_wr32(device, 0x400204, init->data); data = init->data; } while (addr < next) { - nv_wr32(priv, 0x400200, addr); - nv_wait(priv, 0x400700, 0x00000002, 0x00000000); + nvkm_wr32(device, 0x400200, addr); + /** + * Wait for GR to go idle after submitting a + * GO_IDLE bundle + */ + if ((addr & 0xffff) == 0xe100) + gf100_gr_wait_idle(gr); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x400700) & 0x00000004)) + break; + ); addr += init->pitch; } } - nv_wr32(priv, 0x400208, 0x00000000); + nvkm_wr32(device, 0x400208, 0x00000000); } void -gf100_gr_mthd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) +gf100_gr_mthd(struct gf100_gr *gr, const struct gf100_gr_pack *p) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; u32 data = 0; @@ -720,79 +802,75 @@ gf100_gr_mthd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) u32 addr = init->addr; if ((pack == p && init == p->init) || data != init->data) { - nv_wr32(priv, 0x40448c, init->data); + nvkm_wr32(device, 0x40448c, init->data); data = init->data; } while (addr < next) { - nv_wr32(priv, 0x404488, ctrl | (addr << 14)); + nvkm_wr32(device, 0x404488, ctrl | (addr << 14)); addr += init->pitch; } } } u64 -gf100_gr_units(struct nvkm_gr *gr) +gf100_gr_units(struct nvkm_gr *base) { - struct gf100_gr_priv *priv = (void *)gr; + struct gf100_gr *gr = gf100_gr(base); u64 cfg; - cfg = (u32)priv->gpc_nr; - cfg |= (u32)priv->tpc_total << 8; - cfg |= (u64)priv->rop_nr << 32; + cfg = (u32)gr->gpc_nr; + cfg |= (u32)gr->tpc_total << 8; + cfg |= (u64)gr->rop_nr << 32; return cfg; } -static const struct nvkm_enum gk104_sked_error[] = { - { 7, "CONSTANT_BUFFER_SIZE" }, - { 9, "LOCAL_MEMORY_SIZE_POS" }, - { 10, "LOCAL_MEMORY_SIZE_NEG" }, - { 11, "WARP_CSTACK_SIZE" }, - { 12, "TOTAL_TEMP_SIZE" }, - { 13, "REGISTER_COUNT" }, - { 18, "TOTAL_THREADS" }, - { 20, "PROGRAM_OFFSET" }, - { 21, "SHARED_MEMORY_SIZE" }, - { 25, "SHARED_CONFIG_TOO_SMALL" }, - { 26, "TOTAL_REGISTER_COUNT" }, +static const struct nvkm_bitfield gk104_sked_error[] = { + { 0x00000080, "CONSTANT_BUFFER_SIZE" }, + { 0x00000200, "LOCAL_MEMORY_SIZE_POS" }, + { 0x00000400, "LOCAL_MEMORY_SIZE_NEG" }, + { 0x00000800, "WARP_CSTACK_SIZE" }, + { 0x00001000, "TOTAL_TEMP_SIZE" }, + { 0x00002000, "REGISTER_COUNT" }, + { 0x00040000, "TOTAL_THREADS" }, + { 0x00100000, "PROGRAM_OFFSET" }, + { 0x00200000, "SHARED_MEMORY_SIZE" }, + { 0x02000000, "SHARED_CONFIG_TOO_SMALL" }, + { 0x04000000, "TOTAL_REGISTER_COUNT" }, {} }; -static const struct nvkm_enum gf100_gpc_rop_error[] = { - { 1, "RT_PITCH_OVERRUN" }, - { 4, "RT_WIDTH_OVERRUN" }, - { 5, "RT_HEIGHT_OVERRUN" }, - { 7, "ZETA_STORAGE_TYPE_MISMATCH" }, - { 8, "RT_STORAGE_TYPE_MISMATCH" }, - { 10, "RT_LINEAR_MISMATCH" }, +static const struct nvkm_bitfield gf100_gpc_rop_error[] = { + { 0x00000002, "RT_PITCH_OVERRUN" }, + { 0x00000010, "RT_WIDTH_OVERRUN" }, + { 0x00000020, "RT_HEIGHT_OVERRUN" }, + { 0x00000080, "ZETA_STORAGE_TYPE_MISMATCH" }, + { 0x00000100, "RT_STORAGE_TYPE_MISMATCH" }, + { 0x00000400, "RT_LINEAR_MISMATCH" }, {} }; static void -gf100_gr_trap_gpc_rop(struct gf100_gr_priv *priv, int gpc) +gf100_gr_trap_gpc_rop(struct gf100_gr *gr, int gpc) { + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + char error[128]; u32 trap[4]; - int i; - trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420)); - trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434)); - trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438)); - trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c)); + trap[0] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0420)) & 0x3fffffff; + trap[1] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0434)); + trap[2] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0438)); + trap[3] = nvkm_rd32(device, GPC_UNIT(gpc, 0x043c)); - nv_error(priv, "GPC%d/PROP trap:", gpc); - for (i = 0; i <= 29; ++i) { - if (!(trap[0] & (1 << i))) - continue; - pr_cont(" "); - nvkm_enum_print(gf100_gpc_rop_error, i); - } - pr_cont("\n"); + nvkm_snprintbf(error, sizeof(error), gf100_gpc_rop_error, trap[0]); - nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n", - trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f, - trap[3] & 0xff); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_error(subdev, "GPC%d/PROP trap: %08x [%s] x = %u, y = %u, " + "format = %x, storage type = %x\n", + gpc, trap[0], error, trap[1] & 0xffff, trap[1] >> 16, + (trap[2] >> 8) & 0x3f, trap[3] & 0xff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); } static const struct nvkm_enum gf100_mp_warp_error[] = { @@ -815,401 +893,418 @@ static const struct nvkm_bitfield gf100_mp_global_error[] = { }; static void -gf100_gr_trap_mp(struct gf100_gr_priv *priv, int gpc, int tpc) +gf100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) { - u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648)); - u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650)); - - nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc); - nvkm_bitfield_print(gf100_mp_global_error, gerr); - if (werr) { - pr_cont(" "); - nvkm_enum_print(gf100_mp_warp_error, werr & 0xffff); - } - pr_cont("\n"); - - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 werr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x648)); + u32 gerr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x650)); + const struct nvkm_enum *warp; + char glob[128]; + + nvkm_snprintbf(glob, sizeof(glob), gf100_mp_global_error, gerr); + warp = nvkm_enum_find(gf100_mp_warp_error, werr & 0xffff); + + nvkm_error(subdev, "GPC%i/TPC%i/MP trap: " + "global %08x [%s] warp %04x [%s]\n", + gpc, tpc, gerr, glob, werr, warp ? warp->name : ""); + + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x650), gerr); } static void -gf100_gr_trap_tpc(struct gf100_gr_priv *priv, int gpc, int tpc) +gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) { - u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508)); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0508)); if (stat & 0x00000001) { - u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224)); - nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); + u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0224)); + nvkm_error(subdev, "GPC%d/TPC%d/TEX: %08x\n", gpc, tpc, trap); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); stat &= ~0x00000001; } if (stat & 0x00000002) { - gf100_gr_trap_mp(priv, gpc, tpc); + gf100_gr_trap_mp(gr, gpc, tpc); stat &= ~0x00000002; } if (stat & 0x00000004) { - u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084)); - nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); + u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0084)); + nvkm_error(subdev, "GPC%d/TPC%d/POLY: %08x\n", gpc, tpc, trap); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { - u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c)); - nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); + u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x048c)); + nvkm_error(subdev, "GPC%d/TPC%d/L1C: %08x\n", gpc, tpc, trap); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); stat &= ~0x00000008; } if (stat) { - nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat); + nvkm_error(subdev, "GPC%d/TPC%d/%08x: unknown\n", gpc, tpc, stat); } } static void -gf100_gr_trap_gpc(struct gf100_gr_priv *priv, int gpc) +gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) { - u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90)); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, GPC_UNIT(gpc, 0x2c90)); int tpc; if (stat & 0x00000001) { - gf100_gr_trap_gpc_rop(priv, gpc); + gf100_gr_trap_gpc_rop(gr, gpc); stat &= ~0x00000001; } if (stat & 0x00000002) { - u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900)); - nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); + u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0900)); + nvkm_error(subdev, "GPC%d/ZCULL: %08x\n", gpc, trap); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); stat &= ~0x00000002; } if (stat & 0x00000004) { - u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028)); - nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); + u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x1028)); + nvkm_error(subdev, "GPC%d/CCACHE: %08x\n", gpc, trap); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { - u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824)); - nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); + u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0824)); + nvkm_error(subdev, "GPC%d/ESETUP: %08x\n", gpc, trap); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); stat &= ~0x00000009; } - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { u32 mask = 0x00010000 << tpc; if (stat & mask) { - gf100_gr_trap_tpc(priv, gpc, tpc); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask); + gf100_gr_trap_tpc(gr, gpc, tpc); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), mask); stat &= ~mask; } } if (stat) { - nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat); + nvkm_error(subdev, "GPC%d/%08x: unknown\n", gpc, stat); } } static void -gf100_gr_trap_intr(struct gf100_gr_priv *priv) +gf100_gr_trap_intr(struct gf100_gr *gr) { - u32 trap = nv_rd32(priv, 0x400108); - int rop, gpc, i; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 trap = nvkm_rd32(device, 0x400108); + int rop, gpc; if (trap & 0x00000001) { - u32 stat = nv_rd32(priv, 0x404000); - nv_error(priv, "DISPATCH 0x%08x\n", stat); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000001); + u32 stat = nvkm_rd32(device, 0x404000); + nvkm_error(subdev, "DISPATCH %08x\n", stat); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000001); trap &= ~0x00000001; } if (trap & 0x00000002) { - u32 stat = nv_rd32(priv, 0x404600); - nv_error(priv, "M2MF 0x%08x\n", stat); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000002); + u32 stat = nvkm_rd32(device, 0x404600); + nvkm_error(subdev, "M2MF %08x\n", stat); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000002); trap &= ~0x00000002; } if (trap & 0x00000008) { - u32 stat = nv_rd32(priv, 0x408030); - nv_error(priv, "CCACHE 0x%08x\n", stat); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000008); + u32 stat = nvkm_rd32(device, 0x408030); + nvkm_error(subdev, "CCACHE %08x\n", stat); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000008); trap &= ~0x00000008; } if (trap & 0x00000010) { - u32 stat = nv_rd32(priv, 0x405840); - nv_error(priv, "SHADER 0x%08x\n", stat); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000010); + u32 stat = nvkm_rd32(device, 0x405840); + nvkm_error(subdev, "SHADER %08x\n", stat); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000010); trap &= ~0x00000010; } if (trap & 0x00000040) { - u32 stat = nv_rd32(priv, 0x40601c); - nv_error(priv, "UNK6 0x%08x\n", stat); - nv_wr32(priv, 0x40601c, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000040); + u32 stat = nvkm_rd32(device, 0x40601c); + nvkm_error(subdev, "UNK6 %08x\n", stat); + nvkm_wr32(device, 0x40601c, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000040); trap &= ~0x00000040; } if (trap & 0x00000080) { - u32 stat = nv_rd32(priv, 0x404490); - nv_error(priv, "MACRO 0x%08x\n", stat); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000080); + u32 stat = nvkm_rd32(device, 0x404490); + nvkm_error(subdev, "MACRO %08x\n", stat); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000080); trap &= ~0x00000080; } if (trap & 0x00000100) { - u32 stat = nv_rd32(priv, 0x407020); + u32 stat = nvkm_rd32(device, 0x407020) & 0x3fffffff; + char sked[128]; - nv_error(priv, "SKED:"); - for (i = 0; i <= 29; ++i) { - if (!(stat & (1 << i))) - continue; - pr_cont(" "); - nvkm_enum_print(gk104_sked_error, i); - } - pr_cont("\n"); + nvkm_snprintbf(sked, sizeof(sked), gk104_sked_error, stat); + nvkm_error(subdev, "SKED: %08x [%s]\n", stat, sked); - if (stat & 0x3fffffff) - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x400108, 0x00000100); + if (stat) + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x400108, 0x00000100); trap &= ~0x00000100; } if (trap & 0x01000000) { - u32 stat = nv_rd32(priv, 0x400118); - for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) { + u32 stat = nvkm_rd32(device, 0x400118); + for (gpc = 0; stat && gpc < gr->gpc_nr; gpc++) { u32 mask = 0x00000001 << gpc; if (stat & mask) { - gf100_gr_trap_gpc(priv, gpc); - nv_wr32(priv, 0x400118, mask); + gf100_gr_trap_gpc(gr, gpc); + nvkm_wr32(device, 0x400118, mask); stat &= ~mask; } } - nv_wr32(priv, 0x400108, 0x01000000); + nvkm_wr32(device, 0x400108, 0x01000000); trap &= ~0x01000000; } if (trap & 0x02000000) { - for (rop = 0; rop < priv->rop_nr; rop++) { - u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070)); - u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144)); - nv_error(priv, "ROP%d 0x%08x 0x%08x\n", + for (rop = 0; rop < gr->rop_nr; rop++) { + u32 statz = nvkm_rd32(device, ROP_UNIT(rop, 0x070)); + u32 statc = nvkm_rd32(device, ROP_UNIT(rop, 0x144)); + nvkm_error(subdev, "ROP%d %08x %08x\n", rop, statz, statc); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); } - nv_wr32(priv, 0x400108, 0x02000000); + nvkm_wr32(device, 0x400108, 0x02000000); trap &= ~0x02000000; } if (trap) { - nv_error(priv, "TRAP UNHANDLED 0x%08x\n", trap); - nv_wr32(priv, 0x400108, trap); + nvkm_error(subdev, "TRAP UNHANDLED %08x\n", trap); + nvkm_wr32(device, 0x400108, trap); } } static void -gf100_gr_ctxctl_debug_unit(struct gf100_gr_priv *priv, u32 base) +gf100_gr_ctxctl_debug_unit(struct gf100_gr *gr, u32 base) { - nv_error(priv, "%06x - done 0x%08x\n", base, - nv_rd32(priv, base + 0x400)); - nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804), - nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c)); - nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814), - nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c)); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + nvkm_error(subdev, "%06x - done %08x\n", base, + nvkm_rd32(device, base + 0x400)); + nvkm_error(subdev, "%06x - stat %08x %08x %08x %08x\n", base, + nvkm_rd32(device, base + 0x800), + nvkm_rd32(device, base + 0x804), + nvkm_rd32(device, base + 0x808), + nvkm_rd32(device, base + 0x80c)); + nvkm_error(subdev, "%06x - stat %08x %08x %08x %08x\n", base, + nvkm_rd32(device, base + 0x810), + nvkm_rd32(device, base + 0x814), + nvkm_rd32(device, base + 0x818), + nvkm_rd32(device, base + 0x81c)); } void -gf100_gr_ctxctl_debug(struct gf100_gr_priv *priv) +gf100_gr_ctxctl_debug(struct gf100_gr *gr) { - u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff; + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 gpcnr = nvkm_rd32(device, 0x409604) & 0xffff; u32 gpc; - gf100_gr_ctxctl_debug_unit(priv, 0x409000); + gf100_gr_ctxctl_debug_unit(gr, 0x409000); for (gpc = 0; gpc < gpcnr; gpc++) - gf100_gr_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000)); + gf100_gr_ctxctl_debug_unit(gr, 0x502000 + (gpc * 0x8000)); } static void -gf100_gr_ctxctl_isr(struct gf100_gr_priv *priv) +gf100_gr_ctxctl_isr(struct gf100_gr *gr) { - u32 stat = nv_rd32(priv, 0x409c18); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x409c18); if (stat & 0x00000001) { - u32 code = nv_rd32(priv, 0x409814); + u32 code = nvkm_rd32(device, 0x409814); if (code == E_BAD_FWMTHD) { - u32 class = nv_rd32(priv, 0x409808); - u32 addr = nv_rd32(priv, 0x40980c); + u32 class = nvkm_rd32(device, 0x409808); + u32 addr = nvkm_rd32(device, 0x40980c); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); - u32 data = nv_rd32(priv, 0x409810); + u32 data = nvkm_rd32(device, 0x409810); - nv_error(priv, "FECS MTHD subc %d class 0x%04x " - "mthd 0x%04x data 0x%08x\n", - subc, class, mthd, data); + nvkm_error(subdev, "FECS MTHD subc %d class %04x " + "mthd %04x data %08x\n", + subc, class, mthd, data); - nv_wr32(priv, 0x409c20, 0x00000001); + nvkm_wr32(device, 0x409c20, 0x00000001); stat &= ~0x00000001; } else { - nv_error(priv, "FECS ucode error %d\n", code); + nvkm_error(subdev, "FECS ucode error %d\n", code); } } if (stat & 0x00080000) { - nv_error(priv, "FECS watchdog timeout\n"); - gf100_gr_ctxctl_debug(priv); - nv_wr32(priv, 0x409c20, 0x00080000); + nvkm_error(subdev, "FECS watchdog timeout\n"); + gf100_gr_ctxctl_debug(gr); + nvkm_wr32(device, 0x409c20, 0x00080000); stat &= ~0x00080000; } if (stat) { - nv_error(priv, "FECS 0x%08x\n", stat); - gf100_gr_ctxctl_debug(priv); - nv_wr32(priv, 0x409c20, stat); + nvkm_error(subdev, "FECS %08x\n", stat); + gf100_gr_ctxctl_debug(gr); + nvkm_wr32(device, 0x409c20, stat); } } static void -gf100_gr_intr(struct nvkm_subdev *subdev) +gf100_gr_intr(struct nvkm_gr *base) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle; - struct gf100_gr_priv *priv = (void *)subdev; - u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff; - u32 stat = nv_rd32(priv, 0x400100); - u32 addr = nv_rd32(priv, 0x400704); + struct gf100_gr *gr = gf100_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_fifo_chan *chan; + unsigned long flags; + u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff; + u32 stat = nvkm_rd32(device, 0x400100); + u32 addr = nvkm_rd32(device, 0x400704); u32 mthd = (addr & 0x00003ffc); u32 subc = (addr & 0x00070000) >> 16; - u32 data = nv_rd32(priv, 0x400708); - u32 code = nv_rd32(priv, 0x400110); + u32 data = nvkm_rd32(device, 0x400708); + u32 code = nvkm_rd32(device, 0x400110); u32 class; - int chid; + const char *name = "unknown"; + int chid = -1; - if (nv_device(priv)->card_type < NV_E0 || subc < 4) - class = nv_rd32(priv, 0x404200 + (subc * 4)); + chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + if (chan) { + name = chan->object.client->name; + chid = chan->chid; + } + + if (device->card_type < NV_E0 || subc < 4) + class = nvkm_rd32(device, 0x404200 + (subc * 4)); else class = 0x0000; - engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); - if (stat & 0x00000001) { /* * notifier interrupt, only needed for cyclestats * can be safely ignored */ - nv_wr32(priv, 0x400100, 0x00000001); + nvkm_wr32(device, 0x400100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000010) { - handle = nvkm_handle_get_class(engctx, class); - if (!handle || nv_call(handle->object, mthd, data)) { - nv_error(priv, - "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), - subc, class, mthd, data); + if (!gf100_gr_mthd_sw(device, class, mthd, data)) { + nvkm_error(subdev, "ILLEGAL_MTHD ch %d [%010llx %s] " + "subc %d class %04x mthd %04x data %08x\n", + chid, inst << 12, name, subc, + class, mthd, data); } - nvkm_handle_put(handle); - nv_wr32(priv, 0x400100, 0x00000010); + nvkm_wr32(device, 0x400100, 0x00000010); stat &= ~0x00000010; } if (stat & 0x00000020) { - nv_error(priv, - "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), subc, - class, mthd, data); - nv_wr32(priv, 0x400100, 0x00000020); + nvkm_error(subdev, "ILLEGAL_CLASS ch %d [%010llx %s] " + "subc %d class %04x mthd %04x data %08x\n", + chid, inst << 12, name, subc, class, mthd, data); + nvkm_wr32(device, 0x400100, 0x00000020); stat &= ~0x00000020; } if (stat & 0x00100000) { - nv_error(priv, "DATA_ERROR ["); - nvkm_enum_print(nv50_data_error_names, code); - pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), subc, - class, mthd, data); - nv_wr32(priv, 0x400100, 0x00100000); + const struct nvkm_enum *en = + nvkm_enum_find(nv50_data_error_names, code); + nvkm_error(subdev, "DATA_ERROR %08x [%s] ch %d [%010llx %s] " + "subc %d class %04x mthd %04x data %08x\n", + code, en ? en->name : "", chid, inst << 12, + name, subc, class, mthd, data); + nvkm_wr32(device, 0x400100, 0x00100000); stat &= ~0x00100000; } if (stat & 0x00200000) { - nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12, - nvkm_client_name(engctx)); - gf100_gr_trap_intr(priv); - nv_wr32(priv, 0x400100, 0x00200000); + nvkm_error(subdev, "TRAP ch %d [%010llx %s]\n", + chid, inst << 12, name); + gf100_gr_trap_intr(gr); + nvkm_wr32(device, 0x400100, 0x00200000); stat &= ~0x00200000; } if (stat & 0x00080000) { - gf100_gr_ctxctl_isr(priv); - nv_wr32(priv, 0x400100, 0x00080000); + gf100_gr_ctxctl_isr(gr); + nvkm_wr32(device, 0x400100, 0x00080000); stat &= ~0x00080000; } if (stat) { - nv_error(priv, "unknown stat 0x%08x\n", stat); - nv_wr32(priv, 0x400100, stat); + nvkm_error(subdev, "intr %08x\n", stat); + nvkm_wr32(device, 0x400100, stat); } - nv_wr32(priv, 0x400500, 0x00010001); - nvkm_engctx_put(engctx); + nvkm_wr32(device, 0x400500, 0x00010001); + nvkm_fifo_chan_put(device->fifo, flags, &chan); } void -gf100_gr_init_fw(struct gf100_gr_priv *priv, u32 fuc_base, +gf100_gr_init_fw(struct gf100_gr *gr, u32 fuc_base, struct gf100_gr_fuc *code, struct gf100_gr_fuc *data) { + struct nvkm_device *device = gr->base.engine.subdev.device; int i; - nv_wr32(priv, fuc_base + 0x01c0, 0x01000000); + nvkm_wr32(device, fuc_base + 0x01c0, 0x01000000); for (i = 0; i < data->size / 4; i++) - nv_wr32(priv, fuc_base + 0x01c4, data->data[i]); + nvkm_wr32(device, fuc_base + 0x01c4, data->data[i]); - nv_wr32(priv, fuc_base + 0x0180, 0x01000000); + nvkm_wr32(device, fuc_base + 0x0180, 0x01000000); for (i = 0; i < code->size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(priv, fuc_base + 0x0188, i >> 6); - nv_wr32(priv, fuc_base + 0x0184, code->data[i]); + nvkm_wr32(device, fuc_base + 0x0188, i >> 6); + nvkm_wr32(device, fuc_base + 0x0184, code->data[i]); } /* code must be padded to 0x40 words */ for (; i & 0x3f; i++) - nv_wr32(priv, fuc_base + 0x0184, 0); + nvkm_wr32(device, fuc_base + 0x0184, 0); } static void -gf100_gr_init_csdata(struct gf100_gr_priv *priv, +gf100_gr_init_csdata(struct gf100_gr *gr, const struct gf100_gr_pack *pack, u32 falcon, u32 starstar, u32 base) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *iter; const struct gf100_gr_init *init; u32 addr = ~0, prev = ~0, xfer = 0; u32 star, temp; - nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar); - star = nv_rd32(priv, falcon + 0x01c4); - temp = nv_rd32(priv, falcon + 0x01c4); + nvkm_wr32(device, falcon + 0x01c0, 0x02000000 + starstar); + star = nvkm_rd32(device, falcon + 0x01c4); + temp = nvkm_rd32(device, falcon + 0x01c4); if (temp > star) star = temp; - nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star); + nvkm_wr32(device, falcon + 0x01c0, 0x01000000 + star); pack_for_each_init(init, iter, pack) { u32 head = init->addr - base; @@ -1218,7 +1313,7 @@ gf100_gr_init_csdata(struct gf100_gr_priv *priv, if (head != prev + 4 || xfer >= 32) { if (xfer) { u32 data = ((--xfer << 26) | addr); - nv_wr32(priv, falcon + 0x01c4, data); + nvkm_wr32(device, falcon + 0x01c4, data); star += 4; } addr = head; @@ -1230,157 +1325,166 @@ gf100_gr_init_csdata(struct gf100_gr_priv *priv, } } - nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr); - nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar); - nv_wr32(priv, falcon + 0x01c4, star + 4); + nvkm_wr32(device, falcon + 0x01c4, (--xfer << 26) | addr); + nvkm_wr32(device, falcon + 0x01c0, 0x01000004 + starstar); + nvkm_wr32(device, falcon + 0x01c4, star + 4); } int -gf100_gr_init_ctxctl(struct gf100_gr_priv *priv) +gf100_gr_init_ctxctl(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)nv_object(priv)->oclass; - struct gf100_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; int i; - if (priv->firmware) { + if (gr->firmware) { /* load fuc microcode */ - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); - gf100_gr_init_fw(priv, 0x409000, &priv->fuc409c, - &priv->fuc409d); - gf100_gr_init_fw(priv, 0x41a000, &priv->fuc41ac, - &priv->fuc41ad); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + nvkm_mc_unk260(device->mc, 0); + gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, &gr->fuc409d); + gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, &gr->fuc41ad); + nvkm_mc_unk260(device->mc, 1); /* start both of them running */ - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x41a10c, 0x00000000); - nv_wr32(priv, 0x40910c, 0x00000000); - nv_wr32(priv, 0x41a100, 0x00000002); - nv_wr32(priv, 0x409100, 0x00000002); - if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001)) - nv_warn(priv, "0x409800 wait failed\n"); - - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x7fffffff); - nv_wr32(priv, 0x409504, 0x00000021); - - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x00000000); - nv_wr32(priv, 0x409504, 0x00000010); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x10 timeout\n"); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x41a10c, 0x00000000); + nvkm_wr32(device, 0x40910c, 0x00000000); + nvkm_wr32(device, 0x41a100, 0x00000002); + nvkm_wr32(device, 0x409100, 0x00000002); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x00000001) + break; + ) < 0) return -EBUSY; - } - priv->size = nv_rd32(priv, 0x409800); - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x00000000); - nv_wr32(priv, 0x409504, 0x00000016); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x16 timeout\n"); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x7fffffff); + nvkm_wr32(device, 0x409504, 0x00000021); + + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x00000000); + nvkm_wr32(device, 0x409504, 0x00000010); + if (nvkm_msec(device, 2000, + if ((gr->size = nvkm_rd32(device, 0x409800))) + break; + ) < 0) return -EBUSY; - } - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x00000000); - nv_wr32(priv, 0x409504, 0x00000025); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x25 timeout\n"); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x00000000); + nvkm_wr32(device, 0x409504, 0x00000016); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) + return -EBUSY; + + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x00000000); + nvkm_wr32(device, 0x409504, 0x00000025); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } - if (nv_device(priv)->chipset >= 0xe0) { - nv_wr32(priv, 0x409800, 0x00000000); - nv_wr32(priv, 0x409500, 0x00000001); - nv_wr32(priv, 0x409504, 0x00000030); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x30 timeout\n"); + if (device->chipset >= 0xe0) { + nvkm_wr32(device, 0x409800, 0x00000000); + nvkm_wr32(device, 0x409500, 0x00000001); + nvkm_wr32(device, 0x409504, 0x00000030); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } - nv_wr32(priv, 0x409810, 0xb00095c8); - nv_wr32(priv, 0x409800, 0x00000000); - nv_wr32(priv, 0x409500, 0x00000001); - nv_wr32(priv, 0x409504, 0x00000031); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x31 timeout\n"); + nvkm_wr32(device, 0x409810, 0xb00095c8); + nvkm_wr32(device, 0x409800, 0x00000000); + nvkm_wr32(device, 0x409500, 0x00000001); + nvkm_wr32(device, 0x409504, 0x00000031); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } - nv_wr32(priv, 0x409810, 0x00080420); - nv_wr32(priv, 0x409800, 0x00000000); - nv_wr32(priv, 0x409500, 0x00000001); - nv_wr32(priv, 0x409504, 0x00000032); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x32 timeout\n"); + nvkm_wr32(device, 0x409810, 0x00080420); + nvkm_wr32(device, 0x409800, 0x00000000); + nvkm_wr32(device, 0x409500, 0x00000001); + nvkm_wr32(device, 0x409504, 0x00000032); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } - nv_wr32(priv, 0x409614, 0x00000070); - nv_wr32(priv, 0x409614, 0x00000770); - nv_wr32(priv, 0x40802c, 0x00000001); + nvkm_wr32(device, 0x409614, 0x00000070); + nvkm_wr32(device, 0x409614, 0x00000770); + nvkm_wr32(device, 0x40802c, 0x00000001); } - if (priv->data == NULL) { - int ret = gf100_grctx_generate(priv); + if (gr->data == NULL) { + int ret = gf100_grctx_generate(gr); if (ret) { - nv_error(priv, "failed to construct context\n"); + nvkm_error(subdev, "failed to construct context\n"); return ret; } } return 0; } else - if (!oclass->fecs.ucode) { + if (!gr->func->fecs.ucode) { return -ENOSYS; } /* load HUB microcode */ - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); - nv_wr32(priv, 0x4091c0, 0x01000000); - for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++) - nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]); + nvkm_mc_unk260(device->mc, 0); + nvkm_wr32(device, 0x4091c0, 0x01000000); + for (i = 0; i < gr->func->fecs.ucode->data.size / 4; i++) + nvkm_wr32(device, 0x4091c4, gr->func->fecs.ucode->data.data[i]); - nv_wr32(priv, 0x409180, 0x01000000); - for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) { + nvkm_wr32(device, 0x409180, 0x01000000); + for (i = 0; i < gr->func->fecs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(priv, 0x409188, i >> 6); - nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]); + nvkm_wr32(device, 0x409188, i >> 6); + nvkm_wr32(device, 0x409184, gr->func->fecs.ucode->code.data[i]); } /* load GPC microcode */ - nv_wr32(priv, 0x41a1c0, 0x01000000); - for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++) - nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]); + nvkm_wr32(device, 0x41a1c0, 0x01000000); + for (i = 0; i < gr->func->gpccs.ucode->data.size / 4; i++) + nvkm_wr32(device, 0x41a1c4, gr->func->gpccs.ucode->data.data[i]); - nv_wr32(priv, 0x41a180, 0x01000000); - for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) { + nvkm_wr32(device, 0x41a180, 0x01000000); + for (i = 0; i < gr->func->gpccs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(priv, 0x41a188, i >> 6); - nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]); + nvkm_wr32(device, 0x41a188, i >> 6); + nvkm_wr32(device, 0x41a184, gr->func->gpccs.ucode->code.data[i]); } - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + nvkm_mc_unk260(device->mc, 1); /* load register lists */ - gf100_gr_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000); - gf100_gr_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000); - gf100_gr_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800); - gf100_gr_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00); + gf100_gr_init_csdata(gr, grctx->hub, 0x409000, 0x000, 0x000000); + gf100_gr_init_csdata(gr, grctx->gpc, 0x41a000, 0x000, 0x418000); + gf100_gr_init_csdata(gr, grctx->tpc, 0x41a000, 0x004, 0x419800); + gf100_gr_init_csdata(gr, grctx->ppc, 0x41a000, 0x008, 0x41be00); /* start HUB ucode running, it'll init the GPCs */ - nv_wr32(priv, 0x40910c, 0x00000000); - nv_wr32(priv, 0x409100, 0x00000002); - if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) { - nv_error(priv, "HUB_INIT timed out\n"); - gf100_gr_ctxctl_debug(priv); + nvkm_wr32(device, 0x40910c, 0x00000000); + nvkm_wr32(device, 0x409100, 0x00000002); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x80000000) + break; + ) < 0) { + gf100_gr_ctxctl_debug(gr); return -EBUSY; } - priv->size = nv_rd32(priv, 0x409804); - if (priv->data == NULL) { - int ret = gf100_grctx_generate(priv); + gr->size = nvkm_rd32(device, 0x409804); + if (gr->data == NULL) { + int ret = gf100_grctx_generate(gr); if (ret) { - nv_error(priv, "failed to construct context\n"); + nvkm_error(subdev, "failed to construct context\n"); return ret; } } @@ -1388,143 +1492,160 @@ gf100_gr_init_ctxctl(struct gf100_gr_priv *priv) return 0; } -int -gf100_gr_init(struct nvkm_object *object) +static int +gf100_gr_oneinit(struct nvkm_gr *base) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); - u32 data[TPC_MAX / 8] = {}; - u8 tpcnr[GPC_MAX]; - int gpc, tpc, rop; - int ret, i; + struct gf100_gr *gr = gf100_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + int ret, i, j; + + nvkm_pmu_pgob(device->pmu, false); - ret = nvkm_gr_init(&priv->base); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, + &gr->unk4188b4); if (ret) return ret; - nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); - - gf100_gr_mmio(priv, oclass->mmio); - - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { - do { - gpc = (gpc + 1) % priv->gpc_nr; - } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; - - data[i / 8] |= tpc << ((i % 8) * 4); - } - - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); - } + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, + &gr->unk4188b8); + if (ret) + return ret; - if (nv_device(priv)->chipset != 0xd7) - nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918); - else - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - - nv_wr32(priv, 0x400500, 0x00010001); - - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - - nv_wr32(priv, 0x409c24, 0x000f0000); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x40601c, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); + nvkm_kmap(gr->unk4188b4); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(gr->unk4188b4, i, 0x00000010); + nvkm_done(gr->unk4188b4); + + nvkm_kmap(gr->unk4188b8); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(gr->unk4188b8, i, 0x00000010); + nvkm_done(gr->unk4188b8); + + gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16; + gr->gpc_nr = nvkm_rd32(device, 0x409604) & 0x0000001f; + for (i = 0; i < gr->gpc_nr; i++) { + gr->tpc_nr[i] = nvkm_rd32(device, GPC_UNIT(i, 0x2608)); + gr->tpc_total += gr->tpc_nr[i]; + gr->ppc_nr[i] = gr->func->ppc_nr; + for (j = 0; j < gr->ppc_nr[i]; j++) { + u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4))); + gr->ppc_tpc_nr[i][j] = hweight8(mask); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + /*XXX: these need figuring out... though it might not even matter */ + switch (device->chipset) { + case 0xc0: + if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ + gr->magic_not_rop_nr = 0x07; + } else + if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ + gr->magic_not_rop_nr = 0x05; + } else + if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ + gr->magic_not_rop_nr = 0x06; + } + break; + case 0xc3: /* 450, 4/0/0/0, 2 */ + gr->magic_not_rop_nr = 0x03; + break; + case 0xc4: /* 460, 3/4/0/0, 4 */ + gr->magic_not_rop_nr = 0x01; + break; + case 0xc1: /* 2/0/0/0, 1 */ + gr->magic_not_rop_nr = 0x01; + break; + case 0xc8: /* 4/4/3/4, 5 */ + gr->magic_not_rop_nr = 0x06; + break; + case 0xce: /* 4/4/0/0, 4 */ + gr->magic_not_rop_nr = 0x03; + break; + case 0xcf: /* 4/0/0/0, 3 */ + gr->magic_not_rop_nr = 0x03; + break; + case 0xd7: + case 0xd9: /* 1/0/0/0, 1 */ + case 0xea: /* gk20a */ + case 0x12b: /* gm20b */ + gr->magic_not_rop_nr = 0x01; + break; } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); - - nv_wr32(priv, 0x400054, 0x34ce3464); - - gf100_gr_zbc_init(priv); + return 0; +} - return gf100_gr_init_ctxctl(priv); +int +gf100_gr_init_(struct nvkm_gr *base) +{ + struct gf100_gr *gr = gf100_gr(base); + nvkm_pmu_pgob(gr->base.engine.subdev.device->pmu, false); + return gr->func->init(gr); } -static void +void gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc) { kfree(fuc->data); fuc->data = NULL; } +void * +gf100_gr_dtor(struct nvkm_gr *base) +{ + struct gf100_gr *gr = gf100_gr(base); + + if (gr->func->dtor) + gr->func->dtor(gr); + kfree(gr->data); + + gf100_gr_dtor_fw(&gr->fuc409c); + gf100_gr_dtor_fw(&gr->fuc409d); + gf100_gr_dtor_fw(&gr->fuc41ac); + gf100_gr_dtor_fw(&gr->fuc41ad); + + nvkm_memory_del(&gr->unk4188b8); + nvkm_memory_del(&gr->unk4188b4); + return gr; +} + +static const struct nvkm_gr_func +gf100_gr_ = { + .dtor = gf100_gr_dtor, + .oneinit = gf100_gr_oneinit, + .init = gf100_gr_init_, + .intr = gf100_gr_intr, + .units = gf100_gr_units, + .chan_new = gf100_gr_chan_new, + .object_get = gf100_gr_object_get, +}; + int -gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname, +gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, struct gf100_gr_fuc *fuc) { - struct nvkm_device *device = nv_device(priv); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; const struct firmware *fw; - char f[32]; + char f[64]; + char cname[16]; int ret; + int i; - snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname); - ret = request_firmware(&fw, f, nv_device_base(device)); + /* Convert device name to lowercase */ + strncpy(cname, device->chip->name, sizeof(cname)); + cname[sizeof(cname) - 1] = '\0'; + i = strlen(cname); + while (i) { + --i; + cname[i] = tolower(cname[i]); + } + + snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); + ret = request_firmware(&fw, f, device->dev); if (ret) { - snprintf(f, sizeof(f), "nouveau/%s", fwname); - ret = request_firmware(&fw, f, nv_device_base(device)); - if (ret) { - nv_error(priv, "failed to load %s\n", fwname); - return ret; - } + nvkm_error(subdev, "failed to load %s\n", fwname); + return ret; } fuc->size = fw->size; @@ -1533,126 +1654,150 @@ gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname, return (fuc->data != NULL) ? 0 : -ENOMEM; } -void -gf100_gr_dtor(struct nvkm_object *object) +int +gf100_gr_ctor(const struct gf100_gr_func *func, struct nvkm_device *device, + int index, struct gf100_gr *gr) { - struct gf100_gr_priv *priv = (void *)object; + int ret; - kfree(priv->data); + gr->func = func; + gr->firmware = nvkm_boolopt(device->cfgopt, "NvGrUseFW", + func->fecs.ucode == NULL); - gf100_gr_dtor_fw(&priv->fuc409c); - gf100_gr_dtor_fw(&priv->fuc409d); - gf100_gr_dtor_fw(&priv->fuc41ac); - gf100_gr_dtor_fw(&priv->fuc41ad); + ret = nvkm_gr_ctor(&gf100_gr_, device, index, 0x08001000, + gr->firmware || func->fecs.ucode != NULL, + &gr->base); + if (ret) + return ret; - nvkm_gpuobj_ref(NULL, &priv->unk4188b8); - nvkm_gpuobj_ref(NULL, &priv->unk4188b4); + if (gr->firmware) { + nvkm_info(&gr->base.engine.subdev, "using external firmware\n"); + if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) || + gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) || + gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) || + gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad)) + return -ENODEV; + } - nvkm_gr_destroy(&priv->base); + return 0; } int -gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *bclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) { - struct gf100_gr_oclass *oclass = (void *)bclass; - struct nvkm_device *device = nv_device(parent); - struct gf100_gr_priv *priv; - bool use_ext_fw, enable; - int ret, i, j; + struct gf100_gr *gr; + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + return gf100_gr_ctor(func, device, index, gr); +} - use_ext_fw = nvkm_boolopt(device->cfgopt, "NvGrUseFW", - oclass->fecs.ucode == NULL); - enable = use_ext_fw || oclass->fecs.ucode != NULL; +int +gf100_gr_init(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); + u32 data[TPC_MAX / 8] = {}; + u8 tpcnr[GPC_MAX]; + int gpc, tpc, rop; + int i; - ret = nvkm_gr_create(parent, engine, bclass, enable, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0888), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x088c), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); - nv_subdev(priv)->unit = 0x08001000; - nv_subdev(priv)->intr = gf100_gr_intr; + gf100_gr_mmio(gr, gr->func->mmio); - priv->base.units = gf100_gr_units; + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { + do { + gpc = (gpc + 1) % gr->gpc_nr; + } while (!tpcnr[gpc]); + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; - if (use_ext_fw) { - nv_info(priv, "using external firmware\n"); - if (gf100_gr_ctor_fw(priv, "fuc409c", &priv->fuc409c) || - gf100_gr_ctor_fw(priv, "fuc409d", &priv->fuc409d) || - gf100_gr_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) || - gf100_gr_ctor_fw(priv, "fuc41ad", &priv->fuc41ad)) - return -ENODEV; - priv->firmware = true; + data[i / 8] |= tpc << ((i % 8) * 4); } - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0, - &priv->unk4188b4); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0, - &priv->unk4188b8); - if (ret) - return ret; + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); - for (i = 0; i < 0x1000; i += 4) { - nv_wo32(priv->unk4188b4, i, 0x00000010); - nv_wo32(priv->unk4188b8, i, 0x00000010); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16; - priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f; - for (i = 0; i < priv->gpc_nr; i++) { - priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608)); - priv->tpc_total += priv->tpc_nr[i]; - priv->ppc_nr[i] = oclass->ppc_nr; - for (j = 0; j < priv->ppc_nr[i]; j++) { - u8 mask = nv_rd32(priv, GPC_UNIT(i, 0x0c30 + (j * 4))); - priv->ppc_tpc_nr[i][j] = hweight8(mask); + if (device->chipset != 0xd7) + nvkm_wr32(device, GPC_BCAST(0x1bd4), magicgpc918); + else + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); + + nvkm_wr32(device, 0x400500, 0x00010001); + + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + + nvkm_wr32(device, 0x409c24, 0x000f0000); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x40601c, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); + nvkm_mask(device, 0x419eb4, 0x00001000, 0x00001000); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - /*XXX: these need figuring out... though it might not even matter */ - switch (nv_device(priv)->chipset) { - case 0xc0: - if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ - priv->magic_not_rop_nr = 0x07; - } else - if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ - priv->magic_not_rop_nr = 0x05; - } else - if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ - priv->magic_not_rop_nr = 0x06; - } - break; - case 0xc3: /* 450, 4/0/0/0, 2 */ - priv->magic_not_rop_nr = 0x03; - break; - case 0xc4: /* 460, 3/4/0/0, 4 */ - priv->magic_not_rop_nr = 0x01; - break; - case 0xc1: /* 2/0/0/0, 1 */ - priv->magic_not_rop_nr = 0x01; - break; - case 0xc8: /* 4/4/3/4, 5 */ - priv->magic_not_rop_nr = 0x06; - break; - case 0xce: /* 4/4/0/0, 4 */ - priv->magic_not_rop_nr = 0x03; - break; - case 0xcf: /* 4/0/0/0, 3 */ - priv->magic_not_rop_nr = 0x03; - break; - case 0xd7: - case 0xd9: /* 1/0/0/0, 1 */ - priv->magic_not_rop_nr = 0x01; - break; + for (rop = 0; rop < gr->rop_nr; rop++) { + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_engine(priv)->cclass = *oclass->cclass; - nv_engine(priv)->sclass = oclass->sclass; - return 0; + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); + + nvkm_wr32(device, 0x400054, 0x34ce3464); + + gf100_gr_zbc_init(gr); + + return gf100_gr_init_ctxctl(gr); } #include "fuc/hubgf100.fuc3.h" @@ -1675,18 +1820,24 @@ gf100_gr_gpccs_ucode = { .data.size = sizeof(gf100_grgpc_data), }; -struct nvkm_oclass * -gf100_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gf100_grctx_oclass, - .sclass = gf100_gr_sclass, +static const struct gf100_gr_func +gf100_gr = { + .init = gf100_gr_init, .mmio = gf100_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; + .grctx = &gf100_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + +int +gf100_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf100_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 8af1a89eda84..4611961b1187 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -21,11 +21,14 @@ * * Authors: Ben Skeggs */ -#ifndef __NVC0_GR_H__ -#define __NVC0_GR_H__ -#include <engine/gr.h> +#ifndef __GF100_GR_H__ +#define __GF100_GR_H__ +#define gf100_gr(p) container_of((p), struct gf100_gr, base) +#include "priv.h" +#include <core/gpuobj.h> #include <subdev/ltc.h> +#include <subdev/mmu.h> #define GPC_MAX 32 #define TPC_MAX (GPC_MAX * 8) @@ -67,7 +70,8 @@ struct gf100_gr_zbc_depth { u32 l2; }; -struct gf100_gr_priv { +struct gf100_gr { + const struct gf100_gr_func *func; struct nvkm_gr base; struct gf100_gr_fuc fuc409c; @@ -76,6 +80,15 @@ struct gf100_gr_priv { struct gf100_gr_fuc fuc41ad; bool firmware; + /* + * Used if the register packs are loaded from NVIDIA fw instead of + * using hardcoded arrays. + */ + struct gf100_gr_pack *fuc_sw_nonctx; + struct gf100_gr_pack *fuc_sw_ctx; + struct gf100_gr_pack *fuc_bundle; + struct gf100_gr_pack *fuc_method; + struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_CNT]; struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_CNT]; @@ -86,8 +99,8 @@ struct gf100_gr_priv { u8 ppc_nr[GPC_MAX]; u8 ppc_tpc_nr[GPC_MAX][4]; - struct nvkm_gpuobj *unk4188b4; - struct nvkm_gpuobj *unk4188b8; + struct nvkm_memory *unk4188b4; + struct nvkm_memory *unk4188b8; struct gf100_gr_data mmio_data[4]; struct gf100_gr_mmio mmio_list[4096/8]; @@ -97,48 +110,65 @@ struct gf100_gr_priv { u8 magic_not_rop_nr; }; +int gf100_gr_ctor(const struct gf100_gr_func *, struct nvkm_device *, + int, struct gf100_gr *); +int gf100_gr_new_(const struct gf100_gr_func *, struct nvkm_device *, + int, struct nvkm_gr **); +void *gf100_gr_dtor(struct nvkm_gr *); + +struct gf100_gr_func { + void (*dtor)(struct gf100_gr *); + int (*init)(struct gf100_gr *); + void (*init_gpc_mmu)(struct gf100_gr *); + void (*set_hww_esr_report_mask)(struct gf100_gr *); + const struct gf100_gr_pack *mmio; + struct { + struct gf100_gr_ucode *ucode; + } fecs; + struct { + struct gf100_gr_ucode *ucode; + } gpccs; + int ppc_nr; + const struct gf100_grctx_func *grctx; + struct nvkm_sclass sclass[]; +}; + +int gf100_gr_init(struct gf100_gr *); + +int gk104_gr_init(struct gf100_gr *); + +int gk20a_gr_new_(const struct gf100_gr_func *, struct nvkm_device *, + int, struct nvkm_gr **); +void gk20a_gr_dtor(struct gf100_gr *); +int gk20a_gr_init(struct gf100_gr *); + +int gm204_gr_init(struct gf100_gr *); + +#define gf100_gr_chan(p) container_of((p), struct gf100_gr_chan, object) + struct gf100_gr_chan { - struct nvkm_gr_chan base; + struct nvkm_object object; + struct gf100_gr *gr; - struct nvkm_gpuobj *mmio; + struct nvkm_memory *mmio; struct nvkm_vma mmio_vma; int mmio_nr; + struct { - struct nvkm_gpuobj *mem; + struct nvkm_memory *mem; struct nvkm_vma vma; } data[4]; }; -int gf100_gr_context_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_gr_context_dtor(struct nvkm_object *); - -void gf100_gr_ctxctl_debug(struct gf100_gr_priv *); +void gf100_gr_ctxctl_debug(struct gf100_gr *); +void gf100_gr_dtor_fw(struct gf100_gr_fuc *); +int gf100_gr_ctor_fw(struct gf100_gr *, const char *, + struct gf100_gr_fuc *); u64 gf100_gr_units(struct nvkm_gr *); -int gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **); -void gf100_gr_dtor(struct nvkm_object *); -int gf100_gr_init(struct nvkm_object *); -void gf100_gr_zbc_init(struct gf100_gr_priv *); - -int gk104_gr_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **); -int gk104_gr_init(struct nvkm_object *); - -int gm204_gr_init(struct nvkm_object *); +void gf100_gr_zbc_init(struct gf100_gr *); -extern struct nvkm_ofuncs gf100_fermi_ofuncs; - -extern struct nvkm_oclass gf100_gr_sclass[]; -extern struct nvkm_omthds gf100_gr_9097_omthds[]; -extern struct nvkm_omthds gf100_gr_90c0_omthds[]; -extern struct nvkm_oclass gf110_gr_sclass[]; -extern struct nvkm_oclass gk110_gr_sclass[]; -extern struct nvkm_oclass gm204_gr_sclass[]; +extern const struct nvkm_object_func gf100_fermi; struct gf100_gr_init { u32 addr; @@ -167,24 +197,11 @@ extern struct gf100_gr_ucode gf100_gr_gpccs_ucode; extern struct gf100_gr_ucode gk110_gr_fecs_ucode; extern struct gf100_gr_ucode gk110_gr_gpccs_ucode; -struct gf100_gr_oclass { - struct nvkm_oclass base; - struct nvkm_oclass **cclass; - struct nvkm_oclass *sclass; - const struct gf100_gr_pack *mmio; - struct { - struct gf100_gr_ucode *ucode; - } fecs; - struct { - struct gf100_gr_ucode *ucode; - } gpccs; - int ppc_nr; -}; - -void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *); -void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *); -void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *); -int gf100_gr_init_ctxctl(struct gf100_gr_priv *); +int gf100_gr_wait_idle(struct gf100_gr *); +void gf100_gr_mmio(struct gf100_gr *, const struct gf100_gr_pack *); +void gf100_gr_icmd(struct gf100_gr *, const struct gf100_gr_pack *); +void gf100_gr_mthd(struct gf100_gr *, const struct gf100_gr_pack *); +int gf100_gr_init_ctxctl(struct gf100_gr *); /* register init value lists */ @@ -260,7 +277,7 @@ extern const struct gf100_gr_init gm107_gr_init_tex_0[]; extern const struct gf100_gr_init gm107_gr_init_l1c_0[]; extern const struct gf100_gr_init gm107_gr_init_wwdx_0[]; extern const struct gf100_gr_init gm107_gr_init_cbm_0[]; -void gm107_gr_init_bios(struct gf100_gr_priv *); +void gm107_gr_init_bios(struct gf100_gr *); extern const struct gf100_gr_pack gm204_gr_pack_mmio[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c index 20d3b85db3b5..8f253e0a22f4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include <nvif/class.h> + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -110,18 +112,24 @@ gf104_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ -struct nvkm_oclass * -gf104_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gf104_grctx_oclass, - .sclass = gf100_gr_sclass, +static const struct gf100_gr_func +gf104_gr = { + .init = gf100_gr_init, .mmio = gf104_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; + .grctx = &gf104_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + +int +gf104_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf104_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c index 8df73421c78c..815a5aafa245 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c @@ -27,20 +27,6 @@ #include <nvif/class.h> /******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf108_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} -}; - -/******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -117,18 +103,25 @@ gf108_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ -struct nvkm_oclass * -gf108_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gf108_grctx_oclass, - .sclass = gf108_gr_sclass, +static const struct gf100_gr_func +gf108_gr = { + .init = gf100_gr_init, .mmio = gf108_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; + .grctx = &gf108_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + +int +gf108_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf108_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c index ef76e2dd1d31..d13187409d68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c @@ -27,21 +27,6 @@ #include <nvif/class.h> /******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -struct nvkm_oclass -gf110_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} -}; - -/******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -99,18 +84,26 @@ gf110_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ -struct nvkm_oclass * -gf110_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc8), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gf110_grctx_oclass, - .sclass = gf110_gr_sclass, +static const struct gf100_gr_func +gf110_gr = { + .init = gf100_gr_init, .mmio = gf110_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; + .grctx = &gf110_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_C, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + +int +gf110_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf110_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c index 871ac5f806f6..28483d8bf3d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include <nvif/class.h> + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -118,19 +120,27 @@ gf117_gr_gpccs_ucode = { .data.size = sizeof(gf117_grgpc_data), }; -struct nvkm_oclass * -gf117_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xd7), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gf117_grctx_oclass, - .sclass = gf110_gr_sclass, +static const struct gf100_gr_func +gf117_gr = { + .init = gf100_gr_init, .mmio = gf117_gr_pack_mmio, .fecs.ucode = &gf117_gr_fecs_ucode, .gpccs.ucode = &gf117_gr_gpccs_ucode, .ppc_nr = 1, -}.base; + .grctx = &gf117_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_C, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + +int +gf117_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf117_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c index e6dd651e2636..9811a72e0313 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include <nvif/class.h> + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -173,18 +175,26 @@ gf119_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ -struct nvkm_oclass * -gf119_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xd9), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gf119_grctx_oclass, - .sclass = gf110_gr_sclass, +static const struct gf100_gr_func +gf119_gr = { + .init = gf100_gr_init, .mmio = gf119_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; + .grctx = &gf119_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_C, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + +int +gf119_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf119_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index 46f7844eca70..abf54928a1a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -24,24 +24,9 @@ #include "gf100.h" #include "ctxgf100.h" -#include <subdev/pmu.h> - #include <nvif/class.h> /******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs }, - { KEPLER_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} -}; - -/******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -193,132 +178,112 @@ gk104_gr_pack_mmio[] = { ******************************************************************************/ int -gk104_gr_init(struct nvkm_object *object) +gk104_gr_init(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - struct nvkm_pmu *pmu = nvkm_pmu(priv); - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, rop; - int ret, i; - - if (pmu) - pmu->pgob(pmu, false); + int i; - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; + nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0888), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x088c), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); - nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + gf100_gr_mmio(gr, gr->func->mmio); - gf100_gr_mmio(priv, oclass->mmio); - - nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - - nv_wr32(priv, 0x400500, 0x00010001); - - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - - nv_wr32(priv, 0x409ffc, 0x00000000); - nv_wr32(priv, 0x409c14, 0x00003e3e); - nv_wr32(priv, 0x409c24, 0x000f0001); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); + + nvkm_wr32(device, 0x400500, 0x00010001); + + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + + nvkm_wr32(device, 0x409ffc, 0x00000000); + nvkm_wr32(device, 0x409c14, 0x00003e3e); + nvkm_wr32(device, 0x409c24, 0x000f0001); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); + nvkm_mask(device, 0x419eb4, 0x00001000, 0x00001000); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x3038), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + for (rop = 0; rop < gr->rop_nr; rop++) { + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); - nv_wr32(priv, 0x400054, 0x34ce3464); + nvkm_wr32(device, 0x400054, 0x34ce3464); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gf100_gr_init_ctxctl(priv); -} - -int -gk104_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_pmu *pmu = nvkm_pmu(parent); - if (pmu) - pmu->pgob(pmu, false); - return gf100_gr_ctor(parent, engine, oclass, data, size, pobject); + return gf100_gr_init_ctxctl(gr); } #include "fuc/hubgk104.fuc3.h" @@ -341,19 +306,25 @@ gk104_gr_gpccs_ucode = { .data.size = sizeof(gk104_grgpc_data), }; -struct nvkm_oclass * -gk104_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gk104_grctx_oclass, - .sclass = gk104_gr_sclass, +static const struct gf100_gr_func +gk104_gr = { + .init = gk104_gr_init, .mmio = gk104_gr_pack_mmio, .fecs.ucode = &gk104_gr_fecs_ucode, .gpccs.ucode = &gk104_gr_gpccs_ucode, .ppc_nr = 1, -}.base; + .grctx = &gk104_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_A }, + { -1, -1, KEPLER_A, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_A }, + {} + } +}; + +int +gk104_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk104_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c index f4cd8e5546af..32aa2946e7b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c @@ -29,19 +29,6 @@ #include <nvif/class.h> /******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -struct nvkm_oclass -gk110_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { KEPLER_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { KEPLER_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} -}; - -/******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -193,19 +180,25 @@ gk110_gr_gpccs_ucode = { .data.size = sizeof(gk110_grgpc_data), }; -struct nvkm_oclass * -gk110_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xf0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gk110_grctx_oclass, - .sclass = gk110_gr_sclass, +static const struct gf100_gr_func +gk110_gr = { + .init = gk104_gr_init, .mmio = gk110_gr_pack_mmio, .fecs.ucode = &gk110_gr_fecs_ucode, .gpccs.ucode = &gk110_gr_gpccs_ucode, .ppc_nr = 2, -}.base; + .grctx = &gk110_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, KEPLER_B, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_B }, + {} + } +}; + +int +gk110_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk110_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c index 9ff9eab0ccaf..22f88afbf35f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include <nvif/class.h> + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -98,19 +100,25 @@ gk110b_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ -struct nvkm_oclass * -gk110b_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xf1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gk110b_grctx_oclass, - .sclass = gk110_gr_sclass, +static const struct gf100_gr_func +gk110b_gr = { + .init = gk104_gr_init, .mmio = gk110b_gr_pack_mmio, .fecs.ucode = &gk110_gr_fecs_ucode, .gpccs.ucode = &gk110_gr_gpccs_ucode, .ppc_nr = 2, -}.base; + .grctx = &gk110b_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, KEPLER_B, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_B }, + {} + } +}; + +int +gk110b_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk110b_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c index 85f44a3d5d11..ee7554fc87dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c @@ -29,19 +29,6 @@ #include <nvif/class.h> /******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk208_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { KEPLER_B, &gf100_fermi_ofuncs }, - { KEPLER_COMPUTE_B, &nvkm_object_ofuncs }, - {} -}; - -/******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -172,19 +159,25 @@ gk208_gr_gpccs_ucode = { .data.size = sizeof(gk208_grgpc_data), }; -struct nvkm_oclass * -gk208_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gk208_grctx_oclass, - .sclass = gk208_gr_sclass, +static const struct gf100_gr_func +gk208_gr = { + .init = gk104_gr_init, .mmio = gk208_gr_pack_mmio, .fecs.ucode = &gk208_gr_fecs_ucode, .gpccs.ucode = &gk208_gr_gpccs_ucode, .ppc_nr = 1, -}.base; + .grctx = &gk208_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, KEPLER_B, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_B }, + {} + } +}; + +int +gk208_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk208_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index 40ff5eb9180c..b8758d3b8b51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,28 +22,335 @@ #include "gf100.h" #include "ctxgf100.h" +#include <subdev/timer.h> + #include <nvif/class.h> -static struct nvkm_oclass -gk20a_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs }, - { KEPLER_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} +static void +gk20a_gr_init_dtor(struct gf100_gr_pack *pack) +{ + vfree(pack); +} + +struct gk20a_fw_av +{ + u32 addr; + u32 data; +}; + +static struct gf100_gr_pack * +gk20a_gr_av_to_init(struct gf100_gr_fuc *fuc) +{ + struct gf100_gr_init *init; + struct gf100_gr_pack *pack; + const int nent = (fuc->size / sizeof(struct gk20a_fw_av)); + int i; + + pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1))); + if (!pack) + return ERR_PTR(-ENOMEM); + + init = (void *)(pack + 2); + + pack[0].init = init; + + for (i = 0; i < nent; i++) { + struct gf100_gr_init *ent = &init[i]; + struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc->data)[i]; + + ent->addr = av->addr; + ent->data = av->data; + ent->count = 1; + ent->pitch = 1; + } + + return pack; +} + +struct gk20a_fw_aiv +{ + u32 addr; + u32 index; + u32 data; }; -struct nvkm_oclass * -gk20a_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gk20a_grctx_oclass, - .sclass = gk20a_gr_sclass, - .mmio = gk104_gr_pack_mmio, +static struct gf100_gr_pack * +gk20a_gr_aiv_to_init(struct gf100_gr_fuc *fuc) +{ + struct gf100_gr_init *init; + struct gf100_gr_pack *pack; + const int nent = (fuc->size / sizeof(struct gk20a_fw_aiv)); + int i; + + pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1))); + if (!pack) + return ERR_PTR(-ENOMEM); + + init = (void *)(pack + 2); + + pack[0].init = init; + + for (i = 0; i < nent; i++) { + struct gf100_gr_init *ent = &init[i]; + struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)fuc->data)[i]; + + ent->addr = av->addr; + ent->data = av->data; + ent->count = 1; + ent->pitch = 1; + } + + return pack; +} + +static struct gf100_gr_pack * +gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc) +{ + struct gf100_gr_init *init; + struct gf100_gr_pack *pack; + /* We don't suppose we will initialize more than 16 classes here... */ + static const unsigned int max_classes = 16; + const int nent = (fuc->size / sizeof(struct gk20a_fw_av)); + int i, classidx = 0; + u32 prevclass = 0; + + pack = vzalloc((sizeof(*pack) * max_classes) + + (sizeof(*init) * (nent + 1))); + if (!pack) + return ERR_PTR(-ENOMEM); + + init = (void *)(pack + max_classes); + + for (i = 0; i < nent; i++) { + struct gf100_gr_init *ent = &init[i]; + struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc->data)[i]; + u32 class = av->addr & 0xffff; + u32 addr = (av->addr & 0xffff0000) >> 14; + + if (prevclass != class) { + pack[classidx].init = ent; + pack[classidx].type = class; + prevclass = class; + if (++classidx >= max_classes) { + vfree(pack); + return ERR_PTR(-ENOSPC); + } + } + + ent->addr = addr; + ent->data = av->data; + ent->count = 1; + ent->pitch = 1; + } + + return pack; +} + +static int +gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr) +{ + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x40910c) & 0x00000006)) + break; + ) < 0) { + nvkm_error(subdev, "FECS mem scrubbing timeout\n"); + return -ETIMEDOUT; + } + + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x41a10c) & 0x00000006)) + break; + ) < 0) { + nvkm_error(subdev, "GPCCS mem scrubbing timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void +gk20a_gr_set_hww_esr_report_mask(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_wr32(device, 0x419e44, 0x1ffffe); + nvkm_wr32(device, 0x419e4c, 0x7f); +} + +int +gk20a_gr_init(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); + u32 data[TPC_MAX / 8] = {}; + u8 tpcnr[GPC_MAX]; + int gpc, tpc; + int ret, i; + + /* Clear SCC RAM */ + nvkm_wr32(device, 0x40802c, 0x1); + + gf100_gr_mmio(gr, gr->fuc_sw_nonctx); + + ret = gk20a_gr_wait_mem_scrubbing(gr); + if (ret) + return ret; + + ret = gf100_gr_wait_idle(gr); + if (ret) + return ret; + + /* MMU debug buffer */ + nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8); + + if (gr->func->init_gpc_mmu) + gr->func->init_gpc_mmu(gr); + + /* Set the PE as stream master */ + nvkm_mask(device, 0x503018, 0x1, 0x1); + + /* Zcull init */ + memset(data, 0x00, sizeof(data)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { + do { + gpc = (gpc + 1) % gr->gpc_nr; + } while (!tpcnr[gpc]); + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; + + data[i / 8] |= tpc << ((i % 8) * 4); + } + + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); + } + + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + + /* Enable FIFO access */ + nvkm_wr32(device, 0x400500, 0x00010001); + + /* Enable interrupts */ + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + + /* Enable FECS error interrupts */ + nvkm_wr32(device, 0x409c24, 0x000f0000); + + /* Enable hardware warning exceptions */ + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + + if (gr->func->set_hww_esr_report_mask) + gr->func->set_hww_esr_report_mask(gr); + + /* Enable TPC exceptions per GPC */ + nvkm_wr32(device, 0x419d0c, 0x2); + nvkm_wr32(device, 0x41ac94, (((1 << gr->tpc_total) - 1) & 0xff) << 16); + + /* Reset and enable all exceptions */ + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); + + gf100_gr_zbc_init(gr); + + return gf100_gr_init_ctxctl(gr); +} + +void +gk20a_gr_dtor(struct gf100_gr *gr) +{ + gk20a_gr_init_dtor(gr->fuc_method); + gk20a_gr_init_dtor(gr->fuc_bundle); + gk20a_gr_init_dtor(gr->fuc_sw_ctx); + gk20a_gr_init_dtor(gr->fuc_sw_nonctx); +} + +int +gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct gf100_gr_fuc fuc; + struct gf100_gr *gr; + int ret; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + + ret = gf100_gr_ctor(func, device, index, gr); + if (ret) + return ret; + + ret = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc); + if (ret) + return ret; + gr->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_sw_nonctx)) + return PTR_ERR(gr->fuc_sw_nonctx); + + ret = gf100_gr_ctor_fw(gr, "sw_ctx", &fuc); + if (ret) + return ret; + gr->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_sw_ctx)) + return PTR_ERR(gr->fuc_sw_ctx); + + ret = gf100_gr_ctor_fw(gr, "sw_bundle_init", &fuc); + if (ret) + return ret; + gr->fuc_bundle = gk20a_gr_av_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_bundle)) + return PTR_ERR(gr->fuc_bundle); + + ret = gf100_gr_ctor_fw(gr, "sw_method_init", &fuc); + if (ret) + return ret; + gr->fuc_method = gk20a_gr_av_to_method(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_method)) + return PTR_ERR(gr->fuc_method); + + return 0; +} + +static const struct gf100_gr_func +gk20a_gr = { + .dtor = gk20a_gr_dtor, + .init = gk20a_gr_init, + .set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask, .ppc_nr = 1, -}.base; + .grctx = &gk20a_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_A }, + { -1, -1, KEPLER_C, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_A }, + {} + } +}; + +int +gk20a_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gk20a_gr_new_(&gk20a_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index a5ebd459bc24..56e960212e5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -30,19 +30,6 @@ #include <nvif/class.h> /******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gm107_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { MAXWELL_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} -}; - -/******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -292,7 +279,7 @@ gm107_gr_pack_mmio[] = { ******************************************************************************/ void -gm107_gr_init_bios(struct gf100_gr_priv *priv) +gm107_gr_init_bios(struct gf100_gr *gr) { static const struct { u32 ctrl; @@ -304,7 +291,8 @@ gm107_gr_init_bios(struct gf100_gr_priv *priv) { 0x419af0, 0x419af4 }, { 0x419af8, 0x419afc }, }; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; struct nvbios_P0260E infoE; struct nvbios_P0260X infoX; int E = -1, X; @@ -312,124 +300,119 @@ gm107_gr_init_bios(struct gf100_gr_priv *priv) while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) { if (X = -1, E < ARRAY_SIZE(regs)) { - nv_wr32(priv, regs[E].ctrl, infoE.data); + nvkm_wr32(device, regs[E].ctrl, infoE.data); while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX)) - nv_wr32(priv, regs[E].data, infoX.data); + nvkm_wr32(device, regs[E].data, infoX.data); } } } int -gm107_gr_init(struct nvkm_object *object) +gm107_gr_init(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, ppc, rop; - int ret, i; - - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; + int i; - nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); - gf100_gr_mmio(priv, oclass->mmio); + gf100_gr_mmio(gr, gr->func->mmio); - gm107_gr_init_bios(priv); + gm107_gr_init_bios(gr); - nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - - nv_wr32(priv, 0x400500, 0x00010001); - - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - nv_wr32(priv, 0x400124, 0x00000002); - nv_wr32(priv, 0x409c24, 0x000e0000); - - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++) - nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); + + nvkm_wr32(device, 0x400500, 0x00010001); + + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400124, 0x00000002); + nvkm_wr32(device, 0x409c24, 0x000e0000); + + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < 2 /* gr->ppc_nr[gpc] */; ppc++) + nvkm_wr32(device, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + for (rop = 0; rop < gr->rop_nr; rop++) { + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); - nv_wr32(priv, 0x400054, 0x2c350f63); + nvkm_wr32(device, 0x400054, 0x2c350f63); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gf100_gr_init_ctxctl(priv); + return gf100_gr_init_ctxctl(gr); } #include "fuc/hubgm107.fuc5.h" @@ -452,19 +435,25 @@ gm107_gr_gpccs_ucode = { .data.size = sizeof(gm107_grgpc_data), }; -struct nvkm_oclass * -gm107_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gm107_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gm107_grctx_oclass, - .sclass = gm107_gr_sclass, +static const struct gf100_gr_func +gm107_gr = { + .init = gm107_gr_init, .mmio = gm107_gr_pack_mmio, .fecs.ucode = &gm107_gr_fecs_ucode, .gpccs.ucode = &gm107_gr_gpccs_ucode, .ppc_nr = 2, -}.base; + .grctx = &gm107_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_A, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_A }, + {} + } +}; + +int +gm107_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gm107_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c index fdb1dcf16a59..90381dde451a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c @@ -27,19 +27,6 @@ #include <nvif/class.h> /******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -struct nvkm_oclass -gm204_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, - {} -}; - -/******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -243,144 +230,144 @@ gm204_gr_data[] = { ******************************************************************************/ static int -gm204_gr_init_ctxctl(struct gf100_gr_priv *priv) +gm204_gr_init_ctxctl(struct gf100_gr *gr) { return 0; } int -gm204_gr_init(struct nvkm_object *object) +gm204_gr_init(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); - u32 data[TPC_MAX / 8] = {}; + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); + u32 data[TPC_MAX / 8] = {}, tmp; u8 tpcnr[GPC_MAX]; int gpc, tpc, ppc, rop; - int ret, i; - u32 tmp; - - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; + int i; - tmp = nv_rd32(priv, 0x100c80); /*XXX: mask? */ - nv_wr32(priv, 0x418880, 0x00001000 | (tmp & 0x00000fff)); - nv_wr32(priv, 0x418890, 0x00000000); - nv_wr32(priv, 0x418894, 0x00000000); - nv_wr32(priv, 0x4188b4, priv->unk4188b4->addr >> 8); - nv_wr32(priv, 0x4188b8, priv->unk4188b8->addr >> 8); - nv_mask(priv, 0x4188b0, 0x00040000, 0x00040000); + tmp = nvkm_rd32(device, 0x100c80); /*XXX: mask? */ + nvkm_wr32(device, 0x418880, 0x00001000 | (tmp & 0x00000fff)); + nvkm_wr32(device, 0x418890, 0x00000000); + nvkm_wr32(device, 0x418894, 0x00000000); + nvkm_wr32(device, 0x4188b4, nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, 0x4188b8, nvkm_memory_addr(gr->unk4188b8) >> 8); + nvkm_mask(device, 0x4188b0, 0x00040000, 0x00040000); /*XXX: belongs in fb */ - nv_wr32(priv, 0x100cc8, priv->unk4188b4->addr >> 8); - nv_wr32(priv, 0x100ccc, priv->unk4188b8->addr >> 8); - nv_mask(priv, 0x100cc4, 0x00040000, 0x00040000); + nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8); + nvkm_mask(device, 0x100cc4, 0x00040000, 0x00040000); - gf100_gr_mmio(priv, oclass->mmio); + gf100_gr_mmio(gr, gr->func->mmio); - gm107_gr_init_bios(priv); + gm107_gr_init_bios(gr); - nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - nv_wr32(priv, GPC_BCAST(0x033c), nv_rd32(priv, 0x100804)); - - nv_wr32(priv, 0x400500, 0x00010001); - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - nv_wr32(priv, 0x400124, 0x00000002); - nv_wr32(priv, 0x409c24, 0x000e0000); - nv_wr32(priv, 0x405848, 0xc0000000); - nv_wr32(priv, 0x40584c, 0x00000001); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) - nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); + nvkm_wr32(device, GPC_BCAST(0x033c), nvkm_rd32(device, 0x100804)); + + nvkm_wr32(device, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400124, 0x00000002); + nvkm_wr32(device, 0x409c24, 0x000e0000); + nvkm_wr32(device, 0x405848, 0xc0000000); + nvkm_wr32(device, 0x40584c, 0x00000001); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) + nvkm_wr32(device, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + for (rop = 0; rop < gr->rop_nr; rop++) { + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); - nv_wr32(priv, 0x400054, 0x2c350f63); + nvkm_wr32(device, 0x400054, 0x2c350f63); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gm204_gr_init_ctxctl(priv); + return gm204_gr_init_ctxctl(gr); } -struct nvkm_oclass * -gm204_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gm204_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gm204_grctx_oclass, - .sclass = gm204_gr_sclass, +static const struct gf100_gr_func +gm204_gr = { + .init = gm204_gr_init, .mmio = gm204_gr_pack_mmio, .ppc_nr = 2, -}.base; + .grctx = &gm204_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_B, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_B }, + {} + } +}; + +int +gm204_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gm204_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c index 04b9733d146a..341dc560acbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c @@ -24,17 +24,25 @@ #include "gf100.h" #include "ctxgf100.h" -struct nvkm_oclass * -gm206_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x26), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gm204_gr_init, - .fini = _nvkm_gr_fini, - }, - .cclass = &gm206_grctx_oclass, - .sclass = gm204_gr_sclass, +#include <nvif/class.h> + +static const struct gf100_gr_func +gm206_gr = { + .init = gm204_gr_init, .mmio = gm204_gr_pack_mmio, .ppc_nr = 2, -}.base; + .grctx = &gm206_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_B, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_B }, + {} + } +}; + +int +gm206_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gm206_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c new file mode 100644 index 000000000000..65b6e3d1e90d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "gf100.h" +#include "ctxgf100.h" + +#include <subdev/timer.h> + +#include <nvif/class.h> + +static void +gm20b_gr_init_gpc_mmu(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 val; + + /* TODO this needs to be removed once secure boot works */ + if (1) { + nvkm_wr32(device, 0x100ce4, 0xffffffff); + } + + /* TODO update once secure boot works */ + val = nvkm_rd32(device, 0x100c80); + val &= 0xf000087f; + nvkm_wr32(device, 0x418880, val); + nvkm_wr32(device, 0x418890, 0); + nvkm_wr32(device, 0x418894, 0); + + nvkm_wr32(device, 0x4188b0, nvkm_rd32(device, 0x100cc4)); + nvkm_wr32(device, 0x4188b4, nvkm_rd32(device, 0x100cc8)); + nvkm_wr32(device, 0x4188b8, nvkm_rd32(device, 0x100ccc)); + + nvkm_wr32(device, 0x4188ac, nvkm_rd32(device, 0x100800)); +} + +static void +gm20b_gr_set_hww_esr_report_mask(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_wr32(device, 0x419e44, 0xdffffe); + nvkm_wr32(device, 0x419e4c, 0x5); +} + +static const struct gf100_gr_func +gm20b_gr = { + .dtor = gk20a_gr_dtor, + .init = gk20a_gr_init, + .init_gpc_mmu = gm20b_gr_init_gpc_mmu, + .set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask, + .ppc_nr = 1, + .grctx = &gm20b_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_B, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_B }, + {} + } +}; + +int +gm20b_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gk20a_gr_new_(&gm20b_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c new file mode 100644 index 000000000000..2e68919f00b2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c @@ -0,0 +1,47 @@ +/* + * 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 const struct nvkm_gr_func +gt200_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8397, &nv50_gr_object }, + {} + } +}; + +int +gt200_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(>200_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c new file mode 100644 index 000000000000..2bf7aac360cc --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c @@ -0,0 +1,48 @@ +/* + * 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 const struct nvkm_gr_func +gt215_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8597, &nv50_gr_object }, + { -1, -1, 0x85c0, &nv50_gr_object }, + {} + } +}; + +int +gt215_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(>215_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c new file mode 100644 index 000000000000..95d5219faf93 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c @@ -0,0 +1,46 @@ +/* + * 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 const struct nvkm_gr_func +mcp79_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8397, &nv50_gr_object }, + {} + } +}; + +int +mcp79_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&mcp79_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c new file mode 100644 index 000000000000..027b58e5976b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c @@ -0,0 +1,48 @@ +/* + * 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 const struct nvkm_gr_func +mcp89_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x85c0, &nv50_gr_object }, + { -1, -1, 0x8697, &nv50_gr_object }, + {} + } +}; + +int +mcp89_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&mcp89_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 2614510c28d0..85c5b7fea5f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -21,13 +21,13 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <engine/gr.h> +#include "priv.h" #include "regs.h" #include <core/client.h> -#include <core/device.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> #include <subdev/instmem.h> #include <subdev/timer.h> @@ -346,25 +346,23 @@ nv04_gr_ctx_regs[] = { NV04_PGRAPH_DEBUG_3 }; -struct nv04_gr_priv { +#define nv04_gr(p) container_of((p), struct nv04_gr, base) + +struct nv04_gr { struct nvkm_gr base; struct nv04_gr_chan *chan[16]; spinlock_t lock; }; +#define nv04_gr_chan(p) container_of((p), struct nv04_gr_chan, object) + struct nv04_gr_chan { - struct nvkm_object base; + struct nvkm_object object; + struct nv04_gr *gr; int chid; u32 nv04[ARRAY_SIZE(nv04_gr_ctx_regs)]; }; - -static inline struct nv04_gr_priv * -nv04_gr_priv(struct nv04_gr_chan *chan) -{ - return (void *)nv_object(chan)->engine; -} - /******************************************************************************* * Graphics object classes ******************************************************************************/ @@ -444,35 +442,34 @@ nv04_gr_priv(struct nv04_gr_chan *chan) */ static void -nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value) +nv04_gr_set_ctx1(struct nvkm_device *device, u32 inst, u32 mask, u32 value) { - struct nv04_gr_priv *priv = (void *)object->engine; - int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; + int subc = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; u32 tmp; - tmp = nv_ro32(object, 0x00); + tmp = nvkm_rd32(device, 0x700000 + inst); tmp &= ~mask; tmp |= value; - nv_wo32(object, 0x00, tmp); + nvkm_wr32(device, 0x700000 + inst, tmp); - nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp); - nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); + nvkm_wr32(device, NV04_PGRAPH_CTX_SWITCH1, tmp); + nvkm_wr32(device, NV04_PGRAPH_CTX_CACHE1 + (subc << 2), tmp); } static void -nv04_gr_set_ctx_val(struct nvkm_object *object, u32 mask, u32 value) +nv04_gr_set_ctx_val(struct nvkm_device *device, u32 inst, u32 mask, u32 value) { int class, op, valid = 1; u32 tmp, ctx1; - ctx1 = nv_ro32(object, 0x00); + ctx1 = nvkm_rd32(device, 0x700000 + inst); class = ctx1 & 0xff; op = (ctx1 >> 15) & 7; - tmp = nv_ro32(object, 0x0c); + tmp = nvkm_rd32(device, 0x70000c + inst); tmp &= ~mask; tmp |= value; - nv_wo32(object, 0x0c, tmp); + nvkm_wr32(device, 0x70000c + inst, tmp); /* check for valid surf2d/surf_dst/surf_color */ if (!(tmp & 0x02000000)) @@ -504,527 +501,567 @@ nv04_gr_set_ctx_val(struct nvkm_object *object, u32 mask, u32 value) break; } - nv04_gr_set_ctx1(object, 0x01000000, valid << 24); + nv04_gr_set_ctx1(device, inst, 0x01000000, valid << 24); } -static int -nv04_gr_mthd_set_operation(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_set_operation(struct nvkm_device *device, u32 inst, u32 data) { - u32 class = nv_ro32(object, 0) & 0xff; - u32 data = *(u32 *)args; + u8 class = nvkm_rd32(device, 0x700000) & 0x000000ff; if (data > 5) - return 1; + return false; /* Old versions of the objects only accept first three operations. */ if (data > 2 && class < 0x40) - return 1; - nv04_gr_set_ctx1(object, 0x00038000, data << 15); + return false; + nv04_gr_set_ctx1(device, inst, 0x00038000, data << 15); /* changing operation changes set of objects needed for validation */ - nv04_gr_set_ctx_val(object, 0, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0, 0); + return true; } -static int -nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_surf3d_clip_h(struct nvkm_device *device, u32 inst, u32 data) { - struct nv04_gr_priv *priv = (void *)object->engine; - u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; if (min & 0x8000) /* too large */ - return 1; + return false; if (w & 0x8000) /* yes, it accepts negative for some reason. */ w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(priv, 0x40053c, min); - nv_wr32(priv, 0x400544, max); - return 0; + nvkm_wr32(device, 0x40053c, min); + nvkm_wr32(device, 0x400544, max); + return true; } -static int -nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_surf3d_clip_v(struct nvkm_device *device, u32 inst, u32 data) { - struct nv04_gr_priv *priv = (void *)object->engine; - u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; if (min & 0x8000) /* too large */ - return 1; + return false; if (w & 0x8000) /* yes, it accepts negative for some reason. */ w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(priv, 0x400540, min); - nv_wr32(priv, 0x400548, max); - return 0; + nvkm_wr32(device, 0x400540, min); + nvkm_wr32(device, 0x400548, max); + return true; } -static u16 -nv04_gr_mthd_bind_class(struct nvkm_object *object, u32 *args, u32 size) +static u8 +nv04_gr_mthd_bind_class(struct nvkm_device *device, u32 inst) { - struct nvkm_instmem *imem = nvkm_instmem(object); - u32 inst = *(u32 *)args << 4; - return nv_ro32(imem, inst); + return nvkm_rd32(device, 0x700000 + (inst << 4)); } -static int -nv04_gr_mthd_bind_surf2d(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf2d(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x42: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x42: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; case 0x52: - nv04_gr_set_ctx1(object, 0x00004000, 0x00004000); - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0x00004000); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv01_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv01_gr_mthd_bind_patt(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x08000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0); + return true; case 0x18: - nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0x08000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_patt(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x08000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0); + return true; case 0x44: - nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0x08000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_rop(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_rop(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x10000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x10000000, 0); + return true; case 0x43: - nv04_gr_set_ctx_val(object, 0x10000000, 0x10000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x10000000, 0x10000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_beta1(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_beta1(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x20000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x20000000, 0); + return true; case 0x12: - nv04_gr_set_ctx_val(object, 0x20000000, 0x20000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x20000000, 0x20000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_beta4(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_beta4(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x40000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x40000000, 0); + return true; case 0x72: - nv04_gr_set_ctx_val(object, 0x40000000, 0x40000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x40000000, 0x40000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_dst(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_dst(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x58: - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_src(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_src(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x04000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0); + return true; case 0x59: - nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0x04000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_color(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_color(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x5a: - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_zeta(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_zeta(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x04000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0); + return true; case 0x5b: - nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0x04000000); + return true; } - return 1; + return false; } -static int -nv01_gr_mthd_bind_clip(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv01_gr_mthd_bind_clip(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x2000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x2000, 0); + return true; case 0x19: - nv04_gr_set_ctx1(object, 0x2000, 0x2000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x2000, 0x2000); + return true; } - return 1; + return false; } -static int -nv01_gr_mthd_bind_chroma(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv01_gr_mthd_bind_chroma(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x1000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x1000, 0); + return true; /* Yes, for some reason even the old versions of objects * accept 0x57 and not 0x17. Consistency be damned. */ case 0x57: - nv04_gr_set_ctx1(object, 0x1000, 0x1000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x1000, 0x1000); + return true; } - return 1; + return false; } -static struct nvkm_omthds -nv03_gr_gdi_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_patt }, - { 0x0188, 0x0188, nv04_gr_mthd_bind_rop }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_beta1 }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; - -static struct nvkm_omthds -nv04_gr_gdi_omthds[] = { - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv03_gr_mthd_gdi(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_patt; break; + case 0x0188: func = nv04_gr_mthd_bind_rop; break; + case 0x018c: func = nv04_gr_mthd_bind_beta1; break; + case 0x0190: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv01_gr_blit_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv01_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_surf_src }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_gdi(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_blit_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv01_gr_mthd_blit(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv01_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x019c: func = nv04_gr_mthd_bind_surf_src; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_iifc_omthds[] = { - { 0x0188, 0x0188, nv01_gr_mthd_bind_chroma }, - { 0x018c, 0x018c, nv01_gr_mthd_bind_clip }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_patt }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_rop }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_beta1 }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_beta4 }, - { 0x01a0, 0x01a0, nv04_gr_mthd_bind_surf2d_swzsurf }, - { 0x03e4, 0x03e4, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_blit(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv04_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_beta4; break; + case 0x019c: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv01_gr_ifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv01_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_iifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv01_gr_mthd_bind_chroma; break; + case 0x018c: func = nv01_gr_mthd_bind_clip; break; + case 0x0190: func = nv04_gr_mthd_bind_patt; break; + case 0x0194: func = nv04_gr_mthd_bind_rop; break; + case 0x0198: func = nv04_gr_mthd_bind_beta1; break; + case 0x019c: func = nv04_gr_mthd_bind_beta4; break; + case 0x01a0: func = nv04_gr_mthd_bind_surf2d_swzsurf; break; + case 0x03e4: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_ifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv01_gr_mthd_ifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv01_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv03_gr_sifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_ifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv04_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_beta4; break; + case 0x019c: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_sifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv03_gr_mthd_sifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv03_gr_sifm_omthds[] = { - { 0x0188, 0x0188, nv01_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst }, - { 0x0304, 0x0304, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_sifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_sifm_omthds[] = { - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x0304, 0x0304, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv03_gr_mthd_sifm(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv01_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x0304: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_surf3d_omthds[] = { - { 0x02f8, 0x02f8, nv04_gr_mthd_surf3d_clip_h }, - { 0x02fc, 0x02fc, nv04_gr_mthd_surf3d_clip_v }, - {} -}; +static bool +nv04_gr_mthd_sifm(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x0304: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv03_gr_ttri_omthds[] = { - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_surf_color }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_surf_zeta }, - {} -}; +static bool +nv04_gr_mthd_surf3d(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x02f8: func = nv04_gr_mthd_surf3d_clip_h; break; + case 0x02fc: func = nv04_gr_mthd_surf3d_clip_v; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv01_gr_prim_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_clip }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv03_gr_mthd_ttri(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv04_gr_mthd_bind_surf_color; break; + case 0x0190: func = nv04_gr_mthd_bind_surf_zeta; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_prim_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_clip }, - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv01_gr_mthd_prim(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_clip; break; + case 0x0188: func = nv01_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static int -nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static bool +nv04_gr_mthd_prim(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) { - struct nvkm_gpuobj *obj; - int ret; + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_clip; break; + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; +static bool +nv04_gr_mthd(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32, u32); + switch (nvkm_rd32(device, 0x700000 + inst) & 0x000000ff) { + case 0x1c ... 0x1e: + func = nv01_gr_mthd_prim; break; + case 0x1f: func = nv01_gr_mthd_blit; break; + case 0x21: func = nv01_gr_mthd_ifc; break; + case 0x36: func = nv03_gr_mthd_sifc; break; + case 0x37: func = nv03_gr_mthd_sifm; break; + case 0x48: func = nv03_gr_mthd_ttri; break; + case 0x4a: func = nv04_gr_mthd_gdi; break; + case 0x4b: func = nv03_gr_mthd_gdi; break; + case 0x53: func = nv04_gr_mthd_surf3d; break; + case 0x5c ... 0x5e: + func = nv04_gr_mthd_prim; break; + case 0x5f: func = nv04_gr_mthd_blit; break; + case 0x60: func = nv04_gr_mthd_iifc; break; + case 0x61: func = nv04_gr_mthd_ifc; break; + case 0x76: func = nv04_gr_mthd_sifc; break; + case 0x77: func = nv04_gr_mthd_sifm; break; + default: + return false; + } + return func(device, inst, mthd, data); +} - nv_wo32(obj, 0x00, nv_mclass(obj)); +static int +nv04_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, align, + false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); #ifdef __BIG_ENDIAN - nv_mo32(obj, 0x00, 0x00080000, 0x00080000); + nvkm_mo32(*pgpuobj, 0x00, 0x00080000, 0x00080000); #endif - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); - return 0; + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -struct nvkm_ofuncs -nv04_gr_ofuncs = { - .ctor = nv04_gr_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv04_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0017, &nv04_gr_ofuncs }, /* chroma */ - { 0x0018, &nv04_gr_ofuncs }, /* pattern (nv01) */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x001c, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* line */ - { 0x001d, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* tri */ - { 0x001e, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* rect */ - { 0x001f, &nv04_gr_ofuncs, nv01_gr_blit_omthds }, - { 0x0021, &nv04_gr_ofuncs, nv01_gr_ifc_omthds }, - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0036, &nv04_gr_ofuncs, nv03_gr_sifc_omthds }, - { 0x0037, &nv04_gr_ofuncs, nv03_gr_sifm_omthds }, - { 0x0038, &nv04_gr_ofuncs }, /* dvd subpicture */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0042, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x0048, &nv04_gr_ofuncs, nv03_gr_ttri_omthds }, - { 0x004a, &nv04_gr_ofuncs, nv04_gr_gdi_omthds }, - { 0x004b, &nv04_gr_ofuncs, nv03_gr_gdi_omthds }, - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x0053, &nv04_gr_ofuncs, nv04_gr_surf3d_omthds }, - { 0x0054, &nv04_gr_ofuncs }, /* ttri */ - { 0x0055, &nv04_gr_ofuncs }, /* mtri */ - { 0x0057, &nv04_gr_ofuncs }, /* chroma */ - { 0x0058, &nv04_gr_ofuncs }, /* surf_dst */ - { 0x0059, &nv04_gr_ofuncs }, /* surf_src */ - { 0x005a, &nv04_gr_ofuncs }, /* surf_color */ - { 0x005b, &nv04_gr_ofuncs }, /* surf_zeta */ - { 0x005c, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* line */ - { 0x005d, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* tri */ - { 0x005e, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* rect */ - { 0x005f, &nv04_gr_ofuncs, nv04_gr_blit_omthds }, - { 0x0060, &nv04_gr_ofuncs, nv04_gr_iifc_omthds }, - { 0x0061, &nv04_gr_ofuncs, nv04_gr_ifc_omthds }, - { 0x0064, &nv04_gr_ofuncs }, /* iifc (nv05) */ - { 0x0065, &nv04_gr_ofuncs }, /* ifc (nv05) */ - { 0x0066, &nv04_gr_ofuncs }, /* sifc (nv05) */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0076, &nv04_gr_ofuncs, nv04_gr_sifc_omthds }, - { 0x0077, &nv04_gr_ofuncs, nv04_gr_sifm_omthds }, - {}, +const struct nvkm_object_func +nv04_gr_object = { + .bind = nv04_gr_object_bind, }; /******************************************************************************* @@ -1032,13 +1069,14 @@ nv04_gr_sclass[] = { ******************************************************************************/ static struct nv04_gr_chan * -nv04_gr_channel(struct nv04_gr_priv *priv) +nv04_gr_channel(struct nv04_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv04_gr_chan *chan = NULL; - if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) { - int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24; - if (chid < ARRAY_SIZE(priv->chan)) - chan = priv->chan[chid]; + if (nvkm_rd32(device, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) { + int chid = nvkm_rd32(device, NV04_PGRAPH_CTX_USER) >> 24; + if (chid < ARRAY_SIZE(gr->chan)) + chan = gr->chan[chid]; } return chan; } @@ -1046,55 +1084,52 @@ nv04_gr_channel(struct nv04_gr_priv *priv) static int nv04_gr_load_context(struct nv04_gr_chan *chan, int chid) { - struct nv04_gr_priv *priv = nv04_gr_priv(chan); + struct nvkm_device *device = chan->gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) - nv_wr32(priv, nv04_gr_ctx_regs[i], chan->nv04[i]); + nvkm_wr32(device, nv04_gr_ctx_regs[i], chan->nv04[i]); - nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100); - nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24); - nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL, 0x10010100); + nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nvkm_mask(device, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000); return 0; } static int nv04_gr_unload_context(struct nv04_gr_chan *chan) { - struct nv04_gr_priv *priv = nv04_gr_priv(chan); + struct nvkm_device *device = chan->gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) - chan->nv04[i] = nv_rd32(priv, nv04_gr_ctx_regs[i]); + chan->nv04[i] = nvkm_rd32(device, nv04_gr_ctx_regs[i]); - nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000); - nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL, 0x10000000); + nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); return 0; } static void -nv04_gr_context_switch(struct nv04_gr_priv *priv) +nv04_gr_context_switch(struct nv04_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv04_gr_chan *prev = NULL; struct nv04_gr_chan *next = NULL; - unsigned long flags; int chid; - spin_lock_irqsave(&priv->lock, flags); - nv04_gr_idle(priv); + nv04_gr_idle(&gr->base); /* If previous context is valid, we need to save it */ - prev = nv04_gr_channel(priv); + prev = nv04_gr_channel(gr); if (prev) nv04_gr_unload_context(prev); /* load context for next channel */ - chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f; - next = priv->chan[chid]; + chid = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f; + next = gr->chan[chid]; if (next) nv04_gr_load_context(next, chid); - - spin_unlock_irqrestore(&priv->lock, flags); } static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg) @@ -1109,98 +1144,85 @@ static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg) return NULL; } -static int -nv04_gr_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void * +nv04_gr_chan_dtor(struct nvkm_object *object) { - struct nvkm_fifo_chan *fifo = (void *)parent; - struct nv04_gr_priv *priv = (void *)engine; - struct nv04_gr_chan *chan; + struct nv04_gr_chan *chan = nv04_gr_chan(object); + struct nv04_gr *gr = chan->gr; unsigned long flags; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - spin_lock_irqsave(&priv->lock, flags); - if (priv->chan[fifo->chid]) { - *pobject = nv_object(priv->chan[fifo->chid]); - atomic_inc(&(*pobject)->refcount); - spin_unlock_irqrestore(&priv->lock, flags); - nvkm_object_destroy(&chan->base); - return 1; - } - *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; - - priv->chan[fifo->chid] = chan; - chan->chid = fifo->chid; - spin_unlock_irqrestore(&priv->lock, flags); - return 0; + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = NULL; + spin_unlock_irqrestore(&gr->lock, flags); + return chan; } -static void -nv04_gr_context_dtor(struct nvkm_object *object) +static int +nv04_gr_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv04_gr_priv *priv = (void *)object->engine; - struct nv04_gr_chan *chan = (void *)object; + struct nv04_gr_chan *chan = nv04_gr_chan(object); + struct nv04_gr *gr = chan->gr; + struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - priv->chan[chan->chid] = NULL; - spin_unlock_irqrestore(&priv->lock, flags); - - nvkm_object_destroy(&chan->base); + spin_lock_irqsave(&gr->lock, flags); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + if (nv04_gr_channel(gr) == chan) + nv04_gr_unload_context(chan); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); + return 0; } +static const struct nvkm_object_func +nv04_gr_chan = { + .dtor = nv04_gr_chan_dtor, + .fini = nv04_gr_chan_fini, +}; + static int -nv04_gr_context_fini(struct nvkm_object *object, bool suspend) +nv04_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - struct nv04_gr_priv *priv = (void *)object->engine; - struct nv04_gr_chan *chan = (void *)object; + struct nv04_gr *gr = nv04_gr(base); + struct nv04_gr_chan *chan; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (nv04_gr_channel(priv) == chan) - nv04_gr_unload_context(chan); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->lock, flags); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv04_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; - return nvkm_object_fini(&chan->base, suspend); -} + *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; -static struct nvkm_oclass -nv04_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_gr_context_ctor, - .dtor = nv04_gr_context_dtor, - .init = nvkm_object_init, - .fini = nv04_gr_context_fini, - }, -}; + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = chan; + spin_unlock_irqrestore(&gr->lock, flags); + return 0; +} /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ bool -nv04_gr_idle(void *obj) +nv04_gr_idle(struct nvkm_gr *gr) { - struct nvkm_gr *gr = nvkm_gr(obj); + struct nvkm_subdev *subdev = &gr->engine.subdev; + struct nvkm_device *device = subdev->device; u32 mask = 0xffffffff; - if (nv_device(obj)->card_type == NV_40) + if (device->card_type == NV_40) mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL; - if (!nv_wait(gr, NV04_PGRAPH_STATUS, mask, 0)) { - nv_error(gr, "idle timed out with status 0x%08x\n", - nv_rd32(gr, NV04_PGRAPH_STATUS)); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, NV04_PGRAPH_STATUS) & mask)) + break; + ) < 0) { + nvkm_error(subdev, "idle timed out with status %08x\n", + nvkm_rd32(device, NV04_PGRAPH_STATUS)); return false; } @@ -1247,136 +1269,159 @@ nv04_gr_nsource[] = { }; static void -nv04_gr_intr(struct nvkm_subdev *subdev) +nv04_gr_intr(struct nvkm_gr *base) { - struct nv04_gr_priv *priv = (void *)subdev; - struct nv04_gr_chan *chan = NULL; - struct nvkm_namedb *namedb = NULL; - struct nvkm_handle *handle = NULL; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + struct nv04_gr *gr = nv04_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x0f000000) >> 24; u32 subc = (addr & 0x0000e000) >> 13; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff; - u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400180 + subc * 4) & 0xff; + u32 inst = (nvkm_rd32(device, 0x40016c) & 0xffff) << 4; u32 show = stat; + char msg[128], src[128], sta[128]; + struct nv04_gr_chan *chan; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - chan = priv->chan[chid]; - if (chan) - namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&gr->lock, flags); + chan = gr->chan[chid]; if (stat & NV_PGRAPH_INTR_NOTIFY) { if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { - handle = nvkm_namedb_get_vinst(namedb, inst); - if (handle && !nv_call(handle->object, mthd, data)) + if (!nv04_gr_mthd(device, inst, mthd, data)) show &= ~NV_PGRAPH_INTR_NOTIFY; } } if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + nvkm_wr32(device, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - nv04_gr_context_switch(priv); + nv04_gr_context_switch(gr); } - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); - nvkm_bitfield_print(nv04_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv04_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(priv, - "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, nvkm_client_name(chan), subc, class, mthd, - data); + nvkm_snprintbf(msg, sizeof(msg), nv04_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv04_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, chid, + chan ? chan->object.client->name : "unknown", + subc, class, mthd, data); } - nvkm_namedb_put(handle); + spin_unlock_irqrestore(&gr->lock, flags); } static int -nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_gr_init(struct nvkm_gr *base) { - struct nv04_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv04_gr_intr; - nv_engine(priv)->cclass = &nv04_gr_cclass; - nv_engine(priv)->sclass = nv04_gr_sclass; - spin_lock_init(&priv->lock); - return 0; -} - -static int -nv04_gr_init(struct nvkm_object *object) -{ - struct nvkm_engine *engine = nv_engine(object); - struct nv04_gr_priv *priv = (void *)engine; - int ret; - - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; + struct nv04_gr *gr = nv04_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; /* Enable PGRAPH interrupts */ - nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(priv, NV04_PGRAPH_VALID1, 0); - nv_wr32(priv, NV04_PGRAPH_VALID2, 0); - /*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000); + nvkm_wr32(device, NV03_PGRAPH_INTR, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nvkm_wr32(device, NV04_PGRAPH_VALID1, 0); + nvkm_wr32(device, NV04_PGRAPH_VALID2, 0); + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x000001FF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x1231c000); /*1231C000 blob, 001 haiku*/ /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x72111100); /*0x72111100 blob , 01 haiku*/ - /*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071); + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f071); /*haiku same*/ - /*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); /*haiku and blob 10d4*/ - nv_wr32(priv, NV04_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL , 0x10000100); - nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + nvkm_wr32(device, NV04_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL , 0x10000100); + nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); /* These don't belong here, they're part of a per-channel context */ - nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); return 0; } -struct nvkm_oclass -nv04_gr_oclass = { - .handle = NV_ENGINE(GR, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_gr_ctor, - .dtor = _nvkm_gr_dtor, - .init = nv04_gr_init, - .fini = _nvkm_gr_fini, - }, +static const struct nvkm_gr_func +nv04_gr = { + .init = nv04_gr_init, + .intr = nv04_gr_intr, + .chan_new = nv04_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0017, &nv04_gr_object }, /* chroma */ + { -1, -1, 0x0018, &nv04_gr_object }, /* pattern (nv01) */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x001c, &nv04_gr_object }, /* line */ + { -1, -1, 0x001d, &nv04_gr_object }, /* tri */ + { -1, -1, 0x001e, &nv04_gr_object }, /* rect */ + { -1, -1, 0x001f, &nv04_gr_object }, + { -1, -1, 0x0021, &nv04_gr_object }, + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0036, &nv04_gr_object }, + { -1, -1, 0x0037, &nv04_gr_object }, + { -1, -1, 0x0038, &nv04_gr_object }, /* dvd subpicture */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0042, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x0048, &nv04_gr_object }, + { -1, -1, 0x004a, &nv04_gr_object }, + { -1, -1, 0x004b, &nv04_gr_object }, + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x0053, &nv04_gr_object }, + { -1, -1, 0x0054, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0055, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0057, &nv04_gr_object }, /* chroma */ + { -1, -1, 0x0058, &nv04_gr_object }, /* surf_dst */ + { -1, -1, 0x0059, &nv04_gr_object }, /* surf_src */ + { -1, -1, 0x005a, &nv04_gr_object }, /* surf_color */ + { -1, -1, 0x005b, &nv04_gr_object }, /* surf_zeta */ + { -1, -1, 0x005c, &nv04_gr_object }, /* line */ + { -1, -1, 0x005d, &nv04_gr_object }, /* tri */ + { -1, -1, 0x005e, &nv04_gr_object }, /* rect */ + { -1, -1, 0x005f, &nv04_gr_object }, + { -1, -1, 0x0060, &nv04_gr_object }, + { -1, -1, 0x0061, &nv04_gr_object }, + { -1, -1, 0x0064, &nv04_gr_object }, /* iifc (nv05) */ + { -1, -1, 0x0065, &nv04_gr_object }, /* ifc (nv05) */ + { -1, -1, 0x0066, &nv04_gr_object }, /* sifc (nv05) */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0076, &nv04_gr_object }, + { -1, -1, 0x0077, &nv04_gr_object }, + {} + } }; + +int +nv04_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + struct nv04_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + spin_lock_init(&gr->lock); + *pgr = &gr->base; + + return nvkm_gr_ctor(&nv04_gr, device, index, 0x00001000, + true, &gr->base); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 389904eb603f..4542867fa9e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -21,13 +21,13 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <engine/gr.h> +#include "nv10.h" #include "regs.h" #include <core/client.h> -#include <core/device.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> #include <subdev/fb.h> struct pipe_state { @@ -386,14 +386,19 @@ static int nv17_gr_ctx_regs[] = { 0x00400a04, }; -struct nv10_gr_priv { +#define nv10_gr(p) container_of((p), struct nv10_gr, base) + +struct nv10_gr { struct nvkm_gr base; struct nv10_gr_chan *chan[32]; spinlock_t lock; }; +#define nv10_gr_chan(p) container_of((p), struct nv10_gr_chan, object) + struct nv10_gr_chan { - struct nvkm_object base; + struct nvkm_object object; + struct nv10_gr *gr; int chid; int nv10[ARRAY_SIZE(nv10_gr_ctx_regs)]; int nv17[ARRAY_SIZE(nv17_gr_ctx_regs)]; @@ -402,214 +407,151 @@ struct nv10_gr_chan { }; -static inline struct nv10_gr_priv * -nv10_gr_priv(struct nv10_gr_chan *chan) -{ - return (void *)nv_object(chan)->engine; -} - /******************************************************************************* * Graphics object classes ******************************************************************************/ -#define PIPE_SAVE(priv, state, addr) \ +#define PIPE_SAVE(gr, state, addr) \ do { \ int __i; \ - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \ + state[__i] = nvkm_rd32(device, NV10_PGRAPH_PIPE_DATA); \ } while (0) -#define PIPE_RESTORE(priv, state, addr) \ +#define PIPE_RESTORE(gr, state, addr) \ do { \ int __i; \ - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \ + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, state[__i]); \ } while (0) -static struct nvkm_oclass -nv10_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x004a, &nv04_gr_ofuncs }, /* gdi */ - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x005f, &nv04_gr_ofuncs }, /* blit */ - { 0x0062, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs }, /* blit */ - { 0x0093, &nv04_gr_ofuncs }, /* surf3d */ - { 0x0094, &nv04_gr_ofuncs }, /* ttri */ - { 0x0095, &nv04_gr_ofuncs }, /* mtri */ - { 0x0056, &nv04_gr_ofuncs }, /* celcius */ - {}, -}; - -static struct nvkm_oclass -nv15_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x004a, &nv04_gr_ofuncs }, /* gdi */ - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x005f, &nv04_gr_ofuncs }, /* blit */ - { 0x0062, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs }, /* blit */ - { 0x0093, &nv04_gr_ofuncs }, /* surf3d */ - { 0x0094, &nv04_gr_ofuncs }, /* ttri */ - { 0x0095, &nv04_gr_ofuncs }, /* mtri */ - { 0x0096, &nv04_gr_ofuncs }, /* celcius */ - {}, -}; - -static int -nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static void +nv17_gr_mthd_lma_window(struct nv10_gr_chan *chan, u32 mthd, u32 data) { - struct nv10_gr_chan *chan = (void *)object->parent; - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nvkm_device *device = chan->object.engine->subdev.device; + struct nvkm_gr *gr = &chan->gr->base; struct pipe_state *pipe = &chan->pipe_state; u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; u32 xfmode0, xfmode1; - u32 data = *(u32 *)args; int i; chan->lma_window[(mthd - 0x1638) / 4] = data; if (mthd != 0x1644) - return 0; + return; - nv04_gr_idle(priv); + nv04_gr_idle(gr); - PIPE_SAVE(priv, pipe_0x0040, 0x0040); - PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200); + PIPE_SAVE(device, pipe_0x0040, 0x0040); + PIPE_SAVE(device, pipe->pipe_0x0200, 0x0200); - PIPE_RESTORE(priv, chan->lma_window, 0x6790); + PIPE_RESTORE(device, chan->lma_window, 0x6790); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1); + xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0); + xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1); - PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400); - PIPE_SAVE(priv, pipe_0x64c0, 0x64c0); - PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0); - PIPE_SAVE(priv, pipe_0x6a80, 0x6a80); + PIPE_SAVE(device, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(device, pipe_0x64c0, 0x64c0); + PIPE_SAVE(device, pipe_0x6ab0, 0x6ab0); + PIPE_SAVE(device, pipe_0x6a80, 0x6a80); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, 0x10000000); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); - - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000008); - nv04_gr_idle(priv); + PIPE_RESTORE(device, pipe->pipe_0x0200, 0x0200); - PIPE_RESTORE(priv, pipe_0x0040, 0x0040); + nv04_gr_idle(gr); - nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1); + PIPE_RESTORE(device, pipe_0x0040, 0x0040); - PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0); - PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0); - PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80); - PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, xfmode1); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + PIPE_RESTORE(device, pipe_0x64c0, 0x64c0); + PIPE_RESTORE(device, pipe_0x6ab0, 0x6ab0); + PIPE_RESTORE(device, pipe_0x6a80, 0x6a80); + PIPE_RESTORE(device, pipe->pipe_0x4400, 0x4400); - nv04_gr_idle(priv); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - return 0; + nv04_gr_idle(gr); } -static int -nv17_gr_mthd_lma_enable(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static void +nv17_gr_mthd_lma_enable(struct nv10_gr_chan *chan, u32 mthd, u32 data) { - struct nv10_gr_chan *chan = (void *)object->parent; - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nvkm_device *device = chan->object.engine->subdev.device; + struct nvkm_gr *gr = &chan->gr->base; - nv04_gr_idle(priv); + nv04_gr_idle(gr); - nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); - nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000); - return 0; + nvkm_mask(device, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); + nvkm_mask(device, 0x4006b0, 0x08000000, 0x08000000); } -static struct nvkm_omthds -nv17_celcius_omthds[] = { - { 0x1638, 0x1638, nv17_gr_mthd_lma_window }, - { 0x163c, 0x163c, nv17_gr_mthd_lma_window }, - { 0x1640, 0x1640, nv17_gr_mthd_lma_window }, - { 0x1644, 0x1644, nv17_gr_mthd_lma_window }, - { 0x1658, 0x1658, nv17_gr_mthd_lma_enable }, - {} -}; +static bool +nv17_gr_mthd_celcius(struct nv10_gr_chan *chan, u32 mthd, u32 data) +{ + void (*func)(struct nv10_gr_chan *, u32, u32); + switch (mthd) { + case 0x1638 ... 0x1644: + func = nv17_gr_mthd_lma_window; break; + case 0x1658: func = nv17_gr_mthd_lma_enable; break; + default: + return false; + } + func(chan, mthd, data); + return true; +} -static struct nvkm_oclass -nv17_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x004a, &nv04_gr_ofuncs }, /* gdi */ - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x005f, &nv04_gr_ofuncs }, /* blit */ - { 0x0062, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs }, /* blit */ - { 0x0093, &nv04_gr_ofuncs }, /* surf3d */ - { 0x0094, &nv04_gr_ofuncs }, /* ttri */ - { 0x0095, &nv04_gr_ofuncs }, /* mtri */ - { 0x0099, &nv04_gr_ofuncs, nv17_celcius_omthds }, - {}, -}; +static bool +nv10_gr_mthd(struct nv10_gr_chan *chan, u8 class, u32 mthd, u32 data) +{ + bool (*func)(struct nv10_gr_chan *, u32, u32); + switch (class) { + case 0x99: func = nv17_gr_mthd_celcius; break; + default: + return false; + } + return func(chan, mthd, data); +} /******************************************************************************* * PGRAPH context ******************************************************************************/ static struct nv10_gr_chan * -nv10_gr_channel(struct nv10_gr_priv *priv) +nv10_gr_channel(struct nv10_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv10_gr_chan *chan = NULL; - if (nv_rd32(priv, 0x400144) & 0x00010000) { - int chid = nv_rd32(priv, 0x400148) >> 24; - if (chid < ARRAY_SIZE(priv->chan)) - chan = priv->chan[chid]; + if (nvkm_rd32(device, 0x400144) & 0x00010000) { + int chid = nvkm_rd32(device, 0x400148) >> 24; + if (chid < ARRAY_SIZE(gr->chan)) + chan = gr->chan[chid]; } return chan; } @@ -617,75 +559,78 @@ nv10_gr_channel(struct nv10_gr_priv *priv) static void nv10_gr_save_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = chan->gr; struct pipe_state *pipe = &chan->pipe_state; - - PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400); - PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200); - PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400); - PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800); - PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00); - PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000); - PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400); - PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800); - PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040); - PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000); + struct nvkm_device *device = gr->base.engine.subdev.device; + + PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(gr, pipe->pipe_0x0200, 0x0200); + PIPE_SAVE(gr, pipe->pipe_0x6400, 0x6400); + PIPE_SAVE(gr, pipe->pipe_0x6800, 0x6800); + PIPE_SAVE(gr, pipe->pipe_0x6c00, 0x6c00); + PIPE_SAVE(gr, pipe->pipe_0x7000, 0x7000); + PIPE_SAVE(gr, pipe->pipe_0x7400, 0x7400); + PIPE_SAVE(gr, pipe->pipe_0x7800, 0x7800); + PIPE_SAVE(gr, pipe->pipe_0x0040, 0x0040); + PIPE_SAVE(gr, pipe->pipe_0x0000, 0x0000); } static void nv10_gr_load_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = chan->gr; struct pipe_state *pipe = &chan->pipe_state; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 xfmode0, xfmode1; int i; - nv04_gr_idle(priv); + nv04_gr_idle(&gr->base); /* XXX check haiku comments */ - xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1); - nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0); + xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, 0x10000000); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000008); - PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200); - nv04_gr_idle(priv); + PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200); + nv04_gr_idle(&gr->base); /* restore XFMODE */ - nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1); - PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400); - PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800); - PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00); - PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000); - PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400); - PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800); - PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400); - PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000); - PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040); - nv04_gr_idle(priv); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, xfmode1); + PIPE_RESTORE(gr, pipe->pipe_0x6400, 0x6400); + PIPE_RESTORE(gr, pipe->pipe_0x6800, 0x6800); + PIPE_RESTORE(gr, pipe->pipe_0x6c00, 0x6c00); + PIPE_RESTORE(gr, pipe->pipe_0x7000, 0x7000); + PIPE_RESTORE(gr, pipe->pipe_0x7400, 0x7400); + PIPE_RESTORE(gr, pipe->pipe_0x7800, 0x7800); + PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400); + PIPE_RESTORE(gr, pipe->pipe_0x0000, 0x0000); + PIPE_RESTORE(gr, pipe->pipe_0x0040, 0x0040); + nv04_gr_idle(&gr->base); } static void nv10_gr_create_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = chan->gr; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct pipe_state *pipe_state = &chan->pipe_state; u32 *pipe_state_addr; int i; @@ -698,7 +643,7 @@ nv10_gr_create_pipe(struct nv10_gr_chan *chan) u32 *__end_addr = pipe_state->pipe_##addr + \ ARRAY_SIZE(pipe_state->pipe_##addr); \ if (pipe_state_addr != __end_addr) \ - nv_error(priv, "incomplete pipe init for 0x%x : %p/%p\n", \ + nvkm_error(subdev, "incomplete pipe init for 0x%x : %p/%p\n", \ addr, pipe_state_addr, __end_addr); \ } while (0) #define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value @@ -838,33 +783,36 @@ nv10_gr_create_pipe(struct nv10_gr_chan *chan) } static int -nv10_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg) +nv10_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg) { + struct nvkm_subdev *subdev = &gr->base.engine.subdev; int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) { if (nv10_gr_ctx_regs[i] == reg) return i; } - nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg); + nvkm_error(subdev, "unknown offset nv10_ctx_regs %d\n", reg); return -1; } static int -nv17_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg) +nv17_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg) { + struct nvkm_subdev *subdev = &gr->base.engine.subdev; int i; for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) { if (nv17_gr_ctx_regs[i] == reg) return i; } - nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg); + nvkm_error(subdev, "unknown offset nv17_ctx_regs %d\n", reg); return -1; } static void nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = chan->gr; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; u32 ctx_user, ctx_switch[5]; int i, subchan = -1; @@ -876,7 +824,7 @@ nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) /* Look for a celsius object */ for (i = 0; i < 8; i++) { - int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; + int class = nvkm_rd32(device, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; if (class == 0x56 || class == 0x96 || class == 0x99) { subchan = i; @@ -888,159 +836,183 @@ nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) return; /* Save the current ctx object */ - ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER); + ctx_user = nvkm_rd32(device, NV10_PGRAPH_CTX_USER); for (i = 0; i < 5; i++) - ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i)); + ctx_switch[i] = nvkm_rd32(device, NV10_PGRAPH_CTX_SWITCH(i)); /* Save the FIFO state */ - st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2); - st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL); - st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH); - fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR); + st2 = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2); + st2_dl = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2_DL); + st2_dh = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2_DH); + fifo_ptr = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR); for (i = 0; i < ARRAY_SIZE(fifo); i++) - fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i); + fifo[i] = nvkm_rd32(device, 0x4007a0 + 4 * i); /* Switch to the celsius subchannel */ for (i = 0; i < 5; i++) - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), - nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i))); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(i), + nvkm_rd32(device, NV10_PGRAPH_CTX_CACHE(subchan, i))); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); /* Inject NV10TCL_DMA_VTXBUF */ - nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, 0x2c000000 | chid << 20 | subchan << 16 | 0x18c); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst); - nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DL, inst); + nvkm_mask(device, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); /* Restore the FIFO state */ for (i = 0; i < ARRAY_SIZE(fifo); i++) - nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]); + nvkm_wr32(device, 0x4007a0 + 4 * i, fifo[i]); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, st2); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); /* Restore the current ctx object */ for (i = 0; i < 5; i++) - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); - nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); + nvkm_wr32(device, NV10_PGRAPH_CTX_USER, ctx_user); } static int nv10_gr_load_context(struct nv10_gr_chan *chan, int chid) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = chan->gr; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 inst; int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) - nv_wr32(priv, nv10_gr_ctx_regs[i], chan->nv10[i]); + nvkm_wr32(device, nv10_gr_ctx_regs[i], chan->nv10[i]); - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { + if (device->card_type >= NV_11 && device->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) - nv_wr32(priv, nv17_gr_ctx_regs[i], chan->nv17[i]); + nvkm_wr32(device, nv17_gr_ctx_regs[i], chan->nv17[i]); } nv10_gr_load_pipe(chan); - inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff; + inst = nvkm_rd32(device, NV10_PGRAPH_GLOBALSTATE1) & 0xffff; nv10_gr_load_dma_vtxbuf(chan, chid, inst); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24); - nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nvkm_mask(device, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000); return 0; } static int nv10_gr_unload_context(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = chan->gr; + struct nvkm_device *device = gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) - chan->nv10[i] = nv_rd32(priv, nv10_gr_ctx_regs[i]); + chan->nv10[i] = nvkm_rd32(device, nv10_gr_ctx_regs[i]); - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { + if (device->card_type >= NV_11 && device->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) - chan->nv17[i] = nv_rd32(priv, nv17_gr_ctx_regs[i]); + chan->nv17[i] = nvkm_rd32(device, nv17_gr_ctx_regs[i]); } nv10_gr_save_pipe(chan); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000000); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); return 0; } static void -nv10_gr_context_switch(struct nv10_gr_priv *priv) +nv10_gr_context_switch(struct nv10_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv10_gr_chan *prev = NULL; struct nv10_gr_chan *next = NULL; - unsigned long flags; int chid; - spin_lock_irqsave(&priv->lock, flags); - nv04_gr_idle(priv); + nv04_gr_idle(&gr->base); /* If previous context is valid, we need to save it */ - prev = nv10_gr_channel(priv); + prev = nv10_gr_channel(gr); if (prev) nv10_gr_unload_context(prev); /* load context for next channel */ - chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; - next = priv->chan[chid]; + chid = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; + next = gr->chan[chid]; if (next) nv10_gr_load_context(next, chid); +} + +static int +nv10_gr_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nv10_gr_chan *chan = nv10_gr_chan(object); + struct nv10_gr *gr = chan->gr; + struct nvkm_device *device = gr->base.engine.subdev.device; + unsigned long flags; - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&gr->lock, flags); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + if (nv10_gr_channel(gr) == chan) + nv10_gr_unload_context(chan); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); + return 0; +} + +static void * +nv10_gr_chan_dtor(struct nvkm_object *object) +{ + struct nv10_gr_chan *chan = nv10_gr_chan(object); + struct nv10_gr *gr = chan->gr; + unsigned long flags; + + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = NULL; + spin_unlock_irqrestore(&gr->lock, flags); + return chan; } +static const struct nvkm_object_func +nv10_gr_chan = { + .dtor = nv10_gr_chan_dtor, + .fini = nv10_gr_chan_fini, +}; + #define NV_WRITE_CTX(reg, val) do { \ - int offset = nv10_gr_ctx_regs_find_offset(priv, reg); \ + int offset = nv10_gr_ctx_regs_find_offset(gr, reg); \ if (offset > 0) \ chan->nv10[offset] = val; \ } while (0) #define NV17_WRITE_CTX(reg, val) do { \ - int offset = nv17_gr_ctx_regs_find_offset(priv, reg); \ + int offset = nv17_gr_ctx_regs_find_offset(gr, reg); \ if (offset > 0) \ chan->nv17[offset] = val; \ } while (0) -static int -nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - struct nvkm_fifo_chan *fifo = (void *)parent; - struct nv10_gr_priv *priv = (void *)engine; + struct nv10_gr *gr = nv10_gr(base); struct nv10_gr_chan *chan; + struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long flags; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - spin_lock_irqsave(&priv->lock, flags); - if (priv->chan[fifo->chid]) { - *pobject = nv_object(priv->chan[fifo->chid]); - atomic_inc(&(*pobject)->refcount); - spin_unlock_irqrestore(&priv->lock, flags); - nvkm_object_destroy(&chan->base); - return 1; - } + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv10_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; NV_WRITE_CTX(0x00400e88, 0x08000000); NV_WRITE_CTX(0x00400e9c, 0x4b7fffff); @@ -1049,12 +1021,11 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, NV_WRITE_CTX(0x00400e14, 0x00001000); NV_WRITE_CTX(0x00400e30, 0x00080008); NV_WRITE_CTX(0x00400e34, 0x00080008); - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { + if (device->card_type >= NV_11 && device->chipset >= 0x17) { /* is it really needed ??? */ NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4, - nv_rd32(priv, NV10_PGRAPH_DEBUG_4)); - NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0)); + nvkm_rd32(device, NV10_PGRAPH_DEBUG_4)); + NV17_WRITE_CTX(0x004006b0, nvkm_rd32(device, 0x004006b0)); NV17_WRITE_CTX(0x00400eac, 0x0fff0000); NV17_WRITE_CTX(0x00400eb0, 0x0fff0000); NV17_WRITE_CTX(0x00400ec0, 0x00000080); @@ -1064,74 +1035,32 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv10_gr_create_pipe(chan); - priv->chan[fifo->chid] = chan; - chan->chid = fifo->chid; - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = chan; + spin_unlock_irqrestore(&gr->lock, flags); return 0; } -static void -nv10_gr_context_dtor(struct nvkm_object *object) -{ - struct nv10_gr_priv *priv = (void *)object->engine; - struct nv10_gr_chan *chan = (void *)object; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - priv->chan[chan->chid] = NULL; - spin_unlock_irqrestore(&priv->lock, flags); - - nvkm_object_destroy(&chan->base); -} - -static int -nv10_gr_context_fini(struct nvkm_object *object, bool suspend) -{ - struct nv10_gr_priv *priv = (void *)object->engine; - struct nv10_gr_chan *chan = (void *)object; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (nv10_gr_channel(priv) == chan) - nv10_gr_unload_context(chan); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->lock, flags); - - return nvkm_object_fini(&chan->base, suspend); -} - -static struct nvkm_oclass -nv10_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_gr_context_ctor, - .dtor = nv10_gr_context_dtor, - .init = nvkm_object_init, - .fini = nv10_gr_context_fini, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ -static void -nv10_gr_tile_prog(struct nvkm_engine *engine, int i) +void +nv10_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) { - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *pfifo = nvkm_fifo(engine); - struct nv10_gr_priv *priv = (void *)engine; + struct nv10_gr *gr = nv10_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; unsigned long flags; - pfifo->pause(pfifo, &flags); - nv04_gr_idle(priv); + nvkm_fifo_pause(fifo, &flags); + nv04_gr_idle(&gr->base); - nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV10_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV10_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV10_PGRAPH_TILE(i), tile->addr); - pfifo->start(pfifo, &flags); + nvkm_fifo_start(fifo, &flags); } const struct nvkm_bitfield nv10_gr_intr_name[] = { @@ -1148,168 +1077,145 @@ const struct nvkm_bitfield nv10_gr_nstatus[] = { {} }; -static void -nv10_gr_intr(struct nvkm_subdev *subdev) +void +nv10_gr_intr(struct nvkm_gr *base) { - struct nv10_gr_priv *priv = (void *)subdev; - struct nv10_gr_chan *chan = NULL; - struct nvkm_namedb *namedb = NULL; - struct nvkm_handle *handle = NULL; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + struct nv10_gr *gr = nv10_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x01f00000) >> 20; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; + char msg[128], src[128], sta[128]; + struct nv10_gr_chan *chan; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - chan = priv->chan[chid]; - if (chan) - namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&gr->lock, flags); + chan = gr->chan[chid]; if (stat & NV_PGRAPH_INTR_ERROR) { if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { - handle = nvkm_namedb_get_class(namedb, class); - if (handle && !nv_call(handle->object, mthd, data)) + if (!nv10_gr_mthd(chan, class, mthd, data)) show &= ~NV_PGRAPH_INTR_ERROR; } } if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + nvkm_wr32(device, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - nv10_gr_context_switch(priv); + nv10_gr_context_switch(gr); } - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); - nvkm_bitfield_print(nv10_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv10_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(priv, - "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, nvkm_client_name(chan), subc, class, mthd, - data); + nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, chid, + chan ? chan->object.client->name : "unknown", + subc, class, mthd, data); } - nvkm_namedb_put(handle); + spin_unlock_irqrestore(&gr->lock, flags); } -static int -nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv10_gr_init(struct nvkm_gr *base) { - struct nv10_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv10_gr_intr; - nv_engine(priv)->cclass = &nv10_gr_cclass; - - if (nv_device(priv)->chipset <= 0x10) - nv_engine(priv)->sclass = nv10_gr_sclass; - else - if (nv_device(priv)->chipset < 0x17 || - nv_device(priv)->card_type < NV_11) - nv_engine(priv)->sclass = nv15_gr_sclass; - else - nv_engine(priv)->sclass = nv17_gr_sclass; - - nv_engine(priv)->tile_prog = nv10_gr_tile_prog; - spin_lock_init(&priv->lock); - return 0; -} - -static void -nv10_gr_dtor(struct nvkm_object *object) -{ - struct nv10_gr_priv *priv = (void *)object; - nvkm_gr_destroy(&priv->base); -} - -static int -nv10_gr_init(struct nvkm_object *object) -{ - struct nvkm_engine *engine = nv_engine(object); - struct nvkm_fb *pfb = nvkm_fb(object); - struct nv10_gr_priv *priv = (void *)engine; - int ret, i; - - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700); - /* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ - nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); - - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000); - nv_wr32(priv, 0x400a10, 0x03ff3fb6); - nv_wr32(priv, 0x400838, 0x002f8684); - nv_wr32(priv, 0x40083c, 0x00115f3f); - nv_wr32(priv, 0x4006b0, 0x40000020); + struct nv10_gr *gr = nv10_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x00118700); + /* nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); + + if (device->card_type >= NV_11 && device->chipset >= 0x17) { + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x1f000000); + nvkm_wr32(device, 0x400a10, 0x03ff3fb6); + nvkm_wr32(device, 0x400838, 0x002f8684); + nvkm_wr32(device, 0x40083c, 0x00115f3f); + nvkm_wr32(device, 0x4006b0, 0x40000020); } else { - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000); } - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) - engine->tile_prog(engine, i); - - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_STATE, 0xFFFFFFFF); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); return 0; } -static int -nv10_gr_fini(struct nvkm_object *object, bool suspend) +int +nv10_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) { - struct nv10_gr_priv *priv = (void *)object; - return nvkm_gr_fini(&priv->base, suspend); + struct nv10_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + spin_lock_init(&gr->lock); + *pgr = &gr->base; + + return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base); } -struct nvkm_oclass -nv10_gr_oclass = { - .handle = NV_ENGINE(GR, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_gr_ctor, - .dtor = nv10_gr_dtor, - .init = nv10_gr_init, - .fini = nv10_gr_fini, - }, +static const struct nvkm_gr_func +nv10_gr = { + .init = nv10_gr_init, + .intr = nv10_gr_intr, + .tile = nv10_gr_tile, + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0056, &nv04_gr_object }, /* celcius */ + {} + } }; + +int +nv10_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv10_gr_new_(&nv10_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h new file mode 100644 index 000000000000..d7c3d86cc99d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h @@ -0,0 +1,13 @@ +#ifndef __NV10_GR_H__ +#define __NV10_GR_H__ +#include "priv.h" + +int nv10_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index, + struct nvkm_gr **); +int nv10_gr_init(struct nvkm_gr *); +void nv10_gr_intr(struct nvkm_gr *); +void nv10_gr_tile(struct nvkm_gr *, int, struct nvkm_fb_tile *); + +int nv10_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c new file mode 100644 index 000000000000..3e2c6856b4c4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragr) 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "nv10.h" + +static const struct nvkm_gr_func +nv15_gr = { + .init = nv10_gr_init, + .intr = nv10_gr_intr, + .tile = nv10_gr_tile, + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + {} + } +}; + +int +nv15_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv10_gr_new_(&nv15_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c new file mode 100644 index 000000000000..12437d085a73 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr> + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragr) 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "nv10.h" + +static const struct nvkm_gr_func +nv17_gr = { + .init = nv10_gr_init, + .intr = nv10_gr_intr, + .tile = nv10_gr_tile, + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0099, &nv04_gr_object }, + {} + } +}; + +int +nv17_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv10_gr_new_(&nv17_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 1713ffb669e8..5caef65d3c6e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -2,375 +2,374 @@ #include "regs.h" #include <core/client.h> -#include <core/device.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> #include <subdev/fb.h> #include <subdev/timer.h> /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -static struct nvkm_oclass -nv20_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */ - { 0x0097, &nv04_gr_ofuncs, NULL }, /* kelvin */ - { 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - {}, -}; +int +nv20_gr_chan_init(struct nvkm_object *object) +{ + struct nv20_gr_chan *chan = nv20_gr_chan(object); + struct nv20_gr *gr = chan->gr; + u32 inst = nvkm_memory_addr(chan->inst); -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ + nvkm_kmap(gr->ctxtab); + nvkm_wo32(gr->ctxtab, chan->chid * 4, inst >> 4); + nvkm_done(gr->ctxtab); + return 0; +} + +int +nv20_gr_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nv20_gr_chan *chan = nv20_gr_chan(object); + struct nv20_gr *gr = chan->gr; + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 inst = nvkm_memory_addr(chan->inst); + int chid = -1; + + nvkm_mask(device, 0x400720, 0x00000001, 0x00000000); + if (nvkm_rd32(device, 0x400144) & 0x00010000) + chid = (nvkm_rd32(device, 0x400148) & 0x1f000000) >> 24; + if (chan->chid == chid) { + nvkm_wr32(device, 0x400784, inst >> 4); + nvkm_wr32(device, 0x400788, 0x00000002); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x400700)) + break; + ); + nvkm_wr32(device, 0x400144, 0x10000000); + nvkm_mask(device, 0x400148, 0xff000000, 0x1f000000); + } + nvkm_mask(device, 0x400720, 0x00000001, 0x00000001); + + nvkm_kmap(gr->ctxtab); + nvkm_wo32(gr->ctxtab, chan->chid * 4, 0x00000000); + nvkm_done(gr->ctxtab); + return 0; +} + +void * +nv20_gr_chan_dtor(struct nvkm_object *object) +{ + struct nv20_gr_chan *chan = nv20_gr_chan(object); + nvkm_memory_del(&chan->inst); + return chan; +} + +static const struct nvkm_object_func +nv20_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, +}; static int -nv20_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv20_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x37f0, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv20_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x37f0, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x033c, 0xffff0000); - nv_wo32(chan, 0x03a0, 0x0fff0000); - nv_wo32(chan, 0x03a4, 0x0fff0000); - nv_wo32(chan, 0x047c, 0x00000101); - nv_wo32(chan, 0x0490, 0x00000111); - nv_wo32(chan, 0x04a8, 0x44400000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0000, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x033c, 0xffff0000); + nvkm_wo32(chan->inst, 0x03a0, 0x0fff0000); + nvkm_wo32(chan->inst, 0x03a4, 0x0fff0000); + nvkm_wo32(chan->inst, 0x047c, 0x00000101); + nvkm_wo32(chan->inst, 0x0490, 0x00000111); + nvkm_wo32(chan->inst, 0x04a8, 0x44400000); for (i = 0x04d4; i <= 0x04e0; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x04f4; i <= 0x0500; i += 4) - nv_wo32(chan, i, 0x00080000); + nvkm_wo32(chan->inst, i, 0x00080000); for (i = 0x050c; i <= 0x0518; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x051c; i <= 0x0528; i += 4) - nv_wo32(chan, i, 0x000105b8); + nvkm_wo32(chan->inst, i, 0x000105b8); for (i = 0x052c; i <= 0x0538; i += 4) - nv_wo32(chan, i, 0x00080008); + nvkm_wo32(chan->inst, i, 0x00080008); for (i = 0x055c; i <= 0x0598; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x05a4, 0x4b7fffff); - nv_wo32(chan, 0x05fc, 0x00000001); - nv_wo32(chan, 0x0604, 0x00004000); - nv_wo32(chan, 0x0610, 0x00000001); - nv_wo32(chan, 0x0618, 0x00040000); - nv_wo32(chan, 0x061c, 0x00010000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x05a4, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x05fc, 0x00000001); + nvkm_wo32(chan->inst, 0x0604, 0x00004000); + nvkm_wo32(chan->inst, 0x0610, 0x00000001); + nvkm_wo32(chan->inst, 0x0618, 0x00040000); + nvkm_wo32(chan->inst, 0x061c, 0x00010000); for (i = 0x1c1c; i <= 0x248c; i += 16) { - nv_wo32(chan, (i + 0), 0x10700ff9); - nv_wo32(chan, (i + 4), 0x0436086c); - nv_wo32(chan, (i + 8), 0x000c001b); + nvkm_wo32(chan->inst, (i + 0), 0x10700ff9); + nvkm_wo32(chan->inst, (i + 4), 0x0436086c); + nvkm_wo32(chan->inst, (i + 8), 0x000c001b); } - nv_wo32(chan, 0x281c, 0x3f800000); - nv_wo32(chan, 0x2830, 0x3f800000); - nv_wo32(chan, 0x285c, 0x40000000); - nv_wo32(chan, 0x2860, 0x3f800000); - nv_wo32(chan, 0x2864, 0x3f000000); - nv_wo32(chan, 0x286c, 0x40000000); - nv_wo32(chan, 0x2870, 0x3f800000); - nv_wo32(chan, 0x2878, 0xbf800000); - nv_wo32(chan, 0x2880, 0xbf800000); - nv_wo32(chan, 0x34a4, 0x000fe000); - nv_wo32(chan, 0x3530, 0x000003f8); - nv_wo32(chan, 0x3540, 0x002fe000); + nvkm_wo32(chan->inst, 0x281c, 0x3f800000); + nvkm_wo32(chan->inst, 0x2830, 0x3f800000); + nvkm_wo32(chan->inst, 0x285c, 0x40000000); + nvkm_wo32(chan->inst, 0x2860, 0x3f800000); + nvkm_wo32(chan->inst, 0x2864, 0x3f000000); + nvkm_wo32(chan->inst, 0x286c, 0x40000000); + nvkm_wo32(chan->inst, 0x2870, 0x3f800000); + nvkm_wo32(chan->inst, 0x2878, 0xbf800000); + nvkm_wo32(chan->inst, 0x2880, 0xbf800000); + nvkm_wo32(chan->inst, 0x34a4, 0x000fe000); + nvkm_wo32(chan->inst, 0x3530, 0x000003f8); + nvkm_wo32(chan->inst, 0x3540, 0x002fe000); for (i = 0x355c; i <= 0x3578; i += 4) - nv_wo32(chan, i, 0x001c527c); - return 0; -} - -int -nv20_gr_context_init(struct nvkm_object *object) -{ - struct nv20_gr_priv *priv = (void *)object->engine; - struct nv20_gr_chan *chan = (void *)object; - int ret; - - ret = nvkm_gr_context_init(&chan->base); - if (ret) - return ret; - - nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); + nvkm_wo32(chan->inst, i, 0x001c527c); + nvkm_done(chan->inst); return 0; } -int -nv20_gr_context_fini(struct nvkm_object *object, bool suspend) -{ - struct nv20_gr_priv *priv = (void *)object->engine; - struct nv20_gr_chan *chan = (void *)object; - int chid = -1; - - nv_mask(priv, 0x400720, 0x00000001, 0x00000000); - if (nv_rd32(priv, 0x400144) & 0x00010000) - chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24; - if (chan->chid == chid) { - nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4); - nv_wr32(priv, 0x400788, 0x00000002); - nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); - nv_wr32(priv, 0x400144, 0x10000000); - nv_mask(priv, 0x400148, 0xff000000, 0x1f000000); - } - nv_mask(priv, 0x400720, 0x00000001, 0x00000001); - - nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000); - return nvkm_gr_context_fini(&chan->base, suspend); -} - -static struct nvkm_oclass -nv20_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x20), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv20_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ void -nv20_gr_tile_prog(struct nvkm_engine *engine, int i) +nv20_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) { - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *pfifo = nvkm_fifo(engine); - struct nv20_gr_priv *priv = (void *)engine; + struct nv20_gr *gr = nv20_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; unsigned long flags; - pfifo->pause(pfifo, &flags); - nv04_gr_idle(priv); + nvkm_fifo_pause(fifo, &flags); + nv04_gr_idle(&gr->base); - nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->limit); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->pitch); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->addr); - if (nv_device(engine)->chipset != 0x34) { - nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp); + if (device->chipset != 0x34) { + nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->zcomp); } - pfifo->start(pfifo, &flags); + nvkm_fifo_start(fifo, &flags); } void -nv20_gr_intr(struct nvkm_subdev *subdev) +nv20_gr_intr(struct nvkm_gr *base) { - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle; - struct nv20_gr_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + struct nv20_gr *gr = nv20_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_fifo_chan *chan; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x01f00000) >> 20; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; + char msg[128], src[128], sta[128]; + unsigned long flags; - engctx = nvkm_engctx_get(engine, chid); - if (stat & NV_PGRAPH_INTR_ERROR) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - handle = nvkm_handle_get_class(engctx, class); - if (handle && !nv_call(handle->object, mthd, data)) - show &= ~NV_PGRAPH_INTR_ERROR; - nvkm_handle_put(handle); - } - } + chan = nvkm_fifo_chan_chid(device->fifo, chid, &flags); - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); - nvkm_bitfield_print(nv10_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv10_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(priv, - "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, nvkm_client_name(engctx), subc, class, mthd, - data); + nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, chid, + chan ? chan->object.client->name : "unknown", + subc, class, mthd, data); } - nvkm_engctx_put(engctx); -} - -static int -nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv20_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv20_gr_cclass; - nv_engine(priv)->sclass = nv20_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; - return 0; + nvkm_fifo_chan_put(device->fifo, flags, &chan); } -void -nv20_gr_dtor(struct nvkm_object *object) +int +nv20_gr_oneinit(struct nvkm_gr *base) { - struct nv20_gr_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->ctxtab); - nvkm_gr_destroy(&priv->base); + struct nv20_gr *gr = nv20_gr(base); + return nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 32 * 4, 16, + true, &gr->ctxtab); } int -nv20_gr_init(struct nvkm_object *object) +nv20_gr_init(struct nvkm_gr *base) { - struct nvkm_engine *engine = nv_engine(object); - struct nv20_gr_priv *priv = (void *)engine; - struct nvkm_fb *pfb = nvkm_fb(object); + struct nv20_gr *gr = nv20_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; u32 tmp, vramsz; - int ret, i; - - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; + int i; - nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4); + nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, + nvkm_memory_addr(gr->ctxtab) >> 4); - if (nv_device(priv)->chipset == 0x20) { - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000); + if (device->chipset == 0x20) { + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x003d0000); for (i = 0; i < 15; i++) - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000); - nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x400700)) + break; + ); } else { - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x02c80000); for (i = 0; i < 32; i++) - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000); - nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x400700)) + break; + ); } - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000); - nv_wr32(priv, 0x40009C , 0x00000040); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x00118700); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000); + nvkm_wr32(device, 0x40009C , 0x00000040); - if (nv_device(priv)->chipset >= 0x25) { - nv_wr32(priv, 0x400890, 0x00a8cfff); - nv_wr32(priv, 0x400610, 0x304B1FB6); - nv_wr32(priv, 0x400B80, 0x1cbd3883); - nv_wr32(priv, 0x400B84, 0x44000000); - nv_wr32(priv, 0x400098, 0x40000080); - nv_wr32(priv, 0x400B88, 0x000000ff); + if (device->chipset >= 0x25) { + nvkm_wr32(device, 0x400890, 0x00a8cfff); + nvkm_wr32(device, 0x400610, 0x304B1FB6); + nvkm_wr32(device, 0x400B80, 0x1cbd3883); + nvkm_wr32(device, 0x400B84, 0x44000000); + nvkm_wr32(device, 0x400098, 0x40000080); + nvkm_wr32(device, 0x400B88, 0x000000ff); } else { - nv_wr32(priv, 0x400880, 0x0008c7df); - nv_wr32(priv, 0x400094, 0x00000005); - nv_wr32(priv, 0x400B80, 0x45eae20e); - nv_wr32(priv, 0x400B84, 0x24000000); - nv_wr32(priv, 0x400098, 0x00000040); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030); + nvkm_wr32(device, 0x400880, 0x0008c7df); + nvkm_wr32(device, 0x400094, 0x00000005); + nvkm_wr32(device, 0x400B80, 0x45eae20e); + nvkm_wr32(device, 0x400B84, 0x24000000); + nvkm_wr32(device, 0x400098, 0x00000040); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00E00038); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000030); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00E10038); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000030); } - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) - engine->tile_prog(engine, i); + nvkm_wr32(device, 0x4009a0, nvkm_rd32(device, 0x100324)); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, nvkm_rd32(device, 0x100324)); - nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324)); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324)); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nvkm_wr32(device, NV10_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); - - tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00; - nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); - tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100; - nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); + tmp = nvkm_rd32(device, NV10_PGRAPH_SURFACE) & 0x0007ff00; + nvkm_wr32(device, NV10_PGRAPH_SURFACE, tmp); + tmp = nvkm_rd32(device, NV10_PGRAPH_SURFACE) | 0x00020100; + nvkm_wr32(device, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ - vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; - nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200)); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x400820, 0); - nv_wr32(priv, 0x400824, 0); - nv_wr32(priv, 0x400864, vramsz - 1); - nv_wr32(priv, 0x400868, vramsz - 1); + vramsz = device->func->resource_size(device, 1) - 1; + nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x400820, 0); + nvkm_wr32(device, 0x400824, 0); + nvkm_wr32(device, 0x400864, vramsz - 1); + nvkm_wr32(device, 0x400868, vramsz - 1); /* interesting.. the below overwrites some of the tile setup above.. */ - nv_wr32(priv, 0x400B20, 0x00000000); - nv_wr32(priv, 0x400B04, 0xFFFFFFFF); + nvkm_wr32(device, 0x400B20, 0x00000000); + nvkm_wr32(device, 0x400B04, 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); return 0; } -struct nvkm_oclass -nv20_gr_oclass = { - .handle = NV_ENGINE(GR, 0x20), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv20_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv20_gr_init, - .fini = _nvkm_gr_fini, - }, +void * +nv20_gr_dtor(struct nvkm_gr *base) +{ + struct nv20_gr *gr = nv20_gr(base); + nvkm_memory_del(&gr->ctxtab); + return gr; +} + +int +nv20_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct nv20_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + + return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base); +} + +static const struct nvkm_gr_func +nv20_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv20_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv20_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + { -1, -1, 0x0097, &nv04_gr_object }, /* kelvin */ + { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + {} + } }; + +int +nv20_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv20_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h index ac4dc048fed1..cdf4501e3798 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h @@ -1,26 +1,33 @@ #ifndef __NV20_GR_H__ #define __NV20_GR_H__ -#include <engine/gr.h> +#define nv20_gr(p) container_of((p), struct nv20_gr, base) +#include "priv.h" -struct nv20_gr_priv { +struct nv20_gr { struct nvkm_gr base; - struct nvkm_gpuobj *ctxtab; + struct nvkm_memory *ctxtab; }; -struct nv20_gr_chan { - struct nvkm_gr_chan base; - int chid; -}; +int nv20_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, + int, struct nvkm_gr **); +void *nv20_gr_dtor(struct nvkm_gr *); +int nv20_gr_oneinit(struct nvkm_gr *); +int nv20_gr_init(struct nvkm_gr *); +void nv20_gr_intr(struct nvkm_gr *); +void nv20_gr_tile(struct nvkm_gr *, int, struct nvkm_fb_tile *); -extern struct nvkm_oclass nv25_gr_sclass[]; -int nv20_gr_context_init(struct nvkm_object *); -int nv20_gr_context_fini(struct nvkm_object *, bool); +int nv30_gr_init(struct nvkm_gr *); -void nv20_gr_tile_prog(struct nvkm_engine *, int); -void nv20_gr_intr(struct nvkm_subdev *); +#define nv20_gr_chan(p) container_of((p), struct nv20_gr_chan, object) -void nv20_gr_dtor(struct nvkm_object *); -int nv20_gr_init(struct nvkm_object *); +struct nv20_gr_chan { + struct nvkm_object object; + struct nv20_gr *gr; + int chid; + struct nvkm_memory *inst; +}; -int nv30_gr_init(struct nvkm_object *); +void *nv20_gr_chan_dtor(struct nvkm_object *); +int nv20_gr_chan_init(struct nvkm_object *); +int nv20_gr_chan_fini(struct nvkm_object *, bool); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index bc362519cebb..6c4a00819b4b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -1,158 +1,134 @@ #include "nv20.h" #include "regs.h" +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -struct nvkm_oclass -nv25_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */ - { 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0597, &nv04_gr_ofuncs, NULL }, /* kelvin */ - {}, +static const struct nvkm_object_func +nv25_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv25_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv25_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x3724, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv25_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x3724, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x035c, 0xffff0000); - nv_wo32(chan, 0x03c0, 0x0fff0000); - nv_wo32(chan, 0x03c4, 0x0fff0000); - nv_wo32(chan, 0x049c, 0x00000101); - nv_wo32(chan, 0x04b0, 0x00000111); - nv_wo32(chan, 0x04c8, 0x00000080); - nv_wo32(chan, 0x04cc, 0xffff0000); - nv_wo32(chan, 0x04d0, 0x00000001); - nv_wo32(chan, 0x04e4, 0x44400000); - nv_wo32(chan, 0x04fc, 0x4b800000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x035c, 0xffff0000); + nvkm_wo32(chan->inst, 0x03c0, 0x0fff0000); + nvkm_wo32(chan->inst, 0x03c4, 0x0fff0000); + nvkm_wo32(chan->inst, 0x049c, 0x00000101); + nvkm_wo32(chan->inst, 0x04b0, 0x00000111); + nvkm_wo32(chan->inst, 0x04c8, 0x00000080); + nvkm_wo32(chan->inst, 0x04cc, 0xffff0000); + nvkm_wo32(chan->inst, 0x04d0, 0x00000001); + nvkm_wo32(chan->inst, 0x04e4, 0x44400000); + nvkm_wo32(chan->inst, 0x04fc, 0x4b800000); for (i = 0x0510; i <= 0x051c; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x0530; i <= 0x053c; i += 4) - nv_wo32(chan, i, 0x00080000); + nvkm_wo32(chan->inst, i, 0x00080000); for (i = 0x0548; i <= 0x0554; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0558; i <= 0x0564; i += 4) - nv_wo32(chan, i, 0x000105b8); + nvkm_wo32(chan->inst, i, 0x000105b8); for (i = 0x0568; i <= 0x0574; i += 4) - nv_wo32(chan, i, 0x00080008); + nvkm_wo32(chan->inst, i, 0x00080008); for (i = 0x0598; i <= 0x05d4; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x05e0, 0x4b7fffff); - nv_wo32(chan, 0x0620, 0x00000080); - nv_wo32(chan, 0x0624, 0x30201000); - nv_wo32(chan, 0x0628, 0x70605040); - nv_wo32(chan, 0x062c, 0xb0a09080); - nv_wo32(chan, 0x0630, 0xf0e0d0c0); - nv_wo32(chan, 0x0664, 0x00000001); - nv_wo32(chan, 0x066c, 0x00004000); - nv_wo32(chan, 0x0678, 0x00000001); - nv_wo32(chan, 0x0680, 0x00040000); - nv_wo32(chan, 0x0684, 0x00010000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x05e0, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x0620, 0x00000080); + nvkm_wo32(chan->inst, 0x0624, 0x30201000); + nvkm_wo32(chan->inst, 0x0628, 0x70605040); + nvkm_wo32(chan->inst, 0x062c, 0xb0a09080); + nvkm_wo32(chan->inst, 0x0630, 0xf0e0d0c0); + nvkm_wo32(chan->inst, 0x0664, 0x00000001); + nvkm_wo32(chan->inst, 0x066c, 0x00004000); + nvkm_wo32(chan->inst, 0x0678, 0x00000001); + nvkm_wo32(chan->inst, 0x0680, 0x00040000); + nvkm_wo32(chan->inst, 0x0684, 0x00010000); for (i = 0x1b04; i <= 0x2374; i += 16) { - nv_wo32(chan, (i + 0), 0x10700ff9); - nv_wo32(chan, (i + 4), 0x0436086c); - nv_wo32(chan, (i + 8), 0x000c001b); + nvkm_wo32(chan->inst, (i + 0), 0x10700ff9); + nvkm_wo32(chan->inst, (i + 4), 0x0436086c); + nvkm_wo32(chan->inst, (i + 8), 0x000c001b); } - nv_wo32(chan, 0x2704, 0x3f800000); - nv_wo32(chan, 0x2718, 0x3f800000); - nv_wo32(chan, 0x2744, 0x40000000); - nv_wo32(chan, 0x2748, 0x3f800000); - nv_wo32(chan, 0x274c, 0x3f000000); - nv_wo32(chan, 0x2754, 0x40000000); - nv_wo32(chan, 0x2758, 0x3f800000); - nv_wo32(chan, 0x2760, 0xbf800000); - nv_wo32(chan, 0x2768, 0xbf800000); - nv_wo32(chan, 0x308c, 0x000fe000); - nv_wo32(chan, 0x3108, 0x000003f8); - nv_wo32(chan, 0x3468, 0x002fe000); + nvkm_wo32(chan->inst, 0x2704, 0x3f800000); + nvkm_wo32(chan->inst, 0x2718, 0x3f800000); + nvkm_wo32(chan->inst, 0x2744, 0x40000000); + nvkm_wo32(chan->inst, 0x2748, 0x3f800000); + nvkm_wo32(chan->inst, 0x274c, 0x3f000000); + nvkm_wo32(chan->inst, 0x2754, 0x40000000); + nvkm_wo32(chan->inst, 0x2758, 0x3f800000); + nvkm_wo32(chan->inst, 0x2760, 0xbf800000); + nvkm_wo32(chan->inst, 0x2768, 0xbf800000); + nvkm_wo32(chan->inst, 0x308c, 0x000fe000); + nvkm_wo32(chan->inst, 0x3108, 0x000003f8); + nvkm_wo32(chan->inst, 0x3468, 0x002fe000); for (i = 0x3484; i <= 0x34a0; i += 4) - nv_wo32(chan, i, 0x001c527c); + nvkm_wo32(chan->inst, i, 0x001c527c); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv25_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x25), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv25_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ -static int -nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv20_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); - if (ret) - return ret; +static const struct nvkm_gr_func +nv25_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv20_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv25_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */ + {} + } +}; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv25_gr_cclass; - nv_engine(priv)->sclass = nv25_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; - return 0; +int +nv25_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv25_gr, device, index, pgr); } - -struct nvkm_oclass -nv25_gr_oclass = { - .handle = NV_ENGINE(GR, 0x25), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv25_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv20_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index 22a5096e283d..3cad26dbc2b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -1,125 +1,125 @@ #include "nv20.h" #include "regs.h" +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> /******************************************************************************* * PGRAPH context ******************************************************************************/ +static const struct nvkm_object_func +nv2a_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, +}; + static int -nv2a_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv2a_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x36b0, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv2a_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x36b0, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x033c, 0xffff0000); - nv_wo32(chan, 0x03a0, 0x0fff0000); - nv_wo32(chan, 0x03a4, 0x0fff0000); - nv_wo32(chan, 0x047c, 0x00000101); - nv_wo32(chan, 0x0490, 0x00000111); - nv_wo32(chan, 0x04a8, 0x44400000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0000, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x033c, 0xffff0000); + nvkm_wo32(chan->inst, 0x03a0, 0x0fff0000); + nvkm_wo32(chan->inst, 0x03a4, 0x0fff0000); + nvkm_wo32(chan->inst, 0x047c, 0x00000101); + nvkm_wo32(chan->inst, 0x0490, 0x00000111); + nvkm_wo32(chan->inst, 0x04a8, 0x44400000); for (i = 0x04d4; i <= 0x04e0; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x04f4; i <= 0x0500; i += 4) - nv_wo32(chan, i, 0x00080000); + nvkm_wo32(chan->inst, i, 0x00080000); for (i = 0x050c; i <= 0x0518; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x051c; i <= 0x0528; i += 4) - nv_wo32(chan, i, 0x000105b8); + nvkm_wo32(chan->inst, i, 0x000105b8); for (i = 0x052c; i <= 0x0538; i += 4) - nv_wo32(chan, i, 0x00080008); + nvkm_wo32(chan->inst, i, 0x00080008); for (i = 0x055c; i <= 0x0598; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x05a4, 0x4b7fffff); - nv_wo32(chan, 0x05fc, 0x00000001); - nv_wo32(chan, 0x0604, 0x00004000); - nv_wo32(chan, 0x0610, 0x00000001); - nv_wo32(chan, 0x0618, 0x00040000); - nv_wo32(chan, 0x061c, 0x00010000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x05a4, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x05fc, 0x00000001); + nvkm_wo32(chan->inst, 0x0604, 0x00004000); + nvkm_wo32(chan->inst, 0x0610, 0x00000001); + nvkm_wo32(chan->inst, 0x0618, 0x00040000); + nvkm_wo32(chan->inst, 0x061c, 0x00010000); for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */ - nv_wo32(chan, (i + 0), 0x10700ff9); - nv_wo32(chan, (i + 4), 0x0436086c); - nv_wo32(chan, (i + 8), 0x000c001b); + nvkm_wo32(chan->inst, (i + 0), 0x10700ff9); + nvkm_wo32(chan->inst, (i + 4), 0x0436086c); + nvkm_wo32(chan->inst, (i + 8), 0x000c001b); } - nv_wo32(chan, 0x269c, 0x3f800000); - nv_wo32(chan, 0x26b0, 0x3f800000); - nv_wo32(chan, 0x26dc, 0x40000000); - nv_wo32(chan, 0x26e0, 0x3f800000); - nv_wo32(chan, 0x26e4, 0x3f000000); - nv_wo32(chan, 0x26ec, 0x40000000); - nv_wo32(chan, 0x26f0, 0x3f800000); - nv_wo32(chan, 0x26f8, 0xbf800000); - nv_wo32(chan, 0x2700, 0xbf800000); - nv_wo32(chan, 0x3024, 0x000fe000); - nv_wo32(chan, 0x30a0, 0x000003f8); - nv_wo32(chan, 0x33fc, 0x002fe000); + nvkm_wo32(chan->inst, 0x269c, 0x3f800000); + nvkm_wo32(chan->inst, 0x26b0, 0x3f800000); + nvkm_wo32(chan->inst, 0x26dc, 0x40000000); + nvkm_wo32(chan->inst, 0x26e0, 0x3f800000); + nvkm_wo32(chan->inst, 0x26e4, 0x3f000000); + nvkm_wo32(chan->inst, 0x26ec, 0x40000000); + nvkm_wo32(chan->inst, 0x26f0, 0x3f800000); + nvkm_wo32(chan->inst, 0x26f8, 0xbf800000); + nvkm_wo32(chan->inst, 0x2700, 0xbf800000); + nvkm_wo32(chan->inst, 0x3024, 0x000fe000); + nvkm_wo32(chan->inst, 0x30a0, 0x000003f8); + nvkm_wo32(chan->inst, 0x33fc, 0x002fe000); for (i = 0x341c; i <= 0x3438; i += 4) - nv_wo32(chan, i, 0x001c527c); + nvkm_wo32(chan->inst, i, 0x001c527c); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv2a_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x2a), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv2a_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ -static int -nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv20_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); - if (ret) - return ret; +static const struct nvkm_gr_func +nv2a_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv20_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv2a_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */ + {} + } +}; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv2a_gr_cclass; - nv_engine(priv)->sclass = nv25_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; - return 0; +int +nv2a_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv2a_gr, device, index, pgr); } - -struct nvkm_oclass -nv2a_gr_oclass = { - .handle = NV_ENGINE(GR, 0x2a), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv2a_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv20_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index dcc84eb54fb6..69de8c6259fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -1,231 +1,198 @@ #include "nv20.h" #include "regs.h" -#include <core/device.h> +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> #include <subdev/fb.h> /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -static struct nvkm_oclass -nv30_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */ - { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */ - { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */ - { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */ - { 0x0397, &nv04_gr_ofuncs, NULL }, /* rankine */ - {}, +static const struct nvkm_object_func +nv30_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv30_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x5f48, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv30_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x5f48, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x0410, 0x00000101); - nv_wo32(chan, 0x0424, 0x00000111); - nv_wo32(chan, 0x0428, 0x00000060); - nv_wo32(chan, 0x0444, 0x00000080); - nv_wo32(chan, 0x0448, 0xffff0000); - nv_wo32(chan, 0x044c, 0x00000001); - nv_wo32(chan, 0x0460, 0x44400000); - nv_wo32(chan, 0x048c, 0xffff0000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x0410, 0x00000101); + nvkm_wo32(chan->inst, 0x0424, 0x00000111); + nvkm_wo32(chan->inst, 0x0428, 0x00000060); + nvkm_wo32(chan->inst, 0x0444, 0x00000080); + nvkm_wo32(chan->inst, 0x0448, 0xffff0000); + nvkm_wo32(chan->inst, 0x044c, 0x00000001); + nvkm_wo32(chan->inst, 0x0460, 0x44400000); + nvkm_wo32(chan->inst, 0x048c, 0xffff0000); for (i = 0x04e0; i < 0x04e8; i += 4) - nv_wo32(chan, i, 0x0fff0000); - nv_wo32(chan, 0x04ec, 0x00011100); + nvkm_wo32(chan->inst, i, 0x0fff0000); + nvkm_wo32(chan->inst, 0x04ec, 0x00011100); for (i = 0x0508; i < 0x0548; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x0550, 0x4b7fffff); - nv_wo32(chan, 0x058c, 0x00000080); - nv_wo32(chan, 0x0590, 0x30201000); - nv_wo32(chan, 0x0594, 0x70605040); - nv_wo32(chan, 0x0598, 0xb8a89888); - nv_wo32(chan, 0x059c, 0xf8e8d8c8); - nv_wo32(chan, 0x05b0, 0xb0000000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x0550, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x058c, 0x00000080); + nvkm_wo32(chan->inst, 0x0590, 0x30201000); + nvkm_wo32(chan->inst, 0x0594, 0x70605040); + nvkm_wo32(chan->inst, 0x0598, 0xb8a89888); + nvkm_wo32(chan->inst, 0x059c, 0xf8e8d8c8); + nvkm_wo32(chan->inst, 0x05b0, 0xb0000000); for (i = 0x0600; i < 0x0640; i += 4) - nv_wo32(chan, i, 0x00010588); + nvkm_wo32(chan->inst, i, 0x00010588); for (i = 0x0640; i < 0x0680; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x06c0; i < 0x0700; i += 4) - nv_wo32(chan, i, 0x0008aae4); + nvkm_wo32(chan->inst, i, 0x0008aae4); for (i = 0x0700; i < 0x0740; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0740; i < 0x0780; i += 4) - nv_wo32(chan, i, 0x00080008); - nv_wo32(chan, 0x085c, 0x00040000); - nv_wo32(chan, 0x0860, 0x00010000); + nvkm_wo32(chan->inst, i, 0x00080008); + nvkm_wo32(chan->inst, 0x085c, 0x00040000); + nvkm_wo32(chan->inst, 0x0860, 0x00010000); for (i = 0x0864; i < 0x0874; i += 4) - nv_wo32(chan, i, 0x00040004); + nvkm_wo32(chan->inst, i, 0x00040004); for (i = 0x1f18; i <= 0x3088 ; i += 16) { - nv_wo32(chan, i + 0, 0x10700ff9); - nv_wo32(chan, i + 1, 0x0436086c); - nv_wo32(chan, i + 2, 0x000c001b); + nvkm_wo32(chan->inst, i + 0, 0x10700ff9); + nvkm_wo32(chan->inst, i + 1, 0x0436086c); + nvkm_wo32(chan->inst, i + 2, 0x000c001b); } for (i = 0x30b8; i < 0x30c8; i += 4) - nv_wo32(chan, i, 0x0000ffff); - nv_wo32(chan, 0x344c, 0x3f800000); - nv_wo32(chan, 0x3808, 0x3f800000); - nv_wo32(chan, 0x381c, 0x3f800000); - nv_wo32(chan, 0x3848, 0x40000000); - nv_wo32(chan, 0x384c, 0x3f800000); - nv_wo32(chan, 0x3850, 0x3f000000); - nv_wo32(chan, 0x3858, 0x40000000); - nv_wo32(chan, 0x385c, 0x3f800000); - nv_wo32(chan, 0x3864, 0xbf800000); - nv_wo32(chan, 0x386c, 0xbf800000); + nvkm_wo32(chan->inst, i, 0x0000ffff); + nvkm_wo32(chan->inst, 0x344c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3808, 0x3f800000); + nvkm_wo32(chan->inst, 0x381c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3848, 0x40000000); + nvkm_wo32(chan->inst, 0x384c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3850, 0x3f000000); + nvkm_wo32(chan->inst, 0x3858, 0x40000000); + nvkm_wo32(chan->inst, 0x385c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3864, 0xbf800000); + nvkm_wo32(chan->inst, 0x386c, 0xbf800000); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv30_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x30), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv30_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ -static int -nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv20_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv30_gr_cclass; - nv_engine(priv)->sclass = nv30_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; - return 0; -} - int -nv30_gr_init(struct nvkm_object *object) +nv30_gr_init(struct nvkm_gr *base) { - struct nvkm_engine *engine = nv_engine(object); - struct nv20_gr_priv *priv = (void *)engine; - struct nvkm_fb *pfb = nvkm_fb(object); - int ret, i; - - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4); - - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(priv, 0x400890, 0x01b463ff); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475); - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); - nv_wr32(priv, 0x400B80, 0x1003d888); - nv_wr32(priv, 0x400B84, 0x0c000000); - nv_wr32(priv, 0x400098, 0x00000000); - nv_wr32(priv, 0x40009C, 0x0005ad00); - nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ - nv_wr32(priv, 0x4000a0, 0x00000000); - nv_wr32(priv, 0x4000a4, 0x00000008); - nv_wr32(priv, 0x4008a8, 0xb784a400); - nv_wr32(priv, 0x400ba0, 0x002f8685); - nv_wr32(priv, 0x400ba4, 0x00231f3f); - nv_wr32(priv, 0x4008a4, 0x40000020); - - if (nv_device(priv)->chipset == 0x34) { - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002); + struct nv20_gr *gr = nv20_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + + nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, + nvkm_memory_addr(gr->ctxtab) >> 4); + + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nvkm_wr32(device, 0x400890, 0x01b463ff); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf2de0475); + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00008000); + nvkm_wr32(device, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); + nvkm_wr32(device, 0x400B80, 0x1003d888); + nvkm_wr32(device, 0x400B84, 0x0c000000); + nvkm_wr32(device, 0x400098, 0x00000000); + nvkm_wr32(device, 0x40009C, 0x0005ad00); + nvkm_wr32(device, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ + nvkm_wr32(device, 0x4000a0, 0x00000000); + nvkm_wr32(device, 0x4000a4, 0x00000008); + nvkm_wr32(device, 0x4008a8, 0xb784a400); + nvkm_wr32(device, 0x400ba0, 0x002f8685); + nvkm_wr32(device, 0x400ba4, 0x00231f3f); + nvkm_wr32(device, 0x4008a4, 0x40000020); + + if (device->chipset == 0x34) { + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00200201); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000008); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000032); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00E00004); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000002); } - nv_wr32(priv, 0x4000c0, 0x00000016); - - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) - engine->tile_prog(engine, i); + nvkm_wr32(device, 0x4000c0, 0x00000016); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(priv, 0x0040075c , 0x00000001); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nvkm_wr32(device, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, 0x0040075c , 0x00000001); /* begin RAM config */ - /* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */ - nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); - if (nv_device(priv)->chipset != 0x34) { - nv_wr32(priv, 0x400750, 0x00EA0000); - nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x400750, 0x00EA0004); - nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204)); + /* vramsz = pci_resource_len(gr->dev->pdev, 1) - 1; */ + nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); + if (device->chipset != 0x34) { + nvkm_wr32(device, 0x400750, 0x00EA0000); + nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x400750, 0x00EA0004); + nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100204)); } + return 0; } -struct nvkm_oclass -nv30_gr_oclass = { - .handle = NV_ENGINE(GR, 0x30), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv30_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv30_gr_init, - .fini = _nvkm_gr_fini, - }, +static const struct nvkm_gr_func +nv30_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv30_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv30_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ + { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ + { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ + { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ + { -1, -1, 0x0397, &nv04_gr_object }, /* rankine */ + {} + } }; + +int +nv30_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv30_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index 985b7f3306ae..2207dac23981 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -1,159 +1,135 @@ #include "nv20.h" #include "regs.h" +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -static struct nvkm_oclass -nv34_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */ - { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */ - { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */ - { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */ - { 0x0697, &nv04_gr_ofuncs, NULL }, /* rankine */ - {}, +static const struct nvkm_object_func +nv34_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv34_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x46dc, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv34_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x46dc, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x040c, 0x01000101); - nv_wo32(chan, 0x0420, 0x00000111); - nv_wo32(chan, 0x0424, 0x00000060); - nv_wo32(chan, 0x0440, 0x00000080); - nv_wo32(chan, 0x0444, 0xffff0000); - nv_wo32(chan, 0x0448, 0x00000001); - nv_wo32(chan, 0x045c, 0x44400000); - nv_wo32(chan, 0x0480, 0xffff0000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x040c, 0x01000101); + nvkm_wo32(chan->inst, 0x0420, 0x00000111); + nvkm_wo32(chan->inst, 0x0424, 0x00000060); + nvkm_wo32(chan->inst, 0x0440, 0x00000080); + nvkm_wo32(chan->inst, 0x0444, 0xffff0000); + nvkm_wo32(chan->inst, 0x0448, 0x00000001); + nvkm_wo32(chan->inst, 0x045c, 0x44400000); + nvkm_wo32(chan->inst, 0x0480, 0xffff0000); for (i = 0x04d4; i < 0x04dc; i += 4) - nv_wo32(chan, i, 0x0fff0000); - nv_wo32(chan, 0x04e0, 0x00011100); + nvkm_wo32(chan->inst, i, 0x0fff0000); + nvkm_wo32(chan->inst, 0x04e0, 0x00011100); for (i = 0x04fc; i < 0x053c; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x0544, 0x4b7fffff); - nv_wo32(chan, 0x057c, 0x00000080); - nv_wo32(chan, 0x0580, 0x30201000); - nv_wo32(chan, 0x0584, 0x70605040); - nv_wo32(chan, 0x0588, 0xb8a89888); - nv_wo32(chan, 0x058c, 0xf8e8d8c8); - nv_wo32(chan, 0x05a0, 0xb0000000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x0544, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x057c, 0x00000080); + nvkm_wo32(chan->inst, 0x0580, 0x30201000); + nvkm_wo32(chan->inst, 0x0584, 0x70605040); + nvkm_wo32(chan->inst, 0x0588, 0xb8a89888); + nvkm_wo32(chan->inst, 0x058c, 0xf8e8d8c8); + nvkm_wo32(chan->inst, 0x05a0, 0xb0000000); for (i = 0x05f0; i < 0x0630; i += 4) - nv_wo32(chan, i, 0x00010588); + nvkm_wo32(chan->inst, i, 0x00010588); for (i = 0x0630; i < 0x0670; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x06b0; i < 0x06f0; i += 4) - nv_wo32(chan, i, 0x0008aae4); + nvkm_wo32(chan->inst, i, 0x0008aae4); for (i = 0x06f0; i < 0x0730; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0730; i < 0x0770; i += 4) - nv_wo32(chan, i, 0x00080008); - nv_wo32(chan, 0x0850, 0x00040000); - nv_wo32(chan, 0x0854, 0x00010000); + nvkm_wo32(chan->inst, i, 0x00080008); + nvkm_wo32(chan->inst, 0x0850, 0x00040000); + nvkm_wo32(chan->inst, 0x0854, 0x00010000); for (i = 0x0858; i < 0x0868; i += 4) - nv_wo32(chan, i, 0x00040004); + nvkm_wo32(chan->inst, i, 0x00040004); for (i = 0x15ac; i <= 0x271c ; i += 16) { - nv_wo32(chan, i + 0, 0x10700ff9); - nv_wo32(chan, i + 1, 0x0436086c); - nv_wo32(chan, i + 2, 0x000c001b); + nvkm_wo32(chan->inst, i + 0, 0x10700ff9); + nvkm_wo32(chan->inst, i + 1, 0x0436086c); + nvkm_wo32(chan->inst, i + 2, 0x000c001b); } for (i = 0x274c; i < 0x275c; i += 4) - nv_wo32(chan, i, 0x0000ffff); - nv_wo32(chan, 0x2ae0, 0x3f800000); - nv_wo32(chan, 0x2e9c, 0x3f800000); - nv_wo32(chan, 0x2eb0, 0x3f800000); - nv_wo32(chan, 0x2edc, 0x40000000); - nv_wo32(chan, 0x2ee0, 0x3f800000); - nv_wo32(chan, 0x2ee4, 0x3f000000); - nv_wo32(chan, 0x2eec, 0x40000000); - nv_wo32(chan, 0x2ef0, 0x3f800000); - nv_wo32(chan, 0x2ef8, 0xbf800000); - nv_wo32(chan, 0x2f00, 0xbf800000); + nvkm_wo32(chan->inst, i, 0x0000ffff); + nvkm_wo32(chan->inst, 0x2ae0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2e9c, 0x3f800000); + nvkm_wo32(chan->inst, 0x2eb0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2edc, 0x40000000); + nvkm_wo32(chan->inst, 0x2ee0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2ee4, 0x3f000000); + nvkm_wo32(chan->inst, 0x2eec, 0x40000000); + nvkm_wo32(chan->inst, 0x2ef0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2ef8, 0xbf800000); + nvkm_wo32(chan->inst, 0x2f00, 0xbf800000); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv34_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x34), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv34_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ -static int -nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv20_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); - if (ret) - return ret; +static const struct nvkm_gr_func +nv34_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv30_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv34_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ + { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ + { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ + { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ + { -1, -1, 0x0697, &nv04_gr_object }, /* rankine */ + {} + } +}; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv34_gr_cclass; - nv_engine(priv)->sclass = nv34_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; - return 0; +int +nv34_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv34_gr, device, index, pgr); } - -struct nvkm_oclass -nv34_gr_oclass = { - .handle = NV_ENGINE(GR, 0x34), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv34_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv30_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index 707625f19ff5..740df0f52c38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -1,159 +1,135 @@ #include "nv20.h" #include "regs.h" +#include <core/gpuobj.h> #include <engine/fifo.h> +#include <engine/fifo/chan.h> /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -static struct nvkm_oclass -nv35_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */ - { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */ - { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */ - { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */ - { 0x0497, &nv04_gr_ofuncs, NULL }, /* rankine */ - {}, +static const struct nvkm_object_func +nv35_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv35_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv35_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x577c, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv35_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x577c, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x040c, 0x00000101); - nv_wo32(chan, 0x0420, 0x00000111); - nv_wo32(chan, 0x0424, 0x00000060); - nv_wo32(chan, 0x0440, 0x00000080); - nv_wo32(chan, 0x0444, 0xffff0000); - nv_wo32(chan, 0x0448, 0x00000001); - nv_wo32(chan, 0x045c, 0x44400000); - nv_wo32(chan, 0x0488, 0xffff0000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x040c, 0x00000101); + nvkm_wo32(chan->inst, 0x0420, 0x00000111); + nvkm_wo32(chan->inst, 0x0424, 0x00000060); + nvkm_wo32(chan->inst, 0x0440, 0x00000080); + nvkm_wo32(chan->inst, 0x0444, 0xffff0000); + nvkm_wo32(chan->inst, 0x0448, 0x00000001); + nvkm_wo32(chan->inst, 0x045c, 0x44400000); + nvkm_wo32(chan->inst, 0x0488, 0xffff0000); for (i = 0x04dc; i < 0x04e4; i += 4) - nv_wo32(chan, i, 0x0fff0000); - nv_wo32(chan, 0x04e8, 0x00011100); + nvkm_wo32(chan->inst, i, 0x0fff0000); + nvkm_wo32(chan->inst, 0x04e8, 0x00011100); for (i = 0x0504; i < 0x0544; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x054c, 0x4b7fffff); - nv_wo32(chan, 0x0588, 0x00000080); - nv_wo32(chan, 0x058c, 0x30201000); - nv_wo32(chan, 0x0590, 0x70605040); - nv_wo32(chan, 0x0594, 0xb8a89888); - nv_wo32(chan, 0x0598, 0xf8e8d8c8); - nv_wo32(chan, 0x05ac, 0xb0000000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x054c, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x0588, 0x00000080); + nvkm_wo32(chan->inst, 0x058c, 0x30201000); + nvkm_wo32(chan->inst, 0x0590, 0x70605040); + nvkm_wo32(chan->inst, 0x0594, 0xb8a89888); + nvkm_wo32(chan->inst, 0x0598, 0xf8e8d8c8); + nvkm_wo32(chan->inst, 0x05ac, 0xb0000000); for (i = 0x0604; i < 0x0644; i += 4) - nv_wo32(chan, i, 0x00010588); + nvkm_wo32(chan->inst, i, 0x00010588); for (i = 0x0644; i < 0x0684; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x06c4; i < 0x0704; i += 4) - nv_wo32(chan, i, 0x0008aae4); + nvkm_wo32(chan->inst, i, 0x0008aae4); for (i = 0x0704; i < 0x0744; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0744; i < 0x0784; i += 4) - nv_wo32(chan, i, 0x00080008); - nv_wo32(chan, 0x0860, 0x00040000); - nv_wo32(chan, 0x0864, 0x00010000); + nvkm_wo32(chan->inst, i, 0x00080008); + nvkm_wo32(chan->inst, 0x0860, 0x00040000); + nvkm_wo32(chan->inst, 0x0864, 0x00010000); for (i = 0x0868; i < 0x0878; i += 4) - nv_wo32(chan, i, 0x00040004); + nvkm_wo32(chan->inst, i, 0x00040004); for (i = 0x1f1c; i <= 0x308c ; i += 16) { - nv_wo32(chan, i + 0, 0x10700ff9); - nv_wo32(chan, i + 4, 0x0436086c); - nv_wo32(chan, i + 8, 0x000c001b); + nvkm_wo32(chan->inst, i + 0, 0x10700ff9); + nvkm_wo32(chan->inst, i + 4, 0x0436086c); + nvkm_wo32(chan->inst, i + 8, 0x000c001b); } for (i = 0x30bc; i < 0x30cc; i += 4) - nv_wo32(chan, i, 0x0000ffff); - nv_wo32(chan, 0x3450, 0x3f800000); - nv_wo32(chan, 0x380c, 0x3f800000); - nv_wo32(chan, 0x3820, 0x3f800000); - nv_wo32(chan, 0x384c, 0x40000000); - nv_wo32(chan, 0x3850, 0x3f800000); - nv_wo32(chan, 0x3854, 0x3f000000); - nv_wo32(chan, 0x385c, 0x40000000); - nv_wo32(chan, 0x3860, 0x3f800000); - nv_wo32(chan, 0x3868, 0xbf800000); - nv_wo32(chan, 0x3870, 0xbf800000); + nvkm_wo32(chan->inst, i, 0x0000ffff); + nvkm_wo32(chan->inst, 0x3450, 0x3f800000); + nvkm_wo32(chan->inst, 0x380c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3820, 0x3f800000); + nvkm_wo32(chan->inst, 0x384c, 0x40000000); + nvkm_wo32(chan->inst, 0x3850, 0x3f800000); + nvkm_wo32(chan->inst, 0x3854, 0x3f000000); + nvkm_wo32(chan->inst, 0x385c, 0x40000000); + nvkm_wo32(chan->inst, 0x3860, 0x3f800000); + nvkm_wo32(chan->inst, 0x3868, 0xbf800000); + nvkm_wo32(chan->inst, 0x3870, 0xbf800000); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv35_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x35), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv35_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ -static int -nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv20_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); - if (ret) - return ret; +static const struct nvkm_gr_func +nv35_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv30_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv35_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ + { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ + { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ + { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ + { -1, -1, 0x0497, &nv04_gr_object }, /* rankine */ + {} + } +}; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv35_gr_cclass; - nv_engine(priv)->sclass = nv35_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; - return 0; +int +nv35_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv35_gr, device, index, pgr); } - -struct nvkm_oclass -nv35_gr_oclass = { - .handle = NV_ENGINE(GR, 0x35), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv35_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv30_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 7e1937980e3f..ffa902ece872 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -25,26 +25,15 @@ #include "regs.h" #include <core/client.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <subdev/fb.h> #include <subdev/timer.h> #include <engine/fifo.h> -struct nv40_gr_priv { - struct nvkm_gr base; - u32 size; -}; - -struct nv40_gr_chan { - struct nvkm_gr_chan base; -}; - -static u64 +u64 nv40_gr_units(struct nvkm_gr *gr) { - struct nv40_gr_priv *priv = (void *)gr; - - return nv_rd32(priv, 0x1540); + return nvkm_rd32(gr->engine.subdev.device, 0x1540); } /******************************************************************************* @@ -52,80 +41,29 @@ nv40_gr_units(struct nvkm_gr *gr) ******************************************************************************/ static int -nv40_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 20, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 20, align, + false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); #ifdef __BIG_ENDIAN - nv_mo32(obj, 0x08, 0x01000000, 0x01000000); + nvkm_mo32(*pgpuobj, 0x08, 0x01000000, 0x01000000); #endif - nv_wo32(obj, 0x0c, 0x00000000); - nv_wo32(obj, 0x10, 0x00000000); - return 0; + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_ofuncs -nv40_gr_ofuncs = { - .ctor = nv40_gr_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv40_gr_sclass[] = { - { 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv40_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */ - { 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */ - { 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */ - { 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */ - { 0x4097, &nv40_gr_ofuncs, NULL }, /* curie */ - {}, -}; - -static struct nvkm_oclass -nv44_gr_sclass[] = { - { 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv40_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */ - { 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */ - { 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */ - { 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */ - { 0x4497, &nv40_gr_ofuncs, NULL }, /* curie */ - {}, +const struct nvkm_object_func +nv40_gr_object = { + .bind = nv40_gr_object_bind, }; /******************************************************************************* @@ -133,361 +71,334 @@ nv44_gr_sclass[] = { ******************************************************************************/ static int -nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv40_gr_priv *priv = (void *)engine; - struct nv40_gr_chan *chan; - int ret; - - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan)); - nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4); - return 0; + struct nv40_gr_chan *chan = nv40_gr_chan(object); + struct nv40_gr *gr = chan->gr; + int ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size, + align, true, parent, pgpuobj); + if (ret == 0) { + chan->inst = (*pgpuobj)->addr; + nvkm_kmap(*pgpuobj); + nv40_grctx_fill(gr->base.engine.subdev.device, *pgpuobj); + nvkm_wo32(*pgpuobj, 0x00000, chan->inst >> 4); + nvkm_done(*pgpuobj); + } + return ret; } static int -nv40_gr_context_fini(struct nvkm_object *object, bool suspend) +nv40_gr_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv40_gr_priv *priv = (void *)object->engine; - struct nv40_gr_chan *chan = (void *)object; - u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4; + struct nv40_gr_chan *chan = nv40_gr_chan(object); + struct nv40_gr *gr = chan->gr; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 inst = 0x01000000 | chan->inst >> 4; int ret = 0; - nv_mask(priv, 0x400720, 0x00000001, 0x00000000); + nvkm_mask(device, 0x400720, 0x00000001, 0x00000000); - if (nv_rd32(priv, 0x40032c) == inst) { + if (nvkm_rd32(device, 0x40032c) == inst) { if (suspend) { - nv_wr32(priv, 0x400720, 0x00000000); - nv_wr32(priv, 0x400784, inst); - nv_mask(priv, 0x400310, 0x00000020, 0x00000020); - nv_mask(priv, 0x400304, 0x00000001, 0x00000001); - if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) { - u32 insn = nv_rd32(priv, 0x400308); - nv_warn(priv, "ctxprog timeout 0x%08x\n", insn); + nvkm_wr32(device, 0x400720, 0x00000000); + nvkm_wr32(device, 0x400784, inst); + nvkm_mask(device, 0x400310, 0x00000020, 0x00000020); + nvkm_mask(device, 0x400304, 0x00000001, 0x00000001); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x400300) & 0x00000001)) + break; + ) < 0) { + u32 insn = nvkm_rd32(device, 0x400308); + nvkm_warn(subdev, "ctxprog timeout %08x\n", insn); ret = -EBUSY; } } - nv_mask(priv, 0x40032c, 0x01000000, 0x00000000); + nvkm_mask(device, 0x40032c, 0x01000000, 0x00000000); } - if (nv_rd32(priv, 0x400330) == inst) - nv_mask(priv, 0x400330, 0x01000000, 0x00000000); + if (nvkm_rd32(device, 0x400330) == inst) + nvkm_mask(device, 0x400330, 0x01000000, 0x00000000); - nv_mask(priv, 0x400720, 0x00000001, 0x00000001); + nvkm_mask(device, 0x400720, 0x00000001, 0x00000001); return ret; } -static struct nvkm_oclass -nv40_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = nv40_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +static void * +nv40_gr_chan_dtor(struct nvkm_object *object) +{ + struct nv40_gr_chan *chan = nv40_gr_chan(object); + unsigned long flags; + spin_lock_irqsave(&chan->gr->base.engine.lock, flags); + list_del(&chan->head); + spin_unlock_irqrestore(&chan->gr->base.engine.lock, flags); + return chan; +} + +static const struct nvkm_object_func +nv40_gr_chan = { + .dtor = nv40_gr_chan_dtor, + .fini = nv40_gr_chan_fini, + .bind = nv40_gr_chan_bind, }; +int +nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) +{ + struct nv40_gr *gr = nv40_gr(base); + struct nv40_gr_chan *chan; + unsigned long flags; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv40_gr_chan, oclass, &chan->object); + chan->gr = gr; + *pobject = &chan->object; + + spin_lock_irqsave(&chan->gr->base.engine.lock, flags); + list_add(&chan->head, &gr->chan); + spin_unlock_irqrestore(&chan->gr->base.engine.lock, flags); + return 0; +} + /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ static void -nv40_gr_tile_prog(struct nvkm_engine *engine, int i) +nv40_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) { - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *pfifo = nvkm_fifo(engine); - struct nv40_gr_priv *priv = (void *)engine; + struct nv40_gr *gr = nv40_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; unsigned long flags; - pfifo->pause(pfifo, &flags); - nv04_gr_idle(priv); + nvkm_fifo_pause(fifo, &flags); + nv04_gr_idle(&gr->base); - switch (nv_device(priv)->chipset) { + switch (device->chipset) { case 0x40: case 0x41: case 0x42: case 0x43: case 0x45: - case 0x4e: - nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr); - switch (nv_device(priv)->chipset) { + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); + switch (device->chipset) { case 0x40: case 0x45: - nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp); - nv_wr32(priv, NV40_PGRAPH_ZCOMP1(i), tile->zcomp); + nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nvkm_wr32(device, NV40_PGRAPH_ZCOMP1(i), tile->zcomp); break; case 0x41: case 0x42: case 0x43: - nv_wr32(priv, NV41_PGRAPH_ZCOMP0(i), tile->zcomp); - nv_wr32(priv, NV41_PGRAPH_ZCOMP1(i), tile->zcomp); + nvkm_wr32(device, NV41_PGRAPH_ZCOMP0(i), tile->zcomp); + nvkm_wr32(device, NV41_PGRAPH_ZCOMP1(i), tile->zcomp); break; default: break; } break; - case 0x44: - case 0x4a: - nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); - break; - case 0x46: - case 0x4c: case 0x47: case 0x49: case 0x4b: - case 0x63: - case 0x67: - case 0x68: - nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr); - nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr); - switch (nv_device(priv)->chipset) { - case 0x47: - case 0x49: - case 0x4b: - nv_wr32(priv, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); - nv_wr32(priv, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); - break; - default: - break; - } + nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); + nvkm_wr32(device, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); + nvkm_wr32(device, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); break; default: + WARN_ON(1); break; } - pfifo->start(pfifo, &flags); + nvkm_fifo_start(fifo, &flags); } -static void -nv40_gr_intr(struct nvkm_subdev *subdev) +void +nv40_gr_intr(struct nvkm_gr *base) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle = NULL; - struct nv40_gr_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 inst = nv_rd32(priv, 0x40032c) & 0x000fffff; - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + struct nv40_gr *gr = nv40_gr(base); + struct nv40_gr_chan *temp, *chan = NULL; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 inst = nvkm_rd32(device, 0x40032c) & 0x000fffff; + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xffff; u32 show = stat; - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + char msg[128], src[128], sta[128]; + unsigned long flags; - if (stat & NV_PGRAPH_INTR_ERROR) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - handle = nvkm_handle_get_class(engctx, class); - if (handle && !nv_call(handle->object, mthd, data)) - show &= ~NV_PGRAPH_INTR_ERROR; - nvkm_handle_put(handle); + spin_lock_irqsave(&gr->base.engine.lock, flags); + list_for_each_entry(temp, &gr->chan, head) { + if (temp->inst >> 4 == inst) { + chan = temp; + list_del(&chan->head); + list_add(&chan->head, &gr->chan); + break; } + } + if (stat & NV_PGRAPH_INTR_ERROR) { if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { - nv_mask(priv, 0x402000, 0, 0); + nvkm_mask(device, 0x402000, 0, 0); } } - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); - nvkm_bitfield_print(nv10_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv10_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(priv, - "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 4, nvkm_client_name(engctx), subc, - class, mthd, data); + nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%08x %s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, + chan ? chan->fifo->chid : -1, inst << 4, + chan ? chan->fifo->object.client->name : "unknown", + subc, class, mthd, data); } - nvkm_engctx_put(engctx); + spin_unlock_irqrestore(&gr->base.engine.lock, flags); } -static int -nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv40_gr_init(struct nvkm_gr *base) { - struct nv40_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv40_gr_intr; - nv_engine(priv)->cclass = &nv40_gr_cclass; - if (nv44_gr_class(priv)) - nv_engine(priv)->sclass = nv44_gr_sclass; - else - nv_engine(priv)->sclass = nv40_gr_sclass; - nv_engine(priv)->tile_prog = nv40_gr_tile_prog; - - priv->base.units = nv40_gr_units; - return 0; -} - -static int -nv40_gr_init(struct nvkm_object *object) -{ - struct nvkm_engine *engine = nv_engine(object); - struct nvkm_fb *pfb = nvkm_fb(object); - struct nv40_gr_priv *priv = (void *)engine; + struct nv40_gr *gr = nv40_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; int ret, i, j; u32 vramsz; - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; - /* generate and upload context program */ - ret = nv40_grctx_init(nv_device(priv), &priv->size); + ret = nv40_grctx_init(device, &gr->size); if (ret) return ret; /* No context present currently */ - nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); + nvkm_wr32(device, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055); - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xe0de8055); + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00008000); + nvkm_wr32(device, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nvkm_wr32(device, NV10_PGRAPH_STATE , 0xFFFFFFFF); - j = nv_rd32(priv, 0x1540) & 0xff; + j = nvkm_rd32(device, 0x1540) & 0xff; if (j) { for (i = 0; !(j & 1); j >>= 1, i++) ; - nv_wr32(priv, 0x405000, i); + nvkm_wr32(device, 0x405000, i); } - if (nv_device(priv)->chipset == 0x40) { - nv_wr32(priv, 0x4009b0, 0x83280fff); - nv_wr32(priv, 0x4009b4, 0x000000a0); + if (device->chipset == 0x40) { + nvkm_wr32(device, 0x4009b0, 0x83280fff); + nvkm_wr32(device, 0x4009b4, 0x000000a0); } else { - nv_wr32(priv, 0x400820, 0x83280eff); - nv_wr32(priv, 0x400824, 0x000000a0); + nvkm_wr32(device, 0x400820, 0x83280eff); + nvkm_wr32(device, 0x400824, 0x000000a0); } - switch (nv_device(priv)->chipset) { + switch (device->chipset) { case 0x40: case 0x45: - nv_wr32(priv, 0x4009b8, 0x0078e366); - nv_wr32(priv, 0x4009bc, 0x0000014c); + nvkm_wr32(device, 0x4009b8, 0x0078e366); + nvkm_wr32(device, 0x4009bc, 0x0000014c); break; case 0x41: case 0x42: /* pciid also 0x00Cx */ /* case 0x0120: XXX (pciid) */ - nv_wr32(priv, 0x400828, 0x007596ff); - nv_wr32(priv, 0x40082c, 0x00000108); + nvkm_wr32(device, 0x400828, 0x007596ff); + nvkm_wr32(device, 0x40082c, 0x00000108); break; case 0x43: - nv_wr32(priv, 0x400828, 0x0072cb77); - nv_wr32(priv, 0x40082c, 0x00000108); + nvkm_wr32(device, 0x400828, 0x0072cb77); + nvkm_wr32(device, 0x40082c, 0x00000108); break; case 0x44: case 0x46: /* G72 */ case 0x4a: case 0x4c: /* G7x-based C51 */ case 0x4e: - nv_wr32(priv, 0x400860, 0); - nv_wr32(priv, 0x400864, 0); + nvkm_wr32(device, 0x400860, 0); + nvkm_wr32(device, 0x400864, 0); break; case 0x47: /* G70 */ case 0x49: /* G71 */ case 0x4b: /* G73 */ - nv_wr32(priv, 0x400828, 0x07830610); - nv_wr32(priv, 0x40082c, 0x0000016A); + nvkm_wr32(device, 0x400828, 0x07830610); + nvkm_wr32(device, 0x40082c, 0x0000016A); break; default: break; } - nv_wr32(priv, 0x400b38, 0x2ffff800); - nv_wr32(priv, 0x400b3c, 0x00006000); + nvkm_wr32(device, 0x400b38, 0x2ffff800); + nvkm_wr32(device, 0x400b3c, 0x00006000); /* Tiling related stuff. */ - switch (nv_device(priv)->chipset) { + switch (device->chipset) { case 0x44: case 0x4a: - nv_wr32(priv, 0x400bc4, 0x1003d888); - nv_wr32(priv, 0x400bbc, 0xb7a7b500); + nvkm_wr32(device, 0x400bc4, 0x1003d888); + nvkm_wr32(device, 0x400bbc, 0xb7a7b500); break; case 0x46: - nv_wr32(priv, 0x400bc4, 0x0000e024); - nv_wr32(priv, 0x400bbc, 0xb7a7b520); + nvkm_wr32(device, 0x400bc4, 0x0000e024); + nvkm_wr32(device, 0x400bbc, 0xb7a7b520); break; case 0x4c: case 0x4e: case 0x67: - nv_wr32(priv, 0x400bc4, 0x1003d888); - nv_wr32(priv, 0x400bbc, 0xb7a7b540); + nvkm_wr32(device, 0x400bc4, 0x1003d888); + nvkm_wr32(device, 0x400bbc, 0xb7a7b540); break; default: break; } - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) - engine->tile_prog(engine, i); - /* begin RAM config */ - vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; - switch (nv_device(priv)->chipset) { + vramsz = device->func->resource_size(device, 1) - 1; + switch (device->chipset) { case 0x40: - nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x400820, 0); - nv_wr32(priv, 0x400824, 0); - nv_wr32(priv, 0x400864, vramsz); - nv_wr32(priv, 0x400868, vramsz); + nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x4069A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4069A8, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x400820, 0); + nvkm_wr32(device, 0x400824, 0); + nvkm_wr32(device, 0x400864, vramsz); + nvkm_wr32(device, 0x400868, vramsz); break; default: - switch (nv_device(priv)->chipset) { + switch (device->chipset) { case 0x41: case 0x42: case 0x43: @@ -495,33 +406,70 @@ nv40_gr_init(struct nvkm_object *object) case 0x4e: case 0x44: case 0x4a: - nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204)); + nvkm_wr32(device, 0x4009F0, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009F4, nvkm_rd32(device, 0x100204)); break; default: - nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204)); + nvkm_wr32(device, 0x400DF0, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x400DF4, nvkm_rd32(device, 0x100204)); break; } - nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x400840, 0); - nv_wr32(priv, 0x400844, 0); - nv_wr32(priv, 0x4008A0, vramsz); - nv_wr32(priv, 0x4008A4, vramsz); + nvkm_wr32(device, 0x4069F0, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4069F4, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x400840, 0); + nvkm_wr32(device, 0x400844, 0); + nvkm_wr32(device, 0x4008A0, vramsz); + nvkm_wr32(device, 0x4008A4, vramsz); break; } return 0; } -struct nvkm_oclass -nv40_gr_oclass = { - .handle = NV_ENGINE(GR, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_gr_ctor, - .dtor = _nvkm_gr_dtor, - .init = nv40_gr_init, - .fini = _nvkm_gr_fini, - }, +int +nv40_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct nv40_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + INIT_LIST_HEAD(&gr->chan); + + return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base); +} + +static const struct nvkm_gr_func +nv40_gr = { + .init = nv40_gr_init, + .intr = nv40_gr_intr, + .tile = nv40_gr_tile, + .units = nv40_gr_units, + .chan_new = nv40_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv40_gr_object }, /* null */ + { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ + { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ + { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ + { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ + { -1, -1, 0x4097, &nv40_gr_object }, /* curie */ + {} + } }; + +int +nv40_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv40_gr_new_(&nv40_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h index d852bd6de571..2812ed11f877 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h @@ -1,22 +1,45 @@ #ifndef __NV40_GR_H__ #define __NV40_GR_H__ -#include <engine/gr.h> +#define nv40_gr(p) container_of((p), struct nv40_gr, base) +#include "priv.h" -#include <core/device.h> -struct nvkm_gpuobj; +struct nv40_gr { + struct nvkm_gr base; + u32 size; + struct list_head chan; +}; + +int nv40_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index, + struct nvkm_gr **); +int nv40_gr_init(struct nvkm_gr *); +void nv40_gr_intr(struct nvkm_gr *); +u64 nv40_gr_units(struct nvkm_gr *); + +#define nv40_gr_chan(p) container_of((p), struct nv40_gr_chan, object) + +struct nv40_gr_chan { + struct nvkm_object object; + struct nv40_gr *gr; + struct nvkm_fifo_chan *fifo; + u32 inst; + struct list_head head; +}; + +int nv40_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nvkm_object_func nv40_gr_object; /* returns 1 if device is one of the nv4x using the 0x4497 object class, * helpful to determine a number of other hardware features */ static inline int -nv44_gr_class(void *priv) +nv44_gr_class(struct nvkm_device *device) { - struct nvkm_device *device = nv_device(priv); - if ((device->chipset & 0xf0) == 0x60) return 1; - return !(0x0baf & (1 << (device->chipset & 0x0f))); + return !(0x0aaf & (1 << (device->chipset & 0x0f))); } int nv40_grctx_init(struct nvkm_device *, u32 *size); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c new file mode 100644 index 000000000000..45ff80254eb4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c @@ -0,0 +1,108 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "nv40.h" +#include "regs.h" + +#include <subdev/fb.h> +#include <engine/fifo.h> + +static void +nv44_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) +{ + struct nv40_gr *gr = nv40_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; + unsigned long flags; + + nvkm_fifo_pause(fifo, &flags); + nv04_gr_idle(&gr->base); + + switch (device->chipset) { + case 0x44: + case 0x4a: + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); + break; + case 0x46: + case 0x4c: + case 0x63: + case 0x67: + case 0x68: + nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); + break; + case 0x4e: + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); + break; + default: + WARN_ON(1); + break; + } + + nvkm_fifo_start(fifo, &flags); +} + +static const struct nvkm_gr_func +nv44_gr = { + .init = nv40_gr_init, + .intr = nv40_gr_intr, + .tile = nv44_gr_tile, + .units = nv40_gr_units, + .chan_new = nv40_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv40_gr_object }, /* null */ + { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ + { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ + { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ + { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ + { -1, -1, 0x4497, &nv40_gr_object }, /* curie */ + {} + } +}; + +int +nv44_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv40_gr_new_(&nv44_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 270d7cd63fc7..b19b912d5787 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -24,27 +24,13 @@ #include "nv50.h" #include <core/client.h> -#include <core/device.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <engine/fifo.h> -#include <subdev/timer.h> -struct nv50_gr_priv { - struct nvkm_gr base; - spinlock_t lock; - u32 size; -}; - -struct nv50_gr_chan { - struct nvkm_gr_chan base; -}; - -static u64 +u64 nv50_gr_units(struct nvkm_gr *gr) { - struct nv50_gr_priv *priv = (void *)gr; - - return nv_rd32(priv, 0x1540); + return nvkm_rd32(gr->engine.subdev.device, 0x1540); } /******************************************************************************* @@ -52,86 +38,25 @@ nv50_gr_units(struct nvkm_gr *gr) ******************************************************************************/ static int -nv50_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); - return 0; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, + align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_ofuncs -nv50_gr_ofuncs = { - .ctor = nv50_gr_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv50_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x5097, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - {} -}; - -static struct nvkm_oclass -g84_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x8297, &nv50_gr_ofuncs }, - {} -}; - -static struct nvkm_oclass -gt200_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x8397, &nv50_gr_ofuncs }, - {} -}; - -static struct nvkm_oclass -gt215_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x8597, &nv50_gr_ofuncs }, - { 0x85c0, &nv50_gr_ofuncs }, - {} -}; - -static struct nvkm_oclass -mcp89_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x85c0, &nv50_gr_ofuncs }, - { 0x8697, &nv50_gr_ofuncs }, - {} +const struct nvkm_object_func +nv50_gr_object = { + .bind = nv50_gr_object_bind, }; /******************************************************************************* @@ -139,160 +64,43 @@ mcp89_gr_sclass[] = { ******************************************************************************/ static int -nv50_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv50_gr_priv *priv = (void *)engine; - struct nv50_gr_chan *chan; - int ret; - - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size, - 0, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan)); - return 0; + struct nv50_gr *gr = nv50_gr_chan(object)->gr; + int ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size, + align, true, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nv50_grctx_fill(gr->base.engine.subdev.device, *pgpuobj); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_oclass -nv50_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - -/******************************************************************************* - * PGRAPH engine/subdev functions - ******************************************************************************/ - -static const struct nvkm_bitfield nv50_pgr_status[] = { - { 0x00000001, "BUSY" }, /* set when any bit is set */ - { 0x00000002, "DISPATCH" }, - { 0x00000004, "UNK2" }, - { 0x00000008, "UNK3" }, - { 0x00000010, "UNK4" }, - { 0x00000020, "UNK5" }, - { 0x00000040, "M2MF" }, - { 0x00000080, "UNK7" }, - { 0x00000100, "CTXPROG" }, - { 0x00000200, "VFETCH" }, - { 0x00000400, "CCACHE_PREGEOM" }, - { 0x00000800, "STRMOUT_VATTR_POSTGEOM" }, - { 0x00001000, "VCLIP" }, - { 0x00002000, "RATTR_APLANE" }, - { 0x00004000, "TRAST" }, - { 0x00008000, "CLIPID" }, - { 0x00010000, "ZCULL" }, - { 0x00020000, "ENG2D" }, - { 0x00040000, "RMASK" }, - { 0x00080000, "TPC_RAST" }, - { 0x00100000, "TPC_PROP" }, - { 0x00200000, "TPC_TEX" }, - { 0x00400000, "TPC_GEOM" }, - { 0x00800000, "TPC_MP" }, - { 0x01000000, "ROP" }, - {} -}; - -static const char *const nv50_pgr_vstatus_0[] = { - "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP", - NULL -}; - -static const char *const nv50_pgr_vstatus_1[] = { - "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL -}; - -static const char *const nv50_pgr_vstatus_2[] = { - "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK", - "ROP", NULL +static const struct nvkm_object_func +nv50_gr_chan = { + .bind = nv50_gr_chan_bind, }; -static void -nvkm_pgr_vstatus_print(struct nv50_gr_priv *priv, int r, - const char *const units[], u32 status) +int +nv50_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - int i; - - nv_error(priv, "PGRAPH_VSTATUS%d: 0x%08x", r, status); + struct nv50_gr *gr = nv50_gr(base); + struct nv50_gr_chan *chan; - for (i = 0; units[i] && status; i++) { - if ((status & 7) == 1) - pr_cont(" %s", units[i]); - status >>= 3; - } - if (status) - pr_cont(" (invalid: 0x%x)", status); - pr_cont("\n"); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv50_gr_chan, oclass, &chan->object); + chan->gr = gr; + *pobject = &chan->object; + return 0; } -static int -g84_gr_tlb_flush(struct nvkm_engine *engine) -{ - struct nvkm_timer *ptimer = nvkm_timer(engine); - struct nv50_gr_priv *priv = (void *)engine; - bool idle, timeout = false; - unsigned long flags; - u64 start; - u32 tmp; - - spin_lock_irqsave(&priv->lock, flags); - nv_mask(priv, 0x400500, 0x00000001, 0x00000000); - - start = ptimer->read(ptimer); - do { - idle = true; - - for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) { - if ((tmp & 7) == 1) - idle = false; - } - - for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) { - if ((tmp & 7) == 1) - idle = false; - } - - for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) { - if ((tmp & 7) == 1) - idle = false; - } - } while (!idle && - !(timeout = ptimer->read(ptimer) - start > 2000000000)); - - if (timeout) { - nv_error(priv, "PGRAPH TLB flush idle timeout fail\n"); - - tmp = nv_rd32(priv, 0x400700); - nv_error(priv, "PGRAPH_STATUS : 0x%08x", tmp); - nvkm_bitfield_print(nv50_pgr_status, tmp); - pr_cont("\n"); - - nvkm_pgr_vstatus_print(priv, 0, nv50_pgr_vstatus_0, - nv_rd32(priv, 0x400380)); - nvkm_pgr_vstatus_print(priv, 1, nv50_pgr_vstatus_1, - nv_rd32(priv, 0x400384)); - nvkm_pgr_vstatus_print(priv, 2, nv50_pgr_vstatus_2, - nv_rd32(priv, 0x400388)); - } - - - nv_wr32(priv, 0x100c80, 0x00000001); - if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) - nv_error(priv, "vm flush timeout\n"); - nv_mask(priv, 0x400500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->lock, flags); - return timeout ? -EBUSY : 0; -} +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ static const struct nvkm_bitfield nv50_mp_exec_errors[] = { { 0x01, "STACK_UNDERFLOW" }, @@ -427,157 +235,172 @@ static const struct nvkm_bitfield nv50_gr_trap_prop[] = { }; static void -nv50_priv_prop_trap(struct nv50_gr_priv *priv, - u32 ustatus_addr, u32 ustatus, u32 tp) +nv50_gr_prop_trap(struct nv50_gr *gr, u32 ustatus_addr, u32 ustatus, u32 tp) { - u32 e0c = nv_rd32(priv, ustatus_addr + 0x04); - u32 e10 = nv_rd32(priv, ustatus_addr + 0x08); - u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c); - u32 e18 = nv_rd32(priv, ustatus_addr + 0x10); - u32 e1c = nv_rd32(priv, ustatus_addr + 0x14); - u32 e20 = nv_rd32(priv, ustatus_addr + 0x18); - u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 e0c = nvkm_rd32(device, ustatus_addr + 0x04); + u32 e10 = nvkm_rd32(device, ustatus_addr + 0x08); + u32 e14 = nvkm_rd32(device, ustatus_addr + 0x0c); + u32 e18 = nvkm_rd32(device, ustatus_addr + 0x10); + u32 e1c = nvkm_rd32(device, ustatus_addr + 0x14); + u32 e20 = nvkm_rd32(device, ustatus_addr + 0x18); + u32 e24 = nvkm_rd32(device, ustatus_addr + 0x1c); + char msg[128]; /* CUDA memory: l[], g[] or stack. */ if (ustatus & 0x00000080) { if (e18 & 0x80000000) { /* g[] read fault? */ - nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n", tp, e14, e10 | ((e18 >> 24) & 0x1f)); e18 &= ~0x1f000000; } else if (e18 & 0xc) { /* g[] write fault? */ - nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n", tp, e14, e10 | ((e18 >> 7) & 0x1f)); e18 &= ~0x00000f80; } else { - nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n", tp, e14, e10); } ustatus &= ~0x00000080; } if (ustatus) { - nv_error(priv, "TRAP_PROP - TP %d -", tp); - nvkm_bitfield_print(nv50_gr_trap_prop, ustatus); - pr_cont(" - Address %02x%08x\n", e14, e10); + nvkm_snprintbf(msg, sizeof(msg), nv50_gr_trap_prop, ustatus); + nvkm_error(subdev, "TRAP_PROP - TP %d - %08x [%s] - " + "Address %02x%08x\n", + tp, ustatus, msg, e14, e10); } - nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", tp, e0c, e18, e1c, e20, e24); } static void -nv50_priv_mp_trap(struct nv50_gr_priv *priv, int tpid, int display) +nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) { - u32 units = nv_rd32(priv, 0x1540); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 units = nvkm_rd32(device, 0x1540); u32 addr, mp10, status, pc, oplow, ophigh; + char msg[128]; int i; int mps = 0; for (i = 0; i < 4; i++) { if (!(units & 1 << (i+24))) continue; - if (nv_device(priv)->chipset < 0xa0) + if (device->chipset < 0xa0) addr = 0x408200 + (tpid << 12) + (i << 7); else addr = 0x408100 + (tpid << 11) + (i << 7); - mp10 = nv_rd32(priv, addr + 0x10); - status = nv_rd32(priv, addr + 0x14); + mp10 = nvkm_rd32(device, addr + 0x10); + status = nvkm_rd32(device, addr + 0x14); if (!status) continue; if (display) { - nv_rd32(priv, addr + 0x20); - pc = nv_rd32(priv, addr + 0x24); - oplow = nv_rd32(priv, addr + 0x70); - ophigh = nv_rd32(priv, addr + 0x74); - nv_error(priv, "TRAP_MP_EXEC - " - "TP %d MP %d:", tpid, i); - nvkm_bitfield_print(nv50_mp_exec_errors, status); - pr_cont(" at %06x warp %d, opcode %08x %08x\n", - pc&0xffffff, pc >> 24, - oplow, ophigh); + nvkm_rd32(device, addr + 0x20); + pc = nvkm_rd32(device, addr + 0x24); + oplow = nvkm_rd32(device, addr + 0x70); + ophigh = nvkm_rd32(device, addr + 0x74); + nvkm_snprintbf(msg, sizeof(msg), + nv50_mp_exec_errors, status); + nvkm_error(subdev, "TRAP_MP_EXEC - TP %d MP %d: " + "%08x [%s] at %06x warp %d, " + "opcode %08x %08x\n", + tpid, i, status, msg, pc & 0xffffff, + pc >> 24, oplow, ophigh); } - nv_wr32(priv, addr + 0x10, mp10); - nv_wr32(priv, addr + 0x14, 0); + nvkm_wr32(device, addr + 0x10, mp10); + nvkm_wr32(device, addr + 0x14, 0); mps++; } if (!mps && display) - nv_error(priv, "TRAP_MP_EXEC - TP %d: " + nvkm_error(subdev, "TRAP_MP_EXEC - TP %d: " "No MPs claiming errors?\n", tpid); } static void -nv50_priv_tp_trap(struct nv50_gr_priv *priv, int type, u32 ustatus_old, +nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, u32 ustatus_new, int display, const char *name) { + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 units = nvkm_rd32(device, 0x1540); int tps = 0; - u32 units = nv_rd32(priv, 0x1540); int i, r; + char msg[128]; u32 ustatus_addr, ustatus; for (i = 0; i < 16; i++) { if (!(units & (1 << i))) continue; - if (nv_device(priv)->chipset < 0xa0) + if (device->chipset < 0xa0) ustatus_addr = ustatus_old + (i << 12); else ustatus_addr = ustatus_new + (i << 11); - ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff; + ustatus = nvkm_rd32(device, ustatus_addr) & 0x7fffffff; if (!ustatus) continue; tps++; switch (type) { case 6: /* texture error... unknown for now */ if (display) { - nv_error(priv, "magic set %d:\n", i); + nvkm_error(subdev, "magic set %d:\n", i); for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) - nv_error(priv, "\t0x%08x: 0x%08x\n", r, - nv_rd32(priv, r)); + nvkm_error(subdev, "\t%08x: %08x\n", r, + nvkm_rd32(device, r)); if (ustatus) { - nv_error(priv, "%s - TP%d:", name, i); - nvkm_bitfield_print(nv50_tex_traps, - ustatus); - pr_cont("\n"); + nvkm_snprintbf(msg, sizeof(msg), + nv50_tex_traps, ustatus); + nvkm_error(subdev, + "%s - TP%d: %08x [%s]\n", + name, i, ustatus, msg); ustatus = 0; } } break; case 7: /* MP error */ if (ustatus & 0x04030000) { - nv50_priv_mp_trap(priv, i, display); + nv50_gr_mp_trap(gr, i, display); ustatus &= ~0x04030000; } if (ustatus && display) { - nv_error(priv, "%s - TP%d:", name, i); - nvkm_bitfield_print(nv50_mpc_traps, ustatus); - pr_cont("\n"); + nvkm_snprintbf(msg, sizeof(msg), + nv50_mpc_traps, ustatus); + nvkm_error(subdev, "%s - TP%d: %08x [%s]\n", + name, i, ustatus, msg); ustatus = 0; } break; case 8: /* PROP error */ if (display) - nv50_priv_prop_trap( - priv, ustatus_addr, ustatus, i); + nv50_gr_prop_trap( + gr, ustatus_addr, ustatus, i); ustatus = 0; break; } if (ustatus) { if (display) - nv_error(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); + nvkm_error(subdev, "%s - TP%d: Unhandled ustatus %08x\n", name, i, ustatus); } - nv_wr32(priv, ustatus_addr, 0xc0000000); + nvkm_wr32(device, ustatus_addr, 0xc0000000); } if (!tps && display) - nv_warn(priv, "%s - No TPs claiming errors?\n", name); + nvkm_warn(subdev, "%s - No TPs claiming errors?\n", name); } static int -nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, - int chid, u64 inst, struct nvkm_object *engctx) +nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, + int chid, u64 inst, const char *name) { - u32 status = nv_rd32(priv, 0x400108); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 status = nvkm_rd32(device, 0x400108); u32 ustatus; + char msg[128]; if (!status && display) { - nv_error(priv, "TRAP: no units reporting traps?\n"); + nvkm_error(subdev, "TRAP: no units reporting traps?\n"); return 1; } @@ -585,71 +408,72 @@ nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, * COND, QUERY. If you get a trap from it, the command is still stuck * in DISPATCH and you need to do something about it. */ if (status & 0x001) { - ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x400804) & 0x7fffffff; if (!ustatus && display) { - nv_error(priv, "TRAP_DISPATCH - no ustatus?\n"); + nvkm_error(subdev, "TRAP_DISPATCH - no ustatus?\n"); } - nv_wr32(priv, 0x400500, 0x00000000); + nvkm_wr32(device, 0x400500, 0x00000000); /* Known to be triggered by screwed up NOTIFY and COND... */ if (ustatus & 0x00000001) { - u32 addr = nv_rd32(priv, 0x400808); + u32 addr = nvkm_rd32(device, 0x400808); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 datal = nv_rd32(priv, 0x40080c); - u32 datah = nv_rd32(priv, 0x400810); - u32 class = nv_rd32(priv, 0x400814); - u32 r848 = nv_rd32(priv, 0x400848); + u32 datal = nvkm_rd32(device, 0x40080c); + u32 datah = nvkm_rd32(device, 0x400810); + u32 class = nvkm_rd32(device, 0x400814); + u32 r848 = nvkm_rd32(device, 0x400848); - nv_error(priv, "TRAP DISPATCH_FAULT\n"); + nvkm_error(subdev, "TRAP DISPATCH_FAULT\n"); if (display && (addr & 0x80000000)) { - nv_error(priv, - "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n", - chid, inst, - nvkm_client_name(engctx), subc, - class, mthd, datah, datal, addr, r848); + nvkm_error(subdev, + "ch %d [%010llx %s] subc %d " + "class %04x mthd %04x data %08x%08x " + "400808 %08x 400848 %08x\n", + chid, inst, name, subc, class, mthd, + datah, datal, addr, r848); } else if (display) { - nv_error(priv, "no stuck command?\n"); + nvkm_error(subdev, "no stuck command?\n"); } - nv_wr32(priv, 0x400808, 0); - nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3); - nv_wr32(priv, 0x400848, 0); + nvkm_wr32(device, 0x400808, 0); + nvkm_wr32(device, 0x4008e8, nvkm_rd32(device, 0x4008e8) & 3); + nvkm_wr32(device, 0x400848, 0); ustatus &= ~0x00000001; } if (ustatus & 0x00000002) { - u32 addr = nv_rd32(priv, 0x40084c); + u32 addr = nvkm_rd32(device, 0x40084c); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, 0x40085c); - u32 class = nv_rd32(priv, 0x400814); + u32 data = nvkm_rd32(device, 0x40085c); + u32 class = nvkm_rd32(device, 0x400814); - nv_error(priv, "TRAP DISPATCH_QUERY\n"); + nvkm_error(subdev, "TRAP DISPATCH_QUERY\n"); if (display && (addr & 0x80000000)) { - nv_error(priv, - "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n", - chid, inst, - nvkm_client_name(engctx), subc, - class, mthd, data, addr); + nvkm_error(subdev, + "ch %d [%010llx %s] subc %d " + "class %04x mthd %04x data %08x " + "40084c %08x\n", chid, inst, name, + subc, class, mthd, data, addr); } else if (display) { - nv_error(priv, "no stuck command?\n"); + nvkm_error(subdev, "no stuck command?\n"); } - nv_wr32(priv, 0x40084c, 0); + nvkm_wr32(device, 0x40084c, 0); ustatus &= ~0x00000002; } if (ustatus && display) { - nv_error(priv, "TRAP_DISPATCH (unknown " - "0x%08x)\n", ustatus); + nvkm_error(subdev, "TRAP_DISPATCH " + "(unknown %08x)\n", ustatus); } - nv_wr32(priv, 0x400804, 0xc0000000); - nv_wr32(priv, 0x400108, 0x001); + nvkm_wr32(device, 0x400804, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x001); status &= ~0x001; if (!status) return 0; @@ -657,81 +481,91 @@ nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, /* M2MF: Memory to memory copy engine. */ if (status & 0x002) { - u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff; + u32 ustatus = nvkm_rd32(device, 0x406800) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_M2MF"); - nvkm_bitfield_print(nv50_gr_trap_m2mf, ustatus); - pr_cont("\n"); - nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n", - nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808), - nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810)); - + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_m2mf, ustatus); + nvkm_error(subdev, "TRAP_M2MF %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_M2MF %08x %08x %08x %08x\n", + nvkm_rd32(device, 0x406804), + nvkm_rd32(device, 0x406808), + nvkm_rd32(device, 0x40680c), + nvkm_rd32(device, 0x406810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(priv, 0x400040, 2); - nv_wr32(priv, 0x400040, 0); - nv_wr32(priv, 0x406800, 0xc0000000); - nv_wr32(priv, 0x400108, 0x002); + nvkm_wr32(device, 0x400040, 2); + nvkm_wr32(device, 0x400040, 0); + nvkm_wr32(device, 0x406800, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x002); status &= ~0x002; } /* VFETCH: Fetches data from vertex buffers. */ if (status & 0x004) { - u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff; + u32 ustatus = nvkm_rd32(device, 0x400c04) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_VFETCH"); - nvkm_bitfield_print(nv50_gr_trap_vfetch, ustatus); - pr_cont("\n"); - nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n", - nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08), - nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10)); + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_vfetch, ustatus); + nvkm_error(subdev, "TRAP_VFETCH %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_VFETCH %08x %08x %08x %08x\n", + nvkm_rd32(device, 0x400c00), + nvkm_rd32(device, 0x400c08), + nvkm_rd32(device, 0x400c0c), + nvkm_rd32(device, 0x400c10)); } - nv_wr32(priv, 0x400c04, 0xc0000000); - nv_wr32(priv, 0x400108, 0x004); + nvkm_wr32(device, 0x400c04, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x004); status &= ~0x004; } /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ if (status & 0x008) { - ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x401800) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_STRMOUT"); - nvkm_bitfield_print(nv50_gr_trap_strmout, ustatus); - pr_cont("\n"); - nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n", - nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808), - nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810)); - + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_strmout, ustatus); + nvkm_error(subdev, "TRAP_STRMOUT %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_STRMOUT %08x %08x %08x %08x\n", + nvkm_rd32(device, 0x401804), + nvkm_rd32(device, 0x401808), + nvkm_rd32(device, 0x40180c), + nvkm_rd32(device, 0x401810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(priv, 0x400040, 0x80); - nv_wr32(priv, 0x400040, 0); - nv_wr32(priv, 0x401800, 0xc0000000); - nv_wr32(priv, 0x400108, 0x008); + nvkm_wr32(device, 0x400040, 0x80); + nvkm_wr32(device, 0x400040, 0); + nvkm_wr32(device, 0x401800, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x008); status &= ~0x008; } /* CCACHE: Handles code and c[] caches and fills them. */ if (status & 0x010) { - ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x405018) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_CCACHE"); - nvkm_bitfield_print(nv50_gr_trap_ccache, ustatus); - pr_cont("\n"); - nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x" - " %08x %08x %08x\n", - nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004), - nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c), - nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014), - nv_rd32(priv, 0x40501c)); - + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_ccache, ustatus); + nvkm_error(subdev, "TRAP_CCACHE %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_CCACHE %08x %08x %08x %08x " + "%08x %08x %08x\n", + nvkm_rd32(device, 0x405000), + nvkm_rd32(device, 0x405004), + nvkm_rd32(device, 0x405008), + nvkm_rd32(device, 0x40500c), + nvkm_rd32(device, 0x405010), + nvkm_rd32(device, 0x405014), + nvkm_rd32(device, 0x40501c)); } - nv_wr32(priv, 0x405018, 0xc0000000); - nv_wr32(priv, 0x400108, 0x010); + nvkm_wr32(device, 0x405018, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x010); status &= ~0x010; } @@ -739,239 +573,174 @@ nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, * remaining, so try to handle it anyway. Perhaps related to that * unknown DMA slot on tesla? */ if (status & 0x20) { - ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x402000) & 0x7fffffff; if (display) - nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus); - nv_wr32(priv, 0x402000, 0xc0000000); + nvkm_error(subdev, "TRAP_UNKC04 %08x\n", ustatus); + nvkm_wr32(device, 0x402000, 0xc0000000); /* no status modifiction on purpose */ } /* TEXTURE: CUDA texturing units */ if (status & 0x040) { - nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display, + nv50_gr_tp_trap(gr, 6, 0x408900, 0x408600, display, "TRAP_TEXTURE"); - nv_wr32(priv, 0x400108, 0x040); + nvkm_wr32(device, 0x400108, 0x040); status &= ~0x040; } /* MP: CUDA execution engines. */ if (status & 0x080) { - nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display, + nv50_gr_tp_trap(gr, 7, 0x408314, 0x40831c, display, "TRAP_MP"); - nv_wr32(priv, 0x400108, 0x080); + nvkm_wr32(device, 0x400108, 0x080); status &= ~0x080; } /* PROP: Handles TP-initiated uncached memory accesses: * l[], g[], stack, 2d surfaces, render targets. */ if (status & 0x100) { - nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display, + nv50_gr_tp_trap(gr, 8, 0x408e08, 0x408708, display, "TRAP_PROP"); - nv_wr32(priv, 0x400108, 0x100); + nvkm_wr32(device, 0x400108, 0x100); status &= ~0x100; } if (status) { if (display) - nv_error(priv, "TRAP: unknown 0x%08x\n", status); - nv_wr32(priv, 0x400108, status); + nvkm_error(subdev, "TRAP: unknown %08x\n", status); + nvkm_wr32(device, 0x400108, status); } return 1; } -static void -nv50_gr_intr(struct nvkm_subdev *subdev) +void +nv50_gr_intr(struct nvkm_gr *base) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle = NULL; - struct nv50_gr_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x400100); - u32 inst = nv_rd32(priv, 0x40032c) & 0x0fffffff; - u32 addr = nv_rd32(priv, 0x400704); + struct nv50_gr *gr = nv50_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_fifo_chan *chan; + u32 stat = nvkm_rd32(device, 0x400100); + u32 inst = nvkm_rd32(device, 0x40032c) & 0x0fffffff; + u32 addr = nvkm_rd32(device, 0x400704); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, 0x400708); - u32 class = nv_rd32(priv, 0x400814); + u32 data = nvkm_rd32(device, 0x400708); + u32 class = nvkm_rd32(device, 0x400814); u32 show = stat, show_bitfield = stat; - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); - - if (stat & 0x00000010) { - handle = nvkm_handle_get_class(engctx, class); - if (handle && !nv_call(handle->object, mthd, data)) - show &= ~0x00000010; - nvkm_handle_put(handle); + const struct nvkm_enum *en; + unsigned long flags; + const char *name = "unknown"; + char msg[128]; + int chid = -1; + + chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + if (chan) { + name = chan->object.client->name; + chid = chan->chid; } if (show & 0x00100000) { - u32 ecode = nv_rd32(priv, 0x400110); - nv_error(priv, "DATA_ERROR "); - nvkm_enum_print(nv50_data_error_names, ecode); - pr_cont("\n"); + u32 ecode = nvkm_rd32(device, 0x400110); + en = nvkm_enum_find(nv50_data_error_names, ecode); + nvkm_error(subdev, "DATA_ERROR %08x [%s]\n", + ecode, en ? en->name : ""); show_bitfield &= ~0x00100000; } if (stat & 0x00200000) { - if (!nv50_gr_trap_handler(priv, show, chid, (u64)inst << 12, - engctx)) + if (!nv50_gr_trap_handler(gr, show, chid, (u64)inst << 12, name)) show &= ~0x00200000; show_bitfield &= ~0x00200000; } - nv_wr32(priv, 0x400100, stat); - nv_wr32(priv, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400100, stat); + nvkm_wr32(device, 0x400500, 0x00010001); if (show) { show &= show_bitfield; - if (show) { - nv_error(priv, "%s", ""); - nvkm_bitfield_print(nv50_gr_intr_name, show); - pr_cont("\n"); - } - nv_error(priv, - "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, (u64)inst << 12, nvkm_client_name(engctx), - subc, class, mthd, data); + nvkm_snprintbf(msg, sizeof(msg), nv50_gr_intr_name, show); + nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] subc %d " + "class %04x mthd %04x data %08x\n", + stat, msg, chid, (u64)inst << 12, name, + subc, class, mthd, data); } - if (nv_rd32(priv, 0x400824) & (1 << 31)) - nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31)); + if (nvkm_rd32(device, 0x400824) & (1 << 31)) + nvkm_wr32(device, 0x400824, nvkm_rd32(device, 0x400824) & ~(1 << 31)); - nvkm_engctx_put(engctx); + nvkm_fifo_chan_put(device->fifo, flags, &chan); } -static int -nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_gr_init(struct nvkm_gr *base) { - struct nv50_gr_priv *priv; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00201000; - nv_subdev(priv)->intr = nv50_gr_intr; - nv_engine(priv)->cclass = &nv50_gr_cclass; - - priv->base.units = nv50_gr_units; - - switch (nv_device(priv)->chipset) { - case 0x50: - nv_engine(priv)->sclass = nv50_gr_sclass; - break; - case 0x84: - case 0x86: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - nv_engine(priv)->sclass = g84_gr_sclass; - break; - case 0xa0: - case 0xaa: - case 0xac: - nv_engine(priv)->sclass = gt200_gr_sclass; - break; - case 0xa3: - case 0xa5: - case 0xa8: - nv_engine(priv)->sclass = gt215_gr_sclass; - break; - case 0xaf: - nv_engine(priv)->sclass = mcp89_gr_sclass; - break; - - } - - /* unfortunate hw bug workaround... */ - if (nv_device(priv)->chipset != 0x50 && - nv_device(priv)->chipset != 0xac) - nv_engine(priv)->tlb_flush = g84_gr_tlb_flush; - - spin_lock_init(&priv->lock); - return 0; -} - -static int -nv50_gr_init(struct nvkm_object *object) -{ - struct nv50_gr_priv *priv = (void *)object; + struct nv50_gr *gr = nv50_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; int ret, units, i; - ret = nvkm_gr_init(&priv->base); - if (ret) - return ret; - /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */ - nv_wr32(priv, 0x40008c, 0x00000004); + nvkm_wr32(device, 0x40008c, 0x00000004); /* reset/enable traps and interrupts */ - nv_wr32(priv, 0x400804, 0xc0000000); - nv_wr32(priv, 0x406800, 0xc0000000); - nv_wr32(priv, 0x400c04, 0xc0000000); - nv_wr32(priv, 0x401800, 0xc0000000); - nv_wr32(priv, 0x405018, 0xc0000000); - nv_wr32(priv, 0x402000, 0xc0000000); - - units = nv_rd32(priv, 0x001540); + nvkm_wr32(device, 0x400804, 0xc0000000); + nvkm_wr32(device, 0x406800, 0xc0000000); + nvkm_wr32(device, 0x400c04, 0xc0000000); + nvkm_wr32(device, 0x401800, 0xc0000000); + nvkm_wr32(device, 0x405018, 0xc0000000); + nvkm_wr32(device, 0x402000, 0xc0000000); + + units = nvkm_rd32(device, 0x001540); for (i = 0; i < 16; i++) { if (!(units & (1 << i))) continue; - if (nv_device(priv)->chipset < 0xa0) { - nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000); - nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000); - nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000); + if (device->chipset < 0xa0) { + nvkm_wr32(device, 0x408900 + (i << 12), 0xc0000000); + nvkm_wr32(device, 0x408e08 + (i << 12), 0xc0000000); + nvkm_wr32(device, 0x408314 + (i << 12), 0xc0000000); } else { - nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000); - nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000); - nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000); + nvkm_wr32(device, 0x408600 + (i << 11), 0xc0000000); + nvkm_wr32(device, 0x408708 + (i << 11), 0xc0000000); + nvkm_wr32(device, 0x40831c + (i << 11), 0xc0000000); } } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - nv_wr32(priv, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400500, 0x00010001); /* upload context program, initialise ctxctl defaults */ - ret = nv50_grctx_init(nv_device(priv), &priv->size); + ret = nv50_grctx_init(device, &gr->size); if (ret) return ret; - nv_wr32(priv, 0x400824, 0x00000000); - nv_wr32(priv, 0x400828, 0x00000000); - nv_wr32(priv, 0x40082c, 0x00000000); - nv_wr32(priv, 0x400830, 0x00000000); - nv_wr32(priv, 0x40032c, 0x00000000); - nv_wr32(priv, 0x400330, 0x00000000); + nvkm_wr32(device, 0x400824, 0x00000000); + nvkm_wr32(device, 0x400828, 0x00000000); + nvkm_wr32(device, 0x40082c, 0x00000000); + nvkm_wr32(device, 0x400830, 0x00000000); + nvkm_wr32(device, 0x40032c, 0x00000000); + nvkm_wr32(device, 0x400330, 0x00000000); /* some unknown zcull magic */ - switch (nv_device(priv)->chipset & 0xf0) { + switch (device->chipset & 0xf0) { case 0x50: case 0x80: case 0x90: - nv_wr32(priv, 0x402ca8, 0x00000800); + nvkm_wr32(device, 0x402ca8, 0x00000800); break; case 0xa0: default: - if (nv_device(priv)->chipset == 0xa0 || - nv_device(priv)->chipset == 0xaa || - nv_device(priv)->chipset == 0xac) { - nv_wr32(priv, 0x402ca8, 0x00000802); + if (device->chipset == 0xa0 || + device->chipset == 0xaa || + device->chipset == 0xac) { + nvkm_wr32(device, 0x402ca8, 0x00000802); } else { - nv_wr32(priv, 0x402cc0, 0x00000000); - nv_wr32(priv, 0x402ca8, 0x00000002); + nvkm_wr32(device, 0x402cc0, 0x00000000); + nvkm_wr32(device, 0x402ca8, 0x00000002); } break; @@ -979,21 +748,47 @@ nv50_gr_init(struct nvkm_object *object) /* zero out zcull regions */ for (i = 0; i < 8; i++) { - nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000); - nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000); - nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000); - nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c20 + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c24 + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c28 + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c2c + (i * 0x10), 0x00000000); } + return 0; } -struct nvkm_oclass -nv50_gr_oclass = { - .handle = NV_ENGINE(GR, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_gr_ctor, - .dtor = _nvkm_gr_dtor, - .init = nv50_gr_init, - .fini = _nvkm_gr_fini, - }, +int +nv50_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct nv50_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + spin_lock_init(&gr->lock); + *pgr = &gr->base; + + return nvkm_gr_ctor(func, device, index, 0x00201000, true, &gr->base); +} + +static const struct nvkm_gr_func +nv50_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x5097, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + {} + } }; + +int +nv50_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&nv50_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h index bcf786f6b731..45eec83a5969 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h @@ -1,8 +1,34 @@ #ifndef __NV50_GR_H__ #define __NV50_GR_H__ -#include <engine/gr.h> -struct nvkm_device; -struct nvkm_gpuobj; +#define nv50_gr(p) container_of((p), struct nv50_gr, base) +#include "priv.h" + +struct nv50_gr { + struct nvkm_gr base; + const struct nv50_gr_func *func; + spinlock_t lock; + u32 size; +}; + +int nv50_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index, + struct nvkm_gr **); +int nv50_gr_init(struct nvkm_gr *); +void nv50_gr_intr(struct nvkm_gr *); +u64 nv50_gr_units(struct nvkm_gr *); + +int g84_gr_tlb_flush(struct nvkm_gr *); + +#define nv50_gr_chan(p) container_of((p), struct nv50_gr_chan, object) + +struct nv50_gr_chan { + struct nvkm_object object; + struct nv50_gr *gr; +}; + +int nv50_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nvkm_object_func nv50_gr_object; int nv50_grctx_init(struct nvkm_device *, u32 *size); void nv50_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h new file mode 100644 index 000000000000..a234590be88e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h @@ -0,0 +1,38 @@ +#ifndef __NVKM_GR_PRIV_H__ +#define __NVKM_GR_PRIV_H__ +#define nvkm_gr(p) container_of((p), struct nvkm_gr, engine) +#include <engine/gr.h> +#include <core/enum.h> +struct nvkm_fb_tile; +struct nvkm_fifo_chan; + +int nvkm_gr_ctor(const struct nvkm_gr_func *, struct nvkm_device *, + int index, u32 pmc_enable, bool enable, + struct nvkm_gr *); + +bool nv04_gr_idle(struct nvkm_gr *); + +struct nvkm_gr_func { + void *(*dtor)(struct nvkm_gr *); + int (*oneinit)(struct nvkm_gr *); + int (*init)(struct nvkm_gr *); + void (*intr)(struct nvkm_gr *); + void (*tile)(struct nvkm_gr *, int region, struct nvkm_fb_tile *); + int (*tlb_flush)(struct nvkm_gr *); + int (*chan_new)(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + int (*object_get)(struct nvkm_gr *, int, struct nvkm_sclass *); + /* Returns chipset-specific counts of units packed into an u64. + */ + u64 (*units)(struct nvkm_gr *); + struct nvkm_sclass sclass[]; +}; + +extern const struct nvkm_bitfield nv04_gr_nsource[]; +extern const struct nvkm_object_func nv04_gr_object; + +extern const struct nvkm_bitfield nv10_gr_intr_name[]; +extern const struct nvkm_bitfield nv10_gr_nstatus[]; + +extern const struct nvkm_enum nv50_data_error_names[]; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c index 0df889fa2611..34ff0014a6c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c @@ -21,74 +21,24 @@ * * Authors: Ben Skeggs */ -#include <engine/mpeg.h> - -struct g84_mpeg_priv { - struct nvkm_mpeg base; -}; - -struct g84_mpeg_chan { - struct nvkm_mpeg_chan base; -}; - -/******************************************************************************* - * MPEG object classes - ******************************************************************************/ - -static struct nvkm_oclass -g84_mpeg_sclass[] = { - { 0x8274, &nv50_mpeg_ofuncs }, - {} -}; - -/******************************************************************************* - * PMPEG context - ******************************************************************************/ - -static struct nvkm_oclass -g84_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mpeg_context_ctor, - .dtor = _nvkm_mpeg_context_dtor, - .init = _nvkm_mpeg_context_init, - .fini = _nvkm_mpeg_context_fini, - .rd32 = _nvkm_mpeg_context_rd32, - .wr32 = _nvkm_mpeg_context_wr32, - }, +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_engine_func +g84_mpeg = { + .init = nv50_mpeg_init, + .intr = nv50_mpeg_intr, + .cclass = &nv50_mpeg_cclass, + .sclass = { + { -1, -1, G82_MPEG, &nv31_mpeg_object }, + {} + } }; -/******************************************************************************* - * PMPEG engine/subdev functions - ******************************************************************************/ - -static int -g84_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) { - struct g84_mpeg_priv *priv; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv50_mpeg_intr; - nv_engine(priv)->cclass = &g84_mpeg_cclass; - nv_engine(priv)->sclass = g84_mpeg_sclass; - return 0; + return nvkm_engine_new_(&g84_mpeg, device, index, 0x00000002, + true, pmpeg); } - -struct nvkm_oclass -g84_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv50_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index b5bef0718359..d4d8942b1347 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -24,281 +24,271 @@ #include "nv31.h" #include <core/client.h> -#include <core/handle.h> -#include <engine/fifo.h> -#include <subdev/instmem.h> +#include <core/gpuobj.h> #include <subdev/fb.h> #include <subdev/timer.h> +#include <engine/fifo.h> + +#include <nvif/class.h> /******************************************************************************* * MPEG object classes ******************************************************************************/ static int -nv31_mpeg_object_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv31_mpeg_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 20, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); - return 0; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, align, + false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -static int -nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) +const struct nvkm_object_func +nv31_mpeg_object = { + .bind = nv31_mpeg_object_bind, +}; + +/******************************************************************************* + * PMPEG context + ******************************************************************************/ + +static void * +nv31_mpeg_chan_dtor(struct nvkm_object *object) { - struct nvkm_instmem *imem = nvkm_instmem(object); - struct nv31_mpeg_priv *priv = (void *)object->engine; - u32 inst = *(u32 *)arg << 4; - u32 dma0 = nv_ro32(imem, inst + 0); - u32 dma1 = nv_ro32(imem, inst + 4); - u32 dma2 = nv_ro32(imem, inst + 8); + struct nv31_mpeg_chan *chan = nv31_mpeg_chan(object); + struct nv31_mpeg *mpeg = chan->mpeg; + unsigned long flags; + + spin_lock_irqsave(&mpeg->engine.lock, flags); + if (mpeg->chan == chan) + mpeg->chan = NULL; + spin_unlock_irqrestore(&mpeg->engine.lock, flags); + return chan; +} + +static const struct nvkm_object_func +nv31_mpeg_chan = { + .dtor = nv31_mpeg_chan_dtor, +}; + +int +nv31_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nv31_mpeg *mpeg = nv31_mpeg(oclass->engine); + struct nv31_mpeg_chan *chan; + unsigned long flags; + int ret = -EBUSY; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv31_mpeg_chan, oclass, &chan->object); + chan->mpeg = mpeg; + chan->fifo = fifoch; + *pobject = &chan->object; + + spin_lock_irqsave(&mpeg->engine.lock, flags); + if (!mpeg->chan) { + mpeg->chan = chan; + ret = 0; + } + spin_unlock_irqrestore(&mpeg->engine.lock, flags); + return ret; +} + +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ + +void +nv31_mpeg_tile(struct nvkm_engine *engine, int i, struct nvkm_fb_tile *tile) +{ + struct nv31_mpeg *mpeg = nv31_mpeg(engine); + struct nvkm_device *device = mpeg->engine.subdev.device; + + nvkm_wr32(device, 0x00b008 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x00b004 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x00b000 + (i * 0x10), tile->addr); +} + +static bool +nv31_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) +{ + u32 inst = data << 4; + u32 dma0 = nvkm_rd32(device, 0x700000 + inst); + u32 dma1 = nvkm_rd32(device, 0x700004 + inst); + u32 dma2 = nvkm_rd32(device, 0x700008 + inst); u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); u32 size = dma1 + 1; /* only allow linear DMA objects */ if (!(dma0 & 0x00002000)) - return -EINVAL; + return false; if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0); - nv_wr32(priv, 0x00b334, base); - nv_wr32(priv, 0x00b324, size); + nvkm_mask(device, 0x00b300, 0x00010000, + (dma0 & 0x00030000) ? 0x00010000 : 0); + nvkm_wr32(device, 0x00b334, base); + nvkm_wr32(device, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0); - nv_wr32(priv, 0x00b360, base); - nv_wr32(priv, 0x00b364, size); + nvkm_mask(device, 0x00b300, 0x00020000, + (dma0 & 0x00030000) ? 0x00020000 : 0); + nvkm_wr32(device, 0x00b360, base); + nvkm_wr32(device, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) - return -EINVAL; + return false; - nv_wr32(priv, 0x00b370, base); - nv_wr32(priv, 0x00b374, size); + nvkm_wr32(device, 0x00b370, base); + nvkm_wr32(device, 0x00b374, size); } - return 0; + return true; } -struct nvkm_ofuncs -nv31_mpeg_ofuncs = { - .ctor = nv31_mpeg_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_omthds -nv31_mpeg_omthds[] = { - { 0x0190, 0x0190, nv31_mpeg_mthd_dma }, - { 0x01a0, 0x01a0, nv31_mpeg_mthd_dma }, - { 0x01b0, 0x01b0, nv31_mpeg_mthd_dma }, - {} -}; - -struct nvkm_oclass -nv31_mpeg_sclass[] = { - { 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds }, - {} -}; - -/******************************************************************************* - * PMPEG context - ******************************************************************************/ - -static int -nv31_mpeg_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static bool +nv31_mpeg_mthd(struct nv31_mpeg *mpeg, u32 mthd, u32 data) { - struct nv31_mpeg_priv *priv = (void *)engine; - struct nv31_mpeg_chan *chan; - unsigned long flags; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - spin_lock_irqsave(&nv_engine(priv)->lock, flags); - if (priv->chan) { - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); - nvkm_object_destroy(&chan->base); - *pobject = NULL; - return -EBUSY; + struct nvkm_device *device = mpeg->engine.subdev.device; + switch (mthd) { + case 0x190: + case 0x1a0: + case 0x1b0: + return mpeg->func->mthd_dma(device, mthd, data); + default: + break; } - priv->chan = chan; - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); - return 0; + return false; } static void -nv31_mpeg_context_dtor(struct nvkm_object *object) +nv31_mpeg_intr(struct nvkm_engine *engine) { - struct nv31_mpeg_priv *priv = (void *)object->engine; - struct nv31_mpeg_chan *chan = (void *)object; - unsigned long flags; - - spin_lock_irqsave(&nv_engine(priv)->lock, flags); - priv->chan = NULL; - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); - nvkm_object_destroy(&chan->base); -} - -struct nvkm_oclass -nv31_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x31), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv31_mpeg_context_ctor, - .dtor = nv31_mpeg_context_dtor, - .init = nvkm_object_init, - .fini = nvkm_object_fini, - }, -}; - -/******************************************************************************* - * PMPEG engine/subdev functions - ******************************************************************************/ - -void -nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i) -{ - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nv31_mpeg_priv *priv = (void *)engine; - - nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch); - nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit); - nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr); -} - -void -nv31_mpeg_intr(struct nvkm_subdev *subdev) -{ - struct nv31_mpeg_priv *priv = (void *)subdev; - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_handle *handle; - struct nvkm_object *engctx; - u32 stat = nv_rd32(priv, 0x00b100); - u32 type = nv_rd32(priv, 0x00b230); - u32 mthd = nv_rd32(priv, 0x00b234); - u32 data = nv_rd32(priv, 0x00b238); + struct nv31_mpeg *mpeg = nv31_mpeg(engine); + struct nvkm_subdev *subdev = &mpeg->engine.subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x00b100); + u32 type = nvkm_rd32(device, 0x00b230); + u32 mthd = nvkm_rd32(device, 0x00b234); + u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; unsigned long flags; - spin_lock_irqsave(&nv_engine(priv)->lock, flags); - engctx = nv_object(priv->chan); + spin_lock_irqsave(&mpeg->engine.lock, flags); if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_mask(priv, 0x00b308, 0x00000000, 0x00000000); + nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000); show &= ~0x01000000; } - if (type == 0x00000010 && engctx) { - handle = nvkm_handle_get_class(engctx, 0x3174); - if (handle && !nv_call(handle->object, mthd, data)) + if (type == 0x00000010) { + if (!nv31_mpeg_mthd(mpeg, mthd, data)) show &= ~0x01000000; - nvkm_handle_put(handle); } } - nv_wr32(priv, 0x00b100, stat); - nv_wr32(priv, 0x00b230, 0x00000001); + nvkm_wr32(device, 0x00b100, stat); + nvkm_wr32(device, 0x00b230, 0x00000001); if (show) { - nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n", - pfifo->chid(pfifo, engctx), - nvkm_client_name(engctx), stat, type, mthd, data); + nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n", + mpeg->chan ? mpeg->chan->fifo->chid : -1, + mpeg->chan ? mpeg->chan->object.client->name : + "unknown", stat, type, mthd, data); } - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); -} - -static int -nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv31_mpeg_priv *priv; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv31_mpeg_intr; - nv_engine(priv)->cclass = &nv31_mpeg_cclass; - nv_engine(priv)->sclass = nv31_mpeg_sclass; - nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; - return 0; + spin_unlock_irqrestore(&mpeg->engine.lock, flags); } int -nv31_mpeg_init(struct nvkm_object *object) +nv31_mpeg_init(struct nvkm_engine *mpeg) { - struct nvkm_engine *engine = nv_engine(object); - struct nv31_mpeg_priv *priv = (void *)object; - struct nvkm_fb *pfb = nvkm_fb(object); - int ret, i; - - ret = nvkm_mpeg_init(&priv->base); - if (ret) - return ret; + struct nvkm_subdev *subdev = &mpeg->subdev; + struct nvkm_device *device = subdev->device; /* VPE init */ - nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - - for (i = 0; i < pfb->tile.regions; i++) - engine->tile_prog(engine, i); + nvkm_wr32(device, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + nvkm_wr32(device, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ /* PMPEG init */ - nv_wr32(priv, 0x00b32c, 0x00000000); - nv_wr32(priv, 0x00b314, 0x00000100); - nv_wr32(priv, 0x00b220, 0x00000031); - nv_wr32(priv, 0x00b300, 0x02001ec1); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); - - nv_wr32(priv, 0x00b100, 0xffffffff); - nv_wr32(priv, 0x00b140, 0xffffffff); - - if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) { - nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200)); + nvkm_wr32(device, 0x00b32c, 0x00000000); + nvkm_wr32(device, 0x00b314, 0x00000100); + nvkm_wr32(device, 0x00b220, 0x00000031); + nvkm_wr32(device, 0x00b300, 0x02001ec1); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); + + nvkm_wr32(device, 0x00b100, 0xffffffff); + nvkm_wr32(device, 0x00b140, 0xffffffff); + + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x00b200) & 0x00000001)) + break; + ) < 0) { + nvkm_error(subdev, "timeout %08x\n", + nvkm_rd32(device, 0x00b200)); return -EBUSY; } return 0; } -struct nvkm_oclass -nv31_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x31), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv31_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv31_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, +static void * +nv31_mpeg_dtor(struct nvkm_engine *engine) +{ + return nv31_mpeg(engine); +} + +static const struct nvkm_engine_func +nv31_mpeg_ = { + .dtor = nv31_mpeg_dtor, + .init = nv31_mpeg_init, + .intr = nv31_mpeg_intr, + .tile = nv31_mpeg_tile, + .fifo.cclass = nv31_mpeg_chan_new, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } }; + +int +nv31_mpeg_new_(const struct nv31_mpeg_func *func, struct nvkm_device *device, + int index, struct nvkm_engine **pmpeg) +{ + struct nv31_mpeg *mpeg; + + if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL))) + return -ENOMEM; + mpeg->func = func; + *pmpeg = &mpeg->engine; + + return nvkm_engine_ctor(&nv31_mpeg_, device, index, 0x00000002, + true, &mpeg->engine); +} + +static const struct nv31_mpeg_func +nv31_mpeg = { + .mthd_dma = nv31_mpeg_mthd_dma, +}; + +int +nv31_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) +{ + return nv31_mpeg_new_(&nv31_mpeg, device, index, pmpeg); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h index 782b796d7458..d3bb34fcdebf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h @@ -1,13 +1,30 @@ #ifndef __NV31_MPEG_H__ #define __NV31_MPEG_H__ +#define nv31_mpeg(p) container_of((p), struct nv31_mpeg, engine) +#include "priv.h" #include <engine/mpeg.h> -struct nv31_mpeg_chan { - struct nvkm_object base; +struct nv31_mpeg { + const struct nv31_mpeg_func *func; + struct nvkm_engine engine; + struct nv31_mpeg_chan *chan; }; -struct nv31_mpeg_priv { - struct nvkm_mpeg base; - struct nv31_mpeg_chan *chan; +int nv31_mpeg_new_(const struct nv31_mpeg_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +struct nv31_mpeg_func { + bool (*mthd_dma)(struct nvkm_device *, u32 mthd, u32 data); }; + +#define nv31_mpeg_chan(p) container_of((p), struct nv31_mpeg_chan, object) + +struct nv31_mpeg_chan { + struct nvkm_object object; + struct nv31_mpeg *mpeg; + struct nvkm_fifo_chan *fifo; +}; + +int nv31_mpeg_chan_new(struct nvkm_fifo_chan *, const struct nvkm_oclass *, + struct nvkm_object **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index 9508bf9e140f..16de5bd94b14 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -25,110 +25,53 @@ #include <subdev/instmem.h> -/******************************************************************************* - * MPEG object classes - ******************************************************************************/ +#include <nvif/class.h> -static int -nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) +bool +nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) { - struct nvkm_instmem *imem = nvkm_instmem(object); - struct nv31_mpeg_priv *priv = (void *)object->engine; - u32 inst = *(u32 *)arg << 4; - u32 dma0 = nv_ro32(imem, inst + 0); - u32 dma1 = nv_ro32(imem, inst + 4); - u32 dma2 = nv_ro32(imem, inst + 8); + struct nvkm_instmem *imem = device->imem; + u32 inst = data << 4; + u32 dma0 = nvkm_instmem_rd32(imem, inst + 0); + u32 dma1 = nvkm_instmem_rd32(imem, inst + 4); + u32 dma2 = nvkm_instmem_rd32(imem, inst + 8); u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); u32 size = dma1 + 1; /* only allow linear DMA objects */ if (!(dma0 & 0x00002000)) - return -EINVAL; + return false; if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000)); - nv_wr32(priv, 0x00b334, base); - nv_wr32(priv, 0x00b324, size); + nvkm_mask(device, 0x00b300, 0x00030000, (dma0 & 0x00030000)); + nvkm_wr32(device, 0x00b334, base); + nvkm_wr32(device, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); - nv_wr32(priv, 0x00b360, base); - nv_wr32(priv, 0x00b364, size); + nvkm_mask(device, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); + nvkm_wr32(device, 0x00b360, base); + nvkm_wr32(device, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) - return -EINVAL; + return false; - nv_wr32(priv, 0x00b370, base); - nv_wr32(priv, 0x00b374, size); + nvkm_wr32(device, 0x00b370, base); + nvkm_wr32(device, 0x00b374, size); } - return 0; + return true; } -static struct nvkm_omthds -nv40_mpeg_omthds[] = { - { 0x0190, 0x0190, nv40_mpeg_mthd_dma }, - { 0x01a0, 0x01a0, nv40_mpeg_mthd_dma }, - { 0x01b0, 0x01b0, nv40_mpeg_mthd_dma }, - {} +static const struct nv31_mpeg_func +nv40_mpeg = { + .mthd_dma = nv40_mpeg_mthd_dma, }; -struct nvkm_oclass -nv40_mpeg_sclass[] = { - { 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds }, - {} -}; - -/******************************************************************************* - * PMPEG engine/subdev functions - ******************************************************************************/ - -static void -nv40_mpeg_intr(struct nvkm_subdev *subdev) +int +nv40_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) { - struct nv31_mpeg_priv *priv = (void *)subdev; - u32 stat; - - if ((stat = nv_rd32(priv, 0x00b100))) - nv31_mpeg_intr(subdev); - - if ((stat = nv_rd32(priv, 0x00b800))) { - nv_error(priv, "PMSRCH 0x%08x\n", stat); - nv_wr32(priv, 0x00b800, stat); - } + return nv31_mpeg_new_(&nv40_mpeg, device, index, pmpeg); } - -static int -nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv31_mpeg_priv *priv; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv40_mpeg_intr; - nv_engine(priv)->cclass = &nv31_mpeg_cclass; - nv_engine(priv)->sclass = nv40_mpeg_sclass; - nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; - return 0; -} - -struct nvkm_oclass -nv40_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv31_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index 4720ac884468..d433cfa4a8ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -21,165 +21,197 @@ * * Authors: Ben Skeggs */ -#include <engine/mpeg.h> +#define nv44_mpeg(p) container_of((p), struct nv44_mpeg, engine) +#include "priv.h" #include <core/client.h> -#include <core/handle.h> +#include <core/gpuobj.h> #include <engine/fifo.h> -struct nv44_mpeg_priv { - struct nvkm_mpeg base; -}; +#include <nvif/class.h> -struct nv44_mpeg_chan { - struct nvkm_mpeg_chan base; +struct nv44_mpeg { + struct nvkm_engine engine; + struct list_head chan; }; /******************************************************************************* * PMPEG context ******************************************************************************/ +#define nv44_mpeg_chan(p) container_of((p), struct nv44_mpeg_chan, object) + +struct nv44_mpeg_chan { + struct nvkm_object object; + struct nv44_mpeg *mpeg; + struct nvkm_fifo_chan *fifo; + struct list_head head; + u32 inst; +}; static int -nv44_mpeg_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv44_mpeg_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv44_mpeg_chan *chan; - int ret; - - ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 264 * 4, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - nv_wo32(&chan->base.base, 0x78, 0x02001ec1); - return 0; + struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); + int ret = nvkm_gpuobj_new(chan->object.engine->subdev.device, 264 * 4, + align, true, parent, pgpuobj); + if (ret == 0) { + chan->inst = (*pgpuobj)->addr; + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x78, 0x02001ec1); + nvkm_done(*pgpuobj); + } + return ret; } static int -nv44_mpeg_context_fini(struct nvkm_object *object, bool suspend) +nv44_mpeg_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv44_mpeg_priv *priv = (void *)object->engine; - struct nv44_mpeg_chan *chan = (void *)object; - u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4; + struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); + struct nv44_mpeg *mpeg = chan->mpeg; + struct nvkm_device *device = mpeg->engine.subdev.device; + u32 inst = 0x80000000 | (chan->inst >> 4); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000); - if (nv_rd32(priv, 0x00b318) == inst) - nv_mask(priv, 0x00b318, 0x80000000, 0x00000000); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000); + if (nvkm_rd32(device, 0x00b318) == inst) + nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); return 0; } -static struct nvkm_oclass -nv44_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x44), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_mpeg_context_ctor, - .dtor = _nvkm_mpeg_context_dtor, - .init = _nvkm_mpeg_context_init, - .fini = nv44_mpeg_context_fini, - .rd32 = _nvkm_mpeg_context_rd32, - .wr32 = _nvkm_mpeg_context_wr32, - }, +static void * +nv44_mpeg_chan_dtor(struct nvkm_object *object) +{ + struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); + struct nv44_mpeg *mpeg = chan->mpeg; + unsigned long flags; + spin_lock_irqsave(&mpeg->engine.lock, flags); + list_del(&chan->head); + spin_unlock_irqrestore(&mpeg->engine.lock, flags); + return chan; +} + +static const struct nvkm_object_func +nv44_mpeg_chan = { + .dtor = nv44_mpeg_chan_dtor, + .fini = nv44_mpeg_chan_fini, + .bind = nv44_mpeg_chan_bind, }; +static int +nv44_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nv44_mpeg *mpeg = nv44_mpeg(oclass->engine); + struct nv44_mpeg_chan *chan; + unsigned long flags; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv44_mpeg_chan, oclass, &chan->object); + chan->mpeg = mpeg; + chan->fifo = fifoch; + *pobject = &chan->object; + + spin_lock_irqsave(&mpeg->engine.lock, flags); + list_add(&chan->head, &mpeg->chan); + spin_unlock_irqrestore(&mpeg->engine.lock, flags); + return 0; +} + /******************************************************************************* * PMPEG engine/subdev functions ******************************************************************************/ +static bool +nv44_mpeg_mthd(struct nvkm_device *device, u32 mthd, u32 data) +{ + switch (mthd) { + case 0x190: + case 0x1a0: + case 0x1b0: + return nv40_mpeg_mthd_dma(device, mthd, data); + default: + break; + } + return false; +} + static void -nv44_mpeg_intr(struct nvkm_subdev *subdev) +nv44_mpeg_intr(struct nvkm_engine *engine) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle; - struct nv44_mpeg_priv *priv = (void *)subdev; - u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff; - u32 stat = nv_rd32(priv, 0x00b100); - u32 type = nv_rd32(priv, 0x00b230); - u32 mthd = nv_rd32(priv, 0x00b234); - u32 data = nv_rd32(priv, 0x00b238); + struct nv44_mpeg *mpeg = nv44_mpeg(engine); + struct nvkm_subdev *subdev = &mpeg->engine.subdev; + struct nvkm_device *device = subdev->device; + struct nv44_mpeg_chan *temp, *chan = NULL; + unsigned long flags; + u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff; + u32 stat = nvkm_rd32(device, 0x00b100); + u32 type = nvkm_rd32(device, 0x00b230); + u32 mthd = nvkm_rd32(device, 0x00b234); + u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; - int chid; - engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + spin_lock_irqsave(&mpeg->engine.lock, flags); + list_for_each_entry(temp, &mpeg->chan, head) { + if (temp->inst >> 4 == inst) { + chan = temp; + list_del(&chan->head); + list_add(&chan->head, &mpeg->chan); + break; + } + } if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_mask(priv, 0x00b308, 0x00000000, 0x00000000); + nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000); show &= ~0x01000000; } if (type == 0x00000010) { - handle = nvkm_handle_get_class(engctx, 0x3174); - if (handle && !nv_call(handle->object, mthd, data)) + if (!nv44_mpeg_mthd(subdev->device, mthd, data)) show &= ~0x01000000; - nvkm_handle_put(handle); } } - nv_wr32(priv, 0x00b100, stat); - nv_wr32(priv, 0x00b230, 0x00000001); + nvkm_wr32(device, 0x00b100, stat); + nvkm_wr32(device, 0x00b230, 0x00000001); if (show) { - nv_error(priv, - "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n", - chid, inst << 4, nvkm_client_name(engctx), stat, - type, mthd, data); + nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n", + chan ? chan->fifo->chid : -1, inst << 4, + chan ? chan->object.client->name : "unknown", + stat, type, mthd, data); } - nvkm_engctx_put(engctx); + spin_unlock_irqrestore(&mpeg->engine.lock, flags); } -static void -nv44_mpeg_me_intr(struct nvkm_subdev *subdev) -{ - struct nv44_mpeg_priv *priv = (void *)subdev; - u32 stat; - - if ((stat = nv_rd32(priv, 0x00b100))) - nv44_mpeg_intr(subdev); - - if ((stat = nv_rd32(priv, 0x00b800))) { - nv_error(priv, "PMSRCH 0x%08x\n", stat); - nv_wr32(priv, 0x00b800, stat); +static const struct nvkm_engine_func +nv44_mpeg = { + .init = nv31_mpeg_init, + .intr = nv44_mpeg_intr, + .tile = nv31_mpeg_tile, + .fifo.cclass = nv44_mpeg_chan_new, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} } -} +}; -static int -nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv44_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) { - struct nv44_mpeg_priv *priv; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv44_mpeg_me_intr; - nv_engine(priv)->cclass = &nv44_mpeg_cclass; - nv_engine(priv)->sclass = nv40_mpeg_sclass; - nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; - return 0; -} + struct nv44_mpeg *mpeg; -struct nvkm_oclass -nv44_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x44), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv31_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, -}; + if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL))) + return -ENOMEM; + INIT_LIST_HEAD(&mpeg->chan); + *pmpeg = &mpeg->engine; + + return nvkm_engine_ctor(&nv44_mpeg, device, index, 0x00000002, + true, &mpeg->engine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index b3463f3739ce..c3a85dffc782 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -21,98 +21,35 @@ * * Authors: Ben Skeggs */ -#include <engine/mpeg.h> +#include "priv.h" -#include <subdev/bar.h> +#include <core/gpuobj.h> #include <subdev/timer.h> -struct nv50_mpeg_priv { - struct nvkm_mpeg base; -}; - -struct nv50_mpeg_chan { - struct nvkm_mpeg_chan base; -}; - -/******************************************************************************* - * MPEG object classes - ******************************************************************************/ - -static int -nv50_mpeg_object_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); - return 0; -} - -struct nvkm_ofuncs -nv50_mpeg_ofuncs = { - .ctor = nv50_mpeg_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv50_mpeg_sclass[] = { - { 0x3174, &nv50_mpeg_ofuncs }, - {} -}; +#include <nvif/class.h> /******************************************************************************* * PMPEG context ******************************************************************************/ -int -nv50_mpeg_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static int +nv50_mpeg_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_mpeg_chan *chan; - int ret; - - ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4, - 0, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - nv_wo32(chan, 0x0070, 0x00801ec1); - nv_wo32(chan, 0x007c, 0x0000037c); - bar->flush(bar); - return 0; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 128 * 4, + align, true, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x70, 0x00801ec1); + nvkm_wo32(*pgpuobj, 0x7c, 0x0000037c); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_oclass +const struct nvkm_object_func nv50_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mpeg_context_ctor, - .dtor = _nvkm_mpeg_context_dtor, - .init = _nvkm_mpeg_context_init, - .fini = _nvkm_mpeg_context_fini, - .rd32 = _nvkm_mpeg_context_rd32, - .wr32 = _nvkm_mpeg_context_wr32, - }, + .bind = nv50_mpeg_cclass_bind, }; /******************************************************************************* @@ -120,106 +57,79 @@ nv50_mpeg_cclass = { ******************************************************************************/ void -nv50_mpeg_intr(struct nvkm_subdev *subdev) +nv50_mpeg_intr(struct nvkm_engine *mpeg) { - struct nv50_mpeg_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x00b100); - u32 type = nv_rd32(priv, 0x00b230); - u32 mthd = nv_rd32(priv, 0x00b234); - u32 data = nv_rd32(priv, 0x00b238); + struct nvkm_subdev *subdev = &mpeg->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x00b100); + u32 type = nvkm_rd32(device, 0x00b230); + u32 mthd = nvkm_rd32(device, 0x00b234); + u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_wr32(priv, 0x00b308, 0x00000100); + nvkm_wr32(device, 0x00b308, 0x00000100); show &= ~0x01000000; } } if (show) { - nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n", - stat, type, mthd, data); - } - - nv_wr32(priv, 0x00b100, stat); - nv_wr32(priv, 0x00b230, 0x00000001); -} - -static void -nv50_vpe_intr(struct nvkm_subdev *subdev) -{ - struct nv50_mpeg_priv *priv = (void *)subdev; - - if (nv_rd32(priv, 0x00b100)) - nv50_mpeg_intr(subdev); - - if (nv_rd32(priv, 0x00b800)) { - u32 stat = nv_rd32(priv, 0x00b800); - nv_info(priv, "PMSRCH: 0x%08x\n", stat); - nv_wr32(priv, 0xb800, stat); + nvkm_info(subdev, "%08x %08x %08x %08x\n", + stat, type, mthd, data); } -} -static int -nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_mpeg_priv *priv; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00400002; - nv_subdev(priv)->intr = nv50_vpe_intr; - nv_engine(priv)->cclass = &nv50_mpeg_cclass; - nv_engine(priv)->sclass = nv50_mpeg_sclass; - return 0; + nvkm_wr32(device, 0x00b100, stat); + nvkm_wr32(device, 0x00b230, 0x00000001); } int -nv50_mpeg_init(struct nvkm_object *object) +nv50_mpeg_init(struct nvkm_engine *mpeg) { - struct nv50_mpeg_priv *priv = (void *)object; - int ret; - - ret = nvkm_mpeg_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x00b32c, 0x00000000); - nv_wr32(priv, 0x00b314, 0x00000100); - nv_wr32(priv, 0x00b0e0, 0x0000001a); - - nv_wr32(priv, 0x00b220, 0x00000044); - nv_wr32(priv, 0x00b300, 0x00801ec1); - nv_wr32(priv, 0x00b390, 0x00000000); - nv_wr32(priv, 0x00b394, 0x00000000); - nv_wr32(priv, 0x00b398, 0x00000000); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); - - nv_wr32(priv, 0x00b100, 0xffffffff); - nv_wr32(priv, 0x00b140, 0xffffffff); - - if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) { - nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200)); + struct nvkm_subdev *subdev = &mpeg->subdev; + struct nvkm_device *device = subdev->device; + + nvkm_wr32(device, 0x00b32c, 0x00000000); + nvkm_wr32(device, 0x00b314, 0x00000100); + nvkm_wr32(device, 0x00b0e0, 0x0000001a); + + nvkm_wr32(device, 0x00b220, 0x00000044); + nvkm_wr32(device, 0x00b300, 0x00801ec1); + nvkm_wr32(device, 0x00b390, 0x00000000); + nvkm_wr32(device, 0x00b394, 0x00000000); + nvkm_wr32(device, 0x00b398, 0x00000000); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); + + nvkm_wr32(device, 0x00b100, 0xffffffff); + nvkm_wr32(device, 0x00b140, 0xffffffff); + + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x00b200) & 0x00000001)) + break; + ) < 0) { + nvkm_error(subdev, "timeout %08x\n", + nvkm_rd32(device, 0x00b200)); return -EBUSY; } return 0; } -struct nvkm_oclass -nv50_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv50_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, +static const struct nvkm_engine_func +nv50_mpeg = { + .init = nv50_mpeg_init, + .intr = nv50_mpeg_intr, + .cclass = &nv50_mpeg_cclass, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } }; + +int +nv50_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) +{ + return nvkm_engine_new_(&nv50_mpeg, device, index, 0x00400002, + true, pmpeg); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h new file mode 100644 index 000000000000..d5753103ff63 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h @@ -0,0 +1,16 @@ +#ifndef __NVKM_MPEG_PRIV_H__ +#define __NVKM_MPEG_PRIV_H__ +#include <engine/mpeg.h> +struct nvkm_fifo_chan; + +int nv31_mpeg_init(struct nvkm_engine *); +void nv31_mpeg_tile(struct nvkm_engine *, int, struct nvkm_fb_tile *); +extern const struct nvkm_object_func nv31_mpeg_object; + +bool nv40_mpeg_mthd_dma(struct nvkm_device *, u32, u32); + +int nv50_mpeg_init(struct nvkm_engine *); +void nv50_mpeg_intr(struct nvkm_engine *); + +extern const struct nvkm_object_func nv50_mpeg_cclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild index c59c83a67315..1a7151146e9d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild @@ -1,3 +1,5 @@ +nvkm-y += nvkm/engine/mspdec/base.o nvkm-y += nvkm/engine/mspdec/g98.o +nvkm-y += nvkm/engine/mspdec/gt215.o nvkm-y += nvkm/engine/mspdec/gf100.o nvkm-y += nvkm/engine/mspdec/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.c new file mode 100644 index 000000000000..80211f76093b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.c @@ -0,0 +1,32 @@ +/* + * 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" + +int +nvkm_mspdec_new_(const struct nvkm_falcon_func *func, + struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_falcon_new_(func, device, index, true, 0x085000, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c index 2174577793a4..1f1a99e927b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c @@ -21,89 +21,31 @@ * * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin */ -#include <engine/mspdec.h> -#include <engine/falcon.h> +#include "priv.h" -struct g98_mspdec_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * MSPDEC object classes - ******************************************************************************/ - -static struct nvkm_oclass -g98_mspdec_sclass[] = { - { 0x88b2, &nvkm_object_ofuncs }, - { 0x85b2, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPDEC context - ******************************************************************************/ - -static struct nvkm_oclass -g98_mspdec_cclass = { - .handle = NV_ENGCTX(MSPDEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPDEC engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> -static int -g98_mspdec_init(struct nvkm_object *object) +void +g98_mspdec_init(struct nvkm_falcon *mspdec) { - struct g98_mspdec_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x085010, 0x0000ffd2); - nv_wr32(priv, 0x08501c, 0x0000fff2); - return 0; + struct nvkm_device *device = mspdec->engine.subdev.device; + nvkm_wr32(device, 0x085010, 0x0000ffd2); + nvkm_wr32(device, 0x08501c, 0x0000fff2); } -static int -g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct g98_mspdec_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_falcon_func +g98_mspdec = { + .pmc_enable = 0x01020000, + .init = g98_mspdec_init, + .sclass = { + { -1, -1, G98_MSPDEC }, + {} + } +}; - nv_subdev(priv)->unit = 0x01020000; - nv_engine(priv)->cclass = &g98_mspdec_cclass; - nv_engine(priv)->sclass = g98_mspdec_sclass; - return 0; +int +g98_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_mspdec_new_(&g98_mspdec, device, index, pengine); } - -struct nvkm_oclass -g98_mspdec_oclass = { - .handle = NV_ENGINE(MSPDEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_mspdec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = g98_mspdec_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c index c814a5f65eb0..371fd6c3c663 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c @@ -21,89 +21,31 @@ * * Authors: Maarten Lankhorst */ -#include <engine/mspdec.h> -#include <engine/falcon.h> +#include "priv.h" -struct gf100_mspdec_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * MSPDEC object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_mspdec_sclass[] = { - { 0x90b2, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPDEC context - ******************************************************************************/ - -static struct nvkm_oclass -gf100_mspdec_cclass = { - .handle = NV_ENGCTX(MSPDEC, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPDEC engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> -static int -gf100_mspdec_init(struct nvkm_object *object) +void +gf100_mspdec_init(struct nvkm_falcon *mspdec) { - struct gf100_mspdec_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x085010, 0x0000fff2); - nv_wr32(priv, 0x08501c, 0x0000fff2); - return 0; + struct nvkm_device *device = mspdec->engine.subdev.device; + nvkm_wr32(device, 0x085010, 0x0000fff2); + nvkm_wr32(device, 0x08501c, 0x0000fff2); } -static int -gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_mspdec_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_falcon_func +gf100_mspdec = { + .pmc_enable = 0x00020000, + .init = gf100_mspdec_init, + .sclass = { + { -1, -1, GF100_MSPDEC }, + {} + } +}; - nv_subdev(priv)->unit = 0x00020000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gf100_mspdec_cclass; - nv_engine(priv)->sclass = gf100_mspdec_sclass; - return 0; +int +gf100_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_mspdec_new_(&gf100_mspdec, device, index, pengine); } - -struct nvkm_oclass -gf100_mspdec_oclass = { - .handle = NV_ENGINE(MSPDEC, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_mspdec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_mspdec_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c index 979920650dbd..de804a15bfd4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c @@ -21,89 +21,23 @@ * * Authors: Ben Skeggs */ -#include <engine/mspdec.h> -#include <engine/falcon.h> - -struct gk104_mspdec_priv { - struct nvkm_falcon base; +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_falcon_func +gk104_mspdec = { + .pmc_enable = 0x00020000, + .init = gf100_mspdec_init, + .sclass = { + { -1, -1, GK104_MSPDEC }, + {} + } }; -/******************************************************************************* - * MSPDEC object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_mspdec_sclass[] = { - { 0x95b2, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPDEC context - ******************************************************************************/ - -static struct nvkm_oclass -gk104_mspdec_cclass = { - .handle = NV_ENGCTX(MSPDEC, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPDEC engine/subdev functions - ******************************************************************************/ - -static int -gk104_mspdec_init(struct nvkm_object *object) +int +gk104_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct gk104_mspdec_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x085010, 0x0000fff2); - nv_wr32(priv, 0x08501c, 0x0000fff2); - return 0; -} - -static int -gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk104_mspdec_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00020000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gk104_mspdec_cclass; - nv_engine(priv)->sclass = gk104_mspdec_sclass; - return 0; + return nvkm_mspdec_new_(&gk104_mspdec, device, index, pengine); } - -struct nvkm_oclass -gk104_mspdec_oclass = { - .handle = NV_ENGINE(MSPDEC, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_mspdec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gk104_mspdec_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.c new file mode 100644 index 000000000000..835631713c95 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_falcon_func +gt215_mspdec = { + .pmc_enable = 0x01020000, + .init = g98_mspdec_init, + .sclass = { + { -1, -1, GT212_MSPDEC }, + {} + } +}; + +int +gt215_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_mspdec_new_(>215_mspdec, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h new file mode 100644 index 000000000000..d518af4bc9de --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h @@ -0,0 +1,11 @@ +#ifndef __NVKM_MSPDEC_PRIV_H__ +#define __NVKM_MSPDEC_PRIV_H__ +#include <engine/mspdec.h> + +int nvkm_mspdec_new_(const struct nvkm_falcon_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +void g98_mspdec_init(struct nvkm_falcon *); + +void gf100_mspdec_init(struct nvkm_falcon *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild index 4576a9eee39d..3ea7eafb408f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild @@ -1,2 +1,4 @@ +nvkm-y += nvkm/engine/msppp/base.o nvkm-y += nvkm/engine/msppp/g98.o +nvkm-y += nvkm/engine/msppp/gt215.o nvkm-y += nvkm/engine/msppp/gf100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.c new file mode 100644 index 000000000000..bfae5e60e925 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.c @@ -0,0 +1,31 @@ +/* + * 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" + +int +nvkm_msppp_new_(const struct nvkm_falcon_func *func, struct nvkm_device *device, + int index, struct nvkm_engine **pengine) +{ + return nvkm_falcon_new_(func, device, index, true, 0x086000, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c index 7a602a2dec94..73f633ae2ee7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c @@ -21,89 +21,31 @@ * * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin */ -#include <engine/msppp.h> -#include <engine/falcon.h> +#include "priv.h" -struct g98_msppp_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * MSPPP object classes - ******************************************************************************/ - -static struct nvkm_oclass -g98_msppp_sclass[] = { - { 0x88b3, &nvkm_object_ofuncs }, - { 0x85b3, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPPP context - ******************************************************************************/ - -static struct nvkm_oclass -g98_msppp_cclass = { - .handle = NV_ENGCTX(MSPPP, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPPP engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> -static int -g98_msppp_init(struct nvkm_object *object) +void +g98_msppp_init(struct nvkm_falcon *msppp) { - struct g98_msppp_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x086010, 0x0000ffd2); - nv_wr32(priv, 0x08601c, 0x0000fff2); - return 0; + struct nvkm_device *device = msppp->engine.subdev.device; + nvkm_wr32(device, 0x086010, 0x0000ffd2); + nvkm_wr32(device, 0x08601c, 0x0000fff2); } -static int -g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct g98_msppp_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true, - "PMSPPP", "msppp", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_falcon_func +g98_msppp = { + .pmc_enable = 0x00400002, + .init = g98_msppp_init, + .sclass = { + { -1, -1, G98_MSPPP }, + {} + } +}; - nv_subdev(priv)->unit = 0x00400002; - nv_engine(priv)->cclass = &g98_msppp_cclass; - nv_engine(priv)->sclass = g98_msppp_sclass; - return 0; +int +g98_msppp_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msppp_new_(&g98_msppp, device, index, pengine); } - -struct nvkm_oclass -g98_msppp_oclass = { - .handle = NV_ENGINE(MSPPP, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_msppp_ctor, - .dtor = _nvkm_falcon_dtor, - .init = g98_msppp_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c index 6047baee1f75..c42c0c07e2db 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c @@ -21,89 +21,31 @@ * * Authors: Maarten Lankhorst */ -#include <engine/msppp.h> -#include <engine/falcon.h> +#include "priv.h" -struct gf100_msppp_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * MSPPP object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msppp_sclass[] = { - { 0x90b3, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPPP context - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msppp_cclass = { - .handle = NV_ENGCTX(MSPPP, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPPP engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> -static int -gf100_msppp_init(struct nvkm_object *object) +static void +gf100_msppp_init(struct nvkm_falcon *msppp) { - struct gf100_msppp_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x086010, 0x0000fff2); - nv_wr32(priv, 0x08601c, 0x0000fff2); - return 0; + struct nvkm_device *device = msppp->engine.subdev.device; + nvkm_wr32(device, 0x086010, 0x0000fff2); + nvkm_wr32(device, 0x08601c, 0x0000fff2); } -static int -gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_msppp_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true, - "PMSPPP", "msppp", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_falcon_func +gf100_msppp = { + .pmc_enable = 0x00000002, + .init = gf100_msppp_init, + .sclass = { + { -1, -1, GF100_MSPPP }, + {} + } +}; - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gf100_msppp_cclass; - nv_engine(priv)->sclass = gf100_msppp_sclass; - return 0; +int +gf100_msppp_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msppp_new_(&gf100_msppp, device, index, pengine); } - -struct nvkm_oclass -gf100_msppp_oclass = { - .handle = NV_ENGINE(MSPPP, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_msppp_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_msppp_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.c new file mode 100644 index 000000000000..00e7795f1d51 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_falcon_func +gt215_msppp = { + .pmc_enable = 0x00400002, + .init = g98_msppp_init, + .sclass = { + { -1, -1, GT212_MSPPP }, + {} + } +}; + +int +gt215_msppp_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msppp_new_(>215_msppp, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h new file mode 100644 index 000000000000..37a91f9d9181 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h @@ -0,0 +1,9 @@ +#ifndef __NVKM_MSPPP_PRIV_H__ +#define __NVKM_MSPPP_PRIV_H__ +#include <engine/msppp.h> + +int nvkm_msppp_new_(const struct nvkm_falcon_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +void g98_msppp_init(struct nvkm_falcon *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild index 0c9811009e28..28c8ecd27b6d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild @@ -1,3 +1,6 @@ +nvkm-y += nvkm/engine/msvld/base.o nvkm-y += nvkm/engine/msvld/g98.o +nvkm-y += nvkm/engine/msvld/gt215.o +nvkm-y += nvkm/engine/msvld/mcp89.o nvkm-y += nvkm/engine/msvld/gf100.o nvkm-y += nvkm/engine/msvld/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.c new file mode 100644 index 000000000000..745bbb653dc0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.c @@ -0,0 +1,31 @@ +/* + * 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" + +int +nvkm_msvld_new_(const struct nvkm_falcon_func *func, struct nvkm_device *device, + int index, struct nvkm_engine **pengine) +{ + return nvkm_falcon_new_(func, device, index, true, 0x084000, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c index c8a6b4ef52a1..47e2929bfaf0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c @@ -21,90 +21,31 @@ * * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin */ -#include <engine/msvld.h> -#include <engine/falcon.h> +#include "priv.h" -struct g98_msvld_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * MSVLD object classes - ******************************************************************************/ - -static struct nvkm_oclass -g98_msvld_sclass[] = { - { 0x88b1, &nvkm_object_ofuncs }, - { 0x85b1, &nvkm_object_ofuncs }, - { 0x86b1, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSVLD context - ******************************************************************************/ - -static struct nvkm_oclass -g98_msvld_cclass = { - .handle = NV_ENGCTX(MSVLD, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSVLD engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> -static int -g98_msvld_init(struct nvkm_object *object) +void +g98_msvld_init(struct nvkm_falcon *msvld) { - struct g98_msvld_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x084010, 0x0000ffd2); - nv_wr32(priv, 0x08401c, 0x0000fff2); - return 0; + struct nvkm_device *device = msvld->engine.subdev.device; + nvkm_wr32(device, 0x084010, 0x0000ffd2); + nvkm_wr32(device, 0x08401c, 0x0000fff2); } -static int -g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct g98_msvld_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_falcon_func +g98_msvld = { + .pmc_enable = 0x04008000, + .init = g98_msvld_init, + .sclass = { + { -1, -1, G98_MSVLD }, + {} + } +}; - nv_subdev(priv)->unit = 0x04008000; - nv_engine(priv)->cclass = &g98_msvld_cclass; - nv_engine(priv)->sclass = g98_msvld_sclass; - return 0; +int +g98_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msvld_new_(&g98_msvld, device, index, pengine); } - -struct nvkm_oclass -g98_msvld_oclass = { - .handle = NV_ENGINE(MSVLD, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_msvld_ctor, - .dtor = _nvkm_falcon_dtor, - .init = g98_msvld_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c index b8d1e0f521ef..1ac581ba9f96 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c @@ -21,89 +21,31 @@ * * Authors: Maarten Lankhorst */ -#include <engine/msvld.h> -#include <engine/falcon.h> +#include "priv.h" -struct gf100_msvld_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * MSVLD object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msvld_sclass[] = { - { 0x90b1, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSVLD context - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msvld_cclass = { - .handle = NV_ENGCTX(MSVLD, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSVLD engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> -static int -gf100_msvld_init(struct nvkm_object *object) +void +gf100_msvld_init(struct nvkm_falcon *msvld) { - struct gf100_msvld_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x084010, 0x0000fff2); - nv_wr32(priv, 0x08401c, 0x0000fff2); - return 0; + struct nvkm_device *device = msvld->engine.subdev.device; + nvkm_wr32(device, 0x084010, 0x0000fff2); + nvkm_wr32(device, 0x08401c, 0x0000fff2); } -static int -gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_msvld_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_falcon_func +gf100_msvld = { + .pmc_enable = 0x00008000, + .init = gf100_msvld_init, + .sclass = { + { -1, -1, GF100_MSVLD }, + {} + } +}; - nv_subdev(priv)->unit = 0x00008000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gf100_msvld_cclass; - nv_engine(priv)->sclass = gf100_msvld_sclass; - return 0; +int +gf100_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msvld_new_(&gf100_msvld, device, index, pengine); } - -struct nvkm_oclass -gf100_msvld_oclass = { - .handle = NV_ENGINE(MSVLD, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_msvld_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_msvld_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c index a0b0927834df..4bba16e0f560 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c @@ -21,89 +21,23 @@ * * Authors: Ben Skeggs */ -#include <engine/msvld.h> -#include <engine/falcon.h> - -struct gk104_msvld_priv { - struct nvkm_falcon base; +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_falcon_func +gk104_msvld = { + .pmc_enable = 0x00008000, + .init = gf100_msvld_init, + .sclass = { + { -1, -1, GK104_MSVLD }, + {} + } }; -/******************************************************************************* - * MSVLD object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_msvld_sclass[] = { - { 0x95b1, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSVLD context - ******************************************************************************/ - -static struct nvkm_oclass -gk104_msvld_cclass = { - .handle = NV_ENGCTX(MSVLD, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSVLD engine/subdev functions - ******************************************************************************/ - -static int -gk104_msvld_init(struct nvkm_object *object) +int +gk104_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct gk104_msvld_priv *priv = (void *)object; - int ret; - - ret = nvkm_falcon_init(&priv->base); - if (ret) - return ret; - - nv_wr32(priv, 0x084010, 0x0000fff2); - nv_wr32(priv, 0x08401c, 0x0000fff2); - return 0; -} - -static int -gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gk104_msvld_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00008000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gk104_msvld_cclass; - nv_engine(priv)->sclass = gk104_msvld_sclass; - return 0; + return nvkm_msvld_new_(&gk104_msvld, device, index, pengine); } - -struct nvkm_oclass -gk104_msvld_oclass = { - .handle = NV_ENGINE(MSVLD, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_msvld_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gk104_msvld_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.c new file mode 100644 index 000000000000..e17cb5605b2d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_falcon_func +gt215_msvld = { + .pmc_enable = 0x04008000, + .init = g98_msvld_init, + .sclass = { + { -1, -1, GT212_MSVLD }, + {} + } +}; + +int +gt215_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msvld_new_(>215_msvld, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c new file mode 100644 index 000000000000..511800f6a43b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include <nvif/class.h> + +static const struct nvkm_falcon_func +mcp89_msvld = { + .pmc_enable = 0x04008000, + .init = g98_msvld_init, + .sclass = { + { -1, -1, IGT21A_MSVLD }, + {} + } +}; + +int +mcp89_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msvld_new_(&mcp89_msvld, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h new file mode 100644 index 000000000000..9dc1da67d929 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h @@ -0,0 +1,11 @@ +#ifndef __NVKM_MSVLD_PRIV_H__ +#define __NVKM_MSVLD_PRIV_H__ +#include <engine/msvld.h> + +int nvkm_msvld_new_(const struct nvkm_falcon_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +void g98_msvld_init(struct nvkm_falcon *); + +void gf100_msvld_init(struct nvkm_falcon *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild index 413b6091e256..1614d385fb0c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild @@ -1,9 +1,10 @@ nvkm-y += nvkm/engine/pm/base.o -nvkm-y += nvkm/engine/pm/daemon.o nvkm-y += nvkm/engine/pm/nv40.o nvkm-y += nvkm/engine/pm/nv50.o nvkm-y += nvkm/engine/pm/g84.o +nvkm-y += nvkm/engine/pm/gt200.o nvkm-y += nvkm/engine/pm/gt215.o nvkm-y += nvkm/engine/pm/gf100.o +nvkm-y += nvkm/engine/pm/gf108.o +nvkm-y += nvkm/engine/pm/gf117.o nvkm-y += nvkm/engine/pm/gk104.o -nvkm-y += nvkm/engine/pm/gk110.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 2006c445938d..0db9be202c42 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -24,368 +24,751 @@ #include "priv.h" #include <core/client.h> -#include <core/device.h> #include <core/option.h> #include <nvif/class.h> #include <nvif/ioctl.h> #include <nvif/unpack.h> -#define QUAD_MASK 0x0f -#define QUAD_FREE 0x01 +static u8 +nvkm_pm_count_perfdom(struct nvkm_pm *pm) +{ + struct nvkm_perfdom *dom; + u8 domain_nr = 0; -static struct nvkm_perfsig * -nvkm_perfsig_find_(struct nvkm_perfdom *dom, const char *name, u32 size) + list_for_each_entry(dom, &pm->domains, head) + domain_nr++; + return domain_nr; +} + +static u16 +nvkm_perfdom_count_perfsig(struct nvkm_perfdom *dom) { - char path[64]; + u16 signal_nr = 0; int i; - if (name[0] != '/') { + if (dom) { for (i = 0; i < dom->signal_nr; i++) { - if ( dom->signal[i].name && - !strncmp(name, dom->signal[i].name, size)) - return &dom->signal[i]; - } - } else { - for (i = 0; i < dom->signal_nr; i++) { - snprintf(path, sizeof(path), "/%s/%02x", dom->name, i); - if (!strncmp(name, path, size)) - return &dom->signal[i]; + if (dom->signal[i].name) + signal_nr++; } } + return signal_nr; +} +static struct nvkm_perfdom * +nvkm_perfdom_find(struct nvkm_pm *pm, int di) +{ + struct nvkm_perfdom *dom; + int tmp = 0; + + list_for_each_entry(dom, &pm->domains, head) { + if (tmp++ == di) + return dom; + } return NULL; } struct nvkm_perfsig * -nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size, - struct nvkm_perfdom **pdom) +nvkm_perfsig_find(struct nvkm_pm *pm, u8 di, u8 si, struct nvkm_perfdom **pdom) { struct nvkm_perfdom *dom = *pdom; - struct nvkm_perfsig *sig; if (dom == NULL) { - list_for_each_entry(dom, &ppm->domains, head) { - sig = nvkm_perfsig_find_(dom, name, size); - if (sig) { - *pdom = dom; - return sig; - } - } + dom = nvkm_perfdom_find(pm, di); + if (dom == NULL) + return NULL; + *pdom = dom; + } + if (!dom->signal[si].name) return NULL; - } + return &dom->signal[si]; +} - return nvkm_perfsig_find_(dom, name, size); +static u8 +nvkm_perfsig_count_perfsrc(struct nvkm_perfsig *sig) +{ + u8 source_nr = 0, i; + + for (i = 0; i < ARRAY_SIZE(sig->source); i++) { + if (sig->source[i]) + source_nr++; + } + return source_nr; } -struct nvkm_perfctr * -nvkm_perfsig_wrap(struct nvkm_pm *ppm, const char *name, - struct nvkm_perfdom **pdom) +static struct nvkm_perfsrc * +nvkm_perfsrc_find(struct nvkm_pm *pm, struct nvkm_perfsig *sig, int si) { - struct nvkm_perfsig *sig; - struct nvkm_perfctr *ctr; + struct nvkm_perfsrc *src; + bool found = false; + int tmp = 1; /* Sources ID start from 1 */ + u8 i; + + for (i = 0; i < ARRAY_SIZE(sig->source) && sig->source[i]; i++) { + if (sig->source[i] == si) { + found = true; + break; + } + } - sig = nvkm_perfsig_find(ppm, name, strlen(name), pdom); - if (!sig) - return NULL; + if (found) { + list_for_each_entry(src, &pm->sources, head) { + if (tmp++ == si) + return src; + } + } - ctr = kzalloc(sizeof(*ctr), GFP_KERNEL); - if (ctr) { - ctr->signal[0] = sig; - ctr->logic_op = 0xaaaa; + return NULL; +} + +static int +nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) +{ + struct nvkm_subdev *subdev = &pm->engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_perfdom *dom = NULL; + struct nvkm_perfsig *sig; + struct nvkm_perfsrc *src; + u32 mask, value; + int i, j; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 8 && ctr->source[i][j]; j++) { + sig = nvkm_perfsig_find(pm, ctr->domain, + ctr->signal[i], &dom); + if (!sig) + return -EINVAL; + + src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]); + if (!src) + return -EINVAL; + + /* set enable bit if needed */ + mask = value = 0x00000000; + if (src->enable) + mask = value = 0x80000000; + mask |= (src->mask << src->shift); + value |= ((ctr->source[i][j] >> 32) << src->shift); + + /* enable the source */ + nvkm_mask(device, src->addr, mask, value); + nvkm_debug(subdev, + "enabled source %08x %08x %08x\n", + src->addr, mask, value); + } } + return 0; +} - return ctr; +static int +nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) +{ + struct nvkm_subdev *subdev = &pm->engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_perfdom *dom = NULL; + struct nvkm_perfsig *sig; + struct nvkm_perfsrc *src; + u32 mask; + int i, j; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 8 && ctr->source[i][j]; j++) { + sig = nvkm_perfsig_find(pm, ctr->domain, + ctr->signal[i], &dom); + if (!sig) + return -EINVAL; + + src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]); + if (!src) + return -EINVAL; + + /* unset enable bit if needed */ + mask = 0x00000000; + if (src->enable) + mask = 0x80000000; + mask |= (src->mask << src->shift); + + /* disable the source */ + nvkm_mask(device, src->addr, mask, 0); + nvkm_debug(subdev, "disabled source %08x %08x\n", + src->addr, mask); + } + } + return 0; } /******************************************************************************* - * Perfmon object classes + * Perfdom object classes ******************************************************************************/ static int -nvkm_perfctr_query(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_init(struct nvkm_perfdom *dom, void *data, u32 size) { union { - struct nvif_perfctr_query_v0 v0; + struct nvif_perfdom_init none; } *args = data; - struct nvkm_device *device = nv_device(object); - struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfdom *dom = NULL, *chk; - const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); - const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all); - const char *name; - int tmp = 0, di, si; + struct nvkm_object *object = &dom->object; + struct nvkm_pm *pm = dom->perfmon->pm; + int ret, i; + + nvif_ioctl(object, "perfdom init size %d\n", size); + if (nvif_unvers(args->none)) { + nvif_ioctl(object, "perfdom init\n"); + } else + return ret; + + for (i = 0; i < 4; i++) { + if (dom->ctr[i]) { + dom->func->init(pm, dom, dom->ctr[i]); + + /* enable sources */ + nvkm_perfsrc_enable(pm, dom->ctr[i]); + } + } + + /* start next batch of counters for sampling */ + dom->func->next(pm, dom); + return 0; +} + +static int +nvkm_perfdom_sample(struct nvkm_perfdom *dom, void *data, u32 size) +{ + union { + struct nvif_perfdom_sample none; + } *args = data; + struct nvkm_object *object = &dom->object; + struct nvkm_pm *pm = dom->perfmon->pm; int ret; - nv_ioctl(object, "perfctr query size %d\n", size); + nvif_ioctl(object, "perfdom sample size %d\n", size); + if (nvif_unvers(args->none)) { + nvif_ioctl(object, "perfdom sample\n"); + } else + return ret; + pm->sequence++; + + /* sample previous batch of counters */ + list_for_each_entry(dom, &pm->domains, head) + dom->func->next(pm, dom); + + return 0; +} + +static int +nvkm_perfdom_read(struct nvkm_perfdom *dom, void *data, u32 size) +{ + union { + struct nvif_perfdom_read_v0 v0; + } *args = data; + struct nvkm_object *object = &dom->object; + struct nvkm_pm *pm = dom->perfmon->pm; + int ret, i; + + nvif_ioctl(object, "perfdom read size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfctr query vers %d iter %08x\n", - args->v0.version, args->v0.iter); - di = (args->v0.iter & 0xff000000) >> 24; - si = (args->v0.iter & 0x00ffffff) - 1; + nvif_ioctl(object, "perfdom read vers %d\n", args->v0.version); } else return ret; - list_for_each_entry(chk, &ppm->domains, head) { - if (tmp++ == di) { - dom = chk; - break; - } + for (i = 0; i < 4; i++) { + if (dom->ctr[i]) + dom->func->read(pm, dom, dom->ctr[i]); } - if (dom == NULL || si >= (int)dom->signal_nr) - return -EINVAL; + if (!dom->clk) + return -EAGAIN; - if (si >= 0) { - if (raw || !(name = dom->signal[si].name)) { - snprintf(args->v0.name, sizeof(args->v0.name), - "/%s/%02x", dom->name, si); - } else { - strncpy(args->v0.name, name, sizeof(args->v0.name)); + for (i = 0; i < 4; i++) + if (dom->ctr[i]) + args->v0.ctr[i] = dom->ctr[i]->ctr; + args->v0.clk = dom->clk; + return 0; +} + +static int +nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + struct nvkm_perfdom *dom = nvkm_perfdom(object); + switch (mthd) { + case NVIF_PERFDOM_V0_INIT: + return nvkm_perfdom_init(dom, data, size); + case NVIF_PERFDOM_V0_SAMPLE: + return nvkm_perfdom_sample(dom, data, size); + case NVIF_PERFDOM_V0_READ: + return nvkm_perfdom_read(dom, data, size); + default: + break; + } + return -EINVAL; +} + +static void * +nvkm_perfdom_dtor(struct nvkm_object *object) +{ + struct nvkm_perfdom *dom = nvkm_perfdom(object); + struct nvkm_pm *pm = dom->perfmon->pm; + int i; + + for (i = 0; i < 4; i++) { + struct nvkm_perfctr *ctr = dom->ctr[i]; + if (ctr) { + nvkm_perfsrc_disable(pm, ctr); + if (ctr->head.next) + list_del(&ctr->head); } + kfree(ctr); } - do { - while (++si < dom->signal_nr) { - if (all || dom->signal[si].name) { - args->v0.iter = (di << 24) | ++si; - return 0; - } + return dom; +} + +static int +nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, u8 domain, + struct nvkm_perfsig *signal[4], u64 source[4][8], + u16 logic_op, struct nvkm_perfctr **pctr) +{ + struct nvkm_perfctr *ctr; + int i, j; + + if (!dom) + return -EINVAL; + + ctr = *pctr = kzalloc(sizeof(*ctr), GFP_KERNEL); + if (!ctr) + return -ENOMEM; + + ctr->domain = domain; + ctr->logic_op = logic_op; + ctr->slot = slot; + for (i = 0; i < 4; i++) { + if (signal[i]) { + ctr->signal[i] = signal[i] - dom->signal; + for (j = 0; j < 8; j++) + ctr->source[i][j] = source[i][j]; } - si = -1; - di = di + 1; - dom = list_entry(dom->head.next, typeof(*dom), head); - } while (&dom->head != &ppm->domains); + } + list_add_tail(&ctr->head, &dom->list); - args->v0.iter = 0xffffffff; return 0; } +static const struct nvkm_object_func +nvkm_perfdom = { + .dtor = nvkm_perfdom_dtor, + .mthd = nvkm_perfdom_mthd, +}; + static int -nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_new_(struct nvkm_perfmon *perfmon, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { union { - struct nvif_perfctr_sample none; + struct nvif_perfdom_v0 v0; } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfctr *ctr, *tmp; + struct nvkm_pm *pm = perfmon->pm; + struct nvkm_object *parent = oclass->parent; + struct nvkm_perfdom *sdom = NULL; + struct nvkm_perfctr *ctr[4] = {}; struct nvkm_perfdom *dom; + int c, s, m; int ret; - nv_ioctl(object, "perfctr sample size %d\n", size); - if (nvif_unvers(args->none)) { - nv_ioctl(object, "perfctr sample\n"); + nvif_ioctl(parent, "create perfdom size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n", + args->v0.version, args->v0.domain, args->v0.mode); } else return ret; - ppm->sequence++; - - list_for_each_entry(dom, &ppm->domains, head) { - /* sample previous batch of counters */ - if (dom->quad != QUAD_MASK) { - dom->func->next(ppm, dom); - tmp = NULL; - while (!list_empty(&dom->list)) { - ctr = list_first_entry(&dom->list, - typeof(*ctr), head); - if (ctr->slot < 0) break; - if ( tmp && tmp == ctr) break; - if (!tmp) tmp = ctr; - dom->func->read(ppm, dom, ctr); - ctr->slot = -1; - list_move_tail(&ctr->head, &dom->list); - } - } - dom->quad = QUAD_MASK; - - /* setup next batch of counters for sampling */ - list_for_each_entry(ctr, &dom->list, head) { - ctr->slot = ffs(dom->quad) - 1; - if (ctr->slot < 0) - break; - dom->quad &= ~(QUAD_FREE << ctr->slot); - dom->func->init(ppm, dom, ctr); + for (c = 0; c < ARRAY_SIZE(args->v0.ctr); c++) { + struct nvkm_perfsig *sig[4] = {}; + u64 src[4][8] = {}; + + for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) { + sig[s] = nvkm_perfsig_find(pm, args->v0.domain, + args->v0.ctr[c].signal[s], + &sdom); + if (args->v0.ctr[c].signal[s] && !sig[s]) + return -EINVAL; + + for (m = 0; m < 8; m++) { + src[s][m] = args->v0.ctr[c].source[s][m]; + if (src[s][m] && !nvkm_perfsrc_find(pm, sig[s], + src[s][m])) + return -EINVAL; + } } - if (dom->quad != QUAD_MASK) - dom->func->next(ppm, dom); + ret = nvkm_perfctr_new(sdom, c, args->v0.domain, sig, src, + args->v0.ctr[c].logic_op, &ctr[c]); + if (ret) + return ret; } + if (!sdom) + return -EINVAL; + + if (!(dom = kzalloc(sizeof(*dom), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nvkm_perfdom, oclass, &dom->object); + dom->perfmon = perfmon; + *pobject = &dom->object; + + dom->func = sdom->func; + dom->addr = sdom->addr; + dom->mode = args->v0.mode; + for (c = 0; c < ARRAY_SIZE(ctr); c++) + dom->ctr[c] = ctr[c]; return 0; } +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ static int -nvkm_perfctr_read(struct nvkm_object *object, void *data, u32 size) +nvkm_perfmon_mthd_query_domain(struct nvkm_perfmon *perfmon, + void *data, u32 size) { union { - struct nvif_perfctr_read_v0 v0; + struct nvif_perfmon_query_domain_v0 v0; } *args = data; - struct nvkm_perfctr *ctr = (void *)object; - int ret; + struct nvkm_object *object = &perfmon->object; + struct nvkm_pm *pm = perfmon->pm; + struct nvkm_perfdom *dom; + u8 domain_nr; + int di, ret; - nv_ioctl(object, "perfctr read size %d\n", size); + nvif_ioctl(object, "perfmon query domain size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfctr read vers %d\n", args->v0.version); + nvif_ioctl(object, "perfmon domain vers %d iter %02x\n", + args->v0.version, args->v0.iter); + di = (args->v0.iter & 0xff) - 1; } else return ret; - if (!ctr->clk) - return -EAGAIN; + domain_nr = nvkm_pm_count_perfdom(pm); + if (di >= (int)domain_nr) + return -EINVAL; + + if (di >= 0) { + dom = nvkm_perfdom_find(pm, di); + if (dom == NULL) + return -EINVAL; + + args->v0.id = di; + args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom); + strncpy(args->v0.name, dom->name, sizeof(args->v0.name)); + + /* Currently only global counters (PCOUNTER) are implemented + * but this will be different for local counters (MP). */ + args->v0.counter_nr = 4; + } - args->v0.clk = ctr->clk; - args->v0.ctr = ctr->ctr; + if (++di < domain_nr) { + args->v0.iter = ++di; + return 0; + } + + args->v0.iter = 0xff; return 0; } static int -nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +nvkm_perfmon_mthd_query_signal(struct nvkm_perfmon *perfmon, + void *data, u32 size) { - switch (mthd) { - case NVIF_PERFCTR_V0_QUERY: - return nvkm_perfctr_query(object, data, size); - case NVIF_PERFCTR_V0_SAMPLE: - return nvkm_perfctr_sample(object, data, size); - case NVIF_PERFCTR_V0_READ: - return nvkm_perfctr_read(object, data, size); - default: - break; + union { + struct nvif_perfmon_query_signal_v0 v0; + } *args = data; + struct nvkm_object *object = &perfmon->object; + struct nvkm_pm *pm = perfmon->pm; + struct nvkm_device *device = pm->engine.subdev.device; + struct nvkm_perfdom *dom; + struct nvkm_perfsig *sig; + const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); + const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all); + int ret, si; + + nvif_ioctl(object, "perfmon query signal size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, + "perfmon query signal vers %d dom %d iter %04x\n", + args->v0.version, args->v0.domain, args->v0.iter); + si = (args->v0.iter & 0xffff) - 1; + } else + return ret; + + dom = nvkm_perfdom_find(pm, args->v0.domain); + if (dom == NULL || si >= (int)dom->signal_nr) + return -EINVAL; + + if (si >= 0) { + sig = &dom->signal[si]; + if (raw || !sig->name) { + snprintf(args->v0.name, sizeof(args->v0.name), + "/%s/%02x", dom->name, si); + } else { + strncpy(args->v0.name, sig->name, + sizeof(args->v0.name)); + } + + args->v0.signal = si; + args->v0.source_nr = nvkm_perfsig_count_perfsrc(sig); } - return -EINVAL; -} -static void -nvkm_perfctr_dtor(struct nvkm_object *object) -{ - struct nvkm_perfctr *ctr = (void *)object; - if (ctr->head.next) - list_del(&ctr->head); - nvkm_object_destroy(&ctr->base); + while (++si < dom->signal_nr) { + if (all || dom->signal[si].name) { + args->v0.iter = ++si; + return 0; + } + } + + args->v0.iter = 0xffff; + return 0; } static int -nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_perfmon_mthd_query_source(struct nvkm_perfmon *perfmon, + void *data, u32 size) { union { - struct nvif_perfctr_v0 v0; + struct nvif_perfmon_query_source_v0 v0; } *args = data; - struct nvkm_pm *ppm = (void *)engine; + struct nvkm_object *object = &perfmon->object; + struct nvkm_pm *pm = perfmon->pm; struct nvkm_perfdom *dom = NULL; - struct nvkm_perfsig *sig[4] = {}; - struct nvkm_perfctr *ctr; - int ret, i; + struct nvkm_perfsig *sig; + struct nvkm_perfsrc *src; + u8 source_nr = 0; + int si, ret; - nv_ioctl(parent, "create perfctr size %d\n", size); + nvif_ioctl(object, "perfmon query source size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n", - args->v0.version, args->v0.logic_op); + nvif_ioctl(object, + "perfmon source vers %d dom %d sig %02x iter %02x\n", + args->v0.version, args->v0.domain, args->v0.signal, + args->v0.iter); + si = (args->v0.iter & 0xff) - 1; } else return ret; - for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) { - sig[i] = nvkm_perfsig_find(ppm, args->v0.name[i], - strnlen(args->v0.name[i], - sizeof(args->v0.name[i])), - &dom); - if (!sig[i]) + sig = nvkm_perfsig_find(pm, args->v0.domain, args->v0.signal, &dom); + if (!sig) + return -EINVAL; + + source_nr = nvkm_perfsig_count_perfsrc(sig); + if (si >= (int)source_nr) + return -EINVAL; + + if (si >= 0) { + src = nvkm_perfsrc_find(pm, sig, sig->source[si]); + if (!src) return -EINVAL; + + args->v0.source = sig->source[si]; + args->v0.mask = src->mask; + strncpy(args->v0.name, src->name, sizeof(args->v0.name)); } - ret = nvkm_object_create(parent, engine, oclass, 0, &ctr); - *pobject = nv_object(ctr); - if (ret) - return ret; + if (++si < source_nr) { + args->v0.iter = ++si; + return 0; + } - ctr->slot = -1; - ctr->logic_op = args->v0.logic_op; - ctr->signal[0] = sig[0]; - ctr->signal[1] = sig[1]; - ctr->signal[2] = sig[2]; - ctr->signal[3] = sig[3]; - if (dom) - list_add_tail(&ctr->head, &dom->list); + args->v0.iter = 0xff; return 0; } -static struct nvkm_ofuncs -nvkm_perfctr_ofuncs = { - .ctor = nvkm_perfctr_ctor, - .dtor = nvkm_perfctr_dtor, - .init = nvkm_object_init, - .fini = nvkm_object_fini, - .mthd = nvkm_perfctr_mthd, -}; +static int +nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + struct nvkm_perfmon *perfmon = nvkm_perfmon(object); + switch (mthd) { + case NVIF_PERFMON_V0_QUERY_DOMAIN: + return nvkm_perfmon_mthd_query_domain(perfmon, data, size); + case NVIF_PERFMON_V0_QUERY_SIGNAL: + return nvkm_perfmon_mthd_query_signal(perfmon, data, size); + case NVIF_PERFMON_V0_QUERY_SOURCE: + return nvkm_perfmon_mthd_query_source(perfmon, data, size); + default: + break; + } + return -EINVAL; +} + +static int +nvkm_perfmon_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_perfmon *perfmon = nvkm_perfmon(oclass->parent); + return nvkm_perfdom_new_(perfmon, oclass, data, size, pobject); +} + +static int +nvkm_perfmon_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + if (index == 0) { + oclass->base.oclass = NVIF_IOCTL_NEW_V0_PERFDOM; + oclass->base.minver = 0; + oclass->base.maxver = 0; + oclass->ctor = nvkm_perfmon_child_new; + return 0; + } + return -EINVAL; +} + +static void * +nvkm_perfmon_dtor(struct nvkm_object *object) +{ + struct nvkm_perfmon *perfmon = nvkm_perfmon(object); + struct nvkm_pm *pm = perfmon->pm; + mutex_lock(&pm->engine.subdev.mutex); + if (pm->perfmon == &perfmon->object) + pm->perfmon = NULL; + mutex_unlock(&pm->engine.subdev.mutex); + return perfmon; +} -struct nvkm_oclass -nvkm_pm_sclass[] = { - { .handle = NVIF_IOCTL_NEW_V0_PERFCTR, - .ofuncs = &nvkm_perfctr_ofuncs, - }, - {}, +static struct nvkm_object_func +nvkm_perfmon = { + .dtor = nvkm_perfmon_dtor, + .mthd = nvkm_perfmon_mthd, + .sclass = nvkm_perfmon_child_get, }; -/******************************************************************************* - * PPM context - ******************************************************************************/ -static void -nvkm_perfctx_dtor(struct nvkm_object *object) +static int +nvkm_perfmon_new(struct nvkm_pm *pm, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_pm *ppm = (void *)object->engine; - mutex_lock(&nv_subdev(ppm)->mutex); - nvkm_engctx_destroy(&ppm->context->base); - ppm->context = NULL; - mutex_unlock(&nv_subdev(ppm)->mutex); + struct nvkm_perfmon *perfmon; + + if (!(perfmon = kzalloc(sizeof(*perfmon), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nvkm_perfmon, oclass, &perfmon->object); + perfmon->pm = pm; + *pobject = &perfmon->object; + return 0; } +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + static int -nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_pm_oclass_new(struct nvkm_device *device, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_pm *ppm = (void *)engine; - struct nvkm_perfctx *ctx; + struct nvkm_pm *pm = nvkm_pm(oclass->engine); int ret; - ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0, 0, 0, &ctx); - *pobject = nv_object(ctx); + ret = nvkm_perfmon_new(pm, oclass, data, size, pobject); if (ret) return ret; - mutex_lock(&nv_subdev(ppm)->mutex); - if (ppm->context == NULL) - ppm->context = ctx; - mutex_unlock(&nv_subdev(ppm)->mutex); + mutex_lock(&pm->engine.subdev.mutex); + if (pm->perfmon == NULL) + pm->perfmon = *pobject; + ret = (pm->perfmon == *pobject) ? 0 : -EBUSY; + mutex_unlock(&pm->engine.subdev.mutex); + return ret; +} - if (ctx != ppm->context) - return -EBUSY; +static const struct nvkm_device_oclass +nvkm_pm_oclass = { + .base.oclass = NVIF_IOCTL_NEW_V0_PERFMON, + .base.minver = -1, + .base.maxver = -1, + .ctor = nvkm_pm_oclass_new, +}; - return 0; +static int +nvkm_pm_oclass_get(struct nvkm_oclass *oclass, int index, + const struct nvkm_device_oclass **class) +{ + if (index == 0) { + oclass->base = nvkm_pm_oclass.base; + *class = &nvkm_pm_oclass; + return index; + } + return 1; } -struct nvkm_oclass -nvkm_pm_cclass = { - .handle = NV_ENGCTX(PM, 0x00), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nvkm_perfctx_ctor, - .dtor = nvkm_perfctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - }, -}; +int +nvkm_perfsrc_new(struct nvkm_pm *pm, struct nvkm_perfsig *sig, + const struct nvkm_specsrc *spec) +{ + const struct nvkm_specsrc *ssrc; + const struct nvkm_specmux *smux; + struct nvkm_perfsrc *src; + u8 source_nr = 0; + + if (!spec) { + /* No sources are defined for this signal. */ + return 0; + } + + ssrc = spec; + while (ssrc->name) { + smux = ssrc->mux; + while (smux->name) { + bool found = false; + u8 source_id = 0; + u32 len; + + list_for_each_entry(src, &pm->sources, head) { + if (src->addr == ssrc->addr && + src->shift == smux->shift) { + found = true; + break; + } + source_id++; + } + + if (!found) { + src = kzalloc(sizeof(*src), GFP_KERNEL); + if (!src) + return -ENOMEM; + + src->addr = ssrc->addr; + src->mask = smux->mask; + src->shift = smux->shift; + src->enable = smux->enable; + + len = strlen(ssrc->name) + + strlen(smux->name) + 2; + src->name = kzalloc(len, GFP_KERNEL); + if (!src->name) { + kfree(src); + return -ENOMEM; + } + snprintf(src->name, len, "%s_%s", ssrc->name, + smux->name); + + list_add_tail(&src->head, &pm->sources); + } + + sig->source[source_nr++] = source_id + 1; + smux++; + } + ssrc++; + } + + return 0; +} -/******************************************************************************* - * PPM engine/subdev functions - ******************************************************************************/ int -nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, +nvkm_perfdom_new(struct nvkm_pm *pm, const char *name, u32 mask, u32 base, u32 size_unit, u32 size_domain, const struct nvkm_specdom *spec) { const struct nvkm_specdom *sdom; const struct nvkm_specsig *ssig; struct nvkm_perfdom *dom; - int i; + int ret, i; for (i = 0; i == 0 || mask; i++) { u32 addr = base + (i * size_unit); @@ -408,16 +791,20 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, "%s/%02x", name, (int)(sdom - spec)); } - list_add_tail(&dom->head, &ppm->domains); + list_add_tail(&dom->head, &pm->domains); INIT_LIST_HEAD(&dom->list); dom->func = sdom->func; dom->addr = addr; - dom->quad = QUAD_MASK; dom->signal_nr = sdom->signal_nr; ssig = (sdom++)->signal; while (ssig->name) { - dom->signal[ssig->signal].name = ssig->name; + struct nvkm_perfsig *sig = + &dom->signal[ssig->signal]; + sig->name = ssig->name; + ret = nvkm_perfsrc_new(pm, sig, ssig->source); + if (ret) + return ret; ssig++; } @@ -430,47 +817,49 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, return 0; } -int -_nvkm_pm_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_pm *ppm = (void *)object; - return nvkm_engine_fini(&ppm->base, suspend); -} - -int -_nvkm_pm_init(struct nvkm_object *object) +static int +nvkm_pm_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_pm *ppm = (void *)object; - return nvkm_engine_init(&ppm->base); + struct nvkm_pm *pm = nvkm_pm(engine); + if (pm->func->fini) + pm->func->fini(pm); + return 0; } -void -_nvkm_pm_dtor(struct nvkm_object *object) +static void * +nvkm_pm_dtor(struct nvkm_engine *engine) { - struct nvkm_pm *ppm = (void *)object; - struct nvkm_perfdom *dom, *tmp; + struct nvkm_pm *pm = nvkm_pm(engine); + struct nvkm_perfdom *dom, *next_dom; + struct nvkm_perfsrc *src, *next_src; - list_for_each_entry_safe(dom, tmp, &ppm->domains, head) { + list_for_each_entry_safe(dom, next_dom, &pm->domains, head) { list_del(&dom->head); kfree(dom); } - nvkm_engine_destroy(&ppm->base); + list_for_each_entry_safe(src, next_src, &pm->sources, head) { + list_del(&src->head); + kfree(src->name); + kfree(src); + } + + return pm; } +static const struct nvkm_engine_func +nvkm_pm = { + .dtor = nvkm_pm_dtor, + .fini = nvkm_pm_fini, + .base.sclass = nvkm_pm_oclass_get, +}; + int -nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_pm_ctor(const struct nvkm_pm_func *func, struct nvkm_device *device, + int index, struct nvkm_pm *pm) { - struct nvkm_pm *ppm; - int ret; - - ret = nvkm_engine_create_(parent, engine, oclass, true, "PPM", - "pm", length, pobject); - ppm = *pobject; - if (ret) - return ret; - - INIT_LIST_HEAD(&ppm->domains); - return 0; + pm->func = func; + INIT_LIST_HEAD(&pm->domains); + INIT_LIST_HEAD(&pm->sources); + return nvkm_engine_ctor(&nvkm_pm, device, index, 0, true, &pm->engine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c deleted file mode 100644 index a7a5f3a3c91b..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2013 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "priv.h" - -static void -pwr_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, - struct nvkm_perfctr *ctr) -{ - u32 mask = 0x00000000; - u32 ctrl = 0x00000001; - int i; - - for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++) - mask |= 1 << (ctr->signal[i] - dom->signal); - - nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask); - nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl); - nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003); -} - -static void -pwr_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, - struct nvkm_perfctr *ctr) -{ - ctr->ctr = ppm->pwr[ctr->slot]; - ctr->clk = ppm->pwr[ppm->last]; -} - -static void -pwr_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom) -{ - int i; - - for (i = 0; i <= ppm->last; i++) { - ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10)); - nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000); - } -} - -static const struct nvkm_funcdom -pwr_perfctr_func = { - .init = pwr_perfctr_init, - .read = pwr_perfctr_read, - .next = pwr_perfctr_next, -}; - -const struct nvkm_specdom -gt215_pm_pwr[] = { - { 0x20, (const struct nvkm_specsig[]) { - { 0x00, "pwr_gr_idle" }, - { 0x04, "pwr_bsp_idle" }, - { 0x05, "pwr_vp_idle" }, - { 0x06, "pwr_ppp_idle" }, - { 0x13, "pwr_ce0_idle" }, - {} - }, &pwr_perfctr_func }, - {} -}; - -const struct nvkm_specdom -gf100_pm_pwr[] = { - { 0x20, (const struct nvkm_specsig[]) { - { 0x00, "pwr_gr_idle" }, - { 0x04, "pwr_bsp_idle" }, - { 0x05, "pwr_vp_idle" }, - { 0x06, "pwr_ppp_idle" }, - { 0x13, "pwr_ce0_idle" }, - { 0x14, "pwr_ce1_idle" }, - {} - }, &pwr_perfctr_func }, - {} -}; - -const struct nvkm_specdom -gk104_pm_pwr[] = { - { 0x20, (const struct nvkm_specsig[]) { - { 0x00, "pwr_gr_idle" }, - { 0x04, "pwr_bsp_idle" }, - { 0x05, "pwr_vp_idle" }, - { 0x06, "pwr_ppp_idle" }, - { 0x13, "pwr_ce0_idle" }, - { 0x14, "pwr_ce1_idle" }, - { 0x15, "pwr_ce2_idle" }, - {} - }, &pwr_perfctr_func }, - {} -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c index d54c6705ba17..6e441ddafd86 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c @@ -23,15 +23,121 @@ */ #include "nv40.h" +const struct nvkm_specsrc +g84_vfetch_sources[] = { + { 0x400c0c, (const struct nvkm_specmux[]) { + { 0x3, 0, "unk0" }, + {} + }, "pgraph_vfetch_unk0c" }, + {} +}; + +static const struct nvkm_specsrc +g84_prop_sources[] = { + { 0x408e50, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_tpc0_prop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +g84_crop_sources[] = { + { 0x407008, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0x7, 16, "sel1", true }, + {} + }, "pgraph_rop0_crop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +g84_tex_sources[] = { + { 0x408808, (const struct nvkm_specmux[]) { + { 0xfffff, 0, "unk0" }, + {} + }, "pgraph_tpc0_tex_unk08" }, + {} +}; + static const struct nvkm_specdom g84_pm[] = { { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xf0, (const struct nvkm_specsig[]) { + { 0xbd, "pc01_gr_idle" }, + { 0x5e, "pc01_strmout_00" }, + { 0x5f, "pc01_strmout_01" }, + { 0xd2, "pc01_trast_00" }, + { 0xd3, "pc01_trast_01" }, + { 0xd4, "pc01_trast_02" }, + { 0xd5, "pc01_trast_03" }, + { 0xd8, "pc01_trast_04" }, + { 0xd9, "pc01_trast_05" }, + { 0x5c, "pc01_vattr_00" }, + { 0x5d, "pc01_vattr_01" }, + { 0x66, "pc01_vfetch_00", g84_vfetch_sources }, + { 0x67, "pc01_vfetch_01", g84_vfetch_sources }, + { 0x68, "pc01_vfetch_02", g84_vfetch_sources }, + { 0x69, "pc01_vfetch_03", g84_vfetch_sources }, + { 0x6a, "pc01_vfetch_04", g84_vfetch_sources }, + { 0x6b, "pc01_vfetch_05", g84_vfetch_sources }, + { 0x6c, "pc01_vfetch_06", g84_vfetch_sources }, + { 0x6d, "pc01_vfetch_07", g84_vfetch_sources }, + { 0x6e, "pc01_vfetch_08", g84_vfetch_sources }, + { 0x6f, "pc01_vfetch_09", g84_vfetch_sources }, + { 0x70, "pc01_vfetch_0a", g84_vfetch_sources }, + { 0x71, "pc01_vfetch_0b", g84_vfetch_sources }, + { 0x72, "pc01_vfetch_0c", g84_vfetch_sources }, + { 0x73, "pc01_vfetch_0d", g84_vfetch_sources }, + { 0x74, "pc01_vfetch_0e", g84_vfetch_sources }, + { 0x75, "pc01_vfetch_0f", g84_vfetch_sources }, + { 0x76, "pc01_vfetch_10", g84_vfetch_sources }, + { 0x77, "pc01_vfetch_11", g84_vfetch_sources }, + { 0x78, "pc01_vfetch_12", g84_vfetch_sources }, + { 0x79, "pc01_vfetch_13", g84_vfetch_sources }, + { 0x7a, "pc01_vfetch_14", g84_vfetch_sources }, + { 0x7b, "pc01_vfetch_15", g84_vfetch_sources }, + { 0x7c, "pc01_vfetch_16", g84_vfetch_sources }, + { 0x7d, "pc01_vfetch_17", g84_vfetch_sources }, + { 0x7e, "pc01_vfetch_18", g84_vfetch_sources }, + { 0x7f, "pc01_vfetch_19", g84_vfetch_sources }, + { 0x07, "pc01_zcull_00", nv50_zcull_sources }, + { 0x08, "pc01_zcull_01", nv50_zcull_sources }, + { 0x09, "pc01_zcull_02", nv50_zcull_sources }, + { 0x0a, "pc01_zcull_03", nv50_zcull_sources }, + { 0x0b, "pc01_zcull_04", nv50_zcull_sources }, + { 0x0c, "pc01_zcull_05", nv50_zcull_sources }, + { 0xa4, "pc01_unk00" }, + { 0xec, "pc01_trailer" }, {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xa0, (const struct nvkm_specsig[]) { + { 0x30, "pc02_crop_00", g84_crop_sources }, + { 0x31, "pc02_crop_01", g84_crop_sources }, + { 0x32, "pc02_crop_02", g84_crop_sources }, + { 0x33, "pc02_crop_03", g84_crop_sources }, + { 0x00, "pc02_prop_00", g84_prop_sources }, + { 0x01, "pc02_prop_01", g84_prop_sources }, + { 0x02, "pc02_prop_02", g84_prop_sources }, + { 0x03, "pc02_prop_03", g84_prop_sources }, + { 0x04, "pc02_prop_04", g84_prop_sources }, + { 0x05, "pc02_prop_05", g84_prop_sources }, + { 0x06, "pc02_prop_06", g84_prop_sources }, + { 0x07, "pc02_prop_07", g84_prop_sources }, + { 0x48, "pc02_tex_00", g84_tex_sources }, + { 0x49, "pc02_tex_01", g84_tex_sources }, + { 0x4a, "pc02_tex_02", g84_tex_sources }, + { 0x4b, "pc02_tex_03", g84_tex_sources }, + { 0x1a, "pc02_tex_04", g84_tex_sources }, + { 0x1b, "pc02_tex_05", g84_tex_sources }, + { 0x1c, "pc02_tex_06", g84_tex_sources }, + { 0x44, "pc02_zrop_00", nv50_zrop_sources }, + { 0x45, "pc02_zrop_01", nv50_zrop_sources }, + { 0x46, "pc02_zrop_02", nv50_zrop_sources }, + { 0x47, "pc02_zrop_03", nv50_zrop_sources }, + { 0x8c, "pc02_trailer" }, {} }, &nv40_perfctr_func }, { 0x20, (const struct nvkm_specsig[]) { @@ -52,14 +158,8 @@ g84_pm[] = { {} }; -struct nvkm_oclass * -g84_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0x84), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = g84_pm, -}.base; +int +g84_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return nv40_pm_new_(g84_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 008fed73dd82..d2901e9a7808 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -23,62 +23,146 @@ */ #include "gf100.h" +const struct nvkm_specsrc +gf100_pbfb_sources[] = { + { 0x10f100, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + { 0x3f, 4, "unk4" }, + {} + }, "pbfb_broadcast_pm_unk100" }, + {} +}; + +const struct nvkm_specsrc +gf100_pmfb_sources[] = { + { 0x140028, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + { 0x7, 16, "unk16" }, + { 0x3, 24, "unk24" }, + { 0x2, 29, "unk29" }, + {} + }, "pmfb0_pm_unk28" }, + {} +}; + +static const struct nvkm_specsrc +gf100_l1_sources[] = { + { 0x5044a8, (const struct nvkm_specmux[]) { + { 0x3f, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_l1_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +gf100_tex_sources[] = { + { 0x5042c0, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0x7, 8, "sel1", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_mux_c_d" }, + {} +}; + +static const struct nvkm_specsrc +gf100_unk400_sources[] = { + { 0x50440c, (const struct nvkm_specmux[]) { + { 0x3f, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_unk400_pm_mux" }, + {} +}; + static const struct nvkm_specdom gf100_pm_hub[] = { {} }; -static const struct nvkm_specdom +const struct nvkm_specdom gf100_pm_gpc[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x00, "gpc00_l1_00", gf100_l1_sources }, + { 0x01, "gpc00_l1_01", gf100_l1_sources }, + { 0x02, "gpc00_l1_02", gf100_l1_sources }, + { 0x03, "gpc00_l1_03", gf100_l1_sources }, + { 0x05, "gpc00_l1_04", gf100_l1_sources }, + { 0x06, "gpc00_l1_05", gf100_l1_sources }, + { 0x0a, "gpc00_tex_00", gf100_tex_sources }, + { 0x0b, "gpc00_tex_01", gf100_tex_sources }, + { 0x0c, "gpc00_tex_02", gf100_tex_sources }, + { 0x0d, "gpc00_tex_03", gf100_tex_sources }, + { 0x0e, "gpc00_tex_04", gf100_tex_sources }, + { 0x0f, "gpc00_tex_05", gf100_tex_sources }, + { 0x10, "gpc00_tex_06", gf100_tex_sources }, + { 0x11, "gpc00_tex_07", gf100_tex_sources }, + { 0x12, "gpc00_tex_08", gf100_tex_sources }, + { 0x26, "gpc00_unk400_00", gf100_unk400_sources }, + {} + }, &gf100_perfctr_func }, {} }; -static const struct nvkm_specdom +const struct nvkm_specdom gf100_pm_part[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x0f, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x10, "part00_pbfb_01", gf100_pbfb_sources }, + { 0x21, "part00_pmfb_00", gf100_pmfb_sources }, + { 0x04, "part00_pmfb_01", gf100_pmfb_sources }, + { 0x00, "part00_pmfb_02", gf100_pmfb_sources }, + { 0x02, "part00_pmfb_03", gf100_pmfb_sources }, + { 0x01, "part00_pmfb_04", gf100_pmfb_sources }, + { 0x2e, "part00_pmfb_05", gf100_pmfb_sources }, + { 0x2f, "part00_pmfb_06", gf100_pmfb_sources }, + { 0x1b, "part00_pmfb_07", gf100_pmfb_sources }, + { 0x1c, "part00_pmfb_08", gf100_pmfb_sources }, + { 0x1d, "part00_pmfb_09", gf100_pmfb_sources }, + { 0x1e, "part00_pmfb_0a", gf100_pmfb_sources }, + { 0x1f, "part00_pmfb_0b", gf100_pmfb_sources }, + {} + }, &gf100_perfctr_func }, {} }; static void -gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +gf100_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct gf100_pm_priv *priv = (void *)ppm; - struct gf100_pm_cntr *cntr = (void *)ctr; + struct nvkm_device *device = pm->engine.subdev.device; u32 log = ctr->logic_op; u32 src = 0x00000000; int i; - for (i = 0; i < 4 && ctr->signal[i]; i++) - src |= (ctr->signal[i] - dom->signal) << (i * 8); + for (i = 0; i < 4; i++) + src |= ctr->signal[i] << (i * 8); - nv_wr32(priv, dom->addr + 0x09c, 0x00040002); - nv_wr32(priv, dom->addr + 0x100, 0x00000000); - nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); - nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); + nvkm_wr32(device, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3)); + nvkm_wr32(device, dom->addr + 0x100, 0x00000000); + nvkm_wr32(device, dom->addr + 0x040 + (ctr->slot * 0x08), src); + nvkm_wr32(device, dom->addr + 0x044 + (ctr->slot * 0x08), log); } static void -gf100_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +gf100_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct gf100_pm_priv *priv = (void *)ppm; - struct gf100_pm_cntr *cntr = (void *)ctr; - - switch (cntr->base.slot) { - case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break; - case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break; - case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break; - case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break; + struct nvkm_device *device = pm->engine.subdev.device; + + switch (ctr->slot) { + case 0: ctr->ctr = nvkm_rd32(device, dom->addr + 0x08c); break; + case 1: ctr->ctr = nvkm_rd32(device, dom->addr + 0x088); break; + case 2: ctr->ctr = nvkm_rd32(device, dom->addr + 0x080); break; + case 3: ctr->ctr = nvkm_rd32(device, dom->addr + 0x090); break; } - cntr->base.clk = nv_rd32(priv, dom->addr + 0x070); + dom->clk = nvkm_rd32(device, dom->addr + 0x070); } static void -gf100_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom) +gf100_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom) { - struct gf100_pm_priv *priv = (void *)ppm; - nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27); - nv_wr32(priv, dom->addr + 0x0ec, 0x00000011); + struct nvkm_device *device = pm->engine.subdev.device; + nvkm_wr32(device, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27); + nvkm_wr32(device, dom->addr + 0x0ec, 0x00000011); } const struct nvkm_funcdom @@ -88,72 +172,72 @@ gf100_perfctr_func = { .next = gf100_perfctr_next, }; -int -gf100_pm_fini(struct nvkm_object *object, bool suspend) +static void +gf100_pm_fini(struct nvkm_pm *pm) { - struct gf100_pm_priv *priv = (void *)object; - nv_mask(priv, 0x000200, 0x10000000, 0x00000000); - nv_mask(priv, 0x000200, 0x10000000, 0x10000000); - return nvkm_pm_fini(&priv->base, suspend); + struct nvkm_device *device = pm->engine.subdev.device; + nvkm_mask(device, 0x000200, 0x10000000, 0x00000000); + nvkm_mask(device, 0x000200, 0x10000000, 0x10000000); } -static int -gf100_pm_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_pm_func +gf100_pm_ = { + .fini = gf100_pm_fini, +}; + +int +gf100_pm_new_(const struct gf100_pm_func *func, struct nvkm_device *device, + int index, struct nvkm_pm **ppm) { - struct gf100_pm_priv *priv; + struct nvkm_pm *pm; u32 mask; int ret; - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(pm = *ppm = kzalloc(sizeof(*pm), GFP_KERNEL))) + return -ENOMEM; - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gf100_pm_pwr); + ret = nvkm_pm_ctor(&gf100_pm_, device, index, pm); if (ret) return ret; /* HUB */ - ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, - gf100_pm_hub); + ret = nvkm_perfdom_new(pm, "hub", 0, 0x1b0000, 0, 0x200, + func->doms_hub); if (ret) return ret; /* GPC */ - mask = (1 << nv_rd32(priv, 0x022430)) - 1; - mask &= ~nv_rd32(priv, 0x022504); - mask &= ~nv_rd32(priv, 0x022584); + mask = (1 << nvkm_rd32(device, 0x022430)) - 1; + mask &= ~nvkm_rd32(device, 0x022504); + mask &= ~nvkm_rd32(device, 0x022584); - ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000, - 0x1000, 0x200, gf100_pm_gpc); + ret = nvkm_perfdom_new(pm, "gpc", mask, 0x180000, + 0x1000, 0x200, func->doms_gpc); if (ret) return ret; /* PART */ - mask = (1 << nv_rd32(priv, 0x022438)) - 1; - mask &= ~nv_rd32(priv, 0x022548); - mask &= ~nv_rd32(priv, 0x0225c8); + mask = (1 << nvkm_rd32(device, 0x022438)) - 1; + mask &= ~nvkm_rd32(device, 0x022548); + mask &= ~nvkm_rd32(device, 0x0225c8); - ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000, - 0x1000, 0x200, gf100_pm_part); + ret = nvkm_perfdom_new(pm, "part", mask, 0x1a0000, + 0x1000, 0x200, func->doms_part); if (ret) return ret; - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; - priv->base.last = 7; return 0; } -struct nvkm_oclass -gf100_pm_oclass = { - .handle = NV_ENGINE(PM, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, +static const struct gf100_pm_func +gf100_pm = { + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf100_pm_hub, + .doms_part = gf100_pm_part, }; + +int +gf100_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gf100_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h index 6a01fc7fec6f..56d0344853ea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h @@ -2,14 +2,18 @@ #define __NVKM_PM_NVC0_H__ #include "priv.h" -struct gf100_pm_priv { - struct nvkm_pm base; +struct gf100_pm_func { + const struct nvkm_specdom *doms_hub; + const struct nvkm_specdom *doms_gpc; + const struct nvkm_specdom *doms_part; }; -struct gf100_pm_cntr { - struct nvkm_perfctr base; -}; +int gf100_pm_new_(const struct gf100_pm_func *, struct nvkm_device *, + int index, struct nvkm_pm **); extern const struct nvkm_funcdom gf100_perfctr_func; -int gf100_pm_fini(struct nvkm_object *, bool); +extern const struct nvkm_specdom gf100_pm_gpc[]; + +extern const struct nvkm_specsrc gf100_pbfb_sources[]; +extern const struct nvkm_specsrc gf100_pmfb_sources[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c new file mode 100644 index 000000000000..49b24c98a7f7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Samuel Pitoiset + * + * 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 "gf100.h" + +static const struct nvkm_specdom +gf108_pm_hub[] = { + {} +}; + +static const struct nvkm_specdom +gf108_pm_part[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x14, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x15, "part00_pbfb_01", gf100_pbfb_sources }, + { 0x20, "part00_pbfb_02", gf100_pbfb_sources }, + { 0x21, "part00_pbfb_03", gf100_pbfb_sources }, + { 0x01, "part00_pmfb_00", gf100_pmfb_sources }, + { 0x04, "part00_pmfb_01", gf100_pmfb_sources }, + { 0x05, "part00_pmfb_02", gf100_pmfb_sources}, + { 0x07, "part00_pmfb_03", gf100_pmfb_sources }, + { 0x0d, "part00_pmfb_04", gf100_pmfb_sources }, + { 0x12, "part00_pmfb_05", gf100_pmfb_sources }, + { 0x13, "part00_pmfb_06", gf100_pmfb_sources }, + { 0x2c, "part00_pmfb_07", gf100_pmfb_sources }, + { 0x2d, "part00_pmfb_08", gf100_pmfb_sources }, + { 0x2e, "part00_pmfb_09", gf100_pmfb_sources }, + { 0x2f, "part00_pmfb_0a", gf100_pmfb_sources }, + { 0x30, "part00_pmfb_0b", gf100_pmfb_sources }, + {} + }, &gf100_perfctr_func }, + {} +}; + +static const struct gf100_pm_func +gf108_pm = { + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf108_pm_hub, + .doms_part = gf108_pm_part, +}; + +int +gf108_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gf108_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c new file mode 100644 index 000000000000..9170025fc988 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c @@ -0,0 +1,80 @@ +/* + * Copyright 2015 Samuel Pitoiset + * + * 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 "gf100.h" + +static const struct nvkm_specsrc +gf117_pmfb_sources[] = { + { 0x140028, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + { 0x7, 16, "unk16" }, + { 0x3, 24, "unk24" }, + { 0x2, 28, "unk28" }, + {} + }, "pmfb0_pm_unk28" }, + { 0x14125c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp0_pm_unk25c" }, + {} +}; + +static const struct nvkm_specdom +gf117_pm_hub[] = { + {} +}; + +static const struct nvkm_specdom +gf117_pm_part[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x00, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x01, "part00_pbfb_01", gf100_pbfb_sources }, + { 0x12, "part00_pmfb_00", gf117_pmfb_sources }, + { 0x15, "part00_pmfb_01", gf117_pmfb_sources }, + { 0x16, "part00_pmfb_02", gf117_pmfb_sources }, + { 0x18, "part00_pmfb_03", gf117_pmfb_sources }, + { 0x1e, "part00_pmfb_04", gf117_pmfb_sources }, + { 0x23, "part00_pmfb_05", gf117_pmfb_sources }, + { 0x24, "part00_pmfb_06", gf117_pmfb_sources }, + { 0x0c, "part00_pmfb_07", gf117_pmfb_sources }, + { 0x0d, "part00_pmfb_08", gf117_pmfb_sources }, + { 0x0e, "part00_pmfb_09", gf117_pmfb_sources }, + { 0x0f, "part00_pmfb_0a", gf117_pmfb_sources }, + { 0x10, "part00_pmfb_0b", gf117_pmfb_sources }, + {} + }, &gf100_perfctr_func }, + {} +}; + +static const struct gf100_pm_func +gf117_pm = { + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf117_pm_hub, + .doms_part = gf117_pm_part, +}; + +int +gf117_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gf117_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c index 75b9ff3d1a2c..07f946d26ac6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c @@ -23,6 +23,52 @@ */ #include "gf100.h" +static const struct nvkm_specsrc +gk104_pmfb_sources[] = { + { 0x140028, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + { 0x7, 16, "unk16" }, + { 0x3, 24, "unk24" }, + { 0x2, 28, "unk28" }, + {} + }, "pmfb0_pm_unk28" }, + { 0x14125c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp0_pm_unk25c" }, + { 0x14165c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp1_pm_unk25c" }, + { 0x141a5c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp2_pm_unk25c" }, + { 0x141e5c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp3_pm_unk25c" }, + {} +}; + +static const struct nvkm_specsrc +gk104_tex_sources[] = { + { 0x5042c0, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0x7, 8, "sel1", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_mux_c_d" }, + { 0x5042c8, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_unkc8" }, + { 0x5042b8, (const struct nvkm_specmux[]) { + { 0xff, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_unkb8" }, + {} +}; + static const struct nvkm_specdom gk104_pm_hub[] = { { 0x60, (const struct nvkm_specsig[]) { @@ -69,12 +115,51 @@ gk104_pm_gpc[] = { { 0xc7, "gpc00_user_0" }, {} }, &gf100_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &gf100_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + { 0x00, "gpc02_tex_00", gk104_tex_sources }, + { 0x01, "gpc02_tex_01", gk104_tex_sources }, + { 0x02, "gpc02_tex_02", gk104_tex_sources }, + { 0x03, "gpc02_tex_03", gk104_tex_sources }, + { 0x04, "gpc02_tex_04", gk104_tex_sources }, + { 0x05, "gpc02_tex_05", gk104_tex_sources }, + { 0x06, "gpc02_tex_06", gk104_tex_sources }, + { 0x07, "gpc02_tex_07", gk104_tex_sources }, + { 0x08, "gpc02_tex_08", gk104_tex_sources }, + { 0x0a, "gpc02_tex_0a", gk104_tex_sources }, + { 0x0b, "gpc02_tex_0b", gk104_tex_sources }, + { 0x0d, "gpc02_tex_0c", gk104_tex_sources }, + { 0x0c, "gpc02_tex_0d", gk104_tex_sources }, + { 0x0e, "gpc02_tex_0e", gk104_tex_sources }, + { 0x0f, "gpc02_tex_0f", gk104_tex_sources }, + { 0x10, "gpc02_tex_10", gk104_tex_sources }, + { 0x11, "gpc02_tex_11", gk104_tex_sources }, + { 0x12, "gpc02_tex_12", gk104_tex_sources }, + {} + }, &gf100_perfctr_func }, {} }; static const struct nvkm_specdom gk104_pm_part[] = { { 0x60, (const struct nvkm_specsig[]) { + { 0x00, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x01, "part00_pbfb_01", gf100_pbfb_sources }, + { 0x0c, "part00_pmfb_00", gk104_pmfb_sources }, + { 0x0d, "part00_pmfb_01", gk104_pmfb_sources }, + { 0x0e, "part00_pmfb_02", gk104_pmfb_sources }, + { 0x0f, "part00_pmfb_03", gk104_pmfb_sources }, + { 0x10, "part00_pmfb_04", gk104_pmfb_sources }, + { 0x12, "part00_pmfb_05", gk104_pmfb_sources }, + { 0x15, "part00_pmfb_06", gk104_pmfb_sources }, + { 0x16, "part00_pmfb_07", gk104_pmfb_sources }, + { 0x18, "part00_pmfb_08", gk104_pmfb_sources }, + { 0x21, "part00_pmfb_09", gk104_pmfb_sources }, + { 0x25, "part00_pmfb_0a", gk104_pmfb_sources }, + { 0x26, "part00_pmfb_0b", gk104_pmfb_sources }, + { 0x27, "part00_pmfb_0c", gk104_pmfb_sources }, { 0x47, "part00_user_0" }, {} }, &gf100_perfctr_func }, @@ -85,64 +170,15 @@ gk104_pm_part[] = { {} }; -static int -gk104_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_pm_priv *priv; - u32 mask; - int ret; - - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - /* PDAEMON */ - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr); - if (ret) - return ret; - - /* HUB */ - ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, - gk104_pm_hub); - if (ret) - return ret; - - /* GPC */ - mask = (1 << nv_rd32(priv, 0x022430)) - 1; - mask &= ~nv_rd32(priv, 0x022504); - mask &= ~nv_rd32(priv, 0x022584); - - ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000, - 0x1000, 0x200, gk104_pm_gpc); - if (ret) - return ret; - - /* PART */ - mask = (1 << nv_rd32(priv, 0x022438)) - 1; - mask &= ~nv_rd32(priv, 0x022548); - mask &= ~nv_rd32(priv, 0x0225c8); - - ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000, - 0x1000, 0x200, gk104_pm_part); - if (ret) - return ret; +static const struct gf100_pm_func +gk104_pm = { + .doms_gpc = gk104_pm_gpc, + .doms_hub = gk104_pm_hub, + .doms_part = gk104_pm_part, +}; - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; - priv->base.last = 7; - return 0; +int +gk104_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gk104_pm, device, index, ppm); } - -struct nvkm_oclass -gk104_pm_oclass = { - .handle = NV_ENGINE(PM, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c new file mode 100644 index 000000000000..5cf5dd536fd0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c @@ -0,0 +1,157 @@ +/* + * 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. + * + * Authors: Samuel Pitoiset + */ +#include "nv40.h" + +const struct nvkm_specsrc +gt200_crop_sources[] = { + { 0x407008, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0x1f, 16, "sel1", true }, + {} + }, "pgraph_rop0_crop_pm_mux" }, + {} +}; + +const struct nvkm_specsrc +gt200_prop_sources[] = { + { 0x408750, (const struct nvkm_specmux[]) { + { 0x3f, 0, "sel", true }, + {} + }, "pgraph_tpc0_prop_pm_mux" }, + {} +}; + +const struct nvkm_specsrc +gt200_tex_sources[] = { + { 0x408508, (const struct nvkm_specmux[]) { + { 0xfffff, 0, "unk0" }, + {} + }, "pgraph_tpc0_tex_unk08" }, + {} +}; + +static const struct nvkm_specdom +gt200_pm[] = { + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0xf0, (const struct nvkm_specsig[]) { + { 0xc9, "pc01_gr_idle" }, + { 0x84, "pc01_strmout_00" }, + { 0x85, "pc01_strmout_01" }, + { 0xde, "pc01_trast_00" }, + { 0xdf, "pc01_trast_01" }, + { 0xe0, "pc01_trast_02" }, + { 0xe1, "pc01_trast_03" }, + { 0xe4, "pc01_trast_04" }, + { 0xe5, "pc01_trast_05" }, + { 0x82, "pc01_vattr_00" }, + { 0x83, "pc01_vattr_01" }, + { 0x46, "pc01_vfetch_00", g84_vfetch_sources }, + { 0x47, "pc01_vfetch_01", g84_vfetch_sources }, + { 0x48, "pc01_vfetch_02", g84_vfetch_sources }, + { 0x49, "pc01_vfetch_03", g84_vfetch_sources }, + { 0x4a, "pc01_vfetch_04", g84_vfetch_sources }, + { 0x4b, "pc01_vfetch_05", g84_vfetch_sources }, + { 0x4c, "pc01_vfetch_06", g84_vfetch_sources }, + { 0x4d, "pc01_vfetch_07", g84_vfetch_sources }, + { 0x4e, "pc01_vfetch_08", g84_vfetch_sources }, + { 0x4f, "pc01_vfetch_09", g84_vfetch_sources }, + { 0x50, "pc01_vfetch_0a", g84_vfetch_sources }, + { 0x51, "pc01_vfetch_0b", g84_vfetch_sources }, + { 0x52, "pc01_vfetch_0c", g84_vfetch_sources }, + { 0x53, "pc01_vfetch_0d", g84_vfetch_sources }, + { 0x54, "pc01_vfetch_0e", g84_vfetch_sources }, + { 0x55, "pc01_vfetch_0f", g84_vfetch_sources }, + { 0x56, "pc01_vfetch_10", g84_vfetch_sources }, + { 0x57, "pc01_vfetch_11", g84_vfetch_sources }, + { 0x58, "pc01_vfetch_12", g84_vfetch_sources }, + { 0x59, "pc01_vfetch_13", g84_vfetch_sources }, + { 0x5a, "pc01_vfetch_14", g84_vfetch_sources }, + { 0x5b, "pc01_vfetch_15", g84_vfetch_sources }, + { 0x5c, "pc01_vfetch_16", g84_vfetch_sources }, + { 0x5d, "pc01_vfetch_17", g84_vfetch_sources }, + { 0x5e, "pc01_vfetch_18", g84_vfetch_sources }, + { 0x5f, "pc01_vfetch_19", g84_vfetch_sources }, + { 0x07, "pc01_zcull_00", nv50_zcull_sources }, + { 0x08, "pc01_zcull_01", nv50_zcull_sources }, + { 0x09, "pc01_zcull_02", nv50_zcull_sources }, + { 0x0a, "pc01_zcull_03", nv50_zcull_sources }, + { 0x0b, "pc01_zcull_04", nv50_zcull_sources }, + { 0x0c, "pc01_zcull_05", nv50_zcull_sources }, + + { 0xb0, "pc01_unk00" }, + { 0xec, "pc01_trailer" }, + {} + }, &nv40_perfctr_func }, + { 0xf0, (const struct nvkm_specsig[]) { + { 0x55, "pc02_crop_00", gt200_crop_sources }, + { 0x56, "pc02_crop_01", gt200_crop_sources }, + { 0x57, "pc02_crop_02", gt200_crop_sources }, + { 0x58, "pc02_crop_03", gt200_crop_sources }, + { 0x00, "pc02_prop_00", gt200_prop_sources }, + { 0x01, "pc02_prop_01", gt200_prop_sources }, + { 0x02, "pc02_prop_02", gt200_prop_sources }, + { 0x03, "pc02_prop_03", gt200_prop_sources }, + { 0x04, "pc02_prop_04", gt200_prop_sources }, + { 0x05, "pc02_prop_05", gt200_prop_sources }, + { 0x06, "pc02_prop_06", gt200_prop_sources }, + { 0x07, "pc02_prop_07", gt200_prop_sources }, + { 0x78, "pc02_tex_00", gt200_tex_sources }, + { 0x79, "pc02_tex_01", gt200_tex_sources }, + { 0x7a, "pc02_tex_02", gt200_tex_sources }, + { 0x7b, "pc02_tex_03", gt200_tex_sources }, + { 0x32, "pc02_tex_04", gt200_tex_sources }, + { 0x33, "pc02_tex_05", gt200_tex_sources }, + { 0x34, "pc02_tex_06", gt200_tex_sources }, + { 0x74, "pc02_zrop_00", nv50_zrop_sources }, + { 0x75, "pc02_zrop_01", nv50_zrop_sources }, + { 0x76, "pc02_zrop_02", nv50_zrop_sources }, + { 0x77, "pc02_zrop_03", nv50_zrop_sources }, + { 0xec, "pc02_trailer" }, + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + {} +}; + +int +gt200_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return nv40_pm_new_(gt200_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c index d065bfc59bbf..c9227ad41b04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c @@ -23,15 +23,94 @@ */ #include "nv40.h" +static const struct nvkm_specsrc +gt215_zcull_sources[] = { + { 0x402ca4, (const struct nvkm_specmux[]) { + { 0x7fff, 0, "unk0" }, + { 0xff, 24, "unk24" }, + {} + }, "pgraph_zcull_pm_unka4" }, + {} +}; + static const struct nvkm_specdom gt215_pm[] = { { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xf0, (const struct nvkm_specsig[]) { + { 0xcb, "pc01_gr_idle" }, + { 0x86, "pc01_strmout_00" }, + { 0x87, "pc01_strmout_01" }, + { 0xe0, "pc01_trast_00" }, + { 0xe1, "pc01_trast_01" }, + { 0xe2, "pc01_trast_02" }, + { 0xe3, "pc01_trast_03" }, + { 0xe6, "pc01_trast_04" }, + { 0xe7, "pc01_trast_05" }, + { 0x84, "pc01_vattr_00" }, + { 0x85, "pc01_vattr_01" }, + { 0x46, "pc01_vfetch_00", g84_vfetch_sources }, + { 0x47, "pc01_vfetch_01", g84_vfetch_sources }, + { 0x48, "pc01_vfetch_02", g84_vfetch_sources }, + { 0x49, "pc01_vfetch_03", g84_vfetch_sources }, + { 0x4a, "pc01_vfetch_04", g84_vfetch_sources }, + { 0x4b, "pc01_vfetch_05", g84_vfetch_sources }, + { 0x4c, "pc01_vfetch_06", g84_vfetch_sources }, + { 0x4d, "pc01_vfetch_07", g84_vfetch_sources }, + { 0x4e, "pc01_vfetch_08", g84_vfetch_sources }, + { 0x4f, "pc01_vfetch_09", g84_vfetch_sources }, + { 0x50, "pc01_vfetch_0a", g84_vfetch_sources }, + { 0x51, "pc01_vfetch_0b", g84_vfetch_sources }, + { 0x52, "pc01_vfetch_0c", g84_vfetch_sources }, + { 0x53, "pc01_vfetch_0d", g84_vfetch_sources }, + { 0x54, "pc01_vfetch_0e", g84_vfetch_sources }, + { 0x55, "pc01_vfetch_0f", g84_vfetch_sources }, + { 0x56, "pc01_vfetch_10", g84_vfetch_sources }, + { 0x57, "pc01_vfetch_11", g84_vfetch_sources }, + { 0x58, "pc01_vfetch_12", g84_vfetch_sources }, + { 0x59, "pc01_vfetch_13", g84_vfetch_sources }, + { 0x5a, "pc01_vfetch_14", g84_vfetch_sources }, + { 0x5b, "pc01_vfetch_15", g84_vfetch_sources }, + { 0x5c, "pc01_vfetch_16", g84_vfetch_sources }, + { 0x5d, "pc01_vfetch_17", g84_vfetch_sources }, + { 0x5e, "pc01_vfetch_18", g84_vfetch_sources }, + { 0x5f, "pc01_vfetch_19", g84_vfetch_sources }, + { 0x07, "pc01_zcull_00", gt215_zcull_sources }, + { 0x08, "pc01_zcull_01", gt215_zcull_sources }, + { 0x09, "pc01_zcull_02", gt215_zcull_sources }, + { 0x0a, "pc01_zcull_03", gt215_zcull_sources }, + { 0x0b, "pc01_zcull_04", gt215_zcull_sources }, + { 0x0c, "pc01_zcull_05", gt215_zcull_sources }, + { 0xb2, "pc01_unk00" }, + { 0xec, "pc01_trailer" }, {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x64, "pc02_crop_00", gt200_crop_sources }, + { 0x65, "pc02_crop_01", gt200_crop_sources }, + { 0x66, "pc02_crop_02", gt200_crop_sources }, + { 0x67, "pc02_crop_03", gt200_crop_sources }, + { 0x00, "pc02_prop_00", gt200_prop_sources }, + { 0x01, "pc02_prop_01", gt200_prop_sources }, + { 0x02, "pc02_prop_02", gt200_prop_sources }, + { 0x03, "pc02_prop_03", gt200_prop_sources }, + { 0x04, "pc02_prop_04", gt200_prop_sources }, + { 0x05, "pc02_prop_05", gt200_prop_sources }, + { 0x06, "pc02_prop_06", gt200_prop_sources }, + { 0x07, "pc02_prop_07", gt200_prop_sources }, + { 0x80, "pc02_tex_00", gt200_tex_sources }, + { 0x81, "pc02_tex_01", gt200_tex_sources }, + { 0x82, "pc02_tex_02", gt200_tex_sources }, + { 0x83, "pc02_tex_03", gt200_tex_sources }, + { 0x3a, "pc02_tex_04", gt200_tex_sources }, + { 0x3b, "pc02_tex_05", gt200_tex_sources }, + { 0x3c, "pc02_tex_06", gt200_tex_sources }, + { 0x7c, "pc02_zrop_00", nv50_zrop_sources }, + { 0x7d, "pc02_zrop_01", nv50_zrop_sources }, + { 0x7e, "pc02_zrop_02", nv50_zrop_sources }, + { 0x7f, "pc02_zrop_03", nv50_zrop_sources }, + { 0xcc, "pc02_trailer" }, {} }, &nv40_perfctr_func }, { 0x20, (const struct nvkm_specsig[]) { @@ -52,32 +131,8 @@ gt215_pm[] = { {} }; -static int -gt215_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **object) +int +gt215_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) { - int ret = nv40_pm_ctor(parent, engine, oclass, data, size, object); - if (ret == 0) { - struct nv40_pm_priv *priv = (void *)*object; - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, - gt215_pm_pwr); - if (ret) - return ret; - - priv->base.last = 3; - } - return ret; + return nv40_pm_new_(gt215_pm, device, index, ppm); } - -struct nvkm_oclass * -gt215_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0xa3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = gt215_pm, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index ff22f06b22b8..4bef72a9d106 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -24,46 +24,44 @@ #include "nv40.h" static void -nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +nv40_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct nv40_pm_priv *priv = (void *)ppm; - struct nv40_pm_cntr *cntr = (void *)ctr; + struct nvkm_device *device = pm->engine.subdev.device; u32 log = ctr->logic_op; u32 src = 0x00000000; int i; - for (i = 0; i < 4 && ctr->signal[i]; i++) - src |= (ctr->signal[i] - dom->signal) << (i * 8); + for (i = 0; i < 4; i++) + src |= ctr->signal[i] << (i * 8); - nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001); - nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); - nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); + nvkm_wr32(device, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4)); + nvkm_wr32(device, 0x00a400 + dom->addr + (ctr->slot * 0x40), src); + nvkm_wr32(device, 0x00a420 + dom->addr + (ctr->slot * 0x40), log); } static void -nv40_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +nv40_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct nv40_pm_priv *priv = (void *)ppm; - struct nv40_pm_cntr *cntr = (void *)ctr; + struct nvkm_device *device = pm->engine.subdev.device; - switch (cntr->base.slot) { - case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break; - case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break; - case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break; - case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break; + switch (ctr->slot) { + case 0: ctr->ctr = nvkm_rd32(device, 0x00a700 + dom->addr); break; + case 1: ctr->ctr = nvkm_rd32(device, 0x00a6c0 + dom->addr); break; + case 2: ctr->ctr = nvkm_rd32(device, 0x00a680 + dom->addr); break; + case 3: ctr->ctr = nvkm_rd32(device, 0x00a740 + dom->addr); break; } - cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr); + dom->clk = nvkm_rd32(device, 0x00a600 + dom->addr); } static void -nv40_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom) +nv40_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom) { - struct nv40_pm_priv *priv = (void *)ppm; - if (priv->sequence != ppm->sequence) { - nv_wr32(priv, 0x400084, 0x00000020); - priv->sequence = ppm->sequence; + struct nvkm_device *device = pm->engine.subdev.device; + if (pm->sequence != pm->sequence) { + nvkm_wr32(device, 0x400084, 0x00000020); + pm->sequence = pm->sequence; } } @@ -74,6 +72,28 @@ nv40_perfctr_func = { .next = nv40_perfctr_next, }; +static const struct nvkm_pm_func +nv40_pm_ = { +}; + +int +nv40_pm_new_(const struct nvkm_specdom *doms, struct nvkm_device *device, + int index, struct nvkm_pm **ppm) +{ + struct nv40_pm *pm; + int ret; + + if (!(pm = kzalloc(sizeof(*pm), GFP_KERNEL))) + return -ENOMEM; + *ppm = &pm->base; + + ret = nvkm_pm_ctor(&nv40_pm_, device, index, &pm->base); + if (ret) + return ret; + + return nvkm_perfdom_new(&pm->base, "pc", 0, 0, 0, 4, doms); +} + static const struct nvkm_specdom nv40_pm[] = { { 0x20, (const struct nvkm_specsig[]) { @@ -95,36 +115,7 @@ nv40_pm[] = { }; int -nv40_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) { - struct nv40_pm_oclass *mclass = (void *)oclass; - struct nv40_pm_priv *priv; - int ret; - - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - ret = nvkm_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms); - if (ret) - return ret; - - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; - return 0; + return nv40_pm_new_(nv40_pm, device, index, ppm); } - -struct nvkm_oclass * -nv40_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0x40), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = nv40_pm, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h index 2338e150420e..da481abe8f7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h @@ -1,24 +1,14 @@ #ifndef __NVKM_PM_NV40_H__ #define __NVKM_PM_NV40_H__ +#define nv40_pm(p) container_of((p), struct nv40_pm, base) #include "priv.h" -struct nv40_pm_oclass { - struct nvkm_oclass base; - const struct nvkm_specdom *doms; -}; - -struct nv40_pm_priv { +struct nv40_pm { struct nvkm_pm base; u32 sequence; }; -int nv40_pm_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **pobject); - -struct nv40_pm_cntr { - struct nvkm_perfctr base; -}; - +int nv40_pm_new_(const struct nvkm_specdom *, struct nvkm_device *, + int index, struct nvkm_pm **); extern const struct nvkm_funcdom nv40_perfctr_func; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c index 6af83b5d1b11..cc5a41d4c6f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c @@ -23,35 +23,153 @@ */ #include "nv40.h" +const struct nvkm_specsrc +nv50_zcull_sources[] = { + { 0x402ca4, (const struct nvkm_specmux[]) { + { 0x7fff, 0, "unk0" }, + {} + }, "pgraph_zcull_pm_unka4" }, + {} +}; + +const struct nvkm_specsrc +nv50_zrop_sources[] = { + { 0x40708c, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0xf, 16, "sel1", true }, + {} + }, "pgraph_rop0_zrop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +nv50_prop_sources[] = { + { 0x40be50, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_tpc3_prop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +nv50_crop_sources[] = { + { 0x407008, (const struct nvkm_specmux[]) { + { 0x7, 0, "sel0", true }, + { 0x7, 16, "sel1", true }, + {} + }, "pgraph_rop0_crop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +nv50_tex_sources[] = { + { 0x40b808, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pgraph_tpc3_tex_unk08" }, + {} +}; + +static const struct nvkm_specsrc +nv50_vfetch_sources[] = { + { 0x400c0c, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + {} + }, "pgraph_vfetch_unk0c" }, + {} +}; + static const struct nvkm_specdom nv50_pm[] = { - { 0x040, (const struct nvkm_specsig[]) { + { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x100, (const struct nvkm_specsig[]) { - { 0xc8, "gr_idle" }, + { 0xf0, (const struct nvkm_specsig[]) { + { 0xc8, "pc01_gr_idle" }, + { 0x7f, "pc01_strmout_00" }, + { 0x80, "pc01_strmout_01" }, + { 0xdc, "pc01_trast_00" }, + { 0xdd, "pc01_trast_01" }, + { 0xde, "pc01_trast_02" }, + { 0xdf, "pc01_trast_03" }, + { 0xe2, "pc01_trast_04" }, + { 0xe3, "pc01_trast_05" }, + { 0x7c, "pc01_vattr_00" }, + { 0x7d, "pc01_vattr_01" }, + { 0x26, "pc01_vfetch_00", nv50_vfetch_sources }, + { 0x27, "pc01_vfetch_01", nv50_vfetch_sources }, + { 0x28, "pc01_vfetch_02", nv50_vfetch_sources }, + { 0x29, "pc01_vfetch_03", nv50_vfetch_sources }, + { 0x2a, "pc01_vfetch_04", nv50_vfetch_sources }, + { 0x2b, "pc01_vfetch_05", nv50_vfetch_sources }, + { 0x2c, "pc01_vfetch_06", nv50_vfetch_sources }, + { 0x2d, "pc01_vfetch_07", nv50_vfetch_sources }, + { 0x2e, "pc01_vfetch_08", nv50_vfetch_sources }, + { 0x2f, "pc01_vfetch_09", nv50_vfetch_sources }, + { 0x30, "pc01_vfetch_0a", nv50_vfetch_sources }, + { 0x31, "pc01_vfetch_0b", nv50_vfetch_sources }, + { 0x32, "pc01_vfetch_0c", nv50_vfetch_sources }, + { 0x33, "pc01_vfetch_0d", nv50_vfetch_sources }, + { 0x34, "pc01_vfetch_0e", nv50_vfetch_sources }, + { 0x35, "pc01_vfetch_0f", nv50_vfetch_sources }, + { 0x36, "pc01_vfetch_10", nv50_vfetch_sources }, + { 0x37, "pc01_vfetch_11", nv50_vfetch_sources }, + { 0x38, "pc01_vfetch_12", nv50_vfetch_sources }, + { 0x39, "pc01_vfetch_13", nv50_vfetch_sources }, + { 0x3a, "pc01_vfetch_14", nv50_vfetch_sources }, + { 0x3b, "pc01_vfetch_15", nv50_vfetch_sources }, + { 0x3c, "pc01_vfetch_16", nv50_vfetch_sources }, + { 0x3d, "pc01_vfetch_17", nv50_vfetch_sources }, + { 0x3e, "pc01_vfetch_18", nv50_vfetch_sources }, + { 0x3f, "pc01_vfetch_19", nv50_vfetch_sources }, + { 0x20, "pc01_zcull_00", nv50_zcull_sources }, + { 0x21, "pc01_zcull_01", nv50_zcull_sources }, + { 0x22, "pc01_zcull_02", nv50_zcull_sources }, + { 0x23, "pc01_zcull_03", nv50_zcull_sources }, + { 0x24, "pc01_zcull_04", nv50_zcull_sources }, + { 0x25, "pc01_zcull_05", nv50_zcull_sources }, + { 0xae, "pc01_unk00" }, + { 0xee, "pc01_trailer" }, {} }, &nv40_perfctr_func }, - { 0x100, (const struct nvkm_specsig[]) { + { 0xf0, (const struct nvkm_specsig[]) { + { 0x52, "pc02_crop_00", nv50_crop_sources }, + { 0x53, "pc02_crop_01", nv50_crop_sources }, + { 0x54, "pc02_crop_02", nv50_crop_sources }, + { 0x55, "pc02_crop_03", nv50_crop_sources }, + { 0x00, "pc02_prop_00", nv50_prop_sources }, + { 0x01, "pc02_prop_01", nv50_prop_sources }, + { 0x02, "pc02_prop_02", nv50_prop_sources }, + { 0x03, "pc02_prop_03", nv50_prop_sources }, + { 0x04, "pc02_prop_04", nv50_prop_sources }, + { 0x05, "pc02_prop_05", nv50_prop_sources }, + { 0x06, "pc02_prop_06", nv50_prop_sources }, + { 0x07, "pc02_prop_07", nv50_prop_sources }, + { 0x70, "pc02_tex_00", nv50_tex_sources }, + { 0x71, "pc02_tex_01", nv50_tex_sources }, + { 0x72, "pc02_tex_02", nv50_tex_sources }, + { 0x73, "pc02_tex_03", nv50_tex_sources }, + { 0x40, "pc02_tex_04", nv50_tex_sources }, + { 0x41, "pc02_tex_05", nv50_tex_sources }, + { 0x42, "pc02_tex_06", nv50_tex_sources }, + { 0x6c, "pc02_zrop_00", nv50_zrop_sources }, + { 0x6d, "pc02_zrop_01", nv50_zrop_sources }, + { 0x6e, "pc02_zrop_02", nv50_zrop_sources }, + { 0x6f, "pc02_zrop_03", nv50_zrop_sources }, + { 0xee, "pc02_trailer" }, {} }, &nv40_perfctr_func }, - { 0x020, (const struct nvkm_specsig[]) { + { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x040, (const struct nvkm_specsig[]) { + { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, {} }; -struct nvkm_oclass * -nv50_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = nv50_pm, -}.base; +int +nv50_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return nv40_pm_new_(nv50_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 1e6eff2a6d79..d7b81cbf82b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -1,58 +1,85 @@ #ifndef __NVKM_PM_PRIV_H__ #define __NVKM_PM_PRIV_H__ +#define nvkm_pm(p) container_of((p), struct nvkm_pm, engine) #include <engine/pm.h> +int nvkm_pm_ctor(const struct nvkm_pm_func *, struct nvkm_device *, + int index, struct nvkm_pm *); + +struct nvkm_pm_func { + void (*fini)(struct nvkm_pm *); +}; + struct nvkm_perfctr { - struct nvkm_object base; struct list_head head; - struct nvkm_perfsig *signal[4]; + u8 domain; + u8 signal[4]; + u64 source[4][8]; int slot; u32 logic_op; - u32 clk; u32 ctr; }; -extern struct nvkm_oclass nvkm_pm_sclass[]; +struct nvkm_specmux { + u32 mask; + u8 shift; + const char *name; + bool enable; +}; -#include <core/engctx.h> +struct nvkm_specsrc { + u32 addr; + const struct nvkm_specmux *mux; + const char *name; +}; -struct nvkm_perfctx { - struct nvkm_engctx base; +struct nvkm_perfsrc { + struct list_head head; + char *name; + u32 addr; + u32 mask; + u8 shift; + bool enable; }; -extern struct nvkm_oclass nvkm_pm_cclass; +extern const struct nvkm_specsrc nv50_zcull_sources[]; +extern const struct nvkm_specsrc nv50_zrop_sources[]; +extern const struct nvkm_specsrc g84_vfetch_sources[]; +extern const struct nvkm_specsrc gt200_crop_sources[]; +extern const struct nvkm_specsrc gt200_prop_sources[]; +extern const struct nvkm_specsrc gt200_tex_sources[]; struct nvkm_specsig { u8 signal; const char *name; + const struct nvkm_specsrc *source; }; struct nvkm_perfsig { const char *name; + u8 source[8]; }; -struct nvkm_perfdom; -struct nvkm_perfctr * -nvkm_perfsig_wrap(struct nvkm_pm *, const char *, struct nvkm_perfdom **); - struct nvkm_specdom { u16 signal_nr; const struct nvkm_specsig *signal; const struct nvkm_funcdom *func; }; -extern const struct nvkm_specdom gt215_pm_pwr[]; -extern const struct nvkm_specdom gf100_pm_pwr[]; -extern const struct nvkm_specdom gk104_pm_pwr[]; +#define nvkm_perfdom(p) container_of((p), struct nvkm_perfdom, object) struct nvkm_perfdom { + struct nvkm_object object; + struct nvkm_perfmon *perfmon; struct list_head head; struct list_head list; const struct nvkm_funcdom *func; + struct nvkm_perfctr *ctr[4]; char name[32]; u32 addr; - u8 quad; - u32 signal_nr; + u8 mode; + u32 clk; + u16 signal_nr; struct nvkm_perfsig signal[]; }; @@ -67,24 +94,10 @@ struct nvkm_funcdom { int nvkm_perfdom_new(struct nvkm_pm *, const char *, u32, u32, u32, u32, const struct nvkm_specdom *); -#define nvkm_pm_create(p,e,o,d) \ - nvkm_pm_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_pm_dtor(p) ({ \ - struct nvkm_pm *c = (p); \ - _nvkm_pm_dtor(nv_object(c)); \ -}) -#define nvkm_pm_init(p) ({ \ - struct nvkm_pm *c = (p); \ - _nvkm_pm_init(nv_object(c)); \ -}) -#define nvkm_pm_fini(p,s) ({ \ - struct nvkm_pm *c = (p); \ - _nvkm_pm_fini(nv_object(c), (s)); \ -}) - -int nvkm_pm_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_pm_dtor(struct nvkm_object *); -int _nvkm_pm_init(struct nvkm_object *); -int _nvkm_pm_fini(struct nvkm_object *, bool); +#define nvkm_perfmon(p) container_of((p), struct nvkm_perfmon, object) + +struct nvkm_perfmon { + struct nvkm_object object; + struct nvkm_pm *pm; +}; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s index 06ee06071104..66b147bd58eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s @@ -1,5 +1,5 @@ /* - * fuc microcode for g98 psec engine + * fuc microcode for g98 sec engine * Copyright (C) 2010 Marcin Kościelnicki * * This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -.section #g98_psec_data +.section #g98_sec_data ctx_dma: ctx_dma_query: .b32 0 @@ -94,7 +94,7 @@ sec_dtable: .align 0x100 -.section #g98_psec_code +.section #g98_sec_code // $r0 is always set to 0 in our code - this allows some space savings. clear b32 $r0 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h index 5d65c4fbb087..eca62221f299 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h @@ -1,4 +1,4 @@ -uint32_t g98_psec_data[] = { +uint32_t g98_sec_data[] = { /* 0x0000: ctx_dma */ /* 0x0000: ctx_dma_query */ 0x00000000, @@ -150,7 +150,7 @@ uint32_t g98_psec_data[] = { 0x00000000, }; -uint32_t g98_psec_code[] = { +uint32_t g98_sec_code[] = { 0x17f004bd, 0x0010fe35, 0xf10004fe, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index 9d5c1b8b1f8c..995c2c5ec150 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -22,47 +22,14 @@ * Authors: Ben Skeggs */ #include <engine/sec.h> -#include <engine/falcon.h> +#include <engine/fifo.h> #include "fuc/g98.fuc0s.h" #include <core/client.h> #include <core/enum.h> -#include <engine/fifo.h> - -struct g98_sec_priv { - struct nvkm_falcon base; -}; - -/******************************************************************************* - * Crypt object classes - ******************************************************************************/ +#include <core/gpuobj.h> -static struct nvkm_oclass -g98_sec_sclass[] = { - { 0x88b4, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PSEC context - ******************************************************************************/ - -static struct nvkm_oclass -g98_sec_cclass = { - .handle = NV_ENGCTX(SEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PSEC engine/subdev functions - ******************************************************************************/ +#include <nvif/class.h> static const struct nvkm_enum g98_sec_isr_error_name[] = { { 0x0000, "ILLEGAL_MTHD" }, @@ -73,77 +40,44 @@ static const struct nvkm_enum g98_sec_isr_error_name[] = { }; static void -g98_sec_intr(struct nvkm_subdev *subdev) +g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct g98_sec_priv *priv = (void *)subdev; - u32 disp = nv_rd32(priv, 0x08701c); - u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16); - u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff; - u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff; - u32 addr = nv_rd32(priv, 0x087040) >> 16; + struct nvkm_subdev *subdev = &sec->engine.subdev; + struct nvkm_device *device = subdev->device; + u32 ssta = nvkm_rd32(device, 0x087040) & 0x0000ffff; + u32 addr = nvkm_rd32(device, 0x087040) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_rd32(priv, 0x087044); - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); - - if (stat & 0x00000040) { - nv_error(priv, "DISPATCH_ERROR ["); - nvkm_enum_print(g98_sec_isr_error_name, ssta); - pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", - chid, (u64)inst << 12, nvkm_client_name(engctx), - subc, mthd, data); - nv_wr32(priv, 0x087004, 0x00000040); - stat &= ~0x00000040; - } + u32 data = nvkm_rd32(device, 0x087044); + const struct nvkm_enum *en = + nvkm_enum_find(g98_sec_isr_error_name, ssta); + + nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", ssta, + en ? en->name : "UNKNOWN", chan ? chan->chid : -1, + chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", + subc, mthd, data); +} - if (stat) { - nv_error(priv, "unhandled intr 0x%08x\n", stat); - nv_wr32(priv, 0x087004, stat); +static const struct nvkm_falcon_func +g98_sec = { + .code.data = g98_sec_code, + .code.size = sizeof(g98_sec_code), + .data.data = g98_sec_data, + .data.size = sizeof(g98_sec_data), + .pmc_enable = 0x00004000, + .intr = g98_sec_intr, + .sclass = { + { -1, -1, G98_SEC }, + {} } +}; - nvkm_engctx_put(engctx); -} - -static int -g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g98_sec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct g98_sec_priv *priv; - int ret; - - ret = nvkm_falcon_create(parent, engine, oclass, 0x087000, true, - "PSEC", "sec", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x00004000; - nv_subdev(priv)->intr = g98_sec_intr; - nv_engine(priv)->cclass = &g98_sec_cclass; - nv_engine(priv)->sclass = g98_sec_sclass; - nv_falcon(priv)->code.data = g98_psec_code; - nv_falcon(priv)->code.size = sizeof(g98_psec_code); - nv_falcon(priv)->data.data = g98_psec_data; - nv_falcon(priv)->data.size = sizeof(g98_psec_data); - return 0; + return nvkm_falcon_new_(&g98_sec, device, index, + true, 0x087000, pengine); } - -struct nvkm_oclass -g98_sec_oclass = { - .handle = NV_ENGINE(SEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_sec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = _nvkm_falcon_init, - .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild index bdc3a05907d5..1c291e6fcf96 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild @@ -1,4 +1,9 @@ +nvkm-y += nvkm/engine/sw/base.o nvkm-y += nvkm/engine/sw/nv04.o nvkm-y += nvkm/engine/sw/nv10.o nvkm-y += nvkm/engine/sw/nv50.o nvkm-y += nvkm/engine/sw/gf100.o + +nvkm-y += nvkm/engine/sw/chan.o + +nvkm-y += nvkm/engine/sw/nvsw.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c new file mode 100644 index 000000000000..53c1f7e75b54 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c @@ -0,0 +1,110 @@ +/* + * 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 "chan.h" + +#include <engine/fifo.h> + +bool +nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data) +{ + struct nvkm_sw_chan *chan; + bool handled = false; + unsigned long flags; + + spin_lock_irqsave(&sw->engine.lock, flags); + list_for_each_entry(chan, &sw->chan, head) { + if (chan->fifo->chid == chid) { + handled = nvkm_sw_chan_mthd(chan, subc, mthd, data); + list_del(&chan->head); + list_add(&chan->head, &sw->chan); + break; + } + } + spin_unlock_irqrestore(&sw->engine.lock, flags); + return handled; +} + +static int +nvkm_sw_oclass_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_sw_chan *chan = nvkm_sw_chan(oclass->parent); + const struct nvkm_sw_chan_sclass *sclass = oclass->engn; + return sclass->ctor(chan, oclass, data, size, pobject); +} + +static int +nvkm_sw_oclass_get(struct nvkm_oclass *oclass, int index) +{ + struct nvkm_sw *sw = nvkm_sw(oclass->engine); + int c = 0; + + while (sw->func->sclass[c].ctor) { + if (c++ == index) { + oclass->engn = &sw->func->sclass[index]; + oclass->base = sw->func->sclass[index].base; + oclass->base.ctor = nvkm_sw_oclass_new; + return index; + } + } + + return c; +} + +static int +nvkm_sw_cclass_get(struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nvkm_sw *sw = nvkm_sw(oclass->engine); + return sw->func->chan_new(sw, fifoch, oclass, pobject); +} + +static void * +nvkm_sw_dtor(struct nvkm_engine *engine) +{ + return nvkm_sw(engine); +} + +static const struct nvkm_engine_func +nvkm_sw = { + .dtor = nvkm_sw_dtor, + .fifo.cclass = nvkm_sw_cclass_get, + .fifo.sclass = nvkm_sw_oclass_get, +}; + +int +nvkm_sw_new_(const struct nvkm_sw_func *func, struct nvkm_device *device, + int index, struct nvkm_sw **psw) +{ + struct nvkm_sw *sw; + + if (!(sw = *psw = kzalloc(sizeof(*sw), GFP_KERNEL))) + return -ENOMEM; + INIT_LIST_HEAD(&sw->chan); + sw->func = func; + + return nvkm_engine_ctor(&nvkm_sw, device, index, 0, true, &sw->engine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c new file mode 100644 index 000000000000..d082f4f73a80 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c @@ -0,0 +1,111 @@ +/* + * 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 "chan.h" + +#include <core/notify.h> +#include <engine/fifo.h> + +#include <nvif/event.h> +#include <nvif/unpack.h> + +bool +nvkm_sw_chan_mthd(struct nvkm_sw_chan *chan, int subc, u32 mthd, u32 data) +{ + switch (mthd) { + case 0x0000: + return true; + case 0x0500: + nvkm_event_send(&chan->event, 1, 0, NULL, 0); + return true; + default: + if (chan->func->mthd) + return chan->func->mthd(chan, subc, mthd, data); + break; + } + return false; +} + +static int +nvkm_sw_chan_event_ctor(struct nvkm_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + union { + struct nvif_notify_uevent_req none; + } *req = data; + int ret; + + if (nvif_unvers(req->none)) { + notify->size = sizeof(struct nvif_notify_uevent_rep); + notify->types = 1; + notify->index = 0; + } + + return ret; +} + +static const struct nvkm_event_func +nvkm_sw_chan_event = { + .ctor = nvkm_sw_chan_event_ctor, +}; + +static void * +nvkm_sw_chan_dtor(struct nvkm_object *object) +{ + struct nvkm_sw_chan *chan = nvkm_sw_chan(object); + struct nvkm_sw *sw = chan->sw; + unsigned long flags; + void *data = chan; + + if (chan->func->dtor) + data = chan->func->dtor(chan); + nvkm_event_fini(&chan->event); + + spin_lock_irqsave(&sw->engine.lock, flags); + list_del(&chan->head); + spin_unlock_irqrestore(&sw->engine.lock, flags); + return data; +} + +static const struct nvkm_object_func +nvkm_sw_chan = { + .dtor = nvkm_sw_chan_dtor, +}; + +int +nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *func, struct nvkm_sw *sw, + struct nvkm_fifo_chan *fifo, const struct nvkm_oclass *oclass, + struct nvkm_sw_chan *chan) +{ + unsigned long flags; + + nvkm_object_ctor(&nvkm_sw_chan, oclass, &chan->object); + chan->func = func; + chan->sw = sw; + chan->fifo = fifo; + spin_lock_irqsave(&sw->engine.lock, flags); + list_add(&chan->head, &sw->chan); + spin_unlock_irqrestore(&sw->engine.lock, flags); + + return nvkm_event_init(&nvkm_sw_chan_event, 1, 1, &chan->event); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h new file mode 100644 index 000000000000..6608bf6c6842 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h @@ -0,0 +1,26 @@ +#ifndef __NVKM_SW_CHAN_H__ +#define __NVKM_SW_CHAN_H__ +#define nvkm_sw_chan(p) container_of((p), struct nvkm_sw_chan, object) +#include "priv.h" +#include <core/event.h> + +struct nvkm_sw_chan { + const struct nvkm_sw_chan_func *func; + struct nvkm_object object; + struct nvkm_sw *sw; + struct nvkm_fifo_chan *fifo; + struct list_head head; + + struct nvkm_event event; +}; + +struct nvkm_sw_chan_func { + void *(*dtor)(struct nvkm_sw_chan *); + bool (*mthd)(struct nvkm_sw_chan *, int subc, u32 mthd, u32 data); +}; + +int nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *, struct nvkm_sw *, + struct nvkm_fifo_chan *, const struct nvkm_oclass *, + struct nvkm_sw_chan *); +bool nvkm_sw_chan_mthd(struct nvkm_sw_chan *, int subc, u32 mthd, u32 data); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index 533d5d8ed363..b01ef7eca906 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -23,119 +23,133 @@ */ #include "nv50.h" +#include <core/gpuobj.h> #include <subdev/bar.h> +#include <engine/disp.h> +#include <engine/fifo.h> + +#include <nvif/event.h> +#include <nvif/ioctl.h> /******************************************************************************* - * software object classes + * software context ******************************************************************************/ static int -gf100_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +gf100_sw_chan_vblsem_release(struct nvkm_notify *notify) { - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - u64 data = *(u32 *)args; - if (mthd == 0x0400) { - chan->vblank.offset &= 0x00ffffffffULL; - chan->vblank.offset |= data << 32; - } else { - chan->vblank.offset &= 0xff00000000ULL; - chan->vblank.offset |= data; - } - return 0; + struct nv50_sw_chan *chan = + container_of(notify, typeof(*chan), vblank.notify[notify->index]); + struct nvkm_sw *sw = chan->base.sw; + struct nvkm_device *device = sw->engine.subdev.device; + u32 inst = chan->base.fifo->inst->addr >> 12; + + nvkm_wr32(device, 0x001718, 0x80000000 | inst); + nvkm_bar_flush(device->bar); + nvkm_wr32(device, 0x06000c, upper_32_bits(chan->vblank.offset)); + nvkm_wr32(device, 0x060010, lower_32_bits(chan->vblank.offset)); + nvkm_wr32(device, 0x060014, chan->vblank.value); + + return NVKM_NOTIFY_DROP; } -static int -gf100_sw_mthd_mp_control(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +gf100_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) { - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine; - u32 data = *(u32 *)args; - + struct nv50_sw_chan *chan = nv50_sw_chan(base); + struct nvkm_engine *engine = chan->base.object.engine; + struct nvkm_device *device = engine->subdev.device; switch (mthd) { - case 0x600: - nv_wr32(priv, 0x419e00, data); /* MP.PM_UNK000 */ - break; - case 0x644: - if (data & ~0x1ffffe) - return -EINVAL; - nv_wr32(priv, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */ + case 0x0400: + chan->vblank.offset &= 0x00ffffffffULL; + chan->vblank.offset |= (u64)data << 32; + return true; + case 0x0404: + chan->vblank.offset &= 0xff00000000ULL; + chan->vblank.offset |= data; + return true; + case 0x0408: + chan->vblank.value = data; + return true; + case 0x040c: + if (data < device->disp->vblank.index_nr) { + nvkm_notify_get(&chan->vblank.notify[data]); + return true; + } break; - case 0x6ac: - nv_wr32(priv, 0x419eac, data); /* MP.PM_UNK0AC */ + case 0x600: /* MP.PM_UNK000 */ + nvkm_wr32(device, 0x419e00, data); + return true; + case 0x644: /* MP.TRAP_WARP_ERROR_EN */ + if (!(data & ~0x001ffffe)) { + nvkm_wr32(device, 0x419e44, data); + return true; + } break; + case 0x6ac: /* MP.PM_UNK0AC */ + nvkm_wr32(device, 0x419eac, data); + return true; default: - return -EINVAL; + break; } - return 0; + return false; } -static struct nvkm_omthds -gf100_sw_omthds[] = { - { 0x0400, 0x0400, gf100_sw_mthd_vblsem_offset }, - { 0x0404, 0x0404, gf100_sw_mthd_vblsem_offset }, - { 0x0408, 0x0408, nv50_sw_mthd_vblsem_value }, - { 0x040c, 0x040c, nv50_sw_mthd_vblsem_release }, - { 0x0500, 0x0500, nv50_sw_mthd_flip }, - { 0x0600, 0x0600, gf100_sw_mthd_mp_control }, - { 0x0644, 0x0644, gf100_sw_mthd_mp_control }, - { 0x06ac, 0x06ac, gf100_sw_mthd_mp_control }, - {} +static const struct nvkm_sw_chan_func +gf100_sw_chan = { + .dtor = nv50_sw_chan_dtor, + .mthd = gf100_sw_chan_mthd, }; -static struct nvkm_oclass -gf100_sw_sclass[] = { - { 0x906e, &nvkm_object_ofuncs, gf100_sw_omthds }, - {} -}; - -/******************************************************************************* - * software context - ******************************************************************************/ - static int -gf100_sw_vblsem_release(struct nvkm_notify *notify) +gf100_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) { - struct nv50_sw_chan *chan = - container_of(notify, typeof(*chan), vblank.notify[notify->index]); - struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine; - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_disp *disp = sw->engine.subdev.device->disp; + struct nv50_sw_chan *chan; + int ret, i; - nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); - bar->flush(bar); - nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset)); - nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); - nv_wr32(priv, 0x060014, chan->vblank.value); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; - return NVKM_NOTIFY_DROP; -} + ret = nvkm_sw_chan_ctor(&gf100_sw_chan, sw, fifoch, oclass, + &chan->base); + if (ret) + return ret; -static struct nv50_sw_cclass -gf100_sw_cclass = { - .base.handle = NV_ENGCTX(SW, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_context_ctor, - .dtor = nv50_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, - .vblank = gf100_sw_vblsem_release, -}; + for (i = 0; disp && i < disp->vblank.index_nr; i++) { + ret = nvkm_notify_init(NULL, &disp->vblank, + gf100_sw_chan_vblsem_release, false, + &(struct nvif_notify_head_req_v0) { + .head = i, + }, + sizeof(struct nvif_notify_head_req_v0), + sizeof(struct nvif_notify_head_rep_v0), + &chan->vblank.notify[i]); + if (ret) + return ret; + } + + return 0; +} /******************************************************************************* * software engine/subdev functions ******************************************************************************/ -struct nvkm_oclass * -gf100_sw_oclass = &(struct nv50_sw_oclass) { - .base.handle = NV_ENGINE(SW, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, - .cclass = &gf100_sw_cclass.base, - .sclass = gf100_sw_sclass, -}.base; +static const struct nvkm_sw_func +gf100_sw = { + .chan_new = gf100_sw_chan_new, + .sclass = { + { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_GF100 } }, + {} + } +}; + +int +gf100_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) +{ + return nvkm_sw_new_(&gf100_sw, device, index, psw); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index 897024421d36..445217ffa791 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -21,15 +21,18 @@ * * Authors: Ben Skeggs */ -#include <engine/sw.h> -#include <engine/fifo.h> +#define nv04_sw_chan(p) container_of((p), struct nv04_sw_chan, base) +#include "priv.h" +#include "chan.h" +#include "nvsw.h" -struct nv04_sw_priv { - struct nvkm_sw base; -}; +#include <nvif/class.h> +#include <nvif/ioctl.h> +#include <nvif/unpack.h> struct nv04_sw_chan { struct nvkm_sw_chan base; + atomic_t ref; }; /******************************************************************************* @@ -37,103 +40,99 @@ struct nv04_sw_chan { ******************************************************************************/ static int -nv04_sw_set_ref(struct nvkm_object *object, u32 mthd, void *data, u32 size) +nv04_nvsw_mthd_get_ref(struct nvkm_nvsw *nvsw, void *data, u32 size) { - struct nvkm_object *channel = (void *)nv_engctx(object->parent); - struct nvkm_fifo_chan *fifo = (void *)channel->parent; - atomic_set(&fifo->refcnt, *(u32*)data); - return 0; + struct nv04_sw_chan *chan = nv04_sw_chan(nvsw->chan); + union { + struct nv04_nvsw_get_ref_v0 v0; + } *args = data; + int ret; + + if (nvif_unpack(args->v0, 0, 0, false)) { + args->v0.ref = atomic_read(&chan->ref); + } + + return ret; } static int -nv04_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) +nv04_nvsw_mthd(struct nvkm_nvsw *nvsw, u32 mthd, void *data, u32 size) { - struct nv04_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->base.flip) - return chan->base.flip(chan->base.flip_data); + switch (mthd) { + case NV04_NVSW_GET_REF: + return nv04_nvsw_mthd_get_ref(nvsw, data, size); + default: + break; + } return -EINVAL; } -static struct nvkm_omthds -nv04_sw_omthds[] = { - { 0x0150, 0x0150, nv04_sw_set_ref }, - { 0x0500, 0x0500, nv04_sw_flip }, - {} +static const struct nvkm_nvsw_func +nv04_nvsw = { + .mthd = nv04_nvsw_mthd, }; -static struct nvkm_oclass -nv04_sw_sclass[] = { - { 0x006e, &nvkm_object_ofuncs, nv04_sw_omthds }, - {} -}; +static int +nv04_nvsw_new(struct nvkm_sw_chan *chan, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nvkm_nvsw_new_(&nv04_nvsw, chan, oclass, data, size, pobject); +} /******************************************************************************* * software context ******************************************************************************/ -static int -nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static bool +nv04_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) { - struct nv04_sw_chan *chan; - int ret; + struct nv04_sw_chan *chan = nv04_sw_chan(base); - ret = nvkm_sw_context_create(parent, engine, oclass, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + switch (mthd) { + case 0x0150: + atomic_set(&chan->ref, data); + return true; + default: + break; + } - return 0; + return false; } -static struct nvkm_oclass -nv04_sw_cclass = { - .handle = NV_ENGCTX(SW, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_sw_context_ctor, - .dtor = _nvkm_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, +static const struct nvkm_sw_chan_func +nv04_sw_chan = { + .mthd = nv04_sw_chan_mthd, }; -/******************************************************************************* - * software engine/subdev functions - ******************************************************************************/ - -void -nv04_sw_intr(struct nvkm_subdev *subdev) -{ - nv_mask(subdev, 0x000100, 0x80000000, 0x00000000); -} - static int -nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifo, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - struct nv04_sw_priv *priv; - int ret; + struct nv04_sw_chan *chan; - ret = nvkm_sw_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + atomic_set(&chan->ref, 0); + *pobject = &chan->base.object; - nv_engine(priv)->cclass = &nv04_sw_cclass; - nv_engine(priv)->sclass = nv04_sw_sclass; - nv_subdev(priv)->intr = nv04_sw_intr; - return 0; + return nvkm_sw_chan_ctor(&nv04_sw_chan, sw, fifo, oclass, &chan->base); } -struct nvkm_oclass * -nv04_sw_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(SW, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, +/******************************************************************************* + * software engine/subdev functions + ******************************************************************************/ + +static const struct nvkm_sw_func +nv04_sw = { + .chan_new = nv04_sw_chan_new, + .sclass = { + { nv04_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV04 } }, + {} + } }; + +int +nv04_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) +{ + return nvkm_sw_new_(&nv04_sw, device, index, psw); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c index c61153a3fb8b..adf70d92b244 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c @@ -21,102 +21,48 @@ * * Authors: Ben Skeggs */ -#include <engine/sw.h> +#include "priv.h" +#include "chan.h" +#include "nvsw.h" -struct nv10_sw_priv { - struct nvkm_sw base; -}; - -struct nv10_sw_chan { - struct nvkm_sw_chan base; -}; +#include <nvif/ioctl.h> /******************************************************************************* - * software object classes + * software context ******************************************************************************/ -static int -nv10_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) -{ - struct nv10_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->base.flip) - return chan->base.flip(chan->base.flip_data); - return -EINVAL; -} - -static struct nvkm_omthds -nv10_sw_omthds[] = { - { 0x0500, 0x0500, nv10_sw_flip }, - {} -}; - -static struct nvkm_oclass -nv10_sw_sclass[] = { - { 0x016e, &nvkm_object_ofuncs, nv10_sw_omthds }, - {} +static const struct nvkm_sw_chan_func +nv10_sw_chan = { }; -/******************************************************************************* - * software context - ******************************************************************************/ - static int -nv10_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv10_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifo, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - struct nv10_sw_chan *chan; - int ret; + struct nvkm_sw_chan *chan; - ret = nvkm_sw_context_create(parent, engine, oclass, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->object; - return 0; + return nvkm_sw_chan_ctor(&nv10_sw_chan, sw, fifo, oclass, chan); } -static struct nvkm_oclass -nv10_sw_cclass = { - .handle = NV_ENGCTX(SW, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_sw_context_ctor, - .dtor = _nvkm_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, -}; - /******************************************************************************* * software engine/subdev functions ******************************************************************************/ -static int -nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv10_sw_priv *priv; - int ret; - - ret = nvkm_sw_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; +static const struct nvkm_sw_func +nv10_sw = { + .chan_new = nv10_sw_chan_new, + .sclass = { + { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV10 } }, + {} + } +}; - nv_engine(priv)->cclass = &nv10_sw_cclass; - nv_engine(priv)->sclass = nv10_sw_sclass; - nv_subdev(priv)->intr = nv04_sw_intr; - return 0; +int +nv10_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) +{ + return nvkm_sw_new_(&nv10_sw, device, index, psw); } - -struct nvkm_oclass * -nv10_sw_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(SW, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 401fcd73086b..a381196af69d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -23,153 +23,98 @@ */ #include "nv50.h" -#include <core/device.h> -#include <core/handle.h> -#include <core/namedb.h> +#include <core/gpuobj.h> #include <engine/disp.h> +#include <engine/fifo/chan.h> #include <subdev/bar.h> #include <nvif/event.h> - -/******************************************************************************* - * software object classes - ******************************************************************************/ - -static int -nv50_sw_mthd_dma_vblsem(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - struct nvkm_fifo_chan *fifo = (void *)nv_object(chan)->parent; - struct nvkm_handle *handle; - int ret = -EINVAL; - - handle = nvkm_namedb_get(nv_namedb(fifo), *(u32 *)args); - if (!handle) - return -ENOENT; - - if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { - struct nvkm_gpuobj *gpuobj = nv_gpuobj(handle->object); - chan->vblank.ctxdma = gpuobj->node->offset >> 4; - ret = 0; - } - nvkm_namedb_put(handle); - return ret; -} - -static int -nv50_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - chan->vblank.offset = *(u32 *)args; - return 0; -} - -int -nv50_sw_mthd_vblsem_value(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - chan->vblank.value = *(u32 *)args; - return 0; -} - -int -nv50_sw_mthd_vblsem_release(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - u32 head = *(u32 *)args; - if (head >= nvkm_disp(chan)->vblank.index_nr) - return -EINVAL; - - nvkm_notify_get(&chan->vblank.notify[head]); - return 0; -} - -int -nv50_sw_mthd_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->base.flip) - return chan->base.flip(chan->base.flip_data); - return -EINVAL; -} - -static struct nvkm_omthds -nv50_sw_omthds[] = { - { 0x018c, 0x018c, nv50_sw_mthd_dma_vblsem }, - { 0x0400, 0x0400, nv50_sw_mthd_vblsem_offset }, - { 0x0404, 0x0404, nv50_sw_mthd_vblsem_value }, - { 0x0408, 0x0408, nv50_sw_mthd_vblsem_release }, - { 0x0500, 0x0500, nv50_sw_mthd_flip }, - {} -}; - -static struct nvkm_oclass -nv50_sw_sclass[] = { - { 0x506e, &nvkm_object_ofuncs, nv50_sw_omthds }, - {} -}; +#include <nvif/ioctl.h> /******************************************************************************* * software context ******************************************************************************/ static int -nv50_sw_vblsem_release(struct nvkm_notify *notify) +nv50_sw_chan_vblsem_release(struct nvkm_notify *notify) { struct nv50_sw_chan *chan = container_of(notify, typeof(*chan), vblank.notify[notify->index]); - struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine; - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_sw *sw = chan->base.sw; + struct nvkm_device *device = sw->engine.subdev.device; - nv_wr32(priv, 0x001704, chan->vblank.channel); - nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); - bar->flush(bar); + nvkm_wr32(device, 0x001704, chan->base.fifo->inst->addr >> 12); + nvkm_wr32(device, 0x001710, 0x80000000 | chan->vblank.ctxdma); + nvkm_bar_flush(device->bar); - if (nv_device(priv)->chipset == 0x50) { - nv_wr32(priv, 0x001570, chan->vblank.offset); - nv_wr32(priv, 0x001574, chan->vblank.value); + if (device->chipset == 0x50) { + nvkm_wr32(device, 0x001570, chan->vblank.offset); + nvkm_wr32(device, 0x001574, chan->vblank.value); } else { - nv_wr32(priv, 0x060010, chan->vblank.offset); - nv_wr32(priv, 0x060014, chan->vblank.value); + nvkm_wr32(device, 0x060010, chan->vblank.offset); + nvkm_wr32(device, 0x060014, chan->vblank.value); } return NVKM_NOTIFY_DROP; } -void -nv50_sw_context_dtor(struct nvkm_object *object) +static bool +nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) { - struct nv50_sw_chan *chan = (void *)object; - int i; + struct nv50_sw_chan *chan = nv50_sw_chan(base); + struct nvkm_engine *engine = chan->base.object.engine; + struct nvkm_device *device = engine->subdev.device; + switch (mthd) { + case 0x018c: chan->vblank.ctxdma = data; return true; + case 0x0400: chan->vblank.offset = data; return true; + case 0x0404: chan->vblank.value = data; return true; + case 0x0408: + if (data < device->disp->vblank.index_nr) { + nvkm_notify_get(&chan->vblank.notify[data]); + return true; + } + break; + default: + break; + } + return false; +} +void * +nv50_sw_chan_dtor(struct nvkm_sw_chan *base) +{ + struct nv50_sw_chan *chan = nv50_sw_chan(base); + int i; for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++) nvkm_notify_fini(&chan->vblank.notify[i]); - - nvkm_sw_context_destroy(&chan->base); + return chan; } -int -nv50_sw_context_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_sw_chan_func +nv50_sw_chan = { + .dtor = nv50_sw_chan_dtor, + .mthd = nv50_sw_chan_mthd, +}; + +static int +nv50_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - struct nvkm_disp *pdisp = nvkm_disp(parent); - struct nv50_sw_cclass *pclass = (void *)oclass; + struct nvkm_disp *disp = sw->engine.subdev.device->disp; struct nv50_sw_chan *chan; int ret, i; - ret = nvkm_sw_context_create(parent, engine, oclass, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_sw_chan_ctor(&nv50_sw_chan, sw, fifoch, oclass, &chan->base); if (ret) return ret; - for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) { - ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank, - false, + for (i = 0; disp && i < disp->vblank.index_nr; i++) { + ret = nvkm_notify_init(NULL, &disp->vblank, + nv50_sw_chan_vblsem_release, false, &(struct nvif_notify_head_req_v0) { .head = i, }, @@ -180,55 +125,24 @@ nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; } - chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; return 0; } -static struct nv50_sw_cclass -nv50_sw_cclass = { - .base.handle = NV_ENGCTX(SW, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_context_ctor, - .dtor = nv50_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, - .vblank = nv50_sw_vblsem_release, -}; - /******************************************************************************* * software engine/subdev functions ******************************************************************************/ +static const struct nvkm_sw_func +nv50_sw = { + .chan_new = nv50_sw_chan_new, + .sclass = { + { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV50 } }, + {} + } +}; + int -nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) { - struct nv50_sw_oclass *pclass = (void *)oclass; - struct nv50_sw_priv *priv; - int ret; - - ret = nvkm_sw_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_engine(priv)->cclass = pclass->cclass; - nv_engine(priv)->sclass = pclass->sclass; - nv_subdev(priv)->intr = nv04_sw_intr; - return 0; + return nvkm_sw_new_(&nv50_sw, device, index, psw); } - -struct nvkm_oclass * -nv50_sw_oclass = &(struct nv50_sw_oclass) { - .base.handle = NV_ENGINE(SW, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, - .cclass = &nv50_sw_cclass.base, - .sclass = nv50_sw_sclass, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h index d8adc1108467..25cdfdef2d46 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h @@ -1,45 +1,20 @@ #ifndef __NVKM_SW_NV50_H__ #define __NVKM_SW_NV50_H__ -#include <engine/sw.h> +#define nv50_sw_chan(p) container_of((p), struct nv50_sw_chan, base) +#include "priv.h" +#include "chan.h" +#include "nvsw.h" #include <core/notify.h> -struct nv50_sw_oclass { - struct nvkm_oclass base; - struct nvkm_oclass *cclass; - struct nvkm_oclass *sclass; -}; - -struct nv50_sw_priv { - struct nvkm_sw base; -}; - -int nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -struct nv50_sw_cclass { - struct nvkm_oclass base; - int (*vblank)(struct nvkm_notify *); -}; - struct nv50_sw_chan { struct nvkm_sw_chan base; struct { struct nvkm_notify notify[4]; - u32 channel; u32 ctxdma; u64 offset; u32 value; } vblank; }; -int nv50_sw_context_ctor(struct nvkm_object *, - struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv50_sw_context_dtor(struct nvkm_object *); - -int nv50_sw_mthd_vblsem_value(struct nvkm_object *, u32, void *, u32); -int nv50_sw_mthd_vblsem_release(struct nvkm_object *, u32, void *, u32); -int nv50_sw_mthd_flip(struct nvkm_object *, u32, void *, u32); +void *nv50_sw_chan_dtor(struct nvkm_sw_chan *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c new file mode 100644 index 000000000000..66cf986b9572 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c @@ -0,0 +1,85 @@ +/* + * 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 "nvsw.h" +#include "chan.h" + +#include <nvif/class.h> + +static int +nvkm_nvsw_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + struct nvkm_nvsw *nvsw = nvkm_nvsw(object); + if (nvsw->func->mthd) + return nvsw->func->mthd(nvsw, mthd, data, size); + return -ENODEV; +} + +static int +nvkm_nvsw_ntfy_(struct nvkm_object *object, u32 mthd, + struct nvkm_event **pevent) +{ + struct nvkm_nvsw *nvsw = nvkm_nvsw(object); + switch (mthd) { + case NVSW_NTFY_UEVENT: + *pevent = &nvsw->chan->event; + return 0; + default: + break; + } + return -EINVAL; +} + +static const struct nvkm_object_func +nvkm_nvsw_ = { + .mthd = nvkm_nvsw_mthd_, + .ntfy = nvkm_nvsw_ntfy_, +}; + +int +nvkm_nvsw_new_(const struct nvkm_nvsw_func *func, struct nvkm_sw_chan *chan, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_nvsw *nvsw; + + if (!(nvsw = kzalloc(sizeof(*nvsw), GFP_KERNEL))) + return -ENOMEM; + *pobject = &nvsw->object; + + nvkm_object_ctor(&nvkm_nvsw_, oclass, &nvsw->object); + nvsw->func = func; + nvsw->chan = chan; + return 0; +} + +static const struct nvkm_nvsw_func +nvkm_nvsw = { +}; + +int +nvkm_nvsw_new(struct nvkm_sw_chan *chan, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nvkm_nvsw_new_(&nvkm_nvsw, chan, oclass, data, size, pobject); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h new file mode 100644 index 000000000000..943ef4c10091 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h @@ -0,0 +1,21 @@ +#ifndef __NVKM_NVSW_H__ +#define __NVKM_NVSW_H__ +#define nvkm_nvsw(p) container_of((p), struct nvkm_nvsw, object) +#include "priv.h" + +struct nvkm_nvsw { + struct nvkm_object object; + const struct nvkm_nvsw_func *func; + struct nvkm_sw_chan *chan; +}; + +struct nvkm_nvsw_func { + int (*mthd)(struct nvkm_nvsw *, u32 mthd, void *data, u32 size); +}; + +int nvkm_nvsw_new_(const struct nvkm_nvsw_func *, struct nvkm_sw_chan *, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **pobject); +int nvkm_nvsw_new(struct nvkm_sw_chan *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **pobject); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h new file mode 100644 index 000000000000..0ef1318dc2fd --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h @@ -0,0 +1,21 @@ +#ifndef __NVKM_SW_PRIV_H__ +#define __NVKM_SW_PRIV_H__ +#define nvkm_sw(p) container_of((p), struct nvkm_sw, engine) +#include <engine/sw.h> +struct nvkm_sw_chan; + +int nvkm_sw_new_(const struct nvkm_sw_func *, struct nvkm_device *, + int index, struct nvkm_sw **); + +struct nvkm_sw_chan_sclass { + int (*ctor)(struct nvkm_sw_chan *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + struct nvkm_sclass base; +}; + +struct nvkm_sw_func { + int (*chan_new)(struct nvkm_sw *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + const struct nvkm_sw_chan_sclass sclass[]; +}; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c index 45f4e186befc..4188c77ac927 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c @@ -22,72 +22,23 @@ * Authors: Ben Skeggs, Ilia Mirkin */ #include <engine/vp.h> -#include <engine/xtensa.h> -#include <core/engctx.h> - -/******************************************************************************* - * VP object classes - ******************************************************************************/ - -static struct nvkm_oclass -g84_vp_sclass[] = { - { 0x7476, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PVP context - ******************************************************************************/ - -static struct nvkm_oclass -g84_vp_cclass = { - .handle = NV_ENGCTX(VP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_xtensa_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, - }, +#include <nvif/class.h> + +static const struct nvkm_xtensa_func +g84_vp = { + .pmc_enable = 0x01020000, + .fifo_val = 0x111, + .unkd28 = 0x9c544, + .sclass = { + { -1, -1, NV74_VP2 }, + {} + } }; -/******************************************************************************* - * PVP engine/subdev functions - ******************************************************************************/ - -static int -g84_vp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_vp_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine) { - struct nvkm_xtensa *priv; - int ret; - - ret = nvkm_xtensa_create(parent, engine, oclass, 0xf000, true, - "PVP", "vp", &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - nv_subdev(priv)->unit = 0x01020000; - nv_engine(priv)->cclass = &g84_vp_cclass; - nv_engine(priv)->sclass = g84_vp_sclass; - priv->fifo_val = 0x111; - priv->unkd28 = 0x9c544; - return 0; + return nvkm_xtensa_new_(&g84_vp, device, index, + true, 0x00f000, pengine); } - -struct nvkm_oclass -g84_vp_oclass = { - .handle = NV_ENGINE(VP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_vp_ctor, - .dtor = _nvkm_xtensa_dtor, - .init = _nvkm_xtensa_init, - .fini = _nvkm_xtensa_fini, - .rd32 = _nvkm_xtensa_rd32, - .wr32 = _nvkm_xtensa_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index cea90df533d9..a3d4f5bcec7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -20,153 +20,173 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include <engine/xtensa.h> -#include <core/device.h> -#include <core/engctx.h> +#include <core/gpuobj.h> +#include <engine/fifo.h> -u32 -_nvkm_xtensa_rd32(struct nvkm_object *object, u64 addr) +static int +nvkm_xtensa_oclass_get(struct nvkm_oclass *oclass, int index) { - struct nvkm_xtensa *xtensa = (void *)object; - return nv_rd32(xtensa, xtensa->addr + addr); -} + struct nvkm_xtensa *xtensa = nvkm_xtensa(oclass->engine); + int c = 0; -void -_nvkm_xtensa_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_xtensa *xtensa = (void *)object; - nv_wr32(xtensa, xtensa->addr + addr, data); + while (xtensa->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = xtensa->func->sclass[index]; + return index; + } + } + + return c; } -int -_nvkm_xtensa_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static int +nvkm_xtensa_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_engctx *engctx; - int ret; - - ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &engctx); - *pobject = nv_object(engctx); - return ret; + return nvkm_gpuobj_new(object->engine->subdev.device, 0x10000, align, + true, parent, pgpuobj); } -void -_nvkm_xtensa_intr(struct nvkm_subdev *subdev) +static const struct nvkm_object_func +nvkm_xtensa_cclass = { + .bind = nvkm_xtensa_cclass_bind, +}; + +static void +nvkm_xtensa_intr(struct nvkm_engine *engine) { - struct nvkm_xtensa *xtensa = (void *)subdev; - u32 unk104 = nv_ro32(xtensa, 0xd04); - u32 intr = nv_ro32(xtensa, 0xc20); - u32 chan = nv_ro32(xtensa, 0xc28); - u32 unk10c = nv_ro32(xtensa, 0xd0c); + struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); + struct nvkm_subdev *subdev = &xtensa->engine.subdev; + struct nvkm_device *device = subdev->device; + const u32 base = xtensa->addr; + u32 unk104 = nvkm_rd32(device, base + 0xd04); + u32 intr = nvkm_rd32(device, base + 0xc20); + u32 chan = nvkm_rd32(device, base + 0xc28); + u32 unk10c = nvkm_rd32(device, base + 0xd0c); if (intr & 0x10) - nv_warn(xtensa, "Watchdog interrupt, engine hung.\n"); - nv_wo32(xtensa, 0xc20, intr); - intr = nv_ro32(xtensa, 0xc20); + nvkm_warn(subdev, "Watchdog interrupt, engine hung.\n"); + nvkm_wr32(device, base + 0xc20, intr); + intr = nvkm_rd32(device, base + 0xc20); if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) { - nv_debug(xtensa, "Enabling FIFO_CTRL\n"); - nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val); + nvkm_debug(subdev, "Enabling FIFO_CTRL\n"); + nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->func->fifo_val); } } -int -nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 addr, bool enable, - const char *iname, const char *fname, - int length, void **pobject) +static int +nvkm_xtensa_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_xtensa *xtensa; - int ret; + struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); + struct nvkm_device *device = xtensa->engine.subdev.device; + const u32 base = xtensa->addr; - ret = nvkm_engine_create_(parent, engine, oclass, enable, iname, - fname, length, pobject); - xtensa = *pobject; - if (ret) - return ret; + nvkm_wr32(device, base + 0xd84, 0); /* INTR_EN */ + nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */ - nv_subdev(xtensa)->intr = _nvkm_xtensa_intr; - xtensa->addr = addr; + if (!suspend) + nvkm_memory_del(&xtensa->gpu_fw); return 0; } -int -_nvkm_xtensa_init(struct nvkm_object *object) +static int +nvkm_xtensa_init(struct nvkm_engine *engine) { - struct nvkm_device *device = nv_device(object); - struct nvkm_xtensa *xtensa = (void *)object; + struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); + struct nvkm_subdev *subdev = &xtensa->engine.subdev; + struct nvkm_device *device = subdev->device; + const u32 base = xtensa->addr; const struct firmware *fw; char name[32]; int i, ret; + u64 addr, size; u32 tmp; - ret = nvkm_engine_init(&xtensa->base); - if (ret) - return ret; - if (!xtensa->gpu_fw) { snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x", xtensa->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret) { - nv_warn(xtensa, "unable to load firmware %s\n", name); + nvkm_warn(subdev, "unable to load firmware %s\n", name); return ret; } if (fw->size > 0x40000) { - nv_warn(xtensa, "firmware %s too large\n", name); + nvkm_warn(subdev, "firmware %s too large\n", name); release_firmware(fw); return -EINVAL; } - ret = nvkm_gpuobj_new(object, NULL, 0x40000, 0x1000, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x40000, 0x1000, false, &xtensa->gpu_fw); if (ret) { release_firmware(fw); return ret; } - nv_debug(xtensa, "Loading firmware to address: 0x%llx\n", - xtensa->gpu_fw->addr); - + nvkm_kmap(xtensa->gpu_fw); for (i = 0; i < fw->size / 4; i++) - nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i)); + nvkm_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i)); + nvkm_done(xtensa->gpu_fw); release_firmware(fw); } - nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */ - nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */ + addr = nvkm_memory_addr(xtensa->gpu_fw); + size = nvkm_memory_size(xtensa->gpu_fw); - nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */ - nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */ - nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */ + nvkm_wr32(device, base + 0xd10, 0x1fffffff); /* ?? */ + nvkm_wr32(device, base + 0xd08, 0x0fffffff); /* ?? */ - nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */ - nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */ - nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */ + nvkm_wr32(device, base + 0xd28, xtensa->func->unkd28); /* ?? */ + nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ + nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ - tmp = nv_rd32(xtensa, 0x0); - nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */ + nvkm_wr32(device, base + 0xcc0, addr >> 8); /* XT_REGION_BASE */ + nvkm_wr32(device, base + 0xcc4, 0x1c); /* XT_REGION_SETUP */ + nvkm_wr32(device, base + 0xcc8, size >> 8); /* XT_REGION_LIMIT */ - nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */ + tmp = nvkm_rd32(device, 0x0); + nvkm_wr32(device, base + 0xde0, tmp); /* SCRATCH_H2X */ - nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */ - nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */ + nvkm_wr32(device, base + 0xce8, 0xf); /* XT_REGION_SETUP */ + + nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ + nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ return 0; } -int -_nvkm_xtensa_fini(struct nvkm_object *object, bool suspend) +static void * +nvkm_xtensa_dtor(struct nvkm_engine *engine) { - struct nvkm_xtensa *xtensa = (void *)object; + return nvkm_xtensa(engine); +} - nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */ - nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */ +static const struct nvkm_engine_func +nvkm_xtensa = { + .dtor = nvkm_xtensa_dtor, + .init = nvkm_xtensa_init, + .fini = nvkm_xtensa_fini, + .intr = nvkm_xtensa_intr, + .fifo.sclass = nvkm_xtensa_oclass_get, + .cclass = &nvkm_xtensa_cclass, +}; - if (!suspend) - nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw); +int +nvkm_xtensa_new_(const struct nvkm_xtensa_func *func, + struct nvkm_device *device, int index, bool enable, + u32 addr, struct nvkm_engine **pengine) +{ + struct nvkm_xtensa *xtensa; + + if (!(xtensa = kzalloc(sizeof(*xtensa), GFP_KERNEL))) + return -ENOMEM; + xtensa->func = func; + xtensa->addr = addr; + *pengine = &xtensa->engine; - return nvkm_engine_fini(&xtensa->base, suspend); + return nvkm_engine_ctor(&nvkm_xtensa, device, index, func->pmc_enable, + enable, &xtensa->engine); } |