From 205877f9156daebb975fb46205488da6fdf5b3f5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 27 Aug 2015 17:33:19 +1000 Subject: [PATCH] drm/nouveau/pmu/gk104: implement a hackish workaround for a hw bug Only a handful of machines have this enabled by default, where it's been proven to work. The workaround can be explicitly enabled with a module option also. Still waiting on feedback from NVIDIA for a proper idea of exactly what this fix is doing, and how to implement it properly. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 28fdb8e..b744136f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -26,9 +26,36 @@ #include "priv.h" #include "fuc/gf110.fuc4.h" +#include +#include +#include + +static void +magic_(struct nvkm_pmu *pmu, u32 ctrl, int size) +{ + nv_wr32(pmu, 0x00c800, 0x00000000); + nv_wr32(pmu, 0x00c808, 0x00000000); + nv_wr32(pmu, 0x00c800, ctrl); + if (nv_wait(pmu, 0x00c800, 0x40000000, 0x40000000)) { + while (size--) + nv_wr32(pmu, 0x00c804, 0x00000000); + } + nv_wr32(pmu, 0x00c800, 0x00000000); +} + +static void +magic(struct nvkm_pmu *pmu, u32 ctrl) +{ + magic_(pmu, 0x8000a41f | ctrl, 6); + magic_(pmu, 0x80000421 | ctrl, 1); +} + static void gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { + struct nvkm_device *device = nv_device(pmu); + struct nvkm_object *dev = nv_object(device); + nv_mask(pmu, 0x000200, 0x00001000, 0x00000000); nv_rd32(pmu, 0x000200); nv_mask(pmu, 0x000200, 0x08000000, 0x08000000); @@ -48,6 +75,30 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nv_mask(pmu, 0x000200, 0x08000000, 0x00000000); nv_mask(pmu, 0x000200, 0x00001000, 0x00001000); nv_rd32(pmu, 0x000200); + + if (nv_device_match(dev, 0x11fc, 0x17aa, 0x2211) /* Lenovo W541 */ + || nv_device_match(dev, 0x11fc, 0x17aa, 0x221e) /* Lenovo W541 */ + || nvkm_boolopt(device->cfgopt, "War00C800_0", false)) { + nv_info(pmu, "hw bug workaround enabled\n"); + switch (device->chipset) { + case 0xe4: + magic(pmu, 0x04000000); + magic(pmu, 0x06000000); + magic(pmu, 0x0c000000); + magic(pmu, 0x0e000000); + break; + case 0xe6: + magic(pmu, 0x02000000); + magic(pmu, 0x04000000); + magic(pmu, 0x0a000000); + break; + case 0xe7: + magic(pmu, 0x02000000); + break; + default: + break; + } + } } struct nvkm_oclass * -- 2.7.4