/* * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ #ifndef _ZEPHYR_DRIVERS_FIRMWARE_SCMI_MAILBOX_H_ #define _ZEPHYR_DRIVERS_FIRMWARE_SCMI_MAILBOX_H_ #include #include #include #include #include #define DT_DRV_COMPAT arm_scmi /* get a `struct device` for a protocol's shared memory area */ #define _SCMI_MBOX_SHMEM_BY_IDX(node_id, idx) \ COND_CODE_1(DT_PROP_HAS_IDX(node_id, shmem, idx), \ (DEVICE_DT_GET(DT_PROP_BY_IDX(node_id, shmem, idx))), \ (NULL)) /* get the name of mailbox channel's private data */ #define _SCMI_MBOX_CHAN_NAME(proto, idx)\ CONCAT(SCMI_TRANSPORT_CHAN_NAME(proto, idx), _, priv) /* fetch a mailbox channel's doorbell */ #define _SCMI_MBOX_CHAN_DBELL(node_id, name) \ COND_CODE_1(DT_PROP_HAS_NAME(node_id, mboxes, name), \ (MBOX_DT_SPEC_GET(node_id, name)), \ ({ })) /* define private data for a protocol TX channel */ #define _SCMI_MBOX_CHAN_DEFINE_PRIV_TX(node_id, proto) \ static struct scmi_mbox_channel _SCMI_MBOX_CHAN_NAME(proto, 0) =\ { \ .shmem = _SCMI_MBOX_SHMEM_BY_IDX(node_id, 0), \ .tx = _SCMI_MBOX_CHAN_DBELL(node_id, tx), \ .tx_reply = _SCMI_MBOX_CHAN_DBELL(node_id, tx_reply), \ } /* * Define a mailbox channel. This does two things: * 1) Define the mandatory `struct scmi_channel` structure * 2) Define the mailbox-specific private data for said * channel (i.e: a struct scmi_mbox_channel) */ #define _SCMI_MBOX_CHAN_DEFINE(node_id, proto, idx) \ _SCMI_MBOX_CHAN_DEFINE_PRIV_TX(node_id, proto); \ DT_SCMI_TRANSPORT_CHAN_DEFINE(node_id, idx, proto, \ &(_SCMI_MBOX_CHAN_NAME(proto, idx))); \ /* * Optionally define a mailbox channel for a protocol. This is optional * because a protocol might not have a dedicated channel. */ #define _SCMI_MBOX_CHAN_DEFINE_OPTIONAL(node_id, proto, idx) \ COND_CODE_1(DT_PROP_HAS_IDX(node_id, shmem, idx), \ (_SCMI_MBOX_CHAN_DEFINE(node_id, proto, idx)), \ ()) /* define a TX channel for a protocol node. This is preferred over * _SCMI_MBOX_CHAN_DEFINE_OPTIONAL() since support for RX channels * might be added later on. This macro is supposed to also define * the RX channel */ #define SCMI_MBOX_PROTO_CHAN_DEFINE(node_id)\ _SCMI_MBOX_CHAN_DEFINE_OPTIONAL(node_id, DT_REG_ADDR(node_id), 0) /* define and validate base protocol TX channel */ #define DT_INST_SCMI_MBOX_BASE_CHAN_DEFINE(inst) \ BUILD_ASSERT(DT_INST_PROP_LEN(inst, mboxes) != 1 || \ (DT_INST_PROP_HAS_IDX(inst, shmem, 0) && \ DT_INST_PROP_HAS_NAME(inst, mboxes, tx)), \ "bad bidirectional channel description"); \ \ BUILD_ASSERT(DT_INST_PROP_LEN(inst, mboxes) != 2 || \ (DT_INST_PROP_HAS_NAME(inst, mboxes, tx) && \ DT_INST_PROP_HAS_NAME(inst, mboxes, tx_reply)), \ "bad unidirectional channel description"); \ \ BUILD_ASSERT(DT_INST_PROP_LEN(inst, shmem) == 1, \ "bad SHMEM count"); \ \ BUILD_ASSERT(DT_INST_PROP_LEN(inst, mboxes) <= 2, \ "bad mbox count"); \ \ _SCMI_MBOX_CHAN_DEFINE(DT_INST(inst, DT_DRV_COMPAT), SCMI_PROTOCOL_BASE, 0) /* * Define the mailbox-based transport layer. What this does is: * * 1) Goes through all protocol nodes (children of the `scmi` node) * and creates a `struct scmi_channel` and its associated * `struct scmi_mbox_channel` if the protocol has a dedicated channel. * * 2) Creates aforementioned structures for the base protocol * (identified by the `scmi` node) * * 3) "registers" the driver via `DT_INST_SCMI_TRANSPORT_DEFINE()`. */ #define DT_INST_SCMI_MAILBOX_DEFINE(inst, level, prio, api) \ DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, SCMI_MBOX_PROTO_CHAN_DEFINE) \ DT_INST_SCMI_MBOX_BASE_CHAN_DEFINE(inst) \ DT_INST_SCMI_TRANSPORT_DEFINE(inst, NULL, NULL, NULL, level, prio, api) struct scmi_mbox_channel { /* SHMEM area bound to the channel */ const struct device *shmem; /* TX dbell */ struct mbox_dt_spec tx; /* TX reply dbell */ struct mbox_dt_spec tx_reply; }; #endif /* _ZEPHYR_DRIVERS_FIRMWARE_SCMI_MAILBOX_H_ */