diff --git a/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0.dts b/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0.dts index b498b214c257b..12c78669a9ff0 100644 --- a/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0.dts +++ b/boards/ti/am243x_evm/am243x_evm_am2434_r5f0_0.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include +#include #include "am243x_evm_am2434_r5f0_0-pinctrl.dtsi" / { @@ -85,22 +85,16 @@ &main_i2c0 { pinctrl-0 = <&main_i2c0_scl &main_i2c0_sda>; pinctrl-names = "default"; - status = "okay"; - power-domains = <&i2c0_pd>; }; &main_mcspi0 { pinctrl-0 = <&spi0_clk &spi0_cs0 &spi0_d0 &spi0_d1>; pinctrl-names = "default"; - status = "okay"; - power-domains = <&mcspi0_pd>; }; &main_adc0 { ti,vrefp = <1800>; ti,fifo = <0>; - status = "okay"; - power-domains = <&adc0_pd>; channel@0 { reg = <0>; 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 0206289bcbed4..770bf9d66ecdb 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" @@ -15,8 +17,13 @@ #include #define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL #include + LOG_MODULE_REGISTER(ti_k2g_sci); +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "There can only be one DMSC instance"); + +#define DMSC_USES_SECPROXY (DT_NODE_HAS_COMPAT(DT_INST_PHANDLE(0, mboxes), DT_SECPROXY_COMPAT)) + /** * @struct tisci_config - TISCI device configuration structure * @mbox_tx: Mailbox transmit channel specification. @@ -65,7 +72,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; @@ -102,7 +111,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) @@ -127,10 +138,12 @@ static int tisci_get_response(const struct device *dev, struct tisci_xfer *xfer) return -EINVAL; } - if (k_sem_take(data->rx_message.response_ready_sem, K_MSEC(config->max_rx_timeout_ms)) != - 0) { - LOG_ERR("Timeout waiting for response"); - 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"); + return -ETIMEDOUT; + } } if (xfer->rx_message.size > config->max_msg_size) { @@ -152,7 +165,9 @@ static int tisci_get_response(const struct device *dev, struct tisci_xfer *xfer) return -EINVAL; } - k_sem_give(&data->data_sem); + if (!k_is_pre_kernel()) { + k_sem_give(&data->data_sem); + } return 0; } @@ -166,7 +181,18 @@ static int tisci_do_xfer(const struct device *dev, struct tisci_xfer *xfer) struct mbox_msg *msg = &xfer->tx_message; int ret; - ret = mbox_send_dt(&config->mbox_tx, msg); + if (k_is_pre_kernel()) { +#if DMSC_USES_SECPROXY + ret = secproxy_mailbox_send_then_poll_rx_dt(&config->mbox_rx, &config->mbox_tx, + msg); +#else + LOG_ERR("Cannot transceive messages during pre kernel\n"); + return -ENOTSUP; +#endif + } else { + ret = mbox_send_dt(&config->mbox_tx, msg); + } + if (ret < 0) { LOG_ERR("Could not send (%d)\n", ret); return ret; @@ -1576,27 +1602,24 @@ static int tisci_init(const struct device *dev) } /* Device Tree Instantiation */ -#define TISCI_DEFINE(_n) \ - static uint8_t rx_message_buf_##_n[MAILBOX_MBOX_SIZE] = {0}; \ - static struct k_sem response_ready_sem_##_n; \ - static struct tisci_data tisci_data_##_n = { \ - .seq = 0, \ - .rx_message = \ - { \ - .buf = rx_message_buf_##_n, \ - .size = sizeof(rx_message_buf_##_n), \ - .response_ready_sem = &response_ready_sem_##_n, \ - }, \ - .data_sem = Z_SEM_INITIALIZER(tisci_data_##_n.data_sem, 1, 1), \ - }; \ - static const struct tisci_config tisci_config_##_n = { \ - .mbox_tx = MBOX_DT_SPEC_INST_GET(_n, tx), \ - .mbox_rx = MBOX_DT_SPEC_INST_GET(_n, rx), \ - .host_id = DT_INST_PROP(_n, ti_host_id), \ - .max_msg_size = MAILBOX_MBOX_SIZE, \ - .max_rx_timeout_ms = 10000, \ - }; \ - DEVICE_DT_INST_DEFINE(_n, tisci_init, NULL, &tisci_data_##_n, &tisci_config_##_n, \ - PRE_KERNEL_1, CONFIG_TISCI_INIT_PRIORITY, NULL); - -DT_INST_FOREACH_STATUS_OKAY(TISCI_DEFINE) +static uint8_t rx_message_buf[MAILBOX_MBOX_SIZE] = {0}; +static struct k_sem response_ready_sem; +static struct tisci_data tisci_data = { + .seq = 0, + .rx_message = { + .buf = rx_message_buf, + .size = sizeof(rx_message_buf), + .response_ready_sem = &response_ready_sem, + }, + .data_sem = Z_SEM_INITIALIZER(tisci_data.data_sem, 1, 1), +}; +static const struct tisci_config tisci_config = { + .mbox_tx = MBOX_DT_SPEC_INST_GET(0, tx), + .mbox_rx = MBOX_DT_SPEC_INST_GET(0, rx), + .host_id = DT_INST_PROP(0, ti_host_id), + .max_msg_size = MAILBOX_MBOX_SIZE, + .max_rx_timeout_ms = 10000, +}; + +DEVICE_DT_INST_DEFINE(0, tisci_init, NULL, &tisci_data, &tisci_config, 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 01c2478659d6e..0ed07b2db548a 100644 --- a/drivers/mbox/mbox_ti_secproxy.c +++ b/drivers/mbox/mbox_ti_secproxy.c @@ -1,6 +1,8 @@ /* * Copyright (c) 2025 Texas Instruments Incorporated. * + * SPDX-License-Identifier: Apache-2.0 + * * TI Secureproxy Mailbox driver for Zephyr's MBOX model. */ @@ -38,15 +40,12 @@ LOG_MODULE_REGISTER(ti_secure_proxy); #define THREAD_IS_RX 1 #define THREAD_IS_TX 0 -#define SECPROXY_MAILBOX_NUM_MSGS 5 -#define MAILBOX_MAX_CHANNELS 32 -#define MAILBOX_MBOX_SIZE 60 +#define MAILBOX_MAX_CHANNELS 32 +#define MAILBOX_MBOX_SIZE 60 #define SEC_PROXY_DATA_START_OFFS 0x4 #define SEC_PROXY_DATA_END_OFFS 0x3c -#define SEC_PROXY_TIMEOUT_US 1000000 - #define GET_MSG_SEQ(buffer) ((uint32_t *)buffer)[1] struct secproxy_thread { mem_addr_t target_data; @@ -82,13 +81,15 @@ struct secproxy_mailbox_config { DEVICE_MMIO_NAMED_ROM(target_data); DEVICE_MMIO_NAMED_ROM(rt); DEVICE_MMIO_NAMED_ROM(scfg); - uint32_t irq; + uint32_t interrupts[MAILBOX_MAX_CHANNELS]; }; static inline int secproxy_verify_thread(struct secproxy_thread *spt, uint8_t dir) { /* Check for any errors already available */ - if (sys_read32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_ERROR_MASK) { + uint32_t status = sys_read32(spt->rt + RT_THREAD_STATUS); + + if (status & RT_THREAD_STATUS_ERROR_MASK) { LOG_ERR("Thread is corrupted, cannot send data.\n"); return -EINVAL; } @@ -104,106 +105,95 @@ static inline int secproxy_verify_thread(struct secproxy_thread *spt, uint8_t di return -EINVAL; } - /* Check the message queue before sending/receiving data */ - int timeout_ms = SEC_PROXY_TIMEOUT_US; - int waited_ms = 0; - const int poll_interval_ms = 1000; - - while (!(sys_read32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) { - k_busy_wait(poll_interval_ms); - waited_ms += poll_interval_ms; - if (waited_ms >= timeout_ms) { - LOG_ERR("Timeout waiting for thread to %s\n", - (dir == THREAD_IS_TX) ? "empty" : "fill"); - return -ETIMEDOUT; + if ((status & RT_THREAD_STATUS_CUR_CNT_MASK) == 0) { + if (dir == THREAD_IS_TX) { + return -EBUSY; + } else { + return -ENODATA; } } return 0; } -static void secproxy_mailbox_isr(const struct device *dev) +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; - for (int i_channel = 0; i_channel < MAILBOX_MAX_CHANNELS; i_channel++) { - if (!data->channel_enable[i_channel]) { - continue; - } + 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); - spt.target_data = SEC_PROXY_THREAD(DEV_TDATA(dev), i_channel); - spt.rt = SEC_PROXY_THREAD(DEV_RT(dev), i_channel); - spt.scfg = SEC_PROXY_THREAD(DEV_SCFG(dev), i_channel); + if (secproxy_verify_thread(&spt, THREAD_IS_RX)) { + /* Silent failure */ + return -EIO; + } - uint32_t status = sys_read32(spt.rt + RT_THREAD_STATUS); + data_reg = spt.target_data + SEC_PROXY_DATA_START_OFFS; + size_t msg_len = MAILBOX_MBOX_SIZE; + size_t num_words = msg_len / sizeof(uint32_t); + size_t i; + struct rx_msg *rx_data = data->user_data[channel]; - if (status & RT_THREAD_STATUS_ERROR_MASK) { - LOG_ERR("Thread %d error state detected in ISR", i_channel); - continue; - } + if (!rx_data || !rx_data->buf) { + LOG_ERR("No buffer provided for channel %d", channel); + return -EINVAL; + } - if (secproxy_verify_thread(&spt, THREAD_IS_RX)) { - LOG_ERR("Thread %d is in error state\n", i_channel); - continue; - } + if (rx_data->size < MAILBOX_MBOX_SIZE) { + LOG_ERR("Buffer too small for channel %d", channel); + return -ENOBUFS; + } - if (!(sys_read32(spt.rt) & 0x7F)) { - continue; - } + uint8_t *buf = (uint8_t *)rx_data->buf; - data_reg = spt.target_data + SEC_PROXY_DATA_START_OFFS; - size_t msg_len = MAILBOX_MBOX_SIZE; - size_t num_words = msg_len / sizeof(uint32_t); - size_t i; - struct rx_msg *rx_data = data->user_data[i_channel]; + /* Copy full words */ + for (i = 0; i < num_words; i++) { + data_word = sys_read32(data_reg); + memcpy(&buf[i * 4], &data_word, sizeof(uint32_t)); + data_reg += sizeof(uint32_t); + } - if (!rx_data || !rx_data->buf) { - LOG_ERR("No buffer provided for channel %d", i_channel); - continue; - } + /* Handle trail bytes */ + size_t trail_bytes = msg_len % sizeof(uint32_t); - if (rx_data->size < MAILBOX_MBOX_SIZE) { - LOG_ERR("Buffer too small for channel %d", i_channel); - continue; - } + if (trail_bytes) { + uint32_t data_trail = sys_read32(data_reg); - uint8_t *buf = (uint8_t *)rx_data->buf; + i = msg_len - trail_bytes; - /* Copy full words */ - for (i = 0; i < num_words; i++) { - data_word = sys_read32(data_reg); - memcpy(&buf[i * 4], &data_word, sizeof(uint32_t)); - data_reg += sizeof(uint32_t); + while (trail_bytes--) { + buf[i++] = data_trail & 0xff; + data_trail >>= 8; } + } - /* Handle trail bytes */ - size_t trail_bytes = msg_len % sizeof(uint32_t); - - if (trail_bytes) { - uint32_t data_trail = sys_read32(data_reg); + /* Ensure we read the last register if we haven't already */ + if (data_reg <= (spt.target_data + SEC_PROXY_DATA_END_OFFS)) { + sys_read32(spt.target_data + SEC_PROXY_DATA_END_OFFS); + } - i = msg_len - trail_bytes; + rx_data->size = msg_len; + rx_data->seq = GET_MSG_SEQ(buf); + if (data->cb[channel]) { + data->cb[channel](dev, channel, data->user_data[channel], NULL); + } - while (trail_bytes--) { - buf[i++] = data_trail & 0xff; - data_trail >>= 8; - } - } + return 0; +} - /* Ensure we read the last register if we haven't already */ - if (data_reg <= (spt.target_data + SEC_PROXY_DATA_END_OFFS)) { - sys_read32(spt.target_data + SEC_PROXY_DATA_END_OFFS); - } +static void secproxy_mailbox_isr(const struct device *dev, uint32_t channel) +{ + struct secproxy_mailbox_data *data = DEV_DATA(dev); - rx_data->size = msg_len; - rx_data->seq = GET_MSG_SEQ(buf); - if (data->cb[i_channel]) { - data->cb[i_channel](dev, i_channel, data->user_data[i_channel], NULL); - } + if (!data->channel_enable[channel]) { + return; } + + (void)secproxy_mailbox_receive(dev, channel); } static int secproxy_mailbox_send(const struct device *dev, uint32_t channel, @@ -235,14 +225,6 @@ static int secproxy_mailbox_send(const struct device *dev, uint32_t channel, spt.scfg = SEC_PROXY_THREAD(DEV_SCFG(dev), channel); if (secproxy_verify_thread(&spt, THREAD_IS_TX)) { - LOG_ERR("Thread is in error state\n"); - k_spin_unlock(&data->lock, key); - return -EBUSY; - } - - uint32_t status = sys_read32(spt.rt + RT_THREAD_STATUS); - - if ((status & RT_THREAD_STATUS_CUR_CNT_MASK) == (SECPROXY_MAILBOX_NUM_MSGS)) { k_spin_unlock(&data->lock, key); return -EBUSY; } @@ -323,10 +305,25 @@ static uint32_t secproxy_mailbox_max_channels_get(const struct device *dev) return MAILBOX_MAX_CHANNELS; } +static void secproxy_mailbox_flush_thread(const struct device *dev, uint32_t channel) +{ + struct secproxy_thread spt; + + 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); + + /* Drain all pending messages from the thread. Blocking call */ + while ((sys_read32(spt.rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) > 0) { + /* Read from the last data register to consume one message */ + (void)sys_read32(spt.target_data + SEC_PROXY_DATA_END_OFFS); + } +} + static int secproxy_mailbox_set_enabled(const struct device *dev, uint32_t channel, bool enable) { - const struct secproxy_mailbox_config *cfg = DEV_CFG(dev); struct secproxy_mailbox_data *data = DEV_DATA(dev); + const struct secproxy_mailbox_config *config = DEV_CFG(dev); k_spinlock_key_t key; if (channel >= MAILBOX_MAX_CHANNELS) { @@ -341,9 +338,10 @@ static int secproxy_mailbox_set_enabled(const struct device *dev, uint32_t chann data->channel_enable[channel] = enable; if (enable) { - irq_enable(cfg->irq); + secproxy_mailbox_flush_thread(dev, channel); + irq_enable(config->interrupts[channel]); } else { - irq_disable(cfg->irq); + irq_disable(config->interrupts[channel]); } k_spin_unlock(&data->lock, key); @@ -359,25 +357,81 @@ static DEVICE_API(mbox, secproxy_mailbox_driver_api) = { .set_enabled = secproxy_mailbox_set_enabled, }; -#define MAILBOX_INSTANCE_DEFINE(idx) \ - static struct secproxy_mailbox_data secproxy_mailbox_##idx##_data; \ - const static struct secproxy_mailbox_config secproxy_mailbox_##idx##_config = { \ - DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(target_data, DT_DRV_INST(idx)), \ - DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(rt, DT_DRV_INST(idx)), \ - DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(scfg, DT_DRV_INST(idx)), \ - .irq = DT_INST_IRQN(idx), \ - }; \ - static int secproxy_mailbox_##idx##_init(const struct device *dev) \ - { \ - DEVICE_MMIO_NAMED_MAP(dev, target_data, K_MEM_CACHE_NONE); \ - DEVICE_MMIO_NAMED_MAP(dev, rt, K_MEM_CACHE_NONE); \ - DEVICE_MMIO_NAMED_MAP(dev, scfg, K_MEM_CACHE_NONE); \ - IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), secproxy_mailbox_isr, \ - DEVICE_DT_INST_GET(idx), \ - COND_CODE_1(DT_INST_IRQ_HAS_CELL(idx, flags), \ - (DT_INST_IRQ(idx, flags)), (0))); \ - return 0; \ - } \ +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); + int rv; + + 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); + return rv; + } + + /* 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); + return rv; + } + + irq_enable(cfg->interrupts[rx_channel]); + + return 0; +} + +#define SECPROXY_THREAD_ISR(i, idx) \ + COND_CODE_1(DT_INST_IRQ_HAS_NAME(idx, DT_CAT(rx_, i)), \ + ( \ + static void secproxy_mailbox_isr_##idx##_##i(const struct device *dev) \ + { \ + secproxy_mailbox_isr(dev, i); \ + } \ + ), \ + ()) + +/* Generate IRQ number or 0 for array initialization */ +#define SECPROXY_IRQ_OR_ZERO(i, inst) \ + COND_CODE_1(DT_INST_IRQ_HAS_NAME(inst, DT_CAT(rx_, i)), \ + (DT_INST_IRQ_BY_NAME(inst, DT_CAT(rx_, i), irq)), \ + (0)) + +#define SECPROXY_IRQ_CONNECT(i, inst) \ + COND_CODE_1(DT_INST_IRQ_HAS_NAME(inst, DT_CAT(rx_, i)), \ + ( \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, DT_CAT(rx_, i), irq), \ + DT_INST_IRQ_BY_NAME(inst, DT_CAT(rx_, i), priority), \ + secproxy_mailbox_isr_##inst##_##i, \ + DEVICE_DT_INST_GET(inst), \ + COND_CODE_1(DT_INST_IRQ_HAS_CELL(inst, flags), \ + (DT_INST_IRQ_BY_NAME(inst, DT_CAT(rx_, i), flags)), \ + (0))); \ + ), \ + ()) + +#define MAILBOX_INSTANCE_DEFINE(idx) \ + LISTIFY(MAILBOX_MAX_CHANNELS, SECPROXY_THREAD_ISR, (), idx) \ + static struct secproxy_mailbox_data secproxy_mailbox_##idx##_data; \ + const static struct secproxy_mailbox_config secproxy_mailbox_##idx##_config = { \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(target_data, DT_DRV_INST(idx)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(rt, DT_DRV_INST(idx)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(scfg, DT_DRV_INST(idx)), \ + .interrupts = {LISTIFY(MAILBOX_MAX_CHANNELS, SECPROXY_IRQ_OR_ZERO, (,), idx) }}; \ + static int secproxy_mailbox_##idx##_init(const struct device *dev) \ + { \ + DEVICE_MMIO_NAMED_MAP(dev, target_data, K_MEM_CACHE_NONE); \ + DEVICE_MMIO_NAMED_MAP(dev, rt, K_MEM_CACHE_NONE); \ + DEVICE_MMIO_NAMED_MAP(dev, scfg, K_MEM_CACHE_NONE); \ + LISTIFY(MAILBOX_MAX_CHANNELS, SECPROXY_IRQ_CONNECT, (;), idx) \ + return 0; \ + } \ DEVICE_DT_INST_DEFINE(idx, secproxy_mailbox_##idx##_init, NULL, \ &secproxy_mailbox_##idx##_data, &secproxy_mailbox_##idx##_config, \ PRE_KERNEL_1, CONFIG_MBOX_TI_SECURE_PROXY_PRIORITY, \ diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index a4e7c0ef68f1e..8f1d5ca8b414c 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -102,6 +102,7 @@ config POWER_DOMAIN_SOC_PM_STATE config POWER_DOMAIN_TISCI bool "TISCI managed power domain" default y + depends on TISCI depends on DT_HAS_TI_SCI_PM_DOMAIN_ENABLED help TISCI managed power domain control to turn on/off devices when the diff --git a/drivers/power_domain/power_domain_tisci.c b/drivers/power_domain/power_domain_tisci.c index 620fc51c0cf73..f6a510f962481 100644 --- a/drivers/power_domain/power_domain_tisci.c +++ b/drivers/power_domain/power_domain_tisci.c @@ -14,7 +14,7 @@ LOG_MODULE_REGISTER(tisci_pd); #define DT_DRV_COMPAT ti_sci_pm_domain -const struct device *dmsc = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(dmsc)); +static const struct device *dmsc = DEVICE_DT_GET(DT_NODELABEL(dmsc)); struct power_domain { uint32_t devid; @@ -78,11 +78,6 @@ static int tisci_pd_init(const struct device *dev) { int ret; - if (dmsc == NULL) { - LOG_ERR("DMSC device not found"); - return -ENODEV; - } - ret = pm_device_driver_init(dev, tisci_pd_pm_action); if (ret < 0) { LOG_ERR("Failed to enable runtime PM: %d", ret); @@ -92,14 +87,21 @@ static int tisci_pd_init(const struct device *dev) return 0; } -#define TISCI_PD_DEVICE_DEFINE(inst) \ - static struct power_domain power_domain_data_##inst = { \ - .devid = DT_INST_PROP(inst, tisci_device_id), \ - .mode = DT_INST_ENUM_IDX(inst, tisci_device_mode), \ +#define TISCI_PD_DEVICE_DEFINE(node) \ + static struct power_domain power_domain_data_##node = { \ + .devid = DT_PROP(node, tisci_device_id), \ + .mode = DT_ENUM_IDX(node, tisci_device_mode), \ }; \ - PM_DEVICE_DT_INST_DEFINE(inst, tisci_pd_pm_action); \ - DEVICE_DT_INST_DEFINE(inst, tisci_pd_init, PM_DEVICE_DT_INST_GET(inst), NULL, \ - &power_domain_data_##inst, PRE_KERNEL_1, \ - CONFIG_POWER_DOMAIN_TISCI_INIT_PRIORITY, NULL); + PM_DEVICE_DT_DEFINE(node, tisci_pd_pm_action); \ + DEVICE_DT_DEFINE(node, tisci_pd_init, PM_DEVICE_DT_GET(node), NULL, \ + &power_domain_data_##node, PRE_KERNEL_1, \ + CONFIG_POWER_DOMAIN_TISCI_INIT_PRIORITY, NULL); + +#define TISCI_PD_DEVICE_DEFINE_IF_OKAY(pd_node) \ + COND_CODE_1(DT_NODE_HAS_COMPAT_STATUS(pd_node, DT_DRV_COMPAT, okay), \ + (TISCI_PD_DEVICE_DEFINE(pd_node)), ()) + +#define DT_TISCI_CHECK_EACH_DEVICE_PD(node_id) \ + TISCI_PD_DEVICE_DEFINE_IF_OKAY(DT_PHANDLE(node_id, power_domains)) -DT_INST_FOREACH_STATUS_OKAY(TISCI_PD_DEVICE_DEFINE); +DT_FOREACH_STATUS_OKAY_NODE(DT_TISCI_CHECK_EACH_DEVICE_PD) diff --git a/dts/arm/ti/am64x_r5.dtsi b/dts/arm/ti/am64x_r5.dtsi index f95a2ef087392..3084c9afa44e2 100644 --- a/dts/arm/ti/am64x_r5.dtsi +++ b/dts/arm/ti/am64x_r5.dtsi @@ -58,16 +58,6 @@ }; }; -&dmsc { - ti,host-id = <36>; - mboxes = <&secure_proxy_main 2>, <&secure_proxy_main 3>; -}; - -&secure_proxy_main { - interrupts = <0 65 IRQ_TYPE_EDGE IRQ_DEFAULT_PRIORITY>; - interrupt-parent = <&vim>; -}; - &main_timer0 { interrupts = <0 152 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; interrupt-parent = <&vim>; diff --git a/dts/arm/ti/am64x_r5f0_0.dtsi b/dts/arm/ti/am64x_r5f0_0.dtsi index 0a2f943748d66..a320cea5edb97 100644 --- a/dts/arm/ti/am64x_r5f0_0.dtsi +++ b/dts/arm/ti/am64x_r5f0_0.dtsi @@ -10,3 +10,15 @@ usr-id = <0>; status = "okay"; }; + +&dmsc { + ti,host-id = <36>; + mboxes = <&secure_proxy_main 2>, <&secure_proxy_main 3>; +}; + +&secure_proxy_main { + interrupt-names = "rx_0", "rx_2"; + interrupts = <0 64 IRQ_TYPE_EDGE IRQ_DEFAULT_PRIORITY>, + <0 65 IRQ_TYPE_EDGE IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; +}; diff --git a/dts/bindings/mbox/ti,secure-proxy.yaml b/dts/bindings/mbox/ti,secure-proxy.yaml index 807f78f7a2a9a..a0b2b10343b40 100644 --- a/dts/bindings/mbox/ti,secure-proxy.yaml +++ b/dts/bindings/mbox/ti,secure-proxy.yaml @@ -14,5 +14,8 @@ properties: interrupts: required: true + interrupt-names: + required: true + mbox-cells: - channel diff --git a/dts/vendor/ti/am64x_main.dtsi b/dts/vendor/ti/am64x_main.dtsi index e735fe69f3ec8..392907aff33e5 100644 --- a/dts/vendor/ti/am64x_main.dtsi +++ b/dts/vendor/ti/am64x_main.dtsi @@ -17,6 +17,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 { @@ -108,6 +113,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"; @@ -116,6 +123,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"; @@ -124,6 +133,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"; @@ -132,6 +143,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"; @@ -140,6 +153,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"; @@ -148,6 +163,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"; @@ -156,6 +173,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"; @@ -164,6 +183,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>; @@ -173,6 +194,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>; @@ -182,6 +205,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>; @@ -191,6 +216,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>; @@ -216,6 +243,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>; @@ -226,6 +255,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>; @@ -236,6 +267,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>; @@ -246,6 +279,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>; @@ -256,6 +291,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>; @@ -266,6 +303,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 1afd17b537966..807676bc7e9d5 100644 --- a/dts/vendor/ti/am64x_mcu.dtsi +++ b/dts/vendor/ti/am64x_mcu.dtsi @@ -20,6 +20,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>; @@ -29,6 +31,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>; @@ -38,6 +42,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>; @@ -46,6 +52,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>; @@ -65,6 +73,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>; @@ -75,6 +85,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..a92122e1ca80e --- /dev/null +++ b/include/zephyr/drivers/mbox/mbox_ti_secproxy.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025, Texas Instruments + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for the TI Secproxy Mailbox + * + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_MBOX_TI_SECPROXY_H_ +#define INCLUDE_ZEPHYR_DRIVERS_MBOX_TI_SECPROXY_H_ + +#include +#include + +/** + * @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); +} + +#endif /* INCLUDE_ZEPHYR_DRIVERS_MBOX_TI_SECPROXY_H_ */ diff --git a/samples/drivers/adc/adc_dt/boards/am243x_evm_am2434_r5f0_0.overlay b/samples/drivers/adc/adc_dt/boards/am243x_evm_am2434_r5f0_0.overlay index 5d8dccf46af83..d771471d43552 100644 --- a/samples/drivers/adc/adc_dt/boards/am243x_evm_am2434_r5f0_0.overlay +++ b/samples/drivers/adc/adc_dt/boards/am243x_evm_am2434_r5f0_0.overlay @@ -10,3 +10,7 @@ <&adc0 6>, <&adc0 7>; }; }; + +&adc0 { + status = "okay"; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/am243x_evm_am2434_r5f0_0.overlay b/samples/drivers/adc/adc_sequence/boards/am243x_evm_am2434_r5f0_0.overlay new file mode 100644 index 0000000000000..a96ad84a97e06 --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/am243x_evm_am2434_r5f0_0.overlay @@ -0,0 +1,9 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Texas Instruments + */ + +&adc0 { + status = "okay"; +}; diff --git a/soc/ti/k3/am6x/CMakeLists.txt b/soc/ti/k3/am6x/CMakeLists.txt index c20bed681437f..fc24c239dbce6 100644 --- a/soc/ti/k3/am6x/CMakeLists.txt +++ b/soc/ti/k3/am6x/CMakeLists.txt @@ -22,6 +22,8 @@ elseif(CONFIG_SOC_SERIES_AM6X_M4) elseif(CONFIG_SOC_SERIES_AM6X_R5) zephyr_sources(r5/soc.c) zephyr_sources_ifdef(CONFIG_ARM_MPU r5/arm_mpu_regions.c) + zephyr_sources_ifdef(CONFIG_PM_DEVICE_RUNTIME r5/power.c) + zephyr_sources_ifdef(CONFIG_CLOCK_CONTROL_TISCI r5/tisci_clock.c) zephyr_include_directories(r5) diff --git a/soc/ti/k3/am6x/r5/power.c b/soc/ti/k3/am6x/r5/power.c new file mode 100644 index 0000000000000..041e40b43c2fb --- /dev/null +++ b/soc/ti/k3/am6x/r5/power.c @@ -0,0 +1,47 @@ +#include "zephyr/pm/device_runtime.h" +#include + +LOG_MODULE_REGISTER(soc_power, LOG_LEVEL_DBG); + +#define CONSOLE_NODE DT_CHOSEN(zephyr_console) + +#define CHECK_NODE_POWER_COND(node) DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE(node, power_domains)) +#define DEVICE_DT_GET_PD(node) DEVICE_DT_GET(DT_PHANDLE(node, power_domains)) + +int soc_power_domain_turn_on(const struct device *dev) +{ + int err = pm_device_runtime_get(dev); + + LOG_INF("Turning on power domain: %s", dev->name); + if (err < 0) { + LOG_INF("Failed to get power domain: %s", dev->name); + return 1; + } + + return 0; +} + +#if CHECK_NODE_POWER_COND(CONSOLE_NODE) +#define CONSOLE_POWER_ON_PRIORITY 45 +BUILD_ASSERT(CONSOLE_POWER_ON_PRIORITY < CONFIG_SERIAL_INIT_PRIORITY); +int soc_chosen_console_power_init(void) +{ + return soc_power_domain_turn_on(DEVICE_DT_GET_PD(CONSOLE_NODE)); +} +SYS_INIT(soc_chosen_console_power_init, PRE_KERNEL_1, CONSOLE_POWER_ON_PRIORITY); +#endif /* CHECK_NODE_POWER_COND(CONSOLE_NODE) */ + +int soc_power_domain_init(void) +{ + int error_count = 0; + +#define CHECK_NODE_POWER_DOMAIN(node) \ + COND_CODE_1(CHECK_NODE_POWER_COND(node), ( \ + error_count += soc_power_domain_turn_on(DEVICE_DT_GET_PD(node)); \ + ), (/* Do nothing */)) + + DT_FOREACH_STATUS_OKAY_NODE(CHECK_NODE_POWER_DOMAIN); + + return error_count; +} +SYS_INIT(soc_power_domain_init, POST_KERNEL, 0); diff --git a/soc/ti/k3/am6x/r5/tisci_clock.c b/soc/ti/k3/am6x/r5/tisci_clock.c new file mode 100644 index 0000000000000..5d38c04d6a402 --- /dev/null +++ b/soc/ti/k3/am6x/r5/tisci_clock.c @@ -0,0 +1,57 @@ +#include +#include +#include + +LOG_MODULE_REGISTER(soc_clock, LOG_LEVEL_DBG); + +#define CONSOLE_NODE DT_CHOSEN(zephyr_console) + +int soc_clock_set_freq(const struct device *dev, clock_control_subsys_rate_t subsys, + uint64_t frequency) +{ + int err = clock_control_set_rate(dev, subsys, &frequency); + + if (err < 0) { + LOG_ERR("Failed to set clock rate for %s\n", dev->name); + return 1; + } + + return 0; +} + +#define CHECK_NODE_CLOCK_COND(node) \ + UTIL_AND(DT_NODE_HAS_PROP(node, clocks), DT_NODE_HAS_PROP(node, clock_frequency)) + +#define NODE_ENABLE_CLOCK(node) \ + { \ + const struct device *dev = TISCI_GET_CLOCK(node); \ + struct tisci_clock_config config = TISCI_GET_CLOCK_DETAILS(node); \ + uint64_t freq = DT_PROP(node, clock_frequency); \ + LOG_INF("Setting frequency for " DT_NODE_FULL_NAME(node) ": %lluHz", freq); \ + error_count += soc_clock_set_freq(dev, &config, freq); \ + } + +#if CHECK_NODE_CLOCK_COND(CONSOLE_NODE) +int soc_chosen_console_clock_init(void) +{ + int error_count = 0; + + NODE_ENABLE_CLOCK(CONSOLE_NODE); + return error_count; +} + +SYS_INIT(soc_chosen_console_clock_init, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY); +#endif /* CHECK_NODE_CLOCK_COND(zephyr_console) */ + +int soc_clock_init(void) +{ + int error_count = 0; + +#define CHECK_NODE_CLOCK(node) \ + COND_CODE_1(CHECK_NODE_CLOCK_COND(node), (NODE_ENABLE_CLOCK(node)), (/* Do nothing */)) + + DT_FOREACH_STATUS_OKAY_NODE(CHECK_NODE_CLOCK); + + return error_count; +} +SYS_INIT(soc_clock_init, POST_KERNEL, 1); diff --git a/tests/drivers/spi/spi_loopback/boards/am243x_evm_am2434_r5f0_0.overlay b/tests/drivers/spi/spi_loopback/boards/am243x_evm_am2434_r5f0_0.overlay index be2e6e7d4e093..3d236befa57fb 100644 --- a/tests/drivers/spi/spi_loopback/boards/am243x_evm_am2434_r5f0_0.overlay +++ b/tests/drivers/spi/spi_loopback/boards/am243x_evm_am2434_r5f0_0.overlay @@ -7,6 +7,8 @@ #include &main_mcspi0 { + status = "okay"; + slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>;