diff --git a/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0_defconfig b/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0_defconfig index 1b60b680f7a04..d4cc0e5accab1 100644 --- a/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0_defconfig +++ b/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0_defconfig @@ -15,3 +15,15 @@ CONFIG_UART_CONSOLE=y # Enable MPU CONFIG_ARM_MPU=y + +# Enable TISCI +CONFIG_TISCI=y + +# Enable Power Management +CONFIG_POWER_DOMAIN=y +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y + +# Enable Clock Management +CONFIG_CLOCK_CONTROL=y diff --git a/drivers/firmware/tisci/tisci.c b/drivers/firmware/tisci/tisci.c index ed3f4bb16face..2dd9bc88dce3a 100644 --- a/drivers/firmware/tisci/tisci.c +++ b/drivers/firmware/tisci/tisci.c @@ -4,9 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include -#define DT_DRV_COMPAT ti_k2g_sci +#define DT_DRV_COMPAT ti_k2g_sci +#define DT_SECPROXY_COMPAT ti_secure_proxy #include #include #include "tisci.h" @@ -32,6 +34,9 @@ struct tisci_config { int max_msg_size; int max_rx_timeout_ms; bool is_secure; + int (*send_pre_kernel)(const struct mbox_dt_spec *rx_spec, + const struct mbox_dt_spec *tx_spec, + const struct mbox_msg *tx_msg); }; /** @@ -66,7 +71,9 @@ static struct tisci_xfer *tisci_setup_one_xfer(const struct device *dev, uint16_ { struct tisci_data *data = dev->data; - k_sem_take(&data->data_sem, K_FOREVER); + if (!k_is_pre_kernel()) { + k_sem_take(&data->data_sem, K_FOREVER); + } const struct tisci_config *config = dev->config; struct tisci_xfer *xfer = &data->xfer; @@ -75,7 +82,9 @@ static struct tisci_xfer *tisci_setup_one_xfer(const struct device *dev, uint16_ if (rx_message_size > config->max_msg_size || tx_message_size > config->max_msg_size || (rx_message_size > 0 && rx_message_size < sizeof(*hdr)) || tx_message_size < sizeof(*hdr)) { - k_sem_give(&data->data_sem); + if (!k_is_pre_kernel()) { + k_sem_give(&data->data_sem); + } return NULL; } @@ -104,7 +113,9 @@ static void callback(const struct device *dev, mbox_channel_id_t channel_id, voi { struct rx_msg *msg = user_data; - k_sem_give(msg->response_ready_sem); + if (!k_is_pre_kernel()) { + k_sem_give(msg->response_ready_sem); + } } static bool tisci_is_response_ack(void *r) @@ -123,24 +134,27 @@ static int tisci_get_response(const struct device *dev, struct tisci_xfer *xfer) struct tisci_data *data = dev->data; const struct tisci_config *config = dev->config; struct tisci_msg_hdr *hdr; + int ret = 0; if (!xfer->rx_message.buf) { LOG_ERR("No response buffer provided"); - k_sem_give(&data->data_sem); - return -EINVAL; + ret = -EINVAL; + goto release_sem; } - if (k_sem_take(data->rx_message.response_ready_sem, K_MSEC(config->max_rx_timeout_ms)) != - 0) { - LOG_ERR("Timeout waiting for response"); - k_sem_give(&data->data_sem); - return -ETIMEDOUT; + if (!k_is_pre_kernel()) { + if (k_sem_take(data->rx_message.response_ready_sem, + K_MSEC(config->max_rx_timeout_ms)) != 0) { + LOG_ERR("Timeout waiting for response"); + ret = -ETIMEDOUT; + goto release_sem; + } } if (xfer->rx_message.size > config->max_msg_size) { LOG_ERR("rx_message.size [ %d ] > max_msg_size\n", xfer->rx_message.size); - k_sem_give(&data->data_sem); - return -EINVAL; + ret = -EINVAL; + goto release_sem; } if (config->is_secure) { @@ -151,8 +165,8 @@ static int tisci_get_response(const struct device *dev, struct tisci_xfer *xfer) if (data->rx_message.size < xfer->rx_message.size) { LOG_ERR("rx_message.size [ %zu ] < xfer->rx_message.size [ %zu ]\n", data->rx_message.size, xfer->rx_message.size); - k_sem_give(&data->data_sem); - return -EINVAL; + ret = -EINVAL; + goto release_sem; } if (config->is_secure) { @@ -169,12 +183,15 @@ static int tisci_get_response(const struct device *dev, struct tisci_xfer *xfer) /* Sanity check for message response */ if (hdr->seq != data->seq) { LOG_ERR("HDR seq != data seq [%d != %d]\n", hdr->seq, data->seq); - k_sem_give(&data->data_sem); - return -EINVAL; + ret = -EINVAL; + goto release_sem; } - k_sem_give(&data->data_sem); - return 0; +release_sem: + if (!k_is_pre_kernel()) { + k_sem_give(&data->data_sem); + } + return ret; } static int tisci_do_xfer(const struct device *dev, struct tisci_xfer *xfer) @@ -199,8 +216,8 @@ static int tisci_do_xfer(const struct device *dev, struct tisci_xfer *xfer) if (msg->size + sizeof(struct tisci_secure_msg_hdr) > MAILBOX_MBOX_SIZE) { LOG_ERR("Message too large for secure mailbox (%zu + %zu > %d)\n", msg->size, sizeof(struct tisci_secure_msg_hdr), MAILBOX_MBOX_SIZE); - k_sem_give(&data->data_sem); - return -EMSGSIZE; + ret = -EMSGSIZE; + goto release_sem; } /* Prepare secure header */ @@ -217,31 +234,45 @@ static int tisci_do_xfer(const struct device *dev, struct tisci_xfer *xfer) msg = &secure_msg; } - ret = mbox_send_dt(&config->mbox_tx, msg); + if (k_is_pre_kernel()) { + if (config->send_pre_kernel != NULL) { + ret = config->send_pre_kernel(&config->mbox_rx, &config->mbox_tx, msg); + } else { + LOG_ERR("Cannot transceive messages during pre kernel"); + return -ENOTSUP; + } + } else { + ret = mbox_send_dt(&config->mbox_tx, msg); + } + if (ret < 0) { - LOG_ERR("Could not send on %s path\n", - config->is_secure ? "secure" : "non-secure"); - k_sem_give(&data->data_sem); - return ret; + LOG_ERR("Could not send on %s path\n", config->is_secure ? "secure" : "non-secure"); + goto release_sem; } /* Get response if requested */ if (xfer->rx_message.size) { ret = tisci_get_response(dev, xfer); if (ret) { - return ret; + goto release_sem; } if (!tisci_is_response_ack(xfer->rx_message.buf)) { LOG_ERR("TISCI Response in NACK\n"); - k_sem_give(&data->data_sem); - return -ENODEV; + ret = -ENODEV; + goto release_sem; } } else { /* No response requested, release semaphore */ - k_sem_give(&data->data_sem); + goto release_sem; } return 0; + +release_sem: + if (!k_is_pre_kernel()) { + k_sem_give(&data->data_sem); + } + return ret; } /* Clock Management Functions */ @@ -1632,6 +1663,9 @@ static int tisci_init(const struct device *dev) return 0; } +#define TISCI_USES_SECPROXY(_n) \ + DT_NODE_HAS_COMPAT(DT_INST_PHANDLE(_n, mboxes), DT_SECPROXY_COMPAT) + /* Device Tree Instantiation */ #define TISCI_DEFINE(_n) \ static uint8_t rx_message_buf_##_n[MAILBOX_MBOX_SIZE] = {0}; \ @@ -1653,6 +1687,9 @@ static int tisci_init(const struct device *dev) .max_msg_size = MAILBOX_MBOX_SIZE, \ .max_rx_timeout_ms = 10000, \ .is_secure = DT_INST_PROP_OR(_n, ti_is_secure, false), \ + .send_pre_kernel = COND_CODE_1(TISCI_USES_SECPROXY(_n), \ + (secproxy_mailbox_send_then_poll_rx_dt), \ + (NULL)), \ }; \ DEVICE_DT_INST_DEFINE(_n, tisci_init, NULL, &tisci_data_##_n, &tisci_config_##_n, \ PRE_KERNEL_1, CONFIG_TISCI_INIT_PRIORITY, NULL); diff --git a/drivers/mbox/mbox_ti_secproxy.c b/drivers/mbox/mbox_ti_secproxy.c index 910271123894c..a0b73dd4159e3 100644 --- a/drivers/mbox/mbox_ti_secproxy.c +++ b/drivers/mbox/mbox_ti_secproxy.c @@ -113,24 +113,20 @@ static inline int secproxy_verify_thread(struct secproxy_thread *spt, uint8_t di return 0; } -static void secproxy_mailbox_isr(const struct device *dev, uint32_t channel) +static int secproxy_mailbox_receive(const struct device *dev, uint32_t channel) { struct secproxy_mailbox_data *data = DEV_DATA(dev); struct secproxy_thread spt; uint32_t data_word; mem_addr_t data_reg; - if (!data->channel_enable[channel]) { - return; - } - spt.target_data = SEC_PROXY_THREAD(DEV_TDATA(dev), channel); spt.rt = SEC_PROXY_THREAD(DEV_RT(dev), channel); spt.scfg = SEC_PROXY_THREAD(DEV_SCFG(dev), channel); if (secproxy_verify_thread(&spt, THREAD_IS_RX)) { /* Silent failure */ - return; + return -EIO; } data_reg = spt.target_data + SEC_PROXY_DATA_START_OFFS; @@ -141,12 +137,12 @@ static void secproxy_mailbox_isr(const struct device *dev, uint32_t channel) if (!rx_data || !rx_data->buf) { LOG_ERR("No buffer provided for channel %d", channel); - return; + return -EINVAL; } if (rx_data->size < MAILBOX_MBOX_SIZE) { LOG_ERR("Buffer too small for channel %d", channel); - return; + return -ENOBUFS; } uint8_t *buf = (uint8_t *)rx_data->buf; @@ -182,6 +178,19 @@ static void secproxy_mailbox_isr(const struct device *dev, uint32_t channel) if (data->cb[channel]) { data->cb[channel](dev, channel, data->user_data[channel], NULL); } + + return 0; +} + +static void secproxy_mailbox_isr(const struct device *dev, uint32_t channel) +{ + struct secproxy_mailbox_data *data = DEV_DATA(dev); + + if (!data->channel_enable[channel]) { + return; + } + + (void)secproxy_mailbox_receive(dev, channel); } static int secproxy_mailbox_send(const struct device *dev, uint32_t channel, @@ -352,6 +361,43 @@ static DEVICE_API(mbox, secproxy_mailbox_driver_api) = { .set_enabled = secproxy_mailbox_set_enabled, }; +int secproxy_mailbox_send_then_poll_rx(const struct device *dev, uint32_t rx_channel, + uint32_t tx_channel, const struct mbox_msg *tx_msg) +{ + const struct secproxy_mailbox_config *cfg = DEV_CFG(dev); + mem_addr_t rx_rt = SEC_PROXY_THREAD(DEV_RT(dev), rx_channel); + bool irq_was_enabled = irq_is_enabled(cfg->interrupts[rx_channel]); + int rv; + + if (irq_was_enabled) { + irq_disable(cfg->interrupts[rx_channel]); + } + + rv = secproxy_mailbox_send(dev, tx_channel, tx_msg); + if (rv != 0) { + LOG_ERR("failed to send message on channel %u", tx_channel); + goto exit; + } + + /* blocking call */ + while (!(sys_read32(rx_rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) { + } + + rv = secproxy_mailbox_receive(dev, rx_channel); + if (rv != 0) { + LOG_ERR("failed to receive message on channel %u", tx_channel); + goto exit; + } + + rv = 0; + +exit: + if (irq_was_enabled) { + irq_enable(cfg->interrupts[rx_channel]); + } + return rv; +} + #define SECPROXY_THREAD_ISR(i, idx) \ COND_CODE_1(DT_INST_IRQ_HAS_NAME(idx, DT_CAT(rx_, i)), \ ( \ diff --git a/dts/vendor/ti/am64x_main.dtsi b/dts/vendor/ti/am64x_main.dtsi index 5012227ade82b..b08ed27d91698 100644 --- a/dts/vendor/ti/am64x_main.dtsi +++ b/dts/vendor/ti/am64x_main.dtsi @@ -18,6 +18,11 @@ reg-names = "debug_messages"; reg = <0x44043000 0xfe0>; status = "disabled"; + + k3_clks: clock-controller { + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; }; secure_proxy_main: mailbox0@4d000000 { @@ -118,6 +123,8 @@ main_uart0: uart@2800000 { compatible = "ns16550"; reg = <0x02800000 0x200>; + power-domains = <&uart0_pd>; + clocks = <&k3_clks 146 0>; clock-frequency = ; reg-shift = <2>; status = "disabled"; @@ -126,6 +133,8 @@ main_uart1: uart@2810000 { compatible = "ns16550"; reg = <0x02810000 0x200>; + power-domains = <&uart1_pd>; + clocks = <&k3_clks 152 0>; clock-frequency = ; reg-shift = <2>; status = "disabled"; @@ -134,6 +143,8 @@ main_uart2: uart@2820000 { compatible = "ns16550"; reg = <0x02820000 0x200>; + power-domains = <&uart2_pd>; + clocks = <&k3_clks 153 0>; clock-frequency = ; reg-shift = <2>; status = "disabled"; @@ -142,6 +153,8 @@ main_uart3: uart@2830000 { compatible = "ns16550"; reg = <0x02830000 0x200>; + power-domains = <&uart3_pd>; + clocks = <&k3_clks 154 0>; clock-frequency = ; reg-shift = <2>; status = "disabled"; @@ -150,6 +163,8 @@ main_uart4: uart@2840000 { compatible = "ns16550"; reg = <0x02840000 0x200>; + power-domains = <&uart4_pd>; + clocks = <&k3_clks 155 0>; clock-frequency = ; reg-shift = <2>; status = "disabled"; @@ -158,6 +173,8 @@ main_uart5: uart@2850000 { compatible = "ns16550"; reg = <0x02850000 0x200>; + power-domains = <&uart5_pd>; + clocks = <&k3_clks 156 0>; clock-frequency = ; reg-shift = <2>; status = "disabled"; @@ -166,6 +183,8 @@ main_uart6: uart@2860000 { compatible = "ns16550"; reg = <0x02860000 0x200>; + power-domains = <&uart6_pd>; + clocks = <&k3_clks 158 0>; clock-frequency = ; reg-shift = <2>; status = "disabled"; @@ -174,6 +193,8 @@ main_i2c0: i2c0@20000000 { compatible = "ti,omap-i2c"; reg = <0x20000000 0x100>; + power-domains = <&i2c0_pd>; + clocks = <&k3_clks 102 0>; clock-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -183,6 +204,8 @@ main_i2c1: i2c0@20010000 { compatible = "ti,omap-i2c"; reg = <0x20010000 0x100>; + power-domains = <&i2c1_pd>; + clocks = <&k3_clks 103 0>; clock-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -192,6 +215,8 @@ main_i2c2: i2c0@20020000 { compatible = "ti,omap-i2c"; reg = <0x20020000 0x100>; + power-domains = <&i2c2_pd>; + clocks = <&k3_clks 104 0>; clock-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -201,6 +226,8 @@ main_i2c3: i2c0@20030000 { compatible = "ti,omap-i2c"; reg = <0x20030000 0x100>; + power-domains = <&i2c3_pd>; + clocks = <&k3_clks 105 0>; clock-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -356,6 +383,8 @@ main_mcspi0: spi@20100000 { compatible = "ti,omap-mcspi"; reg = <0x20100000 0x400>; + power-domains = <&mcspi0_pd>; + clocks = <&k3_clks 141 0>; clock-frequency = ; ti,spi-num-cs = <4>; #address-cells = <1>; @@ -366,6 +395,8 @@ main_mcspi1: spi@20110000 { compatible = "ti,omap-mcspi"; reg = <0x20110000 0x400>; + power-domains = <&mcspi1_pd>; + clocks = <&k3_clks 142 0>; clock-frequency = ; ti,spi-num-cs = <4>; #address-cells = <1>; @@ -376,6 +407,8 @@ main_mcspi2: spi@20120000 { compatible = "ti,omap-mcspi"; reg = <0x20120000 0x400>; + power-domains = <&mcspi2_pd>; + clocks = <&k3_clks 143 0>; clock-frequency = ; ti,spi-num-cs = <4>; #address-cells = <1>; @@ -386,6 +419,8 @@ main_mcspi3: spi@20130000 { compatible = "ti,omap-mcspi"; reg = <0x20130000 0x400>; + power-domains = <&mcspi3_pd>; + clocks = <&k3_clks 144 0>; clock-frequency = ; ti,spi-num-cs = <4>; #address-cells = <1>; @@ -396,6 +431,8 @@ main_mcspi4: spi@20140000 { compatible = "ti,omap-mcspi"; reg = <0x20140000 0x400>; + power-domains = <&mcspi4_pd>; + clocks = <&k3_clks 145 0>; clock-frequency = ; ti,spi-num-cs = <4>; #address-cells = <1>; @@ -406,6 +443,7 @@ main_adc0: adc@28001000 { compatible = "ti,am335x-adc"; reg = <0x28001000 DT_SIZE_K(1)>; + power-domains = <&adc0_pd>; status = "disabled"; #io-channel-cells = <1>; #address-cells = <1>; diff --git a/dts/vendor/ti/am64x_mcu.dtsi b/dts/vendor/ti/am64x_mcu.dtsi index 72f927f00d676..d2eb6d1715b11 100644 --- a/dts/vendor/ti/am64x_mcu.dtsi +++ b/dts/vendor/ti/am64x_mcu.dtsi @@ -29,6 +29,8 @@ mcu_uart0: serial@4a00000 { compatible = "ns16550"; reg = <0x04a00000 0x200>; + power-domains = <&mcu_uart0_pd>; + clocks = <&k3_clks 149 0>; clock-frequency = ; current-speed = <115200>; reg-shift = <2>; @@ -38,6 +40,8 @@ mcu_uart1: serial@4a10000 { compatible = "ns16550"; reg = <0x04a10000 0x200>; + power-domains = <&mcu_uart1_pd>; + clocks = <&k3_clks 160 0>; clock-frequency = ; current-speed = <115200>; reg-shift = <2>; @@ -47,6 +51,8 @@ mcu_i2c0: i2c0@4900000 { compatible = "ti,omap-i2c"; reg = <0x4900000 0x100>; + power-domains = <&mcu_i2c0_pd>; + clocks = <&k3_clks 106 0>; clock-frequency = ; #address-cells = <1>; #size-cells = <0>; @@ -55,6 +61,8 @@ mcu_i2c1: i2c0@4910000 { compatible = "ti,omap-i2c"; + power-domains = <&mcu_i2c1_pd>; + clocks = <&k3_clks 107 0>; reg = <0x4910000 0x100>; clock-frequency = ; #address-cells = <1>; @@ -74,6 +82,8 @@ mcu_mcspi0: spi@4b00000 { compatible = "ti,omap-mcspi"; reg = <0x4b00000 0x400>; + power-domains = <&mcu_mcspi0_pd>; + clocks = <&k3_clks 147 0>; clock-frequency = ; ti,spi-num-cs = <4>; #address-cells = <1>; @@ -84,6 +94,8 @@ mcu_mcspi1: spi@4b10000 { compatible = "ti,omap-mcspi"; reg = <0x4b10000 0x400>; + power-domains = <&mcu_mcspi1_pd>; + clocks = <&k3_clks 148 0>; clock-frequency = ; ti,spi-num-cs = <4>; #address-cells = <1>; diff --git a/include/zephyr/drivers/mbox/mbox_ti_secproxy.h b/include/zephyr/drivers/mbox/mbox_ti_secproxy.h new file mode 100644 index 0000000000000..8f2f63839169f --- /dev/null +++ b/include/zephyr/drivers/mbox/mbox_ti_secproxy.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2026, Texas Instruments + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for the TI Secproxy Mailbox + * @ingroup ti_secproxy_interface + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_MBOX_TI_SECPROXY_H_ +#define INCLUDE_ZEPHYR_DRIVERS_MBOX_TI_SECPROXY_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief TI Secure Proxy APIs + * @defgroup ti_secproxy_interface TI Secure Proxy Interface + * @since 4.4.0 + * @version 0.1.0 + * @ingroup mbox_interface + * @{ + */ + +/** + * @brief Send a message over secure proxy then poll for the reply + * + * Combine sending and receiving messages over specified channels by polling. This routine disables + * the interrupt associated with the RX channel during its duration and is only meant to be used + * during pre kernel stages where kernel services are not available. The RX buffer for the channel + * should be set up using mbox_register_callback() before calling this API. Since this is a polling + * API, it also blocks the thread. + * + * @param dev: Secure Proxy mailbox device + * @param rx_channel: Channel ID to receive reply on via polling after sending the message + * @param tx_channel: Channel ID to send message on + * @param tx_msg: TX Message struct + * + * @retval 0 On success. + * @retval -EBUSY If the remote hasn't yet read the last data sent. + * @retval -EMSGSIZE If the supplied data size is unsupported by the driver. + * @retval -EIO If there is an issue with RX thread like being in an error state + * @retval -ENOBUFS If the RX buffer is too small for receiving a message + * @retval -EINVAL If there was a bad parameter, such as: too-large channel + * descriptor or the device isn't an outbound MBOX channel. + * @see mbox_register_callback() + * + */ +int secproxy_mailbox_send_then_poll_rx(const struct device *dev, uint32_t rx_channel, + uint32_t tx_channel, const struct mbox_msg *tx_msg); + +/** + * @brief Send a message over secure proxy then poll for the reply, using DT specs + * + * @param rx_spec: MBOX DT spec to receive reply on via polling after sending the message + * @param tx_spec: MBOX DT spec to send message on + * @param tx_msg: TX Message struct + * + * @return See return values for secproxy_mailbox_send_then_poll_rx() + */ +int secproxy_mailbox_send_then_poll_rx_dt(const struct mbox_dt_spec *rx_spec, + const struct mbox_dt_spec *tx_spec, + const struct mbox_msg *tx_msg) +{ + if (rx_spec->dev != tx_spec->dev) { + return -EINVAL; + } + + return secproxy_mailbox_send_then_poll_rx(tx_spec->dev, rx_spec->channel_id, + tx_spec->channel_id, tx_msg); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDE_ZEPHYR_DRIVERS_MBOX_TI_SECPROXY_H_ */