#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)
 enum {
        ACR_CMD_INIT_WPR_REGION = 0x00,
        ACR_CMD_BOOTSTRAP_FALCON = 0x01,
+       ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS = 0x03,
 };
 
 static void
        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)
 {
 
        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;
+}