summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/falcon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/falcon')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c112
3 files changed, 117 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
index f7101a910bc7..d45d7947a964 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
@@ -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;
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
index 2b3a6c3b8f6a..13b54f8d8e04 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
@@ -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 **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c
index 935b9a7e60a9..fec0273158f6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c
@@ -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;
+}
OpenPOWER on IntegriCloud