commit dc5fd11d705d27c877bcb36e6e94128c1f67a5b9 Author: Maxim Levitsky Date: Fri Aug 5 23:47:06 2011 +0300 nv50: resurrect ability to load firmware ctxprog. This feature is usefull to debug problems with built-in ctxprog generator. diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 033cf3a..52dcd56 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -119,7 +119,7 @@ MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n"); int nouveau_msi; module_param_named(msi, nouveau_msi, int, 0400); -MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)\n"); +MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi/tesla)\n"); int nouveau_ctxfw; module_param_named(ctxfw, nouveau_ctxfw, int, 0400); diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index 4b46d69..a14ddc2 100644 --- a/drivers/gpu/drm/nouveau/nv50_grctx.c +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c @@ -108,6 +108,7 @@ #include "drmP.h" #include "nouveau_drv.h" #include "nouveau_grctx.h" +#include #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) #define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac) @@ -170,6 +171,105 @@ static void nv50_graph_construct_mmio(struct nouveau_grctx *ctx); static void nv50_graph_construct_xfer1(struct nouveau_grctx *ctx); static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx); +MODULE_FIRMWARE("nouveau/nv.ctxprog"); +MODULE_FIRMWARE("nouveau/nv.ctxvals"); + + +struct nouveau_ctxprog { + uint32_t signature; + uint8_t version; + uint16_t length; + uint32_t data[]; +} __attribute__ ((packed)); + +struct nouveau_ctxvals { + uint32_t signature; + uint8_t version; + uint32_t length; + struct { + uint32_t offset; + uint32_t value; + } data[]; +} __attribute__ ((packed)); + +#define CTXVAL_SIZE 0x70000 + +int +nv50_ctxfw_load(struct nouveau_grctx *ctx) +{ + struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + struct drm_device *dev = ctx->dev; + + char name[32]; + const struct firmware *fw; + int ret,i; + + if (ctx->mode == NOUVEAU_GRCTX_PROG) { + struct nouveau_ctxprog *cp; + + sprintf(name, "nouveau/nv.ctxprog"); + ret = request_firmware(&fw, name, &dev->pdev->dev); + if (ret || fw->size < 7) { + NV_ERROR(dev, "ctxprog invalid\n"); + release_firmware(fw); + return -EINVAL; + } + + cp = (struct nouveau_ctxprog *)fw->data; + + if (le32_to_cpu(cp->signature) != 0x5043564e || + cp->version != 0 || + le16_to_cpu(cp->length) != ((fw->size - 7) / 4) || + le16_to_cpu(cp->length) > ctx->ctxprog_max) { + NV_ERROR(dev, "ctxprog invalid\n"); + release_firmware(fw); + return -EINVAL; + } + + memcpy(ctx->data, cp->data, cp->length * 4); + ctx->ctxprog_len = cp->length; + ctx->ctxvals_pos = CTXVAL_SIZE / 4; + NV_INFO(dev, "firmware ctxprog loaded"); + + } else { + + struct nouveau_ctxvals *cv; + + sprintf(name, "nouveau/nv.ctxvals"); + ret = request_firmware(&fw, name, &dev->pdev->dev); + if (ret || fw->size < 9) { + NV_ERROR(dev, "ctxvals invalid"); + release_firmware(fw); + return -EINVAL; + } + + cv = (struct nouveau_ctxvals *)fw->data; + if (le32_to_cpu(cv->signature) != 0x5643564e || + cv->version != 0 || + le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) { + NV_ERROR(dev, "ctxvals invalid\n"); + release_firmware(fw); + return -EINVAL; + } + + for (i = 0; i < le32_to_cpu(cv->length); i++) { + + if (cv->data[i].offset >= CTXVAL_SIZE) { + //NV_ERROR(dev, "out of bound ctxval write\n"); + continue; + } + + nv_wo32(ctx->data, le32_to_cpu(cv->data[i].offset) * 4, + le32_to_cpu(cv->data[i].value)); + } + + NV_INFO(dev, "firmware ctxvals loaded\n"); + } + + release_firmware(fw); + return 0; +} + /* Main function: construct the ctxprog skeleton, call the other functions. */ int @@ -177,6 +277,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx) { struct drm_nouveau_private *dev_priv = ctx->dev->dev_private; + if (nouveau_ctxfw && !nv50_ctxfw_load(ctx)) + return 0; + switch (dev_priv->chipset) { case 0x50: case 0x84: