diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 28fdb8ea9ed8..b744136f5526 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 <core/device.h> +#include <core/option.h> +#include <subdev/timer.h> + +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 * |