From 6ac2cc209e0096dabc8e902a8620d45f41b9fc0b Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 14 Feb 2017 15:56:10 +0900 Subject: [PATCH] drm/nouveau/falcon: support for EMEM On SEC, DMEM is unaccessible by the CPU when the falcon is running in LS mode. This makes communication with the firmware using DMEM impossible. For this purpose, a new kind of memory (EMEM) has been added. It works similarly to DMEM, with the difference that its address space starts at 0x1000000. For this reason, it makes sense to treat it like a special case of DMEM. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/falcon.h | 1 + drivers/gpu/drm/nouveau/nvkm/falcon/base.c | 1 + drivers/gpu/drm/nouveau/nvkm/falcon/v1.c | 63 ++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index b04d3a0..9f84ef2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -25,6 +25,7 @@ struct nvkm_falcon { u8 version; u8 secret; bool debug; + bool has_emem; struct nvkm_memory *core; bool external; diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c index a4c6ee6..1b7f48e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c @@ -202,6 +202,7 @@ nvkm_falcon_ctor(const struct nvkm_falcon_func *func, break; case NVKM_ENGINE_SEC2: debug_reg = 0x408; + falcon->has_emem = true; break; default: nvkm_warn(subdev, "unsupported falcon %s!\n", diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c index 2a3c8bfb..669c2402 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c @@ -65,12 +65,44 @@ nvkm_falcon_v1_load_imem(struct nvkm_falcon *falcon, void *data, u32 start, } static void +nvkm_falcon_v1_load_emem(struct nvkm_falcon *falcon, void *data, u32 start, + u32 size, u8 port) +{ + u8 rem = size % 4; + int i; + + size -= rem; + + nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), start | (0x1 << 24)); + for (i = 0; i < size / 4; i++) + nvkm_falcon_wr32(falcon, 0xac4 + (port * 8), ((u32 *)data)[i]); + + /* + * If size is not a multiple of 4, mask the last word to ensure garbage + * does not get written + */ + if (rem) { + u32 extra = ((u32 *)data)[i]; + + nvkm_falcon_wr32(falcon, 0xac4 + (port * 8), + extra & (BIT(rem * 8) - 1)); + } +} + +static const u32 EMEM_START_ADDR = 0x1000000; + +static void nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, u32 size, u8 port) { u8 rem = size % 4; int i; + if (start >= EMEM_START_ADDR && falcon->has_emem) + return nvkm_falcon_v1_load_emem(falcon, data, + start - EMEM_START_ADDR, size, + port); + size -= rem; nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), start | (0x1 << 24)); @@ -90,12 +122,43 @@ nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, } static void +nvkm_falcon_v1_read_emem(struct nvkm_falcon *falcon, u32 start, u32 size, + u8 port, void *data) +{ + u8 rem = size % 4; + int i; + + size -= rem; + + nvkm_falcon_wr32(falcon, 0xac0 + (port * 8), start | (0x1 << 25)); + for (i = 0; i < size / 4; i++) + ((u32 *)data)[i] = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8)); + + /* + * If size is not a multiple of 4, mask the last word to ensure garbage + * does not get read + */ + if (rem) { + u32 extra = nvkm_falcon_rd32(falcon, 0xac4 + (port * 8)); + + for (i = size; i < size + rem; i++) { + ((u8 *)data)[i] = (u8)(extra & 0xff); + extra >>= 8; + } + } +} + +static void nvkm_falcon_v1_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size, u8 port, void *data) { u8 rem = size % 4; int i; + if (start >= EMEM_START_ADDR && falcon->has_emem) + return nvkm_falcon_v1_read_emem(falcon, start - EMEM_START_ADDR, + size, port, data); + size -= rem; nvkm_falcon_wr32(falcon, 0x1c0 + (port * 8), start | (0x1 << 25)); -- 2.7.4