]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/nouveau/msgqueue: support for GP10B PMU firmware
authorAlexandre Courbot <acourbot@nvidia.com>
Wed, 29 Mar 2017 09:31:15 +0000 (18:31 +0900)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 6 Apr 2017 04:39:04 +0000 (14:39 +1000)
The GP10B firmware is very close to GM20B's. The only difference is that
it supports booting multiple falcons. In order to avoid having too much
functions and structures shared, implement its support in the same
source file as GM20B firmware.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c

index f7101a910bc78fedde7bbbc82f2a0d6736fc2d63..d45d7947a964a3399d983b234c685a8c335f63f1 100644 (file)
@@ -501,6 +501,9 @@ nvkm_msgqueue_new(u32 version, struct nvkm_falcon *falcon,
        case 0x0137c63d:
                ret = msgqueue_0137c63d_new(falcon, sb, queue);
                break;
+       case 0x0137bca5:
+               ret = msgqueue_0137bca5_new(falcon, sb, queue);
+               break;
        case 0x0148cdec:
                ret = msgqueue_0148cdec_new(falcon, sb, queue);
                break;
index 2b3a6c3b8f6ae044a85814a1c4aa0425b9ed64f7..13b54f8d8e049e5edfd052519306f3a17cc2d32a 100644 (file)
@@ -205,6 +205,8 @@ void nvkm_msgqueue_process_msgs(struct nvkm_msgqueue *,
 
 int msgqueue_0137c63d_new(struct nvkm_falcon *, const struct nvkm_secboot *,
                          struct nvkm_msgqueue **);
+int msgqueue_0137bca5_new(struct nvkm_falcon *, const struct nvkm_secboot *,
+                         struct nvkm_msgqueue **);
 int msgqueue_0148cdec_new(struct nvkm_falcon *, const struct nvkm_secboot *,
                          struct nvkm_msgqueue **);
 
index 935b9a7e60a9ec5ed2af498ae1beb21fbf553f49..fec0273158f6a7f99499c09a7073ec450e019ee3 100644 (file)
@@ -43,6 +43,15 @@ struct msgqueue_0137c63d {
 #define msgqueue_0137c63d(q) \
        container_of(q, struct msgqueue_0137c63d, base)
 
+struct msgqueue_0137bca5 {
+       struct msgqueue_0137c63d base;
+
+       u64 wpr_addr;
+};
+#define msgqueue_0137bca5(q) \
+       container_of(container_of(q, struct msgqueue_0137c63d, base), \
+                    struct msgqueue_0137bca5, base);
+
 static struct nvkm_msgqueue_queue *
 msgqueue_0137c63d_cmd_queue(struct nvkm_msgqueue *queue,
                            enum msgqueue_msg_priority priority)
@@ -180,6 +189,7 @@ msgqueue_0137c63d_init_func = {
 enum {
        ACR_CMD_INIT_WPR_REGION = 0x00,
        ACR_CMD_BOOTSTRAP_FALCON = 0x01,
+       ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS = 0x03,
 };
 
 static void
@@ -286,11 +296,81 @@ acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon)
        return 0;
 }
 
+static void
+acr_boot_multiple_falcons_callback(struct nvkm_msgqueue *priv,
+                                  struct nvkm_msgqueue_hdr *hdr)
+{
+       struct acr_bootstrap_falcon_msg {
+               struct nvkm_msgqueue_msg base;
+
+               u32 falcon_mask;
+       } *msg = (void *)hdr;
+       const struct nvkm_subdev *subdev = priv->falcon->owner;
+       unsigned long falcon_mask = msg->falcon_mask;
+       u32 falcon_id, falcon_treated = 0;
+
+       for_each_set_bit(falcon_id, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
+               nvkm_debug(subdev, "%s booted\n",
+                          nvkm_secboot_falcon_name[falcon_id]);
+               falcon_treated |= BIT(falcon_id);
+       }
+
+       if (falcon_treated != msg->falcon_mask) {
+               nvkm_error(subdev, "in bootstrap falcon callback:\n");
+               nvkm_error(subdev, "invalid falcon mask 0x%x\n",
+                          msg->falcon_mask);
+               return;
+       }
+}
+
+static int
+acr_boot_multiple_falcons(struct nvkm_msgqueue *priv, unsigned long falcon_mask)
+{
+       DECLARE_COMPLETION_ONSTACK(completed);
+       /*
+        * flags      - Flag specifying RESET or no RESET.
+        * falcon id  - Falcon id specifying falcon to bootstrap.
+        */
+       struct {
+               struct nvkm_msgqueue_hdr hdr;
+               u8 cmd_type;
+               u32 flags;
+               u32 falcon_mask;
+               u32 use_va_mask;
+               u32 wpr_lo;
+               u32 wpr_hi;
+       } cmd;
+       struct msgqueue_0137bca5 *queue = msgqueue_0137bca5(priv);
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR;
+       cmd.hdr.size = sizeof(cmd);
+       cmd.cmd_type = ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS;
+       cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
+       cmd.falcon_mask = falcon_mask;
+       cmd.wpr_lo = lower_32_bits(queue->wpr_addr);
+       cmd.wpr_hi = upper_32_bits(queue->wpr_addr);
+       nvkm_msgqueue_post(priv, MSGQUEUE_MSG_PRIORITY_HIGH, &cmd.hdr,
+                       acr_boot_multiple_falcons_callback, &completed, true);
+
+       if (!wait_for_completion_timeout(&completed, msecs_to_jiffies(1000)))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 static const struct nvkm_msgqueue_acr_func
 msgqueue_0137c63d_acr_func = {
        .boot_falcon = acr_boot_falcon,
 };
 
+static const struct nvkm_msgqueue_acr_func
+msgqueue_0137bca5_acr_func = {
+       .boot_falcon = acr_boot_falcon,
+       .boot_multiple_falcons = acr_boot_multiple_falcons,
+};
+
 static void
 msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue)
 {
@@ -322,3 +402,35 @@ msgqueue_0137c63d_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb,
 
        return 0;
 }
+
+static const struct nvkm_msgqueue_func
+msgqueue_0137bca5_func = {
+       .init_func = &msgqueue_0137c63d_init_func,
+       .acr_func = &msgqueue_0137bca5_acr_func,
+       .cmd_queue = msgqueue_0137c63d_cmd_queue,
+       .recv = msgqueue_0137c63d_process_msgs,
+       .dtor = msgqueue_0137c63d_dtor,
+};
+
+int
+msgqueue_0137bca5_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb,
+                     struct nvkm_msgqueue **queue)
+{
+       struct msgqueue_0137bca5 *ret;
+
+       ret = kzalloc(sizeof(*ret), GFP_KERNEL);
+       if (!ret)
+               return -ENOMEM;
+
+       *queue = &ret->base.base;
+
+       /*
+        * FIXME this must be set to the address of a *GPU* mapping within the
+        * ACR address space!
+        */
+       /* ret->wpr_addr = sb->wpr_addr; */
+
+       nvkm_msgqueue_ctor(&msgqueue_0137bca5_func, falcon, &ret->base.base);
+
+       return 0;
+}