drm/nouveau/falcon: support for EMEM
authorAlexandre Courbot <acourbot@nvidia.com>
Tue, 14 Feb 2017 06:56:10 +0000 (15:56 +0900)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 7 Mar 2017 07:05:13 +0000 (17:05 +1000)
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 <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
drivers/gpu/drm/nouveau/nvkm/falcon/base.c
drivers/gpu/drm/nouveau/nvkm/falcon/v1.c

index b04d3a0e82e68e4dae8a57b2be7c208cd27dfcfb..9f84ef24a8b3d566f5e359aa786bdba936812022 100644 (file)
@@ -25,6 +25,7 @@ struct nvkm_falcon {
        u8 version;
        u8 secret;
        bool debug;
+       bool has_emem;
 
        struct nvkm_memory *core;
        bool external;
index a4c6ee6ffde65c45ad164fec770c1d82cf837acb..1b7f48efd8b122e0ff5de36a2e815514e7d42a1f 100644 (file)
@@ -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",
index 2a3c8bfb084a95381e9b1d7ce78e93d6c50f3c39..669c2402847090fe3c8c7acf2d638862231fb1d2 100644 (file)
@@ -64,6 +64,33 @@ nvkm_falcon_v1_load_imem(struct nvkm_falcon *falcon, void *data, u32 start,
                nvkm_falcon_wr32(falcon, 0x184 + (port * 16), 0);
 }
 
+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)
@@ -71,6 +98,11 @@ nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start,
        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));
@@ -89,6 +121,33 @@ 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)
@@ -96,6 +155,10 @@ nvkm_falcon_v1_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size,
        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));