diff options
author | Alexandre Courbot <acourbot@nvidia.com> | 2017-02-16 15:13:49 +0900 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2017-03-07 17:05:15 +1000 |
commit | ec91cb028511d68193c792f27a1bcd8d3e756280 (patch) | |
tree | c000e1730828c51c3180c6a4b5bed8a19197d1b3 /drivers/gpu/drm | |
parent | c5e1fef4875b75df48a7e9828243062799e444dc (diff) | |
download | linux-ec91cb028511d68193c792f27a1bcd8d3e756280.tar.bz2 |
drm/nouveau/secboot: workaround bug when starting SEC2 firmware
For some unknown reason the LS SEC2 firmware needs to be started twice
to operate. Detect and address that condition.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c index b4e0add13a33..72ca537b0b59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c @@ -26,6 +26,7 @@ #include <core/firmware.h> #include <engine/falcon.h> #include <subdev/mc.h> +#include <subdev/timer.h> #include <subdev/pmu.h> #include <core/msgqueue.h> #include <engine/sec2.h> @@ -977,6 +978,7 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb) { const struct nvkm_subdev *subdev = &sb->subdev; unsigned long managed_falcons = acr->base.managed_falcons; + u32 reg; int falcon_id; int ret; @@ -1025,6 +1027,37 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb) /* Start LS firmware on boot falcon */ nvkm_falcon_start(sb->boot_falcon); + + /* + * There is a bug where the LS firmware sometimes require to be started + * twice (this happens only on SEC). Detect and workaround that + * condition. + * + * Once started, the falcon will end up in STOPPED condition (bit 5) + * if successful, or in HALT condition (bit 4) if not. + */ + nvkm_msec(subdev->device, 1, + if ((reg = nvkm_rd32(subdev->device, + sb->boot_falcon->addr + 0x100) + & 0x30) != 0) + break; + ); + if (reg & BIT(4)) { + nvkm_debug(subdev, "applying workaround for start bug..."); + nvkm_falcon_start(sb->boot_falcon); + nvkm_msec(subdev->device, 1, + if ((reg = nvkm_rd32(subdev->device, + sb->boot_falcon->addr + 0x100) + & 0x30) != 0) + break; + ); + if (reg & BIT(4)) { + nvkm_error(subdev, "%s failed to start\n", + nvkm_secboot_falcon_name[acr->base.boot_falcon]); + return -EINVAL; + } + } + nvkm_debug(subdev, "%s started\n", nvkm_secboot_falcon_name[acr->base.boot_falcon]); |