diff --git a/drivers/gpu/drm/nouveau/core/core/engine.c b/drivers/gpu/drm/nouveau/core/core/engine.c index c8bed4a..0405fba 100644 --- a/drivers/gpu/drm/nouveau/core/core/engine.c +++ b/drivers/gpu/drm/nouveau/core/core/engine.c @@ -34,6 +34,7 @@ nouveau_engine_create_(struct nouveau_object *parent, int length, void **pobject) { struct nouveau_engine *engine; + struct nouveau_device *device; int ret; ret = nouveau_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS, @@ -42,11 +43,21 @@ nouveau_engine_create_(struct nouveau_object *parent, if (ret) return ret; - if ( parent && - !nouveau_boolopt(nv_device(parent)->cfgopt, iname, enable)) { - if (!enable) - nv_warn(engine, "disabled, %s=1 to enable\n", iname); - return -ENODEV; + if (parent) { + device = nv_device(parent); + if (device->disable_mask & (1ULL << (oclass->handle & 0xff))) { + if (nouveau_boolopt(device->cfgopt, iname, false)) { + nv_warn(engine, "hardware is marked as disabled, but obeying explicit enable\n"); + } else { + nv_info(engine, "hardware is marked as disabled\n"); + return -ENODEV; + } + } + if (!nouveau_boolopt(device->cfgopt, iname, enable)) { + if (!enable) + nv_warn(engine, "disabled, %s=1 to enable\n", iname); + return -ENODEV; + } } INIT_LIST_HEAD(&engine->contexts); diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h index ac2881d..d04c523 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/device.h +++ b/drivers/gpu/drm/nouveau/core/include/core/device.h @@ -70,6 +70,7 @@ struct nouveau_device { const char *dbgopt; const char *name; const char *cname; + u64 disable_mask; enum { NV_04 = 0x04, diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c index 6df7224..b9f67a1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c @@ -78,11 +78,14 @@ int nv50_devinit_init(struct nouveau_object *object) { struct nouveau_bios *bios = nouveau_bios(object); + struct nouveau_device *device = nv_device(object); struct nv50_devinit_priv *priv = (void *)object; struct nvbios_outp info; struct dcb_output outp; u8 ver = 0xff, hdr, cnt, len; int ret, i = 0; + bool vdec; + u32 r154c; if (!priv->base.post) { if (!nv_rdvgac(priv, 0, 0x00) && @@ -117,6 +120,63 @@ nv50_devinit_init(struct nouveau_object *object) i++; } + /* check for disabled engines */ + vdec = nv_rd32(device, 0x1540) & 0x40000000; + if (device->chipset > 0x50) + r154c = nv_rd32(device, 0x154c); + else + r154c = 0; + + switch (device->chipset) { + case 0x50: + if (!vdec) + device->disable_mask |= 1ULL << NVDEV_ENGINE_MPEG; + break; + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0xa0: + if (!vdec) { + device->disable_mask |= 1ULL << NVDEV_ENGINE_MPEG; + device->disable_mask |= 1ULL << NVDEV_ENGINE_VP; + } + if (!vdec || !(r154c & 0x20)) + device->disable_mask |= 1ULL << NVDEV_ENGINE_BSP; + if (!vdec || !(r154c & 0x40)) + device->disable_mask |= 1ULL << NVDEV_ENGINE_CRYPT; + break; + case 0x98: + case 0xaa: + case 0xac: + if (!vdec) { + device->disable_mask |= 1ULL << NVDEV_ENGINE_VP; + device->disable_mask |= 1ULL << NVDEV_ENGINE_PPP; + } + if (!vdec || !(r154c & 0x20)) + device->disable_mask |= 1ULL << NVDEV_ENGINE_BSP; + if (!(r154c & 0x40)) + device->disable_mask |= 1ULL << NVDEV_ENGINE_CRYPT; + break; + case 0xaf: + if (!(r154c & 0x40)) + device->disable_mask |= 1ULL << NVDEV_ENGINE_VIC; + /* fallthrough */ + case 0xa3: + case 0xa5: + case 0xa8: + if (!vdec) { + device->disable_mask |= 1ULL << NVDEV_ENGINE_VP; + device->disable_mask |= 1ULL << NVDEV_ENGINE_PPP; + } + if (!(r154c & 0x20)) + device->disable_mask |= 1ULL << NVDEV_ENGINE_BSP; + if (!(r154c & 0x200)) + device->disable_mask |= 1ULL << NVDEV_ENGINE_COPY0; + break; + } + return 0; }