From bd47268dd5d722a0b8de9aeceb8ab614638e86c3 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 21 Oct 2025 16:29:10 +0800 Subject: [PATCH 001/397] Bluetooth: Fix double set random address for every advertising enable The `bt_le_ext_adv_update_param` will set new random address when option not select `BT_LE_ADV_OPT_USE_IDENTITY`, But `bt_le_ext_adv_start` will also set random address again. This will be affect bluetooth mesh, after this change, will ensure address only change once for every advertising. Signed-off-by: Lingao Meng --- subsys/bluetooth/host/adv.c | 9 +++++++-- subsys/bluetooth/host/hci_core.h | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index bdf74f47aa84b..07d80b18c03a5 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -1178,6 +1178,9 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, atomic_set_bit_to(adv->flags, BT_ADV_EXT_ADV, param->options & BT_LE_ADV_OPT_EXT_ADV); + atomic_set_bit_to(adv->flags, BT_ADV_RANDOM_ADDR_UPDATED, + own_addr_type == BT_HCI_OWN_ADDR_RANDOM); + return 0; } @@ -1507,11 +1510,13 @@ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, if (atomic_test_bit(adv->flags, BT_ADV_CONNECTABLE)) { if (IS_ENABLED(CONFIG_BT_PRIVACY) && - !atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY)) { + !atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY) && + !atomic_test_and_clear_bit(adv->flags, BT_ADV_RANDOM_ADDR_UPDATED)) { bt_id_set_adv_private_addr(adv); } } else { - if (!atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY)) { + if (!atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY) && + !atomic_test_and_clear_bit(adv->flags, BT_ADV_RANDOM_ADDR_UPDATED)) { bt_id_set_adv_private_addr(adv); } } diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 3d1c87cb3c0bd..e4a390af20aaf 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -116,6 +116,10 @@ enum { BT_ADV_PARAMS_SET, /* Advertising data has been set in the controller. */ BT_ADV_DATA_SET, + /* Advertising random address has been updated in the controller before + * enabling advertising. + */ + BT_ADV_RANDOM_ADDR_UPDATED, /* Advertising random address pending to be set in the controller. */ BT_ADV_RANDOM_ADDR_PENDING, /* The private random address of the advertiser is valid for this cycle From a7b7c066bf7d94289af926bc0c22cb70a9ddc801 Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 21 Oct 2025 19:24:04 +0800 Subject: [PATCH 002/397] tests: bluetooth: mesh: fix bbsim timing fix bluetooth mesh relay timing problem. Signed-off-by: Lingao Meng --- tests/bsim/bluetooth/mesh/src/test_advertiser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/bsim/bluetooth/mesh/src/test_advertiser.c b/tests/bsim/bluetooth/mesh/src/test_advertiser.c index f7489f9e8315c..290b4365ef2a1 100644 --- a/tests/bsim/bluetooth/mesh/src/test_advertiser.c +++ b/tests/bsim/bluetooth/mesh/src/test_advertiser.c @@ -688,7 +688,9 @@ static void test_tx_send_relay(void) net_buf_simple_add_u8(&relay_second->b, 0x02); bt_mesh_adv_send(local, &local_send_cb, NULL); + k_sleep(K_MSEC(1)); bt_mesh_adv_send(relay_first, &relay_first_send_cb, NULL); + k_sleep(K_MSEC(1)); bt_mesh_adv_send(relay_second, &relay_second_send_cb, NULL); bt_mesh_adv_unref(local); From 099b09b724cba8e86e4a00c1c6b8aa1d9f39c84f Mon Sep 17 00:00:00 2001 From: Nhut Nguyen Date: Tue, 21 Oct 2025 13:31:43 +0700 Subject: [PATCH 003/397] tests: drivers: uart_async_api: Fix format warnings Use %zu for size_t to avoid build warning with arm64 compiler Signed-off-by: Nhut Nguyen --- .../uart/uart_async_api/src/test_uart_async.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/src/test_uart_async.c b/tests/drivers/uart/uart_async_api/src/test_uart_async.c index 936600c96fcbe..14e6395170161 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart_async.c +++ b/tests/drivers/uart/uart_async_api/src/test_uart_async.c @@ -432,7 +432,7 @@ ZTEST_USER(uart_async_chain_read, test_chained_read) "TX_DONE timeout"); k_msleep(rx_timeout_ms + 10); zassert_equal(rx_data_idx, sizeof(tx_buf), - "Unexpected amount of data received %d exp:%d", + "Unexpected amount of data received %d exp:%zu", rx_data_idx, sizeof(tx_buf)); zassert_equal(memcmp(tx_buf, chained_cpy_buf, sizeof(tx_buf)), 0, "Buffers not equal exp %s, real %s", tx_buf, chained_cpy_buf); @@ -1089,22 +1089,22 @@ static ZTEST_BMEM uint8_t tx_buffer[VAR_LENGTH_TX_BUF_SIZE]; ret = uart_rx_enable(uart_dev, (uint8_t *)&var_length_rx_buf_pool[var_length_buf_rx_pool_idx], buf_len, 2 * USEC_PER_MSEC); - zassert_true(ret == 0, "[buff=%d][tx=%d]Failed to enable RX: %d\n", buf_len, tx_len, ret); + zassert_true(ret == 0, "[buff=%zu][tx=%zu]Failed to enable RX: %d\n", buf_len, tx_len, ret); var_length_buf_rx_pool_idx += buf_len; ret = uart_tx(uart_dev, tx_buffer, tx_len, 100 * USEC_PER_MSEC); - zassert_true(ret == 0, "[buff=%d][tx=%d]Failed to TX: %d\n", buf_len, tx_len, ret); + zassert_true(ret == 0, "[buff=%zu][tx=%zu]Failed to TX: %d\n", buf_len, tx_len, ret); k_msleep(10); uart_rx_disable(uart_dev); zassert_equal(k_sem_take(&rx_disabled, K_MSEC(500)), 0, - "[buff=%d][tx=%d]RX_DISABLED timeout\n", buf_len, tx_len); + "[buff=%zu][tx=%zu]RX_DISABLED timeout\n", buf_len, tx_len); zassert_equal(var_length_buf_rx_idx, tx_len, - "[buff=%d][tx=%d]Wrong number of bytes received, got: %d, expected: %d\n", + "[buff=%zu][tx=%zu]Wrong number of bytes received, got: %zu, expected: %zu\n", buf_len, tx_len, var_length_buf_rx_idx, tx_len); zassert_equal(memcmp((void *)var_length_rx_buf, tx_buffer, tx_len), 0, - "[buff=%d][tx=%d]Buffers not equal\n", buf_len, tx_len); + "[buff=%zu][tx=%zu]Buffers not equal\n", buf_len, tx_len); } ZTEST_USER(uart_async_var_buf_length, test_var_buf_length) From 1507925c54a69e03a62b771a5dc5e2ac048ee52a Mon Sep 17 00:00:00 2001 From: Nhut Nguyen Date: Tue, 21 Oct 2025 14:43:33 +0700 Subject: [PATCH 004/397] drivers: eeprom: fm25xxx: Fix format warning Use %zu for size_t to avoid build warning with arm64 compiler Signed-off-by: Nhut Nguyen --- drivers/eeprom/eeprom_fm25xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/eeprom/eeprom_fm25xxx.c b/drivers/eeprom/eeprom_fm25xxx.c index f0061c84265c1..f35d7de2d20ad 100644 --- a/drivers/eeprom/eeprom_fm25xxx.c +++ b/drivers/eeprom/eeprom_fm25xxx.c @@ -104,7 +104,7 @@ int eeprom_fm25xxx_read(const struct device *dev, off_t offset, void *data, size sys_put_be24(offset, &read_op[1]); break; default: - LOG_ERR("Invalid number of address bytes %u", addr_bytes); + LOG_ERR("Invalid number of address bytes %zu", addr_bytes); return -EINVAL; } @@ -182,7 +182,7 @@ int eeprom_fm25xxx_write(const struct device *dev, off_t offset, const void *dat sys_put_be24(offset, &write_op[1]); break; default: - LOG_ERR("Invalid number of address bytes %u", addr_bytes); + LOG_ERR("Invalid number of address bytes %zu", addr_bytes); return -EINVAL; } From 3113cee66f0979c8fc484f95c3c3140bb516b00f Mon Sep 17 00:00:00 2001 From: Jeppe Odgaard Date: Fri, 17 Oct 2025 12:37:34 +0200 Subject: [PATCH 005/397] drivers: sensor: qdec_stm32: check counts/revoultion compile time Use build assert to check counts_per_revolution DTS value compile time to prevent runtime failure and also decrease flash usage slightly. Signed-off-by: Jeppe Odgaard --- drivers/sensor/st/qdec_stm32/qdec_stm32.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/sensor/st/qdec_stm32/qdec_stm32.c b/drivers/sensor/st/qdec_stm32/qdec_stm32.c index d3ed5b4b1f2e9..01bddb810a4ec 100644 --- a/drivers/sensor/st/qdec_stm32/qdec_stm32.c +++ b/drivers/sensor/st/qdec_stm32/qdec_stm32.c @@ -114,12 +114,6 @@ static int qdec_stm32_initialize(const struct device *dev) return retval; } - if (dev_cfg->counts_per_revolution < 1) { - LOG_ERR("Invalid number of counts per revolution (%d)", - dev_cfg->counts_per_revolution); - return -EINVAL; - } - /* Ensure that the counter will always count up to a multiple of counts_per_revolution */ if (IS_TIM_32B_COUNTER_INSTANCE(dev_cfg->timer_inst)) { max_counter_value = UINT32_MAX - (UINT32_MAX % dev_cfg->counts_per_revolution) - 1; @@ -146,6 +140,9 @@ static DEVICE_API(sensor, qdec_stm32_driver_api) = { }; #define QDEC_STM32_INIT(n) \ + BUILD_ASSERT(DT_INST_PROP(n, st_counts_per_revolution) > 0, \ + "Counts per revolution must be above 0"); \ + \ BUILD_ASSERT(!(DT_INST_PROP(n, st_encoder_mode) & ~TIM_SMCR_SMS), \ "Encoder mode is not supported by this MCU"); \ \ From 65f66a7fd8ce1f7dad274daee59a64460bf558ae Mon Sep 17 00:00:00 2001 From: Ben Marsh Date: Fri, 17 Oct 2025 10:25:07 +0100 Subject: [PATCH 006/397] drivers: flash: stm32_{q|o|x}spi: Fix write unprotect logs The STM32 QSPI, OSPI, and XSPI drivers support sending the ULBPR command for flash ICs that require unlocking before writing to. This is done conditionally based on the requires_ulbpr devicetree property. Previously the driver would always log "Write Un-protected", even if a write un-protect was not attempted. Fix this so that "Write Un-protected" is only logged when a write un-protect is attempted and succeeds. Signed-off-by: Ben Marsh --- drivers/flash/flash_stm32_ospi.c | 25 +++++++++++-------------- drivers/flash/flash_stm32_qspi.c | 25 +++++++++++-------------- drivers/flash/flash_stm32_xspi.c | 25 +++++++++++-------------- 3 files changed, 33 insertions(+), 42 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index d95f3a18d723e..17592b008e194 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -720,17 +720,12 @@ static int ospi_write_unprotect(const struct device *dev) cmd_unprotect.AddressMode = HAL_OSPI_ADDRESS_NONE; cmd_unprotect.DataMode = HAL_OSPI_DATA_NONE; - if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { - ret = stm32_ospi_write_enable(dev_data, OSPI_SPI_MODE, OSPI_STR_TRANSFER); - - if (ret != 0) { - return ret; - } - - ret = ospi_send_cmd(dev, &cmd_unprotect); + ret = stm32_ospi_write_enable(dev_data, OSPI_SPI_MODE, OSPI_STR_TRANSFER); + if (ret != 0) { + return ret; } - return ret; + return ospi_send_cmd(dev, &cmd_unprotect); } /* Write Flash configuration register 2 with new dummy cycles */ @@ -2599,12 +2594,14 @@ static int flash_stm32_ospi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ - ret = ospi_write_unprotect(dev); - if (ret != 0) { - LOG_ERR("write unprotect failed: %d", ret); - return -ENODEV; + if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { + ret = ospi_write_unprotect(dev); + if (ret != 0) { + LOG_ERR("write unprotect failed: %d", ret); + return -ENODEV; + } + LOG_DBG("Write Un-protected"); } - LOG_DBG("Write Un-protected"); #ifdef CONFIG_STM32_MEMMAP /* Now configure the octo Flash in MemoryMapped (access by address) */ diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 4f55d40b9e0a5..1c0c0c9614492 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -454,17 +454,12 @@ static int qspi_write_unprotect(const struct device *dev) .InstructionMode = QSPI_INSTRUCTION_1_LINE, }; - if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { - ret = qspi_send_cmd(dev, &cmd_write_en); - - if (ret != 0) { - return ret; - } - - ret = qspi_send_cmd(dev, &cmd_unprotect); + ret = qspi_send_cmd(dev, &cmd_write_en); + if (ret != 0) { + return ret; } - return ret; + return qspi_send_cmd(dev, &cmd_unprotect); } /* @@ -1739,12 +1734,14 @@ static int flash_stm32_qspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ - ret = qspi_write_unprotect(dev); - if (ret != 0) { - LOG_ERR("write unprotect failed: %d", ret); - return -ENODEV; + if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { + ret = qspi_write_unprotect(dev); + if (ret != 0) { + LOG_ERR("write unprotect failed: %d", ret); + return -ENODEV; + } + LOG_DBG("Write Un-protected"); } - LOG_DBG("Write Un-protected"); #ifdef CONFIG_STM32_MEMMAP ret = stm32_qspi_set_memory_mapped(dev); diff --git a/drivers/flash/flash_stm32_xspi.c b/drivers/flash/flash_stm32_xspi.c index a7a2d56d90f57..fa8849e81f35f 100644 --- a/drivers/flash/flash_stm32_xspi.c +++ b/drivers/flash/flash_stm32_xspi.c @@ -579,17 +579,12 @@ static int xspi_write_unprotect(const struct device *dev) cmd_unprotect.AddressMode = HAL_XSPI_ADDRESS_NONE; cmd_unprotect.DataMode = HAL_XSPI_DATA_NONE; - if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { - ret = stm32_xspi_write_enable(dev, XSPI_SPI_MODE, XSPI_STR_TRANSFER); - - if (ret != 0) { - return ret; - } - - ret = xspi_send_cmd(dev, &cmd_unprotect); + ret = stm32_xspi_write_enable(dev, XSPI_SPI_MODE, XSPI_STR_TRANSFER); + if (ret != 0) { + return ret; } - return ret; + return xspi_send_cmd(dev, &cmd_unprotect); } /* Write Flash configuration register 2 with new dummy cycles */ @@ -2401,12 +2396,14 @@ static int flash_stm32_xspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ - ret = xspi_write_unprotect(dev); - if (ret != 0) { - LOG_ERR("write unprotect failed: %d", ret); - return -ENODEV; + if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { + ret = xspi_write_unprotect(dev); + if (ret != 0) { + LOG_ERR("write unprotect failed: %d", ret); + return -ENODEV; + } + LOG_DBG("Write Un-protected"); } - LOG_DBG("Write Un-protected"); #ifdef CONFIG_STM32_MEMMAP ret = stm32_xspi_set_memorymap(dev); From ad8ad49c5e9de5c5df2078f8cdb1e5defc8cdc3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Fri, 17 Oct 2025 10:59:00 +0200 Subject: [PATCH 007/397] editorconfig: Trailing spaces are meaningful in patches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My editor (nvim) started to automatically source .editorconfig. This new feature broke my git workflow when I edit my staging changes (yes, I edit patches and they still apply). It took me a bit of time to understand my editor striped the trailing space (which are meaningful patches) because of .editorconfig. Signed-off-by: Jérôme Pouiller --- .editorconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.editorconfig b/.editorconfig index 988cb95f5e42e..206960dd7dd15 100644 --- a/.editorconfig +++ b/.editorconfig @@ -86,6 +86,10 @@ indent_size = 8 [COMMIT_EDITMSG] max_line_length = 75 +# Patches +[{*.patch,*.diff}] +trim_trailing_whitespace = false + # Kconfig [Kconfig*] indent_style = tab From 8e3b017932fab8897d610d6025ad9876ebb7353e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Oct 2025 09:54:36 +0200 Subject: [PATCH 008/397] boards: amd: fix full_name for versalnet_apu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should be Versal NET APU Development Board Signed-off-by: Benjamin Cabé --- boards/amd/versalnet_apu/board.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/amd/versalnet_apu/board.yml b/boards/amd/versalnet_apu/board.yml index 230690e7c71c1..0c7b0dda2908d 100644 --- a/boards/amd/versalnet_apu/board.yml +++ b/boards/amd/versalnet_apu/board.yml @@ -1,5 +1,6 @@ board: name: versalnet_apu + full_name: Versal Net APU Development Board vendor: amd socs: - name: amd_versalnet_apu From d2ca6e4b9bbaf2da552ea34fde2188f0ad2033f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Oct 2025 09:54:52 +0200 Subject: [PATCH 009/397] boards: infineon: fix full_name for kit_pse84_ev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should be PSOC Edge E84 Evaluation Kit Signed-off-by: Benjamin Cabé --- boards/infineon/kit_pse84_eval/board.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/infineon/kit_pse84_eval/board.yml b/boards/infineon/kit_pse84_eval/board.yml index 821aeea313213..1e6733003ee1c 100644 --- a/boards/infineon/kit_pse84_eval/board.yml +++ b/boards/infineon/kit_pse84_eval/board.yml @@ -5,7 +5,7 @@ board: name: kit_pse84_eval - full_name: kit_pse84_eval + full_name: PSOC Edge E84 Evaluation Kit vendor: infineon socs: - name: pse846gps2dbzc4a From 873fd46c307cd5a7eace3c367eda62d433e7551a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Oct 2025 09:55:47 +0200 Subject: [PATCH 010/397] boards: st: nucleo_c092rc: drop figure from docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Board image needs not to be manually included in the documentation, as zephyr:board:: directive takes care of this already. Signed-off-by: Benjamin Cabé --- boards/st/nucleo_c092rc/doc/index.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/boards/st/nucleo_c092rc/doc/index.rst b/boards/st/nucleo_c092rc/doc/index.rst index 3547334d43f47..6cf87da671d4d 100644 --- a/boards/st/nucleo_c092rc/doc/index.rst +++ b/boards/st/nucleo_c092rc/doc/index.rst @@ -6,10 +6,6 @@ The STM32 Nucleo-64 development board, featuring the STM32C092RC MCU, supports both Arduino and ST morpho connectivity, and includes a CAN FD interface with an onboard transceiver. -.. image:: img/st_nucleo_c092rc.webp - :align: center - :alt: Nucleo C092RC development board - More information about the board can be found at the `Nucleo C092RC website`_. Hardware From 98a0013d6e58a6f26830c54dc1e31a37cc0e1373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 17 Oct 2025 09:57:27 +0200 Subject: [PATCH 011/397] boards: egis: egis_et171: drop figure from docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Board image needs not to be manually included in the documentation, as zephyr:board:: directive takes care of this already. Signed-off-by: Benjamin Cabé --- .../img/{et171_snapshot.webp => egis_et171.webp} | Bin boards/egis/egis_et171/doc/index.rst | 4 ---- 2 files changed, 4 deletions(-) rename boards/egis/egis_et171/doc/img/{et171_snapshot.webp => egis_et171.webp} (100%) diff --git a/boards/egis/egis_et171/doc/img/et171_snapshot.webp b/boards/egis/egis_et171/doc/img/egis_et171.webp similarity index 100% rename from boards/egis/egis_et171/doc/img/et171_snapshot.webp rename to boards/egis/egis_et171/doc/img/egis_et171.webp diff --git a/boards/egis/egis_et171/doc/index.rst b/boards/egis/egis_et171/doc/index.rst index 7b3cf0b67980b..adaa6292db3b2 100644 --- a/boards/egis/egis_et171/doc/index.rst +++ b/boards/egis/egis_et171/doc/index.rst @@ -22,10 +22,6 @@ The platform provides following hardware components: - DMA - USB -.. figure:: img/et171_snapshot.webp - :align: center - :alt: EGIS_ET171_SOC - Supported Features ================== From a7833a4ad6249a67f030461867895a7aeac244f9 Mon Sep 17 00:00:00 2001 From: David Jewsbury Date: Thu, 16 Oct 2025 10:18:49 +0100 Subject: [PATCH 012/397] drivers: clock_control: Add macros for AUXPLL output frequencies These represent the outputted frequencies of the AUXPLL of different settings set in the device tree set using dt-bindings in nrf-auxpll.h. This is added to remove the need for 'magic numbers' in drivers and tests. Signed-off-by: David Jewsbury --- .../drivers/clock_control/nrf_clock_control.h | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/zephyr/drivers/clock_control/nrf_clock_control.h b/include/zephyr/drivers/clock_control/nrf_clock_control.h index 37fc4a1f1a852..7fa4530a6a048 100644 --- a/include/zephyr/drivers/clock_control/nrf_clock_control.h +++ b/include/zephyr/drivers/clock_control/nrf_clock_control.h @@ -188,6 +188,29 @@ uint32_t z_nrf_clock_bt_ctlr_hf_get_startup_time_us(void); /* Specifies that default precision of the clock is sufficient. */ #define NRF_CLOCK_CONTROL_PRECISION_DEFAULT 0 +/* AUXPLL devicetree takes in raw register values, these are the actual frequencies outputted */ +#define CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_MIN_HZ 80000000 +#define CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_AUDIO_44K1_HZ 11289591 +#define CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_USB24M_HZ 24000000 +#define CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_AUDIO_48K_HZ 12287963 + +/* Internal helper macro to map DT property value to output frequency */ +#define _CLOCK_CONTROL_NRF_AUXPLL_MAP_FREQ(freq_val) \ + ((freq_val) == NRF_AUXPLL_FREQ_DIV_MIN ? \ + CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_MIN_HZ : \ + (freq_val) == NRF_AUXPLL_FREQ_DIV_AUDIO_44K1 ? \ + CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_AUDIO_44K1_HZ : \ + (freq_val) == NRF_AUXPLL_FREQ_DIV_USB24M ? \ + CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_USB24M_HZ : \ + (freq_val) == NRF_AUXPLL_FREQ_DIV_AUDIO_48K ? \ + CLOCK_CONTROL_NRF_AUXPLL_FREQ_OUT_AUDIO_48K_HZ : 0) + +/* Public macro to get output frequency of AUXPLL */ +#define CLOCK_CONTROL_NRF_AUXPLL_GET_FREQ(node) \ + COND_CODE_1(DT_NODE_HAS_PROP(node, nordic_frequency), \ + (_CLOCK_CONTROL_NRF_AUXPLL_MAP_FREQ(DT_PROP(node, nordic_frequency))), \ + (0)) + struct nrf_clock_spec { uint32_t frequency; uint16_t accuracy : 15; From 68a61a4b3d469c966da976575de15f6f56ea9eae Mon Sep 17 00:00:00 2001 From: David Jewsbury Date: Thu, 16 Oct 2025 10:28:05 +0100 Subject: [PATCH 013/397] drivers: audio: dmic_nrfx: Update AUXPLL control with frequency macros Frequencies being for AUXPLL were register assignments and not actual frequencies. Signed-off-by: David Jewsbury --- drivers/audio/dmic_nrfx_pdm.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/audio/dmic_nrfx_pdm.c b/drivers/audio/dmic_nrfx_pdm.c index c2c80a7414c1e..a2d630f847a98 100644 --- a/drivers/audio/dmic_nrfx_pdm.c +++ b/drivers/audio/dmic_nrfx_pdm.c @@ -24,11 +24,15 @@ LOG_MODULE_REGISTER(dmic_nrfx_pdm, CONFIG_AUDIO_DMIC_LOG_LEVEL); #define DMIC_NRFX_CLOCK_FACTOR 8192 #define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(NODE_AUDIOPLL, frequency, 0) #elif DT_NODE_HAS_STATUS_OKAY(NODE_AUDIO_AUXPLL) -#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP(NODE_AUDIO_AUXPLL, nordic_frequency) -BUILD_ASSERT((DMIC_NRFX_AUDIO_CLOCK_FREQ == NRF_AUXPLL_FREQ_DIV_AUDIO_48K) || - (DMIC_NRFX_AUDIO_CLOCK_FREQ == NRF_AUXPLL_FREQ_DIV_AUDIO_44K1), +#define AUXPLL_FREQUENCY_SETTING DT_PROP(NODE_AUDIO_AUXPLL, nordic_frequency) +BUILD_ASSERT((AUXPLL_FREQUENCY_SETTING == NRF_AUXPLL_FREQ_DIV_AUDIO_48K) || + (AUXPLL_FREQUENCY_SETTING == NRF_AUXPLL_FREQ_DIV_AUDIO_44K1), "Unsupported Audio AUXPLL frequency selection for PDM"); + +#define DMIC_NRFX_AUDIO_CLOCK_FREQ CLOCK_CONTROL_NRF_AUXPLL_GET_FREQ(NODE_AUDIO_AUXPLL) + #define DMIC_NRFX_CLOCK_FREQ MHZ(32) + #else #define DMIC_NRFX_CLOCK_FREQ MHZ(32) #define DMIC_NRFX_CLOCK_FACTOR 4096 From 373ffbf25e1f1c0538e73cb77262126f6c397344 Mon Sep 17 00:00:00 2001 From: David Jewsbury Date: Thu, 16 Oct 2025 10:29:29 +0100 Subject: [PATCH 014/397] tests: drivers: Update AUXPLL test to use frequency Macros Eliminate the need for magic numbers when setting AUXPLL_FREQ_OUT Signed-off-by: David Jewsbury --- .../clock_control/nrf_clock_control/src/main.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/drivers/clock_control/nrf_clock_control/src/main.c b/tests/drivers/clock_control/nrf_clock_control/src/main.c index 83fdc98ca1934..3612373a867dd 100644 --- a/tests/drivers/clock_control/nrf_clock_control/src/main.c +++ b/tests/drivers/clock_control/nrf_clock_control/src/main.c @@ -162,17 +162,10 @@ static const struct test_clk_context lfclk_test_clk_contexts[] = { #define AUXPLL_NODE DT_INST(0, AUXPLL_COMPAT) #define AUXPLL_FREQ DT_PROP(AUXPLL_NODE, nordic_frequency) -/* Gets selected AUXPLL DIV and selects the expected frequency */ -#if AUXPLL_FREQ == NRF_AUXPLL_FREQUENCY_DIV_MIN -#define AUXPLL_FREQ_OUT 80000000 -#elif AUXPLL_FREQ == NRF_AUXPLL_FREQ_DIV_AUDIO_44K1 -#define AUXPLL_FREQ_OUT 11289591 -#elif AUXPLL_FREQ == NRF_AUXPLL_FREQ_DIV_USB_24M -#define AUXPLL_FREQ_OUT 24000000 -#elif AUXPLL_FREQ == NRF_AUXPLL_FREQ_DIV_AUDIO_48K -#define AUXPLL_FREQ_OUT 12287963 -#else -/*No use case for NRF_AUXPLL_FREQ_DIV_MAX or others yet*/ + +/* Gets expected AUXPLL frequency */ +#define AUXPLL_FREQ_OUT CLOCK_CONTROL_NRF_AUXPLL_GET_FREQ(AUXPLL_NODE) +#if AUXPLL_FREQ_OUT == 0 #error "Unsupported AUXPLL frequency selection" #endif From fb96b4075bcaec938c24eb61915ee6fac38f1c94 Mon Sep 17 00:00:00 2001 From: farsin NASAR V A Date: Tue, 29 Jul 2025 12:37:01 +0530 Subject: [PATCH 015/397] dts: arm: microchip: add RSTC node and binding for G1 IP Add the device tree node and the binding file for microchip RSTC G1 IP. Signed-off-by: farsin NASAR V A --- .../sam/sam_d5x_e5x/common/samd5xe5x.dtsi | 6 ++++++ .../reset/microchip,rstc-g1-reset.yaml | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 dts/bindings/reset/microchip,rstc-g1-reset.yaml diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi index d799321d5be4e..4a545dd952048 100644 --- a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi @@ -54,6 +54,12 @@ }; }; + rstc: rstc@40000c00 { + compatible = "microchip,rstc-g1-reset"; + status = "disabled"; + reg = <0x40000c00 0x400>; + }; + sercom0: sercom@40003000 { compatible = "microchip,sercom-g1"; status = "disabled"; diff --git a/dts/bindings/reset/microchip,rstc-g1-reset.yaml b/dts/bindings/reset/microchip,rstc-g1-reset.yaml new file mode 100644 index 0000000000000..34575e5859164 --- /dev/null +++ b/dts/bindings/reset/microchip,rstc-g1-reset.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip RSTC Reset driver + +description: | + Microchip RSTC Reset driver bindings. + + Group g1 RSTC Reset driver supports following hardware peripherals: + - module name="RSTC" id="U2239" version="4.0.0" + +include: base.yaml + +compatible: "microchip,rstc-g1-reset" + +properties: + reg: + required: true + description: | + Base address and size of the RSTC register block. From 1ed5674b1c9475cd03209157d8cab1269e67e684 Mon Sep 17 00:00:00 2001 From: farsin NASAR V A Date: Tue, 5 Aug 2025 14:35:54 +0530 Subject: [PATCH 016/397] drivers: reset: microchip: Add reset driver Add reset driver for Microchip RSTC G1 IP. Signed-off-by: farsin NASAR V A --- drivers/reset/CMakeLists.txt | 1 + drivers/reset/Kconfig | 1 + drivers/reset/Kconfig.mchp | 9 ++ drivers/reset/reset_mchp_rstc_g1.c | 118 ++++++++++++++++++++ include/zephyr/drivers/reset/mchp_reset.h | 20 ++++ include/zephyr/drivers/reset/mchp_rstc_g1.h | 35 ++++++ 6 files changed, 184 insertions(+) create mode 100644 drivers/reset/Kconfig.mchp create mode 100644 drivers/reset/reset_mchp_rstc_g1.c create mode 100644 include/zephyr/drivers/reset/mchp_reset.h create mode 100644 include/zephyr/drivers/reset/mchp_rstc_g1.h diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index 363720f271304..9646ba6dd5a8f 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -15,4 +15,5 @@ zephyr_library_sources_ifdef(CONFIG_RESET_NXP_MRCC reset_nxp_mrcc.c) zephyr_library_sources_ifdef(CONFIG_RESET_NXP_RSTCTL reset_nxp_rstctl.c) zephyr_library_sources_ifdef(CONFIG_RESET_MMIO reset_mmio.c) zephyr_library_sources_ifdef(CONFIG_RESET_MCHP_MSS reset_mchp_mss.c) +zephyr_library_sources_ifdef(CONFIG_RESET_MCHP_RSTC_G1 reset_mchp_rstc_g1.c) zephyr_library_sources_ifdef(CONFIG_RESET_SF32LB reset_sf32lb.c) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index b5c76cc70c9fe..8562f2c183586 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -38,6 +38,7 @@ rsource "Kconfig.lpc_syscon" rsource "Kconfig.nxp_mrcc" rsource "Kconfig.nxp_rstctl" rsource "Kconfig.mmio" +rsource "Kconfig.mchp" rsource "Kconfig.mchp_mss" rsource "Kconfig.sf32lb" diff --git a/drivers/reset/Kconfig.mchp b/drivers/reset/Kconfig.mchp new file mode 100644 index 0000000000000..61d5920e9d04c --- /dev/null +++ b/drivers/reset/Kconfig.mchp @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config RESET_MCHP_RSTC_G1 + bool "Microchip Reset Controller g1 peripheral driver" + default y + depends on DT_HAS_MICROCHIP_RSTC_G1_RESET_ENABLED + help + Enable RESET driver for Microchip G1. diff --git a/drivers/reset/reset_mchp_rstc_g1.c b/drivers/reset/reset_mchp_rstc_g1.c new file mode 100644 index 0000000000000..33d141aaff34a --- /dev/null +++ b/drivers/reset/reset_mchp_rstc_g1.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file reset_mchp_rstc_g1.c + * @brief Zephyr reset driver for Microchip G1 peripherals + * + * This file implements the driver for the Microchip RSTC g1 reset controller, + * providing APIs to assert, deassert, toggle, and query the status of reset lines. + * + */ + +#include +#include +#include +#include + +#define DT_DRV_COMPAT microchip_rstc_g1_reset + +/* Maximum number of reset lines supported by the controller */ +#define MCHP_RST_LINE_MAX 8 + +struct reset_mchp_config { + rstc_registers_t *regs; +}; + +/** + * @brief Get the status of a reset line. + * + * This function checks if the specified reset line is currently asserted. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] id Reset line ID (0-7). + * @param[out] status Pointer to a variable to store the status (1 = asserted, 0 = not asserted). + * + * @retval 0 On success. + * @retval -EINVAL If the reset line ID is invalid. + */ +static int reset_mchp_status(const struct device *dev, uint32_t id, uint8_t *status) +{ + int ret = 0; + uint8_t rcause = 0; + + if (id >= MCHP_RST_LINE_MAX) { + ret = -EINVAL; + } else { + rcause = (((const struct reset_mchp_config *)((dev)->config))->regs)->RSTC_RCAUSE; + *status = (rcause & BIT(id)) ? 1 : 0; + } + + return ret; +} + +/** + * @brief Assert (activate) a reset line. + * + * This function asserts the specified reset line. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] id Reset line ID. + * + * @retval -ENOTSUP Operation not supported by hardware. + */ +static int reset_mchp_line_assert(const struct device *dev, uint32_t id) +{ + return -ENOTSUP; +} + +/** + * @brief Deassert (deactivate) a reset line. + * + * This function deasserts the specified reset line. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] id Reset line ID. + * + * @retval -ENOTSUP Operation not supported by hardware. + */ +static int reset_mchp_line_deassert(const struct device *dev, uint32_t id) +{ + return -ENOTSUP; +} + +/** + * @brief Toggle a reset line (assert then deassert). + * + * This function asserts and then deasserts the specified reset line, with a short delay in between. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] id Reset line ID. + * + * @retval -ENOTSUP Operation not supported by hardware. + */ +static int reset_mchp_line_toggle(const struct device *dev, uint32_t id) +{ + return -ENOTSUP; +} + +static DEVICE_API(reset, reset_mchp_api) = { + .status = reset_mchp_status, + .line_assert = reset_mchp_line_assert, + .line_deassert = reset_mchp_line_deassert, + .line_toggle = reset_mchp_line_toggle, +}; + +/* Configuration instance for the Microchip RSTC g1 reset controller */ +static const struct reset_mchp_config reset_mchp_config = { + .regs = (rstc_registers_t *)DT_INST_REG_ADDR(0), +}; + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) <= 1, + "Only one Microchip RSTC g1 instance is supported."); + +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &reset_mchp_config, PRE_KERNEL_1, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &reset_mchp_api) diff --git a/include/zephyr/drivers/reset/mchp_reset.h b/include/zephyr/drivers/reset/mchp_reset.h new file mode 100644 index 0000000000000..9c08a48645cdf --- /dev/null +++ b/include/zephyr/drivers/reset/mchp_reset.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** + * @file mchp_reset.h + * @brief Microchip Reset header + * + * This header defines the macros for use with the Microchip reset controller driver. + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_RESET_MCHP_RESET_H_ +#define INCLUDE_ZEPHYR_DRIVERS_RESET_MCHP_RESET_H_ + +#if defined(CONFIG_RESET_MCHP_RSTC_G1) +#include "mchp_rstc_g1.h" +#endif + +#endif /* INCLUDE_ZEPHYR_DRIVERS_RESET_MCHP_RESET_H_ */ diff --git a/include/zephyr/drivers/reset/mchp_rstc_g1.h b/include/zephyr/drivers/reset/mchp_rstc_g1.h new file mode 100644 index 0000000000000..174fca359c921 --- /dev/null +++ b/include/zephyr/drivers/reset/mchp_rstc_g1.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file mchp_rstc_g1.h + * @brief Microchip RSTC G1 reset controller header + * + * This header includes the Microchip RSTC G1 macro definitions. + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_RESET_MCHP_RSTC_G1_H_ +#define INCLUDE_ZEPHYR_DRIVERS_RESET_MCHP_RSTC_G1_H_ + +/** + * @enum rstc_g1_rcause + * @brief Reset cause flags for Microchip RSTC G1. + * + * This enumeration defines the possible reset causes as indicated by the + * RSTC_RCAUSE register in the Microchip RSTC G1 reset controller. + */ +enum rstc_g1_rcause { + RSTC_G1_RCAUSE_POR = 0, /* Power-on Reset */ + RSTC_G1_RCAUSE_BOD12 = 1, /* Brown-Out 1.2V Detector Reset */ + RSTC_G1_RCAUSE_BOD33 = 2, /* Brown-Out 3.3V Detector Reset */ + RSTC_G1_RCAUSE_NVM = 3, /* NVM Reset */ + RSTC_G1_RCAUSE_EXT = 4, /* External Reset */ + RSTC_G1_RCAUSE_WDT = 5, /* Watchdog Reset */ + RSTC_G1_RCAUSE_SYST = 6, /* System Reset Request */ + RSTC_G1_RCAUSE_BACKUP = 7 /* Backup Reset */ +}; + +#endif /* INCLUDE_ZEPHYR_DRIVERS_RESET_MCHP_RSTC_G1_H_ */ From bf86f2ce19bac995dc601db4491189cf2101c8bd Mon Sep 17 00:00:00 2001 From: Farsin NASAR V A - I78438 Date: Fri, 10 Oct 2025 17:13:46 +0530 Subject: [PATCH 017/397] boards: microchip: sam_e54_xpro: add RESET to supported list Update sam_e54_xpro.yml to include RESET in the supported modules list. Signed-off-by: Farsin NASAR V A - I78438 --- boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml index d349dbd338489..7c608e61f1647 100644 --- a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml @@ -11,6 +11,7 @@ flash: 1024 ram: 256 supported: - pinctrl + - reset - shell - uart vendor: microchip From d557a0ec72b3d53641b4641ee4166c1ec46e8989 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Tue, 14 Oct 2025 12:02:20 -0500 Subject: [PATCH 018/397] boards: mcx_n5xx_evk: Add jlink runner Add jlink runner arguments for mcxn5xxevk Signed-off-by: Declan Snyder --- boards/nxp/mcx_nx4x_evk/board.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/nxp/mcx_nx4x_evk/board.cmake b/boards/nxp/mcx_nx4x_evk/board.cmake index e31e7eacb36be..4abf13fd95a84 100644 --- a/boards/nxp/mcx_nx4x_evk/board.cmake +++ b/boards/nxp/mcx_nx4x_evk/board.cmake @@ -28,6 +28,7 @@ elseif(CONFIG_SOC_MCXN947_CPU1) board_runner_args(linkserver "--device=MCXN947:MCX-N9XX-EVK") board_runner_args(linkserver "--core=cm33_core1") elseif(CONFIG_SOC_MCXN547_CPU0) + board_runner_args(jlink "--device=MCXN547_M33_0" "--reset-after-load") board_runner_args(linkserver "--device=MCXN547:MCX-N5XX-EVK") endif() From f67d76f984ebd3ae20d53296e30c32c2879a70fa Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 9 Oct 2025 14:06:11 +0200 Subject: [PATCH 019/397] drivers: flash: stm32: test HAL functions return value Add missing test of some HAL fnuctions return value. Signed-off-by: Etienne Carriere --- drivers/flash/flash_stm32_qspi.c | 14 ++++++++++---- drivers/flash/flash_stm32_xspi.c | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 1c0c0c9614492..83b945cc93b27 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -1596,7 +1596,9 @@ static int flash_stm32_qspi_init(const struct device *dev) /* Initialize DMA HAL */ __HAL_LINKDMA(&dev_data->hqspi, hdma, hdma); - HAL_DMA_Init(&hdma); + if (HAL_DMA_Init(&hdma) != HAL_OK) { + return -EIO; + } #endif /* STM32_QSPI_USE_DMA */ @@ -1643,7 +1645,9 @@ static int flash_stm32_qspi_init(const struct device *dev) dev_data->hqspi.Init.FlashID = QSPI_FLASH_ID_1; #endif /* STM32_QSPI_DOUBLE_FLASH */ - HAL_QSPI_Init(&dev_data->hqspi); + if (HAL_QSPI_Init(&dev_data->hqspi) != HAL_OK) { + return -EIO; + } #if DT_NODE_HAS_PROP(DT_NODELABEL(quadspi), flash_id) && \ defined(QUADSPI_CR_FSEL) @@ -1653,8 +1657,10 @@ static int flash_stm32_qspi_init(const struct device *dev) */ uint8_t qspi_flash_id = DT_PROP(DT_NODELABEL(quadspi), flash_id); - HAL_QSPI_SetFlashID(&dev_data->hqspi, - (qspi_flash_id - 1) << QUADSPI_CR_FSEL_Pos); + if (HAL_QSPI_SetFlashID(&dev_data->hqspi, + (qspi_flash_id - 1) << QUADSPI_CR_FSEL_Pos) != HAL_OK) { + return -EIO; + } #endif /* Initialize semaphores */ k_sem_init(&dev_data->sem, 1, 1); diff --git a/drivers/flash/flash_stm32_xspi.c b/drivers/flash/flash_stm32_xspi.c index fa8849e81f35f..75a5a151921a5 100644 --- a/drivers/flash/flash_stm32_xspi.c +++ b/drivers/flash/flash_stm32_xspi.c @@ -390,7 +390,9 @@ static int stm32_xspi_wait_auto_polling(const struct device *dev, if (k_sem_take(&dev_data->sync, K_MSEC(timeout_ms)) != 0) { LOG_ERR("XSPI AutoPoll wait failed"); - HAL_XSPI_Abort(&dev_data->hxspi); + if (HAL_XSPI_Abort(&dev_data->hxspi) != HAL_OK) { + LOG_ERR("XSPI abort failed"); + } k_sem_reset(&dev_data->sync); return -EIO; } From a04923f06cd31a6d34ee865ab165d1e1bf838e3f Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 9 Oct 2025 13:59:41 +0200 Subject: [PATCH 020/397] drivers: eeprom: stm32: don't mix HAL return value and errno Correct eeprom_stm32_write() to return a valid errno instead of mixing HAL return values and errno return values. Clarify HAL return value is of type HAL_StatusTypeDef and not an int in eeprom_stm32_read(). Remove printing of HAL_FLASHEx_DATAEEPROM_Lock() error code since not very useful. Signed-off-by: Etienne Carriere --- drivers/eeprom/eeprom_stm32.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/eeprom/eeprom_stm32.c b/drivers/eeprom/eeprom_stm32.c index a3288fe3dc6de..73dc1bda95522 100644 --- a/drivers/eeprom/eeprom_stm32.c +++ b/drivers/eeprom/eeprom_stm32.c @@ -57,7 +57,7 @@ static int eeprom_stm32_write(const struct device *dev, off_t offset, { const struct eeprom_stm32_config *config = dev->config; const uint8_t *pbuf = buf; - HAL_StatusTypeDef ret = HAL_OK; + HAL_StatusTypeDef hal_ret; if (!len) { return 0; @@ -73,14 +73,13 @@ static int eeprom_stm32_write(const struct device *dev, off_t offset, HAL_FLASHEx_DATAEEPROM_Unlock(); while (len) { - ret = HAL_FLASHEx_DATAEEPROM_Program( - FLASH_TYPEPROGRAMDATA_BYTE, - config->addr + offset, *pbuf); - if (ret) { - LOG_ERR("failed to write to EEPROM (err %d)", ret); + hal_ret = HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, + config->addr + offset, *pbuf); + if (hal_ret != HAL_OK) { + LOG_ERR("failed to write to EEPROM (err %d)", hal_ret); HAL_FLASHEx_DATAEEPROM_Lock(); k_mutex_unlock(&lock); - return ret; + return -EIO; } pbuf++; @@ -88,14 +87,16 @@ static int eeprom_stm32_write(const struct device *dev, off_t offset, len--; } - ret = HAL_FLASHEx_DATAEEPROM_Lock(); - if (ret) { - LOG_ERR("failed to lock EEPROM (err %d)", ret); - } + hal_ret = HAL_FLASHEx_DATAEEPROM_Lock(); k_mutex_unlock(&lock); - return ret; + if (hal_ret != HAL_OK) { + LOG_ERR("failed to lock EEPROM"); + return -EIO; + } + + return 0; } static size_t eeprom_stm32_size(const struct device *dev) From 6bd09fd75e6f6633634dcffc79ea44e3f822e8f3 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Oct 2025 20:05:09 +0200 Subject: [PATCH 021/397] drivers: eeprom: stm32: test HAL return value Add missing test of HAL_FLASHEx_DATAEEPROM_Unlock() return value. By the way, add a error trace message when failing to relock the EEPROM after we failed to program it. Signed-off-by: Etienne Carriere --- drivers/eeprom/eeprom_stm32.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/eeprom/eeprom_stm32.c b/drivers/eeprom/eeprom_stm32.c index 73dc1bda95522..076b547279fb5 100644 --- a/drivers/eeprom/eeprom_stm32.c +++ b/drivers/eeprom/eeprom_stm32.c @@ -70,16 +70,21 @@ static int eeprom_stm32_write(const struct device *dev, off_t offset, k_mutex_lock(&lock, K_FOREVER); - HAL_FLASHEx_DATAEEPROM_Unlock(); + hal_ret = HAL_FLASHEx_DATAEEPROM_Unlock(); + if (hal_ret != HAL_OK) { + LOG_ERR("failed to unlock to EEPROM"); + goto out; + } while (len) { hal_ret = HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, config->addr + offset, *pbuf); if (hal_ret != HAL_OK) { LOG_ERR("failed to write to EEPROM (err %d)", hal_ret); - HAL_FLASHEx_DATAEEPROM_Lock(); - k_mutex_unlock(&lock); - return -EIO; + if (HAL_FLASHEx_DATAEEPROM_Lock() != HAL_OK) { + LOG_ERR("failed to lock to EEPROM"); + } + goto out; } pbuf++; @@ -88,11 +93,14 @@ static int eeprom_stm32_write(const struct device *dev, off_t offset, } hal_ret = HAL_FLASHEx_DATAEEPROM_Lock(); + if (hal_ret != HAL_OK) { + LOG_ERR("failed to lock EEPROM"); + } +out: k_mutex_unlock(&lock); if (hal_ret != HAL_OK) { - LOG_ERR("failed to lock EEPROM"); return -EIO; } From 9dce4eaf049004c67f43197e9348875bff027c22 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 9 Oct 2025 11:03:41 +0200 Subject: [PATCH 022/397] drivers: disk: sdmmc_stm32: don't mix HAL return values and error Ensure STM32 SDMMC driver returns proper errno values and not HAL return codes. Signed-off-by: Etienne Carriere --- drivers/disk/sdmmc_stm32.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/disk/sdmmc_stm32.c b/drivers/disk/sdmmc_stm32.c index 0fc94d1e2e7d5..98532d01d9acd 100644 --- a/drivers/disk/sdmmc_stm32.c +++ b/drivers/disk/sdmmc_stm32.c @@ -449,9 +449,11 @@ static int stm32_sdmmc_access_init(struct disk_info *disk) static int stm32_sdmmc_access_deinit(struct stm32_sdmmc_priv *priv) { - int err = 0; + HAL_StatusTypeDef hal_ret; #if STM32_SDMMC_USE_DMA + int err; + err = stm32_sdmmc_dma_deinit(priv); if (err) { LOG_ERR("DMA deinit failed"); @@ -460,14 +462,14 @@ static int stm32_sdmmc_access_deinit(struct stm32_sdmmc_priv *priv) #endif #if defined(CONFIG_SDMMC_STM32_EMMC) - err = HAL_MMC_DeInit(&priv->hsd); + hal_ret = HAL_MMC_DeInit(&priv->hsd); #else - err = HAL_SD_DeInit(&priv->hsd); + hal_ret = HAL_SD_DeInit(&priv->hsd); stm32_sdmmc_clock_disable(priv); #endif - if (err != HAL_OK) { + if (hal_ret != HAL_OK) { LOG_ERR("failed to deinit stm32_sdmmc (ErrorCode 0x%X)", priv->hsd.ErrorCode); - return err; + return -EIO; } #if !defined(CONFIG_SDMMC_STM32_EMMC) From f3a150f90e671cfeb38c3082fbb6fc8266d8806c Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Fri, 10 Oct 2025 11:49:15 +0200 Subject: [PATCH 023/397] drivers: disk: sdmmc_stm32: don't assume HAL return value is an int Clarify HAL return value is of type HAL_StatusTypeDef and may not be a int. This change aims preventing one from mixing standard "errno" int return values and STM32 HAL return value finding misleading implementation in existing code. No functional change. Signed-off-by: Etienne Carriere --- drivers/disk/sdmmc_stm32.c | 73 +++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/drivers/disk/sdmmc_stm32.c b/drivers/disk/sdmmc_stm32.c index 98532d01d9acd..a562cf909d2bb 100644 --- a/drivers/disk/sdmmc_stm32.c +++ b/drivers/disk/sdmmc_stm32.c @@ -361,6 +361,7 @@ static int stm32_sdmmc_access_init(struct disk_info *disk) { const struct device *dev = disk->dev; struct stm32_sdmmc_priv *priv = dev->data; + HAL_StatusTypeDef hal_ret; int err; err = stm32_sdmmc_pwr_on(priv); @@ -412,11 +413,11 @@ static int stm32_sdmmc_access_init(struct disk_info *disk) } #ifdef CONFIG_SDMMC_STM32_EMMC - err = HAL_MMC_Init(&priv->hsd); + hal_ret = HAL_MMC_Init(&priv->hsd); #else - err = HAL_SD_Init(&priv->hsd); + hal_ret = HAL_SD_Init(&priv->hsd); #endif - if (err != HAL_OK) { + if (hal_ret != HAL_OK) { LOG_ERR("failed to init stm32_sdmmc (ErrorCode 0x%X)", priv->hsd.ErrorCode); err = -EIO; goto error; @@ -424,8 +425,8 @@ static int stm32_sdmmc_access_init(struct disk_info *disk) if (SDMMC_BUS_WIDTH != SDMMC_BUS_WIDE_1B) { priv->hsd.Init.BusWide = SDMMC_BUS_WIDTH; - err = HAL_SD_ConfigWideBusOperation(&priv->hsd, priv->hsd.Init.BusWide); - if (err != HAL_OK) { + hal_ret = HAL_SD_ConfigWideBusOperation(&priv->hsd, priv->hsd.Init.BusWide); + if (hal_ret != HAL_OK) { LOG_ERR("failed to configure wide bus operation (ErrorCode 0x%X)", priv->hsd.ErrorCode); err = -EIO; @@ -501,23 +502,32 @@ static int stm32_sdmmc_is_card_in_transfer(HandleTypeDef *hsd) static int stm32_sdmmc_read_blocks(HandleTypeDef *hsd, uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector) { + HAL_StatusTypeDef hal_ret; + #if STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma)) #ifdef CONFIG_SDMMC_STM32_EMMC - return HAL_MMC_ReadBlocks_DMA(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_MMC_ReadBlocks_DMA(hsd, data_buf, start_sector, num_sector); #else - return HAL_SD_ReadBlocks_DMA(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_SD_ReadBlocks_DMA(hsd, data_buf, start_sector, num_sector); #endif -#else +#else /* STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma)) */ #ifdef CONFIG_SDMMC_STM32_EMMC - return HAL_MMC_ReadBlocks_IT(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_MMC_ReadBlocks_IT(hsd, data_buf, start_sector, num_sector); #else - return HAL_SD_ReadBlocks_IT(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_SD_ReadBlocks_IT(hsd, data_buf, start_sector, num_sector); #endif -#endif +#endif /* STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma)) */ + + if (hal_ret != HAL_OK) { + LOG_ERR("sd read block failed %d", hal_ret); + return -EIO; + } + + return 0; } static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf, @@ -539,9 +549,7 @@ static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf, #endif err = stm32_sdmmc_read_blocks(&priv->hsd, data_buf, start_sector, num_sector); - if (err != HAL_OK) { - LOG_ERR("sd read block failed %d", err); - err = -EIO; + if (err != 0) { goto end; } @@ -569,23 +577,32 @@ static int stm32_sdmmc_write_blocks(HandleTypeDef *hsd, uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector) { + HAL_StatusTypeDef hal_ret; + #if STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma)) #ifdef CONFIG_SDMMC_STM32_EMMC - return HAL_MMC_WriteBlocks_DMA(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_MMC_WriteBlocks_DMA(hsd, data_buf, start_sector, num_sector); #else - return HAL_SD_WriteBlocks_DMA(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_SD_WriteBlocks_DMA(hsd, data_buf, start_sector, num_sector); #endif -#else +#else /* STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma)) */ #ifdef CONFIG_SDMMC_STM32_EMMC - return HAL_MMC_WriteBlocks_IT(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_MMC_WriteBlocks_IT(hsd, data_buf, start_sector, num_sector); #else - return HAL_SD_WriteBlocks_IT(hsd, data_buf, start_sector, num_sector); + hal_ret = HAL_SD_WriteBlocks_IT(hsd, data_buf, start_sector, num_sector); #endif -#endif +#endif /* STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma)) */ + + if (hal_ret != HAL_OK) { + LOG_ERR("sd write block failed %d", hal_ret); + return -EIO; + } + + return 0; } static int stm32_sdmmc_access_write(struct disk_info *disk, @@ -608,9 +625,7 @@ static int stm32_sdmmc_access_write(struct disk_info *disk, #endif err = stm32_sdmmc_write_blocks(&priv->hsd, (uint8_t *)data_buf, start_sector, num_sector); - if (err != HAL_OK) { - LOG_ERR("sd write block failed %d", err); - err = -EIO; + if (err != 0) { goto end; } @@ -637,9 +652,9 @@ static int stm32_sdmmc_access_write(struct disk_info *disk, static int stm32_sdmmc_get_card_info(HandleTypeDef *hsd, CardInfoTypeDef *info) { #ifdef CONFIG_SDMMC_STM32_EMMC - return HAL_MMC_GetCardInfo(hsd, info); + return (HAL_MMC_GetCardInfo(hsd, info) == HAL_OK) ? 0 : -EIO; #else - return HAL_SD_GetCardInfo(hsd, info); + return (HAL_SD_GetCardInfo(hsd, info) == HAL_OK) ? 0 : -EIO; #endif } @@ -654,15 +669,15 @@ static int stm32_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd, switch (cmd) { case DISK_IOCTL_GET_SECTOR_COUNT: err = stm32_sdmmc_get_card_info(&priv->hsd, &info); - if (err != HAL_OK) { - return -EIO; + if (err != 0) { + return err; } *(uint32_t *)buff = info.LogBlockNbr; break; case DISK_IOCTL_GET_SECTOR_SIZE: err = stm32_sdmmc_get_card_info(&priv->hsd, &info); - if (err != HAL_OK) { - return -EIO; + if (err != 0) { + return err; } *(uint32_t *)buff = info.LogBlockSize; break; From 9e63215bb4d6721982ff6f00c8c94ce05cfbefeb Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 9 Oct 2025 11:04:57 +0200 Subject: [PATCH 024/397] drivers: disk: sdmmc_stm32: test HAL init/deinit return values Add tests of the value returned by initialization and deinitialization HAL functions. Signed-off-by: Etienne Carriere --- drivers/disk/sdmmc_stm32.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/disk/sdmmc_stm32.c b/drivers/disk/sdmmc_stm32.c index a562cf909d2bb..38ae227de6117 100644 --- a/drivers/disk/sdmmc_stm32.c +++ b/drivers/disk/sdmmc_stm32.c @@ -300,7 +300,9 @@ static int stm32_sdmmc_dma_init(struct stm32_sdmmc_priv *priv) return err; } __HAL_LINKDMA(&priv->hsd, hdmatx, priv->dma_tx_handle); - HAL_DMA_Init(&priv->dma_tx_handle); + if (HAL_DMA_Init(&priv->dma_tx_handle) != HAL_OK) { + return -EIO; + } err = stm32_sdmmc_configure_dma(&priv->dma_rx_handle, &priv->dma_rx); if (err) { @@ -308,7 +310,9 @@ static int stm32_sdmmc_dma_init(struct stm32_sdmmc_priv *priv) return err; } __HAL_LINKDMA(&priv->hsd, hdmarx, priv->dma_rx_handle); - HAL_DMA_Init(&priv->dma_rx_handle); + if (HAL_DMA_Init(&priv->dma_rx_handle) != HAL_OK) { + return -EIO; + } #endif /* STM32_SDMMC_USE_DMA_SHARED */ return err; @@ -332,14 +336,17 @@ static int stm32_sdmmc_dma_deinit(struct stm32_sdmmc_priv *priv) #else struct sdmmc_dma_stream *dma_tx = &priv->dma_tx; struct sdmmc_dma_stream *dma_rx = &priv->dma_rx; + HAL_StatusTypeDef __maybe_unused hal_ret; ret = dma_stop(dma_tx->dev, dma_tx->channel); __ASSERT(ret == 0, "TX DMA channel index corrupted"); - HAL_DMA_DeInit(&priv->dma_tx_handle); + hal_ret = HAL_DMA_DeInit(&priv->dma_tx_handle); + __ASSERT_NO_MSG(hal_ret == HAL_OK); ret = dma_stop(dma_rx->dev, dma_rx->channel); __ASSERT(ret == 0, "RX DMA channel index corrupted"); - HAL_DMA_DeInit(&priv->dma_rx_handle); + hal_ret = HAL_DMA_DeInit(&priv->dma_rx_handle); + __ASSERT_NO_MSG(hal_ret == HAL_OK); #endif return 0; } @@ -556,7 +563,10 @@ static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf, k_sem_take(&priv->sync, K_FOREVER); #if STM32_SDMMC_USE_DMA_SHARED - HAL_DMA_DeInit(&priv->dma_txrx_handle); + if (HAL_DMA_DeInit(&priv->dma_txrx_handle) != HAL_OK) { + err = -EIO; + goto end; + } #endif if (priv->status != DISK_STATUS_OK) { @@ -632,7 +642,11 @@ static int stm32_sdmmc_access_write(struct disk_info *disk, k_sem_take(&priv->sync, K_FOREVER); #if STM32_SDMMC_USE_DMA_SHARED - HAL_DMA_DeInit(&priv->dma_txrx_handle); + if (HAL_DMA_DeInit(&priv->dma_txrx_handle) != HAL_OK) { + LOG_ERR("DMA deinit error"); + err = -EIO; + goto end; + } #endif if (priv->status != DISK_STATUS_OK) { From 53a768d029b6b0e596fd8735d03c2e9ed9768c49 Mon Sep 17 00:00:00 2001 From: Tim Pambor Date: Mon, 6 Oct 2025 17:57:32 +0200 Subject: [PATCH 025/397] drivers: ethernet: adin1100: add support for hardware reset Add support for hardware reset via GPIO in the ADIN1100 PHY driver. The reset pin is configured via device tree using the reset-gpios property. Signed-off-by: Tim Pambor --- drivers/ethernet/phy/Kconfig | 1 + drivers/ethernet/phy/phy_adin2111.c | 47 +++++++++++++++++++ .../ethernet/phy/adi,adin1100-phy.yaml | 5 ++ 3 files changed, 53 insertions(+) diff --git a/drivers/ethernet/phy/Kconfig b/drivers/ethernet/phy/Kconfig index 5cb3b336499e5..80924322fa125 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -42,6 +42,7 @@ config PHY_ADIN2111 default y depends on DT_HAS_ADI_ADIN2111_PHY_ENABLED || DT_HAS_ADI_ADIN1100_PHY_ENABLED select MDIO + select GPIO if $(dt_compat_any_has_prop,$(DT_COMPAT_ADI_ADIN1100_PHY),reset-gpios) help Enable ADIN2111 PHY driver. diff --git a/drivers/ethernet/phy/phy_adin2111.c b/drivers/ethernet/phy/phy_adin2111.c index 8ba0023fd2499..411f5673254d2 100644 --- a/drivers/ethernet/phy/phy_adin2111.c +++ b/drivers/ethernet/phy/phy_adin2111.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,8 @@ LOG_MODULE_REGISTER(phy_adin, CONFIG_PHY_LOG_LEVEL); /* Software reset, CLK_25 disabled time*/ #define ADIN1100_PHY_SFT_RESET_MS 25U +#define ADIN1100_PHY_HRD_RESET_MS 70U +#define ADIN1100_PHY_HRD_RESET_PULSE_WIDTH_US 16U /* PHYs autonegotiation complete timeout */ #define ADIN2111_AN_COMPLETE_AWAIT_TIMEOUT_MS 3000U @@ -90,6 +93,9 @@ LOG_MODULE_REGISTER(phy_adin, CONFIG_PHY_LOG_LEVEL); struct phy_adin2111_config { const struct device *mdio; +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(adi_adin1100_phy, reset_gpios) + const struct gpio_dt_spec reset_gpio; +#endif /* DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(adi_adin1100_phy, reset_gpios) */ uint8_t phy_addr; bool led0_en; bool led1_en; @@ -352,6 +358,30 @@ static int phy_adin2111_reset(const struct device *dev) { int ret; +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(adi_adin1100_phy, reset_gpios) + const struct phy_adin2111_config *config = dev->config; + + if (config->reset_gpio.port != NULL) { + /* Assert reset (min. reset pulse width 10us) */ + ret = gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret < 0) { + return ret; + } + k_busy_wait(ADIN1100_PHY_HRD_RESET_PULSE_WIDTH_US); + + /* Deassert reset */ + ret = gpio_pin_set_dt(&config->reset_gpio, 0); + if (ret < 0) { + return ret; + } + + k_msleep(ADIN1100_PHY_HRD_RESET_MS); + + return 0; + } +#endif /* DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(adi_adin1100_phy, reset_gpios) */ + + /* Perform software reset */ ret = phy_adin2111_c22_write(dev, MII_BMCR, MII_BMCR_RESET); if (ret < 0) { return ret; @@ -439,6 +469,15 @@ static int phy_adin2111_init(const struct device *dev) data->state.is_up = false; data->state.speed = LINK_FULL_10BASE; +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(adi_adin1100_phy, reset_gpios) + if (cfg->reset_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + return ret; + } + } +#endif /* DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(adi_adin1100_phy, reset_gpios) */ + /* * For adin1100 and further mii stuff, * reset may not be performed from the mac layer, doing a clean reset here. @@ -617,9 +656,17 @@ static DEVICE_API(ethphy, phy_adin2111_api) = { .write = phy_adin2111_reg_write, }; +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(adi_adin1100_phy, reset_gpios) +#define RESET_GPIO(n) \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), +#else +#define RESET_GPIO(n) +#endif /* reset gpio */ + #define ADIN2111_PHY_INITIALIZE(n, model) \ static const struct phy_adin2111_config phy_adin##model##_config_##n = { \ .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \ + RESET_GPIO(n) \ .phy_addr = DT_INST_REG_ADDR(n), \ .led0_en = DT_INST_PROP(n, led0_en), \ .led1_en = DT_INST_PROP(n, led1_en), \ diff --git a/dts/bindings/ethernet/phy/adi,adin1100-phy.yaml b/dts/bindings/ethernet/phy/adi,adin1100-phy.yaml index c8613bcb90212..c3cfe7e044dc0 100644 --- a/dts/bindings/ethernet/phy/adi,adin1100-phy.yaml +++ b/dts/bindings/ethernet/phy/adi,adin1100-phy.yaml @@ -7,3 +7,8 @@ description: ADIN1100 PHY compatible: "adi,adin1100-phy" include: adi,adin2111-phy.yaml + +properties: + reset-gpios: + type: phandle-array + description: GPIO connected to PHY reset signal pin. Reset is active low. From 3d569c63eb2e077b988d2f6b15708c8fe143384c Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 4 Oct 2025 20:33:11 +1000 Subject: [PATCH 026/397] modem: modem_cellular: comms check result callback Add a callback for the periodic script result so that applications have a way of detecting dead links. Signed-off-by: Jordan Yates --- doc/releases/release-notes-4.3.rst | 4 ++++ drivers/modem/modem_cellular.c | 4 ++++ include/zephyr/drivers/cellular.h | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index 72d51e066511e..747c1ed15544b 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -146,6 +146,10 @@ New APIs and options * :kconfig:option:`CONFIG_CPU_FREQ` +* Cellular + + * :c:enumerator:`CELLULAR_EVENT_MODEM_COMMS_CHECK_RESULT` + * Crypto * :kconfig:option:`CONFIG_MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS` diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index 31c28533bf3f9..dc4c8cb53e738 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -1391,11 +1391,15 @@ static void modem_cellular_carrier_on_event_handler(struct modem_cellular_data * { const struct modem_cellular_config *config = (const struct modem_cellular_config *)data->dev->config; + struct cellular_evt_modem_comms_check_result result; switch (evt) { case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS: case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: + result.success = evt == MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS; + modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); + modem_cellular_emit_event(data, CELLULAR_EVENT_MODEM_COMMS_CHECK_RESULT, &result); break; case MODEM_CELLULAR_EVENT_TIMEOUT: diff --git a/include/zephyr/drivers/cellular.h b/include/zephyr/drivers/cellular.h index 967d53e89b409..ba78207a340c1 100644 --- a/include/zephyr/drivers/cellular.h +++ b/include/zephyr/drivers/cellular.h @@ -139,6 +139,8 @@ enum cellular_event { CELLULAR_EVENT_MODEM_INFO_CHANGED = BIT(0), /** Cellular network registration status changed */ CELLULAR_EVENT_REGISTRATION_STATUS_CHANGED = BIT(1), + /** Result of a communications link check to the modem */ + CELLULAR_EVENT_MODEM_COMMS_CHECK_RESULT = BIT(2), }; /* Opaque bit-mask large enough for all current & future events */ @@ -154,6 +156,11 @@ struct cellular_evt_registration_status { enum cellular_registration_status status; /**< New registration status */ }; +/** Payload for @ref CELLULAR_EVENT_MODEM_COMMS_CHECK_RESULT */ +struct cellular_evt_modem_comms_check_result { + bool success; /**< Communications to modem checked successfully */ +}; + /** * @brief Prototype for cellular event callbacks. * From 042bc8a648ffc1d22b334743d94ea7cbbeb0d86d Mon Sep 17 00:00:00 2001 From: Tom Chang Date: Thu, 9 Oct 2025 17:10:36 +0800 Subject: [PATCH 027/397] driver: peci: npcx: prevent sleep during PECI transactions This commit prevents enter deep sleep mode during PECI transactions since clocks if PECI will stop. Signed-off-by: Tom Chang Signed-off-by: Mulin Chao --- drivers/peci/peci_npcx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/peci/peci_npcx.c b/drivers/peci/peci_npcx.c index 24e3f1d4bac60..9a0518a6c21e1 100644 --- a/drivers/peci/peci_npcx.c +++ b/drivers/peci/peci_npcx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -141,6 +142,12 @@ static int peci_npcx_transfer(const struct device *dev, struct peci_msg *msg) enum peci_command_code cmd_code = msg->cmd_code; int ret = 0; + /* + * suspend-to-idle stops PECI module clocks (derived from APB2), which + * must remain active during a transaction + */ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + k_sem_take(&data->lock, K_FOREVER); if (peci_tx_buf->len > PECI_NPCX_MAX_TX_BUF_LEN || @@ -194,6 +201,7 @@ static int peci_npcx_transfer(const struct device *dev, struct peci_msg *msg) out: k_sem_give(&data->lock); + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); return ret; } From 47796d80ad49b9e7d45a838e516f04298b75f1fa Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 15:18:44 +0200 Subject: [PATCH 028/397] drivers: usb: udc: stm32: fix N6 power-up sequence logic Actually do what the comment says and wait for Vdd33USB to be ready, instead of waiting for the opposite. Signed-off-by: Mathieu Choplain --- drivers/usb/udc/udc_stm32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index de57cabb2f788..d7a3db7ca5fe8 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -1258,10 +1258,10 @@ static int priv_clock_enable(void) } #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) */ #elif defined(CONFIG_SOC_SERIES_STM32N6X) - /* Enable Vdd USB voltage monitoring */ + /* Enable Vdd33USB voltage monitoring */ LL_PWR_EnableVddUSBMonitoring(); - while (__HAL_PWR_GET_FLAG(PWR_FLAG_USB33RDY)) { - /* Wait FOR VDD33USB ready */ + while (!LL_PWR_IsActiveFlag_USB33RDY()) { + /* Wait for Vdd33USB ready */ } /* Enable VDDUSB */ From feaa74c16e2c1a5b33b6c69824295965df0d8926 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 15:19:17 +0200 Subject: [PATCH 029/397] drivers: usb: device: stm32: fix N6 power-up sequence logic Actually do what the comment says and wait for Vdd33USB to be ready, instead of waiting for the opposite. Signed-off-by: Mathieu Choplain --- drivers/usb/device/usb_dc_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index ea560ad751a4e..0d90f93dc583c 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -349,7 +349,7 @@ static int usb_dc_stm32_phy_specific_clock_enable(const struct device *const clk #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32n6_otghs) /* Enable Vdd USB voltage monitoring */ LL_PWR_EnableVddUSBMonitoring(); - while (__HAL_PWR_GET_FLAG(PWR_FLAG_USB33RDY)) { + while (!__HAL_PWR_GET_FLAG(PWR_FLAG_USB33RDY)) { /* Wait for VDD33USB ready */ } /* Enable VDDUSB */ From ba3275f013dbfa8266998c729c7f3c74617fd925 Mon Sep 17 00:00:00 2001 From: Tomas Pajurek Date: Fri, 17 Oct 2025 14:50:21 +0200 Subject: [PATCH 030/397] Debugging: Fix GDB packet parsing for ARM Cortex M When analyzing Zephyr coredumps from ARM Cortex M, sometimes the GDB server fails with the error 'binascii.Error: Odd-length string'. This happens because the GDB packet parsing logic does not correctly handle the '=' separator in register write packets containing register identifiers with more than one letter/digit. Fix it by properly locating the '=' character and slicing the packet string accordingly. Signed-off-by: Tomas Pajurek --- scripts/coredump/gdbstubs/arch/arm_cortex_m.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/coredump/gdbstubs/arch/arm_cortex_m.py b/scripts/coredump/gdbstubs/arch/arm_cortex_m.py index 02cdac598ff9b..3a7f1cbd91fb7 100644 --- a/scripts/coredump/gdbstubs/arch/arm_cortex_m.py +++ b/scripts/coredump/gdbstubs/arch/arm_cortex_m.py @@ -115,8 +115,13 @@ def handle_register_single_read_packet(self, pkt): def handle_register_single_write_packet(self, pkt): pkt_str = pkt.decode("ascii") - reg = int(pkt_str[1:pkt_str.index('=')], 16) - self.registers[reg] = int.from_bytes(binascii.unhexlify(pkt[3:]), byteorder = 'little') + separator_index = pkt_str.index('=') + + if separator_index < 0: + raise ValueError(f"Malformed register write packet: {pkt_str}") + + reg = int(pkt_str[1:separator_index], 16) + self.registers[reg] = int.from_bytes(binascii.unhexlify(pkt[(separator_index + 1):]), byteorder = 'little') self.put_gdb_packet(b'+') def arch_supports_thread_operations(self): From 5194114817011bf9af6d67b50eb4278b30356350 Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Fri, 17 Oct 2025 13:38:33 +0200 Subject: [PATCH 031/397] drivers: entropy: gecko_trng: Ensure bus clock is enabled Ensure bus clock is enabled before accessing TRNG FIFO on Series 2 VSE devices. This is a minimal bugfix to work around an issue where certain HAL APIs disable the bus clock after accessing the crypto block. Long term, this driver should be rewritten to properly use clock control APIs for clock management. Signed-off-by: Aksel Skauge Mellbye --- drivers/entropy/entropy_gecko_trng.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/entropy/entropy_gecko_trng.c b/drivers/entropy/entropy_gecko_trng.c index 68b8833b49506..8eda146c52ef9 100644 --- a/drivers/entropy/entropy_gecko_trng.c +++ b/drivers/entropy/entropy_gecko_trng.c @@ -80,6 +80,7 @@ static int entropy_gecko_trng_get_entropy(const struct device *dev, #ifndef CONFIG_CRYPTO_ACC_GECKO_TRNG available = TRNG0->FIFOLEVEL * 4; #else + CMU_ClockEnable(cmuClock_CRYPTOACC, true); available = S2_FIFO_LEVEL * 4; #endif if (available == 0) { @@ -107,6 +108,7 @@ static int entropy_gecko_trng_get_entropy_isr(const struct device *dev, #ifndef CONFIG_CRYPTO_ACC_GECKO_TRNG size_t available = TRNG0->FIFOLEVEL * 4; #else + CMU_ClockEnable(cmuClock_CRYPTOACC, true); size_t available = S2_FIFO_LEVEL * 4; #endif From 9ac1c9d6bdf36dd2a3b4f3c98d34f3ef34597c5e Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 13:18:37 +0200 Subject: [PATCH 032/397] drivers: usb: udc: stm32: fix FS mode on OTG_FS for STM32F4 series On most parts of the STM32F4 series, when the OTG_HS controller is used in FS mode, the ULIP **low-power** clock must also be disabled for proper operation. This was done properly in an old version of the driver but was lost as part of refactoring[1]. Re-introduce ULPI low-power clock disable when OTG_HS is used in FS mode. [1] See commit e31ddec7812b68c11bd4490884e3e98b55c57469 Signed-off-by: Mathieu Choplain --- drivers/usb/udc/udc_stm32.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index d7a3db7ca5fe8..99e7804ebbb48 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -1366,6 +1366,13 @@ static int priv_clock_enable(void) #else /* CONFIG_SOC_SERIES_STM32F2X || CONFIG_SOC_SERIES_STM32F4X */ if (UDC_STM32_NODE_PHY_ITFACE(DT_DRV_INST(0)) == PCD_PHY_ULPI) { LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_OTGHSULPI); + } else if (UDC_STM32_NODE_SPEED(DT_DRV_INST(0)) == PCD_SPEED_HIGH_IN_FULL) { + /* + * Some parts of the STM32F4 series require the OTGHSULPILPEN to be + * cleared if the OTG_HS is used in FS mode. Disable it on all parts + * since it has no nefarious effect if performed when not required. + */ + LL_AHB1_GRP1_DisableClockLowPower(LL_AHB1_GRP1_PERIPH_OTGHSULPI); } #endif /* CONFIG_SOC_SERIES_* */ #elif defined(CONFIG_SOC_SERIES_STM32H7X) && DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) From fa3e4801bb10cc4e81fffbe64ff479e89adb28a1 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 14 Oct 2025 14:19:43 +0300 Subject: [PATCH 033/397] lib: Introduce a way to set minimum file descriptors count Instead of user trying to figure out what is the amount of file / socket descriptors in the system, let the various subsystems etc. specify their need using a Kconfig option. The build system will then add these smaller values together and set a suitable file descriptor count in the system. This works the same way as the heap size calculation introduced in commit 3fbf12487c6c01c488210bc56b0f342f07098df9 Signed-off-by: Jukka Rissanen --- include/zephyr/sys/fdtable.h | 2 +- lib/os/CMakeLists.txt | 30 ++++++++++++++++++++++++ lib/os/Kconfig | 24 +++++++++++++++---- lib/os/fdtable.c | 4 ++-- modules/hostap/Kconfig | 4 ++++ modules/nrf_wifi/Kconfig | 4 ++++ subsys/net/lib/dns/dispatcher.c | 2 +- subsys/net/lib/sockets/socket_obj_core.c | 4 ++-- 8 files changed, 63 insertions(+), 11 deletions(-) diff --git a/include/zephyr/sys/fdtable.h b/include/zephyr/sys/fdtable.h index d4153828fbb2d..676c0dc3a3745 100644 --- a/include/zephyr/sys/fdtable.h +++ b/include/zephyr/sys/fdtable.h @@ -245,7 +245,7 @@ struct zvfs_pollfd { __syscall int zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout); struct zvfs_fd_set { - uint32_t bitset[(CONFIG_ZVFS_OPEN_MAX + 31) / 32]; + uint32_t bitset[DIV_ROUND_UP(ZVFS_OPEN_SIZE, 32)]; }; /** @brief Number of file descriptors which can be added @ref zvfs_fd_set */ diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index c8c56d7e07281..7fc5f23ff4748 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -13,6 +13,36 @@ zephyr_sources( thread_entry.c ) +if(CONFIG_ZVFS_OPEN_IGNORE_MIN) + set(final_fd_size ${CONFIG_ZVFS_OPEN_MAX}) +else() + # Import all custom ZVFS_OPEN_ size requirements + import_kconfig(CONFIG_ZVFS_OPEN_ADD_SIZE_ ${DOTCONFIG} add_size_keys) + + # Calculate the sum of all "ADD_SIZE" requirements + set(add_size_sum 0) + foreach(add_size ${add_size_keys}) + math(EXPR add_size_sum "${add_size_sum} + ${${add_size}}") + endforeach() + + if(CONFIG_ZVFS_OPEN_MAX LESS "${add_size_sum}") + # Only warn if default value 0 has been modified + if(NOT CONFIG_ZVFS_OPEN_MAX EQUAL 0) + message(WARNING " + CONFIG_ZVFS_OPEN_MAX is less than requested minimum: + ${CONFIG_ZVFS_OPEN_MAX} < ${add_size_sum} + Setting the file descriptor size to ${add_size_sum}") + endif() + + set(final_fd_size ${add_size_sum}) + else() + # CONFIG_ZVFS_OPEN_MAX was greater than the sum of the requirements + set(final_fd_size ${CONFIG_ZVFS_OPEN_MAX}) + endif() +endif() + +zephyr_compile_definitions(ZVFS_OPEN_SIZE=${final_fd_size}) + zephyr_sources_ifdef(CONFIG_FDTABLE fdtable.c) zephyr_syscall_header_ifdef(CONFIG_FDTABLE ${ZEPHYR_BASE}/include/zephyr/sys/fdtable.h diff --git a/lib/os/Kconfig b/lib/os/Kconfig index bca940023c6e5..eb1433e09d1e3 100644 --- a/lib/os/Kconfig +++ b/lib/os/Kconfig @@ -12,13 +12,27 @@ config FDTABLE config ZVFS_OPEN_MAX int "Maximum number of open file descriptors" - default 24 if NRF70_ENABLE_DUAL_VIF - default 16 if WIFI_NM_WPA_SUPPLICANT - default 16 if POSIX_API - default 4 + default 0 help Maximum number of open file descriptors, this includes - files, sockets, special devices, etc. + files, sockets, special devices, etc. If subsystems + specify ZVFS_OPEN_ADD_SIZE_* options, these will be added together + and the sum will be compared to the ZVFS_OPEN_MAX value. + If the sum is greater than the ZVFS_OPEN_MAX option (even if this + has the default 0 value), then the actual file descriptor count will be + rounded up to the sum of the individual requirements (unless the + ZVFS_OPEN_IGNORE_MIN option is enabled). If the final value, after + considering both this option as well as sum of the custom + requirements, ends up being zero, then no file descriptors will be + available. + +config ZVFS_OPEN_IGNORE_MIN + bool "Ignore the minimum fd count requirement" + help + This option can be set to force setting a smaller file descriptor + count than what's specified by enabled subsystems. This can be useful + when optimizing memory usage and a more precise minimum fd count + is known for a given application. config PRINTK_SYNC bool "Serialize printk() calls" diff --git a/lib/os/fdtable.c b/lib/os/fdtable.c index be53627efca7b..25b27eca38070 100644 --- a/lib/os/fdtable.c +++ b/lib/os/fdtable.c @@ -39,10 +39,10 @@ struct fd_entry { #if defined(CONFIG_POSIX_DEVICE_IO) static const struct fd_op_vtable stdinout_fd_op_vtable; -BUILD_ASSERT(CONFIG_ZVFS_OPEN_MAX >= 3, "CONFIG_ZVFS_OPEN_MAX >= 3 for CONFIG_POSIX_DEVICE_IO"); +BUILD_ASSERT(ZVFS_OPEN_SIZE >= 3, "ZVFS_OPEN_SIZE >= 3 for CONFIG_POSIX_DEVICE_IO"); #endif /* defined(CONFIG_POSIX_DEVICE_IO) */ -static struct fd_entry fdtable[CONFIG_ZVFS_OPEN_MAX] = { +static struct fd_entry fdtable[ZVFS_OPEN_SIZE] = { #if defined(CONFIG_POSIX_DEVICE_IO) /* * Predefine entries for stdin/stdout/stderr. diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index d6ddc3eeaec77..581745d352185 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -24,6 +24,10 @@ config WIFI_NM_WPA_SUPPLICANT if WIFI_NM_WPA_SUPPLICANT +config ZVFS_OPEN_ADD_SIZE_WIFI_NM_WPA_SUPPLICANT + int "Number of socket descriptors needed by hostap" + default 12 + config WIFI_NM_WPA_SUPPLICANT_GLOBAL_HEAP bool "Use Zephyr kernel heap for Wi-Fi driver" default y diff --git a/modules/nrf_wifi/Kconfig b/modules/nrf_wifi/Kconfig index 655fce838e50a..518a068d7139c 100644 --- a/modules/nrf_wifi/Kconfig +++ b/modules/nrf_wifi/Kconfig @@ -4,4 +4,8 @@ config ZEPHYR_NRF_WIFI_MODULE bool +config ZVFS_OPEN_ADD_SIZE_NRF70_ENABLE_DUAL_VIF + int "Number of socket descriptors needed by nrf wifi driver" + default 8 + source "modules/nrf_wifi/bus/Kconfig" diff --git a/subsys/net/lib/dns/dispatcher.c b/subsys/net/lib/dns/dispatcher.c index fcaf7682fb584..9c71bc6353d8b 100644 --- a/subsys/net/lib/dns/dispatcher.c +++ b/subsys/net/lib/dns/dispatcher.c @@ -31,7 +31,7 @@ NET_BUF_POOL_DEFINE(dns_msg_pool, DNS_RESOLVER_BUF_CTR, static struct socket_dispatch_table { struct dns_socket_dispatcher *ctx; -} dispatch_table[CONFIG_ZVFS_OPEN_MAX]; +} dispatch_table[ZVFS_OPEN_SIZE]; static int dns_dispatch(struct dns_socket_dispatcher *dispatcher, int sock, struct sockaddr *addr, size_t addrlen, diff --git a/subsys/net/lib/sockets/socket_obj_core.c b/subsys/net/lib/sockets/socket_obj_core.c index 76ef0927a0a1b..7138b63fcdd42 100644 --- a/subsys/net/lib/sockets/socket_obj_core.c +++ b/subsys/net/lib/sockets/socket_obj_core.c @@ -20,8 +20,8 @@ static K_MUTEX_DEFINE(sock_obj_mutex); /* Allocate some extra socket objects so that we can track * closed sockets and get some historical statistics. */ -static struct sock_obj sock_objects[CONFIG_ZVFS_OPEN_MAX * 2] = { - [0 ... ((CONFIG_ZVFS_OPEN_MAX * 2) - 1)] = { +static struct sock_obj sock_objects[ZVFS_OPEN_SIZE * 2] = { + [0 ... ((ZVFS_OPEN_SIZE * 2) - 1)] = { .fd = -1, .init_done = false, } From 66ba8baa6aa0c58dc7ad725022f5bb61aeaae407 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 10:41:29 +0300 Subject: [PATCH 034/397] doc: migration-guide-4.3: Add entry about file descriptor table changes The file descriptor table size is now controlled by adding together the values of CONFIG_ZVFS_OPEN_ADD_SIZE_* options. Signed-off-by: Jukka Rissanen --- doc/releases/migration-guide-4.3.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/releases/migration-guide-4.3.rst b/doc/releases/migration-guide-4.3.rst index e4379d44775a3..b5a4a81afdda4 100644 --- a/doc/releases/migration-guide-4.3.rst +++ b/doc/releases/migration-guide-4.3.rst @@ -51,6 +51,15 @@ Base Libraries may include :zephyr_file:`include/zephyr/posix/posix_limits.h` for Zephyr's definitions. Some runtime-invariant values may need to be queried via :c:func:`sysconf`. +* The number of file descriptor table size and its availability is now determined by + a ``ZVFS_OPEN_SIZE`` define instead of the :kconfig:option:`CONFIG_ZVFS_OPEN_MAX` + Kconfig option. Subsystems can specify their own custom file descriptor table size + requirements by specifying Kconfig options with the prefix ``CONFIG_ZVFS_OPEN_ADD_SIZE_``. + The old Kconfig option still exists, but will be overridden if the custom requirements + are larger. To force the old Kconfig option to be used, even when its value is less + than the indicated custom requirements, a new :kconfig:option:`CONFIG_ZVFS_OPEN_IGNORE_MIN` + option has been introduced (which defaults being disabled). + Boards ****** From fbe00a73fff18e9d4dcfc219900c38c6389c55b7 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 10:43:21 +0300 Subject: [PATCH 035/397] lib: posix: device_io: Add standard file descriptor sizes Make sure we always allocate space for stdin, stdout and stderr file descriptors if Posix device io option is enabled. Signed-off-by: Jukka Rissanen --- lib/posix/options/Kconfig.device_io | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/posix/options/Kconfig.device_io b/lib/posix/options/Kconfig.device_io index 416ccf74a6218..f7d035abe8543 100644 --- a/lib/posix/options/Kconfig.device_io +++ b/lib/posix/options/Kconfig.device_io @@ -45,12 +45,17 @@ config POSIX_DEVICE_IO_ALIAS_WRITE endif # POSIX_DEVICE_IO +# Allocate fd for stdin, stdout and stderr +config ZVFS_OPEN_ADD_SIZE_POSIX + int "Amount of file descriptors used by Posix" + default 3 + config POSIX_OPEN_MAX int - default ZVFS_OPEN_MAX + default ZVFS_OPEN_ADD_SIZE_POSIX help The maximum number of files that a process can have open at one time. This option is not - directly user-configurable but can be adjusted via CONFIG_ZVFS_OPEN_MAX. + directly user-configurable but can be adjusted via CONFIG_ZVFS_OPEN_ADD_SIZE_POSIX. For more information, please see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html From 8040e4d669f854e87ef6ef896838cabe127fd220 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 10:46:10 +0300 Subject: [PATCH 036/397] samples: net: Allow app to control the amount of sockets used Create a Kconfig entry that allows the application to control how many sockets it needs. Signed-off-by: Jukka Rissanen --- samples/net/common/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/net/common/Kconfig b/samples/net/common/Kconfig index ceed53efa8692..ee55cdacfccb2 100644 --- a/samples/net/common/Kconfig +++ b/samples/net/common/Kconfig @@ -50,3 +50,8 @@ config NET_SAMPLE_COMMON_TUNNEL_MY_ADDR depends on NET_L2_IPIP help The value depends on your network setup. + +# Generic way to allocate enough sockets for the application +config ZVFS_OPEN_ADD_SIZE_NET_SAMPLE + int "Amount of sockets needed by the networking sample" + default 0 From 12071b199f9f711de4c7ed2f2f11514d73c9daf6 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 10:47:44 +0300 Subject: [PATCH 037/397] scripts: compliance: Add ZVFS_OPEN_ADD_SIZE_ to undef whitelist The ZVFS_OPEN_ADD_SIZE_ is used as a prefix for matching specific Kconfig option names, i.e. it's not a real option in itself. Signed-off-by: Jukka Rissanen --- scripts/ci/check_compliance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 025c3f085ab86..5167e568c147f 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1370,6 +1370,7 @@ def check_no_undef_outside_kconfig(self, kconf): "ZEPHYR_TRY_MASS_ERASE", # MCUBoot setting described in sysbuild # documentation "ZTEST_FAIL_TEST_", # regex in tests/ztest/fail/CMakeLists.txt + "ZVFS_OPEN_ADD_SIZE_", # Used as an option matching prefix # zephyr-keep-sorted-stop } From bbcf45b61cc53711c5a75ff8dc905131d0cb143d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 10:48:41 +0300 Subject: [PATCH 038/397] net: context: Make sure to allocate enough sockets The number of net_context now determines the minimum amount of network sockets that are to be allocated. Signed-off-by: Jukka Rissanen --- subsys/net/ip/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 463e1220e2e9d..bb6df8ebf4401 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -509,6 +509,10 @@ config NET_MAX_CONTEXTS is used when listening or sending network traffic. This is very similar as one could call a network socket in some other systems. +config ZVFS_OPEN_ADD_SIZE_NET + int "Number of network sockets to allocate" + default NET_MAX_CONTEXTS + config NET_CONTEXT_NET_PKT_POOL bool "Net_buf TX pool / context" default y if NET_TCP && NET_6LO From 056e7f595d1b77972abe3096b614849a22cdafe4 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 17:03:32 +0300 Subject: [PATCH 039/397] net: sockets: tls: Add ZVFS_OPEN_ADD_SIZE_TLS to count TLS sockets Make sure that the CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS will reflect the number of required file descriptors in the system. Signed-off-by: Jukka Rissanen --- subsys/net/lib/sockets/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index bce60ee7276e6..e857dd83a5f2f 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -215,6 +215,11 @@ config NET_SOCKETS_TLS_MAX_CONTEXTS "This variable specifies maximum number of TLS/DTLS contexts that can be allocated at the same time." +config ZVFS_OPEN_ADD_SIZE_TLS + int "Number of TLS network sockets to allocate" + default NET_SOCKETS_TLS_MAX_CONTEXTS if NET_SOCKETS_SOCKOPT_TLS + default 0 + config NET_SOCKETS_TLS_MAX_CREDENTIALS int "Maximum number of TLS/DTLS credentials per socket" default 4 From 485d986f5abfef9b198f0e2a1ee1dcef4ed78b25 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 10:51:03 +0300 Subject: [PATCH 040/397] snippets: wifi: Set default number of sockets to use Set the minimum number of sockets that are used by the wifi snippets. Signed-off-by: Jukka Rissanen --- snippets/wifi/wifi-ip/wifi-ip.conf | 2 +- snippets/wifi/wifi-ipv4/wifi-ipv4.conf | 2 +- snippets/wifi/wifi-ipv6/wifi-ipv6.conf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/snippets/wifi/wifi-ip/wifi-ip.conf b/snippets/wifi/wifi-ip/wifi-ip.conf index 788715d59b701..cc4dbd175c6e8 100644 --- a/snippets/wifi/wifi-ip/wifi-ip.conf +++ b/snippets/wifi/wifi-ip/wifi-ip.conf @@ -5,7 +5,7 @@ CONFIG_WIFI_NM_WPA_SUPPLICANT=y # Make sure there is enough resources for supplicant and most of the samples CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_ZVFS_OPEN_MAX=24 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=10 CONFIG_NET_MAX_CONN=10 CONFIG_ZVFS_POLL_MAX=10 diff --git a/snippets/wifi/wifi-ipv4/wifi-ipv4.conf b/snippets/wifi/wifi-ipv4/wifi-ipv4.conf index 89feb091ad351..83684f28b65fa 100644 --- a/snippets/wifi/wifi-ipv4/wifi-ipv4.conf +++ b/snippets/wifi/wifi-ipv4/wifi-ipv4.conf @@ -5,7 +5,7 @@ CONFIG_WIFI_NM_WPA_SUPPLICANT=y # Make sure there is enough resources for supplicant and most of the samples CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_ZVFS_OPEN_MAX=24 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=10 CONFIG_NET_MAX_CONN=10 CONFIG_ZVFS_POLL_MAX=10 diff --git a/snippets/wifi/wifi-ipv6/wifi-ipv6.conf b/snippets/wifi/wifi-ipv6/wifi-ipv6.conf index f4ea1214ece17..df546df978d10 100644 --- a/snippets/wifi/wifi-ipv6/wifi-ipv6.conf +++ b/snippets/wifi/wifi-ipv6/wifi-ipv6.conf @@ -5,7 +5,7 @@ CONFIG_WIFI_NM_WPA_SUPPLICANT=y # Make sure there is enough resources for supplicant and most of the samples CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_ZVFS_OPEN_MAX=24 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=10 CONFIG_NET_MAX_CONN=10 CONFIG_ZVFS_POLL_MAX=10 From 9f0a0d973f235447a354425b37a5ec26d63ab4be Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 10:52:57 +0300 Subject: [PATCH 041/397] samples: net: Remove / replace the CONFIG_ZVFS_OPEN_MAX option Remove unneeded CONFIG_ZVFS_OPEN_MAX config option as it is now controlled by number of net_context i.e., CONFIG_NET_MAX_CONTEXTS Some of the samples now use CONFIG_ZVFS_OPEN_ADD_SIZE_NET_SAMPLE to specify the sample socket needs. Signed-off-by: Jukka Rissanen --- samples/net/dns_resolve/prj.conf | 1 - samples/net/dsa/prj.conf | 1 - samples/net/lwm2m_client/Kconfig | 1 + samples/net/lwm2m_client/boards/native_sim.conf | 2 +- samples/net/mqtt_sn_publisher/prj.conf | 1 - samples/net/openthread/border_router/prj.conf | 5 ----- samples/net/prometheus/prj.conf | 2 -- samples/net/sockets/dumb_http_server_mt/prj.conf | 1 - samples/net/sockets/echo_client/Kconfig | 1 + samples/net/sockets/echo_client/overlay-tls.conf | 2 +- samples/net/sockets/echo_server/overlay-tls.conf | 2 +- samples/net/sockets/echo_server/overlay-ws-console.conf | 2 +- samples/net/sockets/echo_server/prj.conf | 2 +- samples/net/sockets/http_server/Kconfig | 1 + samples/net/sockets/http_server/prj.conf | 2 +- samples/net/sockets/net_mgmt/prj.conf | 1 - samples/net/sockets/packet/prj.conf | 1 - samples/net/zperf/prj.conf | 1 - 18 files changed, 9 insertions(+), 20 deletions(-) diff --git a/samples/net/dns_resolve/prj.conf b/samples/net/dns_resolve/prj.conf index de837ae082889..16d77bdaace76 100644 --- a/samples/net/dns_resolve/prj.conf +++ b/samples/net/dns_resolve/prj.conf @@ -15,7 +15,6 @@ CONFIG_NET_IPV4=y CONFIG_NET_DHCPV4=n CONFIG_ZVFS_POLL_MAX=5 -CONFIG_ZVFS_OPEN_MAX=5 # Enable the DNS resolver CONFIG_DNS_RESOLVER=y diff --git a/samples/net/dsa/prj.conf b/samples/net/dsa/prj.conf index 02d94378f822a..f7f00d5eb8e77 100644 --- a/samples/net/dsa/prj.conf +++ b/samples/net/dsa/prj.conf @@ -18,7 +18,6 @@ CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=5 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=1 CONFIG_NET_MAX_CONTEXTS=4 -CONFIG_ZVFS_OPEN_MAX=4 CONFIG_ZVFS_POLL_MAX=4 CONFIG_NET_MAX_CONN=4 diff --git a/samples/net/lwm2m_client/Kconfig b/samples/net/lwm2m_client/Kconfig index 7952bf39b1887..d9b8b427b8797 100644 --- a/samples/net/lwm2m_client/Kconfig +++ b/samples/net/lwm2m_client/Kconfig @@ -52,4 +52,5 @@ config NET_SAMPLE_LWM2M_WAIT_DNS Make sure we get DNS server addresses from the network before considering the connection to be up. +source "samples/net/common/Kconfig" source "Kconfig.zephyr" diff --git a/samples/net/lwm2m_client/boards/native_sim.conf b/samples/net/lwm2m_client/boards/native_sim.conf index 8ac063ecc3164..f5607d22b9f69 100644 --- a/samples/net/lwm2m_client/boards/native_sim.conf +++ b/samples/net/lwm2m_client/boards/native_sim.conf @@ -4,4 +4,4 @@ CONFIG_DNS_SERVER1="192.0.2.2" CONFIG_LWM2M_DNS_SUPPORT=y CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" CONFIG_HEAP_MEM_POOL_SIZE=32768 -CONFIG_ZVFS_OPEN_MAX=16 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET_SAMPLE=16 diff --git a/samples/net/mqtt_sn_publisher/prj.conf b/samples/net/mqtt_sn_publisher/prj.conf index d3f62bcd387f6..c943a391f3986 100644 --- a/samples/net/mqtt_sn_publisher/prj.conf +++ b/samples/net/mqtt_sn_publisher/prj.conf @@ -4,7 +4,6 @@ CONFIG_NET_UDP=y CONFIG_NET_IPV4=y CONFIG_NET_IPV6=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=6 CONFIG_NET_CONNECTION_MANAGER=y # Kernel options diff --git a/samples/net/openthread/border_router/prj.conf b/samples/net/openthread/border_router/prj.conf index c5482c4b434fd..ff1447fa885a4 100644 --- a/samples/net/openthread/border_router/prj.conf +++ b/samples/net/openthread/border_router/prj.conf @@ -16,7 +16,6 @@ CONFIG_NET_ROUTE_MCAST=y CONFIG_NET_SOCKETS_SERVICE=y CONFIG_NET_CONTEXT_RECV_PKTINFO=y CONFIG_NET_CONTEXT_RECV_HOPLIMIT=y -CONFIG_ZVFS_POLL_MAX=15 CONFIG_NET_SOCKETS_SERVICE_STACK_SIZE=12288 CONFIG_NET_MAX_CONN=12 CONFIG_NET_CONNECTION_MANAGER_MONITOR_STACK_SIZE=2048 @@ -72,10 +71,6 @@ CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=6 CONFIG_NET_IF_MAX_IPV4_COUNT=2 CONFIG_NET_IF_MAX_IPV6_COUNT=6 -# Number of socket descriptors might need adjusting -# if there are more than 1 handlers defined. -CONFIG_ZVFS_OPEN_MAX=15 - # DNS resolver required by DNS upstream resolver CONFIG_DNS_RESOLVER=y CONFIG_DNS_RESOLVER_PACKET_FORWARDING=y diff --git a/samples/net/prometheus/prj.conf b/samples/net/prometheus/prj.conf index b863915a8386c..2f9aee94c6e7e 100644 --- a/samples/net/prometheus/prj.conf +++ b/samples/net/prometheus/prj.conf @@ -5,13 +5,11 @@ CONFIG_LOG=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_INIT_STACKS=y -CONFIG_ZVFS_OPEN_MAX=32 CONFIG_POSIX_API=y CONFIG_FDTABLE=y CONFIG_NET_SOCKETS_POLL_MAX=32 CONFIG_REQUIRES_FULL_LIBC=y CONFIG_HEAP_MEM_POOL_SIZE=2048 -CONFIG_ZVFS_OPEN_MAX=32 # Prometheus CONFIG_PROMETHEUS=y diff --git a/samples/net/sockets/dumb_http_server_mt/prj.conf b/samples/net/sockets/dumb_http_server_mt/prj.conf index 7b802e6e8b482..77ec17c7c7e00 100644 --- a/samples/net/sockets/dumb_http_server_mt/prj.conf +++ b/samples/net/sockets/dumb_http_server_mt/prj.conf @@ -2,7 +2,6 @@ CONFIG_TEST_RANDOM_GENERATOR=y # POSIX options -CONFIG_ZVFS_OPEN_MAX=20 CONFIG_POSIX_API=y # Networking config diff --git a/samples/net/sockets/echo_client/Kconfig b/samples/net/sockets/echo_client/Kconfig index 851189b1454a7..5fe58b8f062ea 100644 --- a/samples/net/sockets/echo_client/Kconfig +++ b/samples/net/sockets/echo_client/Kconfig @@ -58,4 +58,5 @@ config NET_SAMPLE_SEND_ITERATIONS Send sample data this many times before exiting. A value of zero means that the sample application is run forever. +source "samples/net/common/Kconfig" source "Kconfig.zephyr" diff --git a/samples/net/sockets/echo_client/overlay-tls.conf b/samples/net/sockets/echo_client/overlay-tls.conf index c807e9a1c9580..90cc5aea2b211 100644 --- a/samples/net/sockets/echo_client/overlay-tls.conf +++ b/samples/net/sockets/echo_client/overlay-tls.conf @@ -13,4 +13,4 @@ CONFIG_NET_SOCKETS_SOCKOPT_TLS=y CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=4 CONFIG_NET_SOCKETS_ENABLE_DTLS=y CONFIG_NET_SOCKETS_DTLS_MAX_FRAGMENT_LENGTH=2048 -CONFIG_ZVFS_OPEN_MAX=12 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET_SAMPLE=9 diff --git a/samples/net/sockets/echo_server/overlay-tls.conf b/samples/net/sockets/echo_server/overlay-tls.conf index f2351c0ecc86b..3ec1b7dc82329 100644 --- a/samples/net/sockets/echo_server/overlay-tls.conf +++ b/samples/net/sockets/echo_server/overlay-tls.conf @@ -14,4 +14,4 @@ CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=6 CONFIG_NET_SOCKETS_ENABLE_DTLS=y CONFIG_NET_SOCKETS_DTLS_TIMEOUT=30000 CONFIG_NET_SOCKETS_DTLS_MAX_FRAGMENT_LENGTH=2048 -CONFIG_ZVFS_OPEN_MAX=20 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET_SAMPLE=16 diff --git a/samples/net/sockets/echo_server/overlay-ws-console.conf b/samples/net/sockets/echo_server/overlay-ws-console.conf index 84bbed81d4f86..c8b990cfcee1e 100644 --- a/samples/net/sockets/echo_server/overlay-ws-console.conf +++ b/samples/net/sockets/echo_server/overlay-ws-console.conf @@ -9,4 +9,4 @@ CONFIG_NET_SOCKETS_POLL_MAX=32 CONFIG_NET_MAX_CONN=32 CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=32 CONFIG_ZVFS_EVENTFD_MAX=10 -CONFIG_ZVFS_OPEN_MAX=32 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET_SAMPLE=24 diff --git a/samples/net/sockets/echo_server/prj.conf b/samples/net/sockets/echo_server/prj.conf index 6038f6bb1083a..d233af340652e 100644 --- a/samples/net/sockets/echo_server/prj.conf +++ b/samples/net/sockets/echo_server/prj.conf @@ -47,7 +47,7 @@ CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" # Number of socket descriptors might need adjusting # if there are more than 1 handlers defined. -CONFIG_ZVFS_OPEN_MAX=12 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET_SAMPLE=8 # How many client can connect to echo-server simultaneously CONFIG_NET_SAMPLE_NUM_HANDLERS=1 diff --git a/samples/net/sockets/http_server/Kconfig b/samples/net/sockets/http_server/Kconfig index 07d5b26e52d5e..017c0ab8d75db 100644 --- a/samples/net/sockets/http_server/Kconfig +++ b/samples/net/sockets/http_server/Kconfig @@ -76,4 +76,5 @@ if USB_DEVICE_STACK_NEXT source "samples/subsys/usb/common/Kconfig.sample_usbd" endif +source "samples/net/common/Kconfig" source "Kconfig.zephyr" diff --git a/samples/net/sockets/http_server/prj.conf b/samples/net/sockets/http_server/prj.conf index 5cfe2a04ad297..9f9e3f5885576 100644 --- a/samples/net/sockets/http_server/prj.conf +++ b/samples/net/sockets/http_server/prj.conf @@ -6,7 +6,7 @@ CONFIG_LOG=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_INIT_STACKS=y -CONFIG_ZVFS_OPEN_MAX=32 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET_SAMPLE=24 CONFIG_POSIX_API=y CONFIG_FDTABLE=y CONFIG_ZVFS_POLL_MAX=32 diff --git a/samples/net/sockets/net_mgmt/prj.conf b/samples/net/sockets/net_mgmt/prj.conf index 72f32e1f58f88..854419e60d4cd 100644 --- a/samples/net/sockets/net_mgmt/prj.conf +++ b/samples/net/sockets/net_mgmt/prj.conf @@ -6,7 +6,6 @@ CONFIG_NET_IPV6=y CONFIG_NET_IPV4=y CONFIG_NET_SOCKETS=y CONFIG_POSIX_API=y -CONFIG_ZVFS_OPEN_MAX=6 CONFIG_NET_SOCKETS_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y diff --git a/samples/net/sockets/packet/prj.conf b/samples/net/sockets/packet/prj.conf index 555e824bf5880..254248f10129a 100644 --- a/samples/net/sockets/packet/prj.conf +++ b/samples/net/sockets/packet/prj.conf @@ -7,7 +7,6 @@ CONFIG_NET_IPV4=n CONFIG_NET_MAX_CONTEXTS=10 CONFIG_NET_SOCKETS=y CONFIG_POSIX_API=y -CONFIG_ZVFS_OPEN_MAX=6 CONFIG_NET_CONTEXT_RCVTIMEO=y CONFIG_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y diff --git a/samples/net/zperf/prj.conf b/samples/net/zperf/prj.conf index 129260a113ac7..8889a1ccc4407 100644 --- a/samples/net/zperf/prj.conf +++ b/samples/net/zperf/prj.conf @@ -23,7 +23,6 @@ CONFIG_NET_TC_TX_COUNT=1 CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_SERVICE_THREAD_PRIO=-1 CONFIG_ZVFS_POLL_MAX=9 -CONFIG_ZVFS_OPEN_MAX=12 CONFIG_POSIX_API=y CONFIG_INIT_STACKS=y From 09d81d967537adbbd5afc5538692446d01b7fd39 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 11:13:19 +0300 Subject: [PATCH 042/397] samples: Remove not needed CONFIG_ZVFS_OPEN_MAX option The number of file/socket descriptors is now determined by CONFIG_ZVFS_OPEN_ADD_SIZE_* options and the networking side already sets the minimum values so the CONFIG_ZVFS_OPEN_MAX option is not needed. Signed-off-by: Jukka Rissanen --- samples/drivers/video/tcpserversink/prj.conf | 1 - samples/modules/thrift/hello/client/prj.conf | 5 ----- samples/modules/thrift/hello/server/prj.conf | 4 ---- 3 files changed, 10 deletions(-) diff --git a/samples/drivers/video/tcpserversink/prj.conf b/samples/drivers/video/tcpserversink/prj.conf index a49aa3de90ff3..d7c140b6aae2b 100644 --- a/samples/drivers/video/tcpserversink/prj.conf +++ b/samples/drivers/video/tcpserversink/prj.conf @@ -3,7 +3,6 @@ CONFIG_NETWORKING=y CONFIG_NET_TCP=y CONFIG_NET_IPV4=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=6 CONFIG_POSIX_API=y # Kernel options diff --git a/samples/modules/thrift/hello/client/prj.conf b/samples/modules/thrift/hello/client/prj.conf index 3c3cfcdbbe8e1..dea85eac5e0ca 100644 --- a/samples/modules/thrift/hello/client/prj.conf +++ b/samples/modules/thrift/hello/client/prj.conf @@ -28,7 +28,6 @@ CONFIG_NET_TCP=y CONFIG_NET_IPV6=n CONFIG_NET_IPV4=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=6 CONFIG_NET_CONNECTION_MANAGER=y # Kernel options @@ -59,10 +58,6 @@ CONFIG_NET_CONFIG_NEED_IPV4=y CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" -# Number of socket descriptors might need adjusting -# if there are more than 1 handlers defined. -CONFIG_ZVFS_OPEN_MAX=16 - # Some platforms require relatively large stack sizes. # This can be tuned per-board. CONFIG_MAIN_STACK_SIZE=8192 diff --git a/samples/modules/thrift/hello/server/prj.conf b/samples/modules/thrift/hello/server/prj.conf index 78b009fb3e285..e8f3044415f8a 100644 --- a/samples/modules/thrift/hello/server/prj.conf +++ b/samples/modules/thrift/hello/server/prj.conf @@ -50,10 +50,6 @@ CONFIG_NET_CONFIG_NEED_IPV4=y CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" -# Number of socket descriptors might need adjusting -# if there are more than 1 handlers defined. -CONFIG_ZVFS_OPEN_MAX=16 - # Some platforms require relatively large stack sizes. # This can be tuned per-board. CONFIG_MAIN_STACK_SIZE=8192 From cf84bb39a92786dc6cf9070bba2b5940ce938696 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 12:03:02 +0300 Subject: [PATCH 043/397] tests: net: Allow setting CONFIG_ZVFS_OPEN_MAX Add CONFIG_ZVFS_OPEN_IGNORE_MIN=y so that we can set the CONFIG_ZVFS_OPEN_MAX without specifying individual sub values. This is just specific to this test and not something that needs to be done in other tests. Signed-off-by: Jukka Rissanen --- tests/net/all/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/net/all/prj.conf b/tests/net/all/prj.conf index b2cb791f7962f..f220a6e9a1143 100644 --- a/tests/net/all/prj.conf +++ b/tests/net/all/prj.conf @@ -353,6 +353,7 @@ CONFIG_NET_SOCKETS_ENABLE_DTLS=y CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=y CONFIG_NET_SOCKETS_OFFLOAD=y CONFIG_NET_SOCKETS_PACKET=y +CONFIG_ZVFS_OPEN_IGNORE_MIN=y CONFIG_ZVFS_OPEN_MAX=50 CONFIG_ZVFS_POLL_MAX=50 CONFIG_NET_SOCKETS=y From 0bdff54896c212cb01420dac9f2a1bb1cdc615c9 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 11:15:26 +0300 Subject: [PATCH 044/397] tests: Remove not needed CONFIG_ZVFS_OPEN_MAX option Either remove the option from conf file or adjust its value by using CONFIG_ZVFS_OPEN_ADD_SIZE_NET option because the max number of socket descriptors is now calculated dynamically at built time. Signed-off-by: Jukka Rissanen --- tests/modules/thrift/ThriftTest/overlay-tls.conf | 3 +-- tests/modules/thrift/ThriftTest/prj.conf | 13 ------------- tests/net/lib/dns_addremove/prj.conf | 1 - tests/net/lib/dns_dispatcher/prj.conf | 2 +- tests/net/lib/dns_resolve/prj.conf | 1 - tests/net/lib/http_server/core/prj.conf | 1 - tests/net/lib/http_server/crime/prj.conf | 1 - tests/net/lib/http_server/tls/prj.conf | 1 - tests/net/lib/lwm2m/interop/boards/native_sim.conf | 2 +- tests/net/lib/mdns_responder/prj.conf | 1 - tests/net/pm/prj.conf | 1 - tests/net/pmtu/prj.conf | 1 - tests/net/socket/af_packet/prj.conf | 1 - tests/net/socket/poll/prj.conf | 2 +- tests/net/socket/reuseaddr_reuseport/prj.conf | 1 - tests/net/socket/select/prj.conf | 7 ++++++- tests/net/socket/service/prj.conf | 2 +- tests/net/socket/socketpair/prj.conf | 2 +- tests/net/socket/tcp/prj.conf | 1 - tests/net/socket/tls/prj.conf | 2 +- tests/net/socket/tls_ext/prj.conf | 2 +- tests/net/socket/udp/prj.conf | 2 +- tests/posix/fs/prj.conf | 1 + 23 files changed, 16 insertions(+), 35 deletions(-) diff --git a/tests/modules/thrift/ThriftTest/overlay-tls.conf b/tests/modules/thrift/ThriftTest/overlay-tls.conf index 7676b38883292..1bfda0bc41914 100644 --- a/tests/modules/thrift/ThriftTest/overlay-tls.conf +++ b/tests/modules/thrift/ThriftTest/overlay-tls.conf @@ -8,13 +8,12 @@ CONFIG_THRIFT_SSL_SOCKET=y # # File Descriptor Usage # --------------------- -# stdin, stdout, stderr: 3 # tcp socket (accept): 1 # tls socket (accept): 1 # tcp sockets (client, server): 2 # tls sockets (client, server): 2 # socketpairs for cancellation (accept, client, server): 6 -CONFIG_ZVFS_OPEN_MAX=15 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=12 # TLS configuration CONFIG_MBEDTLS=y diff --git a/tests/modules/thrift/ThriftTest/prj.conf b/tests/modules/thrift/ThriftTest/prj.conf index 4bc7153026a10..a4727acced11c 100755 --- a/tests/modules/thrift/ThriftTest/prj.conf +++ b/tests/modules/thrift/ThriftTest/prj.conf @@ -41,19 +41,6 @@ CONFIG_NET_PKT_TX_COUNT=20 CONFIG_NET_BUF_RX_COUNT=20 CONFIG_NET_PKT_RX_COUNT=20 -# We can get away with using fewer sockets in the non-TLS tests because we use -# TFDServer.cpp for our server and socketpair() for our channel. We do not -# need an accept socket for the server (in contrast to TCP), it only needs 1 -# eventfd for server cancellation, and there are no cancellation sockets -# required because we close them in the testsuite. -# -# File Descriptor Usage -# --------------------- -# stdin, stdout, stderr: 3 -# socketpair for channel: 2 -# eventfd for cancellation: 1 -CONFIG_ZVFS_OPEN_MAX=6 - # Network address config CONFIG_NET_IPV4=y CONFIG_NET_CONFIG_SETTINGS=y diff --git a/tests/net/lib/dns_addremove/prj.conf b/tests/net/lib/dns_addremove/prj.conf index 112794a03da38..b14e5f47e73d5 100644 --- a/tests/net/lib/dns_addremove/prj.conf +++ b/tests/net/lib/dns_addremove/prj.conf @@ -17,5 +17,4 @@ CONFIG_NET_ARP=n CONFIG_PRINTK=y CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_ZVFS_OPEN_MAX=5 CONFIG_ZVFS_POLL_MAX=5 diff --git a/tests/net/lib/dns_dispatcher/prj.conf b/tests/net/lib/dns_dispatcher/prj.conf index 035c73e9b3b6e..af5bf4bb484c3 100644 --- a/tests/net/lib/dns_dispatcher/prj.conf +++ b/tests/net/lib/dns_dispatcher/prj.conf @@ -15,7 +15,7 @@ CONFIG_NET_IPV6=y CONFIG_PRINTK=y CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_ZVFS_OPEN_MAX=10 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=5 CONFIG_ZVFS_POLL_MAX=10 CONFIG_MDNS_RESPONDER=n CONFIG_MDNS_RESOLVER=n diff --git a/tests/net/lib/dns_resolve/prj.conf b/tests/net/lib/dns_resolve/prj.conf index 56518027b8d30..2101f247e757c 100644 --- a/tests/net/lib/dns_resolve/prj.conf +++ b/tests/net/lib/dns_resolve/prj.conf @@ -30,5 +30,4 @@ CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=1344 CONFIG_HEAP_MEM_POOL_SIZE=1024 -CONFIG_ZVFS_OPEN_MAX=9 CONFIG_ZVFS_POLL_MAX=9 diff --git a/tests/net/lib/http_server/core/prj.conf b/tests/net/lib/http_server/core/prj.conf index 0668f13070269..9d032dc348899 100644 --- a/tests/net/lib/http_server/core/prj.conf +++ b/tests/net/lib/http_server/core/prj.conf @@ -7,7 +7,6 @@ CONFIG_POSIX_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_ZVFS_OPEN_MAX=10 CONFIG_REQUIRES_FULL_LIBC=y CONFIG_ZVFS_EVENTFD_MAX=10 CONFIG_NET_MAX_CONTEXTS=10 diff --git a/tests/net/lib/http_server/crime/prj.conf b/tests/net/lib/http_server/crime/prj.conf index 910b89a4c04e2..276466da4163e 100644 --- a/tests/net/lib/http_server/crime/prj.conf +++ b/tests/net/lib/http_server/crime/prj.conf @@ -9,7 +9,6 @@ CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_ZTEST_STACK_SIZE=1024 -CONFIG_ZVFS_OPEN_MAX=10 CONFIG_REQUIRES_FULL_LIBC=y CONFIG_ZVFS_EVENTFD_MAX=10 CONFIG_NET_MAX_CONTEXTS=10 diff --git a/tests/net/lib/http_server/tls/prj.conf b/tests/net/lib/http_server/tls/prj.conf index d8facb4a1d90f..9decd429d2069 100644 --- a/tests/net/lib/http_server/tls/prj.conf +++ b/tests/net/lib/http_server/tls/prj.conf @@ -46,7 +46,6 @@ CONFIG_NET_BUF_RX_COUNT=32 CONFIG_NET_PKT_TX_COUNT=16 CONFIG_NET_PKT_RX_COUNT=16 CONFIG_ZVFS_POLL_MAX=32 -CONFIG_ZVFS_OPEN_MAX=32 CONFIG_REQUIRES_FULL_LIBC=y CONFIG_ZVFS_EVENTFD_MAX=10 CONFIG_NET_MAX_CONTEXTS=10 diff --git a/tests/net/lib/lwm2m/interop/boards/native_sim.conf b/tests/net/lib/lwm2m/interop/boards/native_sim.conf index 3ca97938bd992..1c5feb6afbe35 100644 --- a/tests/net/lib/lwm2m/interop/boards/native_sim.conf +++ b/tests/net/lib/lwm2m/interop/boards/native_sim.conf @@ -8,4 +8,4 @@ CONFIG_UART_NATIVE_PTY_0_ON_STDINOUT=y CONFIG_ASAN=y CONFIG_NATIVE_EXTRA_CMDLINE_ARGS="--seed-random" CONFIG_HEAP_MEM_POOL_SIZE=32768 -CONFIG_ZVFS_OPEN_MAX=16 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=8 diff --git a/tests/net/lib/mdns_responder/prj.conf b/tests/net/lib/mdns_responder/prj.conf index ecd170c5e510f..7833fef4ab6c8 100644 --- a/tests/net/lib/mdns_responder/prj.conf +++ b/tests/net/lib/mdns_responder/prj.conf @@ -5,7 +5,6 @@ CONFIG_NET_DRIVERS=y CONFIG_NET_LOOPBACK=y CONFIG_NET_IPV4=y CONFIG_NET_IPV6=y -CONFIG_ZVFS_OPEN_MAX=7 CONFIG_ZVFS_POLL_MAX=7 # Network driver config diff --git a/tests/net/pm/prj.conf b/tests/net/pm/prj.conf index 9c838139d9b8e..2c6626660aa91 100644 --- a/tests/net/pm/prj.conf +++ b/tests/net/pm/prj.conf @@ -7,7 +7,6 @@ CONFIG_NET_L2_ETHERNET=n CONFIG_NET_UDP=y CONFIG_NET_IPV4=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=3 CONFIG_ZTEST_STACK_SIZE=2048 CONFIG_MAIN_STACK_SIZE=2048 CONFIG_NET_LOG=y diff --git a/tests/net/pmtu/prj.conf b/tests/net/pmtu/prj.conf index 1253c5c7c1c85..d075205adc74b 100644 --- a/tests/net/pmtu/prj.conf +++ b/tests/net/pmtu/prj.conf @@ -21,6 +21,5 @@ CONFIG_NET_BUF_TX_COUNT=20 CONFIG_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=32 CONFIG_NET_MAX_CONTEXTS=32 CONFIG_NET_MAX_CONN=32 diff --git a/tests/net/socket/af_packet/prj.conf b/tests/net/socket/af_packet/prj.conf index 342442f9cfc98..ed02e5be4a936 100644 --- a/tests/net/socket/af_packet/prj.conf +++ b/tests/net/socket/af_packet/prj.conf @@ -6,7 +6,6 @@ CONFIG_NET_UDP=y CONFIG_NET_TCP=n CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_PACKET=y -CONFIG_ZVFS_OPEN_MAX=8 CONFIG_NET_IPV6_DAD=n CONFIG_NET_IPV6_MLD=n diff --git a/tests/net/socket/poll/prj.conf b/tests/net/socket/poll/prj.conf index 4a404b96aea24..1c27a6e5b36e8 100644 --- a/tests/net/socket/poll/prj.conf +++ b/tests/net/socket/poll/prj.conf @@ -5,7 +5,7 @@ CONFIG_NET_IPV6=y CONFIG_NET_UDP=y CONFIG_NET_TCP=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=10 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=5 CONFIG_NET_PKT_TX_COUNT=8 CONFIG_NET_PKT_RX_COUNT=8 CONFIG_NET_MAX_CONN=5 diff --git a/tests/net/socket/reuseaddr_reuseport/prj.conf b/tests/net/socket/reuseaddr_reuseport/prj.conf index f151d25130eb1..513a4114ab4d6 100644 --- a/tests/net/socket/reuseaddr_reuseport/prj.conf +++ b/tests/net/socket/reuseaddr_reuseport/prj.conf @@ -28,7 +28,6 @@ CONFIG_NET_CONTEXT_REUSEPORT=y CONFIG_NET_HOSTNAME_ENABLE=y CONFIG_NET_HOSTNAME="ztest_hostname" -CONFIG_ZVFS_OPEN_MAX=8 CONFIG_NET_MAX_CONN=10 CONFIG_NET_MAX_CONTEXTS=10 diff --git a/tests/net/socket/select/prj.conf b/tests/net/socket/select/prj.conf index 53c0c5de3bf95..49d0d8edd333b 100644 --- a/tests/net/socket/select/prj.conf +++ b/tests/net/socket/select/prj.conf @@ -9,8 +9,13 @@ CONFIG_NET_LOOPBACK=y CONFIG_NET_IPV4=n CONFIG_NET_IPV6=y CONFIG_NET_SOCKETS=y -# Defines fd_set size + +# Defines fd_set size. The test wants to specifically +# check that select bitset size is calculated correctly. +# We want to set the max fd count to 33 so need to ignore +# the min value. CONFIG_ZVFS_OPEN_MAX=33 +CONFIG_ZVFS_OPEN_IGNORE_MIN=y # Network driver config CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/tests/net/socket/service/prj.conf b/tests/net/socket/service/prj.conf index 151b79e85303b..f2835795342b0 100644 --- a/tests/net/socket/service/prj.conf +++ b/tests/net/socket/service/prj.conf @@ -5,7 +5,7 @@ CONFIG_NET_IPV6=y CONFIG_NET_UDP=y CONFIG_NET_TCP=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=20 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=10 CONFIG_NET_PKT_TX_COUNT=8 CONFIG_NET_PKT_RX_COUNT=8 CONFIG_NET_MAX_CONN=5 diff --git a/tests/net/socket/socketpair/prj.conf b/tests/net/socket/socketpair/prj.conf index 314e999680620..8615d581ebc4b 100644 --- a/tests/net/socket/socketpair/prj.conf +++ b/tests/net/socket/socketpair/prj.conf @@ -7,7 +7,7 @@ CONFIG_NET_IPV4=y CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETPAIR=y CONFIG_NET_SOCKETPAIR_BUFFER_SIZE=64 -CONFIG_ZVFS_OPEN_MAX=10 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=5 # Network driver config CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/tests/net/socket/tcp/prj.conf b/tests/net/socket/tcp/prj.conf index 724e208aa0bed..af9650c4595b2 100644 --- a/tests/net/socket/tcp/prj.conf +++ b/tests/net/socket/tcp/prj.conf @@ -11,7 +11,6 @@ CONFIG_NET_IPV6=y CONFIG_NET_IPV6_ND=n CONFIG_NET_TCP=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=10 CONFIG_NET_MAX_CONTEXTS=10 CONFIG_NET_MAX_CONN=10 diff --git a/tests/net/socket/tls/prj.conf b/tests/net/socket/tls/prj.conf index 6c4e061e808c0..24058c31dd789 100644 --- a/tests/net/socket/tls/prj.conf +++ b/tests/net/socket/tls/prj.conf @@ -20,7 +20,7 @@ CONFIG_TLS_MAX_CREDENTIALS_NUMBER=10 CONFIG_NET_CONTEXT_RCVTIMEO=y CONFIG_NET_CONTEXT_SNDTIMEO=y CONFIG_NET_CONTEXT_RCVBUF=y -CONFIG_ZVFS_OPEN_MAX=20 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=10 # Keep timings short for the test CONFIG_NET_TCP_TIME_WAIT_DELAY=10 diff --git a/tests/net/socket/tls_ext/prj.conf b/tests/net/socket/tls_ext/prj.conf index 50f764286daa0..ed2b8852ecb1e 100644 --- a/tests/net/socket/tls_ext/prj.conf +++ b/tests/net/socket/tls_ext/prj.conf @@ -31,7 +31,7 @@ CONFIG_NET_BUF_TX_COUNT=64 CONFIG_NET_PKT_TX_COUNT=64 CONFIG_NET_BUF_RX_COUNT=64 CONFIG_NET_PKT_RX_COUNT=64 -CONFIG_ZVFS_OPEN_MAX=10 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=5 # Stack sizes CONFIG_MAIN_STACK_SIZE=2048 diff --git a/tests/net/socket/udp/prj.conf b/tests/net/socket/udp/prj.conf index ebdbb0d24e73a..c40b5a8b527f7 100644 --- a/tests/net/socket/udp/prj.conf +++ b/tests/net/socket/udp/prj.conf @@ -7,7 +7,7 @@ CONFIG_NET_IPV4=y CONFIG_NET_IPV6=y CONFIG_NET_UDP=y CONFIG_NET_SOCKETS=y -CONFIG_ZVFS_OPEN_MAX=10 +CONFIG_ZVFS_OPEN_ADD_SIZE_NET=5 CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 CONFIG_NET_IPV6_DAD=n CONFIG_NET_IPV6_MLD=n diff --git a/tests/posix/fs/prj.conf b/tests/posix/fs/prj.conf index e1501c697ae19..9b04196534602 100644 --- a/tests/posix/fs/prj.conf +++ b/tests/posix/fs/prj.conf @@ -8,3 +8,4 @@ CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=4096 CONFIG_ZTEST_STACK_SIZE=2048 CONFIG_EVENTFD=n +CONFIG_ZVFS_OPEN_ADD_SIZE_POSIX=5 From 9b6d49294616526f6fb8b1d37945b66f36b3cf7d Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 17 Oct 2025 12:05:34 +0300 Subject: [PATCH 045/397] tests: Make sure to use ZVFS_OPEN_SIZE define As the CONFIG_ZVFS_OPEN_MAX is set to 0 by default, we must use ZVFS_OPEN_SIZE in the tests. Signed-off-by: Jukka Rissanen --- tests/net/socket/tcp/src/main.c | 2 +- tests/net/socket/udp/src/main.c | 2 +- tests/posix/fs/src/test_fs_file.c | 2 +- tests/posix/xsi_realtime/src/shm.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c index 76a4d62925385..aee0132e9f0cf 100644 --- a/tests/net/socket/tcp/src/main.c +++ b/tests/net/socket/tcp/src/main.c @@ -2665,7 +2665,7 @@ static void after(void *arg) { ARG_UNUSED(arg); - for (int i = 0; i < CONFIG_ZVFS_OPEN_MAX; ++i) { + for (int i = 0; i < ZVFS_OPEN_SIZE; ++i) { (void)zsock_close(i); } } diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index b4f57ec182546..ca6ed384f7db4 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -3719,7 +3719,7 @@ static void after(void *arg) { ARG_UNUSED(arg); - for (int i = 0; i < CONFIG_ZVFS_OPEN_MAX; ++i) { + for (int i = 0; i < ZVFS_OPEN_SIZE; ++i) { (void)zsock_close(i); } } diff --git a/tests/posix/fs/src/test_fs_file.c b/tests/posix/fs/src/test_fs_file.c index 23496c92b8c22..63795e30b2eac 100644 --- a/tests/posix/fs/src/test_fs_file.c +++ b/tests/posix/fs/src/test_fs_file.c @@ -261,7 +261,7 @@ ZTEST(posix_fs_file_test, test_fs_unlink) ZTEST(posix_fs_file_test, test_fs_fd_leak) { const int reps = - MAX(CONFIG_POSIX_OPEN_MAX, CONFIG_ZVFS_OPEN_MAX) + 5; + MAX(CONFIG_POSIX_OPEN_MAX, ZVFS_OPEN_SIZE) + 5; for (int i = 0; i < reps; i++) { if (i > 0) { diff --git a/tests/posix/xsi_realtime/src/shm.c b/tests/posix/xsi_realtime/src/shm.c index 6755798ef5a33..d59273a26fdd2 100644 --- a/tests/posix/xsi_realtime/src/shm.c +++ b/tests/posix/xsi_realtime/src/shm.c @@ -31,10 +31,10 @@ #define OPEN_FLAGS (VALID_FLAGS & ~O_CREAT) /* account for stdin, stdout, stderr */ -#define N (CONFIG_ZVFS_OPEN_MAX - 3) +#define N (ZVFS_OPEN_SIZE - 3) /* we need to have at least 2 shared memory objects */ -BUILD_ASSERT(N >= 2, "CONFIG_ZVFS_OPEN_MAX must be > 4"); +BUILD_ASSERT(N >= 2, "ZVFS_OPEN_SIZE must be > 4"); #define S_TYPEISSHM(st) (((st)->st_mode & ZVFS_MODE_IFMT) == ZVFS_MODE_IFSHM) From 59a487120f7f00f4812d6a42cd9e52853ea67c5e Mon Sep 17 00:00:00 2001 From: Alberto Dalibor Rodda Date: Wed, 15 Oct 2025 20:36:40 +0200 Subject: [PATCH 046/397] cmake: mcuboot: Fix build with RAM load and encryption Fix wrong byproduct name for the unencrypted slot 1 image, avoiding conflicts with the encrypted image. Signed-off-by: Alberto Dalibor Rodda --- cmake/mcuboot.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index d22a068023e3e..43d265c419d5f 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -222,7 +222,7 @@ function(zephyr_mcuboot_tasks) endif() if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD OR CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) - list(APPEND byproducts ${output}.slot1.signed.encrypted.bin) + list(APPEND byproducts ${output}.slot1.signed.bin) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.bin ${output}.slot1.signed.bin) From f9e81846e14eb82f1fe2cf9fa22aecebf7230abf Mon Sep 17 00:00:00 2001 From: Firas Sammoura Date: Tue, 14 Oct 2025 22:42:41 +0000 Subject: [PATCH 047/397] riscv: pmp: Factor out PMP address reading logic Refactor the code to read all PMP address CSRs (pmpaddr0 through pmpaddrN) into a new helper function, `z_riscv_pmp_read_addr`. This change encapsulates the register reading loop, improving code organization and potential reusability. The new function includes size assertions Signed-off-by: Firas Sammoura --- arch/riscv/core/pmp.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/arch/riscv/core/pmp.c b/arch/riscv/core/pmp.c index 7aca54e4eea08..9ecb2c975db9c 100644 --- a/arch/riscv/core/pmp.c +++ b/arch/riscv/core/pmp.c @@ -168,20 +168,35 @@ static inline void z_riscv_pmp_write_config(unsigned long *pmp_cfg, size_t pmp_c #endif } -static void dump_pmp_regs(const char *banner) +/** + * @brief Reads the PMP address CSRs (pmpaddrX) for all configured slots. + * + * This helper function abstracts the iterative logic required to read the + * individual PMP address registers (pmpaddr0, pmpaddr1, ..., pmpaddrN) + * up to the total number of PMP slots configured by CONFIG_PMP_SLOTS. + * + * @param pmp_addr Pointer to the array where the CSR contents will be stored. + * @param pmp_addr_size The size of the pmp_addr array, measured in unsigned long entries. + */ +static inline void z_riscv_pmp_read_addr(unsigned long *pmp_addr, size_t pmp_addr_size) { - unsigned long pmp_addr[CONFIG_PMP_SLOTS]; - unsigned long pmp_cfg[CONFIG_PMP_SLOTS / PMPCFG_STRIDE]; + __ASSERT(pmp_addr_size == (size_t)(CONFIG_PMP_SLOTS), "PMP address array size mismatch"); #define PMPADDR_READ(x) pmp_addr[x] = csr_read(pmpaddr##x) - FOR_EACH(PMPADDR_READ, (;), 0, 1, 2, 3, 4, 5, 6, 7); + #if CONFIG_PMP_SLOTS > 8 FOR_EACH(PMPADDR_READ, (;), 8, 9, 10, 11, 12, 13, 14, 15); #endif - #undef PMPADDR_READ +} + +static void dump_pmp_regs(const char *banner) +{ + unsigned long pmp_addr[CONFIG_PMP_SLOTS]; + unsigned long pmp_cfg[CONFIG_PMP_SLOTS / PMPCFG_STRIDE]; + z_riscv_pmp_read_addr(pmp_addr, (size_t)(CONFIG_PMP_SLOTS)); z_riscv_pmp_read_config(pmp_cfg, (size_t)(CONFIG_PMP_SLOTS / PMPCFG_STRIDE)); print_pmp_entries(0, CONFIG_PMP_SLOTS, pmp_addr, pmp_cfg, banner); } From 0ca2183d7b63a099d135dcddcc5180f8ad3e6cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Mon, 13 Oct 2025 11:14:05 +0200 Subject: [PATCH 048/397] boards: litex: move changeable peripherals to board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move changeable peripherals from dtsi to board, as in litex these can change and might be on different registers on custom out of tree boards. So we limit riscv32-litex-vexriscv.dtsi to just the interrupt controller and the cpu, which don't change. Signed-off-by: Fin Maaß --- .../litex_vexriscv/litex_vexriscv.dts | 450 +++++++++++++++--- dts/riscv/riscv32-litex-vexriscv.dtsi | 407 ---------------- 2 files changed, 389 insertions(+), 468 deletions(-) diff --git a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts index 4f94a15fad6ba..5d062f59daf0a 100644 --- a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts +++ b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include / { model = "LiteX VexRiscV"; @@ -16,6 +17,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,sram = &ram0; + zephyr,entropy = &prbs0; }; aliases { @@ -26,85 +28,411 @@ device_type = "memory"; reg = <0x40000000 0x10000000>; }; -}; -&ctrl0 { - status = "okay"; -}; + soc { + ctrl0: soc_controller@e0000000 { + compatible = "litex,soc-controller"; + reg = <0xe0000000 0x4 + 0xe0000004 0x4 + 0xe0000008 0x4>; + reg-names = "reset", + "scratch", + "bus_errors"; + status = "okay"; + }; -&uart0 { - status = "okay"; - current-speed = <115200>; -}; + uart0: serial@e0001800 { + compatible = "litex,uart"; + interrupt-parent = <&intc0>; + interrupts = <2 10>; + reg = <0xe0001800 0x4 + 0xe0001804 0x4 + 0xe0001808 0x4 + 0xe000180c 0x4 + 0xe0001810 0x4 + 0xe0001814 0x4 + 0xe0001818 0x4 + 0xe000181c 0x4>; + reg-names = "rxtx", + "txfull", + "rxempty", + "ev_status", + "ev_pending", + "ev_enable", + "txempty", + "rxfull"; + status = "okay"; + current-speed = <115200>; + }; -&timer0 { - status = "okay"; -}; + timer0: timer@e0002800 { + compatible = "litex,timer0"; + interrupt-parent = <&intc0>; + interrupts = <1 0>; + reg = <0xe0002800 0x4 + 0xe0002804 0x4 + 0xe0002808 0x4 + 0xe000280c 0x4 + 0xe0002810 0x4 + 0xe0002814 0x4 + 0xe0002818 0x4 + 0xe000281c 0x4 + 0xe0002820 0x4 + 0xe0002824 0x8>; + reg-names = "load", + "reload", + "en", + "update_value", + "value", + "ev_status", + "ev_pending", + "ev_enable", + "uptime_latch", + "uptime_cycles"; + status = "okay"; + }; -&wdt0 { - status = "okay"; -}; + wdt0: watchdog@e000d000 { + compatible = "litex,watchdog"; + interrupt-parent = <&intc0>; + reg = <0xe000d000 0x4>, + <0xe000d004 0x4>, + <0xe000d008 0x4>, + <0xe000d00c 0x4>, + <0xe000d010 0x4>, + <0xe000d014 0x4>; + reg-names = "control", + "cycles", + "remaining", + "ev_status", + "ev_pending", + "ev_enable"; + interrupts = <8 15>; + status = "okay"; + }; -&mdio0 { - status = "okay"; -}; + mdio0: mdio@e0008000 { + compatible = "litex,liteeth-mdio"; + reg = <0xe0008000 0x4>, + <0xe0008004 0x4>, + <0xe0008008 0x4>; + reg-names = "crg_reset", + "mdio_w", + "mdio_r"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; -&phy0 { - status = "okay"; -}; + phy0: ethernet-phy@1 { + compatible = "ethernet-phy"; + reg = <1>; + status = "okay"; + }; + }; -ð0 { - status = "okay"; -}; + eth0: ethernet@e0009800 { + compatible = "litex,liteeth"; + interrupt-parent = <&intc0>; + interrupts = <3 0>; + reg = <0xe0009800 0x4 + 0xe0009804 0x4 + 0xe0009808 0x4 + 0xe000980c 0x4 + 0xe0009810 0x4 + 0xe0009814 0x4 + 0xe0009818 0x4 + 0xe000981c 0x4 + 0xe0009820 0x4 + 0xe0009824 0x4 + 0xe0009828 0x4 + 0xe000982c 0x4 + 0xe0009830 0x4 + 0xe0009834 0x4 + 0xb0000000 0x2000>; + local-mac-address = [10 e2 d5 00 00 02]; + reg-names = "rx_slot", + "rx_length", + "rx_errors", + "rx_ev_status", + "rx_ev_pending", + "rx_ev_enable", + "tx_start", + "tx_ready", + "tx_level", + "tx_slot", + "tx_length", + "tx_ev_status", + "tx_ev_pending", + "tx_ev_enable", + "buffers"; + phy-handle = <&phy0>; + status = "okay"; + }; -&dna0 { - status = "okay"; -}; + dna0: dna@e0003800 { + compatible = "litex,dna0"; + /* DNA data is 57-bits long, + * so it requires 8 bytes. + * In LiteX each 32-bit register holds + * only a single byte of meaningful data, + * hence 8 registers. + */ + reg = <0xe0003800 0x20>; + reg-names = "mem"; + status = "okay"; + }; -&spi0 { - status = "okay"; -}; + spi0: spi@e0002000 { + compatible = "litex,spi"; + reg = <0xe0002000 0x4 + 0xe0002004 0x4 + 0xe0002008 0x4 + 0xe000200c 0x4 + 0xe0002010 0x4 + 0xe0002014 0x4>; + reg-names = "control", + "status", + "mosi", + "miso", + "cs", + "loopback"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + }; -&prbs0 { - status = "okay"; -}; + spi1: spi@e000c000 { + compatible = "litex,spi-litespi"; + interrupt-parent = <&intc0>; + reg = <0xe000c000 0x4>, + <0xe000c004 0x4>, + <0xe000c008 0x4>, + <0xe000c00c 0x4>, + <0xe000c010 0x4>, + <0xe000c014 0x4>, + <0xe000c018 0x4>, + <0xe000c01c 0x4>, + <0xe000c020 0x4>, + <0x60000000 0x1000000>; + reg-names = "phy_clk_divisor", + "mmap_dummy_bits", + "master_cs", + "master_phyconfig", + "master_rxtx", + "master_status", + "master_ev_status", + "master_ev_pending", + "master_ev_enable", + "flash_mmap"; + interrupts = <9 0>; + #address-cells = <1>; + #size-cells = <0>; -&i2c0 { - status = "okay"; -}; + spiflash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <10000000>; + }; + }; -&i2c1 { - status = "okay"; -}; + prbs0: prbs@e0006800 { + compatible = "litex,prbs"; + reg = <0xe0006800 0x4>; + reg-names = "status"; + status = "okay"; + }; -&pwm0 { - status = "okay"; -}; + i2c0: i2c@e0005000 { + compatible = "litex,i2c"; + reg = <0xe0005000 0x4 0xe0005004 0x4>; + reg-names = "write", "read"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + }; -&gpio_out { - status = "okay"; -}; + i2c1: i2c@e000d800 { + compatible = "litex,litei2c"; + interrupt-parent = <&intc0>; + reg = <0xe000d800 0x4>, + <0xe000d804 0x4>, + <0xe000d808 0x4>, + <0xe000d80c 0x4>, + <0xe000d810 0x4>, + <0xe000d814 0x4>, + <0xe000d818 0x4>, + <0xe000d81c 0x4>, + <0xe000d820 0x4>; + reg-names = "phy_speed_mode", + "master_active", + "master_settings", + "master_addr", + "master_rxtx", + "master_status", + "master_ev_status", + "master_ev_pending", + "master_ev_enable"; + interrupts = <10 0>; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + }; -&gpio_in { - status = "okay"; -}; + pwm0: pwm@e0007000 { + compatible = "litex,pwm"; + reg = <0xe0007000 0x4 0xe0007004 0x10 0xe0007014 0x10>; + reg-names = "enable", "width", "period"; + status = "okay"; + #pwm-cells = <2>; + }; -&i2s_rx { - status = "okay"; -}; + gpio_out: gpio@e0005800 { + compatible = "litex,gpio"; + reg = <0xe0005800 0x4>; + reg-names = "control"; + ngpios = <4>; + port-is-output; + status = "okay"; + gpio-controller; + #gpio-cells = <2>; + }; -&i2s_tx { - status = "okay"; -}; + gpio_in: gpio@e0006000 { + compatible = "litex,gpio"; + reg = <0xe0006000 0x4 + 0xe0006004 0x4 + 0xe0006008 0x4 + 0xe0006010 0x4 + 0xe0006014 0x4>; + interrupt-parent = <&intc0>; + interrupts = <4 2>; + reg-names = "base", + "irq_mode", + "irq_edge", + "irq_pend", + "irq_en"; + ngpios = <4>; + status = "okay"; + gpio-controller; + #gpio-cells = <2>; + }; -&clk0 { - status = "okay"; -}; + i2s_rx: i2s_rx@e000a800 { + compatible = "litex,i2s"; + reg = <0xe000a800 0x4 + 0xe000a804 0x4 + 0xe000a808 0x4 + 0xe000a80c 0x4 + 0xe000a810 0x4 + 0xe000a814 0x4 + 0xb1000000 0x40000>; + interrupt-parent = <&intc0>; + interrupts = <6 2>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "ev_status", + "ev_pending", + "ev_enable", + "rx_ctl", + "rx_stat", + "rx_conf", + "fifo"; + fifo-depth = <256>; + status = "okay"; + }; -&clk1 { - status = "okay"; -}; + i2s_tx: i2s_tx@e000b000 { + compatible = "litex,i2s"; + reg = <0xe000b000 0x4 + 0xe000b004 0x4 + 0xe000b008 0x4 + 0xe000b00c 0x4 + 0xe000b010 0x4 + 0xe000b014 0x4 + 0xb2000000 0x40000>; + interrupt-parent = <&intc0>; + interrupts = <7 2>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "ev_status", + "ev_pending", + "ev_enable", + "tx_ctl", + "tx_stat", + "tx_conf", + "fifo"; + fifo-depth = <256>; + status = "okay"; + }; + + clock-outputs { + #address-cells = <1>; + #size-cells = <0>; -&clock0 { - status = "okay"; + clk0: clock-controller@0 { + #clock-cells = <1>; + reg = <0>; + compatible = "litex,clkout"; + clock-output-names = "CLK_0"; + litex,clock-frequency = <11289600>; + litex,clock-phase = <0>; + litex,clock-duty-num = <1>; + litex,clock-duty-den = <2>; + litex,clock-margin = <1>; + litex,clock-margin-exp = <2>; + status = "okay"; + }; + + clk1: clock-controller@1 { + #clock-cells = <1>; + reg = <1>; + compatible = "litex,clkout"; + clock-output-names = "CLK_1"; + litex,clock-frequency = <22579200>; + litex,clock-phase = <0>; + litex,clock-duty-num = <1>; + litex,clock-duty-den = <2>; + litex,clock-margin = <1>; + litex,clock-margin-exp = <2>; + status = "okay"; + }; + }; + + clock0: clock@e0004800 { + compatible = "litex,clk"; + reg = <0xe0004800 0x4 + 0xe0004804 0x4 + 0xe0004808 0x4 + 0xe000480c 0x4 + 0xe0004810 0x4 + 0xe0004814 0x4 + 0xe0004818 0x4 + 0xe000481c 0x4>; + reg-names = "drp_reset", + "drp_locked", + "drp_read", + "drp_write", + "drp_drdy", + "drp_adr", + "drp_dat_w", + "drp_dat_r"; + #clock-cells = <1>; + clocks = <&clk0 0>, <&clk1 1>; + clock-output-names = "CLK_0", "CLK_1"; + litex,lock-timeout = <10>; + litex,drdy-timeout = <10>; + litex,divclk-divide-min = <1>; + litex,divclk-divide-max = <107>; + litex,clkfbout-mult-min = <2>; + litex,clkfbout-mult-max = <65>; + litex,vco-freq-min = <600000000>; + litex,vco-freq-max = <1200000000>; + litex,clkout-divide-min = <1>; + litex,clkout-divide-max = <126>; + litex,vco-margin = <0>; + status = "okay"; + }; + }; }; diff --git a/dts/riscv/riscv32-litex-vexriscv.dtsi b/dts/riscv/riscv32-litex-vexriscv.dtsi index 33f7bd03fc286..c51803ed5ab84 100644 --- a/dts/riscv/riscv32-litex-vexriscv.dtsi +++ b/dts/riscv/riscv32-litex-vexriscv.dtsi @@ -4,18 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - / { #address-cells = <1>; #size-cells = <1>; compatible = "litex,vexriscv", "litex-dev"; model = "litex,vexriscv"; - chosen { - zephyr,entropy = &prbs0; - }; - cpus { #address-cells = <1>; #size-cells = <0>; @@ -36,16 +30,6 @@ compatible = "litex,vexriscv"; ranges; - ctrl0: soc_controller@e0000000 { - compatible = "litex,soc-controller"; - reg = <0xe0000000 0x4 - 0xe0000004 0x4 - 0xe0000008 0x4>; - reg-names = "reset", - "scratch", - "bus_errors"; - }; - intc0: interrupt-controller@bc0 { compatible = "litex,vexriscv-intc0"; #address-cells = <0>; @@ -55,396 +39,5 @@ reg-names = "irq_mask", "irq_pending"; riscv,max-priority = <7>; }; - - uart0: serial@e0001800 { - compatible = "litex,uart"; - interrupt-parent = <&intc0>; - interrupts = <2 10>; - reg = <0xe0001800 0x4 - 0xe0001804 0x4 - 0xe0001808 0x4 - 0xe000180c 0x4 - 0xe0001810 0x4 - 0xe0001814 0x4 - 0xe0001818 0x4 - 0xe000181c 0x4>; - reg-names = "rxtx", - "txfull", - "rxempty", - "ev_status", - "ev_pending", - "ev_enable", - "txempty", - "rxfull"; - status = "disabled"; - }; - - spi0: spi@e0002000 { - compatible = "litex,spi"; - reg = <0xe0002000 0x4 - 0xe0002004 0x4 - 0xe0002008 0x4 - 0xe000200c 0x4 - 0xe0002010 0x4 - 0xe0002014 0x4>; - reg-names = "control", - "status", - "mosi", - "miso", - "cs", - "loopback"; - status = "disabled"; - #address-cells = <1>; - #size-cells = <0>; - }; - - spi1: spi@e000c000 { - compatible = "litex,spi-litespi"; - interrupt-parent = <&intc0>; - reg = <0xe000c000 0x4>, - <0xe000c004 0x4>, - <0xe000c008 0x4>, - <0xe000c00c 0x4>, - <0xe000c010 0x4>, - <0xe000c014 0x4>, - <0xe000c018 0x4>, - <0xe000c01c 0x4>, - <0xe000c020 0x4>, - <0x60000000 0x1000000>; - reg-names = "phy_clk_divisor", - "mmap_dummy_bits", - "master_cs", - "master_phyconfig", - "master_rxtx", - "master_status", - "master_ev_status", - "master_ev_pending", - "master_ev_enable", - "flash_mmap"; - interrupts = <9 0>; - #address-cells = <1>; - #size-cells = <0>; - - spiflash0: flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <10000000>; - }; - }; - - timer0: timer@e0002800 { - compatible = "litex,timer0"; - interrupt-parent = <&intc0>; - interrupts = <1 0>; - reg = <0xe0002800 0x4 - 0xe0002804 0x4 - 0xe0002808 0x4 - 0xe000280c 0x4 - 0xe0002810 0x4 - 0xe0002814 0x4 - 0xe0002818 0x4 - 0xe000281c 0x4 - 0xe0002820 0x4 - 0xe0002824 0x8>; - reg-names = "load", - "reload", - "en", - "update_value", - "value", - "ev_status", - "ev_pending", - "ev_enable", - "uptime_latch", - "uptime_cycles"; - status = "disabled"; - }; - - wdt0: watchdog@e000d000 { - compatible = "litex,watchdog"; - interrupt-parent = <&intc0>; - reg = <0xe000d000 0x4>, - <0xe000d004 0x4>, - <0xe000d008 0x4>, - <0xe000d00c 0x4>, - <0xe000d010 0x4>, - <0xe000d014 0x4>; - reg-names = "control", - "cycles", - "remaining", - "ev_status", - "ev_pending", - "ev_enable"; - interrupts = <8 15>; - }; - - mdio0: mdio@e0008000 { - compatible = "litex,liteeth-mdio"; - reg = <0xe0008000 0x4>, - <0xe0008004 0x4>, - <0xe0008008 0x4>; - reg-names = "crg_reset", - "mdio_w", - "mdio_r"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - - phy0: ethernet-phy@1 { - compatible = "ethernet-phy"; - reg = <1>; - }; - }; - - eth0: ethernet@e0009800 { - compatible = "litex,liteeth"; - interrupt-parent = <&intc0>; - interrupts = <3 0>; - reg = <0xe0009800 0x4 - 0xe0009804 0x4 - 0xe0009808 0x4 - 0xe000980c 0x4 - 0xe0009810 0x4 - 0xe0009814 0x4 - 0xe0009818 0x4 - 0xe000981c 0x4 - 0xe0009820 0x4 - 0xe0009824 0x4 - 0xe0009828 0x4 - 0xe000982c 0x4 - 0xe0009830 0x4 - 0xe0009834 0x4 - 0xb0000000 0x2000>; - local-mac-address = [10 e2 d5 00 00 02]; - reg-names = "rx_slot", - "rx_length", - "rx_errors", - "rx_ev_status", - "rx_ev_pending", - "rx_ev_enable", - "tx_start", - "tx_ready", - "tx_level", - "tx_slot", - "tx_length", - "tx_ev_status", - "tx_ev_pending", - "tx_ev_enable", - "buffers"; - phy-handle = <&phy0>; - status = "disabled"; - }; - - dna0: dna@e0003800 { - compatible = "litex,dna0"; - /* DNA data is 57-bits long, - * so it requires 8 bytes. - * In LiteX each 32-bit register holds - * only a single byte of meaningful data, - * hence 8 registers. - */ - reg = <0xe0003800 0x20>; - reg-names = "mem"; - status = "disabled"; - }; - - i2c0: i2c@e0005000 { - compatible = "litex,i2c"; - reg = <0xe0005000 0x4 0xe0005004 0x4>; - reg-names = "write", "read"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c1: i2c@e000d800 { - compatible = "litex,litei2c"; - interrupt-parent = <&intc0>; - reg = <0xe000d800 0x4>, - <0xe000d804 0x4>, - <0xe000d808 0x4>, - <0xe000d80c 0x4>, - <0xe000d810 0x4>, - <0xe000d814 0x4>, - <0xe000d818 0x4>, - <0xe000d81c 0x4>, - <0xe000d820 0x4>; - reg-names = "phy_speed_mode", - "master_active", - "master_settings", - "master_addr", - "master_rxtx", - "master_status", - "master_ev_status", - "master_ev_pending", - "master_ev_enable"; - interrupts = <10 0>; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - gpio_out: gpio@e0005800 { - compatible = "litex,gpio"; - reg = <0xe0005800 0x4>; - reg-names = "control"; - ngpios = <4>; - port-is-output; - status = "disabled"; - gpio-controller; - #gpio-cells = <2>; - }; - - gpio_in: gpio@e0006000 { - compatible = "litex,gpio"; - reg = <0xe0006000 0x4 - 0xe0006004 0x4 - 0xe0006008 0x4 - 0xe0006010 0x4 - 0xe0006014 0x4>; - interrupt-parent = <&intc0>; - interrupts = <4 2>; - reg-names = "base", - "irq_mode", - "irq_edge", - "irq_pend", - "irq_en"; - ngpios = <4>; - status = "disabled"; - gpio-controller; - #gpio-cells = <2>; - }; - - prbs0: prbs@e0006800 { - compatible = "litex,prbs"; - reg = <0xe0006800 0x4>; - reg-names = "status"; - status = "disabled"; - }; - - pwm0: pwm@e0007000 { - compatible = "litex,pwm"; - reg = <0xe0007000 0x4 0xe0007004 0x10 0xe0007014 0x10>; - reg-names = "enable", "width", "period"; - status = "disabled"; - #pwm-cells = <2>; - }; - - i2s_rx: i2s_rx@e000a800 { - compatible = "litex,i2s"; - reg = <0xe000a800 0x4 - 0xe000a804 0x4 - 0xe000a808 0x4 - 0xe000a80c 0x4 - 0xe000a810 0x4 - 0xe000a814 0x4 - 0xb1000000 0x40000>; - interrupt-parent = <&intc0>; - interrupts = <6 2>; - #address-cells = <1>; - #size-cells = <0>; - reg-names = "ev_status", - "ev_pending", - "ev_enable", - "rx_ctl", - "rx_stat", - "rx_conf", - "fifo"; - fifo-depth = <256>; - status = "disabled"; - }; - - i2s_tx: i2s_tx@e000b000 { - compatible = "litex,i2s"; - reg = <0xe000b000 0x4 - 0xe000b004 0x4 - 0xe000b008 0x4 - 0xe000b00c 0x4 - 0xe000b010 0x4 - 0xe000b014 0x4 - 0xb2000000 0x40000>; - interrupt-parent = <&intc0>; - interrupts = <7 2>; - #address-cells = <1>; - #size-cells = <0>; - reg-names = "ev_status", - "ev_pending", - "ev_enable", - "tx_ctl", - "tx_stat", - "tx_conf", - "fifo"; - fifo-depth = <256>; - status = "disabled"; - }; - - clock-outputs { - #address-cells = <1>; - #size-cells = <0>; - - clk0: clock-controller@0 { - #clock-cells = <1>; - reg = <0>; - compatible = "litex,clkout"; - clock-output-names = "CLK_0"; - litex,clock-frequency = <11289600>; - litex,clock-phase = <0>; - litex,clock-duty-num = <1>; - litex,clock-duty-den = <2>; - litex,clock-margin = <1>; - litex,clock-margin-exp = <2>; - status = "disabled"; - }; - - clk1: clock-controller@1 { - #clock-cells = <1>; - reg = <1>; - compatible = "litex,clkout"; - clock-output-names = "CLK_1"; - litex,clock-frequency = <22579200>; - litex,clock-phase = <0>; - litex,clock-duty-num = <1>; - litex,clock-duty-den = <2>; - litex,clock-margin = <1>; - litex,clock-margin-exp = <2>; - status = "disabled"; - }; - }; - - clock0: clock@e0004800 { - compatible = "litex,clk"; - reg = <0xe0004800 0x4 - 0xe0004804 0x4 - 0xe0004808 0x4 - 0xe000480c 0x4 - 0xe0004810 0x4 - 0xe0004814 0x4 - 0xe0004818 0x4 - 0xe000481c 0x4>; - reg-names = "drp_reset", - "drp_locked", - "drp_read", - "drp_write", - "drp_drdy", - "drp_adr", - "drp_dat_w", - "drp_dat_r"; - #clock-cells = <1>; - clocks = <&clk0 0>, <&clk1 1>; - clock-output-names = "CLK_0", "CLK_1"; - litex,lock-timeout = <10>; - litex,drdy-timeout = <10>; - litex,divclk-divide-min = <1>; - litex,divclk-divide-max = <107>; - litex,clkfbout-mult-min = <2>; - litex,clkfbout-mult-max = <65>; - litex,vco-freq-min = <600000000>; - litex,vco-freq-max = <1200000000>; - litex,clkout-divide-min = <1>; - litex,clkout-divide-max = <126>; - litex,vco-margin = <0>; - status = "disabled"; - }; }; }; From e9b11abd7242829c5555f1adaa5036000150b27e Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 9 Oct 2025 14:20:12 +0200 Subject: [PATCH 049/397] drivers: video: stm32: don't mix HAL return value and errno Clarify HAL return value is of type HAL_StatusTypeDef and not an int in STM32 DCMI and DCMIPP drivers. For consistency, rename the variable holding HAL return value from ret to hal_ret. Signed-off-by: Etienne Carriere --- drivers/video/video_stm32_dcmi.c | 14 +-- drivers/video/video_stm32_dcmipp.c | 185 +++++++++++++++-------------- 2 files changed, 104 insertions(+), 95 deletions(-) diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c index e390395a1c8a4..ffaf3f4f97fdf 100644 --- a/drivers/video/video_stm32_dcmi.c +++ b/drivers/video/video_stm32_dcmi.c @@ -252,6 +252,7 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable, { struct video_stm32_dcmi_data *data = dev->data; const struct video_stm32_dcmi_config *config = dev->config; + HAL_StatusTypeDef hal_ret; int err; if (!enable) { @@ -260,8 +261,8 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable, return err; } - err = HAL_DCMI_Stop(&data->hdcmi); - if (err != HAL_OK) { + hal_ret = HAL_DCMI_Stop(&data->hdcmi); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to stop DCMI"); return -EIO; } @@ -283,9 +284,9 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable, data->hdcmi.Instance->CR &= ~(DCMI_CR_FCRC_0 | DCMI_CR_FCRC_1); data->hdcmi.Instance->CR |= STM32_DCMI_GET_CAPTURE_RATE(data->capture_rate); - err = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS, - (uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4); - if (err != HAL_OK) { + hal_ret = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS, + (uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to start DCMI DMA"); return -EIO; } @@ -577,8 +578,7 @@ static int video_stm32_dcmi_init(const struct device *dev) config->irq_config(dev); /* Initialize DCMI peripheral */ - err = HAL_DCMI_Init(&data->hdcmi); - if (err != HAL_OK) { + if (HAL_DCMI_Init(&data->hdcmi) != HAL_OK) { LOG_ERR("DCMI initialization failed."); return -EIO; } diff --git a/drivers/video/video_stm32_dcmipp.c b/drivers/video/video_stm32_dcmipp.c index 37c7d1724598b..8564f9235cb81 100644 --- a/drivers/video/video_stm32_dcmipp.c +++ b/drivers/video/video_stm32_dcmipp.c @@ -196,15 +196,15 @@ void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t struct stm32_dcmipp_data *dcmipp = CONTAINER_OF(hdcmipp, struct stm32_dcmipp_data, hdcmipp); struct stm32_dcmipp_pipe_data *pipe = dcmipp->pipe[Pipe]; + HAL_StatusTypeDef hal_ret; uint32_t bytesused; - int ret; __ASSERT(pipe->active, "Unexpected behavior, active_buf must not be NULL"); /* Counter is only available on Pipe0 */ if (Pipe == DCMIPP_PIPE0) { - ret = HAL_DCMIPP_PIPE_GetDataCounter(hdcmipp, Pipe, &bytesused); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_GetDataCounter(hdcmipp, Pipe, &bytesused); + if (hal_ret != HAL_OK) { LOG_WRN("Failed to read counter - buffer in error"); pipe->active->bytesused = 0; } else { @@ -324,7 +324,7 @@ static int stm32_dcmipp_conf_parallel(const struct device *dev, struct stm32_dcmipp_data *dcmipp = dev->data; const struct stm32_dcmipp_config *config = dev->config; DCMIPP_ParallelConfTypeDef parallel_cfg = { 0 }; - int ret; + HAL_StatusTypeDef hal_ret; parallel_cfg.Format = input_fmt->dcmipp_format; parallel_cfg.SwapCycles = DCMIPP_SWAPCYCLES_DISABLE; @@ -334,8 +334,8 @@ static int stm32_dcmipp_conf_parallel(const struct device *dev, parallel_cfg.ExtendedDataMode = DCMIPP_INTERFACE_8BITS; parallel_cfg.SynchroMode = DCMIPP_SYNCHRO_HARDWARE; - ret = HAL_DCMIPP_PARALLEL_SetConfig(&dcmipp->hdcmipp, ¶llel_cfg); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PARALLEL_SetConfig(&dcmipp->hdcmipp, ¶llel_cfg); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to configure DCMIPP Parallel interface"); return -EIO; } @@ -381,8 +381,9 @@ static int stm32_dcmipp_conf_csi(const struct device *dev, uint32_t dcmipp_csi_b const struct stm32_dcmipp_config *config = dev->config; struct stm32_dcmipp_data *dcmipp = dev->data; DCMIPP_CSI_ConfTypeDef csiconf = { 0 }; + HAL_StatusTypeDef hal_ret; int64_t phy_bitrate; - int err, i; + int i; csiconf.NumberOfLanes = config->csi.nb_lanes == 2 ? DCMIPP_CSI_TWO_DATA_LANES : DCMIPP_CSI_ONE_DATA_LANE; @@ -411,17 +412,17 @@ static int stm32_dcmipp_conf_csi(const struct device *dev, uint32_t dcmipp_csi_b } csiconf.PHYBitrate = stm32_dcmipp_bitrate[i].PHYBitrate; - err = HAL_DCMIPP_CSI_SetConfig(&dcmipp->hdcmipp, &csiconf); - if (err != HAL_OK) { + hal_ret = HAL_DCMIPP_CSI_SetConfig(&dcmipp->hdcmipp, &csiconf); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to configure DCMIPP CSI"); return -EIO; } /* Set Virtual Channel config */ /* TODO - need to be able to use an alternate VC, info coming from the source */ - err = HAL_DCMIPP_CSI_SetVCConfig(&dcmipp->hdcmipp, DCMIPP_VIRTUAL_CHANNEL0, - dcmipp_csi_bpp); - if (err != HAL_OK) { + hal_ret = HAL_DCMIPP_CSI_SetVCConfig(&dcmipp->hdcmipp, DCMIPP_VIRTUAL_CHANNEL0, + dcmipp_csi_bpp); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to set CSI configuration"); return -EIO; } @@ -694,7 +695,7 @@ static int stm32_dcmipp_set_crop(struct stm32_dcmipp_pipe_data *pipe) DCMIPP_CropConfTypeDef crop_cfg; uint32_t frame_width = dcmipp->source_fmt.width; uint32_t frame_height = dcmipp->source_fmt.height; - int ret; + HAL_StatusTypeDef hal_ret; #if defined(STM32_DCMIPP_HAS_PIXEL_PIPES) if (pipe->id == DCMIPP_PIPE1 || pipe->id == DCMIPP_PIPE2) { @@ -705,8 +706,8 @@ static int stm32_dcmipp_set_crop(struct stm32_dcmipp_pipe_data *pipe) /* If crop area is equal to frame size, disable the crop */ if (pipe->crop.width == frame_width && pipe->crop.height == frame_height) { - ret = HAL_DCMIPP_PIPE_DisableCrop(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_DisableCrop(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable pipe crop"); return -EIO; } @@ -734,14 +735,14 @@ static int stm32_dcmipp_set_crop(struct stm32_dcmipp_pipe_data *pipe) } #endif - ret = HAL_DCMIPP_PIPE_SetCropConfig(&dcmipp->hdcmipp, pipe->id, &crop_cfg); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_SetCropConfig(&dcmipp->hdcmipp, pipe->id, &crop_cfg); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to configure pipe crop"); return -EIO; } - ret = HAL_DCMIPP_PIPE_EnableCrop(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_EnableCrop(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to enable pipe crop"); return -EIO; } @@ -763,17 +764,17 @@ static int stm32_dcmipp_set_downscale(struct stm32_dcmipp_pipe_data *pipe) DCMIPP_DownsizeTypeDef downsize_cfg; struct video_rect *compose = &pipe->compose; uint32_t hdec = 1, vdec = 1; - int ret; + HAL_StatusTypeDef hal_ret; if (compose->width == pipe->crop.width && compose->height == pipe->crop.height) { - ret = HAL_DCMIPP_PIPE_DisableDecimation(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_DisableDecimation(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable the pipe decimation"); return -EIO; } - ret = HAL_DCMIPP_PIPE_DisableDownsize(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_DisableDownsize(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable the pipe downsize"); return -EIO; } @@ -792,8 +793,8 @@ static int stm32_dcmipp_set_downscale(struct stm32_dcmipp_pipe_data *pipe) } if (hdec == 1 && vdec == 1) { - ret = HAL_DCMIPP_PIPE_DisableDecimation(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_DisableDecimation(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable the pipe decimation"); return -EIO; } @@ -802,13 +803,13 @@ static int stm32_dcmipp_set_downscale(struct stm32_dcmipp_pipe_data *pipe) dec_cfg.HRatio = __builtin_ctz(hdec) << DCMIPP_P1DECR_HDEC_Pos; dec_cfg.VRatio = __builtin_ctz(vdec) << DCMIPP_P1DECR_VDEC_Pos; - ret = HAL_DCMIPP_PIPE_SetDecimationConfig(&dcmipp->hdcmipp, pipe->id, &dec_cfg); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_SetDecimationConfig(&dcmipp->hdcmipp, pipe->id, &dec_cfg); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable the pipe decimation"); return -EIO; } - ret = HAL_DCMIPP_PIPE_EnableDecimation(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_EnableDecimation(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to enable the pipe decimation"); return -EIO; } @@ -838,14 +839,14 @@ static int stm32_dcmipp_set_downscale(struct stm32_dcmipp_pipe_data *pipe) downsize_cfg.HSize = compose->width; downsize_cfg.VSize = compose->height; - ret = HAL_DCMIPP_PIPE_SetDownsizeConfig(&dcmipp->hdcmipp, pipe->id, &downsize_cfg); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_SetDownsizeConfig(&dcmipp->hdcmipp, pipe->id, &downsize_cfg); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to configure the pipe downsize"); return -EIO; } - ret = HAL_DCMIPP_PIPE_EnableDownsize(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_EnableDownsize(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to enable the pipe downsize"); return -EIO; } @@ -874,7 +875,7 @@ static int stm32_dcmipp_set_yuv_conversion(struct stm32_dcmipp_pipe_data *pipe, { struct stm32_dcmipp_data *dcmipp = pipe->dcmipp; const DCMIPP_ColorConversionConfTypeDef *cfg = NULL; - int ret; + HAL_StatusTypeDef hal_ret; /* No YUV conversion on pipe 2 */ if (pipe->id == DCMIPP_PIPE2) { @@ -892,8 +893,8 @@ static int stm32_dcmipp_set_yuv_conversion(struct stm32_dcmipp_pipe_data *pipe, /* Need to perform YUV to RGB conversion */ cfg = &stm32_dcmipp_yuv_to_rgb; } else { - ret = HAL_DCMIPP_PIPE_DisableYUVConversion(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_DisableYUVConversion(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable YUV conversion"); return -EIO; } @@ -901,14 +902,14 @@ static int stm32_dcmipp_set_yuv_conversion(struct stm32_dcmipp_pipe_data *pipe, return 0; } - ret = HAL_DCMIPP_PIPE_SetYUVConversionConfig(&dcmipp->hdcmipp, pipe->id, cfg); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_SetYUVConversionConfig(&dcmipp->hdcmipp, pipe->id, cfg); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to setup YUV conversion"); return -EIO; } - ret = HAL_DCMIPP_PIPE_EnableYUVConversion(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_EnableYUVConversion(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable YUV conversion"); return -EIO; } @@ -925,7 +926,7 @@ static int stm32_dcmipp_start_pipeline(const struct device *dev, #if defined(STM32_DCMIPP_HAS_PIXEL_PIPES) struct video_format *fmt = &pipe->fmt; #endif - int ret; + HAL_StatusTypeDef hal_ret; #if defined(STM32_DCMIPP_HAS_PIXEL_PIPES) if (VIDEO_FMT_IS_PLANAR(fmt)) { @@ -938,20 +939,21 @@ static int stm32_dcmipp_start_pipeline(const struct device *dev, }; if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) { - ret = HAL_DCMIPP_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id, - &planar_addr, DCMIPP_MODE_CONTINUOUS); + hal_ret = HAL_DCMIPP_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id, + &planar_addr, + DCMIPP_MODE_CONTINUOUS); } #if defined(STM32_DCMIPP_HAS_CSI) else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) { - ret = HAL_DCMIPP_CSI_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id, - DCMIPP_VIRTUAL_CHANNEL0, - &planar_addr, - DCMIPP_MODE_CONTINUOUS); + hal_ret = HAL_DCMIPP_CSI_PIPE_FullPlanarStart(&dcmipp->hdcmipp, pipe->id, + DCMIPP_VIRTUAL_CHANNEL0, + &planar_addr, + DCMIPP_MODE_CONTINUOUS); } #endif else { LOG_ERR("Invalid bus_type"); - ret = -EINVAL; + hal_ret = HAL_ERROR; } } else if (VIDEO_FMT_IS_SEMI_PLANAR(fmt)) { uint8_t *uv_addr = pipe->next->buffer + VIDEO_FMT_PLANAR_Y_PLANE_SIZE(fmt); @@ -961,45 +963,45 @@ static int stm32_dcmipp_start_pipeline(const struct device *dev, }; if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) { - ret = HAL_DCMIPP_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id, - &semiplanar_addr, - DCMIPP_MODE_CONTINUOUS); + hal_ret = HAL_DCMIPP_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id, + &semiplanar_addr, + DCMIPP_MODE_CONTINUOUS); } #if defined(STM32_DCMIPP_HAS_CSI) else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) { - ret = HAL_DCMIPP_CSI_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id, - DCMIPP_VIRTUAL_CHANNEL0, - &semiplanar_addr, - DCMIPP_MODE_CONTINUOUS); + hal_ret = HAL_DCMIPP_CSI_PIPE_SemiPlanarStart(&dcmipp->hdcmipp, pipe->id, + DCMIPP_VIRTUAL_CHANNEL0, + &semiplanar_addr, + DCMIPP_MODE_CONTINUOUS); } #endif else { LOG_ERR("Invalid bus_type"); - ret = -EINVAL; + hal_ret = HAL_ERROR; } } else { #endif if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) { - ret = HAL_DCMIPP_PIPE_Start(&dcmipp->hdcmipp, pipe->id, - (uint32_t)pipe->next->buffer, - DCMIPP_MODE_CONTINUOUS); + hal_ret = HAL_DCMIPP_PIPE_Start(&dcmipp->hdcmipp, pipe->id, + (uint32_t)pipe->next->buffer, + DCMIPP_MODE_CONTINUOUS); } #if defined(STM32_DCMIPP_HAS_CSI) else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) { - ret = HAL_DCMIPP_CSI_PIPE_Start(&dcmipp->hdcmipp, pipe->id, - DCMIPP_VIRTUAL_CHANNEL0, - (uint32_t)pipe->next->buffer, - DCMIPP_MODE_CONTINUOUS); + hal_ret = HAL_DCMIPP_CSI_PIPE_Start(&dcmipp->hdcmipp, pipe->id, + DCMIPP_VIRTUAL_CHANNEL0, + (uint32_t)pipe->next->buffer, + DCMIPP_MODE_CONTINUOUS); } #endif else { LOG_ERR("Invalid bus_type"); - ret = -EINVAL; + hal_ret = HAL_ERROR; } #if defined(STM32_DCMIPP_HAS_PIXEL_PIPES) } #endif - if (ret != HAL_OK) { + if (hal_ret != HAL_OK) { return -EIO; } @@ -1018,6 +1020,7 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) DCMIPP_CSI_PIPE_ConfTypeDef csi_pipe_cfg = { 0 }; #endif DCMIPP_PipeConfTypeDef pipe_cfg = { 0 }; + HAL_StatusTypeDef hal_ret; int ret; k_mutex_lock(&pipe->lock, K_FOREVER); @@ -1072,10 +1075,10 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) /* Configure the Pipe input */ csi_pipe_cfg.DataTypeMode = DCMIPP_DTMODE_DTIDA; csi_pipe_cfg.DataTypeIDA = input_fmt->dcmipp_csi_dt; - ret = HAL_DCMIPP_CSI_PIPE_SetConfig(&dcmipp->hdcmipp, - pipe->id == DCMIPP_PIPE2 ? DCMIPP_PIPE1 : pipe->id, - &csi_pipe_cfg); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_CSI_PIPE_SetConfig(&dcmipp->hdcmipp, + pipe->id == DCMIPP_PIPE2 ? DCMIPP_PIPE1 : pipe->id, + &csi_pipe_cfg); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to configure pipe #%d input", pipe->id); ret = -EIO; goto out; @@ -1097,8 +1100,8 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) pipe_cfg.PixelPackerFormat = mapping->pixels.dcmipp_format; } #endif - ret = HAL_DCMIPP_PIPE_SetConfig(&dcmipp->hdcmipp, pipe->id, &pipe_cfg); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_SetConfig(&dcmipp->hdcmipp, pipe->id, &pipe_cfg); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to configure pipe #%d", pipe->id); ret = -EIO; goto out; @@ -1113,9 +1116,9 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) /* Only the PIPE0 has a limiter */ /* Set Limiter to avoid buffer overflow, in number of 32 bits words */ - ret = HAL_DCMIPP_PIPE_EnableLimitEvent(&dcmipp->hdcmipp, DCMIPP_PIPE0, - (fmt->pitch * fmt->height) / 4); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_EnableLimitEvent(&dcmipp->hdcmipp, DCMIPP_PIPE0, + (fmt->pitch * fmt->height) / 4); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to set limiter"); ret = -EIO; goto out; @@ -1128,15 +1131,15 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) /* Enable / disable SWAPRB if necessary */ if (mapping->pixels.swap_uv) { - ret = HAL_DCMIPP_PIPE_EnableRedBlueSwap(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_EnableRedBlueSwap(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to enable Red-Blue swap"); ret = -EIO; goto out; } } else { - ret = HAL_DCMIPP_PIPE_DisableRedBlueSwap(&dcmipp->hdcmipp, pipe->id); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_DisableRedBlueSwap(&dcmipp->hdcmipp, pipe->id); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable Red-Blue swap"); ret = -EIO; goto out; @@ -1145,17 +1148,18 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) if (source_colorspace == VIDEO_COLORSPACE_RAW) { /* Enable demosaicing if input format is Bayer */ - ret = HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(&dcmipp->hdcmipp, DCMIPP_PIPE1); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(&dcmipp->hdcmipp, + DCMIPP_PIPE1); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to enable demosaicing"); ret = -EIO; goto out; } } else { /* Disable demosaicing */ - ret = HAL_DCMIPP_PIPE_DisableISPRawBayer2RGB(&dcmipp->hdcmipp, - DCMIPP_PIPE1); - if (ret != HAL_OK) { + hal_ret = HAL_DCMIPP_PIPE_DisableISPRawBayer2RGB(&dcmipp->hdcmipp, + DCMIPP_PIPE1); + if (hal_ret != HAL_OK) { LOG_ERR("Failed to disable demosaicing"); ret = -EIO; goto out; @@ -1258,12 +1262,18 @@ static int stm32_dcmipp_stream_disable(const struct device *dev) #endif /* Disable the DCMIPP Pipeline */ + ret = 0; if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) { - ret = HAL_DCMIPP_PIPE_Stop(&dcmipp->hdcmipp, pipe->id); + if (HAL_DCMIPP_PIPE_Stop(&dcmipp->hdcmipp, pipe->id) != HAL_OK) { + ret = -EIO; + } } #if defined(STM32_DCMIPP_HAS_CSI) else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) { - ret = HAL_DCMIPP_CSI_PIPE_Stop(&dcmipp->hdcmipp, pipe->id, DCMIPP_VIRTUAL_CHANNEL0); + if (HAL_DCMIPP_CSI_PIPE_Stop(&dcmipp->hdcmipp, pipe->id, + DCMIPP_VIRTUAL_CHANNEL0) != HAL_OK) { + ret = -EIO; + } } #endif else { @@ -1271,9 +1281,8 @@ static int stm32_dcmipp_stream_disable(const struct device *dev) ret = -EIO; goto out; } - if (ret != HAL_OK) { + if (ret < 0) { LOG_ERR("Failed to stop the pipeline"); - ret = -EIO; goto out; } From 0f3fc1cd546bfbd5b67aaf9789224c08f29ad60b Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 9 Oct 2025 14:16:58 +0200 Subject: [PATCH 050/397] drivers: video: stm32: test HAL functions return value Add missing test of some HAL functions return value. Signed-off-by: Etienne Carriere --- drivers/video/video_stm32_dcmi.c | 7 +++++-- drivers/video/video_stm32_dcmipp.c | 12 +++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c index ffaf3f4f97fdf..055d5199ae7ec 100644 --- a/drivers/video/video_stm32_dcmi.c +++ b/drivers/video/video_stm32_dcmi.c @@ -87,8 +87,10 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) struct video_stm32_dcmi_data *dev_data = CONTAINER_OF(hdcmi, struct video_stm32_dcmi_data, hdcmi); struct video_buffer *vbuf; + HAL_StatusTypeDef __maybe_unused hal_ret; - HAL_DCMI_Suspend(hdcmi); + hal_ret = HAL_DCMI_Suspend(hdcmi); + __ASSERT_NO_MSG(hal_ret == HAL_OK); vbuf = k_fifo_get(&dev_data->fifo_in, K_NO_WAIT); @@ -103,7 +105,8 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) k_fifo_put(&dev_data->fifo_out, vbuf); resume: - HAL_DCMI_Resume(hdcmi); + hal_ret = HAL_DCMI_Resume(hdcmi); + __ASSERT_NO_MSG(hal_ret == HAL_OK); } static void stm32_dcmi_isr(const struct device *dev) diff --git a/drivers/video/video_stm32_dcmipp.c b/drivers/video/video_stm32_dcmipp.c index 8564f9235cb81..05955f4967d2e 100644 --- a/drivers/video/video_stm32_dcmipp.c +++ b/drivers/video/video_stm32_dcmipp.c @@ -1205,12 +1205,18 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) if (ret < 0) { LOG_ERR("Failed to start the source"); if (config->bus_type == VIDEO_BUS_TYPE_PARALLEL) { - HAL_DCMIPP_PIPE_Stop(&dcmipp->hdcmipp, pipe->id); + if (HAL_DCMIPP_PIPE_Stop(&dcmipp->hdcmipp, pipe->id) != HAL_OK) { + ret = -EIO; + goto out; + } } #if defined(STM32_DCMIPP_HAS_CSI) else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) { - HAL_DCMIPP_CSI_PIPE_Stop(&dcmipp->hdcmipp, pipe->id, - DCMIPP_VIRTUAL_CHANNEL0); + if (HAL_DCMIPP_CSI_PIPE_Stop(&dcmipp->hdcmipp, pipe->id, + DCMIPP_VIRTUAL_CHANNEL0) != HAL_OK) { + ret = -EIO; + goto out; + } } #endif else { From 9404e27f3285129ec3aa343b69152c82d2263854 Mon Sep 17 00:00:00 2001 From: Muhammed Asif Date: Tue, 21 Oct 2025 11:55:37 +0530 Subject: [PATCH 051/397] dts: bindings: microchip: add tcc node for pwm peripheral Adds binding YAMLs for pwm peripheral Signed-off-by: Muhammed Asif --- dts/bindings/counter/microchip,tcc-g1.yaml | 73 ++++++++++++++++++++++ dts/bindings/pwm/microchip,tcc-g1-pwm.yaml | 31 +++++++++ 2 files changed, 104 insertions(+) create mode 100644 dts/bindings/counter/microchip,tcc-g1.yaml create mode 100644 dts/bindings/pwm/microchip,tcc-g1-pwm.yaml diff --git a/dts/bindings/counter/microchip,tcc-g1.yaml b/dts/bindings/counter/microchip,tcc-g1.yaml new file mode 100644 index 0000000000000..5c53351550861 --- /dev/null +++ b/dts/bindings/counter/microchip,tcc-g1.yaml @@ -0,0 +1,73 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip TCC G1 timer counter peripheral. + +description: | + Microchip TCC G1 timer counter peripheral. + + This peripheral is used for generating PWM signals. + This compatible string is to be used for the following peripherals: + - module name="TCC" id="U2213" version="3.1.0" + +compatible: "microchip,tcc-g1" + +include: + - name: base.yaml + - name: pinctrl-device.yaml + +properties: + reg: + description: | + Specifies the base address and size of the register set for the timer counter peripheral. + required: true + + interrupts: + description: | + Defines the interrupt lines used by the timer counter peripheral. + + This property specifies the interrupt number and priority. + required: true + + clocks: + description: | + Specifies the clock sources and their configurations for the timer counter peripheral. + + This property ensures the peripheral is provided with the necessary clock signals. + required: true + + prescaler: + type: int + description: | + Timer prescaler values. + + The prescaler divides the input clock frequency to + achieve the desired timer frequency. + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + - 64 + - 256 + - 1024 + + channels: + type: int + required: true + description: | + This specifies the maximum number of channels available for the peripheral instance. + + max-bit-width: + type: int + required: true + description: | + Maximum bit width supported by the counter. + + This property specifies the resolution of the counter. The value provided in the device tree + should reflect the maximum supported by the hardware instance. It should only be overridden + after consulting the relevant family datasheet to ensure compatibility. + enum: + - 16 + - 24 diff --git a/dts/bindings/pwm/microchip,tcc-g1-pwm.yaml b/dts/bindings/pwm/microchip,tcc-g1-pwm.yaml new file mode 100644 index 0000000000000..b02f32fd3019e --- /dev/null +++ b/dts/bindings/pwm/microchip,tcc-g1-pwm.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Microchip G1 TCC pwm driver. + +description: | + Microchip TCC pwm driver. + + This driver is used for configuring + and managing TCC (Timer/ Counter for Control Applications) + peripheral in Microchip microcontrollers. This peripherals + support creating PWM signals. The supported peripherals are + as follows: + - module name="TCC" id="U2213" version="3.1.0" + +compatible: "microchip,tcc-g1-pwm" + +include: + - base.yaml + - pwm-controller.yaml + - microchip,tcc-g1.yaml + - pinctrl-device.yaml + +properties: + "#pwm-cells": + const: 3 + +pwm-cells: + - channel + - period + - polarity From a9074016e6f2248198a347181037699052b3e74a Mon Sep 17 00:00:00 2001 From: Muhammed Asif Date: Tue, 21 Oct 2025 11:57:11 +0530 Subject: [PATCH 052/397] dts: arm: microchip: add tcc node for pwm peripheral Adds the dts nodes for pwm driver using tcc peripheral. Signed-off-by: Muhammed Asif --- .../sam/sam_d5x_e5x/common/samd5xe5x.dtsi | 34 +++++++++++++++++++ .../sam/sam_d5x_e5x/common/samd5xe5x_j.dtsi | 31 +++++++++++++++++ .../sam/sam_d5x_e5x/common/samd5xe5x_n.dtsi | 22 ++++++++++++ .../sam/sam_d5x_e5x/common/samd5xe5x_p.dtsi | 22 ++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_j.dtsi diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi index 4a545dd952048..efc33042eff97 100644 --- a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x.dtsi @@ -5,6 +5,7 @@ */ #include +#include #include / { @@ -123,6 +124,39 @@ clock-names = "mclk", "gclk"; }; + tcc0: tcc@41016000 { + compatible = "microchip,tcc-g1"; + reg = <0x41016000 0x2000>; + interrupts = <85 0>, <86 0>, <87 0>, <88 0>, <89 0>, <90 0>, <91 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBB_TCC0>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC0>; + clock-names = "mclk", "gclk"; + max-bit-width = <24>; + channels = <6>; + }; + + tcc1: tcc@41018000 { + compatible = "microchip,tcc-g1"; + reg = <0x41018000 0x2000>; + interrupts = <92 0>, <93 0>, <94 0>, <95 0>, <96 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBB_TCC1>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC1>; + clock-names = "mclk", "gclk"; + max-bit-width = <24>; + channels = <4>; + }; + + tcc2: tcc@42000c00 { + compatible = "microchip,tcc-g1"; + reg = <0x42000c00 0x2000>; + interrupts = <97 0>, <98 0>, <99 0>, <100 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC2>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC2>; + clock-names = "mclk", "gclk"; + max-bit-width = <16>; + channels = <3>; + }; + sercom4: sercom@43000000 { compatible = "microchip,sercom-g1"; status = "disabled"; diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_j.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_j.dtsi new file mode 100644 index 0000000000000..68e36423459e1 --- /dev/null +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_j.dtsi @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + tcc3: tcc@42001000 { + compatible = "microchip,tcc-g1"; + reg = <0x42001000 0x2000>; + interrupts = <101 0>, <102 0>, <103 0>; + clocks = <&mclkperiphperiph CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC3>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC3>; + clock-names = "mclk", "gclk"; + max-bit-width = <16>; + channels = <2>; + }; + + tcc4: tcc@43001000 { + compatible = "microchip,tcc-g1"; + reg = <0x43001000 0x2000>; + interrupts = <104 0>, <105 0>, <106 0>; + clocks = <&mclkperiphperiph CLOCK_MCHP_MCLKPERIPH_ID_APBD_TCC4>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC4>; + clock-names = "mclk", "gclk"; + max-bit-width = <16>; + channels = <2>; + }; + }; +}; diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_n.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_n.dtsi index 208a4cec49da4..dd74a5e521e08 100644 --- a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_n.dtsi +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_n.dtsi @@ -6,6 +6,17 @@ / { soc { + tcc3: tcc@42001000 { + compatible = "microchip,tcc-g1"; + reg = <0x42001000 0x2000>; + interrupts = <101 0>, <102 0>, <103 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC3>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC3>; + clock-names = "mclk", "gclk"; + max-bit-width = <16>; + channels = <2>; + }; + sercom6: sercom@43000800 { compatible = "microchip,sercom-g1"; status = "disabled"; @@ -25,5 +36,16 @@ <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM7_CORE>; clock-names = "mclk", "gclk"; }; + + tcc4: tcc@43001000 { + compatible = "microchip,tcc-g1"; + reg = <0x43001000 0x2000>; + interrupts = <104 0>, <105 0>, <106 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBD_TCC4>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC4>; + clock-names = "mclk", "gclk"; + max-bit-width = <16>; + channels = <2>; + }; }; }; diff --git a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_p.dtsi b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_p.dtsi index 208a4cec49da4..dd74a5e521e08 100644 --- a/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_p.dtsi +++ b/dts/arm/microchip/sam/sam_d5x_e5x/common/samd5xe5x_p.dtsi @@ -6,6 +6,17 @@ / { soc { + tcc3: tcc@42001000 { + compatible = "microchip,tcc-g1"; + reg = <0x42001000 0x2000>; + interrupts = <101 0>, <102 0>, <103 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBC_TCC3>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC3>; + clock-names = "mclk", "gclk"; + max-bit-width = <16>; + channels = <2>; + }; + sercom6: sercom@43000800 { compatible = "microchip,sercom-g1"; status = "disabled"; @@ -25,5 +36,16 @@ <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_SERCOM7_CORE>; clock-names = "mclk", "gclk"; }; + + tcc4: tcc@43001000 { + compatible = "microchip,tcc-g1"; + reg = <0x43001000 0x2000>; + interrupts = <104 0>, <105 0>, <106 0>; + clocks = <&mclkperiph CLOCK_MCHP_MCLKPERIPH_ID_APBD_TCC4>, + <&gclkperiph CLOCK_MCHP_GCLKPERIPH_ID_TCC4>; + clock-names = "mclk", "gclk"; + max-bit-width = <16>; + channels = <2>; + }; }; }; From 29f61b011e4a91d003977aaafd397fc54ca43d08 Mon Sep 17 00:00:00 2001 From: Muhammed Asif Date: Tue, 23 Sep 2025 13:07:50 +0530 Subject: [PATCH 053/397] drivers: pwm: microchip: add support for pwm tcc g1 IPs Add pwm driver using tcc g1 peripheral. Adds the support for generating pwm output. Supports both 16-bit and 24bit mode of tcc peripheral Signed-off-by: Muhammed Asif --- drivers/pwm/CMakeLists.txt | 1 + drivers/pwm/Kconfig | 2 + drivers/pwm/Kconfig.mchp | 14 + drivers/pwm/pwm_mchp_tcc_g1.c | 479 ++++++++++++++++++++++++++++++++++ 4 files changed, 496 insertions(+) create mode 100644 drivers/pwm/Kconfig.mchp create mode 100644 drivers/pwm/pwm_mchp_tcc_g1.c diff --git a/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index c976a24b44c44..3497f51688ec4 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -46,6 +46,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_BBLED_XEC pwm_mchp_xec_bbled.c) zephyr_library_sources_ifdef(CONFIG_PWM_INTEL_BLINKY pwm_intel_blinky.c) zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU4 pwm_xmc4xxx_ccu4.c) zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU8 pwm_xmc4xxx_ccu8.c) +zephyr_library_sources_ifdef(CONFIG_PWM_MCHP_G1_TCC pwm_mchp_tcc_g1.c) zephyr_library_sources_ifdef(CONFIG_PWM_MCUX_CTIMER pwm_mcux_ctimer.c) zephyr_library_sources_ifdef(CONFIG_PWM_MSPM0 pwm_mspm0.c) zephyr_library_sources_ifdef(CONFIG_PWM_NUMAKER pwm_numaker.c) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index f0db0f8b10c16..3b9911b2de94e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -110,6 +110,8 @@ source "drivers/pwm/Kconfig.xmc4xxx_ccu4" source "drivers/pwm/Kconfig.xmc4xxx_ccu8" +source "drivers/pwm/Kconfig.mchp" + source "drivers/pwm/Kconfig.mcux_ctimer" source "drivers/pwm/Kconfig.mspm0" diff --git a/drivers/pwm/Kconfig.mchp b/drivers/pwm/Kconfig.mchp new file mode 100644 index 0000000000000..d468b0ee49b5e --- /dev/null +++ b/drivers/pwm/Kconfig.mchp @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +menu "Microchip PWM Drivers" + +config PWM_MCHP_G1_TCC + bool "Microchip TCC G1 PWM driver" + default y + depends on DT_HAS_MICROCHIP_TCC_G1_PWM_ENABLED + select PINCTRL + help + Enable the Microchip Pulse Width Modulation(PWM) driver. + +endmenu diff --git a/drivers/pwm/pwm_mchp_tcc_g1.c b/drivers/pwm/pwm_mchp_tcc_g1.c new file mode 100644 index 0000000000000..ee6d9d05b1f2c --- /dev/null +++ b/drivers/pwm/pwm_mchp_tcc_g1.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file pwm_mchp_tcc_g1.c + * @brief PWM driver for Microchip tcc g1 peripheral. + * + * This file provides the implementation of pwm functions + * for Microchip tcc g1 Peripheral. + */ + +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * @brief Devicetree definitions + *****************************************************************************/ +#define DT_DRV_COMPAT microchip_tcc_g1_pwm + +/******************************************* + * Const and Macro Defines + *******************************************/ + +LOG_MODULE_REGISTER(pwm_mchp_tcc_g1, CONFIG_PWM_LOG_LEVEL); + +#define PWM_REG(addr) ((tcc_registers_t *)addr) + +#define MCHP_PWM_SUCCESS 0 + +/** + * @brief Timeout duration for acquiring the PWM lock. + * + * This macro defines the timeout duration for acquiring the PWM lock. + * The timeout is specified in milliseconds. + */ +#define MCHP_PWM_LOCK_TIMEOUT K_MSEC(10) + +/** + * @brief Initialize the PWM lock. + * + * This macro initializes the PWM lock. + * + * @param p_lock Pointer to the lock to be initialized. + */ +#define MCHP_PWM_DATA_LOCK_INIT(p_lock) k_mutex_init(p_lock) + +/** + * @brief Acquire the PWM lock. + * + * This macro acquires the PWM lock. If the lock is not available, the + * function will wait for the specified timeout duration. + * + * @param p_lock Pointer to the lock to be acquired. + * @return 0 if the lock was successfully acquired, or a negative error code. + */ +#define MCHP_PWM_DATA_LOCK(p_lock) k_mutex_lock(p_lock, MCHP_PWM_LOCK_TIMEOUT) + +/** + * @brief Release the PWM lock. + * + * This macro releases the PWM lock. + * + * @param p_lock Pointer to the lock to be released. + * @return 0 if the lock was successfully released, or a negative error code. + */ +#define MCHP_PWM_DATA_UNLOCK(p_lock) k_mutex_unlock(p_lock) + +/* Timeout values for WAIT_FOR macro */ +#define TIMEOUT_VALUE_US 1000 +#define DELAY_US 2 + +/*********************************** + * Typedefs and Enum Declarations + **********************************/ +typedef enum { + PWM_PRESCALE_1 = 1, + PWM_PRESCALE_2 = 2, + PWM_PRESCALE_4 = 4, + PWM_PRESCALE_8 = 8, + PWM_PRESCALE_16 = 16, + PWM_PRESCALE_32 = 32, + PWM_PRESCALE_64 = 64, + PWM_PRESCALE_128 = 128, + PWM_PRESCALE_256 = 256, + PWM_PRESCALE_512 = 512, + PWM_PRESCALE_1024 = 1024 +} pwm_prescale_modes_t; + +/** + * @brief Structure for managing flags for the pwm. + */ +typedef enum { + PWM_MCHP_FLAGS_CAPTURE_TYPE_PERIOD, + PWM_MCHP_FLAGS_CAPTURE_TYPE_PULSE, + PWM_MCHP_FLAGS_CAPTURE_TYPE_BOTH, + PWM_MCHP_FLAGS_CAPTURE_MODE_SINGLE, + PWM_MCHP_FLAGS_CAPTURE_MODE_CONTINUOUS, +} pwm_mchp_flags_t; + +/** + * @brief Structure to hold PWM data specific to Microchip hardware. + */ +typedef struct { + struct k_mutex lock; /* Lock type for PWM configuration */ +} pwm_mchp_data_t; + +typedef struct mchp_counter_clock { + /* Clock driver */ + const struct device *clock_dev; + + /* Main clock subsystem. */ + clock_control_subsys_t host_core_sync_clk; + /* Generic clock subsystem. */ + clock_control_subsys_t periph_async_clk; +} pwm_mchp_clock_t; + +/** + * @brief Structure to hold the configuration for Microchip PWM. + */ +typedef struct { + pwm_mchp_clock_t pwm_clock; /* PWM clock configuration */ + const struct pinctrl_dev_config *pinctrl_config; /* Pin control configuration */ + void *regs; /* Pointer to PWM peripheral registers */ + uint32_t max_bit_width; /* Used for finding out the resolution of the pwm peripheral */ + uint16_t prescaler; /* Prescaler value for PWM */ + uint8_t channels; /* Number of PWM channels */ + uint32_t freq; /* Frequency of the PWM signal */ +} pwm_mchp_config_t; + +/*********************************** + * Internal functions + ***********************************/ + +/** + *Get the prescale value based on the given prescaler. + */ +static uint32_t tcc_get_prescale_val(uint32_t prescaler) +{ + uint32_t prescaler_val = 0; + + switch (prescaler) { + case PWM_PRESCALE_1: + prescaler_val = TCC_CTRLA_PRESCALER_DIV1; + break; + case PWM_PRESCALE_2: + prescaler_val = TCC_CTRLA_PRESCALER_DIV2; + break; + case PWM_PRESCALE_4: + prescaler_val = TCC_CTRLA_PRESCALER_DIV4; + break; + case PWM_PRESCALE_8: + prescaler_val = TCC_CTRLA_PRESCALER_DIV8; + break; + case PWM_PRESCALE_16: + prescaler_val = TCC_CTRLA_PRESCALER_DIV16; + break; + case PWM_PRESCALE_64: + prescaler_val = TCC_CTRLA_PRESCALER_DIV64; + break; + case PWM_PRESCALE_256: + prescaler_val = TCC_CTRLA_PRESCALER_DIV256; + break; + case PWM_PRESCALE_1024: + prescaler_val = TCC_CTRLA_PRESCALER_DIV1024; + break; + default: + prescaler_val = TCC_CTRLA_PRESCALER_DIV1; /* Default fallback */ + LOG_ERR("Unsupported prescaler specified in dts. Initialising with default " + "prescaler of DIV1"); + + break; + } + + return prescaler_val; +} + +/** + *Enable or disable the PWM instance. + */ +static inline void tcc_enable(void *pwm_reg, bool enable) +{ + + if (enable != 0) { + PWM_REG(pwm_reg)->TCC_CTRLA |= TCC_CTRLA_ENABLE(1); + } else { + PWM_REG(pwm_reg)->TCC_CTRLA &= ~TCC_CTRLA_ENABLE(1); + } + LOG_DBG("%s %d invoked", __func__, enable); +} + +/** + *Wait for the PWM instance to complete synchronization. + */ +static inline void tcc_sync_wait(void *pwm_reg) +{ + + if (!WAIT_FOR(((PWM_REG(pwm_reg)->TCC_SYNCBUSY) != 0), TIMEOUT_VALUE_US, + k_busy_wait(DELAY_US))) { + LOG_ERR("TCC_SYNCBUSY wait timed out"); + } + LOG_DBG("%s invoked", __func__); +} + +/** + *Set the output inversion for a specific PWM channel. + */ +static int32_t tcc_set_invert(void *pwm_reg, uint32_t channel) +{ + uint32_t invert_mask = 1 << (channel + TCC_DRVCTRL_INVEN0_Pos); + + tcc_enable(pwm_reg, false); + tcc_sync_wait(pwm_reg); + PWM_REG(pwm_reg)->TCC_DRVCTRL |= invert_mask; + tcc_enable(pwm_reg, true); + tcc_sync_wait(pwm_reg); + LOG_DBG("tcc set invert 0x%x invoked", invert_mask); + + return MCHP_PWM_SUCCESS; +} + +/** + *Initialize the PWM instance with the specified prescaler. + */ +void tcc_init(void *pwm_reg, uint32_t prescaler) +{ + prescaler = tcc_get_prescale_val(prescaler); + PWM_REG(pwm_reg)->TCC_CTRLA = TCC_CTRLA_SWRST(1); + tcc_sync_wait(pwm_reg); + PWM_REG(pwm_reg)->TCC_CTRLA |= prescaler; + PWM_REG(pwm_reg)->TCC_WAVE = TCC_WAVE_WAVEGEN_NPWM; + PWM_REG(pwm_reg)->TCC_PER = TCC_PER_PER(0); + tcc_enable(pwm_reg, true); +} + +/** + *Get the output inversion status for a specific PWM channel. + */ +static inline bool tcc_get_invert_status(void *pwm_reg, uint32_t channel) +{ + uint32_t invert_status = 0; + uint32_t invert_mask = 1 << (channel + TCC_DRVCTRL_INVEN0_Pos); + + LOG_DBG("tcc get invert status 0x%x invoked", invert_mask); + invert_status = PWM_REG(pwm_reg)->TCC_DRVCTRL & invert_mask; + + return (invert_status == 0) ? true : false; +} + +/*********************************** + * Zephyr APIs + **********************************/ +/** + * @brief Set the PWM cycles for a specific channel. + * + * This function sets the PWM period and pulse width for a specified channel. It also handles the + * polarity inversion if required. + * + * @param pwm_dev Pointer to the PWM device structure. + * @param channel PWM channel number. + * @param period PWM period in cycles. + * @param pulse PWM pulse width in cycles. + * @param flags PWM flags (e.g., polarity inversion). + * + * @return 0 on success, -EINVAL if the channel is invalid or the period/pulse is out of range. + */ +static int pwm_mchp_set_cycles(const struct device *pwm_dev, uint32_t channel, uint32_t period, + uint32_t pulse, pwm_flags_t flags) +{ + const pwm_mchp_config_t *const mchp_pwm_cfg = pwm_dev->config; + pwm_mchp_data_t *mchp_pwm_data = pwm_dev->data; + int ret_val = -EINVAL; + uint32_t top = (BIT(mchp_pwm_cfg->max_bit_width) - 1); + + MCHP_PWM_DATA_LOCK(&mchp_pwm_data->lock); + + if (channel >= mchp_pwm_cfg->channels) { + LOG_ERR("channel %d is invalid", channel); + } else if ((period > top) || (pulse > top)) { + LOG_ERR("period or pulse is out of range"); + } else { + + bool invert_flag_set = ((flags & PWM_POLARITY_INVERTED) != 0); + bool not_inverted = tcc_get_invert_status(mchp_pwm_cfg->regs, channel); + + if ((invert_flag_set == true) && (not_inverted == true)) { + tcc_set_invert(mchp_pwm_cfg->regs, channel); + } + + PWM_REG(mchp_pwm_cfg->regs)->TCC_CCBUF[channel] = TCC_CCBUF_CCBUF(pulse); + PWM_REG(mchp_pwm_cfg->regs)->TCC_PER = TCC_PER_PER(period); + ret_val = MCHP_PWM_SUCCESS; + } + + MCHP_PWM_DATA_UNLOCK(&mchp_pwm_data->lock); + + return ret_val; +} + +/** + * @brief Get the number of PWM cycles per second for a specific channel. + * + * This function retrieves the frequency of the PWM signal in cycles per second for a specified + * channel. + * + * @param pwm_dev Pointer to the PWM device structure. + * @param channel PWM channel number. + * @param cycles Pointer to store the number of cycles per second. + * + * @return 0 on success, -EINVAL if the channel is invalid. + */ +static int pwm_mchp_get_cycles_per_sec(const struct device *pwm_dev, uint32_t channel, + uint64_t *cycles) +{ + const pwm_mchp_config_t *const mchp_pwm_cfg = pwm_dev->config; + pwm_mchp_data_t *mchp_pwm_data = pwm_dev->data; + uint32_t periph_clk_freq = 0; + int ret_val = -EINVAL; + + MCHP_PWM_DATA_LOCK(&mchp_pwm_data->lock); + + if (channel < (mchp_pwm_cfg->channels)) { + /* clang-format off */ + clock_control_get_rate( + mchp_pwm_cfg->pwm_clock.clock_dev, + mchp_pwm_cfg->pwm_clock.periph_async_clk, + &periph_clk_freq); + /* clang-format on */ + *cycles = periph_clk_freq / mchp_pwm_cfg->prescaler; + ret_val = MCHP_PWM_SUCCESS; + } else { + LOG_ERR("channel %d is invalid", channel); + } + + MCHP_PWM_DATA_UNLOCK(&mchp_pwm_data->lock); + + return ret_val; +} + +/****************************************************************************** + * @brief Zephyr driver instance creation + *****************************************************************************/ + +/** + * @brief PWM driver API structure for the Microchip PWM device. + * + * This structure defines the API functions for the Microchip PWM driver, including setting PWM + * cycles, getting the number of cycles per second, and optionally configuring, enabling, and + * disabling PWM capture. + */ +static DEVICE_API(pwm, pwm_mchp_api) = { + .set_cycles = pwm_mchp_set_cycles, + .get_cycles_per_sec = pwm_mchp_get_cycles_per_sec, +}; + +/** + * @brief Initialize the Microchip PWM device. + * + * This function initializes the Microchip PWM device by applying the pin control configuration and + * initializing the PWM hardware with the specified prescaler. + * + * @param pwm_dev Pointer to the PWM device structure. + * + * @return 0 on success, negative error code on failure. + */ +static int pwm_mchp_init(const struct device *pwm_dev) +{ + int ret_val; + const pwm_mchp_config_t *const mchp_pwm_cfg = pwm_dev->config; + pwm_mchp_data_t *mchp_pwm_data = pwm_dev->data; + + MCHP_PWM_DATA_LOCK_INIT(&mchp_pwm_data->lock); + do { + + ret_val = clock_control_on(mchp_pwm_cfg->pwm_clock.clock_dev, + mchp_pwm_cfg->pwm_clock.periph_async_clk); + if ((ret_val < 0) && (ret_val != -EALREADY)) { + LOG_ERR("Failed to enable the periph_async_clk for PWM: %d", ret_val); + break; + } + ret_val = clock_control_on(mchp_pwm_cfg->pwm_clock.clock_dev, + mchp_pwm_cfg->pwm_clock.host_core_sync_clk); + if ((ret_val < 0) && (ret_val != -EALREADY)) { + LOG_ERR("Failed to enable the host_core_sync_clk for PWM: %d", ret_val); + break; + } + ret_val = pinctrl_apply_state(mchp_pwm_cfg->pinctrl_config, PINCTRL_STATE_DEFAULT); + if (ret_val < 0) { + LOG_ERR("Pincontrol apply state failed %d", ret_val); + break; + } + tcc_init(mchp_pwm_cfg->regs, mchp_pwm_cfg->prescaler); + } while (0); + ret_val = (ret_val == -EALREADY) ? 0 : ret_val; + + return ret_val; +} + +/** + * @brief Macro to define the PWM data structure for a specific instance. + * + * This macro defines the PWM data structure for a specific instance of the Microchip PWM device. + * + * @param n Instance number. + * @param ip IP identifier. + */ +#define PWM_MCHP_DATA_DEFN(n) static pwm_mchp_data_t pwm_mchp_data_##n + +/** + * @brief Macro to assign clock configurations for the Microchip PWM device. + * + * This macro assigns the clock configurations for the PWM device, including the + * host core synchronous clock, and + * peripheral asynchronous clock (conditionally). + * + * @param n Device tree node number. + * + * @note This macro conditionally includes peripheral asynchronous clock configurations based on + * the presence of relevant device tree properties. + */ +/* clang-format off */ +#define PWM_MCHP_CLOCK_ASSIGN(n) \ + .pwm_clock.clock_dev = DEVICE_DT_GET(DT_NODELABEL(clock)), \ + .pwm_clock.host_core_sync_clk = (void *)(DT_INST_CLOCKS_CELL_BY_NAME(n, mclk, subsystem)),\ + COND_CODE_1(DT_NODE_EXISTS(DT_INST_CLOCKS_CTLR_BY_NAME(n, rtcclk)), \ + (.pwm_clock.periph_async_clk = \ + (void *)(DT_INST_CLOCKS_CELL_BY_NAME(n, rtcclk, subsystem)),), \ + ()) COND_CODE_1(DT_NODE_EXISTS(DT_INST_CLOCKS_CTLR_BY_NAME(n, gclk)), \ + (.pwm_clock.periph_async_clk = (void *)(DT_INST_CLOCKS_CELL_BY_NAME(n, gclk, subsystem)),),\ + ()) +/* clang-format on */ + +/** + * @brief Macro to define the PWM configuration structure for a specific instance. + * + * This macro defines the PWM configuration structure for a specific instance of the Microchip PWM + * device. + * + * @param n Instance number. + */ +#define PWM_MCHP_CONFIG_DEFN(n) \ + static const pwm_mchp_config_t pwm_mchp_config_##n = { \ + .prescaler = DT_INST_PROP(n, prescaler), \ + .pinctrl_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .channels = DT_INST_PROP(n, channels), \ + .regs = (void *)DT_INST_REG_ADDR(n), \ + .max_bit_width = DT_INST_PROP(n, max_bit_width), \ + PWM_MCHP_CLOCK_ASSIGN(n)} + +/** + * @brief Macro to define the device structure for a specific instance of the PWM device. + * + * This macro defines the device structure for a specific instance of the Microchip PWM device. + * It uses the DEVICE_DT_INST_DEFINE macro to create the device instance with the specified + * initialization function, data structure, configuration structure, and driver API. + * + * @param n Instance number. + */ +#define PWM_MCHP_DEVICE_DT_DEFN(n) \ + DEVICE_DT_INST_DEFINE(n, pwm_mchp_init, NULL, &pwm_mchp_data_##n, &pwm_mchp_config_##n, \ + POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, &pwm_mchp_api) + +/** + *Initialize the PWM device with pin control, data, and configuration definitions. + */ +#define PWM_MCHP_DEVICE_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + PWM_MCHP_DATA_DEFN(n); \ + PWM_MCHP_CONFIG_DEFN(n); \ + PWM_MCHP_DEVICE_DT_DEFN(n); + +/* Run init macro for each pwm-generic node */ +DT_INST_FOREACH_STATUS_OKAY(PWM_MCHP_DEVICE_INIT) From 267755ae246d16774b16a4c5f345d05dc3d1cb7b Mon Sep 17 00:00:00 2001 From: Muhammed Asif Date: Tue, 23 Sep 2025 17:21:44 +0530 Subject: [PATCH 054/397] boards: microchip: sam_e54_xpro: Enabled blinky pwm support Added the pinmuxing as well as the dts node for supporting blinky on sam_e54_xpro board. Signed-off-by: Muhammed Asif --- .../sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi | 6 +++++ .../sam/sam_e54_xpro/sam_e54_xpro.dts | 24 +++++++++++++++++++ .../sam/sam_e54_xpro/sam_e54_xpro.yaml | 1 + 3 files changed, 31 insertions(+) diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi index 05798b46d3ecd..dcd24d59b034d 100644 --- a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro-pinctrl.dtsi @@ -13,4 +13,10 @@ ; }; }; + + tcc0_pwm_default: tcc0_pwm_default { + group1 { + pinmux = ; + }; + }; }; diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.dts b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.dts index 025d49b64e98a..5f8ac877f8e8d 100644 --- a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.dts +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.dts @@ -19,6 +19,19 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; }; + + aliases { + pwm-led0 = &pwm_led0; + }; + + pwmleds { + compatible = "pwm-leds"; + + pwm_led0: pwm_led_0 { + status = "okay"; + pwms = <&tcc0 2 PWM_MSEC(20) 0>; + }; + }; }; &flash0 { @@ -60,3 +73,14 @@ pinctrl-0 = <&sercom2_uart_default>; pinctrl-names = "default"; }; + +&tcc0 { + compatible = "microchip,tcc-g1-pwm"; + status = "okay"; + #pwm-cells = <3>; + pinctrl-0 = <&tcc0_pwm_default>; + pinctrl-names = "default"; + max-bit-width = <24>; + prescaler = <8>; + channels = <6>; +}; diff --git a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml index 7c608e61f1647..06b83ffc0fc55 100644 --- a/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml +++ b/boards/microchip/sam/sam_e54_xpro/sam_e54_xpro.yaml @@ -11,6 +11,7 @@ flash: 1024 ram: 256 supported: - pinctrl + - pwm - reset - shell - uart From bcfec0a6b51b39ca59675bf9bc15a7d9e63d27d3 Mon Sep 17 00:00:00 2001 From: Adam BERLINGER Date: Tue, 30 Sep 2025 15:52:58 +0200 Subject: [PATCH 055/397] drivers: video: stm32_dcmipp: Initialize ISP only once This fixes bug where stm32_dcmipp_isp_init is called multiple times. Signed-off-by: Adam BERLINGER --- drivers/video/Kconfig.stm32_dcmipp | 8 ++++ drivers/video/video_stm32_dcmipp.c | 74 ++++++++++++------------------ 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/drivers/video/Kconfig.stm32_dcmipp b/drivers/video/Kconfig.stm32_dcmipp index e986312a6d7ad..728db10a284a0 100644 --- a/drivers/video/Kconfig.stm32_dcmipp +++ b/drivers/video/Kconfig.stm32_dcmipp @@ -17,6 +17,14 @@ config VIDEO_STM32_DCMIPP if VIDEO_STM32_DCMIPP +config VIDEO_STM32_DCMIPP_INIT_PRIORITY + int "STM32 DCMIPP initialization priority" + default 61 + help + System initialization priority for DCMIPP drivers. + This priority needs to be lower than VIDEO_INIT_PRIORITY + to ensure that the source device (sensor) initializes first. + config VIDEO_STM32_DCMIPP_SENSOR_WIDTH int "Width of the sensor frame" default 2592 diff --git a/drivers/video/video_stm32_dcmipp.c b/drivers/video/video_stm32_dcmipp.c index 05955f4967d2e..24db419289586 100644 --- a/drivers/video/video_stm32_dcmipp.c +++ b/drivers/video/video_stm32_dcmipp.c @@ -646,43 +646,6 @@ static void stm32_dcmipp_get_isp_decimation(struct stm32_dcmipp_data *dcmipp) static int stm32_dcmipp_get_fmt(const struct device *dev, struct video_format *fmt) { struct stm32_dcmipp_pipe_data *pipe = dev->data; -#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES) - struct stm32_dcmipp_data *dcmipp = pipe->dcmipp; - const struct stm32_dcmipp_config *config = dev->config; - static atomic_t isp_init_once; - int ret; - - /* Initialize the external ISP handling stack */ - /* - * TODO - this is not the right place to do that, however we need to know - * the source format before calling the isp_init handler hence can't - * do that within the stm32_dcmipp_init function due to unknown - * driver initialization order - * - * Would need an ops that get called when both side of an endpoint get - * initiialized - */ - if (atomic_cas(&isp_init_once, 0, 1) && - (pipe->id == DCMIPP_PIPE1 || pipe->id == DCMIPP_PIPE2)) { - /* - * It is necessary to perform a dummy configuration here otherwise any - * ISP related configuration done by the stm32_dcmipp_isp_init will - * fail due to the HAL DCMIPP driver not being in READY state - */ - ret = stm32_dcmipp_conf_parallel(dcmipp->dev, &stm32_dcmipp_input_fmt_desc[0]); - if (ret < 0) { - LOG_ERR("Failed to perform dummy parallel configuration"); - return ret; - } - - ret = stm32_dcmipp_isp_init(&dcmipp->hdcmipp, config->source_dev); - if (ret < 0) { - LOG_ERR("Failed to initialize the ISP"); - return ret; - } - stm32_dcmipp_get_isp_decimation(dcmipp); - } -#endif *fmt = pipe->fmt; @@ -1184,12 +1147,6 @@ static int stm32_dcmipp_stream_enable(const struct device *dev) goto out; } } - - /* Initialize the external ISP handling stack */ - ret = stm32_dcmipp_isp_init(&dcmipp->hdcmipp, config->source_dev); - if (ret < 0) { - goto out; - } #endif /* Enable the DCMIPP Pipeline */ @@ -1695,6 +1652,33 @@ static int stm32_dcmipp_init(const struct device *dev) return -EIO; } +#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES) + /* Check if source device is ready */ + if (!device_is_ready(cfg->source_dev)) { + LOG_ERR("Source device not ready"); + return -ENODEV; + } + + /* + * It is necessary to perform a dummy configuration here otherwise any + * ISP related configuration done by the stm32_dcmipp_isp_init will + * fail due to the HAL DCMIPP driver not being in READY state + */ + err = stm32_dcmipp_conf_parallel(dcmipp->dev, &stm32_dcmipp_input_fmt_desc[0]); + if (err < 0) { + LOG_ERR("Failed to perform dummy parallel configuration"); + return err; + } + + err = stm32_dcmipp_isp_init(&dcmipp->hdcmipp, cfg->source_dev); + if (err < 0) { + LOG_ERR("Failed to initialize the ISP"); + return err; + } + + stm32_dcmipp_get_isp_decimation(dcmipp); +#endif + LOG_DBG("%s initialized", dev->name); return 0; @@ -1744,7 +1728,7 @@ static void stm32_dcmipp_isr(const struct device *dev) DEVICE_DT_DEFINE(node_id, &stm32_dcmipp_pipe_init, NULL, \ &stm32_dcmipp_pipe_##node_id, \ &stm32_dcmipp_config_##inst, \ - POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \ + POST_KERNEL, CONFIG_VIDEO_STM32_DCMIPP_INIT_PRIORITY, \ &stm32_dcmipp_driver_api); \ \ VIDEO_DEVICE_DEFINE(dcmipp_##inst_pipe_##node_id, DEVICE_DT_GET(node_id), SOURCE_DEV(inst)); @@ -1829,7 +1813,7 @@ static void stm32_dcmipp_isr(const struct device *dev) DEVICE_DT_INST_DEFINE(inst, &stm32_dcmipp_init, \ NULL, &stm32_dcmipp_data_##inst, \ &stm32_dcmipp_config_##inst, \ - POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \ + POST_KERNEL, CONFIG_VIDEO_STM32_DCMIPP_INIT_PRIORITY, \ NULL); \ \ STM32_DCMIPP_PIPES(inst) From 3523f2f9f483789cfa38e9d1bae4ceb20495930c Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Thu, 9 Oct 2025 13:43:28 +0700 Subject: [PATCH 056/397] drivers: spi: Add SPI support for Renesas RZ/V2L, A3UL Add SPI driver support for Renesas RZ/V2L, A3UL Signed-off-by: Hieu Nguyen Signed-off-by: Nhut Nguyen --- drivers/spi/spi_renesas_rz_rspi.c | 51 +++++++++++++++++++------------ 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi_renesas_rz_rspi.c b/drivers/spi/spi_renesas_rz_rspi.c index f5290ce95692b..c8f1709610f83 100644 --- a/drivers/spi/spi_renesas_rz_rspi.c +++ b/drivers/spi/spi_renesas_rz_rspi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -46,9 +46,9 @@ struct spi_rz_rspi_data { }; #ifdef CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT -void rspi_rxi_isr(void); -void rspi_txi_isr(void); -void rspi_eri_isr(void); +void rspi_rxi_isr(void *irq); +void rspi_txi_isr(void *irq); +void rspi_eri_isr(void *irq); #elif defined(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC) void dmac_b_int_isr(void); void rspi_tx_dmac_callback(rspi_instance_ctrl_t *p_ctrl); @@ -63,10 +63,10 @@ static bool spi_rz_rspi_transfer_ongoing(struct spi_rz_rspi_data *data) #if defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) return (spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx)); #else - if (spi_context_total_tx_len(&data->ctx) < spi_context_total_rx_len(&data->ctx)) { - return (spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx)); - } else { + if (spi_context_total_tx_len(&data->ctx) == spi_context_total_rx_len(&data->ctx)) { return (spi_context_tx_on(&data->ctx) && spi_context_rx_on(&data->ctx)); + } else { + return (spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx)); } #endif } @@ -100,20 +100,23 @@ static void spi_rz_rspi_retransmit(const struct device *dev) #ifdef CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT static void spi_rz_rspi_rxi_isr(const struct device *dev) { - ARG_UNUSED(dev); - rspi_rxi_isr(); + struct spi_rz_rspi_data *data = dev->data; + + rspi_rxi_isr((void *)data->fsp_config->rxi_irq); } static void spi_rz_rspi_txi_isr(const struct device *dev) { - ARG_UNUSED(dev); - rspi_txi_isr(); + struct spi_rz_rspi_data *data = dev->data; + + rspi_txi_isr((void *)data->fsp_config->txi_irq); } static void spi_rz_rspi_eri_isr(const struct device *dev) { - ARG_UNUSED(dev); - rspi_eri_isr(); + struct spi_rz_rspi_data *data = dev->data; + + rspi_eri_isr((void *)data->fsp_config->eri_irq); } #endif /* CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT */ @@ -263,6 +266,7 @@ static int spi_rz_rspi_transceive_data(struct spi_rz_rspi_data *data) { R_RSPI0_Type *p_spi_reg = (R_RSPI0_Type *)data->fsp_ctrl->p_regs; uint32_t data_count = (p_spi_reg->SPBFDR & R_RSPI0_SPBFDR_T_Msk) >> R_RSPI0_SPBFDR_T_Pos; + uint32_t rx; data_count = 8 - data_count; @@ -295,21 +299,28 @@ static int spi_rz_rspi_transceive_data(struct spi_rz_rspi_data *data) spi_context_update_tx(&data->ctx, data->dfs, 1); /* RX transfer */ - if (spi_context_rx_on(&data->ctx)) { + while (!p_spi_reg->SPSR_b.SPRF) { + } - while (!p_spi_reg->SPSR_b.SPRF) { - } + if (data->dfs > 2) { + rx = (uint32_t)p_spi_reg->SPDR_b.SPD; + } else if (data->dfs > 1) { + rx = (uint16_t)p_spi_reg->SPDR_hword.L; + } else { + rx = (uint8_t)p_spi_reg->SPDR_byte.LL; + } + if (spi_context_rx_buf_on(&data->ctx)) { /* Read data from Data Register */ if (data->dfs > 2) { - UNALIGNED_PUT(p_spi_reg->SPDR_b.SPD, (uint32_t *)data->ctx.rx_buf); + UNALIGNED_PUT(rx, (uint32_t *)data->ctx.rx_buf); } else if (data->dfs > 1) { - UNALIGNED_PUT(p_spi_reg->SPDR_hword.L, (uint16_t *)data->ctx.rx_buf); + UNALIGNED_PUT(rx, (uint16_t *)data->ctx.rx_buf); } else { - UNALIGNED_PUT(p_spi_reg->SPDR_byte.LL, (uint8_t *)data->ctx.rx_buf); + UNALIGNED_PUT(rx, (uint8_t *)data->ctx.rx_buf); } - spi_context_update_rx(&data->ctx, data->dfs, 1); } + spi_context_update_rx(&data->ctx, data->dfs, 1); return 0; } #endif /* #if !defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) */ From 8e48737101fcf872ae0e4111767ffa65d85f0d7b Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Thu, 9 Oct 2025 13:45:14 +0700 Subject: [PATCH 057/397] dts: renesas: Add SPI support for Renesas RZ/V2L, A3UL Add SPI nodes to Renesas RZ/V2L, A3UL Signed-off-by: Hieu Nguyen Signed-off-by: Nhut Nguyen --- dts/arm/renesas/rz/rzv/r9a07g054.dtsi | 54 +++++++++++++++++++++++++ dts/arm64/renesas/rz/rza/r9a07g063.dtsi | 38 +++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/dts/arm/renesas/rz/rzv/r9a07g054.dtsi b/dts/arm/renesas/rz/rzv/r9a07g054.dtsi index b48319f8839c2..d8d3e7e8e96a7 100644 --- a/dts/arm/renesas/rz/rzv/r9a07g054.dtsi +++ b/dts/arm/renesas/rz/rzv/r9a07g054.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { compatible = "renesas,r9a07g054"; @@ -641,6 +642,26 @@ }; }; + dma0: dma@41800000 { /* Secure DMA */ + compatible = "renesas,rz-dma"; + reg = <0x41800000 0x800>, <0x41810000 0x20>; + reg-names = "reg_main", "ext"; + interrupts = <108 1>, <109 1>, <110 1>, <111 1>, + <112 1>, <113 1>, <114 1>, <115 1>, + <116 1>, <117 1>, <118 1>, <119 1>, + <120 1>, <121 1>, <122 1>, <123 1>, + <124 1>; /* DMAERR1 */ + interrupt-names = "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15", + "err1"; + dma-channels = <16>; + #dma-cells = <2>; + dma-buf-addr-alignment = <4>; + status = "disabled"; + }; + scif0: serial@4004b800 { compatible = "renesas,rz-scif-uart"; channel = <0>; @@ -1018,6 +1039,39 @@ status = "disabled"; }; + spi0: spi@4004ac00 { + compatible = "renesas,rz-rspi"; + reg = <0x4004ac00 DT_SIZE_K(1)>; + interrupts = <413 1>, <414 1>, <415 1>; + interrupt-names = "rx", "tx", "error"; + channel = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@4004b000 { + compatible = "renesas,rz-rspi"; + reg = <0x4004b000 DT_SIZE_K(1)>; + interrupts = <416 1>, <417 1>, <418 1>; + interrupt-names = "rx", "tx", "error"; + channel = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@4004b400 { + compatible = "renesas,rz-rspi"; + reg = <0x4004b400 DT_SIZE_K(1)>; + interrupts = <419 1>, <420 1>, <421 1>; + interrupt-names = "rx", "tx", "error"; + channel = <2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + gtm0: gtm@42801000 { compatible = "renesas,rz-gtm"; reg = <0x42801000 0x400>; diff --git a/dts/arm64/renesas/rz/rza/r9a07g063.dtsi b/dts/arm64/renesas/rz/rza/r9a07g063.dtsi index 92c02faa1b00f..50b7f13114fb8 100644 --- a/dts/arm64/renesas/rz/rza/r9a07g063.dtsi +++ b/dts/arm64/renesas/rz/rza/r9a07g063.dtsi @@ -855,6 +855,44 @@ status = "disabled"; }; + spi0: spi@1004ac00 { + compatible = "renesas,rz-rspi"; + reg = <0x1004ac00 DT_SIZE_K(1)>; + interrupts = , + , + ; + interrupt-names = "rx", "tx", "error"; + channel = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@1004b000 { + compatible = "renesas,rz-rspi"; + reg = <0x1004b000 DT_SIZE_K(1)>; + interrupts = , + , + ; + interrupt-names = "rx", "tx", "error"; + channel = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@1004b400 { + compatible = "renesas,rz-rspi"; + reg = <0x1004b400 DT_SIZE_K(1)>; + interrupts = , + , + ; + interrupt-names = "rx", "tx", "error"; + channel = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + gtm0: gtm@12801000 { compatible = "renesas,rz-gtm"; reg = <0x12801000 0x400>; From c9daa9877b9664ca9944c27275b72ff7000964f7 Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Thu, 9 Oct 2025 13:51:29 +0700 Subject: [PATCH 058/397] boards: renesas: Add SPI support for Renesas RZ/V2L, A3UL Add SPI support for board Renesas RZ/V2L-SMARC, RZ/A3UL-SMARC Signed-off-by: Hieu Nguyen Signed-off-by: Nhut Nguyen --- boards/renesas/rza3ul_smarc/rza3ul_smarc-pinctrl.dtsi | 9 +++++++++ boards/renesas/rza3ul_smarc/rza3ul_smarc.dts | 6 ++++++ boards/renesas/rza3ul_smarc/rza3ul_smarc.yaml | 1 + boards/renesas/rzv2l_smarc/rzv2l_smarc-pinctrl.dtsi | 9 +++++++++ .../rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.dts | 6 ++++++ .../rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.yaml | 1 + 6 files changed, 32 insertions(+) diff --git a/boards/renesas/rza3ul_smarc/rza3ul_smarc-pinctrl.dtsi b/boards/renesas/rza3ul_smarc/rza3ul_smarc-pinctrl.dtsi index 073e7ebb17181..61db6fc06b1a5 100644 --- a/boards/renesas/rza3ul_smarc/rza3ul_smarc-pinctrl.dtsi +++ b/boards/renesas/rza3ul_smarc/rza3ul_smarc-pinctrl.dtsi @@ -34,4 +34,13 @@ input-enable; }; }; + + /omit-if-no-ref/ spi0_pins: spi0 { + spi0-pinmux { + pinmux = , /* CK */ + , /* MOSI */ + , /* MISO */ + ; /* SSL */ + }; + }; }; diff --git a/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts b/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts index 1517949346cd3..f6644ebfb0215 100644 --- a/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts +++ b/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts @@ -81,6 +81,12 @@ status = "okay"; }; +&spi0 { + pinctrl-0 = <&spi0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &wdt0 { status = "okay"; }; diff --git a/boards/renesas/rza3ul_smarc/rza3ul_smarc.yaml b/boards/renesas/rza3ul_smarc/rza3ul_smarc.yaml index 13c9e23ca371e..2fe827e979617 100644 --- a/boards/renesas/rza3ul_smarc/rza3ul_smarc.yaml +++ b/boards/renesas/rza3ul_smarc/rza3ul_smarc.yaml @@ -11,6 +11,7 @@ supported: - pwm - adc - i2c + - spi - counter - watchdog testing: diff --git a/boards/renesas/rzv2l_smarc/rzv2l_smarc-pinctrl.dtsi b/boards/renesas/rzv2l_smarc/rzv2l_smarc-pinctrl.dtsi index 0e0b91c4738f1..ed7e4d66695e4 100644 --- a/boards/renesas/rzv2l_smarc/rzv2l_smarc-pinctrl.dtsi +++ b/boards/renesas/rzv2l_smarc/rzv2l_smarc-pinctrl.dtsi @@ -32,4 +32,13 @@ ; /* SCL */ }; }; + + /omit-if-no-ref/ spi1_pins: spi1 { + spi1-pinmux { + pinmux = , /* CK */ + , /* MOSI */ + , /* MISO */ + ; /* SSL */ + }; + }; }; diff --git a/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.dts b/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.dts index 06534843bab28..b71ef82061dc9 100644 --- a/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.dts +++ b/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.dts @@ -43,3 +43,9 @@ pinctrl-names = "default"; status = "okay"; }; + +&spi1 { + pinctrl-0 = <&spi1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.yaml b/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.yaml index b69c99cd18550..cf8105de9cc45 100644 --- a/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.yaml +++ b/boards/renesas/rzv2l_smarc/rzv2l_smarc_r9a07g054l23gbg_cm33.yaml @@ -11,6 +11,7 @@ supported: - pwm - adc - i2c + - spi - counter - mbox vendor: renesas From 7e5dc40a8c7986104938ac94abb3ac06fccbf20c Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Thu, 9 Oct 2025 13:53:25 +0700 Subject: [PATCH 059/397] tests: drivers: spi: Add SPI support for Renesas RZ/V2L, A3UL Add SPI test support for Renesas RZ/V2L-SMARC, RZ/A3UL-SMARC Signed-off-by: Hieu Nguyen Signed-off-by: Nhut Nguyen --- .../spi/spi_loopback/boards/rza3ul_smarc.conf | 6 ++++ .../spi_loopback/boards/rza3ul_smarc.overlay | 19 +++++++++++++ .../rzv2l_smarc_r9a07g054l23gbg_cm33.conf | 7 +++++ .../rzv2l_smarc_r9a07g054l23gbg_cm33.overlay | 28 +++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.conf b/tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.conf new file mode 100644 index 0000000000000..37ec783b76925 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.conf @@ -0,0 +1,6 @@ +CONFIG_SPI_ASYNC=y +CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT=y +CONFIG_SPI_RTIO=n +CONFIG_SPI_LOOPBACK_MODE_LOOP=n +CONFIG_SPI_LARGE_BUFFER_SIZE=2048 +CONFIG_SPI_IDEAL_TRANSFER_DURATION_SCALING=9 diff --git a/tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.overlay b/tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.overlay new file mode 100644 index 0000000000000..042818f4bc5f9 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rza3ul_smarc.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi0 { + slow@2 { + compatible = "test-spi-loopback-slow"; + reg = <2>; + spi-max-frequency = <500000>; + }; + + fast@2 { + compatible = "test-spi-loopback-fast"; + reg = <2>; + spi-max-frequency = <8333333>; + }; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf b/tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf new file mode 100644 index 0000000000000..9396e8b801869 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf @@ -0,0 +1,7 @@ +CONFIG_SPI_ASYNC=y +CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT=y +CONFIG_SPI_RENESAS_RZ_RSPI_DMAC=n +CONFIG_SPI_RTIO=n +CONFIG_SPI_LOOPBACK_MODE_LOOP=n +CONFIG_SPI_LARGE_BUFFER_SIZE=2048 +CONFIG_SPI_IDEAL_TRANSFER_DURATION_SCALING=41 diff --git a/tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay b/tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay new file mode 100644 index 0000000000000..2be457cc96629 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi1 { + dmas = <&dma0 6 RZ_DMA_PERIPH_TO_MEM>, + <&dma0 5 RZ_DMA_MEM_TO_PERIPH>; + dma-names = "rx", "tx"; + + slow@2 { + compatible = "test-spi-loopback-slow"; + reg = <2>; + spi-max-frequency = <500000>; + }; + + fast@2 { + compatible = "test-spi-loopback-fast"; + reg = <2>; + spi-max-frequency = <8333333>; + }; +}; + +&dma0 { + status = "okay"; + dma-buf-addr-alignment = <1>; +}; From 91bf704f84c460b57900c11c1390b06fa2c4c958 Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Thu, 9 Oct 2025 13:55:28 +0700 Subject: [PATCH 060/397] samples: drivers: spi: Add SPI support for Renesas RZ/V2L, A3UL Add SPI sample support for Renesas RZ/V2L-SMARC, RZ/A3UL-SMARC Signed-off-by: Hieu Nguyen Signed-off-by: Nhut Nguyen --- .../drivers/spi_bitbang/boards/rza3ul_smarc.conf | 1 + .../drivers/spi_bitbang/boards/rza3ul_smarc.overlay | 13 +++++++++++++ .../boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf | 3 +++ .../boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay | 13 +++++++++++++ 4 files changed, 30 insertions(+) create mode 100644 samples/drivers/spi_bitbang/boards/rza3ul_smarc.conf create mode 100644 samples/drivers/spi_bitbang/boards/rza3ul_smarc.overlay create mode 100644 samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf create mode 100644 samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay diff --git a/samples/drivers/spi_bitbang/boards/rza3ul_smarc.conf b/samples/drivers/spi_bitbang/boards/rza3ul_smarc.conf new file mode 100644 index 0000000000000..91c3c15b37d1e --- /dev/null +++ b/samples/drivers/spi_bitbang/boards/rza3ul_smarc.conf @@ -0,0 +1 @@ +CONFIG_GPIO=y diff --git a/samples/drivers/spi_bitbang/boards/rza3ul_smarc.overlay b/samples/drivers/spi_bitbang/boards/rza3ul_smarc.overlay new file mode 100644 index 0000000000000..f842150309a0c --- /dev/null +++ b/samples/drivers/spi_bitbang/boards/rza3ul_smarc.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +spibb0: &spi0 { + cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; diff --git a/samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf b/samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf new file mode 100644 index 0000000000000..1dd585f098f05 --- /dev/null +++ b/samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.conf @@ -0,0 +1,3 @@ +CONFIG_GPIO=y +CONFIG_SPI_RENESAS_RZ_RSPI_DMAC=n +CONFIG_NO_OPTIMIZATIONS=y diff --git a/samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay b/samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay new file mode 100644 index 0000000000000..f6c0e135c335a --- /dev/null +++ b/samples/drivers/spi_bitbang/boards/rzv2l_smarc_r9a07g054l23gbg_cm33.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +spibb0: &spi1 { + cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; From ec1ec5e5813564a7e36a6d1aa7bd4b80c77f6bf6 Mon Sep 17 00:00:00 2001 From: Jiafei Pan Date: Wed, 14 Jul 2021 14:52:37 +0800 Subject: [PATCH 061/397] counter: add counter_ticks_to_ns() Add new API to get nanosecond from counter ticks. Signed-off-by: Jiafei Pan --- include/zephyr/drivers/counter.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/zephyr/drivers/counter.h b/include/zephyr/drivers/counter.h index f8d19bc69dafa..ca3a35183f41d 100644 --- a/include/zephyr/drivers/counter.h +++ b/include/zephyr/drivers/counter.h @@ -338,6 +338,22 @@ static inline uint64_t z_impl_counter_ticks_to_us(const struct device *dev, return ((uint64_t)ticks * USEC_PER_SEC) / z_impl_counter_get_frequency(dev); } +/** + * @brief Function to convert ticks to nanoseconds. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] ticks Ticks. + * + * @return Converted nanoseconds. + */ +__syscall uint64_t counter_ticks_to_ns(const struct device *dev, uint32_t ticks); + +static inline uint64_t z_impl_counter_ticks_to_ns(const struct device *dev, + uint32_t ticks) +{ + return ((uint64_t)ticks * NSEC_PER_SEC) / z_impl_counter_get_frequency(dev); +} + /** * @brief Function to retrieve maximum top value that can be set. * From b59921698e4ec4d188071b5ccfa6bc306bb60a80 Mon Sep 17 00:00:00 2001 From: Matheus Marques Date: Mon, 22 Sep 2025 19:41:14 -0300 Subject: [PATCH 062/397] mgmt: hawkbit: Add options to not confirm or erase at init Current implementation forces confirmation of current boot image and second slot erase at hawkbit_init() and it is impossible to communicate with hawkBit server without running it. This makes impossible to notify update failures to server (#71750) Add option HAWKBIT_CONFIRM_IMG_ON_INIT to allow disabling the auto image confirmation and HAWKBIT_ERASE_SECOND_SLOT_ON_CONFIRM to select if the second partition slot shall be erased or not. Disable those to handle of these behaviors on application code. Signed-off-by: Matheus Marques --- doc/releases/release-notes-4.3.rst | 2 ++ subsys/mgmt/hawkbit/Kconfig | 15 +++++++++++++++ subsys/mgmt/hawkbit/hawkbit.c | 14 +++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index 747c1ed15544b..814c0f6bab5f8 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -217,6 +217,8 @@ New APIs and options * hawkBit * :kconfig:option:`CONFIG_HAWKBIT_REBOOT_NONE` + * :kconfig:option:`CONFIG_HAWKBIT_CONFIRM_IMG_ON_INIT` + * :kconfig:option:`CONFIG_HAWKBIT_ERASE_SECOND_SLOT_ON_CONFIRM` * Modem diff --git a/subsys/mgmt/hawkbit/Kconfig b/subsys/mgmt/hawkbit/Kconfig index ce0fd7c160f3e..4111f20ccd261 100644 --- a/subsys/mgmt/hawkbit/Kconfig +++ b/subsys/mgmt/hawkbit/Kconfig @@ -258,6 +258,21 @@ config HAWKBIT_SAVE_PROGRESS_INTERVAL Set the interval (in percent) that the hawkBit update download progress will be saved. 0 means that the progress will be saved every time a new chunk is downloaded. +config HAWKBIT_CONFIRM_IMG_ON_INIT + bool "Confirm boot image at hawkBit init" + default y + help + Automatically confirm current boot image at hawkBit initialization. + Application shall handle image confirmation when set to false. + +config HAWKBIT_ERASE_SECOND_SLOT_ON_CONFIRM + bool "Erase second slot after confirming boot image" + default y + depends on HAWKBIT_CONFIRM_IMG_ON_INIT + help + Erase the second image slot partition contents after confirming current boot image + at hawkBit init. + module = HAWKBIT module-str = Log Level for hawkbit module-help = Enables logging for hawkBit code. diff --git a/subsys/mgmt/hawkbit/hawkbit.c b/subsys/mgmt/hawkbit/hawkbit.c index 69a75d44efff9..1452836dc7a92 100644 --- a/subsys/mgmt/hawkbit/hawkbit.c +++ b/subsys/mgmt/hawkbit/hawkbit.c @@ -910,7 +910,8 @@ int hawkbit_init(void) image_ok = boot_is_img_confirmed(); LOG_INF("Current image is%s confirmed", image_ok ? "" : " not"); - if (!image_ok) { + + if (IS_ENABLED(CONFIG_HAWKBIT_CONFIRM_IMG_ON_INIT) && !image_ok) { ret = boot_write_img_confirmed(); if (ret < 0) { LOG_ERR("Failed to confirm current image: %d", ret); @@ -918,10 +919,13 @@ int hawkbit_init(void) } LOG_DBG("Marked current image as OK"); - ret = boot_erase_img_bank(flash_img_get_upload_slot()); - if (ret < 0) { - LOG_ERR("Failed to erase second slot: %d", ret); - return ret; + + if (IS_ENABLED(CONFIG_HAWKBIT_ERASE_SECOND_SLOT_ON_CONFIRM)) { + ret = boot_erase_img_bank(flash_img_get_upload_slot()); + if (ret < 0) { + LOG_ERR("Failed to erase second slot: %d", ret); + return ret; + } } hawkbit_event_raise(HAWKBIT_EVENT_CONFIRMED_CURRENT_IMAGE); From 82ecdcf7f8c7ee4242243e0c0f4ec0094e788cde Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Tue, 9 Sep 2025 16:13:06 +0200 Subject: [PATCH 063/397] samples: cleanup sysbuild/hello_world sample Remove the prompt for REMOTE_BOARD. REMOTE_BOARD should not be having a prompt or be configurable on command line. Instead REMOTE_BOARD should be defined based on the SoC as this will allow creation of new boards using the same SoC, and thereby be able to build the sample out-of-the-box for any supported SoC. This allows us to remove several single line config files. For SoCs with more than two CPU clusters, such as the nRF54h20, then a choice is provided to select specific core. Remove the REMOTE_BOARD restriction, as this sample will build and run even for single core SoCs, and may be useful for testing other sysbuild multi-image features even for single cores SoCs. Signed-off-by: Torsten Rasmussen --- samples/sysbuild/hello_world/Kconfig.sysbuild | 31 ++++++++++++++++- samples/sysbuild/hello_world/sample.yaml | 34 ++++++------------- samples/sysbuild/hello_world/sysbuild.cmake | 20 +++++------ .../bl54l15_dvk_nrf54l15_cpuflpr.conf | 6 ---- .../bl54l15u_dvk_nrf54l15_cpuflpr.conf | 6 ---- .../sysbuild/nrf5340dk_nrf5340_cpunet.conf | 1 - .../sysbuild/nrf54h20dk_nrf54h20_cpuflpr.conf | 1 - .../nrf54h20dk_nrf54h20_cpuflpr_xip.conf | 1 - .../sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf | 1 - .../nrf54h20dk_nrf54h20_cpuppr_xip.conf | 1 - .../sysbuild/nrf54h20dk_nrf54h20_cpurad.conf | 1 - .../sysbuild/nrf54l15dk_nrf54l15_cpuflpr.conf | 1 - 12 files changed, 49 insertions(+), 55 deletions(-) delete mode 100644 samples/sysbuild/hello_world/sysbuild/bl54l15_dvk_nrf54l15_cpuflpr.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/bl54l15u_dvk_nrf54l15_cpuflpr.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/nrf5340dk_nrf5340_cpunet.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr_xip.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpurad.conf delete mode 100644 samples/sysbuild/hello_world/sysbuild/nrf54l15dk_nrf54l15_cpuflpr.conf diff --git a/samples/sysbuild/hello_world/Kconfig.sysbuild b/samples/sysbuild/hello_world/Kconfig.sysbuild index 53ed4507b7605..5204e7d6f6458 100644 --- a/samples/sysbuild/hello_world/Kconfig.sysbuild +++ b/samples/sysbuild/hello_world/Kconfig.sysbuild @@ -3,5 +3,34 @@ source "$(ZEPHYR_BASE)/share/sysbuild/Kconfig" +choice REMOTE_NRF54H20_CORE + prompt "Remote nRF54h20 core" + default REMOTE_NRF54H20_CPUFLPR_CORE + depends on SOC_NRF54H20_CPUAPP + +config REMOTE_NRF54H20_CPUFLPR_CORE + bool "flpr core" + +config REMOTE_NRF54H20_CPUFLPR_XIP_CORE + bool "flpr/xip core" + +config REMOTE_NRF54H20_CPUPPR_CORE + bool "ppr core" + +config REMOTE_NRF54H20_CPUPPR_XIP_CORE + bool "ppr/xip core" + +config REMOTE_NRF54H20_CPURAD_CORE + bool "cpurad" + +endchoice + config REMOTE_BOARD - string "The board used for remote target" + string + default "$(BOARD)/nrf5340/cpunet" if SOC_NRF5340_CPUAPP + default "$(BOARD)/nrf54l15/cpuflpr" if SOC_NRF54L15_CPUAPP + default "$(BOARD)/nrf54h20/cpurad" if SOC_NRF54H20_CPUAPP && REMOTE_NRF54H20_CPURAD_CORE + default "$(BOARD)/nrf54h20/cpuppr" if SOC_NRF54H20_CPUAPP && REMOTE_NRF54H20_CPUPPR_CORE + default "$(BOARD)/nrf54h20/cpuppr/xip" if SOC_NRF54H20_CPUAPP && REMOTE_NRF54H20_CPUPPR_XIP_CORE + default "$(BOARD)/nrf54h20/cpuflpr" if SOC_NRF54H20_CPUAPP && REMOTE_NRF54H20_CPUFLPR_CORE + default "$(BOARD)/nrf54h20/cpuflpr/xip" if SOC_NRF54H20_CPUAPP && REMOTE_NRF54H20_CPUFLPR_XIP_CORE diff --git a/samples/sysbuild/hello_world/sample.yaml b/samples/sysbuild/hello_world/sample.yaml index 86eeea479c6f8..eaff50bb68e1d 100644 --- a/samples/sysbuild/hello_world/sample.yaml +++ b/samples/sysbuild/hello_world/sample.yaml @@ -17,14 +17,13 @@ tests: - nrf5340dk/nrf5340/cpuapp integration_platforms: - nrf5340dk/nrf5340/cpuapp - extra_args: SB_CONF_FILE=sysbuild/nrf5340dk_nrf5340_cpunet.conf sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpurad: platform_allow: - nrf54h20dk/nrf54h20/cpuapp integration_platforms: - nrf54h20dk/nrf54h20/cpuapp extra_args: - - SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpurad.conf + - SB_CONFIG_REMOTE_NRF54H20_CPURAD_CORE=y - hello_world_CONFIG_SOC_NRF54H20_CPURAD_ENABLE=y sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpuppr: platform_allow: @@ -32,7 +31,7 @@ tests: integration_platforms: - nrf54h20dk/nrf54h20/cpuapp extra_args: - - SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf + - SB_CONFIG_REMOTE_NRF54H20_CPUPPR_CORE=y - hello_world_SNIPPET=nordic-ppr sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpuppr_xip: platform_allow: @@ -40,17 +39,20 @@ tests: integration_platforms: - nrf54h20dk/nrf54h20/cpuapp extra_args: - - SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf + - SB_CONFIG_REMOTE_NRF54H20_CPUPPR_XIP_CORE=y - hello_world_SNIPPET=nordic-ppr-xip - sample.sysbuild.hello_world.nrf54l15dk_nrf54l15_cpuflpr: + sample.sysbuild.hello_world.nrf54l15_cpuflpr: platform_allow: - nrf54l15dk/nrf54l15/cpuapp - ophelia4ev/nrf54l15/cpuapp + - bl54l15_dvk/nrf54l15/cpuapp + - bl54l15u_dvk/nrf54l15/cpuapp integration_platforms: - nrf54l15dk/nrf54l15/cpuapp - ophelia4ev/nrf54l15/cpuapp + - bl54l15_dvk/nrf54l15/cpuapp + - bl54l15u_dvk/nrf54l15/cpuapp extra_args: - - SB_CONF_FILE=sysbuild/nrf54l15dk_nrf54l15_cpuflpr.conf - hello_world_SNIPPET=nordic-flpr sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpuflpr: platform_allow: @@ -58,7 +60,7 @@ tests: integration_platforms: - nrf54h20dk/nrf54h20/cpuapp extra_args: - - SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpuflpr.conf + - SB_CONFIG_REMOTE_NRF54H20_CPUFLPR_CORE=y - hello_world_SNIPPET=nordic-flpr sample.sysbuild.hello_world.nrf54h20dk_cpuapp_cpuflpr_xip: platform_allow: @@ -66,21 +68,5 @@ tests: integration_platforms: - nrf54h20dk/nrf54h20/cpuapp extra_args: - - SB_CONF_FILE=sysbuild/nrf54h20dk_nrf54h20_cpuflpr_xip.conf + - SB_CONFIG_REMOTE_NRF54H20_CPUFLPR_XIP_CORE=y - hello_world_SNIPPET=nordic-flpr-xip - sample.sysbuild.hello_world.bl54l15_dvk_nrf54l15_cpuflpr: - platform_allow: - - bl54l15_dvk/nrf54l15/cpuapp - integration_platforms: - - bl54l15_dvk/nrf54l15/cpuapp - extra_args: - - SB_CONF_FILE=sysbuild/bl54l15_dvk_nrf54l15_cpuflpr.conf - - hello_world_SNIPPET=nordic-flpr - sample.sysbuild.hello_world.bl54l15u_dvk_nrf54l15_cpuflpr: - platform_allow: - - bl54l15u_dvk/nrf54l15/cpuapp - integration_platforms: - - bl54l15u_dvk/nrf54l15/cpuapp - extra_args: - - SB_CONF_FILE=sysbuild/bl54l15u_dvk_nrf54l15_cpuflpr.conf - - hello_world_SNIPPET=nordic-flpr diff --git a/samples/sysbuild/hello_world/sysbuild.cmake b/samples/sysbuild/hello_world/sysbuild.cmake index c7c2615c665ac..b7a4be187a990 100644 --- a/samples/sysbuild/hello_world/sysbuild.cmake +++ b/samples/sysbuild/hello_world/sysbuild.cmake @@ -1,15 +1,13 @@ # Copyright (c) 2024 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") - message(FATAL_ERROR "REMOTE_BOARD must be set to a valid board name") -endif() - -ExternalZephyrProject_Add( - APPLICATION remote - SOURCE_DIR ${APP_DIR}/remote - BOARD ${SB_CONFIG_REMOTE_BOARD} -) +if(DEFINED SB_CONFIG_REMOTE_BOARD) + ExternalZephyrProject_Add( + APPLICATION remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_REMOTE_BOARD} + ) -add_dependencies(${DEFAULT_IMAGE} remote) -sysbuild_add_dependencies(FLASH ${DEFAULT_IMAGE} remote) + add_dependencies(${DEFAULT_IMAGE} remote) + sysbuild_add_dependencies(FLASH ${DEFAULT_IMAGE} remote) +endif() diff --git a/samples/sysbuild/hello_world/sysbuild/bl54l15_dvk_nrf54l15_cpuflpr.conf b/samples/sysbuild/hello_world/sysbuild/bl54l15_dvk_nrf54l15_cpuflpr.conf deleted file mode 100644 index e801448406715..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/bl54l15_dvk_nrf54l15_cpuflpr.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2025 Nordic Semiconductor ASA -# Copyright (c) 2025 Ezurio LLC -# -# SPDX-License-Identifier: Apache-2.0 - -SB_CONFIG_REMOTE_BOARD="bl54l15_dvk/nrf54l15/cpuflpr" diff --git a/samples/sysbuild/hello_world/sysbuild/bl54l15u_dvk_nrf54l15_cpuflpr.conf b/samples/sysbuild/hello_world/sysbuild/bl54l15u_dvk_nrf54l15_cpuflpr.conf deleted file mode 100644 index 927961f56e307..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/bl54l15u_dvk_nrf54l15_cpuflpr.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2025 Nordic Semiconductor ASA -# Copyright (c) 2025 Ezurio LLC -# -# SPDX-License-Identifier: Apache-2.0 - -SB_CONFIG_REMOTE_BOARD="bl54l15u_dvk/nrf54l15/cpuflpr" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf5340dk_nrf5340_cpunet.conf b/samples/sysbuild/hello_world/sysbuild/nrf5340dk_nrf5340_cpunet.conf deleted file mode 100644 index b8ae05d4ef6fa..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/nrf5340dk_nrf5340_cpunet.conf +++ /dev/null @@ -1 +0,0 @@ -SB_CONFIG_REMOTE_BOARD="nrf5340dk/nrf5340/cpunet" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr.conf deleted file mode 100644 index 1f67cc417982a..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr.conf +++ /dev/null @@ -1 +0,0 @@ -SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpuflpr" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr_xip.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr_xip.conf deleted file mode 100644 index 0d827be9a1bbc..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuflpr_xip.conf +++ /dev/null @@ -1 +0,0 @@ -SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpuflpr/xip" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf deleted file mode 100644 index f50bc8553a011..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr.conf +++ /dev/null @@ -1 +0,0 @@ -SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpuppr" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf deleted file mode 100644 index 270c92c09a4f3..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpuppr_xip.conf +++ /dev/null @@ -1 +0,0 @@ -SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpuppr/xip" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpurad.conf b/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpurad.conf deleted file mode 100644 index dd863e78d9933..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/nrf54h20dk_nrf54h20_cpurad.conf +++ /dev/null @@ -1 +0,0 @@ -SB_CONFIG_REMOTE_BOARD="nrf54h20dk/nrf54h20/cpurad" diff --git a/samples/sysbuild/hello_world/sysbuild/nrf54l15dk_nrf54l15_cpuflpr.conf b/samples/sysbuild/hello_world/sysbuild/nrf54l15dk_nrf54l15_cpuflpr.conf deleted file mode 100644 index 203dc628f47d6..0000000000000 --- a/samples/sysbuild/hello_world/sysbuild/nrf54l15dk_nrf54l15_cpuflpr.conf +++ /dev/null @@ -1 +0,0 @@ -SB_CONFIG_REMOTE_BOARD="nrf54l15dk/nrf54l15/cpuflpr" From 57a573d7337eccbee140ffaa5ba8118444b44524 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 10 Sep 2025 11:50:39 +0200 Subject: [PATCH 064/397] samples: pass on board revision in sysbuild/hello_world Pass on the board revision to remote image build if specified for the application image board target. Signed-off-by: Torsten Rasmussen --- samples/sysbuild/hello_world/sysbuild.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/sysbuild/hello_world/sysbuild.cmake b/samples/sysbuild/hello_world/sysbuild.cmake index b7a4be187a990..fa0599c6a6214 100644 --- a/samples/sysbuild/hello_world/sysbuild.cmake +++ b/samples/sysbuild/hello_world/sysbuild.cmake @@ -6,6 +6,7 @@ if(DEFINED SB_CONFIG_REMOTE_BOARD) APPLICATION remote SOURCE_DIR ${APP_DIR}/remote BOARD ${SB_CONFIG_REMOTE_BOARD} + BOARD_REVISION ${BOARD_REVISION} ) add_dependencies(${DEFAULT_IMAGE} remote) From 843db50cdb203dc21310b071f8b1690f999b313d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag=20Erik=20Gj=C3=B8rvad?= Date: Thu, 9 Oct 2025 16:03:30 +0200 Subject: [PATCH 065/397] manifest: Update commit id for trusted-firmware-m MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update commit id for trusted-firmware-m to bring in support for nRF54LM20A/ns. Signed-off-by: Dag Erik Gjørvad --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0115484ee4e6e..33f2ebc3dc7d0 100644 --- a/west.yml +++ b/west.yml @@ -369,7 +369,7 @@ manifest: groups: - tee - name: trusted-firmware-m - revision: 591f37f31a882208e7b1ddb8e053a4bdf72c68ed + revision: 62ad723311da2cac938e2ae88bafe9e815b3b248 path: modules/tee/tf-m/trusted-firmware-m groups: - tee From 29b24f753fcee0be1ba2bac64023e60be09dc0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag=20Erik=20Gj=C3=B8rvad?= Date: Thu, 7 Aug 2025 12:50:50 +0200 Subject: [PATCH 066/397] boards: nordic: Add initial support for nRF54LM20A/ns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add board files for nRF54LM20A/ns. Update existing nRF54LM20A board files to support this. Signed-off-by: Dag Erik Gjørvad --- boards/nordic/nrf54lm20dk/Kconfig | 28 ++++++++ boards/nordic/nrf54lm20dk/Kconfig.defconfig | 9 +++ boards/nordic/nrf54lm20dk/Kconfig.nrf54lm20dk | 2 +- boards/nordic/nrf54lm20dk/board.cmake | 8 +++ boards/nordic/nrf54lm20dk/board.yml | 5 ++ .../nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi | 38 ----------- .../nrf54lm20dk_nrf54lm20a_cpuapp.dts | 1 + .../nrf54lm20dk_nrf54lm20a_cpuapp_ns.dts | 68 +++++++++++++++++++ .../nrf54lm20dk_nrf54lm20a_cpuapp_ns.yaml | 22 ++++++ ...nrf54lm20dk_nrf54lm20a_cpuapp_ns_defconfig | 45 ++++++++++++ dts/arm/nordic/nrf54lm20a_enga_cpuapp.dtsi | 4 ++ dts/vendor/nordic/nrf54lm20a.dtsi | 25 +++++++ .../nordic/nrf54lm20a_ns_partition.dtsi | 62 +++++++++++++++++ dts/vendor/nordic/nrf54lm20a_partition.dtsi | 37 ++++++++++ modules/trusted-firmware-m/Kconfig.tfm | 1 + .../nordic/nrf54lm20a_cpuapp/CMakeLists.txt | 23 +++++++ .../nordic/nrf54lm20a_cpuapp/config.cmake | 9 +++ .../nordic/nrf54lm20a_cpuapp/cpuarch.cmake | 9 +++ .../nrf54lm20a_cpuapp/ns/cpuarch_ns.cmake | 10 +++ samples/drivers/watchdog/sample.yaml | 1 + .../tfm_integration/config_build/sample.yaml | 1 + samples/tfm_integration/tfm_ipc/sample.yaml | 1 + tests/drivers/adc/adc_api/testcase.yaml | 1 + .../watchdog/wdt_basic_api/testcase.yaml | 1 + tests/subsys/settings/its/testcase.yaml | 1 + 25 files changed, 373 insertions(+), 39 deletions(-) create mode 100644 boards/nordic/nrf54lm20dk/Kconfig create mode 100644 boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.dts create mode 100644 boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.yaml create mode 100644 boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns_defconfig create mode 100644 dts/vendor/nordic/nrf54lm20a_ns_partition.dtsi create mode 100644 dts/vendor/nordic/nrf54lm20a_partition.dtsi create mode 100644 modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/CMakeLists.txt create mode 100644 modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/config.cmake create mode 100644 modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/cpuarch.cmake create mode 100644 modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/ns/cpuarch_ns.cmake diff --git a/boards/nordic/nrf54lm20dk/Kconfig b/boards/nordic/nrf54lm20dk/Kconfig new file mode 100644 index 0000000000000..0b1905a0d8ef1 --- /dev/null +++ b/boards/nordic/nrf54lm20dk/Kconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +DT_NRF_MPC := $(dt_nodelabel_path,nrf_mpc) + +if BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP_NS + +config NRF_TRUSTZONE_FLASH_REGION_SIZE + hex + default $(dt_node_int_prop_hex,$(DT_NRF_MPC),override-granularity) + help + This defines the flash region size from the TrustZone perspective. + It is used when configuring the TrustZone and when setting alignments + requirements for the partitions. + This abstraction allows us to configure TrustZone without depending + on peripheral-specific symbols. + +config NRF_TRUSTZONE_RAM_REGION_SIZE + hex + default $(dt_node_int_prop_hex,$(DT_NRF_MPC),override-granularity) + help + This defines the RAM region size from the TrustZone perspective. + It is used when configuring the TrustZone and when setting alignments + requirements for the partitions. + This abstraction allows us to configure TrustZone without depending + on peripheral specific symbols. + +endif # BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP_NS diff --git a/boards/nordic/nrf54lm20dk/Kconfig.defconfig b/boards/nordic/nrf54lm20dk/Kconfig.defconfig index 67410cd4d653f..c77e844b822cf 100644 --- a/boards/nordic/nrf54lm20dk/Kconfig.defconfig +++ b/boards/nordic/nrf54lm20dk/Kconfig.defconfig @@ -7,3 +7,12 @@ config HW_STACK_PROTECTION default ARCH_HAS_STACK_PROTECTION endif # BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP + +if BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP_NS + +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y + +endif # BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP_NS diff --git a/boards/nordic/nrf54lm20dk/Kconfig.nrf54lm20dk b/boards/nordic/nrf54lm20dk/Kconfig.nrf54lm20dk index 83b3842211f31..b311fd9ae87e1 100644 --- a/boards/nordic/nrf54lm20dk/Kconfig.nrf54lm20dk +++ b/boards/nordic/nrf54lm20dk/Kconfig.nrf54lm20dk @@ -2,5 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_NRF54LM20DK - select SOC_NRF54LM20A_ENGA_CPUAPP if BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP + select SOC_NRF54LM20A_ENGA_CPUAPP if BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP || BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP_NS select SOC_NRF54LM20A_ENGA_CPUFLPR if BOARD_NRF54LM20DK_NRF54LM20A_CPUFLPR diff --git a/boards/nordic/nrf54lm20dk/board.cmake b/boards/nordic/nrf54lm20dk/board.cmake index e487ecfb476fe..6aaf6196d5729 100644 --- a/boards/nordic/nrf54lm20dk/board.cmake +++ b/boards/nordic/nrf54lm20dk/board.cmake @@ -7,5 +7,13 @@ elseif(CONFIG_SOC_NRF54LM20A_ENGA_CPUFLPR) board_runner_args(jlink "--speed=4000") endif() +if(CONFIG_BOARD_NRF54LM20DK_NRF54LM20A_CPUAPP_NS) + set(TFM_PUBLIC_KEY_FORMAT "full") +endif() + +if(CONFIG_TFM_FLASH_MERGED_BINARY) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex) +endif() + include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/nordic/nrf54lm20dk/board.yml b/boards/nordic/nrf54lm20dk/board.yml index 2930f9d3dfbdc..86decbf7c7cd0 100644 --- a/boards/nordic/nrf54lm20dk/board.yml +++ b/boards/nordic/nrf54lm20dk/board.yml @@ -5,6 +5,8 @@ board: socs: - name: nrf54lm20a variants: + - name: ns + cpucluster: cpuapp - name: xip cpucluster: cpuflpr runners: @@ -17,6 +19,7 @@ runners: groups: - boards: - nrf54lm20dk/nrf54lm20a/cpuapp + - nrf54lm20dk/nrf54lm20a/cpuapp/ns - nrf54lm20dk/nrf54lm20a/cpuflpr - nrf54lm20dk/nrf54lm20a/cpuflpr/xip '--erase': @@ -28,6 +31,7 @@ runners: groups: - boards: - nrf54lm20dk/nrf54lm20a/cpuapp + - nrf54lm20dk/nrf54lm20a/cpuapp/ns - nrf54lm20dk/nrf54lm20a/cpuflpr - nrf54lm20dk/nrf54lm20a/cpuflpr/xip '--reset': @@ -39,5 +43,6 @@ runners: groups: - boards: - nrf54lm20dk/nrf54lm20a/cpuapp + - nrf54lm20dk/nrf54lm20a/cpuapp/ns - nrf54lm20dk/nrf54lm20a/cpuflpr - nrf54lm20dk/nrf54lm20a/cpuflpr/xip diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi index b096e0e9ebcfd..f0946efb543f2 100644 --- a/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi +++ b/boards/nordic/nrf54lm20dk/nrf54lm20a_cpuapp_common.dtsi @@ -58,44 +58,6 @@ status = "okay"; }; -&cpuapp_rram { - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x0 DT_SIZE_K(64)>; - }; - - slot0_partition: partition@10000 { - label = "image-0"; - reg = <0x10000 DT_SIZE_K(449)>; - }; - - slot0_ns_partition: partition@80400 { - label = "image-0-nonsecure"; - reg = <0x80400 DT_SIZE_K(449)>; - }; - - slot1_partition: partition@f0800 { - label = "image-1"; - reg = <0xf0800 DT_SIZE_K(449)>; - }; - - slot1_ns_partition: partition@160c00 { - label = "image-1-nonsecure"; - reg = <0x160c00 DT_SIZE_K(449)>; - }; - - storage_partition: partition@1d1000 { - label = "storage"; - reg = <0x1d1000 DT_SIZE_K(36)>; - }; - }; -}; - &uart20 { status = "okay"; }; diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp.dts b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp.dts index 6dd2c5b2e850a..2e79bbb98215c 100644 --- a/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp.dts +++ b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp.dts @@ -7,6 +7,7 @@ /dts-v1/; #include "nrf54lm20a_cpuapp_common.dtsi" +#include / { compatible = "nordic,nrf54lm20dk_nrf54lm20a-cpuapp"; diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.dts b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.dts new file mode 100644 index 0000000000000..04cb9d04a60ca --- /dev/null +++ b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.dts @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#define USE_NON_SECURE_ADDRESS_MAP 1 + +#include "nrf54lm20a_cpuapp_common.dtsi" + +/ { + compatible = "nordic,nrf54lm20dk_nrf54lm20a-cpuapp-ns"; + model = "Nordic nRF54LM20 DK nRF54LM20A Application MCU Non-Secure"; + + chosen { + zephyr,code-partition = &slot0_ns_partition; + zephyr,sram = &sram0_ns; + zephyr,entropy = &psa_rng; + }; + + /delete-node/ rng; + + psa_rng: psa-rng { + status = "okay"; + }; +}; + +/ { + /* + * Default SRAM planning when building for nRF54LM20A with ARM TrustZone-M support + * - Lowest 208 kB SRAM allocated to Secure image (sram0_s). + * - Upper 208 kB SRAM allocated to Non-Secure image (sram0_ns). + * + * nRF54LM20A has 512 kB of volatile memory (SRAM), but 96kB is allocated for the FLPR MCU. + * This static layout needs to be the same with the upstream TF-M layout in the + * header flash_layout.h of the relevant platform. Any updates in the layout + * needs to happen both in the flash_layout.h and in this file at the same time. + */ + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_s: image_s@20000000 { + /* Secure image memory */ + reg = <0x20000000 DT_SIZE_K(208)>; + }; + + sram0_ns: image_ns@20034000 { + /* Non-Secure image memory */ + reg = <0x20034000 DT_SIZE_K(208)>; + }; + }; +}; + +&bt_hci_controller { + status = "disabled"; +}; + +&uart30 { + /* Disable so that TF-M can use this UART */ + status = "disabled"; +}; + +/* Include default memory partition configuration file */ +#include diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.yaml b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.yaml new file mode 100644 index 0000000000000..3f10201892fb5 --- /dev/null +++ b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns.yaml @@ -0,0 +1,22 @@ +identifier: nrf54lm20dk/nrf54lm20a/cpuapp/ns +name: nRF54lm20-DK-nRF54lm20a-Application-Non-Secure +type: mcu +arch: arm +toolchain: + - gnuarmemb + - zephyr +ram: 208 +flash: 1356 +supported: + - adc + - counter + - dmic + - gpio + - i2c + - i2s + - pwm + - spi + - usbd + - watchdog +vendor: nordic +sysbuild: true diff --git a/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns_defconfig b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns_defconfig new file mode 100644 index 0000000000000..d360ef89bac48 --- /dev/null +++ b/boards/nordic/nrf54lm20dk/nrf54lm20dk_nrf54lm20a_cpuapp_ns_defconfig @@ -0,0 +1,45 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Enable MPU +CONFIG_ARM_MPU=y +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable TrustZone-M +CONFIG_ARM_TRUSTZONE_M=y + +# This Board implies building Non-Secure firmware +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# Use devicetree code partition for TF-M +CONFIG_USE_DT_CODE_PARTITION=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Don't enable the cache in the non-secure image as it is a +# secure-only peripheral on 54l +CONFIG_CACHE_MANAGEMENT=n +CONFIG_EXTERNAL_CACHE=n + +# Start SYSCOUNTER on driver init +CONFIG_NRF_GRTC_START_SYSCOUNTER=y + +# Disable TFM BL2 since it is not supported +CONFIG_TFM_BL2=n +# Support for silence logging is not supported at the moment +# Tracked by: NCSDK-31930 +CONFIG_TFM_LOG_LEVEL_SILENCE=n + +# The oscillators are configured as secure and cannot be configured +# from the non secure application directly. This needs to be set +# otherwise nrfx will try to configure them, resulting in a bus +# fault. +CONFIG_NRF_SKIP_CLOCK_CONFIG=y diff --git a/dts/arm/nordic/nrf54lm20a_enga_cpuapp.dtsi b/dts/arm/nordic/nrf54lm20a_enga_cpuapp.dtsi index d5aa024dd6d30..dff01d80d7fef 100644 --- a/dts/arm/nordic/nrf54lm20a_enga_cpuapp.dtsi +++ b/dts/arm/nordic/nrf54lm20a_enga_cpuapp.dtsi @@ -66,7 +66,11 @@ nvic: &cpuapp_nvic {}; }; &grtc { +#ifdef USE_NON_SECURE_ADDRESS_MAP + interrupts = <227 NRF_DEFAULT_IRQ_PRIORITY>, +#else interrupts = <228 NRF_DEFAULT_IRQ_PRIORITY>, +#endif <229 NRF_DEFAULT_IRQ_PRIORITY>; /* reserved for Zero Latency IRQs */ }; diff --git a/dts/vendor/nordic/nrf54lm20a.dtsi b/dts/vendor/nordic/nrf54lm20a.dtsi index 233e4417986a5..2f3e9b9934ded 100644 --- a/dts/vendor/nordic/nrf54lm20a.dtsi +++ b/dts/vendor/nordic/nrf54lm20a.dtsi @@ -96,10 +96,14 @@ #nordic,ficr-cells = <1>; }; +#ifdef USE_NON_SECURE_ADDRESS_MAP + /* intentionally empty because UICR is hardware fixed to Secure */ +#else uicr: uicr@ffd000 { compatible = "nordic,nrf-uicr"; reg = <0xffd000 0x1000>; }; +#endif cpuapp_sram: memory@20000000 { compatible = "mmio-sram"; @@ -117,11 +121,19 @@ ranges = <0x0 0x20067c00 DT_SIZE_K(96)>; }; +#ifdef USE_NON_SECURE_ADDRESS_MAP + global_peripherals: peripheral@40000000 { + reg = <0x40000000 0x10000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x40000000 0x10000000>; +#else global_peripherals: peripheral@50000000 { reg = <0x50000000 0x10000000>; ranges = <0x0 0x50000000 0x10000000>; #address-cells = <1>; #size-cells = <1>; +#endif dppic00: dppic@42000 { compatible = "nordic,nrf-dppic"; @@ -748,12 +760,16 @@ interrupts = <262 NRF_DEFAULT_IRQ_PRIORITY>; }; +#ifdef USE_NON_SECURE_ADDRESS_MAP + /* intentionally empty because WDT30 is hardware fixed to Secure */ +#else wdt30: watchdog@108000 { compatible = "nordic,nrf-wdt"; reg = <0x108000 0x620>; interrupts = <264 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; }; +#endif wdt31: watchdog@109000 { compatible = "nordic,nrf-wdt"; @@ -852,6 +868,15 @@ }; }; + nrf_mpc: memory@50041000 { + compatible = "nordic,nrf-mpc"; + reg = <0x50041000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + override-num = <5>; + override-granularity = <4096>; + }; + cpuapp_ppb: cpuapp-ppb-bus { #address-cells = <1>; #size-cells = <1>; diff --git a/dts/vendor/nordic/nrf54lm20a_ns_partition.dtsi b/dts/vendor/nordic/nrf54lm20a_ns_partition.dtsi new file mode 100644 index 0000000000000..954dd8290453f --- /dev/null +++ b/dts/vendor/nordic/nrf54lm20a_ns_partition.dtsi @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuapp_rram { + /* + * Default NVM layout on NRF54LM20A Application MCU without BL2: + * This layout matches (by necessity) that in the TF-M repository: + * + * 0x0000_0000 Secure image primary (512 KB) + * 0x0008_0000 Protected Storage Area (16 KB) + * 0x0008_4000 Internal Trusted Storage Area (16 KB) + * 0x0008_8000 OTP / NV counters area (8 KB) + * 0x0008_A000 Non-secure image primary (1356 KB) + * 0x001D_DD00 Non-secure storage, used when built with NRF_NS_STORAGE=ON, + * otherwise unused (32 KB) + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* nRF54LM20A has 2036 kB of non-volatile memory (RRAM) but the last + * 96 kB are reserved for the FLPR MCU. + * + * This static layout needs to be the same with the upstream TF-M layout in the + * header flash_layout.h of the relevant platform. Any updates in the layout + * needs to happen both in the flash_layout.h and in this file at the same time. + */ + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x0000000 DT_SIZE_K(512)>; + }; + + tfm_ps_partition: partition@80000 { + label = "tfm-ps"; + reg = <0x00080000 DT_SIZE_K(16)>; + }; + + tfm_its_partition: partition@84000 { + label = "tfm-its"; + reg = <0x00084000 DT_SIZE_K(16)>; + }; + + tfm_otp_partition: partition@88000 { + label = "tfm-otp"; + reg = <0x00088000 DT_SIZE_K(8)>; + }; + + slot0_ns_partition: partition@8A000 { + label = "image-0-nonsecure"; + reg = <0x0008A000 DT_SIZE_K(1356)>; + }; + + storage_partition: partition@1DD000 { + label = "storage"; + reg = <0x001DD000 DT_SIZE_K(32)>; + }; + }; +}; diff --git a/dts/vendor/nordic/nrf54lm20a_partition.dtsi b/dts/vendor/nordic/nrf54lm20a_partition.dtsi new file mode 100644 index 0000000000000..049f87139d914 --- /dev/null +++ b/dts/vendor/nordic/nrf54lm20a_partition.dtsi @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuapp_rram { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* nRF54LM20A has 2036 kB of non-volatile memory (RRAM) but the last + * 96 kB are reserved for the FLPR MCU, so we have ~1940 kB available. + */ + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 DT_SIZE_K(64)>; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x10000 DT_SIZE_K(922)>; + }; + + slot1_partition: partition@f6800 { + label = "image-1"; + reg = <0xf6800 DT_SIZE_K(922)>; + }; + + storage_partition: partition@1dd000 { + label = "storage"; + reg = <0x1dd000 DT_SIZE_K(32)>; + }; + }; +}; diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index 39232b88fb9e8..06c7221321ec9 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -31,6 +31,7 @@ config TFM_BOARD default "$(ZEPHYR_BASE)/modules/trusted-firmware-m/nordic/nrf5340_cpuapp" if SOC_NRF5340_CPUAPP default "$(ZEPHYR_BASE)/modules/trusted-firmware-m/nordic/nrf54l15_cpuapp" if SOC_NRF54L15_CPUAPP default "$(ZEPHYR_BASE)/modules/trusted-firmware-m/nordic/nrf54l10_cpuapp" if SOC_NRF54L10_CPUAPP + default "$(ZEPHYR_BASE)/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp" if SOC_NRF54LM20A_ENGA_CPUAPP help The board name used for building TFM. Building with TFM requires that TFM has been ported to the given board/SoC. diff --git a/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/CMakeLists.txt b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/CMakeLists.txt new file mode 100644 index 0000000000000..c926ace19c8f2 --- /dev/null +++ b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright (c) 2025, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(NRF_BOARD_SELECTED True) + +add_subdirectory(${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf54lm20a nrf54lm20a) + +add_subdirectory(.. common) + +install(FILES ${CMAKE_CURRENT_LIST_DIR}/ns/cpuarch_ns.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR} + RENAME cpuarch.cmake) + +install(FILES config.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) + +install(DIRECTORY ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/nrf54lm20dk_nrf54lm20a_cpuapp/tests + + DESTINATION ${INSTALL_PLATFORM_NS_DIR} +) diff --git a/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/config.cmake b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/config.cmake new file mode 100644 index 0000000000000..4b1e3ab5e97c4 --- /dev/null +++ b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/config.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2025, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(NRF_SOC_VARIANT nrf54lm20a CACHE STRING "nRF SoC Variant") + +include(${PLATFORM_PATH}/common/nrf54lm20a/config.cmake) diff --git a/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/cpuarch.cmake b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/cpuarch.cmake new file mode 100644 index 0000000000000..1766b89f99647 --- /dev/null +++ b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/cpuarch.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2025, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(PLATFORM_PATH platform/ext/target/nordic_nrf) + +include(${PLATFORM_PATH}/common/nrf54lm20a/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/ns/cpuarch_ns.cmake b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/ns/cpuarch_ns.cmake new file mode 100644 index 0000000000000..cec0a5536dd33 --- /dev/null +++ b/modules/trusted-firmware-m/nordic/nrf54lm20a_cpuapp/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2025, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(PLATFORM_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(PLATFORM_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/common/nrf54lm20a/cpuarch.cmake) diff --git a/samples/drivers/watchdog/sample.yaml b/samples/drivers/watchdog/sample.yaml index 0eb51a0e93c22..b89590cac86a4 100644 --- a/samples/drivers/watchdog/sample.yaml +++ b/samples/drivers/watchdog/sample.yaml @@ -26,6 +26,7 @@ tests: - panb611evb/nrf54l15/cpuapp/ns - panb611evb/nrf54l15/cpuflpr - panb611evb/nrf54l15/cpuflpr/xip + - nrf54lm20dk/nrf54lm20a/cpuapp/ns - nrf54l15dk/nrf54l15/cpuapp/ns - nrf54l15dk/nrf54l10/cpuapp/ns - bl54l15_dvk/nrf54l10/cpuapp/ns diff --git a/samples/tfm_integration/config_build/sample.yaml b/samples/tfm_integration/config_build/sample.yaml index 3c46c148f7bab..55c4e2348081f 100644 --- a/samples/tfm_integration/config_build/sample.yaml +++ b/samples/tfm_integration/config_build/sample.yaml @@ -10,6 +10,7 @@ common: - nrf9160dk/nrf9160/ns - nrf54l15dk/nrf54l15/cpuapp/ns - nrf54l15dk/nrf54l10/cpuapp/ns + - nrf54lm20dk/nrf54lm20a/cpuapp/ns - bl5340_dvk/nrf5340/cpuapp/ns integration_platforms: - nrf5340dk/nrf5340/cpuapp/ns diff --git a/samples/tfm_integration/tfm_ipc/sample.yaml b/samples/tfm_integration/tfm_ipc/sample.yaml index 390efa24fb7e1..154d91b23f312 100644 --- a/samples/tfm_integration/tfm_ipc/sample.yaml +++ b/samples/tfm_integration/tfm_ipc/sample.yaml @@ -35,6 +35,7 @@ tests: - mps2/an521/cpu0/ns - nrf54l15dk/nrf54l15/cpuapp/ns - nrf54l15dk/nrf54l10/cpuapp/ns + - nrf54lm20dk/nrf54lm20a/cpuapp/ns extra_configs: - CONFIG_TFM_BL2=n harness: console diff --git a/tests/drivers/adc/adc_api/testcase.yaml b/tests/drivers/adc/adc_api/testcase.yaml index 25bcedc3aa7fd..3cb2711665512 100644 --- a/tests/drivers/adc/adc_api/testcase.yaml +++ b/tests/drivers/adc/adc_api/testcase.yaml @@ -15,6 +15,7 @@ tests: - panb611evb/nrf54l15/cpuapp/ns - nrf54l15dk/nrf54l15/cpuapp/ns - nrf54l15dk/nrf54l10/cpuapp/ns + - nrf54lm20dk/nrf54lm20a/cpuapp/ns - bl54l15_dvk/nrf54l10/cpuapp/ns - bl54l15_dvk/nrf54l15/cpuapp/ns - bl54l15u_dvk/nrf54l15/cpuapp/ns diff --git a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml index 84d4ab51b9496..608d058fb35f3 100644 --- a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml +++ b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml @@ -28,6 +28,7 @@ tests: - mimxrt700_evk/mimxrt798s/cm33_cpu1 - nrf54l15dk/nrf54l15/cpuapp/ns - nrf54l15dk/nrf54l10/cpuapp/ns + - nrf54lm20dk/nrf54lm20a/cpuapp/ns - bl54l15_dvk/nrf54l10/cpuapp/ns - bl54l15_dvk/nrf54l15/cpuapp/ns - bl54l15u_dvk/nrf54l15/cpuapp/ns diff --git a/tests/subsys/settings/its/testcase.yaml b/tests/subsys/settings/its/testcase.yaml index de11f1ef72643..c63019e634573 100644 --- a/tests/subsys/settings/its/testcase.yaml +++ b/tests/subsys/settings/its/testcase.yaml @@ -10,5 +10,6 @@ tests: - max32657evkit/max32657/ns - nrf5340dk/nrf5340/cpuapp/ns - nrf54l15dk/nrf54l15/cpuapp/ns + - nrf54lm20dk/nrf54lm20a/cpuapp/ns platform_exclude: - lpcxpresso55s69/lpc55s69/cpu0/ns From 270b5cd486406fc0b49c999b454d2e361874136d Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Thu, 14 Aug 2025 12:35:19 +0200 Subject: [PATCH 067/397] drivers: flash: esp32: Add asynchronous flash access using work queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Direct flash access can cause exceptions when performed while the flash memory is inaccessible or being modified — for example, when code is executing from PSRAM. To avoid such invalid access, this change introduces asynchronous flash operations that are executed from a safe runtime context via a work queue. This ensures all flash accesses occur only when the flash is valid and accessible. Signed-off-by: Marek Matej --- drivers/flash/Kconfig.esp32 | 31 +++++++ drivers/flash/flash_esp32.c | 156 +++++++++++++++++++++++++++++++----- 2 files changed, 167 insertions(+), 20 deletions(-) diff --git a/drivers/flash/Kconfig.esp32 b/drivers/flash/Kconfig.esp32 index 4da80bce0c0fd..aa34e04045113 100644 --- a/drivers/flash/Kconfig.esp32 +++ b/drivers/flash/Kconfig.esp32 @@ -15,3 +15,34 @@ config MPU_ALLOW_FLASH_WRITE bool "Add MPU access to write to flash" help Enable this to allow MPU RWX access to flash memory + +if SOC_FLASH_ESP32 + +config ESP_FLASH_ASYNC + bool "Use asynchronous work thread to execute the flash access operations" + depends on MULTITHREADING && !MCUBOOT + help + Enabling this makes the flash access operations deferred to the work thread. + Meaning every flash read or write would be postponed and executed when available. + +config ESP_FLASH_ASYNC_WORK + bool "Use dedicated work thread to perform the work tasks" + depends on ESP_FLASH_ASYNC + help + Use dedicated work thread to perform the workqueue tasks with flash asynchronous operations. + +config ESP_FLASH_ASYNC_WORK_STACK_SIZE + int "Stack size for dedicated work thread" + depends on ESP_FLASH_ASYNC_WORK + default 1024 + help + Define stack size for a dedicated work thread processing workqueue. + +config ESP_FLASH_ASYNC_WORK_PRIORITY + int "Thread priority for dedicated work thread" + depends on ESP_FLASH_ASYNC_WORK + default 5 + help + Define thread priority for a dedicated work thread processing workqueue. + +endif # SOC_FLASH_ESP32 diff --git a/drivers/flash/flash_esp32.c b/drivers/flash/flash_esp32.c index da91199c1c4d7..88a3e5031f9f0 100644 --- a/drivers/flash/flash_esp32.c +++ b/drivers/flash/flash_esp32.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2021-2025 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ @@ -45,11 +45,37 @@ LOG_MODULE_REGISTER(flash_esp32, CONFIG_FLASH_LOG_LEVEL); #define ALIGN_OFFSET(num, align) ((num) & ((align) - 1)) #endif +#ifdef CONFIG_ESP_FLASH_ASYNC_WORK +#define ESP_FLASH_WORKQUEUE_STACK_SIZE CONFIG_ESP_FLASH_ASYNC_WORK_STACK_SIZE +#define ESP_FLASH_WORKQUEUE_PRIORITY CONFIG_ESP_FLASH_ASYNC_WORK_PRIORITY +K_THREAD_STACK_DEFINE(esp_flash_workqueue_stack, ESP_FLASH_WORKQUEUE_STACK_SIZE); +static struct k_work_q esp_flash_workqueue; +#endif /* CONFIG_ESP_FLASH_ASYNC_WORK */ + +#ifdef CONFIG_ESP_FLASH_ASYNC +enum { + FLASH_OP_NONE, + FLASH_OP_READ, + FLASH_OP_WRITE, + FLASH_OP_ERASE +}; +#endif + struct flash_esp32_dev_config { spi_dev_t *controller; }; struct flash_esp32_dev_data { +#ifdef CONFIG_ESP_FLASH_ASYNC + struct k_work work; + struct k_mutex lock; + const struct device *dev; + int type; + off_t addr; + size_t len; + void *buf; + int ret; +#endif #ifdef CONFIG_MULTITHREADING struct k_sem sem; #endif @@ -60,7 +86,7 @@ static const struct flash_parameters flash_esp32_parameters = { .erase_value = 0xff, }; -#ifdef CONFIG_MULTITHREADING +#if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_ESP_FLASH_ASYNC) static inline void flash_esp32_sem_take(const struct device *dev) { struct flash_esp32_dev_data *data = dev->data; @@ -79,7 +105,7 @@ static inline void flash_esp32_sem_give(const struct device *dev) #define flash_esp32_sem_take(dev) do {} while (0) #define flash_esp32_sem_give(dev) do {} while (0) -#endif /* CONFIG_MULTITHREADING */ +#endif /* CONFIG_MULTITHREADING && !CONFIG_ESP_FLASH_ASYNC */ #include #include @@ -374,12 +400,9 @@ static int flash_esp32_read(const struct device *dev, off_t address, void *buffe } #else flash_esp32_sem_take(dev); - ret = flash_esp32_read_check_enc(address, buffer, length); - flash_esp32_sem_give(dev); -#endif - +#endif /* CONFIG_MCUBOOT */ if (ret != 0) { LOG_ERR("Flash read error: %d", ret); return -EIO; @@ -388,9 +411,7 @@ static int flash_esp32_read(const struct device *dev, off_t address, void *buffe return 0; } -static int flash_esp32_write(const struct device *dev, - off_t address, - const void *buffer, +static int flash_esp32_write(const struct device *dev, off_t address, const void *buffer, size_t length) { int ret = 0; @@ -423,11 +444,10 @@ static int flash_esp32_write(const struct device *dev, } #else ret = flash_esp32_write_check_enc(address, buffer, length); -#endif +#endif /* CONFIG_ESP_FLASH_ENCRYPTION */ flash_esp32_sem_give(dev); -#endif - +#endif /* CONFIG_MCUBOOT */ if (ret != 0) { LOG_ERR("Flash write error: %d", ret); return -EIO; @@ -480,10 +500,10 @@ static int flash_esp32_erase(const struct device *dev, off_t start, size_t len) } #else ret = esp_flash_erase_region(NULL, start, len); -#endif +#endif /* CONFIG_ESP_FLASH_ENCRYPTION */ flash_esp32_sem_give(dev); -#endif +#endif /* CONFIG_MCUBOOT */ if (ret != 0) { LOG_ERR("Flash erase error: %d", ret); return -EIO; @@ -491,6 +511,83 @@ static int flash_esp32_erase(const struct device *dev, off_t start, size_t len) return 0; } +#ifdef CONFIG_ESP_FLASH_ASYNC +static void flash_work_handler(struct k_work *work) +{ + struct flash_esp32_dev_data *data = CONTAINER_OF(work, struct flash_esp32_dev_data, work); + + if (data->type == FLASH_OP_READ) { + data->ret = flash_esp32_read(data->dev, data->addr, data->buf, data->len); + } else if (data->type == FLASH_OP_WRITE) { + data->ret = flash_esp32_write(data->dev, data->addr, data->buf, data->len); + } else if (data->type == FLASH_OP_ERASE) { + data->ret = flash_esp32_erase(data->dev, data->addr, data->len); + } else { + data->ret = -EINVAL; + } + + k_sem_give(&data->sem); +} + +static int flash_esp32_read_async(const struct device *dev, off_t address, + void *buffer, size_t length) +{ + struct flash_esp32_dev_data *data = dev->data; + + k_mutex_lock(&data->lock, K_TIMEOUT_ABS_SEC(3)); + + data->dev = dev; + data->addr = address; + data->buf = buffer; + data->len = length; + data->type = FLASH_OP_READ; + + k_work_submit(&data->work); + k_sem_take(&data->sem, FLASH_SEM_TIMEOUT); + k_mutex_unlock(&data->lock); + + return data->ret; +} + +static int flash_esp32_write_async(const struct device *dev, off_t address, + const void *buffer, size_t length) +{ + struct flash_esp32_dev_data *data = dev->data; + + k_mutex_lock(&data->lock, K_TIMEOUT_ABS_SEC(3)); + + data->dev = dev; + data->addr = address; + data->buf = (void *) buffer; + data->len = length; + data->type = FLASH_OP_WRITE; + + k_work_submit(&data->work); + k_sem_take(&data->sem, FLASH_SEM_TIMEOUT); + k_mutex_unlock(&data->lock); + + return 0; +} +static int flash_esp32_erase_async(const struct device *dev, off_t start, size_t len) +{ + struct flash_esp32_dev_data *data = dev->data; + + k_mutex_lock(&data->lock, K_TIMEOUT_ABS_SEC(3)); + + data->addr = start; + data->len = len; + data->buf = NULL; + data->type = FLASH_OP_ERASE; + + k_work_submit(&data->work); + k_sem_take(&data->sem, FLASH_SEM_TIMEOUT); + k_mutex_unlock(&data->lock); + + return 0; +} +#endif + + #if CONFIG_FLASH_PAGE_LAYOUT static const struct flash_pages_layout flash_esp32_pages_layout = { .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ, @@ -504,7 +601,7 @@ void flash_esp32_page_layout(const struct device *dev, *layout = &flash_esp32_pages_layout; *layout_size = 1; } -#endif /* CONFIG_FLASH_PAGE_LAYOUT */ +#endif static const struct flash_parameters * flash_esp32_get_parameters(const struct device *dev) @@ -517,18 +614,37 @@ flash_esp32_get_parameters(const struct device *dev) static int flash_esp32_init(const struct device *dev) { #ifdef CONFIG_MULTITHREADING - struct flash_esp32_dev_data *const dev_data = dev->data; - - k_sem_init(&dev_data->sem, 1, 1); + struct flash_esp32_dev_data *const data = dev->data; + +#ifdef CONFIG_ESP_FLASH_ASYNC + k_sem_init(&data->sem, 0, 1); + k_mutex_init(&data->lock); + k_work_init(&data->work, flash_work_handler); + +#ifdef CONFIG_ESP_FLASH_ASYNC_WORK + k_work_queue_init(&esp_flash_workqueue); + k_work_queue_start(&esp_flash_workqueue, esp_flash_workqueue_stack, + K_THREAD_STACK_SIZEOF(esp_flash_workqueue_stack), + ESP_FLASH_WORKQUEUE_PRIORITY, NULL); + k_work_submit_to_queue(&esp_flash_workqueue, &data->work); +#endif +#else + k_sem_init(&data->sem, 1, 1); +#endif /* CONFIG_ESP_FLASH_ASYNC */ #endif /* CONFIG_MULTITHREADING */ - return 0; } static DEVICE_API(flash, flash_esp32_driver_api) = { +#ifdef CONFIG_ESP_FLASH_ASYNC + .read = flash_esp32_read_async, + .write = flash_esp32_write_async, + .erase = flash_esp32_erase_async, +#else .read = flash_esp32_read, .write = flash_esp32_write, .erase = flash_esp32_erase, +#endif .get_parameters = flash_esp32_get_parameters, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = flash_esp32_page_layout, From 395313d96567883f651e264b115c315463d25a41 Mon Sep 17 00:00:00 2001 From: Lin Yu-Cheng Date: Thu, 7 Aug 2025 13:50:48 +0800 Subject: [PATCH 068/397] driver: espi: implement espi PM function 1. add cs pin as espi driver wake up reference 2. removed the unnecessary update of the cached date 3. removed the unnecessary busy wait in notify funciton Signed-off-by: Lin Yu-Cheng --- drivers/espi/espi_realtek_rts5912.c | 100 +++++++++++++------- dts/arm/realtek/ec/rts5912.dtsi | 2 + dts/bindings/espi/realtek,rts5912-espi.yaml | 9 ++ 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/drivers/espi/espi_realtek_rts5912.c b/drivers/espi/espi_realtek_rts5912.c index 4490bd7bdd408..c0c83dcb964df 100644 --- a/drivers/espi/espi_realtek_rts5912.c +++ b/drivers/espi/espi_realtek_rts5912.c @@ -23,6 +23,14 @@ LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL); #include "reg/reg_kbc.h" #include "reg/reg_port80.h" +#ifdef CONFIG_PM +#include "reg/reg_gpio.h" +#include +#include +#include "reg/reg_system.h" +#include "zephyr/drivers/gpio/gpio_rts5912.h" +#endif + BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "support only one espi compatible node"); struct espi_rts5912_config { @@ -56,6 +64,9 @@ struct espi_rts5912_config { volatile struct port80_reg *const port80_reg; uint32_t port80_clk_grp; uint32_t port80_clk_idx; +#endif +#ifdef CONFIG_PM + struct gpio_dt_spec cs_pin; #endif const struct device *clk_dev; const struct pinctrl_dev_config *pcfg; @@ -1200,7 +1211,6 @@ static void notify_host_warning(const struct device *dev, enum espi_vwire_signal uint8_t status = 0; espi_rts5912_receive_vwire(dev, signal, &status); - k_busy_wait(200); switch (signal) { case ESPI_VWIRE_SIGNAL_SUS_WARN: @@ -1397,8 +1407,6 @@ static int espi_rts5912_send_vwire(const struct device *dev, enum espi_vwire_sig static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_signal signal, uint8_t *level) { - const struct espi_rts5912_config *const espi_config = dev->config; - volatile struct espi_reg *const espi_reg = espi_config->espi_reg; uint8_t vw_idx, lev_msk, valid_msk; uint8_t vw_data; @@ -1415,9 +1423,6 @@ static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_ vw_data = espi_vw_ch_cached_data.idx2; break; case VW_CH_IDX3: - if (espi_vw_ch_cached_data.idx3 != espi_reg->EVIDX3) { - espi_vw_ch_cached_data.idx3 = espi_reg->EVIDX3; - } vw_data = espi_vw_ch_cached_data.idx3; break; case VW_CH_IDX4: @@ -1430,60 +1435,33 @@ static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_ vw_data = espi_vw_tx_cached_data.idx6; break; case VW_CH_IDX7: - if (espi_vw_ch_cached_data.idx7 != espi_reg->EVIDX7) { - espi_vw_ch_cached_data.idx7 = espi_reg->EVIDX7; - } vw_data = espi_vw_ch_cached_data.idx7; break; case VW_CH_IDX40: vw_data = espi_vw_tx_cached_data.idx40; break; case VW_CH_IDX41: - if (espi_vw_ch_cached_data.idx41 != espi_reg->EVIDX41) { - espi_vw_ch_cached_data.idx41 = espi_reg->EVIDX41; - } vw_data = espi_vw_ch_cached_data.idx41; break; case VW_CH_IDX42: - if (espi_vw_ch_cached_data.idx42 != espi_reg->EVIDX42) { - espi_vw_ch_cached_data.idx42 = espi_reg->EVIDX42; - } vw_data = espi_vw_ch_cached_data.idx42; break; case VW_CH_IDX43: - if (espi_vw_ch_cached_data.idx43 != espi_reg->EVIDX43) { - espi_vw_ch_cached_data.idx43 = espi_reg->EVIDX43; - } vw_data = espi_vw_ch_cached_data.idx43; break; case VW_CH_IDX44: - if (espi_vw_ch_cached_data.idx44 != espi_reg->EVIDX44) { - espi_vw_ch_cached_data.idx44 = espi_reg->EVIDX44; - } vw_data = espi_vw_ch_cached_data.idx44; break; case VW_CH_IDX47: - if (espi_vw_ch_cached_data.idx47 != espi_reg->EVIDX47) { - espi_vw_ch_cached_data.idx47 = espi_reg->EVIDX47; - } vw_data = espi_vw_ch_cached_data.idx47; break; case VW_CH_IDX4A: - if (espi_vw_ch_cached_data.idx4a != espi_reg->EVIDX4A) { - espi_vw_ch_cached_data.idx4a = espi_reg->EVIDX4A; - } vw_data = espi_vw_ch_cached_data.idx4a; break; case VW_CH_IDX51: - if (espi_vw_ch_cached_data.idx51 != espi_reg->EVIDX51) { - espi_vw_ch_cached_data.idx51 = espi_reg->EVIDX51; - } vw_data = espi_vw_ch_cached_data.idx51; break; case VW_CH_IDX61: - if (espi_vw_ch_cached_data.idx61 != espi_reg->EVIDX61) { - espi_vw_ch_cached_data.idx61 = espi_reg->EVIDX61; - } vw_data = espi_vw_ch_cached_data.idx61; break; default: @@ -2296,7 +2274,18 @@ static void espi_bus_reset_setup(const struct device *dev) DEVICE_DT_GET(DT_DRV_INST(0)), 0); irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), bus_rst, irq)); } +#ifdef CONFIG_PM +void espi_cs_low_isr(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) +{ + gpio_flags_t cs_pin_config; + gpio_pin_get_config(port, pins, &cs_pin_config); + if (cs_pin_config & GPIO_INT_ENABLE) { + gpio_pin_interrupt_configure(port, (find_msb_set(pins) - 1), + GPIO_INT_MODE_DISABLED); + } +} +#endif static int espi_rts5912_init(const struct device *dev) { const struct espi_rts5912_config *const espi_config = dev->config; @@ -2396,13 +2385,44 @@ static int espi_rts5912_init(const struct device *dev) goto exit; } #endif - +#ifdef CONFIG_PM + static struct gpio_callback cb; + uint32_t cs_irq_nun = gpio_rts5912_get_pin_num(&espi_config->cs_pin); + + NVIC_ClearPendingIRQ(cs_irq_nun); + gpio_init_callback(&cb, espi_cs_low_isr, BIT(espi_config->cs_pin.pin)); + gpio_add_callback(espi_config->cs_pin.port, &cb); + irq_enable(cs_irq_nun); +#endif exit: return rc; } +#ifdef CONFIG_PM +static inline int espi_rts5912_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct espi_rts5912_config *const espi_config = dev->config; + SYSTEM_Type *sys_reg = RTS5912_SCCON_REG_BASE; -PINCTRL_DT_INST_DEFINE(0); + switch (action) { + case PM_DEVICE_ACTION_RESUME: + sys_reg->SLPCTRL &= ~SYSTEM_SLPCTRL_GPIOWKEN_Msk; + gpio_pin_interrupt_configure_dt(&espi_config->cs_pin, GPIO_INT_MODE_DISABLED); + break; + case PM_DEVICE_ACTION_SUSPEND: + sys_reg->SLPCTRL |= SYSTEM_SLPCTRL_GPIOWKEN_Msk; + gpio_pin_interrupt_configure_dt(&espi_config->cs_pin, + GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_LOW); + break; + default: + return -ENOTSUP; + } + return 0; +} +PM_DEVICE_DT_INST_DEFINE(0, espi_rts5912_pm_action); +#endif + +PINCTRL_DT_INST_DEFINE(0); static struct espi_rts5912_data espi_rts5912_data_0; static const struct espi_rts5912_config espi_rts5912_config = { @@ -2437,10 +2457,18 @@ static const struct espi_rts5912_config espi_rts5912_config = { .port80_reg = (volatile struct port80_reg *const)DT_INST_REG_ADDR_BY_NAME(0, port80), .port80_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), port80, clk_grp), .port80_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), port80, clk_idx), +#endif +#ifdef CONFIG_PM + .cs_pin = GPIO_DT_SPEC_INST_GET(0, cs_gpios), #endif .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; - +#ifdef CONFIG_PM +DEVICE_DT_INST_DEFINE(0, &espi_rts5912_init, PM_DEVICE_DT_INST_GET(0), &espi_rts5912_data_0, + &espi_rts5912_config, PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, + &espi_rts5912_driver_api); +#else DEVICE_DT_INST_DEFINE(0, &espi_rts5912_init, NULL, &espi_rts5912_data_0, &espi_rts5912_config, PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, &espi_rts5912_driver_api); +#endif diff --git a/dts/arm/realtek/ec/rts5912.dtsi b/dts/arm/realtek/ec/rts5912.dtsi index 13daf81625df3..f1a517d79ff97 100644 --- a/dts/arm/realtek/ec/rts5912.dtsi +++ b/dts/arm/realtek/ec/rts5912.dtsi @@ -13,6 +13,7 @@ #include #include #include +#include / { cpus { @@ -167,6 +168,7 @@ espi0: espi0@400b1000 { compatible = "realtek,rts5912-espi"; + cs-gpios = ; status = "disabled"; reg = <0x400b1000 0x200 /* espi target */ diff --git a/dts/bindings/espi/realtek,rts5912-espi.yaml b/dts/bindings/espi/realtek,rts5912-espi.yaml index 18198cdfbc868..76044596710a8 100644 --- a/dts/bindings/espi/realtek,rts5912-espi.yaml +++ b/dts/bindings/espi/realtek,rts5912-espi.yaml @@ -17,3 +17,12 @@ properties: pinctrl-names: required: true + + cs-gpios: + description: | + select the cs pin to support the espi wakeup + and it is required when CONFIG_PM is enabled. + please check include/zephyr/dt-bindings/gpio/realtek-gpio.h + For example: + cs-gpios = ; + type: phandle-array From 027614812a8c04043953498b5e518785a96ec24a Mon Sep 17 00:00:00 2001 From: Scott Worley Date: Fri, 25 Jul 2025 16:39:49 -0400 Subject: [PATCH 069/397] soc: microchip: mec: Add common ECIA GIRQ and MMCR routines We added ECIA GIRQ get/set/clear functions avaiable for all MEC parts. Drivers can make use of these functions to get, set, and clear GIRQ status and enables for their peripheral. In cases where code requires 8/16 bit access to these or other SoC registers we added inline helpers modeled after Zephyr's 32-bit sys_read/write/test routines. This commit is part of a long term goal to share drivers among all the MEC parts. Signed-off-by: Scott Worley --- soc/microchip/mec/common/CMakeLists.txt | 1 + soc/microchip/mec/common/soc_cmn_init.c | 3 +- soc/microchip/mec/common/soc_ecia.c | 221 ++++++++++++++++++++++++ soc/microchip/mec/common/soc_ecia.h | 76 ++++++++ soc/microchip/mec/common/soc_mmcr.h | 130 ++++++++++++++ soc/microchip/mec/mec15xx/soc.c | 42 +---- soc/microchip/mec/mec15xx/soc.h | 22 +-- soc/microchip/mec/mec172x/soc.c | 2 +- soc/microchip/mec/mec172x/soc.h | 51 +++--- soc/microchip/mec/mec174x/soc.h | 19 +- soc/microchip/mec/mec175x/soc.h | 19 +- soc/microchip/mec/mech172x/soc.h | 19 +- 12 files changed, 501 insertions(+), 104 deletions(-) create mode 100644 soc/microchip/mec/common/soc_ecia.c create mode 100644 soc/microchip/mec/common/soc_ecia.h create mode 100644 soc/microchip/mec/common/soc_mmcr.h diff --git a/soc/microchip/mec/common/CMakeLists.txt b/soc/microchip/mec/common/CMakeLists.txt index 0669a09cbe295..3cc731329d1ff 100644 --- a/soc/microchip/mec/common/CMakeLists.txt +++ b/soc/microchip/mec/common/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(.) +zephyr_library_sources(soc_ecia.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_MEC172X soc_i2c.c ) diff --git a/soc/microchip/mec/common/soc_cmn_init.c b/soc/microchip/mec/common/soc_cmn_init.c index bff1bf22a2a35..ffb55dd9567a4 100644 --- a/soc/microchip/mec/common/soc_cmn_init.c +++ b/soc/microchip/mec/common/soc_cmn_init.c @@ -8,7 +8,6 @@ #include #include #include -#include #include static void mec5_soc_init_debug_interface(void) @@ -35,7 +34,7 @@ static void mec5_soc_init_debug_interface(void) int mec5_soc_common_init(void) { mec5_soc_init_debug_interface(); - mec_hal_ecia_init(MEC5_ECIA_DIRECT_BITMAP, 1, 0); + soc_ecia_init(MCHP_MEC_ECIA_GIRQ_AGGR_ONLY_BM, MCHP_MEC_ECIA_GIRQ_DIRECT_CAP_BM, 0); return 0; } diff --git a/soc/microchip/mec/common/soc_ecia.c b/soc/microchip/mec/common/soc_ecia.c new file mode 100644 index 0000000000000..e7b00e2d3c0ff --- /dev/null +++ b/soc/microchip/mec/common/soc_ecia.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "soc_ecia.h" + +/* EC Subsystem */ +#define MCHP_XEC_ECS_REG_BASE (mem_addr_t) DT_REG_ADDR(DT_NODELABEL(ecs)) +#define MCHP_XEC_ECS_ICR_OFS 0x18u +#define MCHP_XEC_ECS_ICR_DM_EN_POS 0 /* direct mode enable */ + +/* EC Interrupt Aggregator. It is not real interrupt controller. */ +#define MCHP_XEC_ECIA_REG_BASE (mem_addr_t) DT_REG_ADDR(DT_NODELABEL(ecia)) +#define MCHP_XEC_ECIA_GIRQ_SIZE 20u /* 5 32-bit registers */ +#define MCHP_XEC_ECIA_GIRQ_ALL_MSK GENMASK(MCHP_MEC_ECIA_GIRQ_LAST, MCHP_MEC_ECIA_GIRQ_FIRST) +#define MCHP_XEC_ECIA_GIRQ_DIRECT_MSK (GENMASK(21, 13) | BIT(23)) +#define MCHP_XEC_ECIA_GIRQ_AGGR_MSK (GENMASK(12, 8) | BIT(22) | GENMASK(26, 24)) + +#define MCHP_XEC_ECIA_ZGIRQ_OFS(zgirq) ((uint32_t)(zgirq) * MCHP_XEC_ECIA_GIRQ_SIZE) +#define MCHP_XEC_ECIA_GIRQ_OFS(girq) \ + MCHP_XEC_ECIA_ZGIRQ_OFS((uint32_t)(girq) - MCHP_MEC_ECIA_GIRQ_FIRST) + +#define MCHP_XEC_ECIA_GIRQ_SRC_OFS 0 +#define MCHP_XEC_ECIA_GIRQ_ENSET_OFS 4u +#define MCHP_XEC_ECIA_GIRQ_RESULT_OFS 8u +#define MCHP_XEC_ECIA_GIRQ_ENCLR_OFS 12u +/* offset 16 (0x10) is reserved read-only 0 */ + +/* aggregated enable set/clear registers */ +#define MCHP_XEC_ECIA_AGGR_ENSET_OFS 0x200u /* r/w1s */ +#define MCHP_XEC_ECIA_AGGR_ENCLR_OFS 0x204u /* r/w1c */ +#define MCHP_XEC_ECIA_AGGR_ACTV_OFS 0x208u /* read-only */ + +#define MCHP_XEC_ECIA_GIRQ_REG_OFS(girq, regofs) \ + (MCHP_XEC_ECIA_ZGIRQ_OFS((uint32_t)(girq) - MCHP_MEC_ECIA_GIRQ_FIRST) + (uint32_t)regofs) + +#define MCHP_XEC_ECIA_GIRQ_SRC_REG_OFS(girq) \ + MCHP_XEC_ECIA_GIRQ_REG_OFS(girq, MCHP_XEC_ECIA_GIRQ_SRC_OFS) + +#define MCHP_XEC_ECIA_GIRQ_ENSET_REG_OFS(girq) \ + MCHP_XEC_ECIA_GIRQ_REG_OFS(girq, MCHP_XEC_ECIA_GIRQ_ENSET_OFS) + +#define MCHP_XEC_ECIA_GIRQ_RESULT_REG_OFS(girq) \ + MCHP_XEC_ECIA_GIRQ_REG_OFS(girq, MCHP_XEC_ECIA_GIRQ_RESULT_OFS) + +#define MCHP_XEC_ECIA_GIRQ_ENCLR_REG_OFS(girq) \ + MCHP_XEC_ECIA_GIRQ_REG_OFS(girq, MCHP_XEC_ECIA_GIRQ_ENCLR_OFS) + +int soc_ecia_init(uint32_t aggr_girq_bm, uint32_t direct_girq_bm, uint32_t flags) +{ + mem_addr_t ecia_base = MCHP_XEC_ECIA_REG_BASE; + mem_addr_t ecs_base = MCHP_XEC_ECS_REG_BASE; + uint32_t amsk = 0, dmsk = 0, bm = 0, girq = 0, raddr = 0; + + amsk = aggr_girq_bm & MCHP_XEC_ECIA_GIRQ_AGGR_MSK; + dmsk = direct_girq_bm & MCHP_XEC_ECIA_GIRQ_DIRECT_MSK; + + bm = aggr_girq_bm | direct_girq_bm; + while (bm != 0) { + girq = find_lsb_set(bm) - 1u; + + raddr = ecia_base + MCHP_XEC_ECIA_GIRQ_OFS(girq); + + if ((flags & MCHP_MEC_ECIA_INIT_CLR_ENABLES) != 0) { /* clear enables? */ + sys_write32(UINT32_MAX, raddr + MCHP_XEC_ECIA_GIRQ_ENCLR_OFS); + } + + if ((flags & MCHP_MEC_ECIA_INIT_CLR_STATUS) != 0) { /* clear status */ + sys_write32(UINT32_MAX, raddr + MCHP_XEC_ECIA_GIRQ_SRC_OFS); + } + + bm &= (uint32_t)~BIT(girq); + } + + sys_write32(UINT32_MAX, ecia_base + MCHP_XEC_ECIA_AGGR_ENCLR_OFS); + sys_write32(amsk, ecia_base + MCHP_XEC_ECIA_AGGR_ENSET_OFS); + + if (dmsk != 0) { + sys_set_bit(ecs_base + MCHP_XEC_ECS_ICR_OFS, MCHP_XEC_ECS_ICR_DM_EN_POS); + } else { + sys_clear_bit(ecs_base + MCHP_XEC_ECS_ICR_OFS, MCHP_XEC_ECS_ICR_DM_EN_POS); + } + + return 0; +} + +int soc_ecia_girq_ctrl_bm(uint8_t girq, uint32_t bitmap, uint8_t enable) +{ + mem_addr_t raddr = MCHP_XEC_ECIA_REG_BASE; + + if ((girq < MCHP_MEC_ECIA_GIRQ_FIRST) || (girq > MCHP_MEC_ECIA_GIRQ_LAST)) { + return -EINVAL; + } + + raddr += MCHP_XEC_ECIA_GIRQ_OFS(girq); + + if (enable != 0) { + raddr += MCHP_XEC_ECIA_GIRQ_ENSET_OFS; + } else { + raddr += MCHP_XEC_ECIA_GIRQ_ENCLR_OFS; + } + + sys_write32(bitmap, raddr); + + return 0; +} + +int soc_ecia_girq_ctrl(uint8_t girq, uint8_t srcpos, uint8_t enable) +{ + uint32_t bitmap = BIT(srcpos); + + return soc_ecia_girq_ctrl_bm(girq, bitmap, enable); +} + +uint32_t soc_ecia_girq_get_enable_bm(uint8_t girq) +{ + mem_addr_t raddr = MCHP_XEC_ECIA_REG_BASE; + + if ((girq < MCHP_MEC_ECIA_GIRQ_FIRST) || (girq > MCHP_MEC_ECIA_GIRQ_LAST)) { + return 0; + } + + raddr += MCHP_XEC_ECIA_GIRQ_ENSET_REG_OFS(girq); + + return sys_read32(raddr); +} + +int soc_ecia_girq_status_clear_bm(uint8_t girq, uint32_t bitmap) +{ + mem_addr_t raddr = MCHP_XEC_ECIA_REG_BASE; + + if ((girq < MCHP_MEC_ECIA_GIRQ_FIRST) || (girq > MCHP_MEC_ECIA_GIRQ_LAST)) { + return -EINVAL; + } + + raddr += MCHP_XEC_ECIA_GIRQ_SRC_REG_OFS(girq); + + sys_write32(bitmap, raddr); + + return 0; +} + +int soc_ecia_girq_status_clear(uint8_t girq, uint8_t srcpos) +{ + uint32_t bitmap = BIT(srcpos); + + return soc_ecia_girq_status_clear_bm(girq, bitmap); +} + +int soc_ecia_girq_status(uint8_t girq, uint32_t *status) +{ + mem_addr_t raddr = MCHP_XEC_ECIA_REG_BASE; + + if ((girq < MCHP_MEC_ECIA_GIRQ_FIRST) || (girq > MCHP_MEC_ECIA_GIRQ_LAST)) { + return -EINVAL; + } + + raddr += MCHP_XEC_ECIA_GIRQ_SRC_REG_OFS(girq); + + if (status != NULL) { + *status = sys_read32(raddr); + } + + return 0; +} + +int soc_ecia_girq_result(uint8_t girq, uint32_t *result) +{ + mem_addr_t raddr = MCHP_XEC_ECIA_REG_BASE; + + if ((girq < MCHP_MEC_ECIA_GIRQ_FIRST) || (girq > MCHP_MEC_ECIA_GIRQ_LAST)) { + return -EINVAL; + } + + raddr += MCHP_XEC_ECIA_GIRQ_RESULT_REG_OFS(girq); + + if (result != NULL) { + *result = sys_read32(raddr); + } + + return 0; +} + +int soc_ecia_girq_is_result(uint8_t girq, uint32_t bitmap) +{ + uint32_t result = 0; + + if (soc_ecia_girq_result(girq, &result) != 0) { + return 0; + } + + return (result & bitmap); +} + +int soc_ecia_girq_aggr_ctrl_bm(uint32_t girq_bitmap, uint8_t enable) +{ + mem_addr_t raddr = MCHP_XEC_ECIA_REG_BASE; + + if (enable != 0) { + raddr += MCHP_XEC_ECIA_AGGR_ENSET_OFS; + } else { + raddr += MCHP_XEC_ECIA_AGGR_ENCLR_OFS; + } + + sys_write32(girq_bitmap, raddr); + + return 0; +} + +int soc_ecia_girq_aggr_ctrl(uint8_t girq, uint8_t enable) +{ + uint32_t girq_bitmap = BIT(girq); + + return soc_ecia_girq_aggr_ctrl_bm(girq_bitmap, enable); +} diff --git a/soc/microchip/mec/common/soc_ecia.h b/soc/microchip/mec/common/soc_ecia.h new file mode 100644 index 0000000000000..c137033c4e39b --- /dev/null +++ b/soc/microchip/mec/common/soc_ecia.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Microchip XEC MCU family EC Interrupt Aggregator support. + * + */ + +#ifndef _MICROCHIP_MEC_SOC_ECIA_H_ +#define _MICROCHIP_MEC_SOC_ECIA_H_ + +#include +#include +#include + +/* zero based GIRQ numbering. 19 total GIRQ units in the aggregator */ +#define MCHP_MEC_ECIA_ZGIRQ_MAX 19 + +/* Historically, GIRQ's have been numbered starting with 8 */ +#define MCHP_MEC_ECIA_GIRQ_FIRST 8 +#define MCHP_MEC_ECIA_GIRQ_LAST 26 + +/* MEC ECIA GIRQ's are numbered 8 - 26 for historical reasons. + * GIRQ's 8 - 12, 22, 24 - 26 interrupt sources are only connected to the GIRQ source bits. + * GIRQ's 13 - 21, and 23 result bits can be connected to the NVIC. + */ +#define MCHP_MEC_ECIA_GIRQ_ALL_BM GENMASK(26, 8) +#define MCHP_MEC_ECIA_GIRQ_AGGR_ONLY_BM (GENMASK(12, 8) | BIT(22) | GENMASK(26, 24)) +#define MCHP_MEC_ECIA_GIRQ_DIRECT_CAP_BM (GENMASK(21, 13) | BIT(23)) + +enum mchp_mec_ecia_girq { + MCHP_MEC_ECIA_GIRQ8 = MCHP_MEC_ECIA_GIRQ_FIRST, + MCHP_MEC_ECIA_GIRQ9, + MCHP_MEC_ECIA_GIRQ10, + MCHP_MEC_ECIA_GIRQ11, + MCHP_MEC_ECIA_GIRQ12, + MCHP_MEC_ECIA_GIRQ13, + MCHP_MEC_ECIA_GIRQ14, + MCHP_MEC_ECIA_GIRQ15, + MCHP_MEC_ECIA_GIRQ16, + MCHP_MEC_ECIA_GIRQ17, + MCHP_MEC_ECIA_GIRQ18, + MCHP_MEC_ECIA_GIRQ19, + MCHP_MEC_ECIA_GIRQ20, + MCHP_MEC_ECIA_GIRQ21, + MCHP_MEC_ECIA_GIRQ22, + MCHP_MEC_ECIA_GIRQ23, + MCHP_MEC_ECIA_GIRQ24, + MCHP_MEC_ECIA_GIRQ25, + MCHP_MEC_ECIA_GIRQ26, + MCHP_MEC_ECIA_GIRQ_MAX, +}; + +#define MCHP_MEC_ECIA_INIT_CLR_ENABLES 0x01u +#define MCHP_MEC_ECIA_INIT_CLR_STATUS 0x02u + +int soc_ecia_init(uint32_t aggr_girq_bm, uint32_t direct_girq_bm, uint32_t flags); + +int soc_ecia_girq_ctrl_bm(uint8_t girq, uint32_t bitmap, uint8_t enable); +int soc_ecia_girq_ctrl(uint8_t girq, uint8_t srcpos, uint8_t enable); + +uint32_t soc_ecia_girq_get_enable_bm(uint8_t girq); + +int soc_ecia_girq_status_clear_bm(uint8_t girq, uint32_t bitmap); +int soc_ecia_girq_status_clear(uint8_t girq, uint8_t srcpos); + +int soc_ecia_girq_status(uint8_t girq, uint32_t *status); +int soc_ecia_girq_result(uint8_t girq, uint32_t *result); +int soc_ecia_girq_is_result(uint8_t girq, uint32_t bitmap); + +int soc_ecia_girq_aggr_ctrl_bm(uint32_t girq_bitmap, uint8_t enable); +int soc_ecia_girq_aggr_ctrl(uint8_t girq, uint8_t enable); + +#endif /* _MICROCHIP_MEC_SOC_ECIA_H_ */ diff --git a/soc/microchip/mec/common/soc_mmcr.h b/soc/microchip/mec/common/soc_mmcr.h new file mode 100644 index 0000000000000..8b0c07cbb65fb --- /dev/null +++ b/soc/microchip/mec/common/soc_mmcr.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Microchip MEC MCU family memory mapped control register access + * + */ + +#ifndef _SOC_MICROCHIP_MEC_COMMON_MMCR_H_ +#define _SOC_MICROCHIP_MEC_COMMON_MMCR_H_ + +#include /* mem_addr_t definition */ + +/* Zephyr only provides 32-bit version of these routines. We need these for memory + * mapped control registers located on 16 and 8 bit address boundaries. + */ + +static ALWAYS_INLINE void soc_set_bit8(mem_addr_t addr, unsigned int bit) +{ + uint8_t temp = *(volatile uint8_t *)addr; + + *(volatile uint8_t *)addr = temp | (1U << bit); +} + +static ALWAYS_INLINE void soc_clear_bit8(mem_addr_t addr, unsigned int bit) +{ + uint8_t temp = *(volatile uint8_t *)addr; + + *(volatile uint8_t *)addr = temp & ~(1U << bit); +} + +static ALWAYS_INLINE int soc_test_bit8(mem_addr_t addr, unsigned int bit) +{ + uint8_t temp = *(volatile uint8_t *)addr; + + return temp & (1U << bit); +} + +static ALWAYS_INLINE void soc_set_bits8(mem_addr_t addr, unsigned int mask) +{ + uint8_t temp = *(volatile uint8_t *)addr; + + *(volatile uint8_t *)addr = temp | mask; +} + +static ALWAYS_INLINE void soc_clear_bits8(mem_addr_t addr, unsigned int mask) +{ + uint8_t temp = *(volatile uint8_t *)addr; + + *(volatile uint8_t *)addr = temp & ~mask; +} + +static ALWAYS_INLINE int soc_test_and_set_bit8(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = soc_test_bit8(addr, bit); + soc_set_bit8(addr, bit); + + return ret; +} + +static ALWAYS_INLINE int soc_test_and_clear_bit8(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = soc_test_bit8(addr, bit); + soc_clear_bit8(addr, bit); + + return ret; +} + +static ALWAYS_INLINE void soc_set_bit16(mem_addr_t addr, unsigned int bit) +{ + uint16_t temp = *(volatile uint16_t *)addr; + + *(volatile uint16_t *)addr = temp | (1U << bit); +} + +static ALWAYS_INLINE void soc_clear_bit16(mem_addr_t addr, unsigned int bit) +{ + uint16_t temp = *(volatile uint16_t *)addr; + + *(volatile uint16_t *)addr = temp & ~(1U << bit); +} + +static ALWAYS_INLINE int soc_test_bit16(mem_addr_t addr, unsigned int bit) +{ + uint16_t temp = *(volatile uint16_t *)addr; + + return temp & (1U << bit); +} + +static ALWAYS_INLINE void soc_set_bits16(mem_addr_t addr, unsigned int mask) +{ + uint16_t temp = *(volatile uint16_t *)addr; + + *(volatile uint16_t *)addr = temp | mask; +} + +static ALWAYS_INLINE void soc_clear_bits16(mem_addr_t addr, unsigned int mask) +{ + uint16_t temp = *(volatile uint16_t *)addr; + + *(volatile uint16_t *)addr = temp & ~mask; +} + +static ALWAYS_INLINE int soc_test_and_set_bit16(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = soc_test_bit16(addr, bit); + soc_set_bit16(addr, bit); + + return ret; +} + +static ALWAYS_INLINE int soc_test_and_clear_bit16(mem_addr_t addr, unsigned int bit) +{ + int ret; + + ret = soc_test_bit16(addr, bit); + soc_clear_bit16(addr, bit); + + return ret; +} + +#endif /* SOC_MICROCHIP_MEC_COMMON_MMCR_H_ */ diff --git a/soc/microchip/mec/mec15xx/soc.c b/soc/microchip/mec/mec15xx/soc.c index df21dde363ed2..5c312f73e9abb 100644 --- a/soc/microchip/mec/mec15xx/soc.c +++ b/soc/microchip/mec/mec15xx/soc.c @@ -12,41 +12,6 @@ #include #include -/* - * Initialize MEC1501 EC Interrupt Aggregator (ECIA) and external NVIC - * inputs. - */ -static int soc_ecia_init(void) -{ - GIRQ_Type *pg; - uint32_t n; - - mchp_pcr_periph_slp_ctrl(PCR_ECIA, MCHP_PCR_SLEEP_DIS); - - ECS_REGS->INTR_CTRL |= MCHP_ECS_ICTRL_DIRECT_EN; - - /* gate off all aggregated outputs */ - ECIA_REGS->BLK_EN_CLR = 0xFFFFFFFFul; - /* gate on GIRQ's that are aggregated only */ - ECIA_REGS->BLK_EN_SET = MCHP_ECIA_AGGR_BITMAP; - - /* Clear all GIRQn source enables and source status */ - pg = &ECIA_REGS->GIRQ08; - for (n = MCHP_FIRST_GIRQ; n <= MCHP_LAST_GIRQ; n++) { - pg->EN_CLR = 0xFFFFFFFFul; - pg->SRC = 0xFFFFFFFFul; - pg++; - } - - /* Clear all external NVIC enables and pending status */ - for (n = 0u; n < MCHP_NUM_NVIC_REGS; n++) { - NVIC->ICER[n] = 0xFFFFFFFFul; - NVIC->ICPR[n] = 0xFFFFFFFFul; - } - - return 0; -} - static void configure_debug_interface(void) { /* No debug support */ @@ -75,11 +40,12 @@ void soc_early_init_hook(void) { uint32_t isave; - isave = __get_PRIMASK(); __disable_irq(); - soc_ecia_init(); + configure_debug_interface(); + + soc_ecia_init(MCHP_MEC_ECIA_GIRQ_AGGR_ONLY_BM, MCHP_MEC_ECIA_GIRQ_DIRECT_CAP_BM, 0); /* Configure GPIO bank before usage * VTR1 is not configurable @@ -89,8 +55,6 @@ void soc_early_init_hook(void) ECS_REGS->GPIO_BANK_PWR |= MCHP_ECS_VTR3_LVL_18; #endif - configure_debug_interface(); - if (!isave) { __enable_irq(); } diff --git a/soc/microchip/mec/mec15xx/soc.h b/soc/microchip/mec/mec15xx/soc.h index f13a5d5291653..21a349620edd8 100644 --- a/soc/microchip/mec/mec15xx/soc.h +++ b/soc/microchip/mec/mec15xx/soc.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __MEC_SOC_H -#define __MEC_SOC_H +#ifndef __SOC_MICROCHIP_MEC_MEC15XX_SOC_H +#define __SOC_MICROCHIP_MEC_MEC15XX_SOC_H #define SYSCLK_DEFAULT_IOSC_HZ MHZ(48) @@ -15,16 +15,18 @@ #include "regaccess.h" /* common SoC API */ -#include "../common/soc_dt.h" -#include "../common/soc_gpio.h" -#include "../common/soc_pcr.h" -#include "../common/soc_pins.h" -#include "../common/soc_espi_channels.h" -#include "soc_espi_saf_v1.h" +#include +#include +#include +#include +#include +#include +#include /* common peripheral register defines */ -#include "../common/reg/mec_gpio.h" +#include -#endif +#include "soc_espi_saf_v1.h" #endif +#endif diff --git a/soc/microchip/mec/mec172x/soc.c b/soc/microchip/mec/mec172x/soc.c index 6b000f957b0c8..7960025622f83 100644 --- a/soc/microchip/mec/mec172x/soc.c +++ b/soc/microchip/mec/mec172x/soc.c @@ -40,6 +40,6 @@ static void configure_debug_interface(void) void soc_early_init_hook(void) { - configure_debug_interface(); + soc_ecia_init(MCHP_MEC_ECIA_GIRQ_AGGR_ONLY_BM, MCHP_MEC_ECIA_GIRQ_DIRECT_CAP_BM, 0); } diff --git a/soc/microchip/mec/mec172x/soc.h b/soc/microchip/mec/mec172x/soc.h index 19afc4e920a96..a48ef2bda52b0 100644 --- a/soc/microchip/mec/mec172x/soc.h +++ b/soc/microchip/mec/mec172x/soc.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __MEC_SOC_H -#define __MEC_SOC_H +#ifndef __SOC_MICROCHIP_MEC_MEC172X_SOC_H +#define __SOC_MICROCHIP_MEC_MEC172X_SOC_H #ifndef _ASMLANGUAGE @@ -246,7 +246,7 @@ typedef enum { #include -/* chip specific register defines */ +/* local chip specific register defines */ #include "reg/mec172x_defs.h" #include "reg/mec172x_ecia.h" #include "reg/mec172x_ecs.h" @@ -262,33 +262,34 @@ typedef enum { #include "reg/mec172x_emi.h" /* common peripheral register defines */ -#include "../common/reg/mec_acpi_ec.h" -#include "../common/reg/mec_adc.h" -#include "../common/reg/mec_global_cfg.h" -#include "../common/reg/mec_kbc.h" -#include "../common/reg/mec_keyscan.h" -#include "../common/reg/mec_peci.h" -#include "../common/reg/mec_ps2.h" -#include "../common/reg/mec_pwm.h" -#include "../common/reg/mec_tach.h" -#include "../common/reg/mec_tfdp.h" -#include "../common/reg/mec_timers.h" -#include "../common/reg/mec_uart.h" -#include "../common/reg/mec_vci.h" -#include "../common/reg/mec_wdt.h" -#include "../common/reg/mec_gpio.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* common SoC API */ -#include "../common/soc_dt.h" -#include "../common/soc_gpio.h" -#include "../common/soc_pcr.h" -#include "../common/soc_pins.h" -#include "../common/soc_espi_channels.h" -#include "../common/soc_i2c.h" +#include +#include +#include +#include +#include +#include +#include +#include /* MEC172x SAF V2 */ #include "soc_espi_saf_v2.h" #endif - #endif diff --git a/soc/microchip/mec/mec174x/soc.h b/soc/microchip/mec/mec174x/soc.h index b0a2a46eef83a..2d24e6ed263a6 100644 --- a/soc/microchip/mec/mec174x/soc.h +++ b/soc/microchip/mec/mec174x/soc.h @@ -4,22 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __MEC5_SOC_H -#define __MEC5_SOC_H +#ifndef __SOC_MICROCHIP_MEC_MEC174X_SOC_H +#define __SOC_MICROCHIP_MEC_MEC174X_SOC_H #define SYSCLK_DEFAULT_IOSC_HZ MHZ(96) #ifndef _ASMLANGUAGE -#include "device_mec5.h" +#include /* common SoC API */ -#include "soc_dt.h" -#include "soc_espi_channels.h" -#include "soc_gpio.h" -#include "soc_pcr.h" -#include "soc_pins.h" +#include +#include +#include +#include +#include +#include +#include #endif - #endif diff --git a/soc/microchip/mec/mec175x/soc.h b/soc/microchip/mec/mec175x/soc.h index b0a2a46eef83a..9b03fc925e6e0 100644 --- a/soc/microchip/mec/mec175x/soc.h +++ b/soc/microchip/mec/mec175x/soc.h @@ -4,22 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __MEC5_SOC_H -#define __MEC5_SOC_H +#ifndef __SOC_MICROCHIP_MEC_MEC175X_SOC_H +#define __SOC_MICROCHIP_MEC_MEC175X_SOC_H #define SYSCLK_DEFAULT_IOSC_HZ MHZ(96) #ifndef _ASMLANGUAGE -#include "device_mec5.h" +#include /* common SoC API */ -#include "soc_dt.h" -#include "soc_espi_channels.h" -#include "soc_gpio.h" -#include "soc_pcr.h" -#include "soc_pins.h" +#include +#include +#include +#include +#include +#include +#include #endif - #endif diff --git a/soc/microchip/mec/mech172x/soc.h b/soc/microchip/mec/mech172x/soc.h index b0a2a46eef83a..9c482be784a7a 100644 --- a/soc/microchip/mec/mech172x/soc.h +++ b/soc/microchip/mec/mech172x/soc.h @@ -4,22 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __MEC5_SOC_H -#define __MEC5_SOC_H +#ifndef __SOC_MICROCHIP_MEC_MECH172X_SOC_H +#define __SOC_MICROCHIP_MEC_MECH172X_SOC_H #define SYSCLK_DEFAULT_IOSC_HZ MHZ(96) #ifndef _ASMLANGUAGE -#include "device_mec5.h" +#include /* common SoC API */ -#include "soc_dt.h" -#include "soc_espi_channels.h" -#include "soc_gpio.h" -#include "soc_pcr.h" -#include "soc_pins.h" +#include +#include +#include +#include +#include +#include +#include #endif - #endif From 8b13cc2c73f1010f2b2489ae18967c24a4fd7636 Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Fri, 18 Jul 2025 07:56:21 +0200 Subject: [PATCH 070/397] net: pkt_filter: Filters to modify priority to incoming packets To enable quality-of-service (QoS) applications, allow filters to modify the priority of an incoming packet. This allows that processing can be done on tc-queue-threads with different priorities. Signed-off-by: Cla Mattia Galliard --- include/zephyr/net/net_pkt_filter.h | 17 +++++++++++++---- subsys/net/pkt_filter/base.c | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/net_pkt_filter.h b/include/zephyr/net/net_pkt_filter.h index 1ee42e51b70ef..44c43c3d52bdd 100644 --- a/include/zephyr/net/net_pkt_filter.h +++ b/include/zephyr/net/net_pkt_filter.h @@ -85,10 +85,11 @@ struct npf_test { /** @brief filter rule structure */ struct npf_rule { - sys_snode_t node; /**< Slist rule list node */ - enum net_verdict result; /**< result if all tests pass */ - uint32_t nb_tests; /**< number of tests for this rule */ - struct npf_test *tests[]; /**< pointers to @ref npf_test instances */ + sys_snode_t node; /**< Slist rule list node */ + enum net_verdict result; /**< result if all tests pass */ + enum net_priority priority; /**< priority in case of NET_CONTINUE */ + uint32_t nb_tests; /**< number of tests for this rule */ + struct npf_test *tests[]; /**< pointers to @ref npf_test instances */ }; /** @brief Default rule list termination for accepting a packet */ @@ -242,6 +243,14 @@ bool npf_remove_all_rules(struct npf_rule_list *rules); .tests = { FOR_EACH(Z_NPF_TEST_ADDR, (,), __VA_ARGS__) }, \ } +#define NPF_PRIORITY(_name, _priority, ...) \ + struct npf_rule _name = { \ + .result = NET_CONTINUE, \ + .priority = (_priority), \ + .nb_tests = NUM_VA_ARGS_LESS_1(__VA_ARGS__) + 1, \ + .tests = {FOR_EACH(Z_NPF_TEST_ADDR, (,), __VA_ARGS__)}, \ + } + #define Z_NPF_TEST_ADDR(arg) &arg.test /** @} */ diff --git a/subsys/net/pkt_filter/base.c b/subsys/net/pkt_filter/base.c index 289a55e9d604e..6785cb215d4c6 100644 --- a/subsys/net/pkt_filter/base.c +++ b/subsys/net/pkt_filter/base.c @@ -114,6 +114,10 @@ static enum net_verdict evaluate(sys_slist_t *rule_head, struct net_pkt *pkt) SYS_SLIST_FOR_EACH_CONTAINER(rule_head, rule, node) { if (apply_tests(rule, pkt) == true) { + if (rule->result == NET_CONTINUE) { + net_pkt_set_priority(pkt, rule->priority); + continue; + } return rule->result; } } From a6c220613a9b70cde5362033bf52ac66dc7137fb Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Fri, 17 Oct 2025 19:15:19 +0200 Subject: [PATCH 071/397] doc: net_pkt_filter: Document priority rules Add documentation for newly added priority rules. Signed-off-by: Cla Mattia Galliard --- .../networking/api/net_pkt_filter.rst | 51 +++++++++++++++++-- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/doc/connectivity/networking/api/net_pkt_filter.rst b/doc/connectivity/networking/api/net_pkt_filter.rst index 3a859b140ed84..5fd954e170a07 100644 --- a/doc/connectivity/networking/api/net_pkt_filter.rst +++ b/doc/connectivity/networking/api/net_pkt_filter.rst @@ -12,8 +12,9 @@ Overview The Network Packet Filtering facility provides the infrastructure to construct custom rules for accepting and/or denying packet transmission -and reception. This can be used to create a basic firewall, control -network traffic, etc. +and reception. It also allows to modify the priority of incoming +network packets. This can be used to create a basic firewall, control network +traffic, etc. The :kconfig:option:`CONFIG_NET_PKT_FILTER` must be set in order to enable the relevant APIs. @@ -25,8 +26,13 @@ for a given rule are true then the packet outcome is immediately determined as specified by the current rule and no more rules are considered. If one condition is false then the next rule in the list is considered. -Packet outcome is either ``NET_OK`` to accept the packet or ``NET_DROP`` to -drop it. +Packet outcome is either ``NET_OK`` to accept the packet, ``NET_DROP`` to +drop it or ``NET_CONTINUE`` to modify its priority on the fly. + +When the outcome is ``NET_CONTINUE`` the priority is updated but the final +outcome is not yet determined and processing continues. If all conditions of +multiple rules are true, then the packet gets the priority of the rule last +considered. A rule is represented by a :c:struct:`npf_rule` object. It can be inserted to, appended to or removed from a rule list contained in a @@ -47,7 +53,8 @@ retrieve the outer structure from the provided ``npf_test`` structure pointer. Convenience macros are provided in :zephyr_file:`include/zephyr/net/net_pkt_filter.h` to statically define condition instances for various conditions, and -:c:macro:`NPF_RULE()` to create a rule instance to tie them. +:c:macro:`NPF_RULE()` and :c:macro:`NPF_PRIORITY()` to create a rule instance +with an immediate outcome or a priority change. Examples ******** @@ -86,6 +93,40 @@ Another (less efficient) way to achieve the same result could be: npf_append_recv_rule(&npf_default_ok); } +This example assigns priorities to different network traffic. It gives network +control priority (``NET_PRIORITY_NC``) to the ``ptp`` packets, critical +applications priority (``NET_PRIORITY_CA``) to the internet traffic of version +6, excellent effort (``NET_PRIORITY_EE``) for internet protocol version 4 +traffic, and the lowest background priority (``NET_PRIORITY_BK``) to ``lldp`` +and ``arp``. + +Priority rules are only really usefull if multiple traffic class queues are +enabled in the project configuration :kconfig:option:`CONFIG_NET_TC_RX_COUNT`. +The mapping from the priority of the packet to the traffic class queue is in +accordance with the standard 802.1Q and depends on the +:kconfig:option:`CONFIG_NET_TC_RX_COUNT`. + +.. code-block:: c + + static NPF_ETH_TYPE_MATCH(is_arp, NET_ETH_PTYPE_ARP); + static NPF_ETH_TYPE_MATCH(is_lldp, NET_ETH_PTYPE_LLDP); + static NPF_ETH_TYPE_MATCH(is_ptp, NET_ETH_PTYPE_PTP); + static NPF_ETH_TYPE_MATCH(is_ipv4, NET_ETH_PTYPE_IP); + static NPF_ETH_TYPE_MATCH(is_ipv6, NET_ETH_PTYPE_IPV6); + + static NPF_PRIORITY(priority_bk, NET_PRIORITY_BK, is_arp, is_lldp); + static NPF_PRIORITY(priority_ee, NET_PRIORITY_EE, is_ipv4); + static NPF_PRIORITY(priority_ca, NET_PRIORITY_CA, is_ipv6); + static NPF_PRIORITY(priority_nc, NET_PRIORITY_NC, is_ptp); + + void install_my_filter(void) { + npf_append_recv_rule(&priority_bk); + npf_append_recv_rule(&priority_ee); + npf_append_recv_rule(&priority_ca); + npf_append_recv_rule(&priority_nc); + npf_append_recv_rule(&npf_default_ok); + } + API Reference ************* From ff297e3c851cbf8445e6fc4a034087deb443207a Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Sun, 19 Oct 2025 20:21:54 +0200 Subject: [PATCH 072/397] samples: net: pkt_filter: Add priority filters Add some priority filters to the sample for demonstration purpose. Signed-off-by: Cla Mattia Galliard --- samples/net/pkt_filter/prj.conf | 12 +++++++ samples/net/pkt_filter/src/main.c | 59 ++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/samples/net/pkt_filter/prj.conf b/samples/net/pkt_filter/prj.conf index 1ec1c27ef7feb..151fa6d730092 100644 --- a/samples/net/pkt_filter/prj.conf +++ b/samples/net/pkt_filter/prj.conf @@ -51,4 +51,16 @@ CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" # Logging CONFIG_LOG=y +CONFIG_LOG_MODE_DEFERRED=y CONFIG_LOG_BUFFER_SIZE=4096 + +# VLAN settings. We will have two VLANs in this sample. +CONFIG_NET_VLAN=y +CONFIG_NET_VLAN_COUNT=2 +CONFIG_NET_IF_MAX_IPV4_COUNT=3 +CONFIG_NET_IF_MAX_IPV6_COUNT=3 + +# Network traffic class queues +CONFIG_NET_TC_THREAD_PREEMPTIVE=y +CONFIG_NET_TC_RX_COUNT=2 +CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO=y diff --git a/samples/net/pkt_filter/src/main.c b/samples/net/pkt_filter/src/main.c index d88a29436bed5..81600995b5a2b 100644 --- a/samples/net/pkt_filter/src/main.c +++ b/samples/net/pkt_filter/src/main.c @@ -26,27 +26,38 @@ static NPF_IFACE_MATCH(match_iface_vlan1, NULL); static NPF_IFACE_MATCH(match_iface_vlan2, NULL); static NPF_IFACE_MATCH(match_iface_eth, NULL); -/* Allow all traffic to Ethernet interface, drop VLAN traffic except - * couple of exceptions for IPv4 and IPv6 - */ -static NPF_RULE(eth_iface_rule, NET_OK, match_iface_eth); - +/* Match ethernet packets for the precision time protocol (PTP) */ +static NPF_ETH_TYPE_MATCH(match_ptype_ptp, NET_ETH_PTYPE_PTP); +/* Match ethernet packets for the virtual local area network (VLAN) */ +static NPF_ETH_TYPE_MATCH(match_ptype_vlan, NET_ETH_PTYPE_VLAN); /* Match max size rule */ -static NPF_SIZE_MAX(maxsize_200, 200); -static NPF_ETH_VLAN_TYPE_MATCH(ipv4_packet1, NET_ETH_PTYPE_IP); -static NPF_RULE(small_ipv4_pkt, NET_OK, ipv4_packet1, maxsize_200, - match_iface_vlan1); - +static NPF_SIZE_MAX(match_smaller_200, 200); /* Match min size rule */ -static NPF_SIZE_MIN(minsize_100, 100); -static NPF_ETH_VLAN_TYPE_MATCH(ipv4_packet2, NET_ETH_PTYPE_IP); -static NPF_RULE(large_ipv4_pkt, NET_OK, ipv4_packet2, minsize_100, - match_iface_vlan2); +static NPF_SIZE_MIN(match_bigger_100, 100); +/* Match virtual internet protocol traffic */ +static NPF_ETH_VLAN_TYPE_MATCH(match_ipv4_vlan, NET_ETH_PTYPE_IP); +/* Match virtual address resolution protocol (ARP) traffic */ +static NPF_ETH_VLAN_TYPE_MATCH(match_arp_vlan, NET_ETH_PTYPE_ARP); -/* Allow ARP for VLAN interface */ -static NPF_ETH_VLAN_TYPE_MATCH(arp_packet, NET_ETH_PTYPE_ARP); -static NPF_RULE(arp_pkt_vlan1, NET_OK, arp_packet, match_iface_vlan1); -static NPF_RULE(arp_pkt_vlan2, NET_OK, arp_packet, match_iface_vlan2); +/* Allow all traffic to Ethernet interface */ +static NPF_RULE(eth_iface_rule, NET_OK, match_iface_eth); +/* Maximal priority for ptp traffic */ +static NPF_PRIORITY(eth_priority_ptp, NET_PRIORITY_NC, match_iface_eth, match_ptype_ptp); +/* Prioritize VLAN traffic on Ethernet interface */ +static NPF_PRIORITY(eth_priority_vlan, NET_PRIORITY_EE, match_iface_eth, match_ptype_vlan); +/* Deprioritize all other traffic */ +static NPF_PRIORITY(eth_priority_default, NET_PRIORITY_BK, match_iface_eth); + +/* Allow only small ipv4 packets to the first VLAN interface */ +static NPF_RULE(small_ipv4_pkt, NET_OK, match_iface_vlan1, match_ipv4_vlan, match_smaller_200); +/* Allow only ipv4 packets of minimum size to the second VLAN interface */ +static NPF_RULE(large_ipv4_pkt, NET_OK, match_iface_vlan2, match_ipv4_vlan, match_bigger_100); +/* Allow ARP for both VLAN interfaces */ +static NPF_RULE(arp_pkt_vlan1, NET_OK, match_iface_vlan1, match_arp_vlan); +static NPF_RULE(arp_pkt_vlan2, NET_OK, match_iface_vlan2, match_arp_vlan); +/* But give ARP the lowest priority */ +static NPF_PRIORITY(arp_priority_vlan1, NET_PRIORITY_BK, match_iface_vlan1, match_arp_vlan); +static NPF_PRIORITY(arp_priority_vlan2, NET_PRIORITY_BK, match_iface_vlan2, match_arp_vlan); static void iface_cb(struct net_if *iface, void *user_data) { @@ -106,7 +117,15 @@ static void init_app(void) * optional interfaces (if VLAN is enabled). * We allow all traffic to the Ethernet interface, but have * filters for the VLAN interfaces. + * + * First append the priority rules, so that they get evaluated before + * deciding on the final verdict for the packet. */ + npf_append_recv_rule(ð_priority_default); + npf_append_recv_rule(ð_priority_ptp); + npf_append_recv_rule(ð_priority_vlan); + npf_append_recv_rule(&arp_priority_vlan1); + npf_append_recv_rule(&arp_priority_vlan2); /* We allow small IPv4 packets to the VLAN interface 1 */ npf_append_recv_rule(&small_ipv4_pkt); @@ -117,10 +136,8 @@ static void init_app(void) /* We allow all traffic to the Ethernet interface */ npf_append_recv_rule(ð_iface_rule); - /* We allow ARP traffic to the VLAN 1 interface */ + /* We allow ARP traffic to both VLAN interfaces */ npf_append_recv_rule(&arp_pkt_vlan1); - - /* We allow ARP traffic to the VLAN 2 interface */ npf_append_recv_rule(&arp_pkt_vlan2); /* The remaining packets that do not match are dropped */ From 422a2d4b9281c5dcb034c156eb2ec107360108d7 Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Tue, 30 Sep 2025 10:51:58 +0200 Subject: [PATCH 073/397] net: tc: allow to spread threads by more then 1 priority level Allow to spread tc threads by more then one priority level and cleanup the computation of the priority. Signed-off-by: Cla Mattia Galliard --- subsys/net/ip/Kconfig | 17 +++++ subsys/net/ip/net_private.h | 2 + subsys/net/ip/net_tc.c | 122 +++++++++++------------------------- 3 files changed, 54 insertions(+), 87 deletions(-) diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index bb6df8ebf4401..1748f3013254e 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -294,6 +294,23 @@ config NET_TC_THREAD_PRIO_CUSTOM Customise net threads priority by each. if NET_TC_THREAD_PRIO_CUSTOM + +config NET_TC_TX_THREAD_PRIO_SPREAD + int "Transmit traffic class thread priority spread" + default 1 + range 1 255 + help + Transmit traffic class threads priority will increase/decrease + by this step. They will be separated by this many levels. + +config NET_TC_RX_THREAD_PRIO_SPREAD + int "Receive traffic class thread priority spread" + default 1 + range 1 255 + help + Receive traffic class threads priority will increase/decrease + by this step. They will be separated by this many levels. + config NET_TC_TX_THREAD_BASE_PRIO int "Transmit traffic class base thread priority" default 0 diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 5ee27093deda1..b354148c36bc4 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -208,6 +208,8 @@ static inline void net_tc_rx_init(void) { } enum net_verdict net_tc_try_submit_to_tx_queue(uint8_t tc, struct net_pkt *pkt, k_timeout_t timeout); extern enum net_verdict net_tc_submit_to_rx_queue(uint8_t tc, struct net_pkt *pkt); +extern int net_tc_tx_thread_priority(int tc); +extern int net_tc_rx_thread_priority(int tc); extern enum net_verdict net_promisc_mode_input(struct net_pkt *pkt); char *net_sprint_addr(sa_family_t af, const void *addr); diff --git a/subsys/net/ip/net_tc.c b/subsys/net/ip/net_tc.c index 15a928ffcd3ee..c38004532619d 100644 --- a/subsys/net/ip/net_tc.c +++ b/subsys/net/ip/net_tc.c @@ -151,89 +151,58 @@ int net_rx_priority2tc(enum net_priority prio) #if defined(CONFIG_NET_TC_THREAD_PRIO_CUSTOM) #define BASE_PRIO_TX CONFIG_NET_TC_TX_THREAD_BASE_PRIO +#define PRIO_SPREAD_TX CONFIG_NET_TC_TX_THREAD_PRIO_SPREAD #elif defined(CONFIG_NET_TC_THREAD_COOPERATIVE) #define BASE_PRIO_TX (CONFIG_NET_TC_NUM_PRIORITIES - 1) +#define PRIO_SPREAD_TX 1 +BUILD_ASSERT(NET_TC_TX_COUNT <= CONFIG_NUM_COOP_PRIORITIES, "Too many traffic classes"); #else #define BASE_PRIO_TX (CONFIG_NET_TC_TX_COUNT - 1) +#define PRIO_SPREAD_TX 1 #endif -#define PRIO_TX(i, _) (BASE_PRIO_TX - i) - #if defined(CONFIG_NET_TC_THREAD_PRIO_CUSTOM) #define BASE_PRIO_RX CONFIG_NET_TC_RX_THREAD_BASE_PRIO +#define PRIO_SPREAD_RX CONFIG_NET_TC_RX_THREAD_PRIO_SPREAD #elif defined(CONFIG_NET_TC_THREAD_COOPERATIVE) #define BASE_PRIO_RX (CONFIG_NET_TC_NUM_PRIORITIES - 1) +#define PRIO_SPREAD_RX 1 +BUILD_ASSERT(NET_TC_RX_COUNT <= CONFIG_NUM_COOP_PRIORITIES, "Too many traffic classes"); #else #define BASE_PRIO_RX (CONFIG_NET_TC_RX_COUNT - 1) +#define PRIO_SPREAD_RX 1 #endif -#define PRIO_RX(i, _) (BASE_PRIO_RX - i) - -#if NET_TC_TX_COUNT > 0 -/* Convert traffic class to thread priority */ -static uint8_t tx_tc2thread(uint8_t tc) +int net_tc_tx_thread_priority(int tc) { - /* Initial implementation just maps the traffic class to certain queue. - * If there are less queues than classes, then map them into - * some specific queue. - * - * Lower value in this table means higher thread priority. The - * value is used as a parameter to K_PRIO_COOP() or K_PRIO_PREEMPT() - * which converts it to actual thread priority. - * - * Higher traffic class value means higher priority queue. This means - * that thread_priorities[7] value should contain the highest priority - * for the TX queue handling thread. - * - * For example, if NET_TC_TX_COUNT = 8, which is the maximum number of - * traffic classes, then this priority array will contain following - * values if preemptive priorities are used: - * 7, 6, 5, 4, 3, 2, 1, 0 - * and - * 14, 13, 12, 11, 10, 9, 8, 7 - * if cooperative priorities are used. - * - * Then these will be converted to following thread priorities if - * CONFIG_NET_TC_THREAD_COOPERATIVE is enabled: - * -1, -2, -3, -4, -5, -6, -7, -8 - * - * and if CONFIG_NET_TC_THREAD_PREEMPTIVE is enabled, following thread - * priorities are used: - * 7, 6, 5, 4, 3, 2, 1, 0 - * - * This means that the lowest traffic class 1, will have the lowest - * cooperative priority -1 for coop priorities and 7 for preemptive - * priority. - */ - static const uint8_t thread_priorities[] = { - LISTIFY(NET_TC_TX_COUNT, PRIO_TX, (,)) - }; - - BUILD_ASSERT(NET_TC_TX_COUNT <= CONFIG_NUM_COOP_PRIORITIES, - "Too many traffic classes"); - - NET_ASSERT(tc < ARRAY_SIZE(thread_priorities)); - - return thread_priorities[tc]; + int priority; + int thread_priority; + + BUILD_ASSERT(BASE_PRIO_TX >= PRIO_SPREAD_TX * (NET_TC_TX_COUNT - 1)); + NET_ASSERT(tc >= 0 && tc < NET_TC_TX_COUNT); + thread_priority = BASE_PRIO_TX - PRIO_SPREAD_TX * tc; + + priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? + K_PRIO_COOP(thread_priority) : + K_PRIO_PREEMPT(thread_priority); + return priority; } -#endif -#if NET_TC_RX_COUNT > 0 -/* Convert traffic class to thread priority */ -static uint8_t rx_tc2thread(uint8_t tc) +int net_tc_rx_thread_priority(int tc) { - static const uint8_t thread_priorities[] = { - LISTIFY(NET_TC_RX_COUNT, PRIO_RX, (,)) - }; + int priority; + int thread_priority; - BUILD_ASSERT(NET_TC_RX_COUNT <= CONFIG_NUM_COOP_PRIORITIES, - "Too many traffic classes"); + BUILD_ASSERT(BASE_PRIO_RX >= PRIO_SPREAD_RX * (NET_TC_RX_COUNT - 1)); + NET_ASSERT(tc >= 0 && tc < NET_TC_RX_COUNT); + thread_priority = BASE_PRIO_RX - PRIO_SPREAD_RX * tc; - NET_ASSERT(tc < ARRAY_SIZE(thread_priorities)); - - return thread_priorities[tc]; + priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? + K_PRIO_COOP(thread_priority) : + K_PRIO_PREEMPT(thread_priority); + return priority; } -#endif + #if defined(CONFIG_NET_STATISTICS) /* Fixup the traffic class statistics so that "net stats" shell command will @@ -358,23 +327,12 @@ void net_tc_tx_init(void) #endif for (i = 0; i < NET_TC_TX_COUNT; i++) { - uint8_t thread_priority; - int priority; k_tid_t tid; + int priority = net_tc_tx_thread_priority(i); - thread_priority = tx_tc2thread(i); - - priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? - K_PRIO_COOP(thread_priority) : - K_PRIO_PREEMPT(thread_priority); - - NET_DBG("[%d] Starting TX handler %p stack size %zd " - "prio %d %s(%d)", i, + NET_DBG("[%d] Starting TX handler %p stack size %zd prio %d", i, &tx_classes[i].handler, K_KERNEL_STACK_SIZEOF(tx_stack[i]), - thread_priority, - IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? - "coop" : "preempt", priority); k_fifo_init(&tx_classes[i].fifo); @@ -426,23 +384,13 @@ void net_tc_rx_init(void) #endif for (i = 0; i < NET_TC_RX_COUNT; i++) { - uint8_t thread_priority; - int priority; k_tid_t tid; + int priority = net_tc_rx_thread_priority(i); - thread_priority = rx_tc2thread(i); - - priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? - K_PRIO_COOP(thread_priority) : - K_PRIO_PREEMPT(thread_priority); - NET_DBG("[%d] Starting RX handler %p stack size %zd " - "prio %d %s(%d)", i, + NET_DBG("[%d] Starting RX handler %p stack size %zd prio %d", i, &rx_classes[i].handler, K_KERNEL_STACK_SIZEOF(rx_stack[i]), - thread_priority, - IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? - "coop" : "preempt", priority); k_fifo_init(&rx_classes[i].fifo); From 4efa87a23da2a5691fafa826ee13a1664b0a64b5 Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Sun, 19 Oct 2025 18:59:59 +0200 Subject: [PATCH 074/397] net: shell: filter: Update table Adjust table to print newly available information. Signed-off-by: Cla Mattia Galliard --- .../networking/api/net_pkt_filter.rst | 2 +- subsys/net/ip/net_core.c | 4 +-- subsys/net/ip/net_if.c | 4 +-- subsys/net/ip/net_private.h | 18 +++++++++++ subsys/net/lib/shell/filter.c | 30 +++++++++++++++++-- 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/doc/connectivity/networking/api/net_pkt_filter.rst b/doc/connectivity/networking/api/net_pkt_filter.rst index 5fd954e170a07..338aaa6843789 100644 --- a/doc/connectivity/networking/api/net_pkt_filter.rst +++ b/doc/connectivity/networking/api/net_pkt_filter.rst @@ -100,7 +100,7 @@ applications priority (``NET_PRIORITY_CA``) to the internet traffic of version traffic, and the lowest background priority (``NET_PRIORITY_BK``) to ``lldp`` and ``arp``. -Priority rules are only really usefull if multiple traffic class queues are +Priority rules are only really useful if multiple traffic class queues are enabled in the project configuration :kconfig:option:`CONFIG_NET_TC_RX_COUNT`. The mapping from the priority of the packet to the traffic class queue is in accordance with the standard 802.1Q and depends on the diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index eb9437ccb95dc..533255a6318e5 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -507,9 +507,7 @@ static void net_queue_rx(struct net_if *iface, struct net_pkt *pkt) #if NET_TC_RX_COUNT > 1 NET_DBG("TC %d with prio %d pkt %p", tc, prio, pkt); #endif - - if ((IS_ENABLED(CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO) && - prio >= NET_PRIORITY_CA) || NET_TC_RX_COUNT == 0) { + if (net_tc_rx_is_immediate(tc, prio)) { net_process_rx_packet(pkt); } else { if (net_tc_submit_to_rx_queue(tc, pkt) != NET_OK) { diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index af13143d74b19..7fd784f87424c 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -366,10 +366,8 @@ void net_if_try_queue_tx(struct net_if *iface, struct net_pkt *pkt, k_timeout_t * the driver. Also if there are no TX queue/thread, push the packet * directly to the driver. */ - if ((IS_ENABLED(CONFIG_NET_TC_TX_SKIP_FOR_HIGH_PRIO) && - prio >= NET_PRIORITY_CA) || NET_TC_TX_COUNT == 0) { + if (net_tc_tx_is_immediate(tc, prio)) { net_pkt_set_tx_stats_tick(pkt, k_cycle_get_32()); - net_if_tx(net_pkt_iface(pkt), pkt); } else { if (net_tc_try_submit_to_tx_queue(tc, pkt, timeout) != NET_OK) { diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index b354148c36bc4..7723365a71434 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -210,6 +210,24 @@ enum net_verdict net_tc_try_submit_to_tx_queue(uint8_t tc, struct net_pkt *pkt, extern enum net_verdict net_tc_submit_to_rx_queue(uint8_t tc, struct net_pkt *pkt); extern int net_tc_tx_thread_priority(int tc); extern int net_tc_rx_thread_priority(int tc); +static inline bool net_tc_tx_is_immediate(int tc, int prio) +{ + ARG_UNUSED(tc); + bool high_prio = (prio >= NET_PRIORITY_CA); + bool skipping = IS_ENABLED(CONFIG_NET_TC_TX_SKIP_FOR_HIGH_PRIO); + bool no_queues = (0 == NET_TC_TX_COUNT); + + return no_queues || (high_prio && skipping); +} +static inline bool net_tc_rx_is_immediate(int tc, int prio) +{ + ARG_UNUSED(tc); + bool high_prio = (prio >= NET_PRIORITY_CA); + bool skipping = IS_ENABLED(CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO); + bool no_queues = (0 == NET_TC_RX_COUNT); + + return no_queues || (high_prio && skipping); +} extern enum net_verdict net_promisc_mode_input(struct net_pkt *pkt); char *net_sprint_addr(sa_family_t af, const void *addr); diff --git a/subsys/net/lib/shell/filter.c b/subsys/net/lib/shell/filter.c index c8ff95c78527f..4e9e948714c7f 100644 --- a/subsys/net/lib/shell/filter.c +++ b/subsys/net/lib/shell/filter.c @@ -56,9 +56,33 @@ static void rule_cb(struct npf_rule *rule, enum npf_rule_type type, void *user_d struct net_shell_user_data *data = user_data; const struct shell *sh = data->sh; int *count = data->user_data; + uint8_t tc; + int thread_prio; + + PR("[%2d] %-10s %-8s ", + (*count) + 1, rule_type2str(type), verdict2str(rule->result)); + + if (rule->result == NET_CONTINUE && type == NPF_RULE_TYPE_SEND) { + tc = net_tx_priority2tc(rule->priority); + if (net_tc_tx_is_immediate(tc, rule->priority)) { + PR("%8d %5d SKIP ", rule->priority, tc); + } else { + thread_prio = net_tc_tx_thread_priority(tc); + PR("%8d %5d %11d ", rule->priority, tc, thread_prio); + } + } else if (rule->result == NET_CONTINUE) { + tc = net_rx_priority2tc(rule->priority); + if (net_tc_rx_is_immediate(tc, rule->priority)) { + PR("%8d %5d SKIP ", rule->priority, tc); + } else { + thread_prio = net_tc_rx_thread_priority(tc); + PR("%8d %5d %11d ", rule->priority, tc, thread_prio); + } + } else { + PR(" N/A N/A N/A "); + } - PR("[%2d] %-10s %-7s %-5d", - (*count) + 1, rule_type2str(type), verdict2str(rule->result), rule->nb_tests); + PR("%-5d", rule->nb_tests); for (int i = 0; i < rule->nb_tests; i++) { /* Allocate room for storing two full IPv4/6 addresses */ @@ -89,7 +113,7 @@ static int cmd_net_filter(const struct shell *sh, size_t argc, char *argv[]) struct net_shell_user_data user_data; int count = 0; - PR("Rule %-10s Verdict Tests\n", "Type"); + PR("Rule %-10s Verdict Pkt-Prio Queue Thread-Prio Tests\n", "Type"); user_data.sh = sh; user_data.user_data = &count; From 61441db49da49579332d4ca62cef51b5252632e9 Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Sat, 27 Sep 2025 18:17:43 +0200 Subject: [PATCH 075/397] samples: net: QoS: Add quality of service sample Add a sample, that shows the power of quality of service in Zephyr. Signed-off-by: Cla Mattia Galliard --- samples/net/qos/QoS.rst | 5 + samples/net/qos/ethernet/CMakeLists.txt | 9 + samples/net/qos/ethernet/README.rst | 142 ++++++++ samples/net/qos/ethernet/prj.conf | 33 ++ samples/net/qos/ethernet/sample.yaml | 15 + samples/net/qos/ethernet/src/main.c | 428 ++++++++++++++++++++++++ 6 files changed, 632 insertions(+) create mode 100644 samples/net/qos/QoS.rst create mode 100644 samples/net/qos/ethernet/CMakeLists.txt create mode 100644 samples/net/qos/ethernet/README.rst create mode 100644 samples/net/qos/ethernet/prj.conf create mode 100644 samples/net/qos/ethernet/sample.yaml create mode 100644 samples/net/qos/ethernet/src/main.c diff --git a/samples/net/qos/QoS.rst b/samples/net/qos/QoS.rst new file mode 100644 index 0000000000000..3acc7e4171104 --- /dev/null +++ b/samples/net/qos/QoS.rst @@ -0,0 +1,5 @@ +.. zephyr:code-sample-category:: QoS + :name: Quality of Service + :show-listing: + + These samples demonstrate packet filters for Quality of Service (QoS). diff --git a/samples/net/qos/ethernet/CMakeLists.txt b/samples/net/qos/ethernet/CMakeLists.txt new file mode 100644 index 0000000000000..def810f0dc0ae --- /dev/null +++ b/samples/net/qos/ethernet/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ethernet_qos_demo) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/net/qos/ethernet/README.rst b/samples/net/qos/ethernet/README.rst new file mode 100644 index 0000000000000..5add0ce727e7c --- /dev/null +++ b/samples/net/qos/ethernet/README.rst @@ -0,0 +1,142 @@ +.. zephyr:code-sample:: quality-of-service + :name: Quality of Service + :relevant-api: ethernet + + Implements a demo of quality of service on the ethernet layer. + +Overview +******** + +The purpose of this sample is to show quality-of-service (QoS) on the ethernet layer. + +Building and Running +******************** + +Build like this: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/qos/ethernet + :board: + :goals: build + :compact: + +This sample only works with the native simulator. After the sample starts, it +fakes incoming network packets on a fake network interface and prints +statistics about it. + +Run with: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/qos/ethernet + :host-os: unix + :board: native_sim + :goals: run + :compact: + + +Statistics (With Quality of Service Filtering) +********************************************** + +c (x) := command service for priority x (high means higher priority) + +e (x) := echo service for priority x (high means higher priority) + ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| work us | c(7) | e(7) | c(6) | e(6) | c(5) | e(5) | c(4) | e(4) | c(3) | e(3) | c(2) | e(2) | c(1) | e(1) | c(0) | e(0) | ++=========+======+======+======+======+======+======+======+======+======+======+======+======+======+======+======+======+ +| 800 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 850 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 99 | 53 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 900 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 35 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 950 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 2 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1000 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 99 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 9 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1200 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 75 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1300 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 10 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1400 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 99 | 29 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1600 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1800 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 2000 | 100 | 100 | 100 | 100 | 100 | 100 | 15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 3000 | 100 | 100 | 100 | 100 | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 4000 | 100 | 100 | 99 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 5000 | 100 | 100 | 15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 6000 | 100 | 100 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 7000 | 100 | 85 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 8000 | 100 | 49 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 9000 | 100 | 22 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 10000 | 99 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 15000 | 44 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ + + +Statistics (No Quality of Service Filtering) +********************************************** + +c (x) := command service for priority x (high means higher priority) + +e (x) := echo service for priority x (high means higher priority) + ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| work us | c(7) | e(7) | c(6) | e(6) | c(5) | e(5) | c(4) | e(4) | c(3) | e(3) | c(2) | e(2) | c(1) | e(1) | c(0) | e(0) | ++=========+======+======+======+======+======+======+======+======+======+======+======+======+======+======+======+======+ +| 800 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 850 | 100 | 53 | 100 | 99 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 900 | 100 | 1 | 100 | 23 | 100 | 99 | 100 | 99 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 950 | 100 | 1 | 100 | 1 | 100 | 7 | 100 | 99 | 100 | 99 | 100 | 99 | 100 | 99 | 100 | 100 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1000 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 98 | 100 | 99 | 100 | 99 | 100 | 99 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1100 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 19 | 100 | 97 | 100 | 97 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1200 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 1 | 100 | 59 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1300 | 39 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1400 | 1 | 0 | 99 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1600 | 1 | 0 | 1 | 0 | 99 | 0 | 99 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 1800 | 1 | 0 | 1 | 0 | 12 | 0 | 99 | 0 | 99 | 0 | 100 | 0 | 100 | 0 | 100 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 2000 | 1 | 0 | 1 | 0 | 1 | 0 | 99 | 0 | 99 | 0 | 99 | 0 | 99 | 0 | 100 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 3000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 98 | 0 | 98 | 0 | 99 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 4000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 97 | 0 | 98 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 5000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 96 | 0 | 97 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 6000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 33 | 0 | 96 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 7000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 95 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 8000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 94 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 9000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 93 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 10000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 92 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ +| 15000 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 30 | 0 | ++---------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+------+ diff --git a/samples/net/qos/ethernet/prj.conf b/samples/net/qos/ethernet/prj.conf new file mode 100644 index 0000000000000..7719c937ff446 --- /dev/null +++ b/samples/net/qos/ethernet/prj.conf @@ -0,0 +1,33 @@ +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=n +CONFIG_NET_IF_MAX_IPV4_COUNT=2 +CONFIG_NET_RX_DEFAULT_PRIORITY=7 +CONFIG_NET_TX_DEFAULT_PRIORITY=7 + +# Logging +CONFIG_LOG=y +CONFIG_NET_LOG=y +CONFIG_LOG_THREAD_ID_PREFIX=y +CONFIG_THREAD_NAME=y + +# Network buffers +CONFIG_NET_PKT_RX_COUNT=128 +CONFIG_NET_BUF_RX_COUNT=1800 +CONFIG_NET_PKT_TX_COUNT=64 +CONFIG_NET_BUF_TX_COUNT=900 + +# Network traffic class queues +CONFIG_NET_TC_THREAD_PRIO_CUSTOM=y +CONFIG_NET_TC_TX_THREAD_BASE_PRIO=16 +CONFIG_NET_TC_TX_THREAD_PRIO_SPREAD=2 +CONFIG_NET_TC_RX_THREAD_BASE_PRIO=15 +CONFIG_NET_TC_RX_THREAD_PRIO_SPREAD=2 +CONFIG_NET_TC_THREAD_PREEMPTIVE=y +CONFIG_NET_TC_RX_COUNT=8 +CONFIG_NET_TC_TX_COUNT=8 +CONFIG_NET_TC_LOG_LEVEL_DBG=y + +# Network Packet filters +CONFIG_NET_PKT_FILTER=y diff --git a/samples/net/qos/ethernet/sample.yaml b/samples/net/qos/ethernet/sample.yaml new file mode 100644 index 0000000000000..626c76483d153 --- /dev/null +++ b/samples/net/qos/ethernet/sample.yaml @@ -0,0 +1,15 @@ +sample: + description: demo of quality of service for ethernet layer + name: quality_of_service +common: + harness: net +tests: + sample.net.Qos: + tags: + - net + - socket + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim diff --git a/samples/net/qos/ethernet/src/main.c b/samples/net/qos/ethernet/src/main.c new file mode 100644 index 0000000000000..a6d9a3756d845 --- /dev/null +++ b/samples/net/qos/ethernet/src/main.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2025 The Zephyr Contributors. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(qos_ethernet); + +#define NET_ETH_PTYPE_123 123 +#define NET_ETH_PTYPE_124 124 +#define NET_ETH_PTYPE_125 125 +#define NET_ETH_PTYPE_126 126 +#define NET_ETH_PTYPE_127 127 +#define NET_ETH_PTYPE_128 128 +#define NET_ETH_PTYPE_129 129 +#define NET_ETH_PTYPE_130 130 + +#define SINGLE_RUN_DEADLINE K_MSEC(2000) + +#define MTU 1500 + +enum service_type { + SERVICE_TYPE_COMMAND, + SERVICE_TYPE_ECHO, +}; + +struct net_if_fake_data { + uint8_t mac[sizeof(struct net_eth_addr)]; + struct net_linkaddr ll_addr; +}; + +struct statistics { + unsigned int service_123_count; + unsigned int service_124_count; + unsigned int service_125_count; + unsigned int service_126_count; + unsigned int service_127_count; + unsigned int service_128_count; + unsigned int service_129_count; + unsigned int service_130_count; + unsigned int echo_123_count; + unsigned int echo_124_count; + unsigned int echo_125_count; + unsigned int echo_126_count; + unsigned int echo_127_count; + unsigned int echo_128_count; + unsigned int echo_129_count; + unsigned int echo_130_count; +}; + +static K_SEM_DEFINE(service_123_received, 0, UINT_MAX); +static K_SEM_DEFINE(service_124_received, 0, UINT_MAX); +static K_SEM_DEFINE(service_125_received, 0, UINT_MAX); +static K_SEM_DEFINE(service_126_received, 0, UINT_MAX); +static K_SEM_DEFINE(service_127_received, 0, UINT_MAX); +static K_SEM_DEFINE(service_128_received, 0, UINT_MAX); +static K_SEM_DEFINE(service_129_received, 0, UINT_MAX); +static K_SEM_DEFINE(service_130_received, 0, UINT_MAX); + +static K_SEM_DEFINE(echo_123_send, 0, UINT_MAX); +static K_SEM_DEFINE(echo_124_send, 0, UINT_MAX); +static K_SEM_DEFINE(echo_125_send, 0, UINT_MAX); +static K_SEM_DEFINE(echo_126_send, 0, UINT_MAX); +static K_SEM_DEFINE(echo_127_send, 0, UINT_MAX); +static K_SEM_DEFINE(echo_128_send, 0, UINT_MAX); +static K_SEM_DEFINE(echo_129_send, 0, UINT_MAX); +static K_SEM_DEFINE(echo_130_send, 0, UINT_MAX); + +static NPF_ETH_TYPE_MATCH(npf_123, NET_ETH_PTYPE_123); +static NPF_ETH_TYPE_MATCH(npf_124, NET_ETH_PTYPE_124); +static NPF_ETH_TYPE_MATCH(npf_125, NET_ETH_PTYPE_125); +static NPF_ETH_TYPE_MATCH(npf_126, NET_ETH_PTYPE_126); +static NPF_ETH_TYPE_MATCH(npf_127, NET_ETH_PTYPE_127); +static NPF_ETH_TYPE_MATCH(npf_128, NET_ETH_PTYPE_128); +static NPF_ETH_TYPE_MATCH(npf_129, NET_ETH_PTYPE_129); +static NPF_ETH_TYPE_MATCH(npf_130, NET_ETH_PTYPE_130); + +static NPF_PRIORITY(priority_rule_123, NET_PRIORITY_BK, npf_123); +static NPF_PRIORITY(priority_rule_124, NET_PRIORITY_BE, npf_124); +static NPF_PRIORITY(priority_rule_125, NET_PRIORITY_EE, npf_125); +static NPF_PRIORITY(priority_rule_126, NET_PRIORITY_CA, npf_126); +static NPF_PRIORITY(priority_rule_127, NET_PRIORITY_VI, npf_127); +static NPF_PRIORITY(priority_rule_128, NET_PRIORITY_VO, npf_128); +static NPF_PRIORITY(priority_rule_129, NET_PRIORITY_IC, npf_129); +static NPF_PRIORITY(priority_rule_130, NET_PRIORITY_NC, npf_130); + +static uint32_t simulated_work_time; /* data race ! */ + +int net_fake_dev_init(const struct device *dev) +{ + return 0; +} + +static void copy_mac_to(char destination[static 6]) +{ + /* 00-00-5E-00-53-xx Documentation RFC 7042 */ + /* taken from arp test */ + destination[0] = 0x00; + destination[1] = 0x00; + destination[2] = 0x5E; + destination[3] = 0x00; + destination[4] = 0x53; + destination[5] = 0x3B; +} + +static void net_iface_init(struct net_if *iface) +{ + const struct device *device = net_if_get_device(iface); + struct net_if_fake_data *context = device->data; + + if (context->mac[2] == 0x00) { + copy_mac_to(context->mac); + } + + net_if_set_link_addr(iface, context->mac, sizeof(context->mac), NET_LINK_ETHERNET); +} + +static int net_if_fake_send(const struct device *dev, struct net_pkt *pkt) +{ + LOG_INF("sending service %u, pkt %p", net_pkt_ll_proto_type(pkt), pkt); + + posix_cpu_hold(simulated_work_time); + + switch (net_pkt_ll_proto_type(pkt)) { + case NET_ETH_PTYPE_123: + k_sem_give(&echo_123_send); + break; + case NET_ETH_PTYPE_124: + k_sem_give(&echo_124_send); + break; + case NET_ETH_PTYPE_125: + k_sem_give(&echo_125_send); + break; + case NET_ETH_PTYPE_126: + k_sem_give(&echo_126_send); + break; + case NET_ETH_PTYPE_127: + k_sem_give(&echo_127_send); + break; + case NET_ETH_PTYPE_128: + k_sem_give(&echo_128_send); + break; + case NET_ETH_PTYPE_129: + k_sem_give(&echo_129_send); + break; + case NET_ETH_PTYPE_130: + k_sem_give(&echo_130_send); + break; + default: /* nothing to do */ + break; + } + net_pkt_unref(pkt); + return 0; +} + +static const struct ethernet_api net_if_api = { + .iface_api.init = net_iface_init, + .send = net_if_fake_send, +}; + +static struct net_if_fake_data context; + +#define _ETH_L2_LAYER ETHERNET_L2 +#define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(ETHERNET_L2) + +NET_DEVICE_INIT(net_if_fake, "net_if_fake", net_fake_dev_init, NULL, &context, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &net_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, + MTU); + +static void try_recv_data(struct net_if *iface, uint16_t ptype, enum service_type service_type) +{ + int res; + struct net_pkt *pkt = NULL; + + char src[6] = {6, 7, 8, 9, 10, 11}; + char dest[6]; + + copy_mac_to(dest); + + pkt = net_pkt_rx_alloc_with_buffer(iface, MTU, AF_UNSPEC, 0, K_NO_WAIT); + if (pkt == NULL) { + return; + } + + if (net_pkt_write(pkt, dest, ARRAY_SIZE(dest))) { + goto error; + } + if (net_pkt_write(pkt, src, ARRAY_SIZE(src))) { + goto error; + } + if (net_pkt_write_be16(pkt, ptype)) { + goto error; + } + if (net_pkt_write_u8(pkt, service_type)) { + goto error; + } + + res = net_recv_data(net_pkt_iface(pkt), pkt); + if (res < 0) { + LOG_ERR("Failed to enqueue frame into RX queue: %d", res); + goto error; + } + + return; + +error: + net_pkt_unref(pkt); +} + +struct statistics single_run_with_simulated_work(struct net_if *iface, uint32_t work) +{ + k_timepoint_t deadline = sys_timepoint_calc(SINGLE_RUN_DEADLINE); + + simulated_work_time = work; + + k_sem_reset(&service_123_received); + k_sem_reset(&service_124_received); + k_sem_reset(&service_125_received); + k_sem_reset(&service_126_received); + k_sem_reset(&service_127_received); + k_sem_reset(&service_128_received); + k_sem_reset(&service_129_received); + k_sem_reset(&service_130_received); + k_sem_reset(&echo_123_send); + k_sem_reset(&echo_124_send); + k_sem_reset(&echo_125_send); + k_sem_reset(&echo_126_send); + k_sem_reset(&echo_127_send); + k_sem_reset(&echo_128_send); + k_sem_reset(&echo_129_send); + k_sem_reset(&echo_130_send); + + while (!sys_timepoint_expired(deadline)) { + /*every tick try receive a packet of each type*/ + try_recv_data(iface, NET_ETH_PTYPE_123, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_123, SERVICE_TYPE_COMMAND); + try_recv_data(iface, NET_ETH_PTYPE_124, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_124, SERVICE_TYPE_COMMAND); + try_recv_data(iface, NET_ETH_PTYPE_125, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_125, SERVICE_TYPE_COMMAND); + try_recv_data(iface, NET_ETH_PTYPE_126, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_126, SERVICE_TYPE_COMMAND); + try_recv_data(iface, NET_ETH_PTYPE_127, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_127, SERVICE_TYPE_COMMAND); + try_recv_data(iface, NET_ETH_PTYPE_128, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_128, SERVICE_TYPE_COMMAND); + try_recv_data(iface, NET_ETH_PTYPE_129, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_129, SERVICE_TYPE_COMMAND); + try_recv_data(iface, NET_ETH_PTYPE_130, SERVICE_TYPE_ECHO); + try_recv_data(iface, NET_ETH_PTYPE_130, SERVICE_TYPE_COMMAND); + k_sleep(K_TICKS(1)); + } + + return (struct statistics){ + .service_123_count = k_sem_count_get(&service_123_received), + .service_124_count = k_sem_count_get(&service_124_received), + .service_125_count = k_sem_count_get(&service_125_received), + .service_126_count = k_sem_count_get(&service_126_received), + .service_127_count = k_sem_count_get(&service_127_received), + .service_128_count = k_sem_count_get(&service_128_received), + .service_129_count = k_sem_count_get(&service_129_received), + .service_130_count = k_sem_count_get(&service_130_received), + .echo_123_count = k_sem_count_get(&echo_123_send), + .echo_124_count = k_sem_count_get(&echo_124_send), + .echo_125_count = k_sem_count_get(&echo_125_send), + .echo_126_count = k_sem_count_get(&echo_126_send), + .echo_127_count = k_sem_count_get(&echo_127_send), + .echo_128_count = k_sem_count_get(&echo_128_send), + .echo_129_count = k_sem_count_get(&echo_129_send), + .echo_130_count = k_sem_count_get(&echo_130_send), + }; +} + +void print_result(const char *msg, size_t cnt, uint32_t simulated_work_times[static cnt], + struct statistics stats[static cnt]) +{ + LOG_INF("--- Statistics (%s) ---", msg); + LOG_INF("c (x) := command service for priority x (high means higher priority)"); + LOG_INF("e (x) := echo service for priority x (high means higher priority)"); + LOG_INF("+---------+------+------+------+------+------+------+------+------+------+------+-" + "-----+------+------+------+------+------+"); + LOG_INF("| work us | c(7) | e(7) | c(6) | e(6) | c(5) | e(5) | c(4) | e(4) | c(3) | e(3) | " + "c(2) | e(2) | c(1) | e(1) | c(0) | e(0) |"); + LOG_INF("+=========+======+======+======+======+======+======+======+======+======+======+=" + "=====+======+======+======+======+======+"); + for (size_t i = 0; i < cnt; ++i) { + LOG_INF("| %7u | %4d | %4d | %4d | %4d | %4d | %4d | %4d | %4d | %4d | %4d | %4d | " + "%4d | %4d | %4d | %4d | %4d |", + simulated_work_times[i], stats[i].service_130_count, + stats[i].echo_130_count, stats[i].service_129_count, + stats[i].echo_129_count, stats[i].service_128_count, + stats[i].echo_128_count, stats[i].service_127_count, + stats[i].echo_127_count, stats[i].service_126_count, + stats[i].echo_126_count, stats[i].service_125_count, + stats[i].echo_125_count, stats[i].service_124_count, + stats[i].echo_124_count, stats[i].service_123_count, + stats[i].echo_123_count); + LOG_INF("+---------+------+------+------+------+------+------+------+------+------+" + "------+------+------+------+------+------+------+"); + } +} + +int main(int argc, char **argv) +{ + struct net_if *iface = NULL; + uint32_t simulated_work_times[] = { + 800, 850, 900, 950, 1000, 1100, 1200, 1300, 1400, 1600, 1800, + 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 15000, + }; + struct statistics stats_no_filter[ARRAY_SIZE(simulated_work_times)]; + struct statistics stats_with_filter[ARRAY_SIZE(simulated_work_times)]; + + iface = net_if_lookup_by_dev(DEVICE_GET(net_if_fake)); + if (iface == NULL) { + LOG_ERR("No device"); + return 1; + } + + for (size_t i = 0; i < ARRAY_SIZE(simulated_work_times); ++i) { + stats_no_filter[i] = single_run_with_simulated_work(iface, simulated_work_times[i]); + k_msleep(200); + print_result("In Progress", i + 1, simulated_work_times, stats_no_filter); + /* let simulation settle down */ + k_msleep(800); + } + + npf_append_recv_rule(&priority_rule_123); + npf_append_recv_rule(&priority_rule_124); + npf_append_recv_rule(&priority_rule_125); + npf_append_recv_rule(&priority_rule_126); + npf_append_recv_rule(&priority_rule_127); + npf_append_recv_rule(&priority_rule_128); + npf_append_recv_rule(&priority_rule_129); + npf_append_recv_rule(&priority_rule_130); + npf_append_recv_rule(&npf_default_ok); + + for (size_t i = 0; i < ARRAY_SIZE(simulated_work_times); ++i) { + stats_with_filter[i] = + single_run_with_simulated_work(iface, simulated_work_times[i]); + k_msleep(1000); + print_result("In Progress", i + 1, simulated_work_times, stats_with_filter); + /* let simulation settle down */ + k_msleep(2000); + } + + k_msleep(4000); + print_result("No Quality of Service Filtering", ARRAY_SIZE(simulated_work_times), + simulated_work_times, stats_no_filter); + print_result("With Quality of Service Filtering", ARRAY_SIZE(simulated_work_times), + simulated_work_times, stats_with_filter); + + return 0; +} + +static enum net_verdict l2_service(struct net_if *iface, uint16_t ptype, struct net_pkt *pkt) +{ + struct net_pkt *echo_reply; + uint8_t type; + const char *service_type; + + net_pkt_cursor_init(pkt); + net_pkt_read_u8(pkt, &type); + service_type = (type == SERVICE_TYPE_ECHO) ? "echo" : "command"; + + LOG_INF("handler for %s-service %d, iface %p, ptype %u, pkt %p", service_type, + net_pkt_ll_proto_type(pkt), iface, ptype, pkt); + + posix_cpu_hold(simulated_work_time); + + if (type == SERVICE_TYPE_ECHO) { + echo_reply = net_pkt_alloc_with_buffer(iface, 12, AF_UNSPEC, 0, K_NO_WAIT); + if (echo_reply) { + net_pkt_set_ll_proto_type(echo_reply, net_pkt_ll_proto_type(pkt)); + net_pkt_set_priority(echo_reply, net_pkt_priority(pkt)); + if (net_if_try_send_data(iface, echo_reply, K_NO_WAIT) != NET_OK) { + net_pkt_unref(echo_reply); + } + } + net_pkt_unref(pkt); + return NET_OK; + } + + switch (net_pkt_ll_proto_type(pkt)) { + case NET_ETH_PTYPE_123: + k_sem_give(&service_123_received); + break; + case NET_ETH_PTYPE_124: + k_sem_give(&service_124_received); + break; + case NET_ETH_PTYPE_125: + k_sem_give(&service_125_received); + break; + case NET_ETH_PTYPE_126: + k_sem_give(&service_126_received); + break; + case NET_ETH_PTYPE_127: + k_sem_give(&service_127_received); + break; + case NET_ETH_PTYPE_128: + k_sem_give(&service_128_received); + break; + case NET_ETH_PTYPE_129: + k_sem_give(&service_129_received); + break; + case NET_ETH_PTYPE_130: + k_sem_give(&service_130_received); + break; + default: /* nothing to do */ + break; + } + net_pkt_unref(pkt); + return NET_OK; +} + +ETH_NET_L3_REGISTER(service_123, NET_ETH_PTYPE_123, l2_service); +ETH_NET_L3_REGISTER(service_124, NET_ETH_PTYPE_124, l2_service); +ETH_NET_L3_REGISTER(service_125, NET_ETH_PTYPE_125, l2_service); +ETH_NET_L3_REGISTER(service_126, NET_ETH_PTYPE_126, l2_service); +ETH_NET_L3_REGISTER(service_127, NET_ETH_PTYPE_127, l2_service); +ETH_NET_L3_REGISTER(service_128, NET_ETH_PTYPE_128, l2_service); +ETH_NET_L3_REGISTER(service_129, NET_ETH_PTYPE_129, l2_service); +ETH_NET_L3_REGISTER(service_130, NET_ETH_PTYPE_130, l2_service); From 00e7a60fb4c5ae4f11dc2b1d23f10f9d5e92a4ef Mon Sep 17 00:00:00 2001 From: Tony Han Date: Thu, 3 Jul 2025 13:13:39 +0800 Subject: [PATCH 076/397] soc: microchip: sam: optimize name for sama7g5 programmable clock Change the location of the names for programable clocks from the stack to "static struct clk_programmable" array. Signed-off-by: Tony Han --- soc/microchip/sam/common/clk-programmable.c | 7 +++++-- soc/microchip/sam/common/pmc.h | 2 +- soc/microchip/sam/common/sama7g5.c | 7 +------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/soc/microchip/sam/common/clk-programmable.c b/soc/microchip/sam/common/clk-programmable.c index fb17512c2e1a6..bbac3badb4c0a 100644 --- a/soc/microchip/sam/common/clk-programmable.c +++ b/soc/microchip/sam/common/clk-programmable.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -25,6 +26,7 @@ struct clk_programmable { uint8_t num_parents; uint8_t parent; const struct clk_programmable_layout *layout; + char name[8]; }; #define to_clk_programmable(ptr) CONTAINER_OF(ptr, struct clk_programmable, clk) @@ -79,7 +81,7 @@ static DEVICE_API(clock_control, programmable_api) = { .get_rate = clk_programmable_get_rate, }; -int clk_register_programmable(pmc_registers_t *const pmc, const char *name, +int clk_register_programmable(pmc_registers_t *const pmc, const struct device **parents, uint8_t num_parents, uint8_t id, const struct clk_programmable_layout *layout, @@ -102,9 +104,10 @@ int clk_register_programmable(pmc_registers_t *const pmc, const char *name, } memcpy(prog->parents, parents, sizeof(struct device *) * num_parents); + snprintf(prog->name, sizeof(prog->name), "prog%d", id); *clk = &prog->clk; - (*clk)->name = name; + (*clk)->name = prog->name; (*clk)->api = &programmable_api; prog->num_parents = num_parents; prog->id = id; diff --git a/soc/microchip/sam/common/pmc.h b/soc/microchip/sam/common/pmc.h index a46238f509ed1..e9127cbca743b 100644 --- a/soc/microchip/sam/common/pmc.h +++ b/soc/microchip/sam/common/pmc.h @@ -168,7 +168,7 @@ int sam9x60_clk_register_frac_pll(pmc_registers_t *const pmc, struct k_spinlock const struct clk_pll_characteristics *characteristics, const struct clk_pll_layout *layout, struct device **clk); -int clk_register_programmable(pmc_registers_t *const pmc, const char *name, +int clk_register_programmable(pmc_registers_t *const pmc, const struct device **parents, uint8_t num_parents, uint8_t id, const struct clk_programmable_layout *layout, diff --git a/soc/microchip/sam/common/sama7g5.c b/soc/microchip/sam/common/sama7g5.c index dbcb0a07d096e..1bf28fe1f882d 100644 --- a/soc/microchip/sam/common/sama7g5.c +++ b/soc/microchip/sam/common/sama7g5.c @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -1154,11 +1153,7 @@ void sam_pmc_setup(const struct device *dev) parents[7] = sama7g5_plls[PLL_ID_AUDIO][PLL_COMPID_DIV0].clk; parents[8] = sama7g5_plls[PLL_ID_ETH][PLL_COMPID_DIV0].clk; for (i = 0; i < 8; i++) { - char name[6]; - - snprintf(name, sizeof(name), "prog%d", i); - - ret = clk_register_programmable(regmap, name, parents, + ret = clk_register_programmable(regmap, parents, 9, i, &programmable_layout, sama7g5_prog_mux_table, &clk); From a5b60f0bc6a8009ea0c3f50339e2c248034c03ce Mon Sep 17 00:00:00 2001 From: Tony Han Date: Thu, 3 Jul 2025 13:39:04 +0800 Subject: [PATCH 077/397] soc: microchip: sam: optimize array size for sama7g5 registered clocks Replace the array size for sama7g5 registered clocks with macros and put the macros to soc.h with descriptions. Signed-off-by: Tony Han --- soc/microchip/sam/common/clk-generated.c | 2 +- soc/microchip/sam/common/clk-master.c | 4 ++-- soc/microchip/sam/common/clk-peripheral.c | 2 +- soc/microchip/sam/common/clk-sam9x60-pll.c | 6 +++--- soc/microchip/sam/common/clk-system.c | 2 +- soc/microchip/sam/sama7g5/soc.h | 9 +++++++++ 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/soc/microchip/sam/common/clk-generated.c b/soc/microchip/sam/common/clk-generated.c index e8452cc6bd6e4..4c6c5ae201046 100644 --- a/soc/microchip/sam/common/clk-generated.c +++ b/soc/microchip/sam/common/clk-generated.c @@ -29,7 +29,7 @@ struct clk_generated { #define to_clk_generated(ptr) CONTAINER_OF(ptr, struct clk_generated, clk) -static struct clk_generated clocks_gck[ID_PERIPH_MAX]; +static struct clk_generated clocks_gck[SOC_NUM_CLOCK_GENERATED]; static uint32_t clocks_gck_idx; static int clk_generated_on(const struct device *dev, clock_control_subsys_t sys) diff --git a/soc/microchip/sam/common/clk-master.c b/soc/microchip/sam/common/clk-master.c index f721ea466a03b..a56099a4e97eb 100644 --- a/soc/microchip/sam/common/clk-master.c +++ b/soc/microchip/sam/common/clk-master.c @@ -19,7 +19,7 @@ LOG_MODULE_REGISTER(clk_mck, CONFIG_CLOCK_CONTROL_LOG_LEVEL); #define PMC_MCR_CSS_SHIFT 16 -#define MASTER_MAX_ID 4 +#define MASTER_MAX_ID (SOC_NUM_CLOCK_MASTER - 1) #define to_clk_master(ptr) CONTAINER_OF(ptr, struct clk_master, clk) @@ -38,7 +38,7 @@ struct clk_master { uint8_t div; }; -static struct clk_master clocks_master[5]; +static struct clk_master clocks_master[SOC_NUM_CLOCK_MASTER]; static uint32_t clocks_master_idx; static inline bool clk_master_ready(struct clk_master *master) diff --git a/soc/microchip/sam/common/clk-peripheral.c b/soc/microchip/sam/common/clk-peripheral.c index 2fdc1117d340f..094c37d613c69 100644 --- a/soc/microchip/sam/common/clk-peripheral.c +++ b/soc/microchip/sam/common/clk-peripheral.c @@ -25,7 +25,7 @@ struct clk_peripheral { const struct clk_pcr_layout *layout; }; -static struct clk_peripheral clocks_periph[72]; +static struct clk_peripheral clocks_periph[SOC_NUM_CLOCK_PERIPHERAL]; static uint32_t clocks_periph_idx; #define to_clk_peripheral(ptr) CONTAINER_OF(ptr, struct clk_peripheral, clk) diff --git a/soc/microchip/sam/common/clk-sam9x60-pll.c b/soc/microchip/sam/common/clk-sam9x60-pll.c index 0a3a00d50a792..bd3d65d100200 100644 --- a/soc/microchip/sam/common/clk-sam9x60-pll.c +++ b/soc/microchip/sam/common/clk-sam9x60-pll.c @@ -46,7 +46,7 @@ LOG_MODULE_REGISTER(clk_pll, CONFIG_CLOCK_CONTROL_LOG_LEVEL); q * n_ + r * n_ / d_; \ }) -#define PLL_MAX_ID 7 +#define PLL_MAX_ID SOC_NUM_CLOCK_PLL_FRAC struct sam9x60_pll_core { pmc_registers_t *pmc; @@ -73,10 +73,10 @@ struct sam9x60_div { #define to_sam9x60_frac(ptr) CONTAINER_OF(ptr, struct sam9x60_frac, core) #define to_sam9x60_div(ptr) CONTAINER_OF(ptr, struct sam9x60_div, core) -static struct sam9x60_frac clocks_frac[7]; +static struct sam9x60_frac clocks_frac[SOC_NUM_CLOCK_PLL_FRAC]; static uint32_t clocks_frac_idx; -static struct sam9x60_div clocks_div[8]; +static struct sam9x60_div clocks_div[SOC_NUM_CLOCK_PLL_DIV]; static uint32_t clocks_div_idx; static inline bool sam9x60_pll_ready(pmc_registers_t *pmc, int id) diff --git a/soc/microchip/sam/common/clk-system.c b/soc/microchip/sam/common/clk-system.c index 453408a31935c..d300a8ce66a7d 100644 --- a/soc/microchip/sam/common/clk-system.c +++ b/soc/microchip/sam/common/clk-system.c @@ -25,7 +25,7 @@ struct clk_system { uint8_t id; }; -static struct clk_system clocks_sys[8]; +static struct clk_system clocks_sys[SOC_NUM_CLOCK_SYSTEM]; static uint32_t clocks_sys_idx; static inline int is_pck(int id) diff --git a/soc/microchip/sam/sama7g5/soc.h b/soc/microchip/sam/sama7g5/soc.h index cdacd1592f9d4..bc2c93b57e1e7 100644 --- a/soc/microchip/sam/sama7g5/soc.h +++ b/soc/microchip/sam/sama7g5/soc.h @@ -13,4 +13,13 @@ #include "sam.h" +/* number of clocks registered */ +#define SOC_NUM_CLOCK_PLL_FRAC 7 +#define SOC_NUM_CLOCK_PLL_DIV (SOC_NUM_CLOCK_PLL_FRAC + 1) /* AUDIO PLL: DIVPMC, DIVIO */ +#define SOC_NUM_CLOCK_MASTER 5 /* MCK 0 ~ 4 */ +#define SOC_NUM_CLOCK_PROGRAMMABLE 8 /* MCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_SYSTEM 8 /* PCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_PERIPHERAL 72 +#define SOC_NUM_CLOCK_GENERATED 46 + #endif /* __SAMA7G5_SOC__H_ */ From 3d1fb606edef2befa759ebb58f62c382fc436c24 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 1 Jul 2025 14:19:16 +0800 Subject: [PATCH 078/397] dts: microchip: add the DTSI file for sama7d6 SoCs Add the base DTSI file for Microchip sama7d6 SoCs. Signed-off-by: Tony Han --- dts/arm/microchip/sam/sama7d6.dtsi | 421 +++++++++++++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100644 dts/arm/microchip/sam/sama7d6.dtsi diff --git a/dts/arm/microchip/sam/sama7d6.dtsi b/dts/arm/microchip/sam/sama7d6.dtsi new file mode 100644 index 0000000000000..da766b5d3a924 --- /dev/null +++ b/dts/arm/microchip/sam/sama7d6.dtsi @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include +#include + +/ { + model = "Microchip SAMA7D65 family SoC"; + compatible = "microchip,sama7d6"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0>; + }; + }; + + clocks { + main_xtal: main_xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + slow_xtal: slow_xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + }; + + soc { + sram: memory@100000 { + compatible = "mmio-sram"; + reg = <0x00100000 DT_SIZE_K(128)>; + }; + + pinctrl: pinctrl@e0014000 { + compatible = "microchip,sama7g5-pinctrl"; + reg = <0xe0014000 0x800>; + }; + + pmc: clock-controller@e0018000 { + compatible = "microchip,sam-pmc"; + reg = <0xe0018000 0x200>; + #clock-cells = <2>; + clocks = <&clk32k 1>, <&clk32k 0>, <&main_xtal>; + clock-names = "td_slck", "md_slck", "main_xtal"; + }; + + clk32k: clock-controller@e001d500 { + compatible = "microchip,sama7g5-sckc", "microchip,sam9x60-sckc"; + reg = <0xe001d500 0x4>; + clocks = <&slow_xtal>; + #clock-cells = <1>; + }; + + rtc: rtc@e001d800 { + compatible = "atmel,sam-rtc"; + reg = <0xe001d800 0x30>; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&clk32k 1>; + }; + + pit64b0: timer@e1800000 { + compatible = "microchip,sam-pit64b", "microchip,sam9x60-pit64b"; + reg = <0xe1800000 0x4000>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 66>, <&pmc PMC_TYPE_GCK 66>; + clock-names = "pclk", "gclk"; + interrupt-parent = <&gic>; + interrupts = ; + }; + + flx0: flexcom@e1820000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe1820000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe1820000 0x800>; + status = "disabled"; + + i2c0: i2c0@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 34>; + status = "disabled"; + }; + + uart0: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 34>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx1: flexcom@e1824000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe1824000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe1824000 0x800>; + status = "disabled"; + + i2c1: i2c1@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 35>; + status = "disabled"; + }; + + uart1: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 35>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx2: flexcom@e1828000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe1828000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe1828000 0x800>; + status = "disabled"; + + i2c2: i2c2@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 36>; + status = "disabled"; + }; + + uart2: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 36>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx3: flexcom@e182c000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe182c000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe182c000 0x800>; + status = "disabled"; + + i2c3: i2c3@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 37>; + status = "disabled"; + }; + + uart3: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 37>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx4: flexcom@e2018000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2018000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2018000 0x800>; + status = "disabled"; + + i2c4: i2c4@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 38>; + status = "disabled"; + }; + + uart4: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 38>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx5: flexcom@e201c000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe201c000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe201c000 0x800>; + status = "disabled"; + + i2c5: i2c5@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 39>; + status = "disabled"; + }; + + uart5: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 39>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx6: flexcom@e2020000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2020000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2020000 0x800>; + status = "disabled"; + + i2c6: i2c6@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 40>; + status = "disabled"; + }; + + uart6: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 40>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx7: flexcom@e2024000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2024000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2024000 0x800>; + status = "disabled"; + + i2c7: i2c7@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 41>; + status = "disabled"; + }; + + uart7: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 41>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx8: flexcom@e281c000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe281c000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe281c000 0x800>; + status = "disabled"; + + i2c8: i2c8@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 42>; + status = "disabled"; + }; + + uart8: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 42>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx9: flexcom@e2820000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2820000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2820000 0x800>; + status = "disabled"; + + i2c9: i2c9@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 43>; + status = "disabled"; + }; + + uart9: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 43>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx10: flexcom@e2824000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2824000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2824000 0x800>; + status = "disabled"; + + i2c10: i2c10@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 44>; + status = "disabled"; + }; + + uart10: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 44>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + gic: interrupt-controller@e8c11000 { + compatible = "arm,gic-v2", "arm,gic"; + reg = <0xe8c11000 0x1000>, <0xe8c12000 0x100>; + interrupt-controller; + #interrupt-cells = <4>; + }; + }; +}; From df4e481387d31efb577fbb73214d322f0a5f4d2c Mon Sep 17 00:00:00 2001 From: Tony Han Date: Mon, 30 Jun 2025 17:18:39 +0800 Subject: [PATCH 079/397] soc: microchip: sam: add new SoC sama7d65 Product URL: https://www.microchip.com/en-us/product/SAMA7D65 The files under 'soc/microchip/sam/sama7/' will be used for both sama7d5 and sama7d65 SoCs after the directory structure for sama7g5 is reorganized. Signed-off-by: Tony Han --- soc/microchip/sam/sama7/CMakeLists.txt | 10 ++++ soc/microchip/sam/sama7/Kconfig | 10 ++++ soc/microchip/sam/sama7/Kconfig.defconfig | 16 ++++++ soc/microchip/sam/sama7/Kconfig.soc | 14 +++++ .../sam/sama7/sama7d6/CMakeLists.txt | 9 +++ .../sam/sama7/sama7d6/Kconfig.defconfig | 14 +++++ soc/microchip/sam/sama7/sama7d6/Kconfig.soc | 45 +++++++++++++++ soc/microchip/sam/sama7/sama7d6/soc.c | 56 +++++++++++++++++++ soc/microchip/sam/sama7/sama7d6/soc.h | 41 ++++++++++++++ soc/microchip/sam/sama7/soc.yml | 14 +++++ 10 files changed, 229 insertions(+) create mode 100644 soc/microchip/sam/sama7/CMakeLists.txt create mode 100644 soc/microchip/sam/sama7/Kconfig create mode 100644 soc/microchip/sam/sama7/Kconfig.defconfig create mode 100644 soc/microchip/sam/sama7/Kconfig.soc create mode 100644 soc/microchip/sam/sama7/sama7d6/CMakeLists.txt create mode 100644 soc/microchip/sam/sama7/sama7d6/Kconfig.defconfig create mode 100644 soc/microchip/sam/sama7/sama7d6/Kconfig.soc create mode 100644 soc/microchip/sam/sama7/sama7d6/soc.c create mode 100644 soc/microchip/sam/sama7/sama7d6/soc.h create mode 100644 soc/microchip/sam/sama7/soc.yml diff --git a/soc/microchip/sam/sama7/CMakeLists.txt b/soc/microchip/sam/sama7/CMakeLists.txt new file mode 100644 index 0000000000000..7f08aa1b33ac6 --- /dev/null +++ b/soc/microchip/sam/sama7/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +add_subdirectory(${SOC_SERIES}) + +add_subdirectory(../common ${CMAKE_BINARY_DIR}/common) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/microchip/sam/sama7/Kconfig b/soc/microchip/sam/sama7/Kconfig new file mode 100644 index 0000000000000..f7fe8649c0497 --- /dev/null +++ b/soc/microchip/sam/sama7/Kconfig @@ -0,0 +1,10 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_FAMILY_MICROCHIP_SAMA7 + select MICROCHIP_SAM + select ARM + select CPU_CORTEX_A7 + select MMU diff --git a/soc/microchip/sam/sama7/Kconfig.defconfig b/soc/microchip/sam/sama7/Kconfig.defconfig new file mode 100644 index 0000000000000..99b0bf81148c1 --- /dev/null +++ b/soc/microchip/sam/sama7/Kconfig.defconfig @@ -0,0 +1,16 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +if SOC_FAMILY_MICROCHIP_SAMA7 + +configdefault SOC_EARLY_INIT_HOOK + default y + +configdefault CLOCK_CONTROL + default y + +endif # SOC_FAMILY_MICROCHIP_SAMA7 + +rsource "*/Kconfig.defconfig" diff --git a/soc/microchip/sam/sama7/Kconfig.soc b/soc/microchip/sam/sama7/Kconfig.soc new file mode 100644 index 0000000000000..352678952dacb --- /dev/null +++ b/soc/microchip/sam/sama7/Kconfig.soc @@ -0,0 +1,14 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_FAMILY_MICROCHIP_SAMA7 + bool + help + Enable support for Microchip SAMA7 Cortex-A Microprocessors. + +config SOC_FAMILY + default "microchip_sama7" if SOC_FAMILY_MICROCHIP_SAMA7 + +rsource "*/Kconfig.soc" diff --git a/soc/microchip/sam/sama7/sama7d6/CMakeLists.txt b/soc/microchip/sam/sama7/sama7d6/CMakeLists.txt new file mode 100644 index 0000000000000..8d91aceb1f3a8 --- /dev/null +++ b/soc/microchip/sam/sama7/sama7d6/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_sources(soc.c) +zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/microchip/sam/sama7/sama7d6/Kconfig.defconfig b/soc/microchip/sam/sama7/sama7d6/Kconfig.defconfig new file mode 100644 index 0000000000000..1d7b758263ad7 --- /dev/null +++ b/soc/microchip/sam/sama7/sama7d6/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +if SOC_SERIES_SAMA7D6 + +configdefault NUM_IRQS + default 189 + +configdefault SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/soc/timer@e1800000,clock-frequency) + +endif # SOC_SERIES_SAMA7D6 diff --git a/soc/microchip/sam/sama7/sama7d6/Kconfig.soc b/soc/microchip/sam/sama7/sama7d6/Kconfig.soc new file mode 100644 index 0000000000000..fcbfe636d879d --- /dev/null +++ b/soc/microchip/sam/sama7/sama7d6/Kconfig.soc @@ -0,0 +1,45 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_SERIES_SAMA7D6 + bool + select SOC_FAMILY_MICROCHIP_SAMA7 + help + Enable support for Microchip SAMA7D6 Cortex-A Microprocessors. + +config SOC_SERIES + default "sama7d6" if SOC_SERIES_SAMA7D6 + +config SOC_SAMA7D65 + bool + select SOC_SERIES_SAMA7D6 + +config SOC_SAMA7D65D1G + bool + select SOC_SERIES_SAMA7D6 + +config SOC_SAMA7D65D1GN2 + bool + select SOC_SERIES_SAMA7D6 + +config SOC_SAMA7D65D2G + bool + select SOC_SERIES_SAMA7D6 + +config SOC_SAMA7D65D2GN8 + bool + select SOC_SERIES_SAMA7D6 + +config SOC_SAMA7D65D5M + bool + select SOC_SERIES_SAMA7D6 + +config SOC + default "sama7d65" if SOC_SAMA7D65 + default "sama7d65d1g" if SOC_SAMA7D65D1G + default "sama7d65d1gn2" if SOC_SAMA7D65D1GN2 + default "sama7d65d2g" if SOC_SAMA7D65D2G + default "sama7d65d2gn8" if SOC_SAMA7D65D2GN8 + default "sama7d65d5m" if SOC_SAMA7D65D5M diff --git a/soc/microchip/sam/sama7/sama7d6/soc.c b/soc/microchip/sam/sama7/sama7d6/soc.c new file mode 100644 index 0000000000000..39339f362ba67 --- /dev/null +++ b/soc/microchip/sam/sama7/sama7d6/soc.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include + +#define MMU_REGION_FLEXCOM_DEFN(idx, n) \ + COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flx##n)), \ + (MMU_REGION_FLAT_ENTRY("flexcom"#n, FLEXCOM##n##_BASE_ADDRESS, 0x4000, \ + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W),), \ + ()) + +static const struct arm_mmu_region mmu_regions[] = { + MMU_REGION_FLAT_ENTRY("vectors", CONFIG_KERNEL_VM_BASE, 0x1000, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_X), + + FOR_EACH_IDX(MMU_REGION_FLEXCOM_DEFN, (), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + + MMU_REGION_FLAT_ENTRY("gic", GIC_DISTRIBUTOR_BASE, 0x1100, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("pioa", PIO_BASE_ADDRESS, 0x4000, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("pit64b0", PIT64B0_BASE_ADDRESS, 0x4000, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("pmc", PMC_BASE_ADDRESS, 0x200, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("sckc", SCKC_BASE_ADDRESS, 0x4, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; + +void relocate_vector_table(void) +{ + write_vbar(CONFIG_KERNEL_VM_BASE); +} + +void soc_early_init_hook(void) +{ + /* Enable Generic clock for PIT64B0 for system tick */ + PMC_REGS->PMC_PCR = PMC_PCR_CMD(1) | PMC_PCR_GCLKEN(1) | PMC_PCR_EN(1) | + PMC_PCR_GCLKDIV(20 - 1) | PMC_PCR_GCLKCSS_MCK1 | + PMC_PCR_PID(ID_PIT64B0); +} diff --git a/soc/microchip/sam/sama7/sama7d6/soc.h b/soc/microchip/sam/sama7/sama7d6/soc.h new file mode 100644 index 0000000000000..11926a924306e --- /dev/null +++ b/soc/microchip/sam/sama7/sama7d6/soc.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC_MICROCHIP_SAMA7D6_SOC__H_ +#define _SOC_MICROCHIP_SAMA7D6_SOC__H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_SAMA7D65) + #include +#elif defined(CONFIG_SOC_SAMA7D65D1G) + #include +#elif defined(CONFIG_SOC_SAMA7D65D1GN2) + #include +#elif defined(CONFIG_SOC_SAMA7D65D2G) + #include +#elif defined(CONFIG_SOC_SAMA7D65D2GN8) + #include +#elif defined(CONFIG_SOC_SAMA7D65D5M) + #include +#else + #error Library does not support the specified device +#endif + +#endif /* _ASMLANGUAGE */ + +/* number of clocks registered */ +#define SOC_NUM_CLOCK_PLL_FRAC 9 +#define SOC_NUM_CLOCK_PLL_DIV (SOC_NUM_CLOCK_PLL_FRAC + 1) /* AUDIO PLL: DIVPMC, DIVIO */ +#define SOC_NUM_CLOCK_MASTER 10 /* MCK 0 ~ 9 */ +#define SOC_NUM_CLOCK_PROGRAMMABLE 8 /* MCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_SYSTEM 8 /* PCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_PERIPHERAL 72 +#define SOC_NUM_CLOCK_GENERATED 44 + +#endif /* _SOC_MICROCHIP_SAMA7D6_SOC__H_ */ diff --git a/soc/microchip/sam/sama7/soc.yml b/soc/microchip/sam/sama7/soc.yml new file mode 100644 index 0000000000000..96b42ac83c86b --- /dev/null +++ b/soc/microchip/sam/sama7/soc.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +family: +- name: microchip_sama7 + series: + - name: sama7d6 + socs: + - name: sama7d65 + - name: sama7d65d1g + - name: sama7d65d1gn2 + - name: sama7d65d2g + - name: sama7d65d2gn8 + - name: sama7d65d5m From 487607cf3b4df79de185013060357fc9d61ffce4 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 1 Jul 2025 14:08:43 +0800 Subject: [PATCH 080/397] include: dt-bindings: sam_pmc: add PMC clocks for SAMA7D65 Add LVDSPLL, MCK3 and MCK5 clock definitions for microchip SAMA7D65. Signed-off-by: Tony Han --- include/zephyr/dt-bindings/clock/microchip_sam_pmc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h b/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h index 0656f3de97162..a2e2fa94051df 100644 --- a/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h +++ b/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h @@ -33,4 +33,9 @@ #define UTMI2 1 #define UTMI3 2 +/* SAMA7D65 */ +#define PMC_LVDSPLL (PMC_MAIN + 12) +#define PMC_MCK3 (PMC_MAIN + 20) +#define PMC_MCK5 (PMC_MAIN + 21) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MICROCHIP_SAM_PMC_H_ */ From 8afca2ce6ba2ffc14ae105942ab27c0302ee807e Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 1 Jul 2025 14:20:17 +0800 Subject: [PATCH 081/397] soc: microchip: sam: register clocks for sama7d65 Register sama7d65 clocks in sam_pmc_setup() which will be called by the PMC driver. Signed-off-by: Tony Han --- soc/microchip/sam/common/CMakeLists.txt | 3 +- soc/microchip/sam/common/pmc.h | 1 + soc/microchip/sam/common/sama7d65.c | 1382 +++++++++++++++++++++++ 3 files changed, 1385 insertions(+), 1 deletion(-) create mode 100644 soc/microchip/sam/common/sama7d65.c diff --git a/soc/microchip/sam/common/CMakeLists.txt b/soc/microchip/sam/common/CMakeLists.txt index bbb4727fdf383..50d11f5d75504 100644 --- a/soc/microchip/sam/common/CMakeLists.txt +++ b/soc/microchip/sam/common/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_sources(clk-peripheral.c) zephyr_sources(clk-programmable.c) zephyr_sources(clk-sam9x60-pll.c) zephyr_sources(clk-system.c) -zephyr_sources(clk-utmi.c) +zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMA7G5 clk-utmi.c) zephyr_sources(pmc.c) +zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMA7D6 sama7d65.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMA7G5 sama7g5.c) diff --git a/soc/microchip/sam/common/pmc.h b/soc/microchip/sam/common/pmc.h index e9127cbca743b..72112c5185d30 100644 --- a/soc/microchip/sam/common/pmc.h +++ b/soc/microchip/sam/common/pmc.h @@ -68,6 +68,7 @@ struct clk_pll_characteristics { uint16_t *icpll; uint8_t *out; uint8_t upll : 1; + uint32_t acr; }; struct clk_programmable_layout { diff --git a/soc/microchip/sam/common/sama7d65.c b/soc/microchip/sam/common/sama7d65.c new file mode 100644 index 0000000000000..094f836752958 --- /dev/null +++ b/soc/microchip/sam/common/sama7d65.c @@ -0,0 +1,1382 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(pmc_setup, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) + +#define SAMA7D65_INIT_TABLE(_table, _count) \ + do { \ + uint8_t _i; \ + for (_i = 0; _i < (_count); _i++) { \ + (_table)[_i] = _i; \ + } \ + } while (0) + +#define SAMA7D65_FILL_TABLE(_to, _from, _count) \ + do { \ + uint8_t _i; \ + for (_i = 0; _i < (_count); _i++) { \ + (_to)[_i] = (_from)[_i]; \ + } \ + } while (0) + +static struct k_spinlock pmc_pll_lock; +static struct k_spinlock pmc_mck0_lock; +static struct k_spinlock pmc_mckX_lock; +static struct k_spinlock pmc_pcr_lock; + +/* + * PLL clocks identifiers + * @PLL_ID_CPU: CPU PLL identifier + * @PLL_ID_SYS: System PLL identifier + * @PLL_ID_DDR: DDR PLL identifier + * @PLL_ID_IMG: Image subsystem PLL identifier + * @PLL_ID_BAUD: Baud PLL identifier + * @PLL_ID_AUDIO: Audio PLL identifier + * @PLL_ID_ETH: Ethernet PLL identifier + * @PLL_ID_LVDS: LVDS PLL identifier + * @PLL_ID_USB: USB PLL identifier + */ +enum pll_ids { + PLL_ID_CPU, + PLL_ID_SYS, + PLL_ID_DDR, + PLL_ID_GPU, + PLL_ID_BAUD, + PLL_ID_AUDIO, + PLL_ID_ETH, + PLL_ID_LVDS, + PLL_ID_USB, + PLL_ID_MAX, +}; + +/* + * PLL component identifier + * @PLL_COMPID_FRAC: Fractional PLL component identifier + * @PLL_COMPID_DIV0: 1st PLL divider component identifier + * @PLL_COMPID_DIV1: 2nd PLL divider component identifier + */ +enum pll_component_id { + PLL_COMPID_FRAC, + PLL_COMPID_DIV0, + PLL_COMPID_DIV1, +}; + +/* + * PLL type identifiers + * @PLL_TYPE_FRAC: fractional PLL identifier + * @PLL_TYPE_DIV: divider PLL identifier + */ +enum pll_type { + PLL_TYPE_FRAC, + PLL_TYPE_DIV, +}; + +/* Layout for fractional PLLs. */ +static const struct clk_pll_layout pll_layout_frac = { + .mul_mask = GENMASK(31, 24), + .frac_mask = GENMASK(21, 0), + .mul_shift = 24, + .frac_shift = 0, +}; + +/* Layout for DIVPMC dividers. */ +static const struct clk_pll_layout pll_layout_divpmc = { + .div_mask = GENMASK(7, 0), + .endiv_mask = BIT(29), + .div_shift = 0, + .endiv_shift = 29, +}; + +/* Layout for DIVIO dividers. */ +static const struct clk_pll_layout pll_layout_divio = { + .div_mask = GENMASK(19, 12), + .endiv_mask = BIT(30), + .div_shift = 12, + .endiv_shift = 30, +}; + +/* + * CPU PLL output range. + * Notice: The upper limit has been setup to 1000000002 due to hardware + * block which cannot output exactly 1GHz. + */ +static const struct clk_range cpu_pll_outputs[] = { + { .min = 2343750, .max = 1000000002 }, +}; + +/* PLL output range. */ +static const struct clk_range pll_outputs[] = { + { .min = 2343750, .max = 1200000000 }, +}; + +/* + * Min: fCOREPLLCK = 600 MHz, PMC_PLL_CTRL0.DIVPMC = 255 + * Max: fCOREPLLCK = 800 MHz, PMC_PLL_CTRL0.DIVPMC = 0 + */ +static const struct clk_range lvdspll_outputs[] = { + { .min = 16406250, .max = 800000000 }, +}; + +static const struct clk_range upll_outputs[] = { + { .min = 480000000, .max = 480000000 }, +}; + +/* Fractional PLL core output range. */ +static const struct clk_range core_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +static const struct clk_range lvdspll_core_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +static const struct clk_range upll_core_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +/* CPU PLL characteristics. */ +static const struct clk_pll_characteristics cpu_pll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(cpu_pll_outputs), + .output = cpu_pll_outputs, + .core_output = core_outputs, + .acr = 0x00070010, +}; + +/* PLL characteristics. */ +static const struct clk_pll_characteristics pll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(pll_outputs), + .output = pll_outputs, + .core_output = core_outputs, + .acr = 0x00070010, +}; + +static const struct clk_pll_characteristics lvdspll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(lvdspll_outputs), + .output = lvdspll_outputs, + .core_output = lvdspll_core_outputs, + .acr = 0x00070010, +}; + +static const struct clk_pll_characteristics upll_characteristics = { + .input = { .min = 20000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(upll_outputs), + .output = upll_outputs, + .core_output = upll_core_outputs, + .acr = 0x12020010, + .upll = true, +}; + +/* + * SAMA7D65 PLL possible parents + * @SAMA7D65_PLL_PARENT_MAINCK: MAINCK is PLL a parent + * @SAMA7D65_PLL_PARENT_MAIN_XTAL: MAIN XTAL is a PLL parent + * @SAMA7D65_PLL_PARENT_FRACCK: Frac PLL is a PLL parent (for PLL dividers) + */ +enum sama7d65_pll_parent { + SAMA7D65_PLL_PARENT_MAINCK, + SAMA7D65_PLL_PARENT_MAIN_XTAL, + SAMA7D65_PLL_PARENT_FRACCK, +}; + +/* + * PLL clocks description + * @n: clock name + * @p: clock parent + * @l: clock layout + * @c: clock characteristics + * @hw: pointer to clk_hw + * @t: clock type + * @f: clock flags + * @p: clock parent + * @eid: export index in sama7d65->chws[] array + * @safe_div: intermediate divider need to be set on PRE_RATE_CHANGE + * notification + */ +static struct sama7d65_pll { + const char *n; + const struct clk_pll_layout *l; + const struct clk_pll_characteristics *c; + struct device *clk; + unsigned long f; + enum sama7d65_pll_parent p; + uint8_t t; + uint8_t eid; + uint8_t safe_div; +} sama7d65_plls[][PLL_ID_MAX] = { + [PLL_ID_CPU] = { + [PLL_COMPID_FRAC] = { + .n = "cpupll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &cpu_pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "cpupll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &cpu_pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_CPUPLL, + /* + * Safe div=15 should be safe even for switching b/w 1GHz and + * 90MHz (frac pll might go up to 1.2GHz). + */ + .safe_div = 15, + }, + }, + + [PLL_ID_SYS] = { + [PLL_COMPID_FRAC] = { + .n = "syspll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "syspll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_SYSPLL, + }, + }, + + [PLL_ID_DDR] = { + [PLL_COMPID_FRAC] = { + .n = "ddrpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "ddrpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + }, + }, + + [PLL_ID_GPU] = { + [PLL_COMPID_FRAC] = { + .n = "gpupll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "gpupll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + }, + }, + + [PLL_ID_BAUD] = { + [PLL_COMPID_FRAC] = { + .n = "baudpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "baudpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_BAUDPLL, + }, + }, + + [PLL_ID_AUDIO] = { + [PLL_COMPID_FRAC] = { + .n = "audiopll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "audiopll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_AUDIOPMCPLL, + }, + + [PLL_COMPID_DIV1] = { + .n = "audiopll_diviock", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divio, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_AUDIOIOPLL, + }, + }, + + [PLL_ID_ETH] = { + [PLL_COMPID_FRAC] = { + .n = "ethpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "ethpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_ETHPLL, + }, + }, + + [PLL_ID_LVDS] = { + [PLL_COMPID_FRAC] = { + .n = "lvdspll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &lvdspll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "lvdspll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &lvdspll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_LVDSPLL, + }, + }, + + [PLL_ID_USB] = { + [PLL_COMPID_FRAC] = { + .n = "usbpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &upll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "usbpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &upll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_UTMI, + }, + }, +}; + +/* Used to create an array entry identifying a PLL by its components. */ +#define PLL_IDS_TO_ARR_ENTRY(_id, _comp) { PLL_ID_##_id, PLL_COMPID_##_comp} + +/* + * Master clock (MCK[1..4]) description + * @n: clock name + * @ep_chg_chg_id: index in parents array that specifies the changeable + * @ep: extra parents names array (entry formed by PLL components + * identifiers (see enum pll_component_id)) + * @hw: pointer to clk_hw + * parent + * @ep_count: extra parents count + * @ep_mux_table: mux table for extra parents + * @id: clock id + * @eid: export index in sama7d65->chws[] array + * @c: true if clock is critical and cannot be disabled + */ +static struct { + const char *n; + struct { + int pll_id; + int pll_compid; + } ep[4]; + struct device *clk; + int ep_chg_id; + uint8_t ep_count; + uint8_t ep_mux_table[4]; + uint8_t id; + uint8_t eid; + uint8_t c; +} sama7d65_mckx[] = { + { .n = "mck0", }, /* Dummy entry for MCK0 to store hw in probe. */ + { .n = "mck1", + .id = 1, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_count = 1, + .ep_chg_id = INT_MIN, + .eid = PMC_MCK1, + .c = 1, }, + + { .n = "mck2", + .id = 2, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(DDR, DIV0), }, + .ep_mux_table = { 5, 6, }, + .ep_count = 2, + .ep_chg_id = INT_MIN, + .c = 1, }, + + { .n = "mck3", + .id = 3, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(DDR, DIV0), }, + .ep_mux_table = { 5, 6, }, + .ep_count = 2, + .ep_chg_id = INT_MIN, + .eid = PMC_MCK3, + .c = 1, }, + + { .n = "mck4", + .id = 4, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_count = 1, + .ep_chg_id = INT_MIN, + .c = 1,}, + + { .n = "mck5", + .id = 5, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_count = 1, + .ep_chg_id = INT_MIN, + .eid = PMC_MCK5, + .c = 1,}, + + { .n = "mck6", + .id = 6, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1, + .c = 1,}, + + { .n = "mck7", + .id = 7, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1,}, + + { .n = "mck8", + .id = 8, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1,}, + + { .n = "mck9", + .id = 9, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1, }, +}; + +/* + * System clock description + * @n: clock name + * @p: clock parent name + * @id: clock id + */ +static const struct { + const char *n; + const char *p; + uint8_t id; +} sama7d65_systemck[] = { + { .n = "pck0", .p = "prog0", .id = 8, }, + { .n = "pck1", .p = "prog1", .id = 9, }, + { .n = "pck2", .p = "prog2", .id = 10, }, + { .n = "pck3", .p = "prog3", .id = 11, }, + { .n = "pck4", .p = "prog4", .id = 12, }, + { .n = "pck5", .p = "prog5", .id = 13, }, + { .n = "pck6", .p = "prog6", .id = 14, }, + { .n = "pck7", .p = "prog7", .id = 15, }, +}; + +/* Mux table for programmable clocks. */ +static uint32_t sama7d65_prog_mux_table[] = { 0, 1, 2, 5, 7, 8, 9, 10, 12,}; + +/* + * Peripheral clock parent hw identifier (used to index in sama7d65_mckx[]) + * @PCK_PARENT_HW_MCK0: pck parent hw identifier is MCK0 + * @PCK_PARENT_HW_MCK1: pck parent hw identifier is MCK1 + * @PCK_PARENT_HW_MCK2: pck parent hw identifier is MCK2 + * @PCK_PARENT_HW_MCK3: pck parent hw identifier is MCK3 + * @PCK_PARENT_HW_MCK4: pck parent hw identifier is MCK4 + * @PCK_PARENT_HW_MCK5: pck parent hw identifier is MCK5 + * @PCK_PARENT_HW_MCK6: pck parent hw identifier is MCK6 + * @PCK_PARENT_HW_MCK7: pck parent hw identifier is MCK7 + * @PCK_PARENT_HW_MCK8: pck parent hw identifier is MCK8 + * @PCK_PARENT_HW_MCK9: pck parent hw identifier is MCK9 + * @PCK_PARENT_HW_MAX: max identifier + */ +enum sama7d65_pck_parent_hw_id { + PCK_PARENT_HW_MCK0, + PCK_PARENT_HW_MCK1, + PCK_PARENT_HW_MCK2, + PCK_PARENT_HW_MCK3, + PCK_PARENT_HW_MCK4, + PCK_PARENT_HW_MCK5, + PCK_PARENT_HW_MCK6, + PCK_PARENT_HW_MCK7, + PCK_PARENT_HW_MCK8, + PCK_PARENT_HW_MCK9, + PCK_PARENT_HW_MAX, +}; + +/* + * Peripheral clock description + * @n: clock name + * @p: clock parent hw id + * @r: clock range values + * @id: clock id + * @chgp: index in parent array of the changeable parent + */ +static struct { + const char *n; + enum sama7d65_pck_parent_hw_id p; + struct clk_range r; + uint8_t chgp; + uint8_t id; +} sama7d65_periphck[] = { + { .n = "pioA_clk", .p = PCK_PARENT_HW_MCK0, .id = 10, }, + { .n = "securam_clk", .p = PCK_PARENT_HW_MCK0, .id = 17, }, + { .n = "sfr_clk", .p = PCK_PARENT_HW_MCK7, .id = 18, }, + { .n = "hsmc_clk", .p = PCK_PARENT_HW_MCK5, .id = 20, }, + { .n = "xdmac0_clk", .p = PCK_PARENT_HW_MCK6, .id = 21, }, + { .n = "xdmac1_clk", .p = PCK_PARENT_HW_MCK6, .id = 22, }, + { .n = "xdmac2_clk", .p = PCK_PARENT_HW_MCK1, .id = 23, }, + { .n = "acc_clk", .p = PCK_PARENT_HW_MCK7, .id = 24, }, + { .n = "aes_clk", .p = PCK_PARENT_HW_MCK6, .id = 26, }, + { .n = "tzaesbasc_clk", .p = PCK_PARENT_HW_MCK8, .id = 27, }, + { .n = "asrc_clk", .p = PCK_PARENT_HW_MCK9, .id = 29, .r = { .max = 200000000, }, }, + { .n = "cpkcc_clk", .p = PCK_PARENT_HW_MCK0, .id = 30, }, + { .n = "eic_clk", .p = PCK_PARENT_HW_MCK7, .id = 33, }, + { .n = "flex0_clk", .p = PCK_PARENT_HW_MCK7, .id = 34, }, + { .n = "flex1_clk", .p = PCK_PARENT_HW_MCK7, .id = 35, }, + { .n = "flex2_clk", .p = PCK_PARENT_HW_MCK7, .id = 36, }, + { .n = "flex3_clk", .p = PCK_PARENT_HW_MCK7, .id = 37, }, + { .n = "flex4_clk", .p = PCK_PARENT_HW_MCK8, .id = 38, }, + { .n = "flex5_clk", .p = PCK_PARENT_HW_MCK8, .id = 39, }, + { .n = "flex6_clk", .p = PCK_PARENT_HW_MCK8, .id = 40, }, + { .n = "flex7_clk", .p = PCK_PARENT_HW_MCK8, .id = 41, }, + { .n = "flex8_clk", .p = PCK_PARENT_HW_MCK9, .id = 42, }, + { .n = "flex9_clk", .p = PCK_PARENT_HW_MCK9, .id = 43, }, + { .n = "flex10_clk", .p = PCK_PARENT_HW_MCK9, .id = 44, }, + { .n = "gmac0_clk", .p = PCK_PARENT_HW_MCK6, .id = 46, }, + { .n = "gmac1_clk", .p = PCK_PARENT_HW_MCK6, .id = 47, }, + { .n = "gmac0_tsu_clk", .p = PCK_PARENT_HW_MCK1, .id = 49, }, + { .n = "gmac1_tsu_clk", .p = PCK_PARENT_HW_MCK1, .id = 50, }, + { .n = "icm_clk", .p = PCK_PARENT_HW_MCK5, .id = 53, }, + { .n = "i2smcc0_clk", .p = PCK_PARENT_HW_MCK9, .id = 54, .r = { .max = 200000000, }, }, + { .n = "i2smcc1_clk", .p = PCK_PARENT_HW_MCK9, .id = 55, .r = { .max = 200000000, }, }, + { .n = "lcd_clk", .p = PCK_PARENT_HW_MCK3, .id = 56, }, + { .n = "matrix_clk", .p = PCK_PARENT_HW_MCK5, .id = 57, }, + { .n = "mcan0_clk", .p = PCK_PARENT_HW_MCK5, .id = 58, .r = { .max = 200000000, }, }, + { .n = "mcan1_clk", .p = PCK_PARENT_HW_MCK5, .id = 59, .r = { .max = 200000000, }, }, + { .n = "mcan2_clk", .p = PCK_PARENT_HW_MCK5, .id = 60, .r = { .max = 200000000, }, }, + { .n = "mcan3_clk", .p = PCK_PARENT_HW_MCK5, .id = 61, .r = { .max = 200000000, }, }, + { .n = "mcan4_clk", .p = PCK_PARENT_HW_MCK5, .id = 62, .r = { .max = 200000000, }, }, + { .n = "pdmc0_clk", .p = PCK_PARENT_HW_MCK9, .id = 64, .r = { .max = 200000000, }, }, + { .n = "pdmc1_clk", .p = PCK_PARENT_HW_MCK9, .id = 65, .r = { .max = 200000000, }, }, + { .n = "pit64b0_clk", .p = PCK_PARENT_HW_MCK7, .id = 66, }, + { .n = "pit64b1_clk", .p = PCK_PARENT_HW_MCK7, .id = 67, }, + { .n = "pit64b2_clk", .p = PCK_PARENT_HW_MCK7, .id = 68, }, + { .n = "pit64b3_clk", .p = PCK_PARENT_HW_MCK8, .id = 69, }, + { .n = "pit64b4_clk", .p = PCK_PARENT_HW_MCK8, .id = 70, }, + { .n = "pit64b5_clk", .p = PCK_PARENT_HW_MCK8, .id = 71, }, + { .n = "pwm_clk", .p = PCK_PARENT_HW_MCK7, .id = 72, }, + { .n = "qspi0_clk", .p = PCK_PARENT_HW_MCK5, .id = 73, }, + { .n = "qspi1_clk", .p = PCK_PARENT_HW_MCK5, .id = 74, }, + { .n = "sdmmc0_clk", .p = PCK_PARENT_HW_MCK1, .id = 75, }, + { .n = "sdmmc1_clk", .p = PCK_PARENT_HW_MCK1, .id = 76, }, + { .n = "sdmmc2_clk", .p = PCK_PARENT_HW_MCK1, .id = 77, }, + { .n = "sha_clk", .p = PCK_PARENT_HW_MCK6, .id = 78, }, + { .n = "spdifrx_clk", .p = PCK_PARENT_HW_MCK9, .id = 79, .r = { .max = 200000000, }, }, + { .n = "spdiftx_clk", .p = PCK_PARENT_HW_MCK9, .id = 80, .r = { .max = 200000000, }, }, + { .n = "ssc0_clk", .p = PCK_PARENT_HW_MCK7, .id = 81, .r = { .max = 200000000, }, }, + { .n = "ssc1_clk", .p = PCK_PARENT_HW_MCK8, .id = 82, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch0_clk", .p = PCK_PARENT_HW_MCK8, .id = 83, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch1_clk", .p = PCK_PARENT_HW_MCK8, .id = 84, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch2_clk", .p = PCK_PARENT_HW_MCK8, .id = 85, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch0_clk", .p = PCK_PARENT_HW_MCK5, .id = 86, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch1_clk", .p = PCK_PARENT_HW_MCK5, .id = 87, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch2_clk", .p = PCK_PARENT_HW_MCK5, .id = 88, .r = { .max = 200000000, }, }, + { .n = "tcpca_clk", .p = PCK_PARENT_HW_MCK5, .id = 89, }, + { .n = "tcpcb_clk", .p = PCK_PARENT_HW_MCK5, .id = 90, }, + { .n = "tdes_clk", .p = PCK_PARENT_HW_MCK6, .id = 91, }, + { .n = "trng_clk", .p = PCK_PARENT_HW_MCK6, .id = 92, }, + { .n = "udphsa_clk", .p = PCK_PARENT_HW_MCK5, .id = 99, }, + { .n = "udphsb_clk", .p = PCK_PARENT_HW_MCK5, .id = 100, }, + { .n = "uhphs_clk", .p = PCK_PARENT_HW_MCK5, .id = 101, }, + { .n = "dsi_clk", .p = PCK_PARENT_HW_MCK3, .id = 103, }, + { .n = "lvdsc_clk", .p = PCK_PARENT_HW_MCK3, .id = 104, }, +}; + +/* + * Generic clock description + * @n: clock name + * @pp: PLL parents (entry formed by PLL components identifiers + * (see enum pll_component_id)) + * @pp_mux_table: PLL parents mux table + * @r: clock output range + * @pp_chg_id: id in parent array of changeable PLL parent + * @pp_count: PLL parents count + * @id: clock id + */ +static const struct { + const char *n; + struct { + int pll_id; + int pll_compid; + } pp[8]; + const char pp_mux_table[8]; + struct clk_range r; + int pp_chg_id; + uint8_t pp_count; + uint8_t id; +} sama7d65_gck[] = { + { .n = "adc_gclk", + .id = 25, + .r = { .max = 100000000, }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 8, 9, }, + .pp_count = 2, + .pp_chg_id = INT_MIN, }, + + { .n = "asrc_gclk", + .id = 29, + .r = { .max = 200000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex0_gclk", + .id = 34, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex1_gclk", + .id = 35, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex2_gclk", + .id = 36, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex3_gclk", + .id = 37, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex4_gclk", + .id = 38, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex5_gclk", + .id = 39, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex6_gclk", + .id = 40, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex7_gclk", + .id = 41, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex8_gclk", + .id = 42, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex9_gclk", + .id = 43, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex10_gclk", + .id = 44, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "gmac0_gclk", + .id = 46, + .r = { .max = 125000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 10, }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "gmac1_gclk", + .id = 47, + .r = { .max = 125000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 10, }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "gmac0_tsu_gclk", + .id = 49, + .r = { .max = 400000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {10, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "gmac1_tsu_gclk", + .id = 50, + .r = { .max = 400000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 10, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "i2smcc0_gclk", + .id = 54, + .r = { .max = 100000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "i2smcc1_gclk", + .id = 55, + .r = { .max = 100000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "lcdc_gclk", + .id = 56, + .r = { .max = 90000000 }, + .pp_count = 0, + .pp_chg_id = INT_MIN, + }, + + { .n = "mcan0_gclk", + .id = 58, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan1_gclk", + .id = 59, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan2_gclk", + .id = 60, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan3_gclk", + .id = 61, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan4_gclk", + .id = 62, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "pdmc0_gclk", + .id = 64, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9 }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "pdmc1_gclk", + .id = 65, + .r = { .max = 80000000, }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b0_gclk", + .id = 66, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b1_gclk", + .id = 67, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b2_gclk", + .id = 68, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b3_gclk", + .id = 69, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b4_gclk", + .id = 70, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b5_gclk", + .id = 71, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "qspi0_gclk", + .id = 73, + .r = { .max = 400000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 5, 8, }, + .pp_count = 2, + .pp_chg_id = INT_MIN, }, + + { .n = "qspi1_gclk", + .id = 74, + .r = { .max = 266000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 5, 8, }, + .pp_count = 2, + .pp_chg_id = INT_MIN, }, + + { .n = "sdmmc0_gclk", + .id = 75, + .r = { .max = 208000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 10, }, + .pp_count = 2, + .pp_chg_id = 4, }, + + { .n = "sdmmc1_gclk", + .id = 76, + .r = { .max = 208000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 10, }, + .pp_count = 2, + .pp_chg_id = 4, }, + + { .n = "sdmmc2_gclk", + .id = 77, + .r = { .max = 208000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 10 }, + .pp_count = 2, + .pp_chg_id = 4, }, + + { .n = "spdifrx_gclk", + .id = 79, + .r = { .max = 150000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "spdiftx_gclk", + .id = 80, + .r = { .max = 25000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "tcb0_ch0_gclk", + .id = 83, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "tcb1_ch0_gclk", + .id = 86, + .r = { .max = 67000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "DSI_gclk", + .id = 103, + .r = {.max = 27000000}, + .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .pp_mux_table = {5}, + .pp_count = 1, + .pp_chg_id = INT_MIN,}, + + { .n = "I3CC_gclk", + .id = 105, + .r = {.max = 125000000}, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN,}, +}; + +/* MCK0 characteristics. */ +static const struct clk_master_characteristics mck0_characteristics = { + .output = {.min = 32768, .max = 200000000}, + .divisors = {1, 2, 4, 3, 5}, + .have_div3_pres = 1, +}; + +/* MCK0 layout. */ +static const struct clk_master_layout mck0_layout = { + .mask = 0x773, + .pres_shift = 4, + .offset = 0x28, +}; + +/* Programmable clock layout. */ +static const struct clk_programmable_layout programmable_layout = { + .pres_mask = 0xff, + .pres_shift = 8, + .css_mask = 0x1f, + .have_slck_mck = 0, + .is_pres_direct = 1, +}; + +/* Peripheral clock layout. */ +static const struct clk_pcr_layout sama7d65_pcr_layout = { + .offset = 0x88, + .cmd = BIT(31), + .gckcss_mask = GENMASK(12, 8), + .pid_mask = GENMASK(6, 0), +}; + +enum clock_count { + CLK_CNT_SYSTEM = 15 + 1, + CLK_CNT_PERIPH = 104 + 1, + CLK_CNT_GCK = 105 + 1, +}; + +static struct device *pmc_table[PMC_MCK5 + 1 + CLK_CNT_SYSTEM + CLK_CNT_PERIPH + CLK_CNT_GCK + + SOC_NUM_CLOCK_PROGRAMMABLE]; + +static int sam_pmc_register_pll(const struct device *dev, struct pmc_data *sama7d65_pmc) +{ + const struct sam_pmc_cfg *cfg = dev->config; + void *const regmap = cfg->reg; + struct device *clk; + int ret, i, j; + + for (i = 0; i < PLL_ID_MAX; i++) { + for (j = 0; j < 3; j++) { + const struct device *parent_hw; + + if (!sama7d65_plls[i][j].n) { + continue; + } + + switch (sama7d65_plls[i][j].t) { + case PLL_TYPE_FRAC: + switch (sama7d65_plls[i][j].p) { + case SAMA7D65_PLL_PARENT_MAINCK: + parent_hw = sama7d65_pmc->chws[PMC_MAIN]; + break; + case SAMA7D65_PLL_PARENT_MAIN_XTAL: + parent_hw = cfg->main_xtal; + break; + default: + /* Should not happen. */ + parent_hw = NULL; + break; + } + + ret = sam9x60_clk_register_frac_pll(regmap, + &pmc_pll_lock, + sama7d65_plls[i][j].n, + parent_hw, i, + sama7d65_plls[i][j].c, + sama7d65_plls[i][j].l, + &clk); + break; + + case PLL_TYPE_DIV: + ret = sam9x60_clk_register_div_pll(regmap, + &pmc_pll_lock, + sama7d65_plls[i][j].n, + sama7d65_plls[i][0].clk, i, + sama7d65_plls[i][j].c, + sama7d65_plls[i][j].l, + &clk); + break; + + default: + continue; + } + + if (ret) { + LOG_ERR("Register clock %s failed.", sama7d65_plls[i][j].n); + return ret; + } + + sama7d65_plls[i][j].clk = clk; + if (sama7d65_plls[i][j].eid) { + sama7d65_pmc->chws[sama7d65_plls[i][j].eid] = clk; + } + } + } + + return 0; +} + +static int sam_pmc_register_mckx(const struct device *dev, struct pmc_data *sama7d65_pmc) +{ + const struct sam_pmc_cfg *cfg = dev->config; + const struct device *parents[10]; + void *const regmap = cfg->reg; + uint32_t mux_table[8]; + struct device *clk; + int ret = 0; + int i, j; + + ret = clk_register_master_div(regmap, "mck0", sama7d65_plls[PLL_ID_CPU][1].clk, + &mck0_layout, &mck0_characteristics, &pmc_mck0_lock, 5, &clk); + if (ret) { + LOG_ERR("Register MCK0 clock failed."); + return ret; + } + sama7d65_mckx[PCK_PARENT_HW_MCK0].clk = sama7d65_pmc->chws[PMC_MCK] = clk; + + parents[0] = cfg->md_slck; + parents[1] = cfg->td_slck; + parents[2] = sama7d65_pmc->chws[PMC_MAIN]; + for (i = PCK_PARENT_HW_MCK1; i < ARRAY_SIZE(sama7d65_mckx); i++) { + uint8_t num_parents = 3 + sama7d65_mckx[i].ep_count; + struct device *tmp_parent_hws[8]; + + if (num_parents > ARRAY_SIZE(mux_table)) { + LOG_ERR("Array for mux table not enough"); + return -ENOMEM; + } + + SAMA7D65_INIT_TABLE(mux_table, 3); + SAMA7D65_FILL_TABLE(&mux_table[3], sama7d65_mckx[i].ep_mux_table, + sama7d65_mckx[i].ep_count); + for (j = 0; j < sama7d65_mckx[i].ep_count; j++) { + uint8_t pll_id = sama7d65_mckx[i].ep[j].pll_id; + uint8_t pll_compid = sama7d65_mckx[i].ep[j].pll_compid; + + tmp_parent_hws[j] = sama7d65_plls[pll_id][pll_compid].clk; + } + SAMA7D65_FILL_TABLE(&parents[3], tmp_parent_hws, sama7d65_mckx[i].ep_count); + + ret = clk_register_master(regmap, sama7d65_mckx[i].n, num_parents, parents, + mux_table, &pmc_mckX_lock, sama7d65_mckx[i].id, &clk); + if (ret) { + LOG_ERR("Register MCK%d clock failed.", i); + return ret; + } + + sama7d65_mckx[i].clk = clk; + if (sama7d65_mckx[i].eid) { + sama7d65_pmc->chws[sama7d65_mckx[i].eid] = clk; + } + } + + return 0; +} + +static int sam_pmc_register_generated(const struct device *dev, struct pmc_data *sama7d65_pmc) +{ + const struct sam_pmc_cfg *cfg = dev->config; + const struct device *parents[10]; + void *const regmap = cfg->reg; + uint32_t mux_table[8]; + struct device *clk; + int ret = 0; + int i, j; + + parents[0] = cfg->md_slck; + parents[1] = cfg->td_slck; + parents[2] = sama7d65_pmc->chws[PMC_MAIN]; + parents[3] = sama7d65_pmc->chws[PMC_MCK1]; + for (i = 0; i < ARRAY_SIZE(sama7d65_gck); i++) { + uint8_t num_parents = 4 + sama7d65_gck[i].pp_count; + struct device *tmp_parent_hws[8]; + + if (num_parents > ARRAY_SIZE(mux_table)) { + LOG_ERR("Array for mux table not enough"); + return -ENOMEM; + } + + SAMA7D65_INIT_TABLE(mux_table, 4); + SAMA7D65_FILL_TABLE(&mux_table[4], sama7d65_gck[i].pp_mux_table, + sama7d65_gck[i].pp_count); + for (j = 0; j < sama7d65_gck[i].pp_count; j++) { + uint8_t pll_id = sama7d65_gck[i].pp[j].pll_id; + uint8_t pll_compid = sama7d65_gck[i].pp[j].pll_compid; + + tmp_parent_hws[j] = sama7d65_plls[pll_id][pll_compid].clk; + } + SAMA7D65_FILL_TABLE(&parents[4], tmp_parent_hws, sama7d65_gck[i].pp_count); + + ret = clk_register_generated(regmap, &pmc_pcr_lock, + &sama7d65_pcr_layout, + sama7d65_gck[i].n, + parents, mux_table, + num_parents, + sama7d65_gck[i].id, + &sama7d65_gck[i].r, + sama7d65_gck[i].pp_chg_id, &clk); + if (ret) { + LOG_ERR("Register generated clock failed."); + return ret; + } + sama7d65_pmc->ghws[sama7d65_gck[i].id] = clk; + } + + return 0; +} + +void sam_pmc_setup(const struct device *dev) +{ + const struct sam_pmc_cfg *cfg = dev->config; + struct sam_pmc_data *data = dev->data; + const struct device *main_xtal = cfg->main_xtal; + const struct device *td_slck = cfg->td_slck; + const struct device *md_slck = cfg->md_slck; + + void *const regmap = cfg->reg; + const struct device *parents[10]; + struct pmc_data *sama7d65_pmc; + struct device *clk, *main_rc, *main_osc; + + uint32_t rate, bypass; + int ret, i; + + if (!td_slck || !md_slck || !main_xtal || !regmap) { + LOG_ERR("Incorrect parameters."); + return; + } + + if (CLK_CNT_SYSTEM != nck(sama7d65_systemck) || + CLK_CNT_PERIPH != nck(sama7d65_periphck) || + CLK_CNT_GCK != nck(sama7d65_gck)) { + LOG_ERR("Incorrect definitions could make array for pmc clocks not enough"); + return; + } + + sama7d65_pmc = pmc_data_allocate(PMC_MCK5 + 1, nck(sama7d65_systemck), + nck(sama7d65_periphck), nck(sama7d65_gck), + SOC_NUM_CLOCK_PROGRAMMABLE, &pmc_table[0]); + if (!sama7d65_pmc) { + LOG_ERR("allocate PMC data failed."); + return; + } + data->pmc = sama7d65_pmc; + + ret = clk_register_main_rc_osc(regmap, "main_rc_osc", MHZ(12), &main_rc); + if (ret) { + LOG_ERR("Register clock main_rc_osc failed."); + return; + } + + if (clock_control_get_rate(main_xtal, NULL, &rate)) { + LOG_ERR("get clock rate of main_xtal failed."); + return; + } + + bypass = 0; + ret = clk_register_main_osc(regmap, "main_osc", bypass, rate, &main_osc); + if (ret) { + LOG_ERR("Register clock main_osc failed."); + return; + } + + parents[0] = main_rc; + parents[1] = main_osc; + ret = clk_register_main(regmap, "mainck", parents, 2, &clk); + if (ret) { + LOG_ERR("Register clock mainck failed."); + return; + } + + sama7d65_pmc->chws[PMC_MAIN] = clk; + + ret = sam_pmc_register_pll(dev, sama7d65_pmc); + if (ret) { + return; + } + + ret = sam_pmc_register_mckx(dev, sama7d65_pmc); + if (ret) { + return; + } + + parents[0] = md_slck; + parents[1] = td_slck; + parents[2] = sama7d65_pmc->chws[PMC_MAIN]; + parents[3] = sama7d65_plls[PLL_ID_SYS][PLL_COMPID_DIV0].clk; + parents[4] = sama7d65_plls[PLL_ID_DDR][PLL_COMPID_DIV0].clk; + parents[5] = sama7d65_plls[PLL_ID_GPU][PLL_COMPID_DIV0].clk; + parents[6] = sama7d65_plls[PLL_ID_BAUD][PLL_COMPID_DIV0].clk; + parents[7] = sama7d65_plls[PLL_ID_AUDIO][PLL_COMPID_DIV0].clk; + parents[8] = sama7d65_plls[PLL_ID_ETH][PLL_COMPID_DIV0].clk; + for (i = 0; i < 8; i++) { + ret = clk_register_programmable(regmap, parents, 9, i, &programmable_layout, + sama7d65_prog_mux_table, &clk); + if (ret) { + LOG_ERR("Register programmable clock %d failed.", i); + return; + } + + sama7d65_pmc->pchws[i] = clk; + } + + for (i = 0; i < ARRAY_SIZE(sama7d65_systemck); i++) { + ret = clk_register_system(regmap, sama7d65_systemck[i].n, + sama7d65_pmc->pchws[i], + sama7d65_systemck[i].id, &clk); + if (ret) { + LOG_ERR("Register system clock %d failed.", i); + return; + } + + sama7d65_pmc->shws[sama7d65_systemck[i].id] = clk; + } + + for (i = 0; i < ARRAY_SIZE(sama7d65_periphck); i++) { + clk = sama7d65_mckx[sama7d65_periphck[i].p].clk; + ret = clk_register_peripheral(regmap, &pmc_pcr_lock, + &sama7d65_pcr_layout, + sama7d65_periphck[i].n, + clk, + sama7d65_periphck[i].id, + &sama7d65_periphck[i].r, + &clk); + if (ret) { + LOG_ERR("Register peripheral clock failed."); + return; + } + sama7d65_pmc->phws[sama7d65_periphck[i].id] = clk; + } + + ret = sam_pmc_register_generated(dev, sama7d65_pmc); + if (ret) { + return; + } + + LOG_DBG("Register PMC clocks successfully."); +} From efef71d2e6a3a2ec9eea57649291b4f7954894fb Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 1 Jul 2025 14:15:10 +0800 Subject: [PATCH 082/397] boards: microchip: add new board sama7d65 Curiosity Kit Product URL: https://www.microchip.com/en-us/development-tool/EV63J76A Signed-off-by: Tony Han --- .../Kconfig.sama7d65_curiosity | 7 ++ .../sam/sama7d65_curiosity/board.yml | 6 + .../doc/img/sama7d65_curiosity.webp | Bin 0 -> 56576 bytes .../sam/sama7d65_curiosity/doc/index.rst | 109 ++++++++++++++++++ .../sama7d65_curiosity/sama7d65_curiosity.dts | 64 ++++++++++ .../sama7d65_curiosity.yaml | 16 +++ .../sama7d65_curiosity_defconfig | 9 ++ 7 files changed, 211 insertions(+) create mode 100644 boards/microchip/sam/sama7d65_curiosity/Kconfig.sama7d65_curiosity create mode 100644 boards/microchip/sam/sama7d65_curiosity/board.yml create mode 100644 boards/microchip/sam/sama7d65_curiosity/doc/img/sama7d65_curiosity.webp create mode 100644 boards/microchip/sam/sama7d65_curiosity/doc/index.rst create mode 100644 boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.dts create mode 100644 boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.yaml create mode 100644 boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity_defconfig diff --git a/boards/microchip/sam/sama7d65_curiosity/Kconfig.sama7d65_curiosity b/boards/microchip/sam/sama7d65_curiosity/Kconfig.sama7d65_curiosity new file mode 100644 index 0000000000000..5556c4d81b09f --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/Kconfig.sama7d65_curiosity @@ -0,0 +1,7 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_SAMA7D65_CURIOSITY + select SOC_SAMA7D65 diff --git a/boards/microchip/sam/sama7d65_curiosity/board.yml b/boards/microchip/sam/sama7d65_curiosity/board.yml new file mode 100644 index 0000000000000..324e86c23c1c3 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/board.yml @@ -0,0 +1,6 @@ +board: + name: sama7d65_curiosity + full_name: SAMA7D65 Curiosity Kit + vendor: microchip + socs: + - name: sama7d65 diff --git a/boards/microchip/sam/sama7d65_curiosity/doc/img/sama7d65_curiosity.webp b/boards/microchip/sam/sama7d65_curiosity/doc/img/sama7d65_curiosity.webp new file mode 100644 index 0000000000000000000000000000000000000000..a0d44e8e3a850462e44726fb71ced7863ac5813a GIT binary patch literal 56576 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 literal 0 HcmV?d00001 diff --git a/boards/microchip/sam/sama7d65_curiosity/doc/index.rst b/boards/microchip/sam/sama7d65_curiosity/doc/index.rst new file mode 100644 index 0000000000000..f374b1f2fdd99 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/doc/index.rst @@ -0,0 +1,109 @@ +.. zephyr:board:: sama7d65_curiosity + +Overview +******** + +The EV63J76A (SAMA7D65 Curiosity Kit) is a development kit for evaluating and +prototyping with Microchip SAMA7D65 microprocessor (MPU). The SAMA7D65 MPU is a +high-performance ARM Cortex-A7 CPU-based embedded MPU running up to 1GHz. + +The board allows evaluation of powerful peripherals for connectivity, audio and +user interface applications, including MIPI-DSI and LVDS w/ 2D graphics, dual +Gigabit Ethernet w/ TSN and CAN-FD. The MPUs offer advanced security functions, +like tamper detection, secure boot, secure key stoarge, TRNG, PUF as well as +higher-performance crypto accelerators for AES and SHA. + +The SAMA7D65 series is supported by Microchip MPLAB-X development tools, Harmony +V3, Linux distributions and Microchip Graphic Suite (MGS) for Linux. The +SAMA7D65 is well-suited for industrial and automotive applications with +graphical displays support up to WXGA/720p. + +Hardware +******** +EV63J76A provides the following hardware components: + +- Processor + + - Microchip SAMA7D65-V/4HB (SoC 343-ball TFBGA, 14x14 mm, 0.65 mm pitch) + +- Memory + + - 8 Gb DDR3L (AS4C512M16D3LA-10BIN) + - 64 Mb QSPI NOR Flash with EUI-48 (Microchip SST26VF064BEUI-104I/MF) + - 4Gbit SLC NAND Flash (MX30LF4G28AD-XKI) + - 2Kb EEPROM with EUI-48 (Microchip 24AA025E48) + +- SD/MMC + + - One SD card socket, 4 bit + - One M.2 Radio Module interface, SDIO I/F + +- USB + + - One device USB Type-C connector + - Two host USB Type-A connectors (Microchip MIC2026-1YM) + +- Ethernet + + - One 10/100/1000 RGMII on board + - One 10/100/1000 RGMII SODIMM add-on slot (Microchip LAN8840-V/PSA) + +- Display + + - One MIPI-DSI 34-pin FPC connector + - One LVDS 30-pin FPC connector + +- Debug port + + - One UART Debug connector + - One JTAG interface + +- User interaction + + - One RGB (Red, Green, Blue) LED + - Four push button switches + +- CAN-FD + + - Three onboard CAN-FD transceivers + - Two interfaces available on mikroBUS slots + +- Expansion + + - Raspberry Pi 40-pin GPIO connector + - Two mikroBUS™ connectors + - Two PIOBU/System headers + +- Power management + + - Power Supply Unit (Microchip MCP16502TAB-E/S8B) + - Power Monitoring (Microchip PAC1934) + - Daughter cards power supply (Microchip MIC23450-AAAYML-TR) + - Backup power supply (CR1220 battery holder) + +- Board supply + + - System 5 VDC from USB Type-C + - System 5 VDC from DC Jack + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Connections and IOs +=================== + +The `SAMA7D65-Curiosity Kit User Guide`_ has detailed information about board connections. + +References +********** + +SAMA7D65 Product Page: + https://www.microchip.com/en-us/product/sama7d65 + +SAMA7D65 Curiosity Kit Page: + https://www.microchip.com/en-us/development-tool/EV63J76A + +.. _SAMA7D65-Curiosity Kit User Guide: + https://ww1.microchip.com/downloads/aemDocuments/documents/MPU32/ProductDocuments/UserGuides/SAMA7D65-Curiosity-Kit-User-Guide-DS50003806.pdf diff --git a/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.dts b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.dts new file mode 100644 index 0000000000000..8761d5037ddf1 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.dts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "SAMA7D65-Curiosity board"; + compatible = "microchip,sama7d65curiosity", "microchip,sama7d6", "microchip,sama7"; + + chosen { + zephyr,sram = &ddram; + zephyr,console = &uart6; + zephyr,shell-uart = &uart6; + }; + + clocks { + main_xtal { + clock-frequency = ; + }; + + slow_xtal { + clock-frequency = <32768>; + }; + }; + + ddram: ddram@60000000 { + compatible = "ddram"; + reg = <0x60000000 DT_SIZE_M(1024)>; + }; +}; + +&flx6 { + mchp,flexcom-mode = ; + status = "okay"; + + uart6: serial@200 { + current-speed = <115200>; + pinctrl-0 = <&pinctrl_uart6_default>; + pinctrl-names = "default"; + status = "okay"; + }; +}; + +&pinctrl { + pinctrl_uart6_default: uart6-default { + group1 { + pinmux = , + ; + bias-disable; + }; + }; +}; + +&pit64b0 { + clock-frequency = ; +}; diff --git a/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.yaml b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.yaml new file mode 100644 index 0000000000000..312766bb65dd1 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.yaml @@ -0,0 +1,16 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# SPDX-License-Identifier: Apache-2.0 + +identifier: sama7d65_curiosity +name: SAMA7D65 Curiosity Kit +type: mcu +arch: arm +toolchain: + - zephyr +ram: 128 +supported: + - i2c + - pinctrl + - shell + - uart +vendor: microchip diff --git a/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity_defconfig b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity_defconfig new file mode 100644 index 0000000000000..10b06d0f7f423 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity_defconfig @@ -0,0 +1,9 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y From 32dc68584aa7ceeaf1f2dcb20a1a018de91f784c Mon Sep 17 00:00:00 2001 From: Tony Han Date: Thu, 17 Apr 2025 18:20:29 +0800 Subject: [PATCH 083/397] dts: arm: microchip: sama7g5: add DMA Controller (XDMAC) support Add dma nodes to sama7g5.dtsi file. Signed-off-by: Tony Han --- dts/arm/microchip/sam/sama7g5.dtsi | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dts/arm/microchip/sam/sama7g5.dtsi b/dts/arm/microchip/sam/sama7g5.dtsi index 65064d1502033..e067dffbafad5 100644 --- a/dts/arm/microchip/sam/sama7g5.dtsi +++ b/dts/arm/microchip/sam/sama7g5.dtsi @@ -46,6 +46,39 @@ #clock-cells = <1>; }; + dma0: dma-controller@e2808000 { + compatible = "atmel,sam-xdmac"; + reg = <0xe2808000 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + #dma-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 22>; + clock-names = "dma_clk"; + status = "disabled"; + }; + + dma1: dma-controller@e280c000 { + compatible = "atmel,sam-xdmac"; + reg = <0xe280c000 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + #dma-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 23>; + clock-names = "dma_clk"; + status = "disabled"; + }; + + dma2: dma-controller@e1200000 { + compatible = "atmel,sam-xdmac"; + reg = <0xe1200000 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + #dma-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 24>; + clock-names = "dma_clk"; + status = "disabled"; + }; + flx0: flexcom@e1818000 { compatible = "microchip,sam-flexcom"; reg = <0xe1818000 0x200>; From 0575a133b7919ec0a0502073b2134ebbca278c5b Mon Sep 17 00:00:00 2001 From: Tony Han Date: Fri, 20 Jun 2025 10:56:54 +0800 Subject: [PATCH 084/397] soc: microchip: sam: enable CACHE_MANAGEMENT for sama7g5 series Enable cache manamegent for sama7g5 series. Signed-off-by: Tony Han --- soc/microchip/sam/sama7g5/Kconfig.defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/microchip/sam/sama7g5/Kconfig.defconfig b/soc/microchip/sam/sama7g5/Kconfig.defconfig index dd102f1621cc6..067cabe8f301f 100644 --- a/soc/microchip/sam/sama7g5/Kconfig.defconfig +++ b/soc/microchip/sam/sama7g5/Kconfig.defconfig @@ -14,4 +14,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config MMU default y +config CACHE_MANAGEMENT + default y + endif # SOC_SERIES_SAMA7G5 From 41192d1f85d6d7027e57d4f95ee5ae3b7cb320b7 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Fri, 20 Jun 2025 10:48:43 +0800 Subject: [PATCH 085/397] soc: microchip: sam: update MMU for sama7g5 XDMAC When the XDMAC is activated in the DT, configure it's register region with strong ordered, read and write access. Signed-off-by: Tony Han --- soc/microchip/sam/sama7g5/soc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/soc/microchip/sam/sama7g5/soc.c b/soc/microchip/sam/sama7g5/soc.c index e468b6fc33635..005300968f051 100644 --- a/soc/microchip/sam/sama7g5/soc.c +++ b/soc/microchip/sam/sama7g5/soc.c @@ -15,6 +15,11 @@ MT_STRONGLY_ORDERED | MPERM_R | MPERM_W),), \ ()) +#define MMU_REGION_XDMAC_DEFN(idx, n) \ + IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(dma##n)), \ + (MMU_REGION_FLAT_ENTRY("xdmac"#n, XDMAC##n##_BASE_ADDRESS, 0x4000, \ + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W),)) + static const struct arm_mmu_region mmu_regions[] = { MMU_REGION_FLAT_ENTRY("vectors", CONFIG_KERNEL_VM_BASE, 0x1000, MT_STRONGLY_ORDERED | MPERM_R | MPERM_X), @@ -49,6 +54,8 @@ static const struct arm_mmu_region mmu_regions[] = { IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(trng)), (MMU_REGION_FLAT_ENTRY("trng", TRNG_BASE_ADDRESS, 0x100, MT_STRONGLY_ORDERED | MPERM_R | MPERM_W),)) + + FOR_EACH_IDX(MMU_REGION_XDMAC_DEFN, (), 0, 1, 2) }; const struct arm_mmu_config mmu_config = { From aae399dbead4ea0bf7dec174f1404ea3fca4495b Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 11:13:25 +0800 Subject: [PATCH 086/397] drivers: dma: sam: update to support multiple DMA instances This update xdmac driver to support multiple DMA instancess. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 436991a482af2..5270bead45923 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -407,23 +407,24 @@ static DEVICE_API(dma, sam_xdmac_driver_api) = { .get_status = sam_xdmac_get_status, }; -/* DMA0 */ - -static void dma0_sam_irq_config(void) -{ - IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), sam_xdmac_isr, - DEVICE_DT_INST_GET(0), 0); -} - -static const struct sam_xdmac_dev_cfg dma0_sam_config = { - .regs = (Xdmac *)DT_INST_REG_ADDR(0), - .irq_config = dma0_sam_irq_config, - .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(0), - .irq_id = DT_INST_IRQN(0), -}; - -static struct sam_xdmac_dev_data dma0_sam_data; - -DEVICE_DT_INST_DEFINE(0, sam_xdmac_initialize, NULL, - &dma0_sam_data, &dma0_sam_config, POST_KERNEL, - CONFIG_DMA_INIT_PRIORITY, &sam_xdmac_driver_api); +#define DMA_INIT(n) \ + static void dma##n##_irq_config(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + sam_xdmac_isr, DEVICE_DT_INST_GET(n), 0); \ + } \ + \ + static const struct sam_xdmac_dev_cfg dma##n##_config = { \ + .regs = (Xdmac *)DT_INST_REG_ADDR(n), \ + .irq_config = dma##n##_irq_config, \ + .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n), \ + .irq_id = DT_INST_IRQN(n), \ + }; \ + \ + static struct sam_xdmac_dev_data dma##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &sam_xdmac_initialize, NULL, \ + &dma##n##_data, &dma##n##_config, POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, &sam_xdmac_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DMA_INIT) From 38ac1204ed5c546c9ebd1729ebd6c45b5d5b53e7 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 11:28:54 +0800 Subject: [PATCH 087/397] drivers: dma: sam: support different num of channels for each instance As the number of DMA channels could be different between DMA instances, get the number from "XDMAC Global Type Register" and validate the channel used. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 47 +++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 5270bead45923..ec57702d26b12 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -26,7 +26,7 @@ LOG_MODULE_REGISTER(dma_sam_xdmac); #define XDMAC_INT_ERR (XDMAC_CIE_RBIE | XDMAC_CIE_WBIE | XDMAC_CIE_ROIE) -#define DMA_CHANNELS_NO XDMACCHID_NUMBER +#define DMA_CHANNELS_MAX 31 /* DMA channel configuration */ struct sam_xdmac_channel_cfg { @@ -45,13 +45,15 @@ struct sam_xdmac_dev_cfg { /* Device run time data */ struct sam_xdmac_dev_data { - struct sam_xdmac_channel_cfg dma_channels[DMA_CHANNELS_NO]; + struct dma_context dma_ctx; + struct sam_xdmac_channel_cfg dma_channels[DMA_CHANNELS_MAX + 1]; }; static void sam_xdmac_isr(const struct device *dev) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = dev_cfg->regs; struct sam_xdmac_channel_cfg *channel_cfg; @@ -61,7 +63,7 @@ static void sam_xdmac_isr(const struct device *dev) /* Get global interrupt status */ isr_status = xdmac->XDMAC_GIS; - for (int channel = 0; channel < DMA_CHANNELS_NO; channel++) { + for (int channel = 0; channel < channel_num; channel++) { if (!(isr_status & (1 << channel))) { continue; } @@ -83,10 +85,13 @@ int sam_xdmac_channel_configure(const struct device *dev, uint32_t channel, struct sam_xdmac_channel_config *param) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = dev_cfg->regs; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -126,10 +131,13 @@ int sam_xdmac_transfer_configure(const struct device *dev, uint32_t channel, struct sam_xdmac_transfer_config *param) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = dev_cfg->regs; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -179,13 +187,15 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, struct dma_config *cfg) { struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; struct sam_xdmac_channel_config channel_cfg; struct sam_xdmac_transfer_config transfer_cfg; uint32_t burst_size; uint32_t data_size; int ret; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -300,11 +310,13 @@ static int sam_xdmac_transfer_reload(const struct device *dev, uint32_t channel, int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel) { const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = config->regs; - if (channel >= DMA_CHANNELS_NO) { - LOG_DBG("Channel %d out of range", channel); + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -325,10 +337,13 @@ int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel) int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel) { const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = config->regs; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -352,9 +367,16 @@ int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel) static int sam_xdmac_initialize(const struct device *dev) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; Xdmac * const xdmac = dev_cfg->regs; + dev_data->dma_ctx.dma_channels = FIELD_GET(XDMAC_GTYPE_NB_CH_Msk, xdmac->XDMAC_GTYPE) + 1; + if (dev_data->dma_ctx.dma_channels > DMA_CHANNELS_MAX + 1) { + LOG_ERR("Maximum supported channels is %d", DMA_CHANNELS_MAX + 1); + return -EINVAL; + } + /* Configure interrupts */ dev_cfg->irq_config(); @@ -421,7 +443,12 @@ static DEVICE_API(dma, sam_xdmac_driver_api) = { .irq_id = DT_INST_IRQN(n), \ }; \ \ - static struct sam_xdmac_dev_data dma##n##_data; \ + static ATOMIC_DEFINE(dma_channels_atomic_##n, DMA_CHANNELS_MAX); \ + \ + static struct sam_xdmac_dev_data dma##n##_data = { \ + .dma_ctx.magic = DMA_MAGIC, \ + .dma_ctx.atomic = dma_channels_atomic_##n, \ + }; \ \ DEVICE_DT_INST_DEFINE(n, &sam_xdmac_initialize, NULL, \ &dma##n##_data, &dma##n##_config, POST_KERNEL, \ From 84dbd7e892736809fb96c6f87a8e9e01ccce2537 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 14:06:51 +0800 Subject: [PATCH 088/397] drivers: dma: sam: update to support sama7g5 XDMAC peripheral Update the driver to support sama7g5 XDMAC peripheral. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index ec57702d26b12..42b7ccb375493 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -243,6 +243,10 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, | XDMAC_CC_MBSIZE(burst_size == 0U ? 0 : burst_size - 1) | XDMAC_CC_SAM_INCREMENTED_AM | XDMAC_CC_DAM_INCREMENTED_AM; +#if defined(CONFIG_SOC_SERIES_SAMA7G5) + /* When a memory-to-memory transfer is performed, configure PERID to 0x7F. */ + cfg->dma_slot = 0x7F; +#endif break; case MEMORY_TO_PERIPHERAL: channel_cfg.cfg = @@ -264,11 +268,14 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, return -EINVAL; } - channel_cfg.cfg |= - XDMAC_CC_DWIDTH(data_size) - | XDMAC_CC_SIF_AHB_IF1 - | XDMAC_CC_DIF_AHB_IF1 - | XDMAC_CC_PERID(cfg->dma_slot); + channel_cfg.cfg |= XDMAC_CC_DWIDTH(data_size) | +#ifdef XDMAC_CC_SIF_AHB_IF1 + XDMAC_CC_SIF_AHB_IF1 | +#endif +#ifdef XDMAC_CC_DIF_AHB_IF1 + XDMAC_CC_DIF_AHB_IF1 | +#endif + XDMAC_CC_PERID(cfg->dma_slot); channel_cfg.ds_msp = 0U; channel_cfg.sus = 0U; channel_cfg.dus = 0U; From 0b5cb49fbf1b4b1d65b90448c30d8f28c79d46b4 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 14:41:19 +0800 Subject: [PATCH 089/397] drivers: dma: sam: add DMA channel suspend and resume support Add support for XDMA channel read write suspend and read write resume. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 42b7ccb375493..73efb2dd7a7eb 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -404,6 +404,74 @@ static int sam_xdmac_initialize(const struct device *dev) return 0; } +static int xdmac_suspend(const struct device *dev, uint32_t channel) +{ + const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; + + Xdmac * const xdmac = config->regs; + + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); + return -EINVAL; + } + + if (!(xdmac->XDMAC_GS & BIT(channel))) { + LOG_DBG("Channel %d not enabled", channel); + return -EINVAL; + } + +#if defined(CONFIG_SOC_SERIES_SAMX7X) + if (xdmac->XDMAC_GRS & BIT(channel) || xdmac->XDMAC_GWS & BIT(channel)) { +#elif defined(CONFIG_SOC_SERIES_SAMA7G5) + if (xdmac->XDMAC_GRSS & BIT(channel) || xdmac->XDMAC_GWSS & BIT(channel)) { +#else +#error Unsupported SoC family +#endif + LOG_DBG("Channel %d already suspended", channel); + return 0; + } + + xdmac->XDMAC_GRWS |= BIT(channel); + + return 0; +} + +static int xdmac_resume(const struct device *dev, uint32_t channel) +{ + const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; + + Xdmac * const xdmac = config->regs; + + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); + return -EINVAL; + } + + if (!(xdmac->XDMAC_GS & BIT(channel))) { + LOG_DBG("Channel %d not enabled", channel); + return -EINVAL; + } + +#if defined(CONFIG_SOC_SERIES_SAMX7X) + if (!(xdmac->XDMAC_GRS & BIT(channel) || xdmac->XDMAC_GWS & BIT(channel))) { +#elif defined(CONFIG_SOC_SERIES_SAMA7G5) + if (!(xdmac->XDMAC_GRSS & BIT(channel) || xdmac->XDMAC_GWSS & BIT(channel))) { +#else +#error Unsupported SoC family +#endif + LOG_DBG("Channel %d not suspended", channel); + return 0; + } + + xdmac->XDMAC_GRWR |= BIT(channel); + + return 0; +} + static int sam_xdmac_get_status(const struct device *dev, uint32_t channel, struct dma_status *status) { @@ -433,6 +501,8 @@ static DEVICE_API(dma, sam_xdmac_driver_api) = { .reload = sam_xdmac_transfer_reload, .start = sam_xdmac_transfer_start, .stop = sam_xdmac_transfer_stop, + .suspend = xdmac_suspend, + .resume = xdmac_resume, .get_status = sam_xdmac_get_status, }; From bb712fe5437e4b1adbcaaf99ef67cdeb0b9ddb83 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Wed, 16 Jul 2025 13:53:48 +0800 Subject: [PATCH 090/397] drivers: dma: sam: implement finite state machine for DMA channel Add state machine for config/start/stop/resume/suspend for DMA channels. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 73efb2dd7a7eb..eff294c6481e4 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -28,11 +28,19 @@ LOG_MODULE_REGISTER(dma_sam_xdmac); #define XDMAC_INT_ERR (XDMAC_CIE_RBIE | XDMAC_CIE_WBIE | XDMAC_CIE_ROIE) #define DMA_CHANNELS_MAX 31 +enum dma_state { + DMA_STATE_INIT = 0, + DMA_STATE_CONFIGURED, + DMA_STATE_RUNNING, + DMA_STATE_SUSPENDED, +}; + /* DMA channel configuration */ struct sam_xdmac_channel_cfg { void *user_data; dma_callback_t callback; uint32_t data_size; + enum dma_state state; }; /* Device constant configuration parameters */ @@ -68,6 +76,7 @@ static void sam_xdmac_isr(const struct device *dev) continue; } + dev_data->dma_channels[channel].state = DMA_STATE_CONFIGURED; channel_cfg = &dev_data->dma_channels[channel]; /* Get channel errors */ @@ -180,6 +189,8 @@ int sam_xdmac_transfer_configure(const struct device *dev, uint32_t channel, /* Set next descriptor configuration */ xdmac->XDMAC_CHID[channel].XDMAC_CNDC = param->ndc; + dev_data->dma_channels[channel].state = DMA_STATE_CONFIGURED; + return 0; } @@ -199,6 +210,12 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, return -EINVAL; } + if (dev_data->dma_channels[channel].state != DMA_STATE_INIT && + dev_data->dma_channels[channel].state != DMA_STATE_CONFIGURED) { + LOG_ERR("Config Channel %d at invalidate state", channel); + return -EINVAL; + } + __ASSERT_NO_MSG(cfg->source_data_size == cfg->dest_data_size); __ASSERT_NO_MSG(cfg->source_burst_length == cfg->dest_burst_length); @@ -327,6 +344,12 @@ int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel) return -EINVAL; } + if (dev_data->dma_channels[channel].state != DMA_STATE_CONFIGURED && + dev_data->dma_channels[channel].state != DMA_STATE_RUNNING) { + LOG_ERR("Start Channel %d at invalidate state", channel); + return -EINVAL; + } + /* Check if the channel is enabled */ if (xdmac->XDMAC_GS & (XDMAC_GS_ST0 << channel)) { LOG_DBG("Channel %d already enabled", channel); @@ -338,6 +361,8 @@ int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel) /* Enable channel */ xdmac->XDMAC_GE = XDMAC_GE_EN0 << channel; + dev_data->dma_channels[channel].state = DMA_STATE_RUNNING; + return 0; } @@ -354,6 +379,11 @@ int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel) return -EINVAL; } + if (dev_data->dma_channels[channel].state == DMA_STATE_INIT) { + LOG_ERR("Channel %d not configured", channel); + return -EINVAL; + } + /* Check if the channel is enabled */ if (!(xdmac->XDMAC_GS & (XDMAC_GS_ST0 << channel))) { return 0; @@ -368,6 +398,8 @@ int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel) /* Clear the pending Interrupt Status bit(s) */ (void)xdmac->XDMAC_CHID[channel].XDMAC_CIS; + dev_data->dma_channels[channel].state = DMA_STATE_CONFIGURED; + return 0; } @@ -417,6 +449,16 @@ static int xdmac_suspend(const struct device *dev, uint32_t channel) return -EINVAL; } + switch (dev_data->dma_channels[channel].state) { + case DMA_STATE_RUNNING: + break; + case DMA_STATE_SUSPENDED: + return 0; + default: + LOG_ERR("Suspend Channel %d at invalidate state", channel); + return -EINVAL; + } + if (!(xdmac->XDMAC_GS & BIT(channel))) { LOG_DBG("Channel %d not enabled", channel); return -EINVAL; @@ -435,6 +477,8 @@ static int xdmac_suspend(const struct device *dev, uint32_t channel) xdmac->XDMAC_GRWS |= BIT(channel); + dev_data->dma_channels[channel].state = DMA_STATE_SUSPENDED; + return 0; } @@ -451,6 +495,16 @@ static int xdmac_resume(const struct device *dev, uint32_t channel) return -EINVAL; } + switch (dev_data->dma_channels[channel].state) { + case DMA_STATE_SUSPENDED: + break; + case DMA_STATE_RUNNING: + return 0; + default: + LOG_ERR("Resume Channel %d at invalidate state", channel); + return -EINVAL; + } + if (!(xdmac->XDMAC_GS & BIT(channel))) { LOG_DBG("Channel %d not enabled", channel); return -EINVAL; @@ -469,6 +523,8 @@ static int xdmac_resume(const struct device *dev, uint32_t channel) xdmac->XDMAC_GRWR |= BIT(channel); + dev_data->dma_channels[channel].state = DMA_STATE_RUNNING; + return 0; } From d978bb1230b420a78a649080b78be4953d0b3f13 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Thu, 17 Apr 2025 18:20:29 +0800 Subject: [PATCH 091/397] boards: microchip: sama7g5: add DMA to sama7g54-ek dts and yaml files Add DMA nodes to sama7g54_ek.dts files. Add DMA to sama7g54_ek.yaml support list. Signed-off-by: Tony Han --- boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts | 12 ++++++++++++ boards/microchip/sam/sama7g54_ek/sama7g54_ek.yaml | 1 + 2 files changed, 13 insertions(+) diff --git a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts index e6a3879bf2112..c918f4c03a193 100644 --- a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts +++ b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts @@ -94,6 +94,18 @@ }; }; +&dma0 { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dma2 { + status = "okay"; +}; + &flx3 { mchp,flexcom-mode = ; status = "okay"; diff --git a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.yaml b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.yaml index 4174a0606b3ba..7b463c5a7fe10 100644 --- a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.yaml +++ b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.yaml @@ -9,6 +9,7 @@ toolchain: - zephyr ram: 128 supported: + - dma - entropy - pwm - sdhc From 682694c67d4603ea9167cd28296599bc7f8f7527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Tue, 21 Oct 2025 16:46:45 +0200 Subject: [PATCH 092/397] doc: samples: drivers: clock_control: fix dts include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix dts include for doc Signed-off-by: Fin Maaß --- samples/drivers/clock_control_litex/README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/drivers/clock_control_litex/README.rst b/samples/drivers/clock_control_litex/README.rst index c32ecb27767f6..1d29f7e14730a 100644 --- a/samples/drivers/clock_control_litex/README.rst +++ b/samples/drivers/clock_control_litex/README.rst @@ -20,19 +20,19 @@ Configuration ************* Basic configuration of the driver, including default settings for clock outputs, is held in Device Tree clock control nodes. -.. literalinclude:: ../../../dts/riscv/riscv32-litex-vexriscv.dtsi +.. literalinclude:: ../../../boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts :language: dts :start-at: clk0: clock-controller@0 { :end-at: }; :dedent: -.. literalinclude:: ../../../dts/riscv/riscv32-litex-vexriscv.dtsi +.. literalinclude:: ../../../boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts :language: dts :start-at: clk1: clock-controller@1 { :end-at: }; :dedent: -.. literalinclude:: ../../../dts/riscv/riscv32-litex-vexriscv.dtsi +.. literalinclude:: ../../../boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts :language: dts :start-at: clock0: clock@e0004800 { :end-at: }; From 7e63aef26f24923431ea0484238b0d4b1eb34626 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 21 Oct 2025 12:27:12 +0200 Subject: [PATCH 093/397] net: lib: shell: dns: Fix field precission specifier type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly cast down the string width to int, as otherwise it is size_t which may have a bigger size. Avoids the following build error: subsys/net/lib/shell/dns.c:496:67: error: field precision specifier ‘.*’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ {aka ‘long unsigned int’} Signed-off-by: Alberto Escolar Piedras --- subsys/net/lib/shell/dns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/shell/dns.c b/subsys/net/lib/shell/dns.c index 53838952c95da..b29562218e194 100644 --- a/subsys/net/lib/shell/dns.c +++ b/subsys/net/lib/shell/dns.c @@ -494,7 +494,7 @@ static int cmd_net_dns_service(const struct shell *sh, size_t argc, char *argv[] port = info.ai_srv.port; snprintf(query, sizeof(query), "%.*s", - info.ai_srv.targetlen, + (int)info.ai_srv.targetlen, info.ai_srv.target); /* From 4f7637ae2b2c091a3a054f0428887c4bb303e91e Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:17:01 +0200 Subject: [PATCH 094/397] dts: arm: st: stm32c0: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. There is no consistency about which level of the DTSI inclusion hierarchy the macros from this header start being used, so including it from the root file ensures they are always visible and available without headache. Today, there are places where the header is included twice or more at different DTSI inclusion hierarchy levels because of this ambiguity - this commit solves the issue once and for all. Signed-off-by: Mathieu Choplain --- dts/arm/st/c0/stm32c0.dtsi | 1 + dts/arm/st/c0/stm32c011X6.dtsi | 1 - dts/arm/st/c0/stm32c031X6.dtsi | 1 - dts/arm/st/c0/stm32c051X6.dtsi | 1 - dts/arm/st/c0/stm32c051X8.dtsi | 1 - dts/arm/st/c0/stm32c071X8.dtsi | 1 - dts/arm/st/c0/stm32c071Xb.dtsi | 1 - dts/arm/st/c0/stm32c091Xb.dtsi | 1 - dts/arm/st/c0/stm32c091Xc.dtsi | 1 - dts/arm/st/c0/stm32c092Xb.dtsi | 1 - dts/arm/st/c0/stm32c092Xc.dtsi | 1 - 11 files changed, 1 insertion(+), 10 deletions(-) diff --git a/dts/arm/st/c0/stm32c0.dtsi b/dts/arm/st/c0/stm32c0.dtsi index 2a8a4f101cb5d..b60869063aca4 100644 --- a/dts/arm/st/c0/stm32c0.dtsi +++ b/dts/arm/st/c0/stm32c0.dtsi @@ -69,6 +69,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/c0/stm32c011X6.dtsi b/dts/arm/st/c0/stm32c011X6.dtsi index d5be6b7e7d81a..5c6eea42802d6 100644 --- a/dts/arm/st/c0/stm32c011X6.dtsi +++ b/dts/arm/st/c0/stm32c011X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c031X6.dtsi b/dts/arm/st/c0/stm32c031X6.dtsi index 817118aef2a88..588b3db09a5ad 100644 --- a/dts/arm/st/c0/stm32c031X6.dtsi +++ b/dts/arm/st/c0/stm32c031X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c051X6.dtsi b/dts/arm/st/c0/stm32c051X6.dtsi index 2acdb7a883b84..1b6497e646d1f 100644 --- a/dts/arm/st/c0/stm32c051X6.dtsi +++ b/dts/arm/st/c0/stm32c051X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c051X8.dtsi b/dts/arm/st/c0/stm32c051X8.dtsi index a2fbaf164b696..c065bb63decdc 100644 --- a/dts/arm/st/c0/stm32c051X8.dtsi +++ b/dts/arm/st/c0/stm32c051X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c071X8.dtsi b/dts/arm/st/c0/stm32c071X8.dtsi index 0a9d4001f5d6a..7ef7b785539cf 100644 --- a/dts/arm/st/c0/stm32c071X8.dtsi +++ b/dts/arm/st/c0/stm32c071X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c071Xb.dtsi b/dts/arm/st/c0/stm32c071Xb.dtsi index 909b588d1dc88..03d5e93c022e1 100644 --- a/dts/arm/st/c0/stm32c071Xb.dtsi +++ b/dts/arm/st/c0/stm32c071Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c091Xb.dtsi b/dts/arm/st/c0/stm32c091Xb.dtsi index d1cd06a0eca21..915968a6d2d73 100644 --- a/dts/arm/st/c0/stm32c091Xb.dtsi +++ b/dts/arm/st/c0/stm32c091Xb.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c091Xc.dtsi b/dts/arm/st/c0/stm32c091Xc.dtsi index 4b1a595b0e238..7be153cf28945 100644 --- a/dts/arm/st/c0/stm32c091Xc.dtsi +++ b/dts/arm/st/c0/stm32c091Xc.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c092Xb.dtsi b/dts/arm/st/c0/stm32c092Xb.dtsi index 889f658029f14..b2ebfae968bc9 100644 --- a/dts/arm/st/c0/stm32c092Xb.dtsi +++ b/dts/arm/st/c0/stm32c092Xb.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/c0/stm32c092Xc.dtsi b/dts/arm/st/c0/stm32c092Xc.dtsi index e814ddb4be968..4e86d6e81ab97 100644 --- a/dts/arm/st/c0/stm32c092Xc.dtsi +++ b/dts/arm/st/c0/stm32c092Xc.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 473279b1d62709ee7ee94ee232e63f423518c67d Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:18:15 +0200 Subject: [PATCH 095/397] dts: arm: st: stm32f0: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/f0/stm32f0.dtsi | 1 + dts/arm/st/f0/stm32f030X4.dtsi | 1 - dts/arm/st/f0/stm32f030X6.dtsi | 2 -- dts/arm/st/f0/stm32f030X8.dtsi | 1 - dts/arm/st/f0/stm32f030Xc.dtsi | 1 - dts/arm/st/f0/stm32f031X6.dtsi | 1 - dts/arm/st/f0/stm32f042X6.dtsi | 1 - dts/arm/st/f0/stm32f051X8.dtsi | 1 - dts/arm/st/f0/stm32f070Xb.dtsi | 1 - dts/arm/st/f0/stm32f072X8.dtsi | 1 - dts/arm/st/f0/stm32f072Xb.dtsi | 1 - dts/arm/st/f0/stm32f091Xc.dtsi | 1 - dts/arm/st/f0/stm32f098Xc.dtsi | 1 - 13 files changed, 1 insertion(+), 13 deletions(-) diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index 3a411f35545cc..3df708cb32239 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/f0/stm32f030X4.dtsi b/dts/arm/st/f0/stm32f030X4.dtsi index a38ece02f0fb6..d04d2f4b7d8e7 100644 --- a/dts/arm/st/f0/stm32f030X4.dtsi +++ b/dts/arm/st/f0/stm32f030X4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f030X6.dtsi b/dts/arm/st/f0/stm32f030X6.dtsi index 2050c8523be94..16c6d57748dd5 100644 --- a/dts/arm/st/f0/stm32f030X6.dtsi +++ b/dts/arm/st/f0/stm32f030X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { @@ -20,4 +19,3 @@ }; }; }; - diff --git a/dts/arm/st/f0/stm32f030X8.dtsi b/dts/arm/st/f0/stm32f030X8.dtsi index f0fe64e254a05..c5d316ec92dfa 100644 --- a/dts/arm/st/f0/stm32f030X8.dtsi +++ b/dts/arm/st/f0/stm32f030X8.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f030Xc.dtsi b/dts/arm/st/f0/stm32f030Xc.dtsi index 53cf999a74b5f..8fb5e0f8b8391 100644 --- a/dts/arm/st/f0/stm32f030Xc.dtsi +++ b/dts/arm/st/f0/stm32f030Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f031X6.dtsi b/dts/arm/st/f0/stm32f031X6.dtsi index 373437a18716d..a0c7b02dd3466 100644 --- a/dts/arm/st/f0/stm32f031X6.dtsi +++ b/dts/arm/st/f0/stm32f031X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f042X6.dtsi b/dts/arm/st/f0/stm32f042X6.dtsi index 905c7737cd0df..1e8b63beaef68 100644 --- a/dts/arm/st/f0/stm32f042X6.dtsi +++ b/dts/arm/st/f0/stm32f042X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f051X8.dtsi b/dts/arm/st/f0/stm32f051X8.dtsi index 0b2e8a8af499e..24ee5888a4080 100644 --- a/dts/arm/st/f0/stm32f051X8.dtsi +++ b/dts/arm/st/f0/stm32f051X8.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f070Xb.dtsi b/dts/arm/st/f0/stm32f070Xb.dtsi index e8226c43ac4dd..9a42e1985025e 100644 --- a/dts/arm/st/f0/stm32f070Xb.dtsi +++ b/dts/arm/st/f0/stm32f070Xb.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f072X8.dtsi b/dts/arm/st/f0/stm32f072X8.dtsi index 66669041b911d..a8101ae7b0ff1 100644 --- a/dts/arm/st/f0/stm32f072X8.dtsi +++ b/dts/arm/st/f0/stm32f072X8.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f072Xb.dtsi b/dts/arm/st/f0/stm32f072Xb.dtsi index 2327558183509..8b33d68bfaaf9 100644 --- a/dts/arm/st/f0/stm32f072Xb.dtsi +++ b/dts/arm/st/f0/stm32f072Xb.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f091Xc.dtsi b/dts/arm/st/f0/stm32f091Xc.dtsi index a840f078c09c1..b47404100f5c7 100644 --- a/dts/arm/st/f0/stm32f091Xc.dtsi +++ b/dts/arm/st/f0/stm32f091Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f0/stm32f098Xc.dtsi b/dts/arm/st/f0/stm32f098Xc.dtsi index d1028a6920584..6dd1376bd1b40 100644 --- a/dts/arm/st/f0/stm32f098Xc.dtsi +++ b/dts/arm/st/f0/stm32f098Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 3e6fa94d4f938f3c02bb49cefe34828b9a6c55be Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:18:28 +0200 Subject: [PATCH 096/397] dts: arm: st: stm32f1: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/f1/stm32f1.dtsi | 1 + dts/arm/st/f1/stm32f100Xb.dtsi | 1 - dts/arm/st/f1/stm32f100Xe.dtsi | 1 - dts/arm/st/f1/stm32f103X8.dtsi | 1 - dts/arm/st/f1/stm32f103Xb.dtsi | 1 - dts/arm/st/f1/stm32f103Xc.dtsi | 1 - dts/arm/st/f1/stm32f103Xd.dtsi | 1 - dts/arm/st/f1/stm32f103Xe.dtsi | 1 - dts/arm/st/f1/stm32f103Xg.dtsi | 1 - dts/arm/st/f1/stm32f105Xb.dtsi | 1 - dts/arm/st/f1/stm32f105Xc.dtsi | 1 - dts/arm/st/f1/stm32f107Xc.dtsi | 1 - 12 files changed, 1 insertion(+), 11 deletions(-) diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index 5744dcfa3c939..9c80be9ca8bc2 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/f1/stm32f100Xb.dtsi b/dts/arm/st/f1/stm32f100Xb.dtsi index b0a99a9187ea5..36b9ee57e295a 100644 --- a/dts/arm/st/f1/stm32f100Xb.dtsi +++ b/dts/arm/st/f1/stm32f100Xb.dtsi @@ -6,7 +6,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f100Xe.dtsi b/dts/arm/st/f1/stm32f100Xe.dtsi index 67a85ef347806..d6fc036c34af9 100644 --- a/dts/arm/st/f1/stm32f100Xe.dtsi +++ b/dts/arm/st/f1/stm32f100Xe.dtsi @@ -6,7 +6,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f103X8.dtsi b/dts/arm/st/f1/stm32f103X8.dtsi index 055c97ab269cd..874043f8dd1a0 100644 --- a/dts/arm/st/f1/stm32f103X8.dtsi +++ b/dts/arm/st/f1/stm32f103X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f103Xb.dtsi b/dts/arm/st/f1/stm32f103Xb.dtsi index 7c95f608cc95f..c07233ce48a8d 100644 --- a/dts/arm/st/f1/stm32f103Xb.dtsi +++ b/dts/arm/st/f1/stm32f103Xb.dtsi @@ -7,7 +7,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f103Xc.dtsi b/dts/arm/st/f1/stm32f103Xc.dtsi index 518d243fe62b5..cab9915dc640a 100644 --- a/dts/arm/st/f1/stm32f103Xc.dtsi +++ b/dts/arm/st/f1/stm32f103Xc.dtsi @@ -7,7 +7,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include diff --git a/dts/arm/st/f1/stm32f103Xd.dtsi b/dts/arm/st/f1/stm32f103Xd.dtsi index 2c3935473ed78..5f35c663d1ae7 100644 --- a/dts/arm/st/f1/stm32f103Xd.dtsi +++ b/dts/arm/st/f1/stm32f103Xd.dtsi @@ -7,7 +7,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f103Xe.dtsi b/dts/arm/st/f1/stm32f103Xe.dtsi index 18c0dcc83ff2b..21d8915b59f3f 100644 --- a/dts/arm/st/f1/stm32f103Xe.dtsi +++ b/dts/arm/st/f1/stm32f103Xe.dtsi @@ -7,7 +7,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f103Xg.dtsi b/dts/arm/st/f1/stm32f103Xg.dtsi index 484286fb2bbce..89544b7d86b71 100644 --- a/dts/arm/st/f1/stm32f103Xg.dtsi +++ b/dts/arm/st/f1/stm32f103Xg.dtsi @@ -6,7 +6,6 @@ * where 'x' is replaced for specific SoCs like {R,V,Z} */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f105Xb.dtsi b/dts/arm/st/f1/stm32f105Xb.dtsi index 7db805c8a5f5e..6a535504323a8 100644 --- a/dts/arm/st/f1/stm32f105Xb.dtsi +++ b/dts/arm/st/f1/stm32f105Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f105Xc.dtsi b/dts/arm/st/f1/stm32f105Xc.dtsi index e2151b445485c..43fc52663ed80 100644 --- a/dts/arm/st/f1/stm32f105Xc.dtsi +++ b/dts/arm/st/f1/stm32f105Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f1/stm32f107Xc.dtsi b/dts/arm/st/f1/stm32f107Xc.dtsi index ea7ad2e491ccd..6d5795d552b01 100644 --- a/dts/arm/st/f1/stm32f107Xc.dtsi +++ b/dts/arm/st/f1/stm32f107Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 637da2f8c834b4bfdbb50f137cf7a59fc6965757 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:18:34 +0200 Subject: [PATCH 097/397] dts: arm: st: stm32f2: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/f2/stm32f2.dtsi | 1 + dts/arm/st/f2/stm32f205Xe.dtsi | 1 - dts/arm/st/f2/stm32f207Xg.dtsi | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm/st/f2/stm32f2.dtsi b/dts/arm/st/f2/stm32f2.dtsi index 8e2b67ab92b8f..1c645d5a9d106 100644 --- a/dts/arm/st/f2/stm32f2.dtsi +++ b/dts/arm/st/f2/stm32f2.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/f2/stm32f205Xe.dtsi b/dts/arm/st/f2/stm32f205Xe.dtsi index 2a2723a3ca1d5..c02ac24b92ad8 100644 --- a/dts/arm/st/f2/stm32f205Xe.dtsi +++ b/dts/arm/st/f2/stm32f205Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f2/stm32f207Xg.dtsi b/dts/arm/st/f2/stm32f207Xg.dtsi index 4dfbbbd1c1e0f..68c132c9bf3f7 100644 --- a/dts/arm/st/f2/stm32f207Xg.dtsi +++ b/dts/arm/st/f2/stm32f207Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 6af993e42b88f75790830aa6fdf7e5689194ee82 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:18:42 +0200 Subject: [PATCH 098/397] dts: arm: st: stm32f3: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/f3/stm32f3.dtsi | 1 + dts/arm/st/f3/stm32f302X8.dtsi | 1 - dts/arm/st/f3/stm32f302Xc.dtsi | 1 - dts/arm/st/f3/stm32f303X8.dtsi | 1 - dts/arm/st/f3/stm32f303Xb.dtsi | 1 - dts/arm/st/f3/stm32f303Xc.dtsi | 1 - dts/arm/st/f3/stm32f303Xe.dtsi | 1 - dts/arm/st/f3/stm32f334X8.dtsi | 1 - dts/arm/st/f3/stm32f373Xc.dtsi | 1 - 9 files changed, 1 insertion(+), 8 deletions(-) diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index c86a70889f62d..5c9fbd208354f 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/f3/stm32f302X8.dtsi b/dts/arm/st/f3/stm32f302X8.dtsi index 003a2e055024e..ba3fe3dbe1bbf 100644 --- a/dts/arm/st/f3/stm32f302X8.dtsi +++ b/dts/arm/st/f3/stm32f302X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f3/stm32f302Xc.dtsi b/dts/arm/st/f3/stm32f302Xc.dtsi index 44742e388684f..d4040966288c1 100644 --- a/dts/arm/st/f3/stm32f302Xc.dtsi +++ b/dts/arm/st/f3/stm32f302Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include diff --git a/dts/arm/st/f3/stm32f303X8.dtsi b/dts/arm/st/f3/stm32f303X8.dtsi index 17ea1cdd1d18c..3395b9470a03c 100644 --- a/dts/arm/st/f3/stm32f303X8.dtsi +++ b/dts/arm/st/f3/stm32f303X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f3/stm32f303Xb.dtsi b/dts/arm/st/f3/stm32f303Xb.dtsi index a017c5279a42b..91cda7cb429ad 100644 --- a/dts/arm/st/f3/stm32f303Xb.dtsi +++ b/dts/arm/st/f3/stm32f303Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include diff --git a/dts/arm/st/f3/stm32f303Xc.dtsi b/dts/arm/st/f3/stm32f303Xc.dtsi index 76131f723490c..1a7708707121e 100644 --- a/dts/arm/st/f3/stm32f303Xc.dtsi +++ b/dts/arm/st/f3/stm32f303Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/f3/stm32f303Xe.dtsi b/dts/arm/st/f3/stm32f303Xe.dtsi index 683b7cc9bed00..bc5b4d9cd6afe 100644 --- a/dts/arm/st/f3/stm32f303Xe.dtsi +++ b/dts/arm/st/f3/stm32f303Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include diff --git a/dts/arm/st/f3/stm32f334X8.dtsi b/dts/arm/st/f3/stm32f334X8.dtsi index caf654d77e5a9..827d6e0504d5e 100644 --- a/dts/arm/st/f3/stm32f334X8.dtsi +++ b/dts/arm/st/f3/stm32f334X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f3/stm32f373Xc.dtsi b/dts/arm/st/f3/stm32f373Xc.dtsi index f9898820755d5..07c4d52241b73 100644 --- a/dts/arm/st/f3/stm32f373Xc.dtsi +++ b/dts/arm/st/f3/stm32f373Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 390c11f2db7a731527722b879d0650cde0bab4ad Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:18:49 +0200 Subject: [PATCH 099/397] dts: arm: st: stm32f4: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/f4/stm32f4.dtsi | 1 + dts/arm/st/f4/stm32f401Xc.dtsi | 1 - dts/arm/st/f4/stm32f401Xd.dtsi | 1 - dts/arm/st/f4/stm32f401Xe.dtsi | 1 - dts/arm/st/f4/stm32f405Xg.dtsi | 1 - dts/arm/st/f4/stm32f407Xe.dtsi | 1 - dts/arm/st/f4/stm32f407Xg.dtsi | 1 - dts/arm/st/f4/stm32f410Xb.dtsi | 1 - dts/arm/st/f4/stm32f411Xe.dtsi | 1 - dts/arm/st/f4/stm32f412Xe.dtsi | 1 - dts/arm/st/f4/stm32f412Xg.dtsi | 1 - dts/arm/st/f4/stm32f413Xg.dtsi | 1 - dts/arm/st/f4/stm32f413Xh.dtsi | 1 - dts/arm/st/f4/stm32f415Rg.dtsi | 1 - dts/arm/st/f4/stm32f417Xe.dtsi | 1 - dts/arm/st/f4/stm32f417Xg.dtsi | 1 - dts/arm/st/f4/stm32f423Xg.dtsi | 1 - dts/arm/st/f4/stm32f423Xh.dtsi | 1 - dts/arm/st/f4/stm32f427Xi.dtsi | 1 - dts/arm/st/f4/stm32f427vi.dtsi | 2 -- dts/arm/st/f4/stm32f429Xi.dtsi | 1 - dts/arm/st/f4/stm32f429vi.dtsi | 2 -- dts/arm/st/f4/stm32f437Xi.dtsi | 1 - dts/arm/st/f4/stm32f439Xi.dtsi | 1 - dts/arm/st/f4/stm32f439vi.dtsi | 1 - dts/arm/st/f4/stm32f446Xe.dtsi | 1 - dts/arm/st/f4/stm32f469Xi.dtsi | 1 - dts/arm/st/f4/stm32f479Xi.dtsi | 1 - 28 files changed, 1 insertion(+), 29 deletions(-) diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index b4736ff54b089..d341a521bcab3 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/f4/stm32f401Xc.dtsi b/dts/arm/st/f4/stm32f401Xc.dtsi index 3d733a124ae01..84f415451ab79 100644 --- a/dts/arm/st/f4/stm32f401Xc.dtsi +++ b/dts/arm/st/f4/stm32f401Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f401Xd.dtsi b/dts/arm/st/f4/stm32f401Xd.dtsi index b15480221f466..f26e9047ed4d0 100644 --- a/dts/arm/st/f4/stm32f401Xd.dtsi +++ b/dts/arm/st/f4/stm32f401Xd.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f401Xe.dtsi b/dts/arm/st/f4/stm32f401Xe.dtsi index 087bcb9469a73..6fe6405a0d10a 100644 --- a/dts/arm/st/f4/stm32f401Xe.dtsi +++ b/dts/arm/st/f4/stm32f401Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f405Xg.dtsi b/dts/arm/st/f4/stm32f405Xg.dtsi index 20ba8184ee02c..368640e2752d3 100644 --- a/dts/arm/st/f4/stm32f405Xg.dtsi +++ b/dts/arm/st/f4/stm32f405Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f407Xe.dtsi b/dts/arm/st/f4/stm32f407Xe.dtsi index 0d11257f2e3f5..95f4e8ced6c51 100644 --- a/dts/arm/st/f4/stm32f407Xe.dtsi +++ b/dts/arm/st/f4/stm32f407Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f407Xg.dtsi b/dts/arm/st/f4/stm32f407Xg.dtsi index c2b861a13f5ed..1e5005ff0859c 100644 --- a/dts/arm/st/f4/stm32f407Xg.dtsi +++ b/dts/arm/st/f4/stm32f407Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f410Xb.dtsi b/dts/arm/st/f4/stm32f410Xb.dtsi index 820a67a23d0d0..c7488bb14f3bb 100644 --- a/dts/arm/st/f4/stm32f410Xb.dtsi +++ b/dts/arm/st/f4/stm32f410Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &sdmmc1; diff --git a/dts/arm/st/f4/stm32f411Xe.dtsi b/dts/arm/st/f4/stm32f411Xe.dtsi index bc9e8b2c2e5c9..9ecaf5e1e79a2 100644 --- a/dts/arm/st/f4/stm32f411Xe.dtsi +++ b/dts/arm/st/f4/stm32f411Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f412Xe.dtsi b/dts/arm/st/f4/stm32f412Xe.dtsi index 764ba77d5550d..16443ecdef0eb 100644 --- a/dts/arm/st/f4/stm32f412Xe.dtsi +++ b/dts/arm/st/f4/stm32f412Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f412Xg.dtsi b/dts/arm/st/f4/stm32f412Xg.dtsi index a6958857dbc4f..9e6d243fc0022 100644 --- a/dts/arm/st/f4/stm32f412Xg.dtsi +++ b/dts/arm/st/f4/stm32f412Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f413Xg.dtsi b/dts/arm/st/f4/stm32f413Xg.dtsi index 62a8029fc4883..80af1a3e822a4 100644 --- a/dts/arm/st/f4/stm32f413Xg.dtsi +++ b/dts/arm/st/f4/stm32f413Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f413Xh.dtsi b/dts/arm/st/f4/stm32f413Xh.dtsi index 6e79b06b78411..63c733f98b5d1 100644 --- a/dts/arm/st/f4/stm32f413Xh.dtsi +++ b/dts/arm/st/f4/stm32f413Xh.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f415Rg.dtsi b/dts/arm/st/f4/stm32f415Rg.dtsi index feed35472961e..4f430d88037a7 100644 --- a/dts/arm/st/f4/stm32f415Rg.dtsi +++ b/dts/arm/st/f4/stm32f415Rg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f417Xe.dtsi b/dts/arm/st/f4/stm32f417Xe.dtsi index 2f0bfdbde11b2..aab4fc20deaf7 100644 --- a/dts/arm/st/f4/stm32f417Xe.dtsi +++ b/dts/arm/st/f4/stm32f417Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f417Xg.dtsi b/dts/arm/st/f4/stm32f417Xg.dtsi index 0c8e3a00b9f7f..c272f7b235f41 100644 --- a/dts/arm/st/f4/stm32f417Xg.dtsi +++ b/dts/arm/st/f4/stm32f417Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f423Xg.dtsi b/dts/arm/st/f4/stm32f423Xg.dtsi index 768c0bea023c3..18f2bac697fcc 100644 --- a/dts/arm/st/f4/stm32f423Xg.dtsi +++ b/dts/arm/st/f4/stm32f423Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f423Xh.dtsi b/dts/arm/st/f4/stm32f423Xh.dtsi index 2b2eaa7f1cb3b..6c0332312a26e 100644 --- a/dts/arm/st/f4/stm32f423Xh.dtsi +++ b/dts/arm/st/f4/stm32f423Xh.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f427Xi.dtsi b/dts/arm/st/f4/stm32f427Xi.dtsi index 150607a93bc5e..fd5264e8fd414 100644 --- a/dts/arm/st/f4/stm32f427Xi.dtsi +++ b/dts/arm/st/f4/stm32f427Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f427vi.dtsi b/dts/arm/st/f4/stm32f427vi.dtsi index 06b198a79ef1e..2355bc1603b95 100644 --- a/dts/arm/st/f4/stm32f427vi.dtsi +++ b/dts/arm/st/f4/stm32f427vi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { @@ -26,4 +25,3 @@ }; }; }; - diff --git a/dts/arm/st/f4/stm32f429Xi.dtsi b/dts/arm/st/f4/stm32f429Xi.dtsi index 02cad584de72b..eee3f6d04c9c6 100644 --- a/dts/arm/st/f4/stm32f429Xi.dtsi +++ b/dts/arm/st/f4/stm32f429Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f429vi.dtsi b/dts/arm/st/f4/stm32f429vi.dtsi index b1fd97809e396..3acbf5e0c9838 100644 --- a/dts/arm/st/f4/stm32f429vi.dtsi +++ b/dts/arm/st/f4/stm32f429vi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { @@ -26,4 +25,3 @@ }; }; }; - diff --git a/dts/arm/st/f4/stm32f437Xi.dtsi b/dts/arm/st/f4/stm32f437Xi.dtsi index 23bb97bb8e39e..c64a2e90fa64f 100644 --- a/dts/arm/st/f4/stm32f437Xi.dtsi +++ b/dts/arm/st/f4/stm32f437Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f439Xi.dtsi b/dts/arm/st/f4/stm32f439Xi.dtsi index cc1c6a1276ddf..1dc2f756c7585 100644 --- a/dts/arm/st/f4/stm32f439Xi.dtsi +++ b/dts/arm/st/f4/stm32f439Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f439vi.dtsi b/dts/arm/st/f4/stm32f439vi.dtsi index 837a6cac9d9ec..3c5bd4c99fcf5 100644 --- a/dts/arm/st/f4/stm32f439vi.dtsi +++ b/dts/arm/st/f4/stm32f439vi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f446Xe.dtsi b/dts/arm/st/f4/stm32f446Xe.dtsi index e1c9929ef4d40..5138835338d84 100644 --- a/dts/arm/st/f4/stm32f446Xe.dtsi +++ b/dts/arm/st/f4/stm32f446Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f469Xi.dtsi b/dts/arm/st/f4/stm32f469Xi.dtsi index 87d327d0969f9..3172e37e776eb 100644 --- a/dts/arm/st/f4/stm32f469Xi.dtsi +++ b/dts/arm/st/f4/stm32f469Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f4/stm32f479Xi.dtsi b/dts/arm/st/f4/stm32f479Xi.dtsi index 42eb8c07afe86..4f7db423c8c2e 100644 --- a/dts/arm/st/f4/stm32f479Xi.dtsi +++ b/dts/arm/st/f4/stm32f479Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 37264d6c25f3ff3f8e6eab7b6065e03ce46d7083 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:18:55 +0200 Subject: [PATCH 100/397] dts: arm: st: stm32f7: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/f7/stm32f7.dtsi | 1 + dts/arm/st/f7/stm32f722Xe.dtsi | 1 - dts/arm/st/f7/stm32f723Xe.dtsi | 1 - dts/arm/st/f7/stm32f745Xe.dtsi | 1 - dts/arm/st/f7/stm32f745Xg.dtsi | 1 - dts/arm/st/f7/stm32f746Xg.dtsi | 1 - dts/arm/st/f7/stm32f750X8.dtsi | 1 - dts/arm/st/f7/stm32f756Xg.dtsi | 1 - dts/arm/st/f7/stm32f765Xg.dtsi | 1 - dts/arm/st/f7/stm32f765Xi.dtsi | 1 - dts/arm/st/f7/stm32f767Xi.dtsi | 1 - dts/arm/st/f7/stm32f769Xi.dtsi | 1 - 12 files changed, 1 insertion(+), 11 deletions(-) diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index ba613c7580b48..d2f8153068c3e 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -21,6 +21,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/f7/stm32f722Xe.dtsi b/dts/arm/st/f7/stm32f722Xe.dtsi index 79491e4008b0a..5c0e1a1917a48 100644 --- a/dts/arm/st/f7/stm32f722Xe.dtsi +++ b/dts/arm/st/f7/stm32f722Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f723Xe.dtsi b/dts/arm/st/f7/stm32f723Xe.dtsi index 2a7adcd801653..3a22dee1fdca9 100644 --- a/dts/arm/st/f7/stm32f723Xe.dtsi +++ b/dts/arm/st/f7/stm32f723Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f745Xe.dtsi b/dts/arm/st/f7/stm32f745Xe.dtsi index d46f619b2eb70..34d833650bfb7 100644 --- a/dts/arm/st/f7/stm32f745Xe.dtsi +++ b/dts/arm/st/f7/stm32f745Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f745Xg.dtsi b/dts/arm/st/f7/stm32f745Xg.dtsi index 89f3cb466caac..9775527ed794d 100644 --- a/dts/arm/st/f7/stm32f745Xg.dtsi +++ b/dts/arm/st/f7/stm32f745Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f746Xg.dtsi b/dts/arm/st/f7/stm32f746Xg.dtsi index e9257195aa48a..326649657da6e 100644 --- a/dts/arm/st/f7/stm32f746Xg.dtsi +++ b/dts/arm/st/f7/stm32f746Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f750X8.dtsi b/dts/arm/st/f7/stm32f750X8.dtsi index c1e079365da3a..287b99caf18f0 100644 --- a/dts/arm/st/f7/stm32f750X8.dtsi +++ b/dts/arm/st/f7/stm32f750X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f756Xg.dtsi b/dts/arm/st/f7/stm32f756Xg.dtsi index 439b9e7921623..cdde4571c09bf 100644 --- a/dts/arm/st/f7/stm32f756Xg.dtsi +++ b/dts/arm/st/f7/stm32f756Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f765Xg.dtsi b/dts/arm/st/f7/stm32f765Xg.dtsi index 92705145f9a87..d87bda12c69f8 100644 --- a/dts/arm/st/f7/stm32f765Xg.dtsi +++ b/dts/arm/st/f7/stm32f765Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f765Xi.dtsi b/dts/arm/st/f7/stm32f765Xi.dtsi index aad756a60b54f..725ac5a551b56 100644 --- a/dts/arm/st/f7/stm32f765Xi.dtsi +++ b/dts/arm/st/f7/stm32f765Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f767Xi.dtsi b/dts/arm/st/f7/stm32f767Xi.dtsi index c61f223167c80..01d46149bbf47 100644 --- a/dts/arm/st/f7/stm32f767Xi.dtsi +++ b/dts/arm/st/f7/stm32f767Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/f7/stm32f769Xi.dtsi b/dts/arm/st/f7/stm32f769Xi.dtsi index b298165cfb048..3a23c6ab89ff6 100644 --- a/dts/arm/st/f7/stm32f769Xi.dtsi +++ b/dts/arm/st/f7/stm32f769Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From a2fecaa180f82b3ec036e1265fec49646f17b7fb Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:01 +0200 Subject: [PATCH 101/397] dts: arm: st: stm32g0: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/g0/stm32g0.dtsi | 1 + dts/arm/st/g0/stm32g030X6.dtsi | 1 - dts/arm/st/g0/stm32g030X8.dtsi | 1 - dts/arm/st/g0/stm32g031X4.dtsi | 1 - dts/arm/st/g0/stm32g031X6.dtsi | 1 - dts/arm/st/g0/stm32g031X8.dtsi | 1 - dts/arm/st/g0/stm32g041X6.dtsi | 1 - dts/arm/st/g0/stm32g041X8.dtsi | 1 - dts/arm/st/g0/stm32g050X6.dtsi | 1 - dts/arm/st/g0/stm32g050X8.dtsi | 1 - dts/arm/st/g0/stm32g051X6.dtsi | 1 - dts/arm/st/g0/stm32g051X8.dtsi | 1 - dts/arm/st/g0/stm32g061X6.dtsi | 1 - dts/arm/st/g0/stm32g061X8.dtsi | 1 - dts/arm/st/g0/stm32g070Xb.dtsi | 1 - dts/arm/st/g0/stm32g071X8.dtsi | 1 - dts/arm/st/g0/stm32g071Xb.dtsi | 3 +-- dts/arm/st/g0/stm32g081Xb.dtsi | 1 - dts/arm/st/g0/stm32g0b0Xe.dtsi | 1 - dts/arm/st/g0/stm32g0b1Xb.dtsi | 1 - dts/arm/st/g0/stm32g0b1Xc.dtsi | 1 - dts/arm/st/g0/stm32g0b1Xe.dtsi | 1 - dts/arm/st/g0/stm32g0c1Xc.dtsi | 1 - dts/arm/st/g0/stm32g0c1Xe.dtsi | 1 - 24 files changed, 2 insertions(+), 24 deletions(-) diff --git a/dts/arm/st/g0/stm32g0.dtsi b/dts/arm/st/g0/stm32g0.dtsi index 48d7c55e3d959..f3198a12335f3 100644 --- a/dts/arm/st/g0/stm32g0.dtsi +++ b/dts/arm/st/g0/stm32g0.dtsi @@ -21,6 +21,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/g0/stm32g030X6.dtsi b/dts/arm/st/g0/stm32g030X6.dtsi index d3ac3daf5e6b1..628318b878ccc 100644 --- a/dts/arm/st/g0/stm32g030X6.dtsi +++ b/dts/arm/st/g0/stm32g030X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g030X8.dtsi b/dts/arm/st/g0/stm32g030X8.dtsi index 595584f038228..01eba1a85a52f 100644 --- a/dts/arm/st/g0/stm32g030X8.dtsi +++ b/dts/arm/st/g0/stm32g030X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g031X4.dtsi b/dts/arm/st/g0/stm32g031X4.dtsi index 67d983af816fa..509d7bbb1a21e 100644 --- a/dts/arm/st/g0/stm32g031X4.dtsi +++ b/dts/arm/st/g0/stm32g031X4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g031X6.dtsi b/dts/arm/st/g0/stm32g031X6.dtsi index 10e31f3e1f1b6..573d46f380ebf 100644 --- a/dts/arm/st/g0/stm32g031X6.dtsi +++ b/dts/arm/st/g0/stm32g031X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g031X8.dtsi b/dts/arm/st/g0/stm32g031X8.dtsi index c9fba2028254c..0db744777e437 100644 --- a/dts/arm/st/g0/stm32g031X8.dtsi +++ b/dts/arm/st/g0/stm32g031X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g041X6.dtsi b/dts/arm/st/g0/stm32g041X6.dtsi index d0af1d89d483d..8aed947a94346 100644 --- a/dts/arm/st/g0/stm32g041X6.dtsi +++ b/dts/arm/st/g0/stm32g041X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g041X8.dtsi b/dts/arm/st/g0/stm32g041X8.dtsi index 5c23293d4dc12..9bc433df54b41 100644 --- a/dts/arm/st/g0/stm32g041X8.dtsi +++ b/dts/arm/st/g0/stm32g041X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g050X6.dtsi b/dts/arm/st/g0/stm32g050X6.dtsi index bcb5aecb0977d..94abcd0ea5ff9 100644 --- a/dts/arm/st/g0/stm32g050X6.dtsi +++ b/dts/arm/st/g0/stm32g050X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g050X8.dtsi b/dts/arm/st/g0/stm32g050X8.dtsi index 906332c5d42d7..92a635630a4d1 100644 --- a/dts/arm/st/g0/stm32g050X8.dtsi +++ b/dts/arm/st/g0/stm32g050X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g051X6.dtsi b/dts/arm/st/g0/stm32g051X6.dtsi index 7a84fb6d98433..7c76c640f4df8 100644 --- a/dts/arm/st/g0/stm32g051X6.dtsi +++ b/dts/arm/st/g0/stm32g051X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g051X8.dtsi b/dts/arm/st/g0/stm32g051X8.dtsi index 20df94c4532d2..b2dd1a362a0a9 100644 --- a/dts/arm/st/g0/stm32g051X8.dtsi +++ b/dts/arm/st/g0/stm32g051X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g061X6.dtsi b/dts/arm/st/g0/stm32g061X6.dtsi index 3c1268dfa8c38..e7e7478a37626 100644 --- a/dts/arm/st/g0/stm32g061X6.dtsi +++ b/dts/arm/st/g0/stm32g061X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g061X8.dtsi b/dts/arm/st/g0/stm32g061X8.dtsi index d8d6f5fb0b5df..3a4ebf20b3956 100644 --- a/dts/arm/st/g0/stm32g061X8.dtsi +++ b/dts/arm/st/g0/stm32g061X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g070Xb.dtsi b/dts/arm/st/g0/stm32g070Xb.dtsi index c40b31341864d..6729272b4c7f7 100644 --- a/dts/arm/st/g0/stm32g070Xb.dtsi +++ b/dts/arm/st/g0/stm32g070Xb.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g071X8.dtsi b/dts/arm/st/g0/stm32g071X8.dtsi index 4694a445fbcdd..4bb6648794ac0 100644 --- a/dts/arm/st/g0/stm32g071X8.dtsi +++ b/dts/arm/st/g0/stm32g071X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g071Xb.dtsi b/dts/arm/st/g0/stm32g071Xb.dtsi index 3e437d6bc3c1b..67b9143dd650c 100644 --- a/dts/arm/st/g0/stm32g071Xb.dtsi +++ b/dts/arm/st/g0/stm32g071Xb.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { @@ -20,4 +19,4 @@ }; }; }; -}; \ No newline at end of file +}; diff --git a/dts/arm/st/g0/stm32g081Xb.dtsi b/dts/arm/st/g0/stm32g081Xb.dtsi index 075d8dec25056..88dbeb397f8db 100644 --- a/dts/arm/st/g0/stm32g081Xb.dtsi +++ b/dts/arm/st/g0/stm32g081Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g0b0Xe.dtsi b/dts/arm/st/g0/stm32g0b0Xe.dtsi index 2c604b4e215cc..00d28cfdc576a 100644 --- a/dts/arm/st/g0/stm32g0b0Xe.dtsi +++ b/dts/arm/st/g0/stm32g0b0Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g0b1Xb.dtsi b/dts/arm/st/g0/stm32g0b1Xb.dtsi index b7903e6615329..c118df530c0e1 100644 --- a/dts/arm/st/g0/stm32g0b1Xb.dtsi +++ b/dts/arm/st/g0/stm32g0b1Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g0b1Xc.dtsi b/dts/arm/st/g0/stm32g0b1Xc.dtsi index 1164d9706fbdb..47b957aced2dc 100644 --- a/dts/arm/st/g0/stm32g0b1Xc.dtsi +++ b/dts/arm/st/g0/stm32g0b1Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g0b1Xe.dtsi b/dts/arm/st/g0/stm32g0b1Xe.dtsi index 08875cf1af977..45157fb6a6fdf 100644 --- a/dts/arm/st/g0/stm32g0b1Xe.dtsi +++ b/dts/arm/st/g0/stm32g0b1Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g0c1Xc.dtsi b/dts/arm/st/g0/stm32g0c1Xc.dtsi index 9e5dbdeb16c63..e56eecf7d1705 100644 --- a/dts/arm/st/g0/stm32g0c1Xc.dtsi +++ b/dts/arm/st/g0/stm32g0c1Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/g0/stm32g0c1Xe.dtsi b/dts/arm/st/g0/stm32g0c1Xe.dtsi index b097fa5aae683..56a7b0867e918 100644 --- a/dts/arm/st/g0/stm32g0c1Xe.dtsi +++ b/dts/arm/st/g0/stm32g0c1Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 61c9e7c26a04268fe265110f4ddc5923f8e468a8 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:09 +0200 Subject: [PATCH 102/397] dts: arm: st: stm32g4: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/g4/stm32g4.dtsi | 1 + dts/arm/st/g4/stm32g431X6.dtsi | 1 - dts/arm/st/g4/stm32g431X8.dtsi | 1 - dts/arm/st/g4/stm32g431Xb.dtsi | 1 - dts/arm/st/g4/stm32g441Xb.dtsi | 1 - dts/arm/st/g4/stm32g473Xb.dtsi | 1 - dts/arm/st/g4/stm32g473Xc.dtsi | 1 - dts/arm/st/g4/stm32g473Xe.dtsi | 1 - dts/arm/st/g4/stm32g474Xb.dtsi | 1 - dts/arm/st/g4/stm32g474Xc.dtsi | 1 - dts/arm/st/g4/stm32g474Xe.dtsi | 1 - dts/arm/st/g4/stm32g483Xe.dtsi | 1 - dts/arm/st/g4/stm32g484Xe.dtsi | 1 - dts/arm/st/g4/stm32g491Xc.dtsi | 1 - dts/arm/st/g4/stm32g491Xe.dtsi | 1 - dts/arm/st/g4/stm32g4a1Xe.dtsi | 1 - 16 files changed, 1 insertion(+), 15 deletions(-) diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index c34462a25fb17..acdbec7bf00ee 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/g4/stm32g431X6.dtsi b/dts/arm/st/g4/stm32g431X6.dtsi index 88763de8c639d..94eca168376d8 100644 --- a/dts/arm/st/g4/stm32g431X6.dtsi +++ b/dts/arm/st/g4/stm32g431X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g431X8.dtsi b/dts/arm/st/g4/stm32g431X8.dtsi index 2ffcae57da153..68fb7fdd56a3e 100644 --- a/dts/arm/st/g4/stm32g431X8.dtsi +++ b/dts/arm/st/g4/stm32g431X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g431Xb.dtsi b/dts/arm/st/g4/stm32g431Xb.dtsi index b47afad2ca2db..3412dfb962659 100644 --- a/dts/arm/st/g4/stm32g431Xb.dtsi +++ b/dts/arm/st/g4/stm32g431Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g441Xb.dtsi b/dts/arm/st/g4/stm32g441Xb.dtsi index e5e2a2a1fbbab..e559fc9b15968 100644 --- a/dts/arm/st/g4/stm32g441Xb.dtsi +++ b/dts/arm/st/g4/stm32g441Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g473Xb.dtsi b/dts/arm/st/g4/stm32g473Xb.dtsi index dba276e056396..914efb344f7ac 100644 --- a/dts/arm/st/g4/stm32g473Xb.dtsi +++ b/dts/arm/st/g4/stm32g473Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g473Xc.dtsi b/dts/arm/st/g4/stm32g473Xc.dtsi index 61c30f4b7f1ec..041fcc6a4421d 100644 --- a/dts/arm/st/g4/stm32g473Xc.dtsi +++ b/dts/arm/st/g4/stm32g473Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g473Xe.dtsi b/dts/arm/st/g4/stm32g473Xe.dtsi index 454f2efbe87e2..dfe364ad607fa 100644 --- a/dts/arm/st/g4/stm32g473Xe.dtsi +++ b/dts/arm/st/g4/stm32g473Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g474Xb.dtsi b/dts/arm/st/g4/stm32g474Xb.dtsi index f66a70f01373f..aedf1c4dece70 100644 --- a/dts/arm/st/g4/stm32g474Xb.dtsi +++ b/dts/arm/st/g4/stm32g474Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g474Xc.dtsi b/dts/arm/st/g4/stm32g474Xc.dtsi index e9c6f9b2a8ea4..4dcc96193806f 100644 --- a/dts/arm/st/g4/stm32g474Xc.dtsi +++ b/dts/arm/st/g4/stm32g474Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g474Xe.dtsi b/dts/arm/st/g4/stm32g474Xe.dtsi index a8512d56f3085..cca44161b1f35 100644 --- a/dts/arm/st/g4/stm32g474Xe.dtsi +++ b/dts/arm/st/g4/stm32g474Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g483Xe.dtsi b/dts/arm/st/g4/stm32g483Xe.dtsi index 296f8c1562c8c..b077e15ae6c45 100644 --- a/dts/arm/st/g4/stm32g483Xe.dtsi +++ b/dts/arm/st/g4/stm32g483Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g484Xe.dtsi b/dts/arm/st/g4/stm32g484Xe.dtsi index 49f5edcc80746..94610912094e3 100644 --- a/dts/arm/st/g4/stm32g484Xe.dtsi +++ b/dts/arm/st/g4/stm32g484Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g491Xc.dtsi b/dts/arm/st/g4/stm32g491Xc.dtsi index 07f6f6260cdb1..2698e01e796f5 100644 --- a/dts/arm/st/g4/stm32g491Xc.dtsi +++ b/dts/arm/st/g4/stm32g491Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g491Xe.dtsi b/dts/arm/st/g4/stm32g491Xe.dtsi index 96e5730dcca17..da61ce9fc2056 100644 --- a/dts/arm/st/g4/stm32g491Xe.dtsi +++ b/dts/arm/st/g4/stm32g491Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { diff --git a/dts/arm/st/g4/stm32g4a1Xe.dtsi b/dts/arm/st/g4/stm32g4a1Xe.dtsi index 8e318ea95c019..32056eb61dd81 100644 --- a/dts/arm/st/g4/stm32g4a1Xe.dtsi +++ b/dts/arm/st/g4/stm32g4a1Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include &sram0 { From 9dd66037fd2c97ff3e35fe55cb4d165ff297c372 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:15 +0200 Subject: [PATCH 103/397] dts: arm: st: stm32h5: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/h5/stm32h5.dtsi | 1 + dts/arm/st/h5/stm32h503Xb.dtsi | 1 - dts/arm/st/h5/stm32h523Xe.dtsi | 1 - dts/arm/st/h5/stm32h533Xe.dtsi | 1 - dts/arm/st/h5/stm32h562.dtsi | 1 - dts/arm/st/h5/stm32h562Xg.dtsi | 1 - dts/arm/st/h5/stm32h563Xi.dtsi | 1 - dts/arm/st/h5/stm32h573Xi.dtsi | 1 - 8 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index a40802b2e8af8..a5ad1fb67a86b 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -14,6 +14,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/h5/stm32h503Xb.dtsi b/dts/arm/st/h5/stm32h503Xb.dtsi index 22fc4d042dfcc..ccdda3a20bbf7 100644 --- a/dts/arm/st/h5/stm32h503Xb.dtsi +++ b/dts/arm/st/h5/stm32h503Xb.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h5/stm32h523Xe.dtsi b/dts/arm/st/h5/stm32h523Xe.dtsi index fc122088d298c..4d1137a6431bc 100644 --- a/dts/arm/st/h5/stm32h523Xe.dtsi +++ b/dts/arm/st/h5/stm32h523Xe.dtsi @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h5/stm32h533Xe.dtsi b/dts/arm/st/h5/stm32h533Xe.dtsi index 7b3b530f6a7ef..f09a43622b38e 100644 --- a/dts/arm/st/h5/stm32h533Xe.dtsi +++ b/dts/arm/st/h5/stm32h533Xe.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h5/stm32h562.dtsi b/dts/arm/st/h5/stm32h562.dtsi index 065cc6a927781..3e8ff990e9728 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -8,7 +8,6 @@ #include /* keep both header files for compatibility */ #include -#include / { clocks { diff --git a/dts/arm/st/h5/stm32h562Xg.dtsi b/dts/arm/st/h5/stm32h562Xg.dtsi index 969c61d5d9c7f..caf9948001d4f 100644 --- a/dts/arm/st/h5/stm32h562Xg.dtsi +++ b/dts/arm/st/h5/stm32h562Xg.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h5/stm32h563Xi.dtsi b/dts/arm/st/h5/stm32h563Xi.dtsi index d6908b65e8ef1..31f385209853a 100644 --- a/dts/arm/st/h5/stm32h563Xi.dtsi +++ b/dts/arm/st/h5/stm32h563Xi.dtsi @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h5/stm32h573Xi.dtsi b/dts/arm/st/h5/stm32h573Xi.dtsi index 1a61321a82aaa..88be6598780bf 100644 --- a/dts/arm/st/h5/stm32h573Xi.dtsi +++ b/dts/arm/st/h5/stm32h573Xi.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From ab5b40e86a7f1428bb1747a6629336ad1bcd5372 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:20 +0200 Subject: [PATCH 104/397] dts: arm: st: stm32h7: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/h7/stm32h7.dtsi | 1 + dts/arm/st/h7/stm32h723.dtsi | 1 - dts/arm/st/h7/stm32h723Xe.dtsi | 1 - dts/arm/st/h7/stm32h723Xg.dtsi | 1 - dts/arm/st/h7/stm32h725Xe.dtsi | 1 - dts/arm/st/h7/stm32h725Xg.dtsi | 1 - dts/arm/st/h7/stm32h730Xb.dtsi | 1 - dts/arm/st/h7/stm32h735Xg.dtsi | 1 - dts/arm/st/h7/stm32h742Xg.dtsi | 1 - dts/arm/st/h7/stm32h742Xi.dtsi | 1 - dts/arm/st/h7/stm32h743Xg.dtsi | 1 - dts/arm/st/h7/stm32h743Xi.dtsi | 1 - dts/arm/st/h7/stm32h745Xi_m4.dtsi | 1 - dts/arm/st/h7/stm32h745Xi_m7.dtsi | 1 - dts/arm/st/h7/stm32h747Xi_m4.dtsi | 1 - dts/arm/st/h7/stm32h747Xi_m7.dtsi | 1 - dts/arm/st/h7/stm32h750Xb.dtsi | 1 - dts/arm/st/h7/stm32h753Xi.dtsi | 1 - dts/arm/st/h7/stm32h755Xi_m4.dtsi | 1 - dts/arm/st/h7/stm32h755Xi_m7.dtsi | 1 - dts/arm/st/h7/stm32h757Xi_m4.dtsi | 1 - dts/arm/st/h7/stm32h757Xi_m7.dtsi | 1 - dts/arm/st/h7/stm32h7a3Xi.dtsi | 1 - dts/arm/st/h7/stm32h7b0.dtsi | 1 - dts/arm/st/h7/stm32h7b0Xb.dtsi | 1 - dts/arm/st/h7/stm32h7b3.dtsi | 1 - dts/arm/st/h7/stm32h7b3Xi.dtsi | 1 - 27 files changed, 1 insertion(+), 26 deletions(-) diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 1ff9e1aa5892c..6028d38755dd0 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -23,6 +23,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/h7/stm32h723.dtsi b/dts/arm/st/h7/stm32h723.dtsi index 961e634bbe1ae..466c0d5b513ad 100644 --- a/dts/arm/st/h7/stm32h723.dtsi +++ b/dts/arm/st/h7/stm32h723.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include #include diff --git a/dts/arm/st/h7/stm32h723Xe.dtsi b/dts/arm/st/h7/stm32h723Xe.dtsi index 99c6f2f81f2c8..a13253945c9c5 100644 --- a/dts/arm/st/h7/stm32h723Xe.dtsi +++ b/dts/arm/st/h7/stm32h723Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h723Xg.dtsi b/dts/arm/st/h7/stm32h723Xg.dtsi index 9f18bebfd3795..e094c72e323c3 100644 --- a/dts/arm/st/h7/stm32h723Xg.dtsi +++ b/dts/arm/st/h7/stm32h723Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h725Xe.dtsi b/dts/arm/st/h7/stm32h725Xe.dtsi index 947588898d082..6225bda7fc19c 100644 --- a/dts/arm/st/h7/stm32h725Xe.dtsi +++ b/dts/arm/st/h7/stm32h725Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h725Xg.dtsi b/dts/arm/st/h7/stm32h725Xg.dtsi index 46528b1d2489f..c510798a0b6c2 100644 --- a/dts/arm/st/h7/stm32h725Xg.dtsi +++ b/dts/arm/st/h7/stm32h725Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h730Xb.dtsi b/dts/arm/st/h7/stm32h730Xb.dtsi index 48f67f1331c13..b41a10398da97 100644 --- a/dts/arm/st/h7/stm32h730Xb.dtsi +++ b/dts/arm/st/h7/stm32h730Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h735Xg.dtsi b/dts/arm/st/h7/stm32h735Xg.dtsi index d2644a2d0ca9b..5472079e10481 100644 --- a/dts/arm/st/h7/stm32h735Xg.dtsi +++ b/dts/arm/st/h7/stm32h735Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h742Xg.dtsi b/dts/arm/st/h7/stm32h742Xg.dtsi index 72ba15dd7b08e..fd32aa842b4cc 100644 --- a/dts/arm/st/h7/stm32h742Xg.dtsi +++ b/dts/arm/st/h7/stm32h742Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h742Xi.dtsi b/dts/arm/st/h7/stm32h742Xi.dtsi index f00aad5be1c3b..55da5315021ac 100644 --- a/dts/arm/st/h7/stm32h742Xi.dtsi +++ b/dts/arm/st/h7/stm32h742Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h743Xg.dtsi b/dts/arm/st/h7/stm32h743Xg.dtsi index d90a2e01512e6..06dce761b41e3 100644 --- a/dts/arm/st/h7/stm32h743Xg.dtsi +++ b/dts/arm/st/h7/stm32h743Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h743Xi.dtsi b/dts/arm/st/h7/stm32h743Xi.dtsi index 490185ae2a588..9ab3ef625b3f2 100644 --- a/dts/arm/st/h7/stm32h743Xi.dtsi +++ b/dts/arm/st/h7/stm32h743Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h745Xi_m4.dtsi b/dts/arm/st/h7/stm32h745Xi_m4.dtsi index 8ad4e0f871e75..087241ccb7c26 100644 --- a/dts/arm/st/h7/stm32h745Xi_m4.dtsi +++ b/dts/arm/st/h7/stm32h745Xi_m4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash0; diff --git a/dts/arm/st/h7/stm32h745Xi_m7.dtsi b/dts/arm/st/h7/stm32h745Xi_m7.dtsi index 0e79c0150f352..a529f9e392ad7 100644 --- a/dts/arm/st/h7/stm32h745Xi_m7.dtsi +++ b/dts/arm/st/h7/stm32h745Xi_m7.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash1; diff --git a/dts/arm/st/h7/stm32h747Xi_m4.dtsi b/dts/arm/st/h7/stm32h747Xi_m4.dtsi index e8a77592bf96c..6c45ff6882329 100644 --- a/dts/arm/st/h7/stm32h747Xi_m4.dtsi +++ b/dts/arm/st/h7/stm32h747Xi_m4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash0; diff --git a/dts/arm/st/h7/stm32h747Xi_m7.dtsi b/dts/arm/st/h7/stm32h747Xi_m7.dtsi index bc7791dbf8865..13f0d42c504c4 100644 --- a/dts/arm/st/h7/stm32h747Xi_m7.dtsi +++ b/dts/arm/st/h7/stm32h747Xi_m7.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash1; diff --git a/dts/arm/st/h7/stm32h750Xb.dtsi b/dts/arm/st/h7/stm32h750Xb.dtsi index 7d77cca87ff8f..89e18cb6eeaf3 100644 --- a/dts/arm/st/h7/stm32h750Xb.dtsi +++ b/dts/arm/st/h7/stm32h750Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h753Xi.dtsi b/dts/arm/st/h7/stm32h753Xi.dtsi index 39e68e90a953f..ee41aab66338b 100644 --- a/dts/arm/st/h7/stm32h753Xi.dtsi +++ b/dts/arm/st/h7/stm32h753Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h755Xi_m4.dtsi b/dts/arm/st/h7/stm32h755Xi_m4.dtsi index 81d3d3da2fc8b..d1317b117f4f4 100644 --- a/dts/arm/st/h7/stm32h755Xi_m4.dtsi +++ b/dts/arm/st/h7/stm32h755Xi_m4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash0; diff --git a/dts/arm/st/h7/stm32h755Xi_m7.dtsi b/dts/arm/st/h7/stm32h755Xi_m7.dtsi index 47d80cb178741..3f2b99e27f924 100644 --- a/dts/arm/st/h7/stm32h755Xi_m7.dtsi +++ b/dts/arm/st/h7/stm32h755Xi_m7.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash1; diff --git a/dts/arm/st/h7/stm32h757Xi_m4.dtsi b/dts/arm/st/h7/stm32h757Xi_m4.dtsi index 0d9909a83c664..8f11d7d922d29 100644 --- a/dts/arm/st/h7/stm32h757Xi_m4.dtsi +++ b/dts/arm/st/h7/stm32h757Xi_m4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash0; diff --git a/dts/arm/st/h7/stm32h757Xi_m7.dtsi b/dts/arm/st/h7/stm32h757Xi_m7.dtsi index bf23d7687b3fb..180a10a325e98 100644 --- a/dts/arm/st/h7/stm32h757Xi_m7.dtsi +++ b/dts/arm/st/h7/stm32h757Xi_m7.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &flash1; diff --git a/dts/arm/st/h7/stm32h7a3Xi.dtsi b/dts/arm/st/h7/stm32h7a3Xi.dtsi index 6502bf5be15ba..36f136750f033 100644 --- a/dts/arm/st/h7/stm32h7a3Xi.dtsi +++ b/dts/arm/st/h7/stm32h7a3Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h7b0.dtsi b/dts/arm/st/h7/stm32h7b0.dtsi index 556b1fa2e7823..8b039fab4b77b 100644 --- a/dts/arm/st/h7/stm32h7b0.dtsi +++ b/dts/arm/st/h7/stm32h7b0.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /* diff --git a/dts/arm/st/h7/stm32h7b0Xb.dtsi b/dts/arm/st/h7/stm32h7b0Xb.dtsi index 9136d8058cdcd..d851668c536ce 100644 --- a/dts/arm/st/h7/stm32h7b0Xb.dtsi +++ b/dts/arm/st/h7/stm32h7b0Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7/stm32h7b3.dtsi b/dts/arm/st/h7/stm32h7b3.dtsi index f8b583b9d751e..c9fefc9dc99ca 100644 --- a/dts/arm/st/h7/stm32h7b3.dtsi +++ b/dts/arm/st/h7/stm32h7b3.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /* diff --git a/dts/arm/st/h7/stm32h7b3Xi.dtsi b/dts/arm/st/h7/stm32h7b3Xi.dtsi index 7f15bd91f5f65..7257aad0fa96b 100644 --- a/dts/arm/st/h7/stm32h7b3Xi.dtsi +++ b/dts/arm/st/h7/stm32h7b3Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 3fff99bde2d88fef33ed304e3ca56980eff37471 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:27 +0200 Subject: [PATCH 105/397] dts: arm: st: stm32h7rs: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/h7rs/stm32h7r3.dtsi | 1 - dts/arm/st/h7rs/stm32h7r3X8.dtsi | 1 - dts/arm/st/h7rs/stm32h7r7.dtsi | 1 - dts/arm/st/h7rs/stm32h7r7X8.dtsi | 1 - dts/arm/st/h7rs/stm32h7rs.dtsi | 1 + dts/arm/st/h7rs/stm32h7s3.dtsi | 1 - dts/arm/st/h7rs/stm32h7s3X8.dtsi | 1 - dts/arm/st/h7rs/stm32h7s7.dtsi | 1 - dts/arm/st/h7rs/stm32h7s7X8.dtsi | 1 - 9 files changed, 1 insertion(+), 8 deletions(-) diff --git a/dts/arm/st/h7rs/stm32h7r3.dtsi b/dts/arm/st/h7rs/stm32h7r3.dtsi index 1e18970f134d6..58740b4fc79d4 100644 --- a/dts/arm/st/h7rs/stm32h7r3.dtsi +++ b/dts/arm/st/h7rs/stm32h7r3.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7rs/stm32h7r3X8.dtsi b/dts/arm/st/h7rs/stm32h7r3X8.dtsi index 77e5f728e9499..a6e18c4019e7f 100644 --- a/dts/arm/st/h7rs/stm32h7r3X8.dtsi +++ b/dts/arm/st/h7rs/stm32h7r3X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7rs/stm32h7r7.dtsi b/dts/arm/st/h7rs/stm32h7r7.dtsi index bdc347798c8ca..715cb6eafdd24 100644 --- a/dts/arm/st/h7rs/stm32h7r7.dtsi +++ b/dts/arm/st/h7rs/stm32h7r7.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /* diff --git a/dts/arm/st/h7rs/stm32h7r7X8.dtsi b/dts/arm/st/h7rs/stm32h7r7X8.dtsi index 11ac37be01f31..fa233f17513d8 100644 --- a/dts/arm/st/h7rs/stm32h7r7X8.dtsi +++ b/dts/arm/st/h7rs/stm32h7r7X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7rs/stm32h7rs.dtsi b/dts/arm/st/h7rs/stm32h7rs.dtsi index 15be4b8c3c18d..94694138f1e98 100644 --- a/dts/arm/st/h7rs/stm32h7rs.dtsi +++ b/dts/arm/st/h7rs/stm32h7rs.dtsi @@ -19,6 +19,7 @@ #include #include #include +#include /* * STM32H7RS line contains has many common peripherals with STM32H7. diff --git a/dts/arm/st/h7rs/stm32h7s3.dtsi b/dts/arm/st/h7rs/stm32h7s3.dtsi index f1d490266b7dd..3fd358c1d60ab 100644 --- a/dts/arm/st/h7rs/stm32h7s3.dtsi +++ b/dts/arm/st/h7rs/stm32h7s3.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /* diff --git a/dts/arm/st/h7rs/stm32h7s3X8.dtsi b/dts/arm/st/h7rs/stm32h7s3X8.dtsi index bd450eb04824b..7e28014171fb0 100644 --- a/dts/arm/st/h7rs/stm32h7s3X8.dtsi +++ b/dts/arm/st/h7rs/stm32h7s3X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/h7rs/stm32h7s7.dtsi b/dts/arm/st/h7rs/stm32h7s7.dtsi index 7566df2cfe9c8..7d949d84bdca2 100644 --- a/dts/arm/st/h7rs/stm32h7s7.dtsi +++ b/dts/arm/st/h7rs/stm32h7s7.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /* diff --git a/dts/arm/st/h7rs/stm32h7s7X8.dtsi b/dts/arm/st/h7rs/stm32h7s7X8.dtsi index aa4b805793801..78d0890ee1d14 100644 --- a/dts/arm/st/h7rs/stm32h7s7X8.dtsi +++ b/dts/arm/st/h7rs/stm32h7s7X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 98539cb0140cc4056abf1464a0bdc440e2cdbc75 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:33 +0200 Subject: [PATCH 106/397] dts: arm: st: stm32l0: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/l0/stm32l0.dtsi | 1 + dts/arm/st/l0/stm32l010X4.dtsi | 1 - dts/arm/st/l0/stm32l010X6.dtsi | 1 - dts/arm/st/l0/stm32l010X8.dtsi | 1 - dts/arm/st/l0/stm32l010Xb.dtsi | 1 - dts/arm/st/l0/stm32l011X4.dtsi | 1 - dts/arm/st/l0/stm32l031X6.dtsi | 1 - dts/arm/st/l0/stm32l051X6.dtsi | 1 - dts/arm/st/l0/stm32l051X8.dtsi | 2 -- dts/arm/st/l0/stm32l053X8.dtsi | 1 - dts/arm/st/l0/stm32l071X8.dtsi | 1 - dts/arm/st/l0/stm32l071Xb.dtsi | 1 - dts/arm/st/l0/stm32l071Xz.dtsi | 1 - dts/arm/st/l0/stm32l072Xz.dtsi | 1 - dts/arm/st/l0/stm32l073Xz.dtsi | 1 - dts/arm/st/l0/stm32l081Xz.dtsi | 1 - dts/arm/st/l0/stm32l083Xz.dtsi | 1 - 17 files changed, 1 insertion(+), 17 deletions(-) diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index ef3003d46dbf6..930c2548f9112 100644 --- a/dts/arm/st/l0/stm32l0.dtsi +++ b/dts/arm/st/l0/stm32l0.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/l0/stm32l010X4.dtsi b/dts/arm/st/l0/stm32l010X4.dtsi index e9cfbca6d040a..fa823b934ebcd 100644 --- a/dts/arm/st/l0/stm32l010X4.dtsi +++ b/dts/arm/st/l0/stm32l010X4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l010X6.dtsi b/dts/arm/st/l0/stm32l010X6.dtsi index 94fd9694a2fdd..1b5762fef583b 100644 --- a/dts/arm/st/l0/stm32l010X6.dtsi +++ b/dts/arm/st/l0/stm32l010X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l010X8.dtsi b/dts/arm/st/l0/stm32l010X8.dtsi index 2084b779767d7..0996c32d88746 100644 --- a/dts/arm/st/l0/stm32l010X8.dtsi +++ b/dts/arm/st/l0/stm32l010X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l010Xb.dtsi b/dts/arm/st/l0/stm32l010Xb.dtsi index 16911c6efdd13..b44f88ec480a7 100644 --- a/dts/arm/st/l0/stm32l010Xb.dtsi +++ b/dts/arm/st/l0/stm32l010Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l011X4.dtsi b/dts/arm/st/l0/stm32l011X4.dtsi index 1ed58b1dc2ffe..ae4b3631204ef 100644 --- a/dts/arm/st/l0/stm32l011X4.dtsi +++ b/dts/arm/st/l0/stm32l011X4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l031X6.dtsi b/dts/arm/st/l0/stm32l031X6.dtsi index 80bea705c5f71..3d204e1fd823e 100644 --- a/dts/arm/st/l0/stm32l031X6.dtsi +++ b/dts/arm/st/l0/stm32l031X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l051X6.dtsi b/dts/arm/st/l0/stm32l051X6.dtsi index 5dff4e3e00834..d8ee80fd64389 100644 --- a/dts/arm/st/l0/stm32l051X6.dtsi +++ b/dts/arm/st/l0/stm32l051X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l051X8.dtsi b/dts/arm/st/l0/stm32l051X8.dtsi index 34fb63d97cd28..56b74a1cdea3a 100644 --- a/dts/arm/st/l0/stm32l051X8.dtsi +++ b/dts/arm/st/l0/stm32l051X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { @@ -20,4 +19,3 @@ }; }; }; - diff --git a/dts/arm/st/l0/stm32l053X8.dtsi b/dts/arm/st/l0/stm32l053X8.dtsi index 52f9dade965c5..2f797f079e287 100644 --- a/dts/arm/st/l0/stm32l053X8.dtsi +++ b/dts/arm/st/l0/stm32l053X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l071X8.dtsi b/dts/arm/st/l0/stm32l071X8.dtsi index 4f0fe482c0fee..4c791cda9fa34 100644 --- a/dts/arm/st/l0/stm32l071X8.dtsi +++ b/dts/arm/st/l0/stm32l071X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l071Xb.dtsi b/dts/arm/st/l0/stm32l071Xb.dtsi index 83e4efcc24da9..b2747cd49eccd 100644 --- a/dts/arm/st/l0/stm32l071Xb.dtsi +++ b/dts/arm/st/l0/stm32l071Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l071Xz.dtsi b/dts/arm/st/l0/stm32l071Xz.dtsi index 78566a5d62b1d..e9d425dc7e9ff 100644 --- a/dts/arm/st/l0/stm32l071Xz.dtsi +++ b/dts/arm/st/l0/stm32l071Xz.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l072Xz.dtsi b/dts/arm/st/l0/stm32l072Xz.dtsi index e30ac5d3d1e7b..38b14c4fa6121 100644 --- a/dts/arm/st/l0/stm32l072Xz.dtsi +++ b/dts/arm/st/l0/stm32l072Xz.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l073Xz.dtsi b/dts/arm/st/l0/stm32l073Xz.dtsi index 27f6a57fe79be..7b57194ecd6c2 100644 --- a/dts/arm/st/l0/stm32l073Xz.dtsi +++ b/dts/arm/st/l0/stm32l073Xz.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l081Xz.dtsi b/dts/arm/st/l0/stm32l081Xz.dtsi index d6f28ceecceb4..f76f31da7bb35 100644 --- a/dts/arm/st/l0/stm32l081Xz.dtsi +++ b/dts/arm/st/l0/stm32l081Xz.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l0/stm32l083Xz.dtsi b/dts/arm/st/l0/stm32l083Xz.dtsi index 0166c972c0dde..31b412284db38 100644 --- a/dts/arm/st/l0/stm32l083Xz.dtsi +++ b/dts/arm/st/l0/stm32l083Xz.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From b9c4ec6877041c83fcd4dfc51e9c2ce6972eacae Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:40 +0200 Subject: [PATCH 107/397] dts: arm: st: stm32l1: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/l1/stm32l1.dtsi | 1 + dts/arm/st/l1/stm32l100Xb.dtsi | 1 - dts/arm/st/l1/stm32l151X8-a.dtsi | 1 - dts/arm/st/l1/stm32l151Xb-a.dtsi | 1 - dts/arm/st/l1/stm32l151Xb.dtsi | 1 - dts/arm/st/l1/stm32l151Xc.dtsi | 1 - dts/arm/st/l1/stm32l152Xc.dtsi | 1 - dts/arm/st/l1/stm32l152Xe.dtsi | 1 - 8 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index f39e36e0ea853..fd8ba55e993fd 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -19,6 +19,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/l1/stm32l100Xb.dtsi b/dts/arm/st/l1/stm32l100Xb.dtsi index db0a128bdf588..65f48486dd4ea 100644 --- a/dts/arm/st/l1/stm32l100Xb.dtsi +++ b/dts/arm/st/l1/stm32l100Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l1/stm32l151X8-a.dtsi b/dts/arm/st/l1/stm32l151X8-a.dtsi index 90a7e59eecf33..dca7ae0840d06 100644 --- a/dts/arm/st/l1/stm32l151X8-a.dtsi +++ b/dts/arm/st/l1/stm32l151X8-a.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l1/stm32l151Xb-a.dtsi b/dts/arm/st/l1/stm32l151Xb-a.dtsi index 8c06bec299cd5..24e971e04d945 100644 --- a/dts/arm/st/l1/stm32l151Xb-a.dtsi +++ b/dts/arm/st/l1/stm32l151Xb-a.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l1/stm32l151Xb.dtsi b/dts/arm/st/l1/stm32l151Xb.dtsi index b98578b315145..eed574245e284 100644 --- a/dts/arm/st/l1/stm32l151Xb.dtsi +++ b/dts/arm/st/l1/stm32l151Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l1/stm32l151Xc.dtsi b/dts/arm/st/l1/stm32l151Xc.dtsi index a5fbb0fb93396..210f29b63b841 100644 --- a/dts/arm/st/l1/stm32l151Xc.dtsi +++ b/dts/arm/st/l1/stm32l151Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include diff --git a/dts/arm/st/l1/stm32l152Xc.dtsi b/dts/arm/st/l1/stm32l152Xc.dtsi index 8665396ccf743..227b85127dcba 100644 --- a/dts/arm/st/l1/stm32l152Xc.dtsi +++ b/dts/arm/st/l1/stm32l152Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include diff --git a/dts/arm/st/l1/stm32l152Xe.dtsi b/dts/arm/st/l1/stm32l152Xe.dtsi index 09187903342ea..92cb29ef00182 100644 --- a/dts/arm/st/l1/stm32l152Xe.dtsi +++ b/dts/arm/st/l1/stm32l152Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include From a38e6241c3d5c08b63afff3c66e1bfa355a6000b Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:48 +0200 Subject: [PATCH 108/397] dts: arm: st: stm32l4: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/l4/stm32l4.dtsi | 1 + dts/arm/st/l4/stm32l412X8.dtsi | 1 - dts/arm/st/l4/stm32l412XB.dtsi | 1 - dts/arm/st/l4/stm32l422Xb.dtsi | 1 - dts/arm/st/l4/stm32l431Xb.dtsi | 1 - dts/arm/st/l4/stm32l431Xc.dtsi | 1 - dts/arm/st/l4/stm32l432Xc.dtsi | 1 - dts/arm/st/l4/stm32l433Xb.dtsi | 1 - dts/arm/st/l4/stm32l433Xc.dtsi | 1 - dts/arm/st/l4/stm32l451Xc.dtsi | 1 - dts/arm/st/l4/stm32l451Xe.dtsi | 1 - dts/arm/st/l4/stm32l452Xc.dtsi | 1 - dts/arm/st/l4/stm32l452Xe.dtsi | 1 - dts/arm/st/l4/stm32l462Xe.dtsi | 1 - dts/arm/st/l4/stm32l471Xg.dtsi | 1 - dts/arm/st/l4/stm32l475Xe.dtsi | 1 - dts/arm/st/l4/stm32l475Xg.dtsi | 1 - dts/arm/st/l4/stm32l476Xg.dtsi | 1 - dts/arm/st/l4/stm32l486Xg.dtsi | 1 - dts/arm/st/l4/stm32l496Xe.dtsi | 1 - dts/arm/st/l4/stm32l496Xg.dtsi | 1 - dts/arm/st/l4/stm32l4a6Xg.dtsi | 1 - dts/arm/st/l4/stm32l4p5.dtsi | 1 - dts/arm/st/l4/stm32l4p5Xi.dtsi | 1 - dts/arm/st/l4/stm32l4r5.dtsi | 1 - dts/arm/st/l4/stm32l4r5Xi.dtsi | 1 - dts/arm/st/l4/stm32l4r9.dtsi | 1 - dts/arm/st/l4/stm32l4r9Xi.dtsi | 1 - dts/arm/st/l4/stm32l4s5Xi.dtsi | 1 - 29 files changed, 1 insertion(+), 28 deletions(-) diff --git a/dts/arm/st/l4/stm32l4.dtsi b/dts/arm/st/l4/stm32l4.dtsi index 025bb3279b51a..5dfd821112dcf 100644 --- a/dts/arm/st/l4/stm32l4.dtsi +++ b/dts/arm/st/l4/stm32l4.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/l4/stm32l412X8.dtsi b/dts/arm/st/l4/stm32l412X8.dtsi index 9c66aa8ed6889..3114dc989025d 100644 --- a/dts/arm/st/l4/stm32l412X8.dtsi +++ b/dts/arm/st/l4/stm32l412X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l412XB.dtsi b/dts/arm/st/l4/stm32l412XB.dtsi index 438e15a254731..00ddd72f10338 100644 --- a/dts/arm/st/l4/stm32l412XB.dtsi +++ b/dts/arm/st/l4/stm32l412XB.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l422Xb.dtsi b/dts/arm/st/l4/stm32l422Xb.dtsi index 3284865f70d22..87c769364a3ba 100644 --- a/dts/arm/st/l4/stm32l422Xb.dtsi +++ b/dts/arm/st/l4/stm32l422Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l431Xb.dtsi b/dts/arm/st/l4/stm32l431Xb.dtsi index 75331215ea7d7..c423260da60c9 100644 --- a/dts/arm/st/l4/stm32l431Xb.dtsi +++ b/dts/arm/st/l4/stm32l431Xb.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l431Xc.dtsi b/dts/arm/st/l4/stm32l431Xc.dtsi index c1c382504e597..3ff9140a21312 100644 --- a/dts/arm/st/l4/stm32l431Xc.dtsi +++ b/dts/arm/st/l4/stm32l431Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l432Xc.dtsi b/dts/arm/st/l4/stm32l432Xc.dtsi index 59b6e23cb438d..eb59936d0ded1 100644 --- a/dts/arm/st/l4/stm32l432Xc.dtsi +++ b/dts/arm/st/l4/stm32l432Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l433Xb.dtsi b/dts/arm/st/l4/stm32l433Xb.dtsi index 0c0a1044ac66d..7736a011bc049 100644 --- a/dts/arm/st/l4/stm32l433Xb.dtsi +++ b/dts/arm/st/l4/stm32l433Xb.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l433Xc.dtsi b/dts/arm/st/l4/stm32l433Xc.dtsi index 8dc414720ef2b..280b7c216b674 100644 --- a/dts/arm/st/l4/stm32l433Xc.dtsi +++ b/dts/arm/st/l4/stm32l433Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l451Xc.dtsi b/dts/arm/st/l4/stm32l451Xc.dtsi index 1eaeaf76a5caa..38809bed88a8b 100644 --- a/dts/arm/st/l4/stm32l451Xc.dtsi +++ b/dts/arm/st/l4/stm32l451Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l451Xe.dtsi b/dts/arm/st/l4/stm32l451Xe.dtsi index e9eccfa6f9a12..139dfe520cc29 100644 --- a/dts/arm/st/l4/stm32l451Xe.dtsi +++ b/dts/arm/st/l4/stm32l451Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l452Xc.dtsi b/dts/arm/st/l4/stm32l452Xc.dtsi index 8b35e5442d2fc..8416bb2e16d87 100644 --- a/dts/arm/st/l4/stm32l452Xc.dtsi +++ b/dts/arm/st/l4/stm32l452Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l452Xe.dtsi b/dts/arm/st/l4/stm32l452Xe.dtsi index 619cbb72c2265..1ea24fff3aeb4 100644 --- a/dts/arm/st/l4/stm32l452Xe.dtsi +++ b/dts/arm/st/l4/stm32l452Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l462Xe.dtsi b/dts/arm/st/l4/stm32l462Xe.dtsi index d73342bb408b4..0fc5996d6fde9 100644 --- a/dts/arm/st/l4/stm32l462Xe.dtsi +++ b/dts/arm/st/l4/stm32l462Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l471Xg.dtsi b/dts/arm/st/l4/stm32l471Xg.dtsi index 91ee767080517..18a00366f4870 100644 --- a/dts/arm/st/l4/stm32l471Xg.dtsi +++ b/dts/arm/st/l4/stm32l471Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l475Xe.dtsi b/dts/arm/st/l4/stm32l475Xe.dtsi index 2c99d3c4b3d21..703db40b9ba37 100644 --- a/dts/arm/st/l4/stm32l475Xe.dtsi +++ b/dts/arm/st/l4/stm32l475Xe.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l475Xg.dtsi b/dts/arm/st/l4/stm32l475Xg.dtsi index a4d959a841c48..49f66535319ac 100644 --- a/dts/arm/st/l4/stm32l475Xg.dtsi +++ b/dts/arm/st/l4/stm32l475Xg.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l476Xg.dtsi b/dts/arm/st/l4/stm32l476Xg.dtsi index 4ed441f715978..f5b02f4f3e9f2 100644 --- a/dts/arm/st/l4/stm32l476Xg.dtsi +++ b/dts/arm/st/l4/stm32l476Xg.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l486Xg.dtsi b/dts/arm/st/l4/stm32l486Xg.dtsi index b3b01dc1cb0ad..99da8f147854d 100644 --- a/dts/arm/st/l4/stm32l486Xg.dtsi +++ b/dts/arm/st/l4/stm32l486Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l496Xe.dtsi b/dts/arm/st/l4/stm32l496Xe.dtsi index 030b17453bf51..b1dce6479344c 100644 --- a/dts/arm/st/l4/stm32l496Xe.dtsi +++ b/dts/arm/st/l4/stm32l496Xe.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l496Xg.dtsi b/dts/arm/st/l4/stm32l496Xg.dtsi index 935f98c392967..786f55035f668 100644 --- a/dts/arm/st/l4/stm32l496Xg.dtsi +++ b/dts/arm/st/l4/stm32l496Xg.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l4a6Xg.dtsi b/dts/arm/st/l4/stm32l4a6Xg.dtsi index 8c5f033100c89..111e83ecd0e0c 100644 --- a/dts/arm/st/l4/stm32l4a6Xg.dtsi +++ b/dts/arm/st/l4/stm32l4a6Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l4p5.dtsi b/dts/arm/st/l4/stm32l4p5.dtsi index 7801a1b43b856..dae55b11d62ce 100644 --- a/dts/arm/st/l4/stm32l4p5.dtsi +++ b/dts/arm/st/l4/stm32l4p5.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include #include diff --git a/dts/arm/st/l4/stm32l4p5Xi.dtsi b/dts/arm/st/l4/stm32l4p5Xi.dtsi index de4d6e4351bf9..3c865424aeef4 100644 --- a/dts/arm/st/l4/stm32l4p5Xi.dtsi +++ b/dts/arm/st/l4/stm32l4p5Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l4r5.dtsi b/dts/arm/st/l4/stm32l4r5.dtsi index 675562a9cc8b4..edb1be954e23d 100644 --- a/dts/arm/st/l4/stm32l4r5.dtsi +++ b/dts/arm/st/l4/stm32l4r5.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include /delete-node/ &sdmmc2; diff --git a/dts/arm/st/l4/stm32l4r5Xi.dtsi b/dts/arm/st/l4/stm32l4r5Xi.dtsi index b5318d1e40d85..1c599f6c3adc4 100644 --- a/dts/arm/st/l4/stm32l4r5Xi.dtsi +++ b/dts/arm/st/l4/stm32l4r5Xi.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l4r9.dtsi b/dts/arm/st/l4/stm32l4r9.dtsi index 1f89d00f21e0f..6ab7cf4ba4a3f 100644 --- a/dts/arm/st/l4/stm32l4r9.dtsi +++ b/dts/arm/st/l4/stm32l4r9.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include diff --git a/dts/arm/st/l4/stm32l4r9Xi.dtsi b/dts/arm/st/l4/stm32l4r9Xi.dtsi index 82fe423ed12c1..d258cd9fa88ce 100644 --- a/dts/arm/st/l4/stm32l4r9Xi.dtsi +++ b/dts/arm/st/l4/stm32l4r9Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l4/stm32l4s5Xi.dtsi b/dts/arm/st/l4/stm32l4s5Xi.dtsi index 870b1d8c7ac34..da64e29d0b818 100644 --- a/dts/arm/st/l4/stm32l4s5Xi.dtsi +++ b/dts/arm/st/l4/stm32l4s5Xi.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 99c4bbb8ca1b29045cc1efb4595e228986c36e4c Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:19:55 +0200 Subject: [PATCH 109/397] dts: arm: st: stm32l5: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/l5/stm32l5.dtsi | 1 + dts/arm/st/l5/stm32l552Xc.dtsi | 1 - dts/arm/st/l5/stm32l552Xe.dtsi | 1 - dts/arm/st/l5/stm32l562Xe.dtsi | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index 5bdc447cd360e..778227d908fbc 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/l5/stm32l552Xc.dtsi b/dts/arm/st/l5/stm32l552Xc.dtsi index 49747ff65f6b6..56e18b1202f56 100644 --- a/dts/arm/st/l5/stm32l552Xc.dtsi +++ b/dts/arm/st/l5/stm32l552Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l5/stm32l552Xe.dtsi b/dts/arm/st/l5/stm32l552Xe.dtsi index a5634a7319e46..9312656918e4f 100644 --- a/dts/arm/st/l5/stm32l552Xe.dtsi +++ b/dts/arm/st/l5/stm32l552Xe.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/l5/stm32l562Xe.dtsi b/dts/arm/st/l5/stm32l562Xe.dtsi index b0216949a2541..73e11c5b9c605 100644 --- a/dts/arm/st/l5/stm32l562Xe.dtsi +++ b/dts/arm/st/l5/stm32l562Xe.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From eddf7f8712af6f4c0934b44352cc2cd02e0a38dc Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:21:39 +0200 Subject: [PATCH 110/397] dts: arm: st: stm32n6: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/n6/stm32n6.dtsi | 1 + dts/arm/st/n6/stm32n657X0.dtsi | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/st/n6/stm32n6.dtsi b/dts/arm/st/n6/stm32n6.dtsi index a61a70f7ed366..537800433f05f 100644 --- a/dts/arm/st/n6/stm32n6.dtsi +++ b/dts/arm/st/n6/stm32n6.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include / { cpus { diff --git a/dts/arm/st/n6/stm32n657X0.dtsi b/dts/arm/st/n6/stm32n657X0.dtsi index ab4cb6f326024..24bcd31fa635e 100644 --- a/dts/arm/st/n6/stm32n657X0.dtsi +++ b/dts/arm/st/n6/stm32n657X0.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 9ad1b848675af018561407fdda5732ecbd07b4ef Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:21:45 +0200 Subject: [PATCH 111/397] dts: arm: st: stm32u0: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/u0/stm32u0.dtsi | 1 + dts/arm/st/u0/stm32u031X4.dtsi | 1 - dts/arm/st/u0/stm32u031X6.dtsi | 1 - dts/arm/st/u0/stm32u031X8.dtsi | 1 - dts/arm/st/u0/stm32u073X8.dtsi | 1 - dts/arm/st/u0/stm32u073Xb.dtsi | 1 - dts/arm/st/u0/stm32u073Xc.dtsi | 1 - dts/arm/st/u0/stm32u083Xc.dtsi | 1 - 8 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dts/arm/st/u0/stm32u0.dtsi b/dts/arm/st/u0/stm32u0.dtsi index a3937f138dc59..ec036136807e8 100644 --- a/dts/arm/st/u0/stm32u0.dtsi +++ b/dts/arm/st/u0/stm32u0.dtsi @@ -15,6 +15,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/u0/stm32u031X4.dtsi b/dts/arm/st/u0/stm32u031X4.dtsi index e52e8e22b7bd7..93b3f6fe32003 100644 --- a/dts/arm/st/u0/stm32u031X4.dtsi +++ b/dts/arm/st/u0/stm32u031X4.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u0/stm32u031X6.dtsi b/dts/arm/st/u0/stm32u031X6.dtsi index d71acf7f465bd..b9ef115660d38 100644 --- a/dts/arm/st/u0/stm32u031X6.dtsi +++ b/dts/arm/st/u0/stm32u031X6.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u0/stm32u031X8.dtsi b/dts/arm/st/u0/stm32u031X8.dtsi index 6a47d7f8161a8..0257bf5683ae9 100644 --- a/dts/arm/st/u0/stm32u031X8.dtsi +++ b/dts/arm/st/u0/stm32u031X8.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u0/stm32u073X8.dtsi b/dts/arm/st/u0/stm32u073X8.dtsi index d64eb0a55466c..058afe1b21b01 100644 --- a/dts/arm/st/u0/stm32u073X8.dtsi +++ b/dts/arm/st/u0/stm32u073X8.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u0/stm32u073Xb.dtsi b/dts/arm/st/u0/stm32u073Xb.dtsi index 25d61bd89fcbe..78462ad14e24a 100644 --- a/dts/arm/st/u0/stm32u073Xb.dtsi +++ b/dts/arm/st/u0/stm32u073Xb.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u0/stm32u073Xc.dtsi b/dts/arm/st/u0/stm32u073Xc.dtsi index 196de255dbd8f..cba0775be2fd5 100644 --- a/dts/arm/st/u0/stm32u073Xc.dtsi +++ b/dts/arm/st/u0/stm32u073Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u0/stm32u083Xc.dtsi b/dts/arm/st/u0/stm32u083Xc.dtsi index 3c0586ca8681e..0fc78f3ef442d 100644 --- a/dts/arm/st/u0/stm32u083Xc.dtsi +++ b/dts/arm/st/u0/stm32u083Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 1f954045e3d5ca99b44dacb7fa80a90dd470d3ba Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:21:59 +0200 Subject: [PATCH 112/397] dts: arm: st: stm32u3: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/u3/stm32u3.dtsi | 1 + dts/arm/st/u3/stm32u385Xg.dtsi | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/st/u3/stm32u3.dtsi b/dts/arm/st/u3/stm32u3.dtsi index 5f5f97a7747b5..4439a20b35b3e 100644 --- a/dts/arm/st/u3/stm32u3.dtsi +++ b/dts/arm/st/u3/stm32u3.dtsi @@ -14,6 +14,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/u3/stm32u385Xg.dtsi b/dts/arm/st/u3/stm32u385Xg.dtsi index e10914ffbd642..6367bd21e210f 100644 --- a/dts/arm/st/u3/stm32u385Xg.dtsi +++ b/dts/arm/st/u3/stm32u385Xg.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From d598fa741edf6778fc066ec6af0b5a8967accf9c Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:22:05 +0200 Subject: [PATCH 113/397] dts: arm: st: stm32u5: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/u5/stm32u5.dtsi | 1 + dts/arm/st/u5/stm32u535Xb.dtsi | 1 - dts/arm/st/u5/stm32u535Xc.dtsi | 1 - dts/arm/st/u5/stm32u535Xe.dtsi | 1 - dts/arm/st/u5/stm32u545Xe.dtsi | 1 - dts/arm/st/u5/stm32u575Xg.dtsi | 1 - dts/arm/st/u5/stm32u575Xi.dtsi | 1 - dts/arm/st/u5/stm32u585Xi.dtsi | 1 - dts/arm/st/u5/stm32u595Xi.dtsi | 1 - dts/arm/st/u5/stm32u595Xj.dtsi | 1 - dts/arm/st/u5/stm32u599.dtsi | 1 - dts/arm/st/u5/stm32u599Xi.dtsi | 1 - dts/arm/st/u5/stm32u599Xj.dtsi | 1 - dts/arm/st/u5/stm32u5a5Xj.dtsi | 1 - dts/arm/st/u5/stm32u5a9Xj.dtsi | 1 - dts/arm/st/u5/stm32u5g9Xj.dtsi | 1 - 16 files changed, 1 insertion(+), 15 deletions(-) diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 3f9106d89ca0e..2b6e76e61cd26 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -21,6 +21,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/u5/stm32u535Xb.dtsi b/dts/arm/st/u5/stm32u535Xb.dtsi index b4d0ab0705980..97fcd30dfd177 100644 --- a/dts/arm/st/u5/stm32u535Xb.dtsi +++ b/dts/arm/st/u5/stm32u535Xb.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u535Xc.dtsi b/dts/arm/st/u5/stm32u535Xc.dtsi index 79fc4d6259486..59be842460e39 100644 --- a/dts/arm/st/u5/stm32u535Xc.dtsi +++ b/dts/arm/st/u5/stm32u535Xc.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u535Xe.dtsi b/dts/arm/st/u5/stm32u535Xe.dtsi index 3586d633dbaa9..18ae5dfd34363 100644 --- a/dts/arm/st/u5/stm32u535Xe.dtsi +++ b/dts/arm/st/u5/stm32u535Xe.dtsi @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u545Xe.dtsi b/dts/arm/st/u5/stm32u545Xe.dtsi index e3af68d2ddb01..65722ac82d227 100644 --- a/dts/arm/st/u5/stm32u545Xe.dtsi +++ b/dts/arm/st/u5/stm32u545Xe.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u575Xg.dtsi b/dts/arm/st/u5/stm32u575Xg.dtsi index 110897534d234..a42dc1fb5ab23 100644 --- a/dts/arm/st/u5/stm32u575Xg.dtsi +++ b/dts/arm/st/u5/stm32u575Xg.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u575Xi.dtsi b/dts/arm/st/u5/stm32u575Xi.dtsi index 77223f3e9546f..e063caebb14b0 100644 --- a/dts/arm/st/u5/stm32u575Xi.dtsi +++ b/dts/arm/st/u5/stm32u575Xi.dtsi @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u585Xi.dtsi b/dts/arm/st/u5/stm32u585Xi.dtsi index fc2dedbf86f62..9153fc5f27428 100644 --- a/dts/arm/st/u5/stm32u585Xi.dtsi +++ b/dts/arm/st/u5/stm32u585Xi.dtsi @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u595Xi.dtsi b/dts/arm/st/u5/stm32u595Xi.dtsi index 549bcc7df9e59..2c305554f3029 100644 --- a/dts/arm/st/u5/stm32u595Xi.dtsi +++ b/dts/arm/st/u5/stm32u595Xi.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u595Xj.dtsi b/dts/arm/st/u5/stm32u595Xj.dtsi index 97b64bebec0c1..8a5e65f8123e9 100644 --- a/dts/arm/st/u5/stm32u595Xj.dtsi +++ b/dts/arm/st/u5/stm32u595Xj.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u599.dtsi b/dts/arm/st/u5/stm32u599.dtsi index 4cb5fbd902df7..0236903fc16ec 100644 --- a/dts/arm/st/u5/stm32u599.dtsi +++ b/dts/arm/st/u5/stm32u599.dtsi @@ -10,7 +10,6 @@ #include #include #include -#include / { soc { diff --git a/dts/arm/st/u5/stm32u599Xi.dtsi b/dts/arm/st/u5/stm32u599Xi.dtsi index be05acee34481..52e995ada337f 100644 --- a/dts/arm/st/u5/stm32u599Xi.dtsi +++ b/dts/arm/st/u5/stm32u599Xi.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u599Xj.dtsi b/dts/arm/st/u5/stm32u599Xj.dtsi index fb2c69c4397c4..6fbc82dfcb8d6 100644 --- a/dts/arm/st/u5/stm32u599Xj.dtsi +++ b/dts/arm/st/u5/stm32u599Xj.dtsi @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u5a5Xj.dtsi b/dts/arm/st/u5/stm32u5a5Xj.dtsi index 2a1e265c6f7c4..734119744622e 100644 --- a/dts/arm/st/u5/stm32u5a5Xj.dtsi +++ b/dts/arm/st/u5/stm32u5a5Xj.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u5a9Xj.dtsi b/dts/arm/st/u5/stm32u5a9Xj.dtsi index 7d89265da7747..662589de09148 100644 --- a/dts/arm/st/u5/stm32u5a9Xj.dtsi +++ b/dts/arm/st/u5/stm32u5a9Xj.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/u5/stm32u5g9Xj.dtsi b/dts/arm/st/u5/stm32u5g9Xj.dtsi index f1df71d48eec5..f06c7d388644d 100644 --- a/dts/arm/st/u5/stm32u5g9Xj.dtsi +++ b/dts/arm/st/u5/stm32u5g9Xj.dtsi @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 7c2615c351cada79b5f9be2447c8c1025e936884 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:22:11 +0200 Subject: [PATCH 114/397] dts: arm: st: stm32wb: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/wb/stm32wb.dtsi | 1 + dts/arm/st/wb/stm32wb55Xg.dtsi | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index 2222ef33b82f9..d467cdcc332bb 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/wb/stm32wb55Xg.dtsi b/dts/arm/st/wb/stm32wb55Xg.dtsi index 0e4a2220038cf..27724e5288513 100644 --- a/dts/arm/st/wb/stm32wb55Xg.dtsi +++ b/dts/arm/st/wb/stm32wb55Xg.dtsi @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From fdb8186554b3de82842c8d322b1067d53dcb4efe Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:22:16 +0200 Subject: [PATCH 115/397] dts: arm: st: stm32wba: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/wba/stm32wba.dtsi | 1 + dts/arm/st/wba/stm32wba52Xg.dtsi | 1 - dts/arm/st/wba/stm32wba55Xg.dtsi | 1 - dts/arm/st/wba/stm32wba65Xi.dtsi | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 2a543b094faa2..2f04f92e671a5 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -16,6 +16,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/wba/stm32wba52Xg.dtsi b/dts/arm/st/wba/stm32wba52Xg.dtsi index ecae645171b4a..e32ede0efdd4a 100644 --- a/dts/arm/st/wba/stm32wba52Xg.dtsi +++ b/dts/arm/st/wba/stm32wba52Xg.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wba/stm32wba55Xg.dtsi b/dts/arm/st/wba/stm32wba55Xg.dtsi index f5c23f031e958..26b44848eccff 100644 --- a/dts/arm/st/wba/stm32wba55Xg.dtsi +++ b/dts/arm/st/wba/stm32wba55Xg.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wba/stm32wba65Xi.dtsi b/dts/arm/st/wba/stm32wba65Xi.dtsi index 422ae59aa3bdd..c348c81f339d5 100644 --- a/dts/arm/st/wba/stm32wba65Xi.dtsi +++ b/dts/arm/st/wba/stm32wba65Xi.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 94df5781f30149b6ed082c8da39d8b2de933dbe3 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Fri, 17 Oct 2025 17:22:22 +0200 Subject: [PATCH 116/397] dts: arm: st: stm32wl: include from series' root DTSI Include from the series' root DTSI file and remove inclusion of the file from other levels since it becomes redundant. This avoids the current situation where the same #include directive is duplicated among many files, and where the file is sometimes included multiple times when walking up the inclusion chain up until the root DTSI file. Signed-off-by: Mathieu Choplain --- dts/arm/st/wl/stm32wl.dtsi | 1 + dts/arm/st/wl/stm32wl54Xc.dtsi | 1 - dts/arm/st/wl/stm32wl55Xc.dtsi | 1 - dts/arm/st/wl/stm32wle4X8.dtsi | 1 - dts/arm/st/wl/stm32wle4Xb.dtsi | 1 - dts/arm/st/wl/stm32wle4Xc.dtsi | 1 - dts/arm/st/wl/stm32wle5X8.dtsi | 1 - dts/arm/st/wl/stm32wle5Xb.dtsi | 1 - dts/arm/st/wl/stm32wle5Xc.dtsi | 1 - 9 files changed, 1 insertion(+), 8 deletions(-) diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index 3f5fd71368f53..1544e96369944 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include / { chosen { diff --git a/dts/arm/st/wl/stm32wl54Xc.dtsi b/dts/arm/st/wl/stm32wl54Xc.dtsi index a7c64b9a9dccf..bb50ec471b321 100644 --- a/dts/arm/st/wl/stm32wl54Xc.dtsi +++ b/dts/arm/st/wl/stm32wl54Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wl/stm32wl55Xc.dtsi b/dts/arm/st/wl/stm32wl55Xc.dtsi index 7c32ca481ae68..573e5758507b4 100644 --- a/dts/arm/st/wl/stm32wl55Xc.dtsi +++ b/dts/arm/st/wl/stm32wl55Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wl/stm32wle4X8.dtsi b/dts/arm/st/wl/stm32wle4X8.dtsi index 925c00a5021a2..70a6fec56f13f 100644 --- a/dts/arm/st/wl/stm32wle4X8.dtsi +++ b/dts/arm/st/wl/stm32wle4X8.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wl/stm32wle4Xb.dtsi b/dts/arm/st/wl/stm32wle4Xb.dtsi index 95679802821e0..b5823308ce192 100644 --- a/dts/arm/st/wl/stm32wle4Xb.dtsi +++ b/dts/arm/st/wl/stm32wle4Xb.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wl/stm32wle4Xc.dtsi b/dts/arm/st/wl/stm32wle4Xc.dtsi index 2b47872d42723..5920be01c4584 100644 --- a/dts/arm/st/wl/stm32wle4Xc.dtsi +++ b/dts/arm/st/wl/stm32wle4Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wl/stm32wle5X8.dtsi b/dts/arm/st/wl/stm32wle5X8.dtsi index 925c00a5021a2..70a6fec56f13f 100644 --- a/dts/arm/st/wl/stm32wle5X8.dtsi +++ b/dts/arm/st/wl/stm32wle5X8.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wl/stm32wle5Xb.dtsi b/dts/arm/st/wl/stm32wle5Xb.dtsi index 95679802821e0..b5823308ce192 100644 --- a/dts/arm/st/wl/stm32wle5Xb.dtsi +++ b/dts/arm/st/wl/stm32wle5Xb.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { diff --git a/dts/arm/st/wl/stm32wle5Xc.dtsi b/dts/arm/st/wl/stm32wle5Xc.dtsi index 2b47872d42723..5920be01c4584 100644 --- a/dts/arm/st/wl/stm32wle5Xc.dtsi +++ b/dts/arm/st/wl/stm32wle5Xc.dtsi @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include #include / { From 4082e3ff86b36252499868ccd61927d918ec73f2 Mon Sep 17 00:00:00 2001 From: Tim Pambor Date: Fri, 17 Oct 2025 15:20:11 +0200 Subject: [PATCH 117/397] samples: canopennode: no_storage: disable program download Boards that use MCUboot to start XIP from external flash default to CONFIG_CANOPENNODE_PROGRAM_DOWNLOAD=y. However, in the no_storage sample, dependencies such as CONFIG_FLASH are disabled. This causes build errors. Work around this by explicitly disabling program download in the no_storage sample configuration. Signed-off-by: Tim Pambor --- samples/modules/canopennode/prj_no_storage.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/modules/canopennode/prj_no_storage.conf b/samples/modules/canopennode/prj_no_storage.conf index 2d0ec6b37963c..b296e8c083202 100644 --- a/samples/modules/canopennode/prj_no_storage.conf +++ b/samples/modules/canopennode/prj_no_storage.conf @@ -9,5 +9,6 @@ CONFIG_CAN_MAX_FILTER=13 CONFIG_CANOPEN=y CONFIG_CANOPENNODE_SYNC_THREAD=y CONFIG_CANOPENNODE_LEDS=y +CONFIG_CANOPENNODE_PROGRAM_DOWNLOAD=n CONFIG_REBOOT=y From 06bcd21a148790b982ee1f521450e87822ca1190 Mon Sep 17 00:00:00 2001 From: Benjamin Santon Date: Thu, 2 Oct 2025 11:50:19 +0100 Subject: [PATCH 118/397] drivers: spi: spi_max32: Fix QSPI and half duplex, support hold on CS Fix QSPI and half duplex Support hold on CS flag Create functions to assert and deassert CS Signed-off-by: Benjamin Santon --- drivers/spi/spi_max32.c | 156 +++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 84 deletions(-) diff --git a/drivers/spi/spi_max32.c b/drivers/spi/spi_max32.c index 2e149507f59c5..5b553d901b678 100644 --- a/drivers/spi/spi_max32.c +++ b/drivers/spi/spi_max32.c @@ -205,6 +205,37 @@ static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req, uint8_t dfs MXC_SPI_ClearFlags(spi); } +static void spi_cs_assert(const struct device *dev) +{ + const struct max32_spi_config *cfg = dev->config; + struct max32_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + + if (spi_cs_is_gpio(ctx->config)) { + MXC_SPI_HWSSControl(cfg->regs, false); + spi_context_cs_control(ctx, true); + } else { + MXC_SPI_HWSSControl(cfg->regs, true); + cfg->regs->ctrl0 = (cfg->regs->ctrl0 & ~MXC_F_SPI_CTRL0_START) | + ADI_MAX32_SPI_CTRL0_SS_CTRL; + } +} + +static void spi_cs_deassert(const struct device *dev) +{ + const struct max32_spi_config *cfg = dev->config; + struct max32_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + + if (spi_cs_is_gpio(ctx->config)) { + spi_context_cs_control(ctx, false); + } else { + cfg->regs->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL | + ADI_MAX32_SPI_CTRL_EN); + cfg->regs->ctrl0 |= ADI_MAX32_SPI_CTRL_EN; + } +} + #ifndef CONFIG_SPI_MAX32_INTERRUPT static int spi_max32_transceive_sync(mxc_spi_regs_t *spi, struct max32_spi_data *data, uint8_t dfs_shift) @@ -228,15 +259,23 @@ static int spi_max32_transceive_sync(mxc_spi_regs_t *spi, struct max32_spi_data req->txCnt += MXC_SPI_WriteTXFIFO(spi, &req->txData[req->txCnt], remain); } - if (!(spi->ctrl0 & MXC_F_SPI_CTRL0_START)) { - spi->ctrl0 |= MXC_F_SPI_CTRL0_START; - } } if (req->rxCnt < rx_len) { req->rxCnt += MXC_SPI_ReadRXFIFO(spi, &req->rxData[req->rxCnt], rx_len - req->rxCnt); } + + if (!(spi->ctrl0 & MXC_F_SPI_CTRL0_START)) { + /* Transfer not started */ + if ((MXC_SPI_GetTXFIFOAvailable(spi) - MXC_SPI_FIFO_DEPTH) > 0) { + /* Data remaining in the TX FIFO, ensure TX started */ + spi->ctrl0 |= MXC_F_SPI_CTRL0_START; + } else if (MXC_SPI_GetRXFIFOAvailable(spi) < (rx_len - req->rxCnt)) { + /* Not enough data into the RX FIFO */ + spi->ctrl0 |= MXC_F_SPI_CTRL0_START; + } + } } while ((req->txCnt < tx_len) || (req->rxCnt < rx_len)); do { @@ -307,7 +346,19 @@ static int spi_max32_transceive(const struct device *dev) break; } #else - data->req.txLen = len; + if ((ctx->config->operation & SPI_HALF_DUPLEX) +#if defined(CONFIG_SPI_EXTENDED_MODES) + || (ctx->config->operation & SPI_LINES_DUAL) + || (ctx->config->operation & SPI_LINES_QUAD) + || (ctx->config->operation & SPI_LINES_OCTAL) +#endif + ) { + /* Half duplex mode, tx should be set only if no rx */ + data->req.txLen = ctx->tx_buf ? len : 0; + } else { + /* Full duplex mode, tx and rx can be set independently */ + data->req.txLen = len; + } data->req.txData = (uint8_t *)ctx->tx_buf; data->req.rxLen = len; data->req.rxData = ctx->rx_buf; @@ -375,10 +426,6 @@ static int transceive(const struct device *dev, const struct spi_config *config, int ret = 0; struct max32_spi_data *data = dev->data; struct spi_context *ctx = &data->ctx; -#ifndef CONFIG_SPI_RTIO - const struct max32_spi_config *cfg = dev->config; - bool hw_cs_ctrl = true; -#endif #ifndef CONFIG_SPI_MAX32_INTERRUPT if (async) { @@ -397,19 +444,8 @@ static int transceive(const struct device *dev, const struct spi_config *config, spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); - /* Check if CS GPIO exists */ - if (spi_cs_is_gpio(config)) { - hw_cs_ctrl = false; - } - MXC_SPI_HWSSControl(cfg->regs, hw_cs_ctrl); - - /* Assert the CS line if HW control disabled */ - if (!hw_cs_ctrl) { - spi_context_cs_control(ctx, true); - } else { - cfg->regs->ctrl0 = - (cfg->regs->ctrl0 & ~MXC_F_SPI_CTRL0_START) | ADI_MAX32_SPI_CTRL0_SS_CTRL; - } + /* Assert the CS line */ + spi_cs_assert(dev); #ifdef CONFIG_SPI_MAX32_INTERRUPT do { @@ -433,15 +469,9 @@ static int transceive(const struct device *dev, const struct spi_config *config, #endif /* CONFIG_SPI_MAX32_INTERRUPT */ - /* Deassert the CS line if hw control disabled */ - if (!async) { - if (!hw_cs_ctrl) { - spi_context_cs_control(ctx, false); - } else { - cfg->regs->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL | - ADI_MAX32_SPI_CTRL_EN); - cfg->regs->ctrl0 |= ADI_MAX32_SPI_CTRL_EN; - } + /* Deassert the CS line if hold mode is not enabled */ + if (!async && !(ctx->config->operation & SPI_HOLD_ON_CS)) { + spi_cs_deassert(dev); } #else /* Guard against unsupported word lengths here, as spi_configure is @@ -573,8 +603,6 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con uint32_t len, word_count; uint8_t dfs_shift; - bool hw_cs_ctrl = true; - spi_context_lock(ctx, async, cb, userdata, config); MXC_SPI_ClearTXFIFO(spi); @@ -605,18 +633,8 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); - /* Check if CS GPIO exists */ - if (spi_cs_is_gpio(config)) { - hw_cs_ctrl = false; - } - MXC_SPI_HWSSControl(cfg->regs, hw_cs_ctrl); - - /* Assert the CS line if HW control disabled */ - if (!hw_cs_ctrl) { - spi_context_cs_control(ctx, true); - } else { - spi->ctrl0 = (spi->ctrl0 & ~MXC_F_SPI_CTRL0_START) | ADI_MAX32_SPI_CTRL0_SS_CTRL; - } + /* Assert the CS line */ + spi_cs_assert(dev); MXC_SPI_SetSlave(cfg->regs, ctx->config->slave); @@ -665,14 +683,8 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con } unlock: - /* Deassert the CS line if hw control disabled */ - if (!hw_cs_ctrl) { - spi_context_cs_control(ctx, false); - } else { - spi->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL | - ADI_MAX32_SPI_CTRL_EN); - spi->ctrl0 |= ADI_MAX32_SPI_CTRL_EN; - } + /* Deassert the CS line */ + spi_cs_deassert(dev); spi_context_release(ctx, ret); @@ -712,26 +724,12 @@ static inline void spi_max32_iodev_prepare_start(const struct device *dev) struct spi_rtio *rtio_ctx = data->rtio_ctx; struct spi_dt_spec *spi_dt_spec = rtio_ctx->txn_curr->sqe.iodev->data; struct spi_config *spi_config = &spi_dt_spec->config; - struct max32_spi_config *cfg = (struct max32_spi_config *)dev->config; int ret; - bool hw_cs_ctrl = true; ret = spi_configure(dev, spi_config); __ASSERT(!ret, "%d", ret); - /* Check if CS GPIO exists */ - if (spi_cs_is_gpio(spi_config)) { - hw_cs_ctrl = false; - } - MXC_SPI_HWSSControl(cfg->regs, hw_cs_ctrl); - - /* Assert the CS line if HW control disabled */ - if (!hw_cs_ctrl) { - spi_context_cs_control(&data->ctx, true); - } else { - cfg->regs->ctrl0 = - (cfg->regs->ctrl0 & ~MXC_F_SPI_CTRL0_START) | MXC_F_SPI_CTRL0_SS_CTRL; - }; + spi_cs_assert(dev); } static void spi_max32_iodev_complete(const struct device *dev, int status) @@ -743,16 +741,7 @@ static void spi_max32_iodev_complete(const struct device *dev, int status) rtio_ctx->txn_curr = rtio_txn_next(rtio_ctx->txn_curr); spi_max32_iodev_start(dev); } else { - struct max32_spi_config *cfg = (struct max32_spi_config *)dev->config; - bool hw_cs_ctrl = true; - - if (!hw_cs_ctrl) { - spi_context_cs_control(&data->ctx, false); - } else { - cfg->regs->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | MXC_F_SPI_CTRL0_SS_CTRL | - ADI_MAX32_SPI_CTRL_EN); - cfg->regs->ctrl0 |= ADI_MAX32_SPI_CTRL_EN; - } + spi_cs_deassert(dev); if (spi_rtio_complete(rtio_ctx, status)) { spi_max32_iodev_prepare_start(dev); @@ -820,13 +809,7 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error) if (ctx->asynchronous && ((spi_context_tx_on(ctx) || spi_context_rx_on(ctx)))) { k_work_submit(&data->async_work); } else { - if (spi_cs_is_gpio(ctx->config)) { - spi_context_cs_control(ctx, false); - } else { - req->spi->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL | - ADI_MAX32_SPI_CTRL_EN); - req->spi->ctrl0 |= ADI_MAX32_SPI_CTRL_EN; - } + spi_cs_deassert(dev); spi_context_complete(ctx, dev, error == E_NO_ERROR ? 0 : -EIO); } #else @@ -900,12 +883,17 @@ static void spi_max32_isr(const struct device *dev) static int api_release(const struct device *dev, const struct spi_config *config) { struct max32_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; #ifndef CONFIG_SPI_RTIO if (!spi_context_configured(&data->ctx, config)) { return -EINVAL; } #endif + + if (ctx->config->operation & SPI_HOLD_ON_CS) { + spi_cs_deassert(dev); + } spi_context_unlock_unconditionally(&data->ctx); return 0; } From 54710d3db49147e0360e16a2bdc5996a6c0ad254 Mon Sep 17 00:00:00 2001 From: Mohamed Azhar Date: Fri, 26 Sep 2025 12:27:17 +0530 Subject: [PATCH 119/397] dts: arm: microchip: add dtsi files for Microchip PIC32CZ CA SoC series Adds common and SoC-specific .dtsi files for the Microchip PIC32CZ CA80 CA90 and CA91 family. These files define core peripherals, address maps, and interrupt controller structure shared across the PIC32CZ CA80 9x variants. Signed-off-by: Mohamed Azhar --- .../pic32cz_ca/common/pic32cz_1051_ca.dtsi | 17 ++++ .../pic32cz_ca/common/pic32cz_2051_ca.dtsi | 17 ++++ .../pic32cz_ca/common/pic32cz_4010_ca.dtsi | 17 ++++ .../pic32cz_ca/common/pic32cz_8110_ca.dtsi | 17 ++++ .../pic32c/pic32cz_ca/common/pic32cz_ca.dtsi | 79 +++++++++++++++++++ .../pic32cz_ca/common/pic32cz_ca_100.dtsi | 7 ++ .../pic32cz_ca/common/pic32cz_ca_144.dtsi | 7 ++ .../pic32cz_ca/common/pic32cz_ca_176.dtsi | 38 +++++++++ .../pic32cz_ca/common/pic32cz_ca_208.dtsi | 38 +++++++++ .../pic32cz_ca80/pic32cz2051ca80100.dtsi | 9 +++ .../pic32cz_ca80/pic32cz2051ca80144.dtsi | 9 +++ .../pic32cz_ca80/pic32cz2051ca80176.dtsi | 9 +++ .../pic32cz_ca80/pic32cz2051ca80208.dtsi | 9 +++ .../pic32cz_ca80/pic32cz4010ca80100.dtsi | 9 +++ .../pic32cz_ca80/pic32cz4010ca80144.dtsi | 9 +++ .../pic32cz_ca80/pic32cz4010ca80176.dtsi | 9 +++ .../pic32cz_ca80/pic32cz4010ca80208.dtsi | 9 +++ .../pic32cz_ca80/pic32cz8110ca80100.dtsi | 9 +++ .../pic32cz_ca80/pic32cz8110ca80144.dtsi | 9 +++ .../pic32cz_ca80/pic32cz8110ca80176.dtsi | 9 +++ .../pic32cz_ca80/pic32cz8110ca80208.dtsi | 9 +++ .../pic32cz_ca90/pic32cz2051ca90100.dtsi | 9 +++ .../pic32cz_ca90/pic32cz2051ca90144.dtsi | 9 +++ .../pic32cz_ca90/pic32cz2051ca90176.dtsi | 9 +++ .../pic32cz_ca90/pic32cz2051ca90208.dtsi | 9 +++ .../pic32cz_ca90/pic32cz4010ca90100.dtsi | 9 +++ .../pic32cz_ca90/pic32cz4010ca90144.dtsi | 9 +++ .../pic32cz_ca90/pic32cz4010ca90176.dtsi | 9 +++ .../pic32cz_ca90/pic32cz4010ca90208.dtsi | 9 +++ .../pic32cz_ca90/pic32cz8110ca90100.dtsi | 9 +++ .../pic32cz_ca90/pic32cz8110ca90144.dtsi | 9 +++ .../pic32cz_ca90/pic32cz8110ca90176.dtsi | 9 +++ .../pic32cz_ca90/pic32cz8110ca90208.dtsi | 9 +++ .../pic32cz_ca91/pic32cz2051ca91100.dtsi | 9 +++ .../pic32cz_ca91/pic32cz2051ca91144.dtsi | 9 +++ .../pic32cz_ca91/pic32cz2051ca91176.dtsi | 9 +++ .../pic32cz_ca91/pic32cz4010ca91100.dtsi | 9 +++ .../pic32cz_ca91/pic32cz4010ca91144.dtsi | 9 +++ .../pic32cz_ca91/pic32cz4010ca91176.dtsi | 9 +++ .../pic32cz_ca91/pic32cz4010ca91208.dtsi | 9 +++ 40 files changed, 516 insertions(+) create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_1051_ca.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_2051_ca.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_4010_ca.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_8110_ca.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_208.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80208.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80208.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80208.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90208.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90208.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90208.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91100.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91144.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91176.dtsi create mode 100644 dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91208.dtsi diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_1051_ca.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_1051_ca.dtsi new file mode 100644 index 0000000000000..91334645d5464 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_1051_ca.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(1)>; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(512)>; + }; + }; +}; diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_2051_ca.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_2051_ca.dtsi new file mode 100644 index 0000000000000..01cad81f1a375 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_2051_ca.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(2)>; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(512)>; + }; + }; +}; diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_4010_ca.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_4010_ca.dtsi new file mode 100644 index 0000000000000..ef0c4115ee646 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_4010_ca.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(4)>; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_M(1)>; + }; + }; +}; diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_8110_ca.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_8110_ca.dtsi new file mode 100644 index 0000000000000..f592d9bcdbfcc --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_8110_ca.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + soc { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(8)>; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_M(1)>; + }; + }; +}; diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca.dtsi new file mode 100644 index 0000000000000..9fdaef3a8f95e --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca.dtsi @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m7"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + mpu: mpu@e000ed90 { + compatible = "arm,armv7m-mpu"; + reg = <0xe000ed90 0x40>; + }; + }; + }; + + soc { + flash0: flash@8000000 { + compatible = "soc-nv-flash"; + write-block-size = <8>; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + porta: gpio@44840000 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840000 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + + portb: gpio@44840080 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840080 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + + portc: gpio@44840100 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840100 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + + portd: gpio@44840180 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840180 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_100.dtsi new file mode 100644 index 0000000000000..ffc24df06c27f --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_100.dtsi @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_144.dtsi new file mode 100644 index 0000000000000..ffc24df06c27f --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_144.dtsi @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_176.dtsi new file mode 100644 index 0000000000000..d8d8e4f8c44c3 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_176.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + porte: gpio@44840200 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840200 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + + portf: gpio@44840280 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840280 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + + portg: gpio@44840300 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840300 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + }; +}; diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_208.dtsi new file mode 100644 index 0000000000000..d8d8e4f8c44c3 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/common/pic32cz_ca_208.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + porte: gpio@44840200 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840200 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + + portf: gpio@44840280 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840280 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + + portg: gpio@44840300 { + status = "disabled"; + compatible = "microchip,port-g1-gpio"; + reg = <0x44840300 0x80>; + gpio-controller; + #gpio-cells = <2>; + #microchip,pin-cells = <2>; + }; + }; +}; diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80100.dtsi new file mode 100644 index 0000000000000..2f635a4b33689 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80144.dtsi new file mode 100644 index 0000000000000..29f60b2194bd9 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80176.dtsi new file mode 100644 index 0000000000000..db11ef5defafe --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80208.dtsi new file mode 100644 index 0000000000000..fcde5e4923a91 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz2051ca80208.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80100.dtsi new file mode 100644 index 0000000000000..1531dbb0beb63 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80144.dtsi new file mode 100644 index 0000000000000..8ca3da5228e35 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80176.dtsi new file mode 100644 index 0000000000000..8ebcc3dc3d1e4 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80208.dtsi new file mode 100644 index 0000000000000..7dd5bac8da05c --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz4010ca80208.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80100.dtsi new file mode 100644 index 0000000000000..c20876e390487 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80144.dtsi new file mode 100644 index 0000000000000..55cb09f063df4 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80176.dtsi new file mode 100644 index 0000000000000..b75f0715ca1d5 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80208.dtsi new file mode 100644 index 0000000000000..cac3e7ea75d63 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca80/pic32cz8110ca80208.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90100.dtsi new file mode 100644 index 0000000000000..2f635a4b33689 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90144.dtsi new file mode 100644 index 0000000000000..29f60b2194bd9 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90176.dtsi new file mode 100644 index 0000000000000..db11ef5defafe --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90208.dtsi new file mode 100644 index 0000000000000..fcde5e4923a91 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz2051ca90208.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90100.dtsi new file mode 100644 index 0000000000000..1531dbb0beb63 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90144.dtsi new file mode 100644 index 0000000000000..8ca3da5228e35 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90176.dtsi new file mode 100644 index 0000000000000..8ebcc3dc3d1e4 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90208.dtsi new file mode 100644 index 0000000000000..7dd5bac8da05c --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz4010ca90208.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90100.dtsi new file mode 100644 index 0000000000000..c20876e390487 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90144.dtsi new file mode 100644 index 0000000000000..55cb09f063df4 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90176.dtsi new file mode 100644 index 0000000000000..b75f0715ca1d5 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90208.dtsi new file mode 100644 index 0000000000000..cac3e7ea75d63 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca90/pic32cz8110ca90208.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91100.dtsi new file mode 100644 index 0000000000000..2f635a4b33689 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91144.dtsi new file mode 100644 index 0000000000000..29f60b2194bd9 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91176.dtsi new file mode 100644 index 0000000000000..db11ef5defafe --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz2051ca91176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91100.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91100.dtsi new file mode 100644 index 0000000000000..1531dbb0beb63 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91100.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91144.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91144.dtsi new file mode 100644 index 0000000000000..8ca3da5228e35 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91144.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91176.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91176.dtsi new file mode 100644 index 0000000000000..8ebcc3dc3d1e4 --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91176.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include diff --git a/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91208.dtsi b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91208.dtsi new file mode 100644 index 0000000000000..7dd5bac8da05c --- /dev/null +++ b/dts/arm/microchip/pic32c/pic32cz_ca/pic32cz_ca91/pic32cz4010ca91208.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include From 068ae9a7fe1c25ff47475d5ca2365e7cb2ffbc74 Mon Sep 17 00:00:00 2001 From: Mohamed Azhar Date: Fri, 26 Sep 2025 12:32:45 +0530 Subject: [PATCH 120/397] soc: microchip: add support for PIC32CZ CA SoC series Adds initial SoC-level support for the Microchip PIC32CZ CA80/9x series, including SoC definition files. Signed-off-by: Mohamed Azhar --- .../pic32c/pic32cz_ca/CMakeLists.txt | 6 ++ soc/microchip/pic32c/pic32cz_ca/Kconfig | 18 +++++ .../pic32c/pic32cz_ca/Kconfig.defconfig | 12 +++ soc/microchip/pic32c/pic32cz_ca/Kconfig.soc | 10 +++ .../pic32cz_ca/pic32cz_ca80/Kconfig.soc | 73 +++++++++++++++++++ .../pic32c/pic32cz_ca/pic32cz_ca80/soc.h | 44 +++++++++++ .../pic32cz_ca/pic32cz_ca90/Kconfig.soc | 73 +++++++++++++++++++ .../pic32c/pic32cz_ca/pic32cz_ca90/soc.h | 44 +++++++++++ .../pic32cz_ca/pic32cz_ca91/Kconfig.soc | 48 ++++++++++++ .../pic32c/pic32cz_ca/pic32cz_ca91/soc.h | 34 +++++++++ soc/microchip/pic32c/pic32cz_ca/soc.yml | 43 +++++++++++ 11 files changed, 405 insertions(+) create mode 100644 soc/microchip/pic32c/pic32cz_ca/CMakeLists.txt create mode 100644 soc/microchip/pic32c/pic32cz_ca/Kconfig create mode 100644 soc/microchip/pic32c/pic32cz_ca/Kconfig.defconfig create mode 100644 soc/microchip/pic32c/pic32cz_ca/Kconfig.soc create mode 100644 soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/Kconfig.soc create mode 100644 soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/soc.h create mode 100644 soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/Kconfig.soc create mode 100644 soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/soc.h create mode 100644 soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/Kconfig.soc create mode 100644 soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/soc.h create mode 100644 soc/microchip/pic32c/pic32cz_ca/soc.yml diff --git a/soc/microchip/pic32c/pic32cz_ca/CMakeLists.txt b/soc/microchip/pic32c/pic32cz_ca/CMakeLists.txt new file mode 100644 index 0000000000000..e01d600d17e54 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(${SOC_SERIES}) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/microchip/pic32c/pic32cz_ca/Kconfig b/soc/microchip/pic32c/pic32cz_ca/Kconfig new file mode 100644 index 0000000000000..a295acedd0be2 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_MICROCHIP_PIC32CZ_CA + select ARM + select MICROCHIP_PIC32C + select CPU_CORTEX_M7 + select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU_DOUBLE_PRECISION + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE + select INIT_ARCH_HW_AT_BOOT + select HAS_SWO + select XIP + select HAS_POWEROFF diff --git a/soc/microchip/pic32c/pic32cz_ca/Kconfig.defconfig b/soc/microchip/pic32c/pic32cz_ca/Kconfig.defconfig new file mode 100644 index 0000000000000..b2ba9a7d3e1ec --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_MICROCHIP_PIC32CZ_CA + +config NUM_IRQS + default 240 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + +endif # SOC_FAMILY_MICROCHIP_PIC32CZ_CA diff --git a/soc/microchip/pic32c/pic32cz_ca/Kconfig.soc b/soc/microchip/pic32c/pic32cz_ca/Kconfig.soc new file mode 100644 index 0000000000000..945639b777ec5 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_MICROCHIP_PIC32CZ_CA + bool + +config SOC_FAMILY + default "microchip_pic32cz_ca" if SOC_FAMILY_MICROCHIP_PIC32CZ_CA + +rsource "*/Kconfig.soc" diff --git a/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/Kconfig.soc b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/Kconfig.soc new file mode 100644 index 0000000000000..51de482bf882c --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/Kconfig.soc @@ -0,0 +1,73 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_PIC32CZ_CA80 + bool + select SOC_FAMILY_MICROCHIP_PIC32CZ_CA + help + Enable support for Microchip PIC32CZ CA80 Cortex-M7 microcontrollers. + +config SOC_SERIES + default "pic32cz_ca80" if SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ2051CA80100 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ2051CA80144 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ2051CA80176 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ2051CA80208 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ4010CA80100 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ4010CA80144 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ4010CA80176 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ4010CA80208 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ8110CA80100 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ8110CA80144 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ8110CA80176 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC_PIC32CZ8110CA80208 + bool + select SOC_SERIES_PIC32CZ_CA80 + +config SOC + default "pic32cz2051ca80100" if SOC_PIC32CZ2051CA80100 + default "pic32cz2051ca80144" if SOC_PIC32CZ2051CA80144 + default "pic32cz2051ca80176" if SOC_PIC32CZ2051CA80176 + default "pic32cz2051ca80208" if SOC_PIC32CZ2051CA80208 + default "pic32cz4010ca80100" if SOC_PIC32CZ4010CA80100 + default "pic32cz4010ca80144" if SOC_PIC32CZ4010CA80144 + default "pic32cz4010ca80176" if SOC_PIC32CZ4010CA80176 + default "pic32cz4010ca80208" if SOC_PIC32CZ4010CA80208 + default "pic32cz8110ca80100" if SOC_PIC32CZ8110CA80100 + default "pic32cz8110ca80144" if SOC_PIC32CZ8110CA80144 + default "pic32cz8110ca80176" if SOC_PIC32CZ8110CA80176 + default "pic32cz8110ca80208" if SOC_PIC32CZ8110CA80208 diff --git a/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/soc.h b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/soc.h new file mode 100644 index 0000000000000..6b35483c83037 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca80/soc.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_PIC32CZ_CA80_SOC_H_ +#define SOC_MICROCHIP_PIC32CZ_CA80_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_PIC32CZ2051CA80100) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA80144) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA80176) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA80208) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA80100) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA80144) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA80176) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA80208) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA80100) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA80144) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA80176) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA80208) +#include +#else +#error "Library does not support the specified device." +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_MICROCHIP_PIC32CZ_CA80_SOC_H_ */ diff --git a/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/Kconfig.soc b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/Kconfig.soc new file mode 100644 index 0000000000000..13caeaf7f75a4 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/Kconfig.soc @@ -0,0 +1,73 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_PIC32CZ_CA90 + bool + select SOC_FAMILY_MICROCHIP_PIC32CZ_CA + help + Enable support for Microchip PIC32CZ CA90 Cortex-M7 microcontrollers. + +config SOC_SERIES + default "pic32cz_ca90" if SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ2051CA90100 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ2051CA90144 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ2051CA90176 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ2051CA90208 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ4010CA90100 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ4010CA90144 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ4010CA90176 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ4010CA90208 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ8110CA90100 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ8110CA90144 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ8110CA90176 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC_PIC32CZ8110CA90208 + bool + select SOC_SERIES_PIC32CZ_CA90 + +config SOC + default "pic32cz2051ca90100" if SOC_PIC32CZ2051CA90100 + default "pic32cz2051ca90144" if SOC_PIC32CZ2051CA90144 + default "pic32cz2051ca90176" if SOC_PIC32CZ2051CA90176 + default "pic32cz2051ca90208" if SOC_PIC32CZ2051CA90208 + default "pic32cz4010ca90100" if SOC_PIC32CZ4010CA90100 + default "pic32cz4010ca90144" if SOC_PIC32CZ4010CA90144 + default "pic32cz4010ca90176" if SOC_PIC32CZ4010CA90176 + default "pic32cz4010ca90208" if SOC_PIC32CZ4010CA90208 + default "pic32cz8110ca90100" if SOC_PIC32CZ8110CA90100 + default "pic32cz8110ca90144" if SOC_PIC32CZ8110CA90144 + default "pic32cz8110ca90176" if SOC_PIC32CZ8110CA90176 + default "pic32cz8110ca90208" if SOC_PIC32CZ8110CA90208 diff --git a/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/soc.h b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/soc.h new file mode 100644 index 0000000000000..1db0748b46794 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca90/soc.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_PIC32CZ_CA90_SOC_H_ +#define SOC_MICROCHIP_PIC32CZ_CA90_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_PIC32CZ2051CA90100) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA90144) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA90176) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA90208) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA90100) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA90144) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA90176) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA90208) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA90100) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA90144) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA90176) +#include +#elif defined(CONFIG_SOC_PIC32CZ8110CA90208) +#include +#else +#error "Library does not support the specified device." +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_MICROCHIP_PIC32CZ_CA90_SOC_H_ */ diff --git a/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/Kconfig.soc b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/Kconfig.soc new file mode 100644 index 0000000000000..d6a59d595e372 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/Kconfig.soc @@ -0,0 +1,48 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_PIC32CZ_CA91 + bool + select SOC_FAMILY_MICROCHIP_PIC32CZ_CA + help + Enable support for Microchip PIC32CZ CA91 Cortex-M7 microcontrollers. + +config SOC_SERIES + default "pic32cz_ca91" if SOC_SERIES_PIC32CZ_CA91 + +config SOC_PIC32CZ2051CA91100 + bool + select SOC_SERIES_PIC32CZ_CA91 + +config SOC_PIC32CZ2051CA91144 + bool + select SOC_SERIES_PIC32CZ_CA91 + +config SOC_PIC32CZ2051CA91176 + bool + select SOC_SERIES_PIC32CZ_CA91 + +config SOC_PIC32CZ4010CA91100 + bool + select SOC_SERIES_PIC32CZ_CA91 + +config SOC_PIC32CZ4010CA91144 + bool + select SOC_SERIES_PIC32CZ_CA91 + +config SOC_PIC32CZ4010CA91176 + bool + select SOC_SERIES_PIC32CZ_CA91 + +config SOC_PIC32CZ4010CA91208 + bool + select SOC_SERIES_PIC32CZ_CA91 + +config SOC + default "pic32cz2051ca91100" if SOC_PIC32CZ2051CA91100 + default "pic32cz2051ca91144" if SOC_PIC32CZ2051CA91144 + default "pic32cz2051ca91176" if SOC_PIC32CZ2051CA91176 + default "pic32cz4010ca91100" if SOC_PIC32CZ4010CA91100 + default "pic32cz4010ca91144" if SOC_PIC32CZ4010CA91144 + default "pic32cz4010ca91176" if SOC_PIC32CZ4010CA91176 + default "pic32cz4010ca91208" if SOC_PIC32CZ4010CA91208 diff --git a/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/soc.h b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/soc.h new file mode 100644 index 0000000000000..f5e9829da6d1d --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/pic32cz_ca91/soc.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_MICROCHIP_PIC32CZ_CA91_SOC_H_ +#define SOC_MICROCHIP_PIC32CZ_CA91_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#if defined(CONFIG_SOC_PIC32CZ2051CA91100) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA91144) +#include +#elif defined(CONFIG_SOC_PIC32CZ2051CA91176) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA91100) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA91144) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA91176) +#include +#elif defined(CONFIG_SOC_PIC32CZ4010CA91208) +#include +#else +#error "Library does not support the specified device." +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_MICROCHIP_PIC32CZ_CA91_SOC_H_ */ diff --git a/soc/microchip/pic32c/pic32cz_ca/soc.yml b/soc/microchip/pic32c/pic32cz_ca/soc.yml new file mode 100644 index 0000000000000..f3b620c660b54 --- /dev/null +++ b/soc/microchip/pic32c/pic32cz_ca/soc.yml @@ -0,0 +1,43 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +family: +- name: microchip_pic32cz_ca + series: + - name: pic32cz_ca80 + socs: + - name: pic32cz2051ca80100 + - name: pic32cz2051ca80144 + - name: pic32cz2051ca80176 + - name: pic32cz2051ca80208 + - name: pic32cz4010ca80100 + - name: pic32cz4010ca80144 + - name: pic32cz4010ca80176 + - name: pic32cz4010ca80208 + - name: pic32cz8110ca80100 + - name: pic32cz8110ca80144 + - name: pic32cz8110ca80176 + - name: pic32cz8110ca80208 + - name: pic32cz_ca90 + socs: + - name: pic32cz2051ca90100 + - name: pic32cz2051ca90144 + - name: pic32cz2051ca90176 + - name: pic32cz2051ca90208 + - name: pic32cz4010ca90100 + - name: pic32cz4010ca90144 + - name: pic32cz4010ca90176 + - name: pic32cz4010ca90208 + - name: pic32cz8110ca90100 + - name: pic32cz8110ca90144 + - name: pic32cz8110ca90176 + - name: pic32cz8110ca90208 + - name: pic32cz_ca91 + socs: + - name: pic32cz2051ca91100 + - name: pic32cz2051ca91144 + - name: pic32cz2051ca91176 + - name: pic32cz4010ca91100 + - name: pic32cz4010ca91144 + - name: pic32cz4010ca91176 + - name: pic32cz4010ca91208 From 599f51a5f591f774e419fe0d59506d550ab47990 Mon Sep 17 00:00:00 2001 From: Mohamed Azhar Date: Mon, 29 Sep 2025 17:05:52 +0530 Subject: [PATCH 121/397] boards: microchip: add PIC32CZ CA80 Curiosity Ultra Dev Board support Add initial support for the PIC32CZ CA80 Curiosity Ultra Development Board Product page: https://www.microchip.com/en-us/development-tool/ev51s73a Signed-off-by: Mohamed Azhar --- .../Kconfig.pic32cz_ca80_cult | 5 + .../pic32c/pic32cz_ca80_cult/board.cmake | 6 ++ .../pic32c/pic32cz_ca80_cult/board.yml | 9 ++ .../doc/img/pic32cz_ca80_cult.webp | Bin 0 -> 37490 bytes .../pic32c/pic32cz_ca80_cult/doc/index.rst | 97 ++++++++++++++++++ .../pic32cz_ca80_cult/pic32cz_ca80_cult.dts | 81 +++++++++++++++ .../pic32cz_ca80_cult/pic32cz_ca80_cult.yaml | 14 +++ .../pic32cz_ca80_cult_defconfig | 5 + 8 files changed, 217 insertions(+) create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/Kconfig.pic32cz_ca80_cult create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/board.cmake create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/board.yml create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/doc/img/pic32cz_ca80_cult.webp create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/doc/index.rst create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.dts create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.yaml create mode 100644 boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult_defconfig diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/Kconfig.pic32cz_ca80_cult b/boards/microchip/pic32c/pic32cz_ca80_cult/Kconfig.pic32cz_ca80_cult new file mode 100644 index 0000000000000..a8df482431f52 --- /dev/null +++ b/boards/microchip/pic32c/pic32cz_ca80_cult/Kconfig.pic32cz_ca80_cult @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_PIC32CZ_CA80_CULT + select SOC_PIC32CZ8110CA80208 diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/board.cmake b/boards/microchip/pic32c/pic32cz_ca80_cult/board.cmake new file mode 100644 index 0000000000000..d76c72d4806b5 --- /dev/null +++ b/boards/microchip/pic32c/pic32cz_ca80_cult/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=PIC32CZ8110CA80" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/board.yml b/boards/microchip/pic32c/pic32cz_ca80_cult/board.yml new file mode 100644 index 0000000000000..d26381cc32115 --- /dev/null +++ b/boards/microchip/pic32c/pic32cz_ca80_cult/board.yml @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: pic32cz_ca80_cult + full_name: PIC32CZ CA80 Curiosity Ultra + vendor: microchip + socs: + - name: pic32cz8110ca80208 diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/doc/img/pic32cz_ca80_cult.webp b/boards/microchip/pic32c/pic32cz_ca80_cult/doc/img/pic32cz_ca80_cult.webp new file mode 100644 index 0000000000000000000000000000000000000000..a090e451328b1d3283aabc8f273addb3b9f98f2e GIT binary patch literal 37490 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%0DZ^YC4M4Ls5V$yL|bL3vG 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 N0T2KN05<>t007uNl)?Z2 literal 0 HcmV?d00001 diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/doc/index.rst b/boards/microchip/pic32c/pic32cz_ca80_cult/doc/index.rst new file mode 100644 index 0000000000000..171bbe01ae347 --- /dev/null +++ b/boards/microchip/pic32c/pic32cz_ca80_cult/doc/index.rst @@ -0,0 +1,97 @@ +.. zephyr:board:: pic32cz_ca80_cult + +Overview +******** + +The PIC32CZ CA80 Curiosity Ultra development board is a hardware platform +to evaluate the Microchip PIC32CZ CA80 microcontroller, and the +development board part number is EV51S73A. The development board offers a +set of features that enables the PIC32CZ CA80 users to get started with +the PIC32CZ CA80 peripherals, and to obtain an understanding of how to +integrate the device in their own design. + +Hardware +******** + +- 208-Pin TFBGA PIC32CZ8110 CA80 microcontroller +- 32.768 kHz crystal oscillator +- 8M flash memory and 1M of RAM +- Xplained pro extension compatible interface +- Two yellow user LEDs +- Two mechanical user push button +- One reset button +- Virtual COM port (VCOM) +- Programming and debugging of on-board PIC32CZ CA80 through Serial Wire Debug (SWD) +- Arduino uno R3 compatible interface +- MikroBus Socket +- On-board temperature sensor +- Graphics interface +- G-bit Ethernet +- 2 high-speed USB (Type-C and Micro A/B) + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Connections and IOs +=================== + +The `PIC32CZ CA80 Curiosity Ultra User Guide`_ has detailed information about board connections. + +Programming & Debugging +*********************** + +.. zephyr:board-supported-runners:: + +Flash Using J-Link +================== + +To flash the board using the J-Link debugger, follow the steps below: + +1. Install J-Link Software + + - Download and install the `J-Link software `_ tools from Segger. + - Make sure the installed J-Link executables (e.g., ``JLink``, ``JLinkGDBServer``) are available in your system's PATH. + +2. Connect the Board + + - Connect the `J32 Debug Probe `_ to the board's **CORTEX DEBUG** header. + - Connect the other end of the J32 Debug Probe to your **host machine (PC)** via USB. + - Connect the DEBUG USB port on the board to your host machine to **power up the board**. + +3. Build the Application + + You can build a sample Zephyr application, such as **Blinky**, using the ``west`` tool. Run the following commands from your Zephyr workspace: + + .. code-block:: console + + west build -b pic32cz_ca80_cult -p -s samples/basic/blinky + + This will build the Blinky application for the ``pic32cz_ca80_cult`` board. + +4. Flash the Device + + Once the build completes, flash the firmware using: + + .. code-block:: console + + west flash + + This uses the default ``jlink`` runner to flash the application to the board. + +5. Observe the Result + + After flashing, **LED0** on the board should start **blinking**, indicating that the application is running successfully. + +References +********** + +PIC32CZ CA80 Product Page: + https://www.microchip.com/en-us/product/PIC32CZ8110CA80208 + +PIC32CZ CA80 Curiosity Ultra Development Board Page: + https://www.microchip.com/en-us/development-tool/ev51s73a + +.. _PIC32CZ CA80 Curiosity Ultra User Guide: + https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/UserGuides/PIC32CZ-CA80-CA90-Curiosity-Ultra-User-Guide-DS70005522.pdf diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.dts b/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.dts new file mode 100644 index 0000000000000..e9c286460625d --- /dev/null +++ b/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.dts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include + +/ { + model = "PIC32CZ CA80 Curiosity Ultra"; + compatible = "pic32cz_ca80,cult", "microchip,pic32cz8110ca80208", "microchip,pic32cz"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + aliases { + led0 = &led0; + led1 = &led1; + sw0 = &button0; + sw1 = &button1; + }; + + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&portb 21 GPIO_ACTIVE_LOW>; + label = "User LED 0"; + }; + + led1: led_1 { + gpios = <&portb 22 GPIO_ACTIVE_LOW>; + label = "User LED 1"; + }; + }; + + buttons { + compatible = "gpio-keys"; + + button0: button_0 { + gpios = <&portb 24 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW0"; + zephyr,code = ; + }; + + button1: button_1 { + gpios = <&portc 23 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW1"; + zephyr,code = ; + }; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@7fc000 { + label = "storage"; + reg = <0x0007fc000 0x4000>; + }; + }; +}; + +&cpu0 { + clock-frequency = <48000000>; +}; + +&portb { + status = "okay"; +}; + +&portc { + status = "okay"; +}; diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.yaml b/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.yaml new file mode 100644 index 0000000000000..e1e62f62ee721 --- /dev/null +++ b/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +identifier: pic32cz_ca80_cult +name: PIC32CZ CA80 Curiosity Ultra +type: mcu +arch: arm +toolchain: + - zephyr +flash: 8192 +ram: 1024 +supported: + - gpio +vendor: microchip diff --git a/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult_defconfig b/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult_defconfig new file mode 100644 index 0000000000000..912a8e1042370 --- /dev/null +++ b/boards/microchip/pic32c/pic32cz_ca80_cult/pic32cz_ca80_cult_defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_ARM_MPU=y From 900ffe1d7cdb9230d7e0d5366d3f8cb2e729de06 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 16 Oct 2025 18:56:50 -0500 Subject: [PATCH 122/397] drivers: eth_nxp_enet: Fix power mode control The driver should not take the whole interface down and re-initialize on every low power entry and exit. This is a lot of latency for no real gain as far as I can tell. We can just do as the reference manual actually says which is to set the sleep enable bit to put the module to sleep while still being able to detect magic packets for wake on LAN. Also, the only platform that this power action was "enabled" for was kinetis, but that platform does not have any power management enabled in Zephyr. Which means this code was never getting called even with all the PM configs on. So basically this code is dead code. But it could be useful for other platform, such as RT, so there's no reason not to remove the dependency on kinetis and let it be used for any of the platform as long as PM_DEVICE is enabled (hence the imply). Signed-off-by: Declan Snyder --- drivers/ethernet/Kconfig.nxp_enet | 2 +- drivers/ethernet/eth_nxp_enet.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/ethernet/Kconfig.nxp_enet b/drivers/ethernet/Kconfig.nxp_enet index 953ce84d51233..538543fb96bcb 100644 --- a/drivers/ethernet/Kconfig.nxp_enet +++ b/drivers/ethernet/Kconfig.nxp_enet @@ -12,7 +12,7 @@ config ETH_NXP_ENET depends on DT_HAS_NXP_ENET_MAC_ENABLED select NOCACHE_MEMORY if CPU_HAS_DCACHE select ARM_MPU if CPU_CORTEX_M7 - select NET_POWER_MANAGEMENT if (PM_DEVICE && SOC_FAMILY_KINETIS) + imply NET_POWER_MANAGEMENT select ETH_DSA_SUPPORT_DEPRECATED select PINCTRL select HWINFO if $(dt_compat_any_has_prop,$(DT_COMPAT_NXP_ENET_MAC),$(DT_NXP_UNIQUE_MAC_PROP),True) diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c index a19b3ec3f7ebb..40b2d69f4b237 100644 --- a/drivers/ethernet/eth_nxp_enet.c +++ b/drivers/ethernet/eth_nxp_enet.c @@ -799,14 +799,11 @@ static int eth_nxp_enet_device_pm_action(const struct device *dev, enum pm_devic return ret; } - ENET_Reset(data->base); - ENET_Down(data->base); - clock_control_off(config->clock_dev, (clock_control_subsys_t)config->clock_subsys); + ENET_EnableSleepMode(data->base, true); } else if (action == PM_DEVICE_ACTION_RESUME) { LOG_DBG("Resuming"); - clock_control_on(config->clock_dev, (clock_control_subsys_t)config->clock_subsys); - eth_nxp_enet_init(dev); + ENET_EnableSleepMode(data->base, false); net_if_resume(data->iface); } else { return -ENOTSUP; From 2cc92a6fa09c2957fc160dc775db987a5f49ba63 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 3 Oct 2025 05:11:49 -0400 Subject: [PATCH 123/397] tests: interrupt: Fix nested_irq test for Arm's GIC in Non-Secure state Change SGI interrupt lines from 14-15 to 6-7 for nested interrupt testing. SGI 8-15 are unaccessible from Non-Secure state (e.g., when running with TF-A), causing test failures. SGI 0-2 are reserved for Zephyr SMP IPIs, so use SGI 6-7 which work in both Secure and Non-Secure configurations. Fixes test failure: "isr0 did not execute" assertion at line 184. Signed-off-by: Nicolas Pitre --- tests/arch/common/interrupt/src/nested_irq.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/arch/common/interrupt/src/nested_irq.c b/tests/arch/common/interrupt/src/nested_irq.c index e2a9b70ee360e..ca4cebe987881 100644 --- a/tests/arch/common/interrupt/src/nested_irq.c +++ b/tests/arch/common/interrupt/src/nested_irq.c @@ -45,11 +45,13 @@ #endif #elif defined(CONFIG_GIC) /* - * For the platforms that use the ARM GIC, use the SGI (software generated - * interrupt) lines 14 and 15 for testing. + * For platforms that use Arm's GIC, use the SGI (software generated + * interrupt) lines 6 and 7 for testing. + * SGI 0-2 are used by Zephyr for SMP IPIs. + * SGI 8-15 are unaccessible from Non-Secure state. */ -#define IRQ0_LINE 14 -#define IRQ1_LINE 15 +#define IRQ0_LINE 6 +#define IRQ1_LINE 7 /* * Choose lower prio for IRQ0 and higher priority for IRQ1 From abbe2286b934530f114595a2d277cf91e8568892 Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Sat, 11 Oct 2025 22:48:39 +0200 Subject: [PATCH 124/397] boards: nxp: frdm_mcxa153: add arduino labels Added arduino_i2c, arduino_spi and arduino_header node labels to FRDM-MCXA153 device tree board definition, allowing compatible shield boards to be used. Also extend the board YAML file with related support tags arduino_gpio, arduino_i2c and arduino_spi. Signed-off-by: Stephan Linz --- .../frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi | 12 ++++++ boards/nxp/frdm_mcxa153/frdm_mcxa153.dts | 40 +++++++++++++++++++ boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml | 3 ++ 3 files changed, 55 insertions(+) diff --git a/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi b/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi index b92a00352cc75..3522372e6b504 100644 --- a/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi +++ b/boards/nxp/frdm_mcxa153/frdm_mcxa153-pinctrl.dtsi @@ -75,6 +75,18 @@ }; }; + pinmux_lpspi1: pinmux_lpspi1 { + group0 { + pinmux = , + , + , + ; + slew-rate = "fast"; + drive-strength = "low"; + input-enable; + }; + }; + pinmux_lpuart0: pinmux_lpuart0 { group0 { pinmux = , diff --git a/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts b/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts index e257a5e0bd986..4074c9713e670 100644 --- a/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts +++ b/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts @@ -9,6 +9,7 @@ #include #include "frdm_mcxa153-pinctrl.dtsi" #include +#include #include / { @@ -70,6 +71,35 @@ zephyr,code = ; }; }; + + arduino_header: arduino-connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = , + , + , + , + , + , + , /* GPIO, Not a RX */ + , /* GPIO, Not a TX */ + , + , + , + , + , + , + , + , + , /* CS */ + , /* MOSI */ + , /* MISO */ + , /* SCK */ + , /* SDA */ + ; /* SCL */ + }; }; &cpu0 { @@ -169,12 +199,22 @@ pinctrl-names = "default"; }; +arduino_i2c: &lpi2c0 {}; + &lpspi0 { status = "okay"; pinctrl-0 = <&pinmux_lpspi0>; pinctrl-names = "default"; }; +&lpspi1 { + status = "okay"; + pinctrl-0 = <&pinmux_lpspi1>; + pinctrl-names = "default"; +}; + +arduino_spi: &lpspi1 {}; + &lptmr0 { status = "okay"; }; diff --git a/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml b/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml index 63cb510600f42..252b7233cc6f7 100644 --- a/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml +++ b/boards/nxp/frdm_mcxa153/frdm_mcxa153.yaml @@ -15,6 +15,9 @@ toolchain: - gnuarmemb supported: - adc + - arduino_gpio + - arduino_i2c + - arduino_spi - counter - dma - flash From 36f9d71541813510f4fc7f1e66e14e3f809092ae Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Sat, 11 Oct 2025 22:54:03 +0200 Subject: [PATCH 125/397] boards: nxp: frdm_mcxa153: add mikrobus labels Added mikrobus_serial, mikrobus_spi and mikrobus_header node labels to FRDM-MCXA153 device tree board definition, allowing compatible shield boards to be used. Signed-off-by: Stephan Linz --- boards/nxp/frdm_mcxa153/frdm_mcxa153.dts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts b/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts index 4074c9713e670..2c626ef183d5a 100644 --- a/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts +++ b/boards/nxp/frdm_mcxa153/frdm_mcxa153.dts @@ -72,6 +72,25 @@ }; }; + mikrobus_header: mikrobus-connector { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio3 30 0>, /* AN */ + <1 0 &gpio3 1 0>, /* RST */ + <2 0 &gpio1 3 0>, /* CS */ + <3 0 &gpio1 1 0>, /* SCK */ + <4 0 &gpio1 2 0>, /* MISO */ + <5 0 &gpio1 0 0>, /* MOSI */ + <6 0 &gpio3 12 0>, /* PWM */ + <7 0 &gpio2 5 0>, /* INT */ + <8 0 &gpio3 14 0>, /* RX */ + <9 0 &gpio3 15 0>, /* TX */ + <10 0 &gpio3 27 0>, /* GPIO, Not a SCL */ + <11 0 &gpio3 28 0>; /* GPIO, Not a SDA */ + }; + arduino_header: arduino-connector { compatible = "arduino-header-r3"; #gpio-cells = <2>; @@ -207,6 +226,8 @@ arduino_i2c: &lpi2c0 {}; pinctrl-names = "default"; }; +mikrobus_spi: &lpspi0 {}; + &lpspi1 { status = "okay"; pinctrl-0 = <&pinmux_lpspi1>; @@ -233,6 +254,8 @@ arduino_spi: &lpspi1 {}; pinctrl-names = "default"; }; +mikrobus_serial: &lpuart2 {}; + /* * Uses OS timer as the kernel timer */ From 8356237483ad82cc40c4d5144aa18166b2b22e51 Mon Sep 17 00:00:00 2001 From: Tahsin Mutlugun Date: Tue, 26 Aug 2025 15:53:10 +0300 Subject: [PATCH 126/397] soc: adi: max32: Add support for MAX32658 SoC MAX32658 is the 1.8V variant of MAX32657. From a software perspective, both SoCs are functionally equivalent. Reuse the existing MAX32657 backend for MAX32658 to enable support with minimal changes. Signed-off-by: Tahsin Mutlugun --- soc/adi/max32/Kconfig.soc | 5 +++++ soc/adi/max32/soc.yml | 1 + 2 files changed, 6 insertions(+) diff --git a/soc/adi/max32/Kconfig.soc b/soc/adi/max32/Kconfig.soc index e4b2347ca0218..7bd66bf2cc70e 100644 --- a/soc/adi/max32/Kconfig.soc +++ b/soc/adi/max32/Kconfig.soc @@ -33,6 +33,10 @@ config SOC_MAX32657 bool select SOC_FAMILY_MAX32_M33 +config SOC_MAX32658 + bool + select SOC_MAX32657 + config SOC_MAX32660 bool select SOC_FAMILY_MAX32_M4 @@ -97,6 +101,7 @@ config SOC default "max32650" if SOC_MAX32650 default "max32655" if SOC_MAX32655 default "max32657" if SOC_MAX32657 + default "max32658" if SOC_MAX32658 default "max32660" if SOC_MAX32660 default "max32662" if SOC_MAX32662 default "max32666" if SOC_MAX32666 diff --git a/soc/adi/max32/soc.yml b/soc/adi/max32/soc.yml index 1a4b7c2568d38..270c8c28dfb39 100644 --- a/soc/adi/max32/soc.yml +++ b/soc/adi/max32/soc.yml @@ -9,6 +9,7 @@ family: cpuclusters: - name: m4 - name: max32657 + - name: max32658 - name: max32660 - name: max32662 - name: max32666 From f4624d96e79f87dd632cf64a7984b58bea7891ef Mon Sep 17 00:00:00 2001 From: Tahsin Mutlugun Date: Tue, 26 Aug 2025 16:06:45 +0300 Subject: [PATCH 127/397] boards: adi: Add MAX32658EVKIT secure and nonsecure boards Adds MAX32658EVKIT board with secure and nonsecure variants. Signed-off-by: Tahsin Mutlugun --- boards/adi/max32658evkit/Kconfig.defconfig | 48 ++ .../adi/max32658evkit/Kconfig.max32658evkit | 6 + boards/adi/max32658evkit/board.cmake | 12 + boards/adi/max32658evkit/board.yml | 10 + .../max32658evkit/doc/img/max32658evkit.webp | Bin 0 -> 76448 bytes boards/adi/max32658evkit/doc/index.rst | 571 ++++++++++++++++++ .../max32658evkit/max32658evkit_max32658.dts | 52 ++ .../max32658evkit/max32658evkit_max32658.yaml | 21 + .../max32658evkit_max32658_common.dtsi | 108 ++++ .../max32658evkit_max32658_defconfig | 16 + .../max32658evkit_max32658_ns.dts | 75 +++ .../max32658evkit_max32658_ns.yaml | 20 + .../max32658evkit_max32658_ns_defconfig | 19 + modules/trusted-firmware-m/CMakeLists.txt | 2 +- modules/trusted-firmware-m/Kconfig.tfm | 2 +- 15 files changed, 960 insertions(+), 2 deletions(-) create mode 100644 boards/adi/max32658evkit/Kconfig.defconfig create mode 100644 boards/adi/max32658evkit/Kconfig.max32658evkit create mode 100644 boards/adi/max32658evkit/board.cmake create mode 100644 boards/adi/max32658evkit/board.yml create mode 100644 boards/adi/max32658evkit/doc/img/max32658evkit.webp create mode 100644 boards/adi/max32658evkit/doc/index.rst create mode 100644 boards/adi/max32658evkit/max32658evkit_max32658.dts create mode 100644 boards/adi/max32658evkit/max32658evkit_max32658.yaml create mode 100644 boards/adi/max32658evkit/max32658evkit_max32658_common.dtsi create mode 100644 boards/adi/max32658evkit/max32658evkit_max32658_defconfig create mode 100644 boards/adi/max32658evkit/max32658evkit_max32658_ns.dts create mode 100644 boards/adi/max32658evkit/max32658evkit_max32658_ns.yaml create mode 100644 boards/adi/max32658evkit/max32658evkit_max32658_ns_defconfig diff --git a/boards/adi/max32658evkit/Kconfig.defconfig b/boards/adi/max32658evkit/Kconfig.defconfig new file mode 100644 index 0000000000000..8235ba516f2b5 --- /dev/null +++ b/boards/adi/max32658evkit/Kconfig.defconfig @@ -0,0 +1,48 @@ +# Copyright (c) 2024-2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_MAX32658EVKIT + +# Code Partition: +# +# For the secure version of the board the firmware is linked at the beginning +# of the flash, or into the code-partition defined in DT if it is intended to +# be loaded by MCUboot. If the secure firmware is to be combined with a non- +# secure image (TRUSTED_EXECUTION_SECURE=y), the secure FW image shall always +# be restricted to the size of its code partition. +# +# For the non-secure version of the board, the firmware +# must be linked into the code-partition (non-secure) defined in DT, regardless. +# Apply this configuration below by setting the Kconfig symbols used by +# the linker according to the information extracted from DT partitions. + +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition + +config FLASH_LOAD_SIZE + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +if BOARD_MAX32658EVKIT_MAX32658_NS + +config FLASH_LOAD_OFFSET + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) + +# MAX32658 has one UART interface, +# It can be used either on TFM or Zephyr +# Enabling debug (TFM_SPM_LOG_LEVEL || TFM_PARTITION_LOG_LEVEL) will transfer it to the TFM side +# Disabling TFM debug will transfer it to the Zephyr side. + +choice TFM_SPM_LOG_LEVEL + default TFM_SPM_LOG_LEVEL_SILENCE +endchoice + +choice TFM_PARTITION_LOG_LEVEL + default TFM_PARTITION_LOG_LEVEL_SILENCE +endchoice + +endif # BOARD_MAX32658EVKIT_MAX32658_NS + +config I3C + default y if ADXL367 + +endif # BOARD_MAX32658EVKIT diff --git a/boards/adi/max32658evkit/Kconfig.max32658evkit b/boards/adi/max32658evkit/Kconfig.max32658evkit new file mode 100644 index 0000000000000..d7b695e475872 --- /dev/null +++ b/boards/adi/max32658evkit/Kconfig.max32658evkit @@ -0,0 +1,6 @@ +# Copyright (c) 2024-2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_MAX32658EVKIT + select SOC_MAX32658 if BOARD_MAX32658EVKIT_MAX32658 || \ + BOARD_MAX32658EVKIT_MAX32658_NS diff --git a/boards/adi/max32658evkit/board.cmake b/boards/adi/max32658evkit/board.cmake new file mode 100644 index 0000000000000..32e6669b7018b --- /dev/null +++ b/boards/adi/max32658evkit/board.cmake @@ -0,0 +1,12 @@ +# Copyright (c) 2024-2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_MAX32658EVKIT_MAX32658_NS) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex) +endif() + +board_runner_args(jlink "--device=MAX32658" "--reset-after-load") + +include(${ZEPHYR_BASE}/boards/common/openocd-adi-max32.boards.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/adi/max32658evkit/board.yml b/boards/adi/max32658evkit/board.yml new file mode 100644 index 0000000000000..07a2bd79226d8 --- /dev/null +++ b/boards/adi/max32658evkit/board.yml @@ -0,0 +1,10 @@ +# Copyright (c) 2024-2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +board: + name: max32658evkit + vendor: adi + socs: + - name: max32658 + variants: + - name: "ns" diff --git a/boards/adi/max32658evkit/doc/img/max32658evkit.webp b/boards/adi/max32658evkit/doc/img/max32658evkit.webp new file mode 100644 index 0000000000000000000000000000000000000000..7bbf5b668eef641659656e1ba888ba53d0954131 GIT binary patch literal 76448 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../modules/tee/tf-m/trusted-firmware-m/platform/ext/target/adi/max32657/partition/flash_layout.h file.` +If you would like to update flash region for your application you shall update related section in +these files. + +Additionally if firmware update feature requires slot1 and slot1_ns section need to be +defined. On default the section size set as 0 due to firmware update not requires on default. + + +Peripherals and Memory Ownership +-------------------------------- + +The ARM Security Extensions model allows system developers to partition device hardware and +software resources, so that they exist in either the Secure world for the security subsystem, +or the Normal world for everything else. Correct system design can ensure that no Secure world +assets can be accessed from the Normal world. A Secure design places all sensitive resources +in the Secure world, and ideally has robust software running that can protect assets against +a wide range of possible software attacks (`1`_). + +MPC (Memory Protection Controller) and PPC (Peripheral Protection Controller) are allow to +protect memory and peripheral. Incase of need peripheral and flash ownership can be updated in +../modules/tee/tf-m/trusted-firmware-m/platform/ext/target/adi/max32657/s_ns_access.cmake` +file by updating cmake flags to ON/OFF. + +As an example for below configuration TRNG, SRAM_0 and SRAM_1 is not going to be accessible +by non-secure. All others is going to be accessible by NS world. + +.. code-block:: + + set(ADI_NS_PRPH_GCR ON CACHE BOOL "") + set(ADI_NS_PRPH_SIR ON CACHE BOOL "") + set(ADI_NS_PRPH_FCR ON CACHE BOOL "") + set(ADI_NS_PRPH_WDT ON CACHE BOOL "") + set(ADI_NS_PRPH_AES OFF CACHE BOOL "") + set(ADI_NS_PRPH_AESKEY OFF CACHE BOOL "") + set(ADI_NS_PRPH_CRC ON CACHE BOOL "") + set(ADI_NS_PRPH_GPIO0 ON CACHE BOOL "") + set(ADI_NS_PRPH_TIMER0 ON CACHE BOOL "") + set(ADI_NS_PRPH_TIMER1 ON CACHE BOOL "") + set(ADI_NS_PRPH_TIMER2 ON CACHE BOOL "") + set(ADI_NS_PRPH_TIMER3 ON CACHE BOOL "") + set(ADI_NS_PRPH_TIMER4 ON CACHE BOOL "") + set(ADI_NS_PRPH_TIMER5 ON CACHE BOOL "") + set(ADI_NS_PRPH_I3C ON CACHE BOOL "") + set(ADI_NS_PRPH_UART ON CACHE BOOL "") + set(ADI_NS_PRPH_SPI ON CACHE BOOL "") + set(ADI_NS_PRPH_TRNG OFF CACHE BOOL "") + set(ADI_NS_PRPH_BTLE_DBB ON CACHE BOOL "") + set(ADI_NS_PRPH_BTLE_RFFE ON CACHE BOOL "") + set(ADI_NS_PRPH_RSTZ ON CACHE BOOL "") + set(ADI_NS_PRPH_BOOST ON CACHE BOOL "") + set(ADI_NS_PRPH_BBSIR ON CACHE BOOL "") + set(ADI_NS_PRPH_BBFCR ON CACHE BOOL "") + set(ADI_NS_PRPH_RTC ON CACHE BOOL "") + set(ADI_NS_PRPH_WUT0 ON CACHE BOOL "") + set(ADI_NS_PRPH_WUT1 ON CACHE BOOL "") + set(ADI_NS_PRPH_PWR ON CACHE BOOL "") + set(ADI_NS_PRPH_MCR ON CACHE BOOL "") + + # SRAMs + set(ADI_NS_SRAM_0 OFF CACHE BOOL "Size: 32KB") + set(ADI_NS_SRAM_1 OFF CACHE BOOL "Size: 32KB") + set(ADI_NS_SRAM_2 ON CACHE BOOL "Size: 64KB") + set(ADI_NS_SRAM_3 ON CACHE BOOL "Size: 64KB") + set(ADI_NS_SRAM_4 ON CACHE BOOL "Size: 64KB") + + # Ramfuncs section size + set(ADI_S_RAM_CODE_SIZE "0x800" CACHE STRING "Default: 2KB") + + # Flash: BL2, TFM and Zephyr are contiguous sections. + set(ADI_FLASH_AREA_BL2_SIZE "0x10000" CACHE STRING "Default: 64KB") + set(ADI_FLASH_S_PARTITION_SIZE "0x50000" CACHE STRING "Default: 320KB") + set(ADI_FLASH_NS_PARTITION_SIZE "0x90000" CACHE STRING "Default: 576KB") + set(ADI_FLASH_PS_AREA_SIZE "0x4000" CACHE STRING "Default: 16KB") + set(ADI_FLASH_ITS_AREA_SIZE "0x4000" CACHE STRING "Default: 16KB") + + # + # Allow user set S-NS resources ownership by overlay file + # + if(EXISTS "${CMAKE_BINARY_DIR}/../../s_ns_access_overlay.cmake") + include(${CMAKE_BINARY_DIR}/../../s_ns_access_overlay.cmake) + endif() + + +As an alternative method (which recommended) user can configurate ownership peripheral by +an cmake overlay file too without touching TF-M source files. For this path +create ``s_ns_access_overlay.cmake`` file under your project root folder and put peripheral/memory +you would like to be accessible by secure world. + +As an example if below configuration files been put in the ``s_ns_access_overlay.cmake`` file +TRNG, SRAM_0 and SRAM_1 will be accessible by secure world only. + +.. code-block:: + + set(ADI_NS_PRPH_TRNG OFF CACHE BOOL "") + set(ADI_NS_SRAM_0 OFF CACHE BOOL "Size: 32KB") + set(ADI_NS_SRAM_1 OFF CACHE BOOL "Size: 32KB") + + +Programming and Debugging +************************* + +.. zephyr:board-supported-runners:: + +Flashing +======== + +Here is an example for the :zephyr:code-sample:`hello_world` application. This example uses the +:ref:`jlink-debug-host-tools` as default. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: max32658evkit/max32658 + :goals: flash + +Open a serial terminal, reset the board (press the RESET button), and you should +see the following message in the terminal: + +.. code-block:: console + + ***** Booting Zephyr OS build v4.1.0 ***** + Hello World! max32658evkit/max32658 + +Building and flashing secure/non-secure with Arm |reg| TrustZone |reg| +---------------------------------------------------------------------- +The TF-M integration samples can be run using the +``max32658evkit/max32658/ns`` board target. To run we need to manually flash +the resulting image (``tfm_merged.hex``) with a J-Link as follows +(reset and erase are for recovering a locked core): + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: max32658evkit/max32658/ns + :goals: build + +.. code-block:: console + + west flash --hex-file build/zephyr/tfm_merged.hex + +.. code-block:: console + + [INF] Starting bootloader + [WRN] This device was provisioned with dummy keys. This device is NOT SECURE + [INF] PSA Crypto init done, sig_type: RSA-3072 + [WRN] Cannot upgrade: slots have non-compatible sectors + [WRN] Cannot upgrade: slots have non-compatible sectors + [INF] Bootloader chainload address offset: 0x10000 + [INF] Jumping to the first image slot + ***** Booting Zephyr OS build v4.2.0 ***** + Hello World! max32658evkit/max32658/ns + + +Debugging +========= + +Here is an example for the :zephyr:code-sample:`hello_world` application. This example uses the +:ref:`jlink-debug-host-tools` as default. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: max32658evkit/max32658 + :goals: debug + +Open a serial terminal, step through the application in your debugger, and you +should see the following message in the terminal: + +.. code-block:: console + + ***** Booting Zephyr OS build v4.2.0 ***** + Hello World! max32658evkit/max32658 + +References +********** + +.. _1: + https://developer.arm.com/documentation/100935/0100/The-TrustZone-hardware-architecture- + +.. _Trusted Firmware M: + https://tf-m-user-guide.trustedfirmware.org/building/tfm_build_instruction.html diff --git a/boards/adi/max32658evkit/max32658evkit_max32658.dts b/boards/adi/max32658evkit/max32658evkit_max32658.dts new file mode 100644 index 0000000000000..20b52890f76b3 --- /dev/null +++ b/boards/adi/max32658evkit/max32658evkit_max32658.dts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024-2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "max32658evkit_max32658_common.dtsi" + +/ { + chosen { + zephyr,sram = &secure_ram; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + secure_ram: partition@30000000 { + label = "secure-memory"; + reg = <0x30000000 DT_SIZE_K(256)>; + }; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x0 DT_SIZE_K(960)>; + read-only; + }; + + storage_partition: partition@f0000 { + label = "storage"; + reg = <0xf0000 DT_SIZE_K(64)>; + }; + }; +}; + +&trng { + status = "okay"; +}; diff --git a/boards/adi/max32658evkit/max32658evkit_max32658.yaml b/boards/adi/max32658evkit/max32658evkit_max32658.yaml new file mode 100644 index 0000000000000..f4e7fdac7f8f4 --- /dev/null +++ b/boards/adi/max32658evkit/max32658evkit_max32658.yaml @@ -0,0 +1,21 @@ +identifier: max32658evkit/max32658 +name: max32658evkit-max32658 +vendor: adi +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - serial + - gpio + - trng + - watchdog + - dma + - counter + - pwm + - rtc_counter + - spi + - i3c +ram: 256 +flash: 960 diff --git a/boards/adi/max32658evkit/max32658evkit_max32658_common.dtsi b/boards/adi/max32658evkit/max32658evkit_max32658_common.dtsi new file mode 100644 index 0000000000000..9b65c7bffab63 --- /dev/null +++ b/boards/adi/max32658evkit/max32658evkit_max32658_common.dtsi @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024-2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/ { + model = "Analog Devices MAX32658EVKIT"; + compatible = "adi,max32658evkit"; + + chosen { + zephyr,console = &uart0; + zephyr,cortex-m-idle-timer = &counter_wut1; + zephyr,shell-uart = &uart0; + }; + + leds { + compatible = "gpio-leds"; + + led1: led_1 { + gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + buttons { + compatible = "gpio-keys"; + + pb1: pb1 { + gpios = <&gpio0 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW2"; + zephyr,code = ; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + accel0 = &adxl367; + led0 = &led1; + sw0 = &pb1; + watchdog0 = &wdt0; + }; +}; + +&uart0 { + pinctrl-0 = <&uart0_tx_p0_9 &uart0_rx_p0_5>; + pinctrl-names = "default"; + current-speed = <115200>; + data-bits = <8>; + parity = "none"; + status = "okay"; +}; + +&clk_ipo { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&spi0 { + status = "okay"; + pinctrl-0 = <&spi0_mosi_p0_2 &spi0_miso_p0_4 &spi0_sck_p0_6 &spi0_ss0_p0_3>; + pinctrl-names = "default"; +}; + +&rtc_counter { + status = "okay"; + clock-source = ; +}; + +&i3c0 { + status = "okay"; + pinctrl-0 = <&i3c_scl_p0_0 &i3c_sda_p0_1>; + pinctrl-names = "default"; + i2c-scl-hz = ; + i3c-scl-hz = ; + i3c-od-scl-hz = ; + + adxl367: adxl367@530000000000000000 { + compatible = "adi,adxl367"; + reg = <0x53 0x00 0x00>; + status = "okay"; + }; +}; + +&wut0 { + clock-source = ; +}; + +&wut1 { + status = "okay"; + clock-source = ; + wakeup-source; + counter_wut1: counter { + status = "okay"; + }; +}; diff --git a/boards/adi/max32658evkit/max32658evkit_max32658_defconfig b/boards/adi/max32658evkit/max32658evkit_max32658_defconfig new file mode 100644 index 0000000000000..25ef03ee5131b --- /dev/null +++ b/boards/adi/max32658evkit/max32658evkit_max32658_defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024-2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Enable GPIO +CONFIG_GPIO=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable UART +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# It is secure fw, enable flags +CONFIG_TRUSTED_EXECUTION_SECURE=y diff --git a/boards/adi/max32658evkit/max32658evkit_max32658_ns.dts b/boards/adi/max32658evkit/max32658evkit_max32658_ns.dts new file mode 100644 index 0000000000000..0cc9f08804802 --- /dev/null +++ b/boards/adi/max32658evkit/max32658evkit_max32658_ns.dts @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024-2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "max32658evkit_max32658_common.dtsi" + +/ { + chosen { + zephyr,sram = &non_secure_ram; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_ns_partition; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* RAM split used by TFM */ + secure_ram: partition@20000000 { + label = "secure-memory"; + reg = <0x20000000 DT_SIZE_K(64)>; + }; + + non_secure_ram: partition@20010000 { + label = "non-secure-memory"; + reg = <0x20010000 DT_SIZE_K(192)>; + }; + }; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 DT_SIZE_K(64)>; + read-only; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x10000 DT_SIZE_K(320)>; + }; + + slot0_ns_partition: partition@60000 { + label = "image-0-nonsecure"; + reg = <0x60000 DT_SIZE_K(576)>; + }; + + /* + * slot1_partition: partition@f0000 { + * label = "image-1"; + * reg = <0xf0000 DT_SIZE_K(0)>; + * }; + * slot1_ns_partition: partition@f0000 { + * label = "image-1-nonsecure"; + * reg = <0xf0000 DT_SIZE_K(0)>; + * }; + */ + + storage_partition: partition@f0000 { + label = "storage"; + reg = <0xf0000 DT_SIZE_K(64)>; + }; + }; +}; diff --git a/boards/adi/max32658evkit/max32658evkit_max32658_ns.yaml b/boards/adi/max32658evkit/max32658evkit_max32658_ns.yaml new file mode 100644 index 0000000000000..9868c5bb8a710 --- /dev/null +++ b/boards/adi/max32658evkit/max32658evkit_max32658_ns.yaml @@ -0,0 +1,20 @@ +identifier: max32658evkit/max32658/ns +name: max32658evkit-max32658-Non-Secure +vendor: adi +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - serial + - gpio + - watchdog + - dma + - counter + - pwm + - rtc_counter + - spi + - i3c +ram: 192 +flash: 576 diff --git a/boards/adi/max32658evkit/max32658evkit_max32658_ns_defconfig b/boards/adi/max32658evkit/max32658evkit_max32658_ns_defconfig new file mode 100644 index 0000000000000..d808f79c54594 --- /dev/null +++ b/boards/adi/max32658evkit/max32658evkit_max32658_ns_defconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2024-2025 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Enable GPIO +CONFIG_GPIO=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable UART +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# It is non-secure fw, enable flags +CONFIG_TRUSTED_EXECUTION_NONSECURE=y + +# Set TFM and Zephyr sign key +CONFIG_TFM_MCUBOOT_SIGNATURE_TYPE="RSA-3072" diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 59337875e9c67..a366fbb50bdab 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -251,7 +251,7 @@ if (CONFIG_BUILD_WITH_TFM) list(APPEND TFM_CMAKE_ARGS -DTFM_PLATFORM_NXP_HAL_FILE_PATH=${TFM_PLATFORM_NXP_HAL_FILE_PATH}) endif() - if(CONFIG_BOARD_MAX32657EVKIT_MAX32657_NS) + if(CONFIG_BOARD_MAX32657EVKIT_MAX32657_NS OR CONFIG_BOARD_MAX32658EVKIT_MAX32658_NS) # Supply path to hal_adi for TF-M build list(APPEND TFM_CMAKE_ARGS -DHAL_ADI_PATH=${ZEPHYR_ADI_MODULE_DIR}) endif() diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index 06c7221321ec9..6c3ac64487f2e 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -25,7 +25,7 @@ config TFM_BOARD default "stm/stm32wba65i_dk" if BOARD_NUCLEO_WBA65RI || BOARD_STM32WBA65I_DK1 default "arm/musca_b1" if BOARD_V2M_MUSCA_B1 default "arm/musca_s1" if BOARD_V2M_MUSCA_S1 - default "adi/max32657" if BOARD_MAX32657EVKIT_MAX32657_NS + default "adi/max32657" if BOARD_MAX32657EVKIT_MAX32657_NS || BOARD_MAX32658EVKIT_MAX32658_NS default "$(ZEPHYR_BASE)/modules/trusted-firmware-m/nordic/nrf9160" if SOC_NRF9160 default "$(ZEPHYR_BASE)/modules/trusted-firmware-m/nordic/nrf9120" if SOC_NRF9120 default "$(ZEPHYR_BASE)/modules/trusted-firmware-m/nordic/nrf5340_cpuapp" if SOC_NRF5340_CPUAPP From f717b596da8f61a6507135a5d06e0da8ece524ee Mon Sep 17 00:00:00 2001 From: Neil Chen Date: Tue, 23 Sep 2025 15:45:11 +0800 Subject: [PATCH 128/397] dts: mcxa344: add dts for MCXA344 add dts support for board frdm_mcxa344 Signed-off-by: Neil Chen --- dts/arm/nxp/nxp_mcxa344.dtsi | 477 +++++++++++++++++++++++++++++++++++ 1 file changed, 477 insertions(+) create mode 100644 dts/arm/nxp/nxp_mcxa344.dtsi diff --git a/dts/arm/nxp/nxp_mcxa344.dtsi b/dts/arm/nxp/nxp_mcxa344.dtsi new file mode 100644 index 0000000000000..e7376d9bbcc16 --- /dev/null +++ b/dts/arm/nxp/nxp_mcxa344.dtsi @@ -0,0 +1,477 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m33f"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + /* Dummy pinctrl node, filled with pin mux options at board level */ + pinctrl: pinctrl { + compatible = "nxp,port-pinctrl"; + status = "okay"; + }; + + cmc { + compatible = "nxp,cmc-reset-cause"; + }; + + soc { + syscon: syscon@40091000 { + compatible = "nxp,lpc-syscon"; + reg = <0x40091000 0x4000>; + #clock-cells = <1>; + reset: reset { + compatible = "nxp,lpc-syscon-reset"; + #reset-cells = <1>; + }; + }; + + sramx: memory@4000000 { + compatible = "mmio-sram"; + reg = <0x4000000 DT_SIZE_K(16)>; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(48)>; + }; + + porta: pinmux@400bc000 { + compatible = "nxp,port-pinmux"; + reg = <0x400bc000 0x1000>; + clocks = <&syscon MCUX_PORT0_CLK>; + }; + + portb: pinmux@400bd000 { + compatible = "nxp,port-pinmux"; + reg = <0x400bd000 0x1000>; + clocks = <&syscon MCUX_PORT1_CLK>; + }; + + portc: pinmux@400be000 { + compatible = "nxp,port-pinmux"; + reg = <0x400be000 0x1000>; + clocks = <&syscon MCUX_PORT2_CLK>; + }; + + portd: pinmux@400bf000 { + compatible = "nxp,port-pinmux"; + reg = <0x400bf000 0x1000>; + clocks = <&syscon MCUX_PORT3_CLK>; + }; + + porte: pinmux@400c0000 { + compatible = "nxp,port-pinmux"; + reg = <0x400c0000 0x1000>; + clocks = <&syscon MCUX_PORT4_CLK>; + }; + + gpio0: gpio@40102000 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x40102000 0x1000>; + interrupts = <71 0>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porta>; + }; + + gpio1: gpio@40103000 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x40103000 0x1000>; + interrupts = <72 0>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portb>; + }; + + gpio2: gpio@40104000 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x40104000 0x1000>; + interrupts = <73 0>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portc>; + }; + + gpio3: gpio@40105000 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x40105000 0x1000>; + interrupts = <74 0>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portd>; + }; + + gpio4: gpio@40106000 { + compatible = "nxp,kinetis-gpio"; + status = "disabled"; + reg = <0x40106000 0x1000>; + interrupts = <75 0>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porte>; + }; + + lpuart0: lpuart@4009f000 { + compatible = "nxp,lpuart"; + status = "disabled"; + reg = <0x4009f000 0x1000>; + interrupts = <31 0>; + clocks = <&syscon MCUX_LPUART0_CLK>; + /* DMA channels 0 and 1, muxed to LPUART0 RX and TX */ + dmas = <&edma0 0 21>, <&edma0 1 22>; + dma-names = "rx", "tx"; + }; + + lpuart1: lpuart@400a0000 { + compatible = "nxp,lpuart"; + status = "disabled"; + reg = <0x400a0000 0x1000>; + interrupts = <32 0>; + clocks = <&syscon MCUX_LPUART1_CLK>; + /* DMA channels 2 and 3, muxed to LPUART1 RX and TX */ + dmas = <&edma0 2 23>, <&edma0 3 24>; + dma-names = "rx", "tx"; + }; + + lpuart2: lpuart@400a1000 { + compatible = "nxp,lpuart"; + status = "disabled"; + reg = <0x400a1000 0x1000>; + interrupts = <33 0>; + clocks = <&syscon MCUX_LPUART2_CLK>; + /* DMA channels 4 and 5, muxed to LPUART2 RX and TX */ + dmas = <&edma0 4 25>, <&edma0 5 26>; + dma-names = "rx", "tx"; + }; + + lpuart3: lpuart@400a2000 { + compatible = "nxp,lpuart"; + status = "disabled"; + reg = <0x400a2000 0x1000>; + interrupts = <34 0>; + clocks = <&syscon MCUX_LPUART3_CLK>; + /* DMA channels 6 and 7, muxed to LPUART3 RX and TX */ + dmas = <&edma0 6 27>, <&edma0 7 28>; + dma-names = "rx", "tx"; + }; + + fmu: flash-controller@40095000 { + compatible = "nxp,msf1"; + reg = <0x40095000 0x1000>; + interrupts = <12 0>; + + #address-cells = <1>; + #size-cells = <1>; + + flash: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_K(256)>; + erase-block-size = <8192>; + write-block-size = <128>; + }; + + uuid: uuid@1100800 { + compatible = "nxp,lpc-uid"; + reg = <0x1100800 0x10>; + }; + }; + + ctimer0: ctimer@40004000 { + compatible = "nxp,lpc-ctimer"; + reg = <0x40004000 0x1000>; + interrupts = <39 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER0_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + ctimer1: ctimer@40005000 { + compatible = "nxp,lpc-ctimer"; + reg = <0x40005000 0x1000>; + interrupts = <40 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER1_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + ctimer2: ctimer@40006000 { + compatible = "nxp,lpc-ctimer"; + reg = <0x40006000 0x1000>; + interrupts = <41 0>; + status = "disabled"; + clk-source = <1>; + clocks = <&syscon MCUX_CTIMER2_CLK>; + mode = <0>; + input = <0>; + prescale = <0>; + }; + + edma0: dma-controller@40080000 { + #dma-cells = <2>; + compatible = "nxp,mcux-edma"; + nxp,version = <4>; + dma-channels = <8>; + dma-requests = <86>; + + reg = <0x40080000 0x1000>; + interrupts = <2 0>, <3 0>, <4 0>, <5 0>, + <6 0>, <7 0>, <8 0>, <9 0>; + no-error-irq; + status = "disabled"; + }; + + flexcan0: can@400cc000 { + compatible = "nxp,flexcan"; + reg = <0x400cc000 0x1000>; + interrupts = <19 0>; + interrupt-names = "common"; + clocks = <&syscon MCUX_FLEXCAN0_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexpwm0: flexpwm@400a9000 { + compatible = "nxp,flexpwm"; + reg = <0x400a9000 0x1000>; + interrupt-names = "RELOAD-ERROR", "FAULT"; + interrupts = <44 0>, <45 0>; + flexpwm0_pwm0: pwm0 { + compatible = "nxp,imx-pwm"; + index = <0>; + interrupts = <46 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm0_pwm1: pwm1 { + compatible = "nxp,imx-pwm"; + index = <1>; + interrupts = <47 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm0_pwm2: pwm2 { + compatible = "nxp,imx-pwm"; + index = <2>; + interrupts = <48 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + }; + + flexpwm1: flexpwm@400aa000 { + compatible = "nxp,flexpwm"; + reg = <0x400aa000 0x1000>; + interrupt-names = "RELOAD-ERROR", "FAULT"; + interrupts = <79 0>, <80 0>; + flexpwm1_pwm0: pwm0 { + compatible = "nxp,imx-pwm"; + index = <0>; + interrupts = <81 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm1_pwm1: pwm1 { + compatible = "nxp,imx-pwm"; + index = <1>; + interrupts = <82 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + + flexpwm1_pwm2: pwm2 { + compatible = "nxp,imx-pwm"; + index = <2>; + interrupts = <83 0>; + #pwm-cells = <3>; + clocks = <&syscon MCUX_BUS_CLK>; + nxp,prescaler = <128>; + status = "disabled"; + run-in-wait; + }; + }; + + lpadc0: lpadc@400af000 { + compatible = "nxp,lpc-lpadc"; + reg = <0x400af000 0x1000>; + interrupts = <62 0>; + status = "disabled"; + clk-divider = <1>; + clk-source = <0>; + voltage-ref= <2>; + calibration-average = <128>; + power-level = <0>; + offset-value-a = <0>; + offset-value-b = <0>; + #io-channel-cells = <1>; + clocks = <&syscon MCUX_LPADC1_CLK>; + }; + + lpadc1: lpadc@400b0000 { + compatible = "nxp,lpc-lpadc"; + reg = <0x400b0000 0x1000>; + interrupts = <63 0>; + status = "disabled"; + clk-divider = <1>; + clk-source = <0>; + voltage-ref= <2>; + calibration-average = <128>; + power-level = <1>; + offset-value-a = <0>; + offset-value-b = <0>; + #io-channel-cells = <1>; + clocks = <&syscon MCUX_LPADC2_CLK>; + }; + + lpcmp0: lpcmp@400b1000 { + compatible = "nxp,lpcmp"; + reg = <0x400b1000 0x1000>; + interrupts = <64 0>; + status = "disabled"; + #io-channel-cells = <2>; + }; + + lpcmp1: lpcmp@400b2000 { + compatible = "nxp,lpcmp"; + reg = <0x400b2000 0x1000>; + interrupts = <65 0>; + status = "disabled"; + #io-channel-cells = <2>; + }; + + lpcmp2: lpcmp@400b3000 { + compatible = "nxp,lpcmp"; + reg = <0x400b3000 0x1000>; + interrupts = <66 0>; + status = "disabled"; + #io-channel-cells = <2>; + }; + + lpi2c0: i2c@4009a000 { + compatible = "nxp,lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4009a000 0x1000>; + interrupts = <26 0>; + clocks = <&syscon MCUX_LPI2C0_CLK>; + status = "disabled"; + }; + + lpi2c1: i2c@4009b000 { + compatible = "nxp,lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4009b000 0x1000>; + interrupts = <27 0>; + clocks = <&syscon MCUX_LPI2C1_CLK>; + status = "disabled"; + }; + + lpspi0: spi@4009c000 { + compatible = "nxp,lpspi"; + reg = <0x4009c000 0x1000>; + interrupts = <28 0>; + clocks = <&syscon MCUX_LPSPI0_CLK>; + tx-fifo-size = <4>; + rx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi1: spi@4009d000 { + compatible = "nxp,lpspi"; + reg = <0x4009d000 0x1000>; + interrupts = <29 0>; + clocks = <&syscon MCUX_LPSPI1_CLK>; + tx-fifo-size = <4>; + rx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lptmr0: lptmr@400ab000 { + compatible = "nxp,lptmr"; + reg = <0x400ab000 0x1000>; + interrupts = <55 0>; + clock-frequency = <16000>; + prescale-glitch-filter = <0>; + clk-source = <1>; + resolution = <32>; + status = "disabled"; + }; + + ostimer0: timers@400ad000 { + compatible = "nxp,os-timer"; + reg = <0x400ad000 0x1000>; + interrupts = <57 0>; + status = "disabled"; + }; + + temp0: temp0 { + compatible = "nxp,lpadc-temp40"; + status = "disabled"; + }; + + wwdt0: watchdog@4000c000 { + compatible = "nxp,lpc-wwdt"; + reg = <0x4000c000 0x1000>; + interrupts = <60 0>; + status = "disabled"; + clk-divider = <1>; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; From 6fac5857f1c3abcfbe6cec121799888c5869a706 Mon Sep 17 00:00:00 2001 From: Neil Chen Date: Thu, 9 Oct 2025 10:53:21 +0800 Subject: [PATCH 129/397] soc: mcxa344: add SOC support for MCXA344 Add soc MCXA153 for board frdm_mcxa344 Signed-off-by: Neil Chen --- soc/nxp/mcx/mcxa/Kconfig | 7 +++++++ soc/nxp/mcx/mcxa/Kconfig.soc | 21 +++++++++++++++++++++ soc/nxp/mcx/soc.yml | 5 +++++ 3 files changed, 33 insertions(+) diff --git a/soc/nxp/mcx/mcxa/Kconfig b/soc/nxp/mcx/mcxa/Kconfig index af34d311ebaad..df1092cda6a0a 100644 --- a/soc/nxp/mcx/mcxa/Kconfig +++ b/soc/nxp/mcx/mcxa/Kconfig @@ -40,3 +40,10 @@ config SOC_MCXA366 select CPU_HAS_FPU select ARMV8_M_DSP select HAS_MCUX_CACHE + +config SOC_MCXA344 + select CPU_CORTEX_M33 + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU + select ARMV8_M_DSP + select HAS_MCUX_CACHE diff --git a/soc/nxp/mcx/mcxa/Kconfig.soc b/soc/nxp/mcx/mcxa/Kconfig.soc index 1928fe2e42d3b..549204be406ef 100644 --- a/soc/nxp/mcx/mcxa/Kconfig.soc +++ b/soc/nxp/mcx/mcxa/Kconfig.soc @@ -27,12 +27,17 @@ config SOC_MCXA366 bool select SOC_FAMILY_MCXA +config SOC_MCXA344 + bool + select SOC_FAMILY_MCXA + config SOC default "mcxa153" if SOC_MCXA153 default "mcxa156" if SOC_MCXA156 default "mcxa346" if SOC_MCXA346 default "mcxa266" if SOC_MCXA266 default "mcxa366" if SOC_MCXA366 + default "mcxa344" if SOC_MCXA344 config SOC_PART_NUMBER_MCXA153VFM bool @@ -91,6 +96,18 @@ config SOC_PART_NUMBER_MCXA366VLH config SOC_PART_NUMBER_MCXA366VPN bool +config SOC_PART_NUMBER_MCXA344VFM + bool + +config SOC_PART_NUMBER_MCXA344VLF + bool + +config SOC_PART_NUMBER_MCXA344VLH + bool + +config SOC_PART_NUMBER_MCXA344VLL + bool + config SOC_PART_NUMBER default "MCXA153VFM" if SOC_PART_NUMBER_MCXA153VFM default "MCXA153VFT" if SOC_PART_NUMBER_MCXA153VFT @@ -111,3 +128,7 @@ config SOC_PART_NUMBER default "MCXA366VLL" if SOC_PART_NUMBER_MCXA366VLL default "MCXA366VLH" if SOC_PART_NUMBER_MCXA366VLH default "MCXA366VPN" if SOC_PART_NUMBER_MCXA366VPN + default "MCXA344VFM" if SOC_PART_NUMBER_MCXA344VFM + default "MCXA344VLF" if SOC_PART_NUMBER_MCXA344VLF + default "MCXA344VLH" if SOC_PART_NUMBER_MCXA344VLH + default "MCXA344VLL" if SOC_PART_NUMBER_MCXA344VLL diff --git a/soc/nxp/mcx/soc.yml b/soc/nxp/mcx/soc.yml index 23bce577c193a..fae16fdbd8f8b 100644 --- a/soc/nxp/mcx/soc.yml +++ b/soc/nxp/mcx/soc.yml @@ -23,6 +23,7 @@ family: - name: mcxa346 - name: mcxa266 - name: mcxa366 + - name: mcxa344 - name: mcxw series: - name: mcxw2xx @@ -70,6 +71,8 @@ runners: - mcxw716c - qualifiers: - mcxw236 + - qualifiers: + - mcxa344 '--reset': - run: last runners: @@ -102,3 +105,5 @@ runners: - mcxw716c - qualifiers: - mcxw236 + - qualifiers: + - mcxa344 From 49a9df026767d7962a52e72db2b4cc13bdcf7ea8 Mon Sep 17 00:00:00 2001 From: Neil Chen Date: Tue, 23 Sep 2025 15:49:16 +0800 Subject: [PATCH 130/397] boards: frdm_mcxa344: add frdm_mcxa344 board enable board support for frdm_mcxa344 Signed-off-by: Neil Chen --- boards/nxp/frdm_mcxa344/CMakeLists.txt | 8 + boards/nxp/frdm_mcxa344/Kconfig | 5 + boards/nxp/frdm_mcxa344/Kconfig.frdm_mcxa344 | 6 + boards/nxp/frdm_mcxa344/board.c | 148 ++++++++++++++++ boards/nxp/frdm_mcxa344/board.cmake | 13 ++ boards/nxp/frdm_mcxa344/board.yml | 6 + boards/nxp/frdm_mcxa344/doc/frdm_mcxa344.webp | Bin 0 -> 63790 bytes boards/nxp/frdm_mcxa344/doc/index.rst | 160 +++++++++++++++++ .../frdm_mcxa344/frdm_mcxa344-pinctrl.dtsi | 19 ++ boards/nxp/frdm_mcxa344/frdm_mcxa344.dts | 162 ++++++++++++++++++ boards/nxp/frdm_mcxa344/frdm_mcxa344.yaml | 21 +++ .../nxp/frdm_mcxa344/frdm_mcxa344_defconfig | 12 ++ 12 files changed, 560 insertions(+) create mode 100644 boards/nxp/frdm_mcxa344/CMakeLists.txt create mode 100644 boards/nxp/frdm_mcxa344/Kconfig create mode 100644 boards/nxp/frdm_mcxa344/Kconfig.frdm_mcxa344 create mode 100644 boards/nxp/frdm_mcxa344/board.c create mode 100644 boards/nxp/frdm_mcxa344/board.cmake create mode 100644 boards/nxp/frdm_mcxa344/board.yml create mode 100644 boards/nxp/frdm_mcxa344/doc/frdm_mcxa344.webp create mode 100644 boards/nxp/frdm_mcxa344/doc/index.rst create mode 100644 boards/nxp/frdm_mcxa344/frdm_mcxa344-pinctrl.dtsi create mode 100644 boards/nxp/frdm_mcxa344/frdm_mcxa344.dts create mode 100644 boards/nxp/frdm_mcxa344/frdm_mcxa344.yaml create mode 100644 boards/nxp/frdm_mcxa344/frdm_mcxa344_defconfig diff --git a/boards/nxp/frdm_mcxa344/CMakeLists.txt b/boards/nxp/frdm_mcxa344/CMakeLists.txt new file mode 100644 index 0000000000000..c06b9273965c0 --- /dev/null +++ b/boards/nxp/frdm_mcxa344/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_library() +zephyr_library_sources(board.c) diff --git a/boards/nxp/frdm_mcxa344/Kconfig b/boards/nxp/frdm_mcxa344/Kconfig new file mode 100644 index 0000000000000..9e41ea4cc16a3 --- /dev/null +++ b/boards/nxp/frdm_mcxa344/Kconfig @@ -0,0 +1,5 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FRDM_MCXA344 + select BOARD_EARLY_INIT_HOOK diff --git a/boards/nxp/frdm_mcxa344/Kconfig.frdm_mcxa344 b/boards/nxp/frdm_mcxa344/Kconfig.frdm_mcxa344 new file mode 100644 index 0000000000000..4d895ff6d8efa --- /dev/null +++ b/boards/nxp/frdm_mcxa344/Kconfig.frdm_mcxa344 @@ -0,0 +1,6 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FRDM_MCXA344 + select SOC_MCXA344 + select SOC_PART_NUMBER_MCXA344VLL diff --git a/boards/nxp/frdm_mcxa344/board.c b/boards/nxp/frdm_mcxa344/board.c new file mode 100644 index 0000000000000..aeef915ad35ad --- /dev/null +++ b/boards/nxp/frdm_mcxa344/board.c @@ -0,0 +1,148 @@ +/* + * Copyright 2025 NXP + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +/* Core clock frequency: 180MHz */ +#define CLOCK_INIT_CORE_CLOCK 180000000U +#define BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK 180000000U +/* System clock frequency. */ +extern uint32_t SystemCoreClock; + +void board_early_init_hook(void) +{ + uint32_t core_freq; + spc_active_mode_core_ldo_option_t ldo_option; + spc_sram_voltage_config_t sram_option; + + /* Get the CPU Core frequency */ + core_freq = CLOCK_GetCoreSysClkFreq(); + + /* The flow of increasing voltage and frequency */ + if (core_freq <= BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK) { + /* Set the LDO_CORE VDD regulator level */ + ldo_option.CoreLDOVoltage = kSPC_CoreLDO_OverDriveVoltage; + ldo_option.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength; + (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldo_option); + /* Configure Flash to support different voltage level and frequency */ + FMU0->FCTRL = + (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x4U)); + /* Specifies the operating voltage for the SRAM's read/write timing margin */ + sram_option.operateVoltage = kSPC_sramOperateAt1P2V; + sram_option.requestVoltageUpdate = true; + (void)SPC_SetSRAMOperateVoltage(SPC0, &sram_option); + } + + /*!< Set up system dividers */ + CLOCK_SetClockDiv(kCLOCK_DivAHBCLK, 1U); /* !< Set SYSCON.AHBCLKDIV divider to value 1 */ + CLOCK_SetClockDiv(kCLOCK_DivFRO_HF, 1U); /* !< Set SYSCON.FROHFDIV divider to value 1 */ + CLOCK_SetupFROHFClocking(BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK); /*!< Enable FRO HF */ + CLOCK_SetupFRO12MClocking(); /*!< Setup FRO12M clock */ + + CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /* !< Switch MAIN_CLK to kFRO_HF */ + + /* The flow of decreasing voltage and frequency */ + if (core_freq > BOARD_BOOTCLOCKFROHF180M_CORE_CLOCK) { + /* Configure Flash to support different voltage level and frequency */ + FMU0->FCTRL = + (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x4U)); + /* Specifies the operating voltage for the SRAM's read/write timing margin */ + sram_option.operateVoltage = kSPC_sramOperateAt1P2V; + sram_option.requestVoltageUpdate = true; + (void)SPC_SetSRAMOperateVoltage(SPC0, &sram_option); + /* Set the LDO_CORE VDD regulator level */ + ldo_option.CoreLDOVoltage = kSPC_CoreLDO_OverDriveVoltage; + ldo_option.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength; + (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldo_option); + } + + /*!< Set up clock selectors - Attach clocks to the peripheries */ + CLOCK_AttachClk(kCPU_CLK_to_TRACE); /* !< Switch TRACE to CPU_CLK */ + + /*!< Set up dividers */ + CLOCK_SetClockDiv(kCLOCK_DivFRO_LF, 1U); /* !< Set SYSCON.FROLFDIV divider to value 1 */ + CLOCK_SetClockDiv(kCLOCK_DivTRACE, 2U); /* !< Set MRCC.TRACE_CLKDIV divider to value 2 */ + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(porta)) + RESET_ReleasePeripheralReset(kPORT0_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GatePORT0); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(portb)) + RESET_ReleasePeripheralReset(kPORT1_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GatePORT1); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(portc)) + RESET_ReleasePeripheralReset(kPORT2_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GatePORT2); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(portd)) + RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GatePORT3); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(porte)) + RESET_ReleasePeripheralReset(kPORT4_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GatePORT4); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio0)) + RESET_ReleasePeripheralReset(kGPIO0_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GateGPIO0); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1)) + RESET_ReleasePeripheralReset(kGPIO1_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GateGPIO1); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio2)) + RESET_ReleasePeripheralReset(kGPIO2_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GateGPIO2); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio3)) + RESET_ReleasePeripheralReset(kGPIO3_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GateGPIO3); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio4)) + RESET_ReleasePeripheralReset(kGPIO4_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_GateGPIO4); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart0)) + CLOCK_SetClockDiv(kCLOCK_DivLPUART0, 1u); + CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART0); + RESET_ReleasePeripheralReset(kLPUART0_RST_SHIFT_RSTn); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart1)) + CLOCK_SetClockDiv(kCLOCK_DivLPUART1, 1u); + CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART1); + RESET_ReleasePeripheralReset(kLPUART1_RST_SHIFT_RSTn); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart2)) + CLOCK_SetClockDiv(kCLOCK_DivLPUART2, 1u); + CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART2); + RESET_ReleasePeripheralReset(kLPUART2_RST_SHIFT_RSTn); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart3)) + CLOCK_SetClockDiv(kCLOCK_DivLPUART3, 1u); + CLOCK_AttachClk(kFRO_LF_DIV_to_LPUART3); + RESET_ReleasePeripheralReset(kLPUART3_RST_SHIFT_RSTn); +#endif + + /* Set SystemCoreClock variable. */ + SystemCoreClock = CLOCK_INIT_CORE_CLOCK; +} diff --git a/boards/nxp/frdm_mcxa344/board.cmake b/boards/nxp/frdm_mcxa344/board.cmake new file mode 100644 index 0000000000000..d111b15af049a --- /dev/null +++ b/boards/nxp/frdm_mcxa344/board.cmake @@ -0,0 +1,13 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_runner_args(jlink "--device=MCXA344") +board_runner_args(linkserver "--device=MCXA344:FRDM-MCXA344") +board_runner_args(pyocd "--target=MCXA344") + +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/nxp/frdm_mcxa344/board.yml b/boards/nxp/frdm_mcxa344/board.yml new file mode 100644 index 0000000000000..20a587665eacc --- /dev/null +++ b/boards/nxp/frdm_mcxa344/board.yml @@ -0,0 +1,6 @@ +board: + name: frdm_mcxa344 + full_name: FRDM-MCXA344 + vendor: nxp + socs: + - name: mcxa344 diff --git a/boards/nxp/frdm_mcxa344/doc/frdm_mcxa344.webp b/boards/nxp/frdm_mcxa344/doc/frdm_mcxa344.webp new file mode 100644 index 0000000000000000000000000000000000000000..7412adb76ac8a515ccff4bd6b236513f80591ddf GIT binary patch literal 63790 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 zsymPHcky~5fX&=aihkuEN;p5_9RzRl3*pcJ000000000000000000000000000000 L0000000000r`BId literal 0 HcmV?d00001 diff --git a/boards/nxp/frdm_mcxa344/doc/index.rst b/boards/nxp/frdm_mcxa344/doc/index.rst new file mode 100644 index 0000000000000..729c69c8a80e8 --- /dev/null +++ b/boards/nxp/frdm_mcxa344/doc/index.rst @@ -0,0 +1,160 @@ +.. zephyr:board:: frdm_mcxa344 + +Overview +******** + +FRDM-MCXA344 is a compact and scalable development board for rapid prototyping of MCX A344 +MCUs. They offer industry standard headers for easy access to the MCUs input/output (I/O), +integrated open-standard serial interfaces, external flash memory and an onboard MCU-Link +debugger. + +Hardware +******** + +- MCX-A344 Arm Cortex-M33 microcontroller running at 180 MHz +- 256KB dual-bank on chip Flash +- 64 KB RAM +- 1x FlexCAN with FD, 1x RGB LED, 3x SW buttons +- On-board MCU-Link debugger with CMSIS-DAP +- Arduino Header, SmartDMA/Camera Header, mikroBUS + +For more information about the MCX-A344 SoC and FRDM-MCXA344 board, see: + +- `MCX-A344 SoC Website`_ +- `FRDM-MCXA344 Website`_ +- `FRDM-MCXA344 User Guide`_ + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Connections and IOs +=================== + +The MCX-A344 SoC has 5 gpio controllers and has pinmux registers which +can be used to configure the functionality of a pin. + ++------------+-----------------+----------------------------+ +| Name | Function | Usage | ++============+=================+============================+ +| PIO2_3 | UART | UART RX | ++------------+-----------------+----------------------------+ +| PIO2_2 | UART | UART TX | ++------------+-----------------+----------------------------+ + +System Clock +============ + +The MCX-A344 SoC is configured to use FRO running at 180MHz as a source for +the system clock. + +Serial Port +=========== + +The FRDM-MCXA344 SoC has 4 LPUART interfaces for serial communication. +LPUART 2 is configured as UART for the console. + +Programming and Debugging +************************* + +.. zephyr:board-supported-runners:: + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Configuring a Debug Probe +========================= + +A debug probe is used for both flashing and debugging the board. This board is +configured by default to use the MCU-Link CMSIS-DAP Onboard Debug Probe. + +Using LinkServer +---------------- + +Linkserver is the default runner for this board, and supports the factory +default MCU-Link firmware. Follow the instructions in +:ref:`mcu-link-cmsis-onboard-debug-probe` to reprogram the default MCU-Link +firmware. This only needs to be done if the default onboard debug circuit +firmware was changed. To put the board in ``ISP mode`` to program the firmware, +short jumper JP4. + +Using J-Link +------------ + +There are two options. The onboard debug circuit can be updated with Segger +J-Link firmware by following the instructions in +:ref:`mcu-link-jlink-onboard-debug-probe`. +To be able to program the firmware, you need to put the board in ``ISP mode`` +by shortening the jumper JP4. +The second option is to attach a :ref:`jlink-external-debug-probe` to the +10-pin SWD connector (J11) of the board. Additionally, the jumper JP6 must +be shorted. +For both options use the ``-r jlink`` option with west to use the jlink runner. + +.. code-block:: console + + west flash -r jlink + +Configuring a Console +===================== + +Connect a USB cable from your PC to J13, and use the serial terminal of your choice +(minicom, putty, etc.) with the following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flashing +======== + +Here is an example for the :zephyr:code-sample:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_mcxa344 + :goals: flash + +Open a serial terminal, reset the board (press the RESET button), and you should +see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.6.0-4478-ge6c3a42f5f52 *** + Hello World! frdm_mcxa344/mcxa344 + +Debugging +========= + +Here is an example for the :zephyr:code-sample:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_mcxa344/mcxa344 + :goals: debug + +Open a serial terminal, step through the application in your debugger, and you +should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.6.0-4478-ge6c3a42f5f52 *** + Hello World! frdm_mcxa344/mcxa344 + +Troubleshooting +=============== + +.. include:: ../../common/segger-ecc-systemview.rst.inc + +.. include:: ../../common/board-footer.rst.inc + +.. _MCX-A344 SoC Website: + https://www.nxp.com/products/MCX-A34X + +.. _FRDM-MCXA344 Website: + https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-MCXA344 + +.. _FRDM-MCXA344 User Guide: + https://www.nxp.com/document/guide/getting-started-with-frdm-mcxa344:GS-FRDM-MCXA344 diff --git a/boards/nxp/frdm_mcxa344/frdm_mcxa344-pinctrl.dtsi b/boards/nxp/frdm_mcxa344/frdm_mcxa344-pinctrl.dtsi new file mode 100644 index 0000000000000..0179bb4093d2e --- /dev/null +++ b/boards/nxp/frdm_mcxa344/frdm_mcxa344-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright 2025 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include + +&pinctrl { + pinmux_lpuart2: pinmux_lpuart2 { + group0 { + pinmux = , + ; + drive-strength = "low"; + slew-rate = "fast"; + input-enable; + }; + }; +}; diff --git a/boards/nxp/frdm_mcxa344/frdm_mcxa344.dts b/boards/nxp/frdm_mcxa344/frdm_mcxa344.dts new file mode 100644 index 0000000000000..8028d7df658b9 --- /dev/null +++ b/boards/nxp/frdm_mcxa344/frdm_mcxa344.dts @@ -0,0 +1,162 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "frdm_mcxa344-pinctrl.dtsi" +#include +#include + +/ { + model = "NXP FRDM_MCXA344 board"; + compatible = "nxp,mcxa344", "nxp,mcx"; + + aliases{ + led0 = &red_led; + led1 = &green_led; + led2 = &blue_led; + sw0 = &user_button_2; + sw1 = &user_button_3; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash; + zephyr,flash-controller = &fmu; + zephyr,code-partition = &slot0_partition; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + }; + + leds { + compatible = "gpio-leds"; + + red_led: led_0 { + gpios = <&gpio3 18 GPIO_ACTIVE_LOW>; + label = "Red LED"; + }; + + green_led: led_1 { + gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; + label = "Green LED"; + }; + + blue_led: led_2 { + gpios = <&gpio3 21 GPIO_ACTIVE_LOW>; + label = "Blue LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button_2: button_2 { + label = "User SW2"; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + + user_button_3: button_3 { + label = "User SW3"; + gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + arduino_header: arduino-connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; + +&cpu0 { + clock-frequency = <180000000>; +}; + +&edma0 { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; + +&gpio4 { + status = "okay"; +}; + +&lpuart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart2>; + pinctrl-names = "default"; +}; + +&flash { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(16)>; + read-only; + }; + + slot0_partition: partition@4000 { + label = "image-0"; + reg = <0x00004000 DT_SIZE_K(100)>; + }; + + slot1_partition: partition@1D000 { + label = "image-1"; + reg = <0x0001D000 DT_SIZE_K(100)>; + }; + + storage_partition: partition@36000 { + label = "storage"; + reg = <0x00036000 DT_SIZE_K(28)>; + }; + }; +}; diff --git a/boards/nxp/frdm_mcxa344/frdm_mcxa344.yaml b/boards/nxp/frdm_mcxa344/frdm_mcxa344.yaml new file mode 100644 index 0000000000000..5adc5c835cb40 --- /dev/null +++ b/boards/nxp/frdm_mcxa344/frdm_mcxa344.yaml @@ -0,0 +1,21 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: frdm_mcxa344 +name: NXP FRDM MCXA344 +type: mcu +arch: arm +ram: 48 +flash: 244 +toolchain: + - zephyr + - gnuarmemb +supported: + - arduino_gpio + - flash + - gpio + - uart +vendor: nxp diff --git a/boards/nxp/frdm_mcxa344/frdm_mcxa344_defconfig b/boards/nxp/frdm_mcxa344/frdm_mcxa344_defconfig new file mode 100644 index 0000000000000..e006f6525038c --- /dev/null +++ b/boards/nxp/frdm_mcxa344/frdm_mcxa344_defconfig @@ -0,0 +1,12 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_GPIO=y +CONFIG_LPADC_DO_OFFSET_CALIBRATION=y From d7e342840bf2d10714b341833ec78468eede93e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Laigle?= Date: Fri, 23 May 2025 15:30:32 +0000 Subject: [PATCH 131/397] drivers: sensor: add support for OMRON 2SMPB_02E pressure sensor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for the OMRON 2SMPB_02E digital barometric pressure sensor. Signed-off-by: Clément Laigle --- drivers/sensor/omron/2smpb_02e/2smpb_02e.c | 233 ++++++++++++++++++ drivers/sensor/omron/2smpb_02e/CMakeLists.txt | 6 + drivers/sensor/omron/2smpb_02e/Kconfig | 10 + drivers/sensor/omron/CMakeLists.txt | 1 + drivers/sensor/omron/Kconfig | 1 + dts/bindings/sensor/omron,2smpb-02e.yaml | 9 + 6 files changed, 260 insertions(+) create mode 100644 drivers/sensor/omron/2smpb_02e/2smpb_02e.c create mode 100644 drivers/sensor/omron/2smpb_02e/CMakeLists.txt create mode 100644 drivers/sensor/omron/2smpb_02e/Kconfig create mode 100644 dts/bindings/sensor/omron,2smpb-02e.yaml diff --git a/drivers/sensor/omron/2smpb_02e/2smpb_02e.c b/drivers/sensor/omron/2smpb_02e/2smpb_02e.c new file mode 100644 index 0000000000000..6bcebd822810e --- /dev/null +++ b/drivers/sensor/omron/2smpb_02e/2smpb_02e.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2025 CATIE + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT omron_2smpb_02e + +#include +#include +#include + +LOG_MODULE_REGISTER(O2SMPB_02E, CONFIG_SENSOR_LOG_LEVEL); + +/* + * Calibration coefficients for the Omron 2SMPB-02E sensor. + * + * These coefficients are used in the sensor's compensation algorithm to + * convert raw temperature and pressure readings into calibrated values. + * The values are derived from the sensor's datasheet. + * + * Reference: Omron 2SMPB-02E Application Note / Datasheet. + */ +#define COEFFICIENT_A1_A -6.3E-03 +#define COEFFICIENT_A1_S 4.3E-04 +#define COEFFICIENT_A2_A -1.9E-11 +#define COEFFICIENT_A2_S 1.2E-10 +#define COEFFICIENT_BT1_A 1.0E-01 +#define COEFFICIENT_BT1_S 9.1E-02 +#define COEFFICIENT_BT2_A 1.2E-08 +#define COEFFICIENT_BT2_S 1.2E-06 +#define COEFFICIENT_BP1_A 3.3E-02 +#define COEFFICIENT_BP1_S 1.9E-02 +#define COEFFICIENT_B11_A 2.1E-07 +#define COEFFICIENT_B11_S 1.4E-07 +#define COEFFICIENT_BP2_A -6.3E-10 +#define COEFFICIENT_BP2_S 3.5E-10 +#define COEFFICIENT_B12_A 2.9E-13 +#define COEFFICIENT_B12_S 7.6E-13 +#define COEFFICIENT_B21_A 2.1E-15 +#define COEFFICIENT_B21_S 1.2E-14 +#define COEFFICIENT_BP3_A 1.3E-16 +#define COEFFICIENT_BP3_S 7.9E-17 + +#define U20TOS32(x) (-(x & 0x00080000) + (x & 0xFFF7FFFF)) +#define U16TOS16(x) (-(x & 0x8000) | (x & 0x7FFF)) + +#define O2SMPB_02_REG_TEMP_TXD0 0xFC +#define O2SMPB_02_REG_TEMP_TXD1 0xFB +#define O2SMPB_02_REG_TEMP_TXD2 0xFA +#define O2SMPB_02_REG_PRESS_TXD0 0xF9 +#define O2SMPB_02_REG_PRESS_TXD1 0xF8 +#define O2SMPB_02_REG_PRESS_TXD2 0xF7 +#define O2SMPB_02_REG_RESET 0xE0 +#define O2SMPB_02_REG_CTRL_MEAS 0xF4 +#define O2SMPB_02_REG_CHIP_ID 0xD1 +#define O2SMPB_02_REG_COE_b00_1 0xA0 + +#define CALC_COEFF(A, S, OTP) ((A) + ((S) * (OTP) / 32767.0)) + +struct o2smpb_02e_config { + struct i2c_dt_spec i2c; +}; + +struct o2smpb_02e_data { + int32_t b00; + int32_t a0; + float bt1; + float bp1; + float bt2; + float b11; + float bp2; + float b12; + float b21; + float bp3; + float a1; + float a2; + int32_t dt; + int32_t dp; +}; + +static int o2smpb_02e_read_coefficients(const struct device *dev) +{ + struct o2smpb_02e_data *data = dev->data; + const struct o2smpb_02e_config *config = dev->config; + uint8_t buffer[25]; + + if (i2c_burst_read_dt(&config->i2c, O2SMPB_02_REG_COE_b00_1, buffer, sizeof(buffer)) < 0) { + LOG_ERR("Failed to read coefficients"); + return -EIO; + } + + /* K = OTP / 16 */ + data->a0 = + (int32_t)U20TOS32((buffer[18] << 12 | buffer[19] << 4 | (buffer[24] & 0x0F))) >> 4; + data->b00 = + (int32_t)U20TOS32((buffer[0] << 12 | buffer[1] << 4 | (buffer[24] & 0xF0) >> 4)) >> + 4; + + /* K = A + (S * OTP) / 32767 */ + int16_t bt1 = U16TOS16((buffer[2] << 8 | buffer[3])); + int16_t bp1 = U16TOS16((buffer[6] << 8 | buffer[7])); + int16_t bt2 = U16TOS16((buffer[4] << 8 | buffer[5])); + int16_t b11 = U16TOS16((buffer[8] << 8 | buffer[9])); + int16_t bp2 = U16TOS16((buffer[10] << 8 | buffer[11])); + int16_t b12 = U16TOS16((buffer[12] << 8 | buffer[13])); + int16_t b21 = U16TOS16((buffer[14] << 8 | buffer[15])); + int16_t bp3 = U16TOS16((buffer[16] << 8 | buffer[17])); + int16_t a1 = U16TOS16((buffer[20] << 8 | buffer[21])); + int16_t a2 = U16TOS16((buffer[22] << 8 | buffer[23])); + + data->bt1 = CALC_COEFF(COEFFICIENT_BT1_A, COEFFICIENT_BT1_S, bt1); + data->bp1 = CALC_COEFF(COEFFICIENT_BP1_A, COEFFICIENT_BP1_S, bp1); + data->bt2 = CALC_COEFF(COEFFICIENT_BT2_A, COEFFICIENT_BT2_S, bt2); + data->b11 = CALC_COEFF(COEFFICIENT_B11_A, COEFFICIENT_B11_S, b11); + data->bp2 = CALC_COEFF(COEFFICIENT_BP2_A, COEFFICIENT_BP2_S, bp2); + data->b12 = CALC_COEFF(COEFFICIENT_B12_A, COEFFICIENT_B12_S, b12); + data->b21 = CALC_COEFF(COEFFICIENT_B21_A, COEFFICIENT_B21_S, b21); + data->bp3 = CALC_COEFF(COEFFICIENT_BP3_A, COEFFICIENT_BP3_S, bp3); + data->a1 = CALC_COEFF(COEFFICIENT_A1_A, COEFFICIENT_A1_S, a1); + data->a2 = CALC_COEFF(COEFFICIENT_A2_A, COEFFICIENT_A2_S, a2); + + return 0; +} + +static int o2smpb_02e_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct o2smpb_02e_data *data = dev->data; + const struct o2smpb_02e_config *config = dev->config; + + uint8_t buffer[3]; + + /* Force mode */ + if (i2c_reg_write_byte_dt(&config->i2c, O2SMPB_02_REG_CTRL_MEAS, + (uint8_t)(0x101 << 5 | 0x101 << 2 | 0x1)) < 0) { + LOG_ERR("Could not set sensor to force mode"); + return -EIO; + } + + k_sleep(K_MSEC(500)); + + if (i2c_burst_read_dt(&config->i2c, O2SMPB_02_REG_TEMP_TXD2, buffer, sizeof(buffer)) < 0) { + LOG_ERR("Could not read sensor data"); + return -EIO; + } + + data->dt = (buffer[0] << 16 | buffer[1] << 8 | buffer[2]) - (0x1 << 23); + + if (i2c_burst_read_dt(&config->i2c, O2SMPB_02_REG_PRESS_TXD2, buffer, sizeof(buffer)) < 0) { + LOG_ERR("Could not read sensor data"); + return -EIO; + } + + data->dp = (buffer[0] << 16 | buffer[1] << 8 | buffer[2]) - (0x1 << 23); + + return 0; +} + +static int o2smpb_02e_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct o2smpb_02e_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_AMBIENT_TEMP: + float temp = + (data->a0) + ((data->a1) + (data->a2) * (float)data->dt) * (float)data->dt; + temp /= 256.0f; + + sensor_value_from_float(val, temp); + break; + case SENSOR_CHAN_PRESS: + float tr = + (data->a0) + ((data->a1) + (data->a2) * (float)data->dt) * (float)data->dt; + + float press = data->b00 + data->bt1 * tr + data->bp1 * (float)data->dp + + data->b11 * (float)data->dp * tr + data->bt2 * tr * tr + + data->bp2 * (float)data->dp * (float)data->dp + + data->b12 * (float)data->dp * tr * tr + + data->b21 * (float)data->dp * (float)data->dp * tr + + data->bp3 * (float)data->dp * (float)data->dp * (float)data->dp; + press /= 1000.0f; + + sensor_value_from_float(val, press); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int o2smpb_02e_init(const struct device *dev) +{ + const struct o2smpb_02e_config *config = dev->config; + uint8_t chip_id; + + /* Reset the sensor */ + i2c_reg_write_byte_dt(&config->i2c, O2SMPB_02_REG_RESET, 0xE6); + + k_sleep(K_MSEC(10)); + + /* Read CHIP ID register to make sure the device is present */ + i2c_reg_read_byte_dt(&config->i2c, O2SMPB_02_REG_CHIP_ID, &chip_id); + + if (chip_id != 0x5C) { + LOG_ERR("Invalid chip ID"); + return -EIO; + } + + if (o2smpb_02e_read_coefficients(dev) < 0) { + LOG_ERR("Failed to read calibration coefficients"); + return -EIO; + } + + return 0; +} + +static DEVICE_API(sensor, o2smpb_02e_api_funcs) = { + .sample_fetch = o2smpb_02e_sample_fetch, + .channel_get = o2smpb_02e_channel_get, +}; + +#define O2SMPB_02E_INIT(n) \ + static const struct o2smpb_02e_config o2smpb_02e_config_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + }; \ + static struct o2smpb_02e_data o2smpb_02e_data_##n; \ + SENSOR_DEVICE_DT_INST_DEFINE(n, o2smpb_02e_init, NULL, &o2smpb_02e_data_##n, \ + &o2smpb_02e_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &o2smpb_02e_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(O2SMPB_02E_INIT) diff --git a/drivers/sensor/omron/2smpb_02e/CMakeLists.txt b/drivers/sensor/omron/2smpb_02e/CMakeLists.txt new file mode 100644 index 0000000000000..5ed6172b676e3 --- /dev/null +++ b/drivers/sensor/omron/2smpb_02e/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2025 CATIE +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(2smpb_02e.c) diff --git a/drivers/sensor/omron/2smpb_02e/Kconfig b/drivers/sensor/omron/2smpb_02e/Kconfig new file mode 100644 index 0000000000000..7b07327b9a1e9 --- /dev/null +++ b/drivers/sensor/omron/2smpb_02e/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2025 CATIE +# SPDX-License-Identifier: Apache-2.0 + +config 2SMPB_02E + bool "OMRON 2SMPB_02E digital barometric pressure sensor" + default y + depends on DT_HAS_OMRON_2SMPB_02E_ENABLED + select I2C + help + Enable driver for OMRON O2SMPB_02E digital barometric pressure sensor. diff --git a/drivers/sensor/omron/CMakeLists.txt b/drivers/sensor/omron/CMakeLists.txt index 0237de521fa7f..c82213c7798f4 100644 --- a/drivers/sensor/omron/CMakeLists.txt +++ b/drivers/sensor/omron/CMakeLists.txt @@ -2,5 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 # zephyr-keep-sorted-start +add_subdirectory_ifdef(CONFIG_2SMPB_02E 2smpb_02e) add_subdirectory_ifdef(CONFIG_D6F d6f) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/omron/Kconfig b/drivers/sensor/omron/Kconfig index fce9097a74efe..d27f0a6b7fa68 100644 --- a/drivers/sensor/omron/Kconfig +++ b/drivers/sensor/omron/Kconfig @@ -2,5 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 # zephyr-keep-sorted-start +source "drivers/sensor/omron/2smpb_02e/Kconfig" source "drivers/sensor/omron/d6f/Kconfig" # zephyr-keep-sorted-stop diff --git a/dts/bindings/sensor/omron,2smpb-02e.yaml b/dts/bindings/sensor/omron,2smpb-02e.yaml new file mode 100644 index 0000000000000..5c02c9e8f881a --- /dev/null +++ b/dts/bindings/sensor/omron,2smpb-02e.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2025 CATIE +# SPDX-License-Identifier: Apache-2.0 + +description: | + Omron 2SMPB-02E digital barometric pressure sensor. + +compatible: "omron,2smpb-02e" + +include: [sensor-device.yaml, i2c-device.yaml] From bf4eb85964603b6b60dd67eb209fb8d7213f1ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Laigle?= Date: Mon, 13 Oct 2025 09:50:42 +0200 Subject: [PATCH 132/397] drivers: sensor: omron 2smpb_02e: add FPU selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Luis Ubieda Signed-off-by: Clément Laigle --- drivers/sensor/omron/2smpb_02e/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/sensor/omron/2smpb_02e/Kconfig b/drivers/sensor/omron/2smpb_02e/Kconfig index 7b07327b9a1e9..d3c49107b33fe 100644 --- a/drivers/sensor/omron/2smpb_02e/Kconfig +++ b/drivers/sensor/omron/2smpb_02e/Kconfig @@ -6,5 +6,6 @@ config 2SMPB_02E default y depends on DT_HAS_OMRON_2SMPB_02E_ENABLED select I2C + select FPU if CPU_HAS_FPU help Enable driver for OMRON O2SMPB_02E digital barometric pressure sensor. From fe3a5a49fbced334ba0e1f4ee9fb2973e99f6473 Mon Sep 17 00:00:00 2001 From: Eric Ocasio Date: Thu, 16 Oct 2025 15:18:27 -0500 Subject: [PATCH 133/397] pmci: mctp: samples: Add support for MCTP over USB. Adds support for the USB device binding for MCTP. Binding created based on the DMTF specification for USB Transport Binding. The overall design of this binding follows the existing UART and I2C+GPIO bindings that already exist in Zephyr. Signed-off-by: Eric Ocasio --- include/zephyr/pmci/mctp/mctp_usb.h | 90 ++++ include/zephyr/usb/usb_ch9.h | 1 + .../pmci/mctp/usb_endpoint/CMakeLists.txt | 9 + samples/subsys/pmci/mctp/usb_endpoint/Kconfig | 9 + .../subsys/pmci/mctp/usb_endpoint/README.rst | 56 +++ .../subsys/pmci/mctp/usb_endpoint/prj.conf | 10 + .../pmci/mctp/usb_endpoint/requirements.txt | 2 + .../subsys/pmci/mctp/usb_endpoint/src/main.c | 110 ++++ .../pmci/mctp/usb_endpoint/usb_host_tester.py | 99 ++++ subsys/pmci/mctp/CMakeLists.txt | 2 + subsys/pmci/mctp/Kconfig | 8 + subsys/pmci/mctp/Kconfig.usb | 18 + subsys/pmci/mctp/mctp_usb.c | 468 ++++++++++++++++++ subsys/pmci/mctp/mctp_usb.ld | 3 + 14 files changed, 885 insertions(+) create mode 100644 include/zephyr/pmci/mctp/mctp_usb.h create mode 100644 samples/subsys/pmci/mctp/usb_endpoint/CMakeLists.txt create mode 100644 samples/subsys/pmci/mctp/usb_endpoint/Kconfig create mode 100644 samples/subsys/pmci/mctp/usb_endpoint/README.rst create mode 100644 samples/subsys/pmci/mctp/usb_endpoint/prj.conf create mode 100644 samples/subsys/pmci/mctp/usb_endpoint/requirements.txt create mode 100644 samples/subsys/pmci/mctp/usb_endpoint/src/main.c create mode 100644 samples/subsys/pmci/mctp/usb_endpoint/usb_host_tester.py create mode 100644 subsys/pmci/mctp/Kconfig.usb create mode 100644 subsys/pmci/mctp/mctp_usb.c create mode 100644 subsys/pmci/mctp/mctp_usb.ld diff --git a/include/zephyr/pmci/mctp/mctp_usb.h b/include/zephyr/pmci/mctp/mctp_usb.h new file mode 100644 index 0000000000000..06771f6a60a0f --- /dev/null +++ b/include/zephyr/pmci/mctp/mctp_usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 Intel Corporation + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_MCTP_USB_H_ +#define ZEPHYR_MCTP_USB_H_ + +#include +#include + +/* MCTP class subclass options */ +#define USBD_MCTP_SUBCLASS_MANAGEMENT_CONTROLLER 0 +#define USBD_MCTP_SUBCLASS_MANAGED_DEVICE_ENDPOINT 0 +#define USBD_MCTP_SUBCLASS_HOST_INTERFACE_ENDPOINT 1 + +/* MCTP class protocol options */ +#define USBD_MCTP_PROTOCOL_1_X 1 +#define USBD_MCTP_PROTOCOL_2_X 2 + +/* Binding-specific defines, internal use */ +#define MCTP_USB_HEADER_SIZE 4 +#define MCTP_USB_MAX_PACKET_LENGTH 255 + +/** + * @brief An MCTP binding for Zephyr's USB device stack + */ +struct mctp_binding_usb { + /** @cond INTERNAL_HIDDEN */ + struct mctp_binding binding; + struct usbd_class_data *usb_class_data; + uint8_t tx_buf[MCTP_USB_HEADER_SIZE + MCTP_USB_MAX_PACKET_LENGTH]; + struct k_sem tx_lock; + struct mctp_pktbuf *rx_pkt; + uint8_t rx_data_idx; + enum { + STATE_WAIT_HDR_DMTF0, + STATE_WAIT_HDR_DMTF1, + STATE_WAIT_HDR_RSVD0, + STATE_WAIT_HDR_LEN, + STATE_DATA + } rx_state; + /** @endcond INTERNAL_HIDDEN */ +}; + +struct mctp_usb_class_inst { + uint8_t sublcass; + uint8_t mctp_protocol; + struct mctp_binding_usb *mctp_binding; +}; + +/** @cond INTERNAL_HIDDEN */ +int mctp_usb_start(struct mctp_binding *binding); +int mctp_usb_tx(struct mctp_binding *binding, struct mctp_pktbuf *pkt); +/** @endcond INTERNAL_HIDDEN */ + +/** + * @brief Define a MCTP bus binding for USB + * + * @param _name Symbolic name of the bus binding variable + * @param _subclass MCTP subclass used in the USB interfce descriptor + * @param _protocol MCTP protocol used in the USB interface descriptor + */ +#define MCTP_USB_DEFINE(_name, _subclass, _protocol) \ + struct mctp_binding_usb _name = { \ + .binding = { \ + .name = STRINGIFY(_name), \ + .version = 1, \ + .pkt_size = MCTP_PACKET_SIZE(MCTP_USB_MAX_PACKET_LENGTH), \ + .pkt_header = 0, \ + .pkt_trailer = 0, \ + .start = mctp_usb_start, \ + .tx = mctp_usb_tx \ + }, \ + .usb_class_data = NULL, \ + .rx_pkt = NULL, \ + .rx_data_idx = 0, \ + .rx_state = STATE_WAIT_HDR_DMTF0 \ + }; \ + \ + const STRUCT_SECTION_ITERABLE(mctp_usb_class_inst, mctp_usb_class_inst_##_name) = { \ + .sublcass = _subclass, \ + .mctp_protocol = _protocol, \ + .mctp_binding = &_name, \ + }; + +#endif /* ZEPHYR_MCTP_USB_H_ */ diff --git a/include/zephyr/usb/usb_ch9.h b/include/zephyr/usb/usb_ch9.h index 0c4a3ac06086a..67af0047cc11c 100644 --- a/include/zephyr/usb/usb_ch9.h +++ b/include/zephyr/usb/usb_ch9.h @@ -267,6 +267,7 @@ struct usb_association_descriptor { #define USB_BCC_MASS_STORAGE 0x08 #define USB_BCC_CDC_DATA 0x0A #define USB_BCC_VIDEO 0x0E +#define USB_BCC_MCTP 0x14 #define USB_BCC_WIRELESS_CONTROLLER 0xE0 #define USB_BCC_MISCELLANEOUS 0xEF #define USB_BCC_APPLICATION 0xFE diff --git a/samples/subsys/pmci/mctp/usb_endpoint/CMakeLists.txt b/samples/subsys/pmci/mctp/usb_endpoint/CMakeLists.txt new file mode 100644 index 0000000000000..efbc4cb50f8c6 --- /dev/null +++ b/samples/subsys/pmci/mctp/usb_endpoint/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(mctp_usb_endpoint) + +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/subsys/pmci/mctp/usb_endpoint/Kconfig b/samples/subsys/pmci/mctp/usb_endpoint/Kconfig new file mode 100644 index 0000000000000..96c5455894806 --- /dev/null +++ b/samples/subsys/pmci/mctp/usb_endpoint/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Source common USB sample options used to initialize new experimental USB +# device stack. The scope of these options is limited to USB samples in project +# tree, you cannot use them in your own application. +source "samples/subsys/usb/common/Kconfig.sample_usbd" + +source "Kconfig.zephyr" diff --git a/samples/subsys/pmci/mctp/usb_endpoint/README.rst b/samples/subsys/pmci/mctp/usb_endpoint/README.rst new file mode 100644 index 0000000000000..54569a87bd988 --- /dev/null +++ b/samples/subsys/pmci/mctp/usb_endpoint/README.rst @@ -0,0 +1,56 @@ +.. zephyr:code-sample:: mctp-usb-endpoint + :name: MCTP USB Endpoint Node Sample + :relevant-api: usbd_api + + Create an MCTP endpoint node using the USB device interface. + +Overview +******** +Sets up an MCTP endpoint node that listens for messages from the MCTP bus owner with EID 20. +Responds with "Hello, bus owner" message. + +Requirements +************ +A board and SoC that provide support for USB device capability (either FS or HS, though DMTF spec +specifies only HS). Testing requires a USB host that has the ability to enumerate the MCTP interface +and interact with the board using the MCTP protocol. An easy way to do this is a Python script. + +An example script to test this interface is provided with this sample application. To run the +script, you must first install pyusb. + +.. code-block:: console + + pip install requirements.txt + python usb_host_tester.py + +If the test is successful, you will see the following output from the script: + +.. code-block:: console + + Sending message with size smaller than USB FS MPS (<64b) + Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00' + Sending message spanning two USB FS packets (>64b) + Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00' + Sending message with two MCTP messages in a single USB FS packet + Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00' + Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00' + +Wiring +****** +Connect a USB cable between the host (likely a PC) and the board. The type of cable (mini, micro, +type C) depends on the host and board connectors. + +Building and Running +******************** + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/pmci/mctp/usb_endpoint + :host-os: unix + :board: frdm_mcxn947_mcxn947_cpu0 + :goals: run + :compact: + +References +********** + +`MCTP Base Specification 2019 `_ diff --git a/samples/subsys/pmci/mctp/usb_endpoint/prj.conf b/samples/subsys/pmci/mctp/usb_endpoint/prj.conf new file mode 100644 index 0000000000000..c76567f1412e6 --- /dev/null +++ b/samples/subsys/pmci/mctp/usb_endpoint/prj.conf @@ -0,0 +1,10 @@ +CONFIG_USB_DEVICE_STACK_NEXT=y + +CONFIG_MCTP=y +CONFIG_MCTP_USB=y + +CONFIG_LOG=y +CONFIG_MCTP_LOG_LEVEL_ERR=y +CONFIG_UDC_DRIVER_LOG_LEVEL_ERR=y +CONFIG_USBD_LOG_LEVEL_ERR=y +CONFIG_UDC_DRIVER_LOG_LEVEL_ERR=y diff --git a/samples/subsys/pmci/mctp/usb_endpoint/requirements.txt b/samples/subsys/pmci/mctp/usb_endpoint/requirements.txt new file mode 100644 index 0000000000000..feec2b980afdb --- /dev/null +++ b/samples/subsys/pmci/mctp/usb_endpoint/requirements.txt @@ -0,0 +1,2 @@ +# Needed to run USB host test script. +pyusb diff --git a/samples/subsys/pmci/mctp/usb_endpoint/src/main.c b/samples/subsys/pmci/mctp/usb_endpoint/src/main.c new file mode 100644 index 0000000000000..178fbce47ffdb --- /dev/null +++ b/samples/subsys/pmci/mctp/usb_endpoint/src/main.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024 Intel Corporation + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mctp_endpoint); + +#define SELF_ID 10 +#define BUS_OWNER_ID 20 + +K_SEM_DEFINE(mctp_rx, 0, 1); +MCTP_USB_DEFINE(mctp0, USBD_MCTP_SUBCLASS_MANAGED_DEVICE_ENDPOINT, USBD_MCTP_PROTOCOL_1_X); + +static struct mctp *mctp_ctx; +static bool usb_configured; + +static void sample_msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg) +{ + LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); + + if (msg->type == USBD_MSG_CONFIGURATION) { + usb_configured = true; + } +} + +static int enable_usb_device_next(void) +{ + static struct usbd_context *mctp_poc_usbd; + int err; + + mctp_poc_usbd = sample_usbd_init_device(sample_msg_cb); + if (mctp_poc_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; + } + + if (!usbd_can_detect_vbus(mctp_poc_usbd)) { + err = usbd_enable(mctp_poc_usbd); + if (err) { + LOG_ERR("Failed to enable device support"); + return err; + } + } + + LOG_INF("USB device support enabled"); + + return 0; +} + +static void rx_message(uint8_t eid, bool tag_owner, uint8_t msg_tag, void *data, void *msg, + size_t len) +{ + switch (eid) { + case BUS_OWNER_ID: { + LOG_INF("Received MCTP message \"%s\" from EID %d", (char *)msg, eid); + k_sem_give(&mctp_rx); + break; + } + default: { + LOG_INF("Unknown endpoint %d", eid); + break; + } + } +} + +int main(void) +{ + LOG_INF("MCTP Endpoint EID: %d on %s", SELF_ID, CONFIG_BOARD_TARGET); + + int ret = enable_usb_device_next(); + + if (ret != 0) { + LOG_ERR("Failed to enable USB device support"); + return 0; + } + + while (!usb_configured) { + k_msleep(5); + } + + mctp_set_alloc_ops(malloc, free, realloc); + mctp_ctx = mctp_init(); + __ASSERT_NO_MSG(mctp_ctx != NULL); + + mctp_register_bus(mctp_ctx, &mctp0.binding, SELF_ID); + mctp_set_rx_all(mctp_ctx, rx_message, NULL); + + while (1) { + k_sem_take(&mctp_rx, K_FOREVER); + mctp_message_tx(mctp_ctx, BUS_OWNER_ID, false, 0, "Hello, bus owner", + sizeof("Hello, bus owner")); + } + + return 0; +} diff --git a/samples/subsys/pmci/mctp/usb_endpoint/usb_host_tester.py b/samples/subsys/pmci/mctp/usb_endpoint/usb_host_tester.py new file mode 100644 index 0000000000000..6931002f9e7a0 --- /dev/null +++ b/samples/subsys/pmci/mctp/usb_endpoint/usb_host_tester.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +import usb.core +import usb.util + + +class USBDevice: + def __init__(self, vid, pid): + self.vid = vid + self.pid = pid + self.device = None + self.endpoint_in = None + self.endpoint_out = None + self.interface = None + + def connect(self): + # Find the device + self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid) + if self.device is None: + raise ValueError( + "Device not found. Make sure the board running the MCTP USB endpoint \ + sample is connected." + ) + + # Set the active configuration + self.device.set_configuration() + cfg = self.device.get_active_configuration() + self.interface = cfg[(0, 0)] + + # Claim the interface + usb.util.claim_interface(self.device, self.interface.bInterfaceNumber) + + # Find bulk IN and OUT endpoints + for ep in self.interface: + if usb.util.endpoint_direction(ep.bEndpointAddress) == usb.util.ENDPOINT_IN: + self.endpoint_in = ep + elif usb.util.endpoint_direction(ep.bEndpointAddress) == usb.util.ENDPOINT_OUT: + self.endpoint_out = ep + + if not self.endpoint_in or not self.endpoint_out: + raise ValueError("Bulk IN/OUT endpoints not found") + + # Print descriptor information (for debug purposes) + for cfg in self.device: + print(cfg) + + def send_data(self, data): + if not self.endpoint_out: + raise RuntimeError("OUT endpoint not initialized") + self.endpoint_out.write(data) + + def receive_data(self, size=64, timeout=1000): + if not self.endpoint_in: + raise RuntimeError("IN endpoint not initialized") + return self.endpoint_in.read(size, timeout) + + def disconnect(self): + usb.util.release_interface(self.device, self.interface.bInterfaceNumber) + usb.util.dispose_resources(self.device) + + +if __name__ == "__main__": + usb_dev = USBDevice(0x2FE3, 0x0001) + try: + usb_dev.connect() + + print("Sending message with size smaller than USB FS MPS (<64b)") + usb_dev.send_data( + b'\x1a\xb4\x00\x0f\x01\x0a\x14\xc0\x48\x65\x6c\x6c\x6f\x2c\x20\x4d\x43\x58\x00' + ) + response = usb_dev.receive_data() + print("Received:", bytes(response)) + + print("Sending message spanning two USB FS packets (>64b)") + usb_dev.send_data( + b'\x1a\xb4\x00\x4c\x01\x0a\x14\xc0\x48\x65\x6c\x6c\x6f\x2c\x20\x4d\x43\x58\x2e\x20' + b'\x4c\x65\x74\x27\x73\x20\x74\x65\x73\x74\x20\x61\x20\x6d\x75\x6c\x74\x69\x2d\x70' + b'\x61\x63\x6b\x65\x74\x20\x6d\x65\x73\x73\x61\x67\x65\x20\x74\x6f\x20\x73\x65\x65' + b'\x20\x68\x6f\x77\x20\x79\x6f\x75\x20\x68\x61\x6e\x64\x6c\x65\x20\x69\x74\x2e\x00' + ) + response = usb_dev.receive_data() + print("Received:", bytes(response)) + + print("Sending message with two MCTP messages in a single USB FS packet") + usb_dev.send_data( + b'\x1a\xb4\x00\x12\x01\x0a\x14\xc0\x48\x65\x6c\x6c\x6f\x2c\x20\x4d\x43\x58\x2c\x20' + b'\x31\x00\x1a\xb4\x00\x12\x01\x0a\x14\xc0\x48\x65\x6c\x6c\x6f\x2c\x20\x4d\x43\x58' + b'\x2c\x20\x32\x00' + ) + response = usb_dev.receive_data() + print("Received:", bytes(response)) + response = usb_dev.receive_data() + print("Received:", bytes(response)) + + finally: + usb_dev.disconnect() diff --git a/subsys/pmci/mctp/CMakeLists.txt b/subsys/pmci/mctp/CMakeLists.txt index aa32c208f00c9..43e77180e80e3 100644 --- a/subsys/pmci/mctp/CMakeLists.txt +++ b/subsys/pmci/mctp/CMakeLists.txt @@ -3,3 +3,5 @@ zephyr_library_sources(mctp_memory.c) zephyr_library_sources_ifdef(CONFIG_MCTP_UART mctp_uart.c) zephyr_library_sources_ifdef(CONFIG_MCTP_I2C_GPIO_CONTROLLER mctp_i2c_gpio_controller.c) zephyr_library_sources_ifdef(CONFIG_MCTP_I2C_GPIO_TARGET mctp_i2c_gpio_target.c) +zephyr_library_sources_ifdef(CONFIG_MCTP_USB mctp_usb.c) +zephyr_linker_sources_ifdef(CONFIG_MCTP_USB SECTIONS mctp_usb.ld) diff --git a/subsys/pmci/mctp/Kconfig b/subsys/pmci/mctp/Kconfig index 1d70ccc7b240d..1f5c8c21572f0 100644 --- a/subsys/pmci/mctp/Kconfig +++ b/subsys/pmci/mctp/Kconfig @@ -1,4 +1,5 @@ # Copyright (c) 2024 Intel Corporation +# Copyright 2025 NXP # SPDX-License-Identifier: Apache-2.0 menuconfig MCTP @@ -42,9 +43,16 @@ config MCTP_I2C_GPIO_TARGET Build the MCTP I2C+GPIO target binding to use MCTP over Zephyr's I2C target interface and GPIO to signal writes to the bus controller. +config MCTP_USB + bool "MCTP USB Binding" + depends on USB_DEVICE_STACK_NEXT + help + Build the MCTP USB binding to use MCTP over Zephyr's USB device interface. module = MCTP module-str = MCTP source "subsys/logging/Kconfig.template.log_config" +rsource "Kconfig.usb" + endif diff --git a/subsys/pmci/mctp/Kconfig.usb b/subsys/pmci/mctp/Kconfig.usb new file mode 100644 index 0000000000000..00eb16cdfa4a2 --- /dev/null +++ b/subsys/pmci/mctp/Kconfig.usb @@ -0,0 +1,18 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if MCTP_USB + +config MCTP_USB_TX_TIMEOUT + int "MCTP USB transmit timeout (ms)" + default 1000 + help + Set the MCTP USB transmit timeout, in milliseconds. + +module = MCTP_USB_CLASS +module-str = mctp usb class +default-count = 1 + +source "subsys/usb/device_next/class/Kconfig.template.instances_count" + +endif diff --git a/subsys/pmci/mctp/mctp_usb.c b/subsys/pmci/mctp/mctp_usb.c new file mode 100644 index 0000000000000..ef2a4a4c5c4df --- /dev/null +++ b/subsys/pmci/mctp/mctp_usb.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2024 Intel Corporation + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mctp_usb, CONFIG_MCTP_LOG_LEVEL); + +#include "libmctp-alloc.h" + +#define MCTP_USB_DMTF_0 0x1A +#define MCTP_USB_DMTF_1 0xB4 + +#define MCTP_USB_ENABLED 0 +#define MCTP_USB_NUM_INSTANCES CONFIG_MCTP_USB_CLASS_INSTANCES_COUNT + +UDC_BUF_POOL_DEFINE(mctp_usb_ep_pool, MCTP_USB_NUM_INSTANCES * 2, USBD_MAX_BULK_MPS, + sizeof(struct udc_buf_info), NULL); + +struct mctp_usb_class_desc { + struct usb_if_descriptor if0; + struct usb_ep_descriptor if0_fs_out_ep; + struct usb_ep_descriptor if0_fs_in_ep; + struct usb_ep_descriptor if0_hs_out_ep; + struct usb_ep_descriptor if0_hs_in_ep; + struct usb_desc_header nil_desc; +}; + +struct mctp_usb_class_ctx { + struct usbd_class_data *class_data; + struct mctp_usb_class_desc *const desc; + const struct usb_desc_header **const fs_desc; + const struct usb_desc_header **const hs_desc; + struct mctp_usb_class_inst *inst; + uint8_t inst_idx; + struct net_buf *out_net_buf; + uint8_t out_buf[USBD_MAX_BULK_MPS]; + struct k_work out_work; + atomic_t state; +}; + +static struct net_buf *mctp_usb_class_buf_alloc(const uint8_t ep) +{ + struct net_buf *buf = NULL; + struct udc_buf_info *bi; + + buf = net_buf_alloc(&mctp_usb_ep_pool, K_NO_WAIT); + if (!buf) { + return NULL; + } + + bi = udc_get_buf_info(buf); + bi->ep = ep; + + return buf; +} + +static uint8_t mctp_usb_class_get_bulk_in(struct usbd_class_data *const c_data) +{ + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + +#if USBD_SUPPORTS_HIGH_SPEED + if (usbd_bus_speed(usbd_class_get_ctx(ctx->class_data)) == USBD_SPEED_HS) { + return ctx->desc->if0_hs_in_ep.bEndpointAddress; + } +#endif + + return ctx->desc->if0_fs_in_ep.bEndpointAddress; +} + +static uint8_t mctp_usb_class_get_bulk_out(struct usbd_class_data *const c_data) +{ + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + +#if USBD_SUPPORTS_HIGH_SPEED + if (usbd_bus_speed(usbd_class_get_ctx(ctx->class_data)) == USBD_SPEED_HS) { + return ctx->desc->if0_hs_out_ep.bEndpointAddress; + } +#endif + + return ctx->desc->if0_fs_out_ep.bEndpointAddress; +} + +static void mctp_usb_reset_rx_state(struct mctp_binding_usb *usb) +{ + if (usb->rx_pkt != NULL) { + mctp_pktbuf_free(usb->rx_pkt); + } + + usb->rx_data_idx = 0; + usb->rx_state = STATE_WAIT_HDR_DMTF0; +} + +int mctp_usb_tx(struct mctp_binding *binding, struct mctp_pktbuf *pkt) +{ + struct mctp_binding_usb *usb = CONTAINER_OF(binding, struct mctp_binding_usb, binding); + struct usbd_class_data *c_data = usb->usb_class_data; + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + size_t len = mctp_pktbuf_size(pkt); + struct net_buf *buf = NULL; + int err; + + if (!atomic_test_bit(&ctx->state, MCTP_USB_ENABLED)) { + return -EPERM; + } + + if (len > MCTP_USB_MAX_PACKET_LENGTH) { + return -E2BIG; + } + + err = k_sem_take(&usb->tx_lock, K_MSEC(CONFIG_MCTP_USB_TX_TIMEOUT)); + if (err != 0) { + LOG_ERR("Semaphore could not be obtained"); + return err; + } + + usb->tx_buf[0] = MCTP_USB_DMTF_0; + usb->tx_buf[1] = MCTP_USB_DMTF_1; + usb->tx_buf[2] = 0; + usb->tx_buf[3] = len; + + memcpy((void *)&usb->tx_buf[MCTP_USB_HEADER_SIZE], pkt->data, len); + + LOG_HEXDUMP_DBG(usb->tx_buf, len + MCTP_USB_HEADER_SIZE, "buf = "); + + if (usb->usb_class_data == NULL) { + LOG_ERR("MCTP instance not found"); + return -ENODEV; + } + + buf = mctp_usb_class_buf_alloc(mctp_usb_class_get_bulk_in(c_data)); + if (buf == NULL) { + k_sem_give(&usb->tx_lock); + LOG_ERR("Failed to allocate IN buffer"); + return -ENOMEM; + } + + net_buf_add_mem(buf, usb->tx_buf, len + MCTP_USB_HEADER_SIZE); + + err = usbd_ep_enqueue(c_data, buf); + if (err) { + k_sem_give(&usb->tx_lock); + LOG_ERR("Failed to enqueue IN buffer"); + net_buf_unref(buf); + return err; + } + + return 0; +} + +int mctp_usb_start(struct mctp_binding *binding) +{ + struct mctp_binding_usb *usb = CONTAINER_OF(binding, struct mctp_binding_usb, binding); + + k_sem_init(&usb->tx_lock, 1, 1); + mctp_binding_set_tx_enabled(binding, true); + + return 0; +} + +static void mctp_usb_class_out_work(struct k_work *work) +{ + struct mctp_usb_class_ctx *ctx = CONTAINER_OF(work, struct mctp_usb_class_ctx, out_work); + struct net_buf *buf; + size_t buf_size = 0; + + if (!atomic_test_bit(&ctx->state, MCTP_USB_ENABLED)) { + return; + } + + /* Move data from net_buf to our ctx buffer so we can receive another USB packet */ + if (ctx->out_net_buf != NULL) { + buf_size = ctx->out_net_buf->len; + memcpy(ctx->out_buf, ctx->out_net_buf->data, ctx->out_net_buf->len); + + /* Free the current buffer and allocate another for OUT */ + net_buf_unref(ctx->out_net_buf); + } + + buf = mctp_usb_class_buf_alloc(mctp_usb_class_get_bulk_out(ctx->class_data)); + if (buf == NULL) { + LOG_ERR("Failed to allocate OUT buffer"); + return; + } + + if (usbd_ep_enqueue(ctx->class_data, buf)) { + net_buf_unref(buf); + LOG_ERR("Failed to enqueue OUT buffer"); + } + + /* Process the MCTP data */ + struct mctp_binding_usb *usb = (struct mctp_binding_usb *)ctx->inst->mctp_binding; + + LOG_DBG("size=%d", ctx->out_net_buf->len); + LOG_HEXDUMP_DBG(buf, ctx->out_net_buf->len, "buf = "); + + for (int i = 0; i < buf_size; i++) { + switch (usb->rx_state) { + case STATE_WAIT_HDR_DMTF0: { + if (ctx->out_buf[i] == MCTP_USB_DMTF_0) { + usb->rx_state = STATE_WAIT_HDR_DMTF1; + } else { + LOG_ERR("Invalid DMTF0 %02X", ctx->out_buf[i]); + return; + } + break; + } + case STATE_WAIT_HDR_DMTF1: { + if (ctx->out_buf[i] == MCTP_USB_DMTF_1) { + usb->rx_state = STATE_WAIT_HDR_RSVD0; + } else { + LOG_ERR("Invalid DMTF1 %02X", ctx->out_buf[i]); + usb->rx_state = STATE_WAIT_HDR_DMTF0; + return; + } + break; + } + case STATE_WAIT_HDR_RSVD0: { + if (ctx->out_buf[i] == 0) { + usb->rx_state = STATE_WAIT_HDR_LEN; + } else { + LOG_ERR("Invalid RSVD0 %02X", ctx->out_buf[i]); + usb->rx_state = STATE_WAIT_HDR_DMTF0; + return; + } + break; + } + case STATE_WAIT_HDR_LEN: { + if (ctx->out_buf[i] > MCTP_USB_MAX_PACKET_LENGTH || ctx->out_buf[i] == 0) { + LOG_ERR("Invalid LEN %02X", ctx->out_buf[i]); + usb->rx_state = STATE_WAIT_HDR_DMTF0; + return; + } + + usb->rx_data_idx = 0; + usb->rx_pkt = mctp_pktbuf_alloc(&usb->binding, ctx->out_buf[i]); + if (usb->rx_pkt == NULL) { + LOG_ERR("Could not allocate PKT buffer"); + mctp_usb_reset_rx_state(usb); + return; + } + + usb->rx_state = STATE_DATA; + + LOG_DBG("Expecting LEN=%d", (int)ctx->out_buf[i]); + + break; + } + case STATE_DATA: { + usb->rx_pkt->data[usb->rx_data_idx++] = ctx->out_buf[i]; + + if (usb->rx_data_idx == usb->rx_pkt->end) { + LOG_DBG("Packet complete"); + mctp_bus_rx(&usb->binding, usb->rx_pkt); + mctp_usb_reset_rx_state(usb); + } + + break; + } + } + } +} + +static int mctp_usb_class_request(struct usbd_class_data *const c_data, struct net_buf *buf, + int err) +{ + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + struct udc_buf_info *bi = udc_get_buf_info(buf); + + LOG_DBG("request for EP 0x%x", bi->ep); + + if (err) { + if (err == -ECONNABORTED) { + LOG_WRN("request ep 0x%02x, len %u cancelled", bi->ep, buf->len); + } else { + LOG_ERR("request ep 0x%02x, len %u failed", bi->ep, buf->len); + } + + goto exit; + } + + if (bi->ep == mctp_usb_class_get_bulk_out(c_data)) { + ctx->out_net_buf = buf; + k_work_submit(&ctx->out_work); + } + + if (bi->ep == mctp_usb_class_get_bulk_in(c_data)) { + k_sem_give(&ctx->inst->mctp_binding->tx_lock); + net_buf_unref(buf); + } + +exit: + return 0; +} + +static void *mctp_usb_class_get_desc(struct usbd_class_data *const c_data, + const enum usbd_speed speed) +{ + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + + if (USBD_SUPPORTS_HIGH_SPEED && speed == USBD_SPEED_HS) { + return ctx->hs_desc; + } + + return ctx->fs_desc; +} + +static void mctp_usb_class_enable(struct usbd_class_data *const c_data) +{ + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + + if (!atomic_test_and_set_bit(&ctx->state, MCTP_USB_ENABLED)) { + k_work_submit(&ctx->out_work); + } + + LOG_DBG("Enabled %s", c_data->name); +} + +static void mctp_usb_class_disable(struct usbd_class_data *const c_data) +{ + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + + atomic_clear_bit(&ctx->state, MCTP_USB_ENABLED); + + LOG_DBG("Disabled %s", c_data->name); +} + +static int mctp_usb_class_init(struct usbd_class_data *const c_data) +{ + struct mctp_usb_class_ctx *ctx = usbd_class_get_private(c_data); + size_t num_instances = 0; + + STRUCT_SECTION_COUNT(mctp_usb_class_inst, &num_instances); + + if (num_instances != MCTP_USB_NUM_INSTANCES) { + LOG_ERR("The number of application instances (%d) does not match the number " + "specified by CONFIG_MCTP_USB_CLASS_INSTANCES_COUNT (%d)", + num_instances, MCTP_USB_NUM_INSTANCES); + return -EINVAL; + } + + STRUCT_SECTION_GET(mctp_usb_class_inst, ctx->inst_idx, &ctx->inst); + + ctx->class_data = c_data; + ctx->state = 0; + + /* Share USB class data with the binding so that the binding */ + ctx->inst->mctp_binding->usb_class_data = c_data; + + k_work_init(&ctx->out_work, mctp_usb_class_out_work); + + if (ctx->inst->sublcass == USBD_MCTP_SUBCLASS_MANAGEMENT_CONTROLLER || + ctx->inst->sublcass == USBD_MCTP_SUBCLASS_MANAGED_DEVICE_ENDPOINT || + ctx->inst->sublcass == USBD_MCTP_SUBCLASS_HOST_INTERFACE_ENDPOINT) { + ctx->desc->if0.bInterfaceSubClass = ctx->inst->sublcass; + } else { + LOG_ERR("Invalid USB MCTP sublcass"); + return -EINVAL; + } + + if (ctx->inst->mctp_protocol == USBD_MCTP_PROTOCOL_1_X || + ctx->inst->mctp_protocol == USBD_MCTP_PROTOCOL_2_X) { + ctx->desc->if0.bInterfaceProtocol = ctx->inst->mctp_protocol; + } else { + LOG_ERR("Invalid MCTP protocol"); + return -EINVAL; + } + + LOG_DBG("MCTP device %s initialized", ctx->inst->mctp_binding->binding.name); + + return 0; +} + +struct usbd_class_api mctp_usb_class_api = { + .request = mctp_usb_class_request, + .enable = mctp_usb_class_enable, + .disable = mctp_usb_class_disable, + .init = mctp_usb_class_init, + .get_desc = mctp_usb_class_get_desc, +}; + +#define DEFINE_MCTP_USB_CLASS_DESCRIPTORS(n, _) \ + static struct mctp_usb_class_desc mctp_usb_class_desc_##n = { \ + .if0 = { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_DESC_INTERFACE, \ + .bInterfaceNumber = 0, \ + .bAlternateSetting = 0, \ + .bNumEndpoints = 2, \ + .bInterfaceClass = USB_BCC_MCTP, \ + .bInterfaceSubClass = 0, \ + .bInterfaceProtocol = 1, \ + .iInterface = 0 \ + }, \ + .if0_fs_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(64), \ + .bInterval = 1 \ + }, \ + .if0_fs_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(64), \ + .bInterval = 1 \ + }, \ + .if0_hs_out_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x01, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512), \ + .bInterval = 1 \ + }, \ + .if0_hs_in_ep = { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_DESC_ENDPOINT, \ + .bEndpointAddress = 0x81, \ + .bmAttributes = USB_EP_TYPE_BULK, \ + .wMaxPacketSize = sys_cpu_to_le16(512), \ + .bInterval = 1 \ + }, \ + .nil_desc = { \ + .bLength = 0, \ + .bDescriptorType = 0 \ + } \ + }; \ + const static struct usb_desc_header *mctp_usb_class_fs_desc_##n[] = { \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.if0, \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.if0_fs_in_ep, \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.if0_fs_out_ep, \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.nil_desc \ + }; \ + \ + const static struct usb_desc_header *mctp_usb_class_hs_desc_##n[] = { \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.if0, \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.if0_hs_in_ep, \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.if0_hs_out_ep, \ + (struct usb_desc_header *)&mctp_usb_class_desc_##n.nil_desc \ + }; + +#define DEFINE_MCTP_USB_CLASS_DATA(n, _) \ + static struct mctp_usb_class_ctx mctp_usb_class_ctx_##n = { \ + .desc = &mctp_usb_class_desc_##n, \ + .fs_desc = mctp_usb_class_fs_desc_##n, \ + .hs_desc = mctp_usb_class_hs_desc_##n, \ + .inst_idx = n, \ + .out_net_buf = NULL \ + }; \ + \ + USBD_DEFINE_CLASS(mctp_##n, &mctp_usb_class_api, &mctp_usb_class_ctx_##n, NULL); + +LISTIFY(MCTP_USB_NUM_INSTANCES, DEFINE_MCTP_USB_CLASS_DESCRIPTORS, ()) +LISTIFY(MCTP_USB_NUM_INSTANCES, DEFINE_MCTP_USB_CLASS_DATA, ()) diff --git a/subsys/pmci/mctp/mctp_usb.ld b/subsys/pmci/mctp/mctp_usb.ld new file mode 100644 index 0000000000000..fdbe6bfef107d --- /dev/null +++ b/subsys/pmci/mctp/mctp_usb.ld @@ -0,0 +1,3 @@ +#include + +ITERABLE_SECTION_ROM(mctp_usb_class_inst, Z_LINK_ITERABLE_SUBALIGN) From 1a0d7bc2f4d480e81f2111fd0bdee1573b9b2eb4 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Tue, 21 Oct 2025 16:33:57 +0200 Subject: [PATCH 134/397] MAINTAINERS: mone Kconfig into maintained Move Kconfig into maintained state and add tejlmand as maintainer. Signed-off-by: Torsten Rasmussen --- MAINTAINERS.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 15d61c7169112..896af776573d4 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3047,9 +3047,10 @@ JSON Web Token: - libraries.encoding.jwt Kconfig: - status: odd fixes - collaborators: + status: maintained + maintainers: - tejlmand + collaborators: - nashif files: - scripts/kconfig/ From 9de1e79ee1c7c4eb63f824d6a44c79321251eff3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 21 Oct 2025 16:12:44 +0200 Subject: [PATCH 135/397] net: sockets: tls: Remove leftover todo comment Logs were added, but the todo comment about this was overlooked, remove it. Signed-off-by: Robert Lubos --- subsys/net/lib/sockets/sockets_tls.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 695af67164685..2ccca60a34df5 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -1552,7 +1552,6 @@ static int tls_check_psk(struct tls_credential *psk) #endif } -/* TODO add decent logs */ static int tls_check_credentials(const sec_tag_t *sec_tags, int sec_tag_count) { int err = 0; From dfbe383420ad62de29ea0848f693552dd8edd1bc Mon Sep 17 00:00:00 2001 From: Alessandro Manganaro Date: Tue, 21 Oct 2025 14:52:00 +0200 Subject: [PATCH 136/397] drivers: bluetooth: hci: fix a typo in stm32wbax ble hci driver Typo fix in assert condition used by stm32wbax ble hci driver. Signed-off-by: Alessandro Manganaro --- drivers/bluetooth/hci/hci_stm32wba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci/hci_stm32wba.c b/drivers/bluetooth/hci/hci_stm32wba.c index 77b8ee64fa039..c60e41bcbd585 100644 --- a/drivers/bluetooth/hci/hci_stm32wba.c +++ b/drivers/bluetooth/hci/hci_stm32wba.c @@ -133,7 +133,7 @@ void register_radio_event(void) /* Getting next radio event time if any */ cmd_status = ll_intf_le_get_remaining_time_for_next_event(&next_radio_event_us); UNUSED(cmd_status); - __ASSERT(cmd_staus, "Unable to retrieve next radio event"); + __ASSERT(cmd_status, "Unable to retrieve next radio event"); if (next_radio_event_us == LL_DP_SLP_NO_WAKEUP) { /* No next radio event scheduled */ From 9a24d130f5f0908945ea4aec3d77f4a4144ad028 Mon Sep 17 00:00:00 2001 From: Neil Chen Date: Tue, 21 Oct 2025 11:51:41 +0800 Subject: [PATCH 137/397] soc: nxp: mcx: update config NUM_IRQS value Update mcxa NUM_IRQS value according to part number. Correct mcxn NUM_IRQS value to 156. Signed-off-by: Neil Chen --- soc/nxp/mcx/mcxa/Kconfig.defconfig | 3 +++ soc/nxp/mcx/mcxn/Kconfig.defconfig | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/soc/nxp/mcx/mcxa/Kconfig.defconfig b/soc/nxp/mcx/mcxa/Kconfig.defconfig index 04d2950e1d50e..0d2b2496654df 100644 --- a/soc/nxp/mcx/mcxa/Kconfig.defconfig +++ b/soc/nxp/mcx/mcxa/Kconfig.defconfig @@ -7,6 +7,9 @@ config CORTEX_M_SYSTICK default n if (MCUX_LPTMR_TIMER || MCUX_OS_TIMER) config NUM_IRQS + default 80 if SOC_MCXA153 + default 89 if SOC_MCXA156 + default 122 if (SOC_MCXA346 || SOC_MCXA266 || SOC_MCXA366) default 88 config SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/nxp/mcx/mcxn/Kconfig.defconfig b/soc/nxp/mcx/mcxn/Kconfig.defconfig index 777acbf757d5e..ed99e7651973f 100644 --- a/soc/nxp/mcx/mcxn/Kconfig.defconfig +++ b/soc/nxp/mcx/mcxn/Kconfig.defconfig @@ -10,7 +10,7 @@ config MFD default y if DT_HAS_NXP_LP_FLEXCOMM_ENABLED config NUM_IRQS - default 155 + default 156 config ROM_START_OFFSET default 0x400 if BOOTLOADER_MCUBOOT From cf5ef37d5a2985126296899c352e6731da56b3d7 Mon Sep 17 00:00:00 2001 From: Allen Zhang Date: Mon, 20 Oct 2025 17:19:34 +0800 Subject: [PATCH 138/397] dts: mcxw23x: Correct the flash0 in common dtsi According to the RM, erasing must be done per sector. So, the start address and the size of an erase operation must be a multiple of 8192 bytes. So, the erase-block-size should be 8192 bytes. Programming can be done per phrase (start address and size a multiple of 16 bytes). So, write-block-size should be 16 bytes. Signed-off-by: Allen Zhang --- dts/arm/nxp/nxp_mcxw23x_common.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dts/arm/nxp/nxp_mcxw23x_common.dtsi b/dts/arm/nxp/nxp_mcxw23x_common.dtsi index a1adcffaf8514..ad4965464c264 100644 --- a/dts/arm/nxp/nxp_mcxw23x_common.dtsi +++ b/dts/arm/nxp/nxp_mcxw23x_common.dtsi @@ -89,8 +89,8 @@ flash0: flash@0 { compatible = "soc-nv-flash"; reg = <0x0 DT_SIZE_K(1016)>; - erase-block-size = <512>; - write-block-size = <512>; + erase-block-size = ; + write-block-size = <16>; }; flash_reserved: flash@fe000 { From d7c62c6fe0efb8cdc180ea166a9e043ff0ee4769 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 9 Oct 2025 21:51:07 -0400 Subject: [PATCH 139/397] samples: zbus: msg_subscriber: Filter SMP from pool exhaustion tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "_too_small" test variants intentionally configure an isolated buffer pool with only 2 buffers to validate proper error handling when the pool is exhausted during notification of 16 msg_subscriber observers. These tests are likely to fail on SMP systems due to a buffer recycling race condition: Expected behavior (uniprocessor): Publisher Thread: 1. Allocate buf1 for bar_msg_sub1 ✓ 2. k_fifo_put(sub1_fifo, buf1) 3. Allocate buf2 for bar_msg_sub2 ✓ 4. k_fifo_put(sub2_fifo, buf2) 5. Try allocate buf3 for bar_msg_sub3 → FAIL -ENOMEM Subscriber threads process messages after notification completes, pool exhausts at subscriber #3 as expected. SMP race condition: CPU 0 (Publisher): CPU 1 (bar_msg_sub1): CPU 2 (bar_msg_sub2): ------------------ --------------------- --------------------- Alloc buf1 ✓ k_fifo_put(sub1, buf1) k_fifo_get() → buf1 zbus_sub_wait_msg() net_buf_unref() → buf1 FREED! Alloc buf2 ✓ (reuses buf1!) k_fifo_put(sub2, buf2) k_fifo_get() → buf2 net_buf_unref() → buf2 FREED! Alloc buf3 ✓ (reuses buf1 again!) ...continues... All 16 allocations succeed! On SMP systems, subscriber threads on other CPUs may consume and free buffers quickly enough that they are recycled back to the pool before the publisher's notification loop can exhaust it. The test's assumption that notification completes before subscribers run does not hold with parallel execution. Since this is a test design limitation (not a zbus bug), filter SMP configurations from these specific test variants rather than attempt to artificially slow down subscribers or change thread priorities. Signed-off-by: Nicolas Pitre --- samples/subsys/zbus/msg_subscriber/sample.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/subsys/zbus/msg_subscriber/sample.yaml b/samples/subsys/zbus/msg_subscriber/sample.yaml index 1664f93931ded..236298bc7461a 100644 --- a/samples/subsys/zbus/msg_subscriber/sample.yaml +++ b/samples/subsys/zbus/msg_subscriber/sample.yaml @@ -274,6 +274,7 @@ tests: integration_platforms: - qemu_x86 sample.zbus.msg_subscriber_dynamic_isolated_too_small: + filter: not CONFIG_SMP harness: console extra_configs: - CONFIG_ZBUS_LOG_LEVEL_DBG=y @@ -385,6 +386,7 @@ tests: integration_platforms: - qemu_x86 sample.zbus.msg_subscriber_static_isolated_too_small: + filter: not CONFIG_SMP harness: console extra_configs: - CONFIG_ZBUS_LOG_LEVEL_DBG=y From 8ac94ae79d2eb7cda9caf690cc42aea44b9117fc Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 9 Oct 2025 23:20:22 -0400 Subject: [PATCH 140/397] samples: zbus: benchmark: Filter SMP from benchmark_sync test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The benchmark_sync test produces incorrect results on SMP systems due to a race condition between the producer thread and subscriber threads that only occurs with parallel execution. Thread configuration: - Producer thread: priority 5 (lower priority, runs later) - Subscriber threads (8): priority 3 (higher priority, runs first) Expected behavior on uniprocessor: 1. Producer publishes message 2. Subscriber immediately preempts producer (priority 3 < 5) 3. Subscriber processes message, calls atomic_add(&count, 256) 4. Producer resumes, continues to next message Result: All messages counted before producer checks final count. Race condition on SMP: CPU 0 (Producer): CPU 1-3 (Subscribers): ----------------- ---------------------- Publish msg 1 k_msgq_put(sub1) ✓ k_msgq_get() → processing Publish msg 2 k_msgq_put(sub2) ✓ k_msgq_get() → processing ...continues... Publish msg 128 ✓ atomic_get(&count) Still processing... → Reports incomplete count! atomic_add() comes later On SMP, the producer doesn't get preempted since it runs on a different CPU from the subscribers. It races ahead and checks atomic_get(&count) while subscriber threads on other CPUs are still processing messages. Observed results: - Non-SMP: Bytes sent = 262144, received = 262144 ✓ - SMP: Bytes sent = 262144, received = 260352 ✗ (7 messages lost) This is a benchmark test design issue, not a zbus bug. The test assumes subscribers complete before the producer finishes, which doesn't hold on SMP systems. Filter SMP configurations from this test variant for now. Signed-off-by: Nicolas Pitre --- samples/subsys/zbus/benchmark/sample.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/subsys/zbus/benchmark/sample.yaml b/samples/subsys/zbus/benchmark/sample.yaml index cba42f5c8b988..3be3650ef7679 100644 --- a/samples/subsys/zbus/benchmark/sample.yaml +++ b/samples/subsys/zbus/benchmark/sample.yaml @@ -46,7 +46,10 @@ tests: sample.zbus.benchmark_sync: tags: zbus min_ram: 16 - filter: CONFIG_SYS_CLOCK_EXISTS and not (CONFIG_ARCH_POSIX and not CONFIG_BOARD_NATIVE_SIM) + filter: >- + CONFIG_SYS_CLOCK_EXISTS and + not (CONFIG_ARCH_POSIX and not CONFIG_BOARD_NATIVE_SIM) and + not CONFIG_SMP harness: console harness_config: type: multi_line From 33800e363a7effd0b85a5118630847d317cb3794 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 17 Oct 2025 14:24:26 -0400 Subject: [PATCH 141/397] kernel: mmu: k_mem_page_frame_evict() fix locking typo ... when CONFIG_DEMAND_PAGING_ALLOW_IRQ is set. Found during code inspection. k_mem_page_frame_evict() is otherwise rarely used, Signed-off-by: Nicolas Pitre --- kernel/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/mmu.c b/kernel/mmu.c index 322fc61c5c0b0..e730ca3203f99 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -1503,7 +1503,7 @@ int k_mem_page_frame_evict(uintptr_t phys) do_backing_store_page_out(location); } #ifdef CONFIG_DEMAND_PAGING_ALLOW_IRQ - k_spin_unlock(&z_mm_lock, key); + key = k_spin_lock(&z_mm_lock); #endif /* CONFIG_DEMAND_PAGING_ALLOW_IRQ */ page_frame_free_locked(pf); out: From c00de3fec92a81bf583ba7759c20a9fdd31060c0 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Fri, 17 Oct 2025 13:51:22 -0400 Subject: [PATCH 142/397] sensor: all: Fix missing result argument on RTIO callbacks If there's an error/result checked, consider the callback result in such solution. Signed-off-by: Luis Ubieda --- .../sensor/pixart/paa3905/paa3905_stream.c | 27 ++++++++++++------- .../sensor/pixart/pat9136/pat9136_stream.c | 7 +++-- drivers/sensor/pni/rm3100/rm3100_stream.c | 8 +++--- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/sensor/pixart/paa3905/paa3905_stream.c b/drivers/sensor/pixart/paa3905/paa3905_stream.c index 3f8b281bb8cab..3984da5ec95dd 100644 --- a/drivers/sensor/pixart/paa3905/paa3905_stream.c +++ b/drivers/sensor/pixart/paa3905/paa3905_stream.c @@ -59,6 +59,7 @@ static void start_drdy_backup_timer(const struct device *dev) static void paa3905_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, + int err, void *arg) { const struct device *dev = (const struct device *)arg; @@ -66,7 +67,6 @@ static void paa3905_complete_result(struct rtio *ctx, struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; struct paa3905_encoded_data *edata = sqe->userdata; struct rtio_cqe *cqe; - int err; edata->header.events.drdy = true && data->stream.settings.enabled.drdy; @@ -85,6 +85,22 @@ static void paa3905_complete_result(struct rtio *ctx, start_drdy_backup_timer(dev); } + /* Flush RTIO bus CQEs */ + do { + cqe = rtio_cqe_consume(ctx); + if (cqe != NULL) { + if (err >= 0) { + err = cqe->result; + } + rtio_cqe_release(ctx, cqe); + } + } while (cqe != NULL); + + if (err < 0) { + rtio_iodev_sqe_err(iodev_sqe, err); + return; + } + /** Attempt chip recovery if erratic behavior is detected */ if (!REG_OBSERVATION_CHIP_OK(edata->observation)) { @@ -101,15 +117,6 @@ static void paa3905_complete_result(struct rtio *ctx, } else { rtio_iodev_sqe_ok(iodev_sqe, 0); } - - /* Flush RTIO bus CQEs */ - do { - cqe = rtio_cqe_consume(ctx); - if (cqe != NULL) { - err = cqe->result; - rtio_cqe_release(ctx, cqe); - } - } while (cqe != NULL); } static void paa3905_stream_get_data(const struct device *dev) diff --git a/drivers/sensor/pixart/pat9136/pat9136_stream.c b/drivers/sensor/pixart/pat9136/pat9136_stream.c index 3f7bff784f211..3a1e1e6b86a2d 100644 --- a/drivers/sensor/pixart/pat9136/pat9136_stream.c +++ b/drivers/sensor/pixart/pat9136/pat9136_stream.c @@ -45,6 +45,7 @@ static void start_drdy_cooldown_timer(const struct device *dev) static void pat9136_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, + int result, void *arg) { const struct device *dev = (const struct device *)arg; @@ -74,11 +75,13 @@ static void pat9136_complete_result(struct rtio *ctx, /** Attempt chip recovery if erratic behavior is detected */ if (!REG_OBSERVATION_READ_IS_VALID(edata->observation)) { - LOG_WRN("CHIP OK register indicates issues. Attempting chip recovery: 0x%02X", edata->observation); + result = -EAGAIN; + } - rtio_iodev_sqe_err(iodev_sqe, -EAGAIN); + if (result < 0) { + rtio_iodev_sqe_err(iodev_sqe, result); } else { rtio_iodev_sqe_ok(iodev_sqe, 0); } diff --git a/drivers/sensor/pni/rm3100/rm3100_stream.c b/drivers/sensor/pni/rm3100/rm3100_stream.c index d56a44336ce33..597585e12ac78 100644 --- a/drivers/sensor/pni/rm3100/rm3100_stream.c +++ b/drivers/sensor/pni/rm3100/rm3100_stream.c @@ -16,13 +16,13 @@ #include LOG_MODULE_REGISTER(RM3100_STREAM, CONFIG_SENSOR_LOG_LEVEL); -static void rm3100_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, void *arg) +static void rm3100_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, int err, + void *arg) { const struct device *dev = (const struct device *)arg; struct rm3100_data *data = dev->data; struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; struct rtio_cqe *cqe; - int err = 0; struct rm3100_encoded_data *edata = sqe->userdata; edata->header.events.drdy = ((edata->header.status != 0) && @@ -39,7 +39,9 @@ static void rm3100_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, do { cqe = rtio_cqe_consume(ctx); if (cqe != NULL) { - err = cqe->result; + if (err >= 0) { + err = cqe->result; + } rtio_cqe_release(ctx, cqe); } } while (cqe != NULL); From 8b8f63940839ade6c1e96f677bcc2b92e4fd9338 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Fri, 17 Oct 2025 13:57:30 -0400 Subject: [PATCH 143/397] sensor: icm45686: Fix build-time failure on I3C mode Missed while simplifying RTIO bus transfers on #94832. Signed-off-by: Luis Ubieda --- drivers/sensor/tdk/icm45686/icm45686_stream.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/sensor/tdk/icm45686/icm45686_stream.c b/drivers/sensor/tdk/icm45686/icm45686_stream.c index f76838f118bc0..190d32e3c342d 100644 --- a/drivers/sensor/tdk/icm45686/icm45686_stream.c +++ b/drivers/sensor/tdk/icm45686/icm45686_stream.c @@ -573,18 +573,17 @@ int icm45686_stream_init(const struct device *dev) } #if DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(invensense_icm45686, i3c) /** I3C devices use IBI only if no GPIO INT pin is defined. */ - } else if (data->rtio.type == ICM45686_BUS_I3C) { - const struct i3c_iodev_data *iodev_data = data->rtio.iodev->data; + } else if (data->bus.rtio.type == ICM45686_BUS_I3C) { + const struct i3c_iodev_data *iodev_data = data->bus.rtio.iodev->data; - data->rtio.i3c.desc = i3c_device_find(iodev_data->bus, - &data->rtio.i3c.id); - if (data->rtio.i3c.desc == NULL) { + data->bus.rtio.i3c.desc = i3c_device_find(iodev_data->bus, &data->bus.rtio.i3c.id); + if (data->bus.rtio.i3c.desc == NULL) { LOG_ERR("Failed to find I3C device"); return -ENODEV; } - data->rtio.i3c.desc->ibi_cb = icm45686_ibi_cb; + data->bus.rtio.i3c.desc->ibi_cb = icm45686_ibi_cb; - err = i3c_ibi_enable(data->rtio.i3c.desc); + err = i3c_ibi_enable(data->bus.rtio.i3c.desc); if (err) { LOG_ERR("Failed to enable IBI: %d", err); return err; From a4e2ce2a3709149f0a754ab6b59f982b334a9aca Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Fri, 17 Oct 2025 13:59:50 -0400 Subject: [PATCH 144/397] tests: sensor: build_all: Add ADXL345 to SPI tests Additionally, add fifo-watermark property required for Streaming mode. Signed-off-by: Luis Ubieda --- tests/drivers/build_all/sensor/i2c.dtsi | 2 ++ tests/drivers/build_all/sensor/spi.dtsi | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 27731a13a1d4d..2feda1d16c37f 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -41,6 +41,8 @@ test_i2c_adt7420: adt7420@0 { test_i2c_adxl345: adxl345@1 { compatible = "adi,adxl345"; reg = <0x1>; + int1-gpios = <&test_gpio 0 0>; + fifo-watermark = <1>; }; test_i2c_adxl372: adxl372@2 { diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index 80e6b1d08acd8..6560c377a0e31 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -479,3 +479,11 @@ test_spi_iis3dwb: iis3dwb@39 { odr = ; filter = ; }; + +test_spi_adxl345: adxl345@3a { + compatible = "adi,adxl345"; + reg = <0x3a>; + spi-max-frequency = <0>; + int1-gpios = <&test_gpio 0 0>; + fifo-watermark = <1>; +}; From 2b973b92db0cc6250c5234a77d431512932ea7a4 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Fri, 17 Oct 2025 14:00:32 -0400 Subject: [PATCH 145/397] tests: sensor: build_all: Add Async API test validation This covers both Read-Decode and Streaming mode. Since we haven't had it there have been a few issues (addressed prior to this commit). From now on, we should maintain this test similar to the others. Signed-off-by: Luis Ubieda --- .../build_all/sensor/sensors_async_api.conf | 14 ++++++++++++++ tests/drivers/build_all/sensor/testcase.yaml | 2 ++ 2 files changed, 16 insertions(+) create mode 100644 tests/drivers/build_all/sensor/sensors_async_api.conf diff --git a/tests/drivers/build_all/sensor/sensors_async_api.conf b/tests/drivers/build_all/sensor/sensors_async_api.conf new file mode 100644 index 0000000000000..4b98bb3437d0f --- /dev/null +++ b/tests/drivers/build_all/sensor/sensors_async_api.conf @@ -0,0 +1,14 @@ +CONFIG_SENSOR_ASYNC_API=y +CONFIG_ADXL345_STREAM=y +CONFIG_ADXL362_STREAM=y +CONFIG_ADXL367_STREAM=y +CONFIG_ADXL372_STREAM=y +CONFIG_BMA4XX_STREAM=y +CONFIG_BMM350_STREAM=y +CONFIG_PAA3905_STREAM=y +CONFIG_PAT9136_STREAM=y +CONFIG_RM3100_STREAM=y +CONFIG_IIS3DWB_STREAM=y +CONFIG_LSM6DSV16X_STREAM=y +CONFIG_ICM45686_STREAM=y +CONFIG_ICM4268X_STREAM=y diff --git a/tests/drivers/build_all/sensor/testcase.yaml b/tests/drivers/build_all/sensor/testcase.yaml index 1786d809d7252..eef3e25d79c47 100644 --- a/tests/drivers/build_all/sensor/testcase.yaml +++ b/tests/drivers/build_all/sensor/testcase.yaml @@ -18,6 +18,8 @@ tests: extra_args: EXTRA_CONF_FILE=sensors_trigger_none.conf;sensors_die_temp.conf drivers.sensor.no_default.build: extra_args: EXTRA_CONF_FILE=sensors_no_default.conf + drivers.sensor.async_api: + extra_args: EXTRA_CONF_FILE=sensors_async_api.conf drivers.sensor.build: tags: sensors extra_args: EXTRA_CONF_FILE=sensors_die_temp.conf From b6911fba3d42a759e7bf300f35e66acdb5c472e3 Mon Sep 17 00:00:00 2001 From: Biwen Li Date: Wed, 6 Aug 2025 16:28:55 +0900 Subject: [PATCH 146/397] drivers: dma: mcux_edma: print SADDR, DADDR - Print SADDR, DADDR for debugging. Signed-off-by: Biwen Li --- drivers/dma/dma_mcux_edma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/dma_mcux_edma.c b/drivers/dma/dma_mcux_edma.c index ed9431af645fc..f48b1b5ad913d 100644 --- a/drivers/dma/dma_mcux_edma.c +++ b/drivers/dma/dma_mcux_edma.c @@ -966,6 +966,8 @@ static int dma_mcux_edma_get_status(const struct device *dev, uint32_t channel, LOG_DBG("DMA CHx_ES 0x%x", DEV_BASE(dev)->TCD[hw_channel].CH_ES); LOG_DBG("DMA CHx_INT 0x%x", DEV_BASE(dev)->TCD[hw_channel].CH_INT); LOG_DBG("DMA TCD_CSR 0x%x", DEV_BASE(dev)->TCD[hw_channel].CSR); + LOG_DBG("DMA TCD_SADDR 0x%x", DEV_BASE(dev)->TCD[hw_channel].SADDR); + LOG_DBG("DMA TCD_DADDR 0x%x", DEV_BASE(dev)->TCD[hw_channel].DADDR); #else LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR); LOG_DBG("DMA INT 0x%x", DEV_BASE(dev)->INT); From cb522302cd9c40eeb5cfc1c527f62c7c87e16fda Mon Sep 17 00:00:00 2001 From: Biwen Li Date: Mon, 4 Aug 2025 13:39:56 +0900 Subject: [PATCH 147/397] drivers: dma: mcux_edma: get irq number for multi level int Get irq number when multi level intrerrupts is enabled. Signed-off-by: Biwen Li --- drivers/dma/dma_mcux_edma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/dma_mcux_edma.c b/drivers/dma/dma_mcux_edma.c index f48b1b5ad913d..0f7b85cbc0d20 100644 --- a/drivers/dma/dma_mcux_edma.c +++ b/drivers/dma/dma_mcux_edma.c @@ -1043,11 +1043,11 @@ static int dma_mcux_edma_init(const struct device *dev) #define IRQ_CONFIG(n, idx, fn) \ { \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, idx, irq), \ + IRQ_CONNECT(DT_INST_IRQN_BY_IDX(n, idx), \ DT_INST_IRQ_BY_IDX(n, idx, priority), \ fn, \ DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(n, idx, irq)); \ + irq_enable(DT_INST_IRQN_BY_IDX(n, idx)); \ } #define EDMA_CHANNELS_MASK(n) static uint32_t edma_channel_mask_##n[] = \ From d30c8c27c37663b45bea61cfb9506af6b6db2066 Mon Sep 17 00:00:00 2001 From: Felix Wang Date: Tue, 14 Oct 2025 14:48:37 +0800 Subject: [PATCH 148/397] tests: drivers: pwm: pwm_api: enable qtmr test Add mimxrt1180_evk_mimxrt1189_cm33_qtmr.overlay for test. Signed-off-by: Felix Wang --- ...imxrt1180_evk_mimxrt1189_cm33_qtmr.overlay | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/drivers/pwm/pwm_api/boards/mimxrt1180_evk_mimxrt1189_cm33_qtmr.overlay diff --git a/tests/drivers/pwm/pwm_api/boards/mimxrt1180_evk_mimxrt1189_cm33_qtmr.overlay b/tests/drivers/pwm/pwm_api/boards/mimxrt1180_evk_mimxrt1189_cm33_qtmr.overlay new file mode 100644 index 0000000000000..35aa3c5cc1499 --- /dev/null +++ b/tests/drivers/pwm/pwm_api/boards/mimxrt1180_evk_mimxrt1189_cm33_qtmr.overlay @@ -0,0 +1,30 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + pwm-test = &qtmr4; + }; +}; + +&pinctrl { + qtmr4_timer0_default: qtmr4 { + group0 { + pinmux = <&iomuxc_gpio_ad_00_qtimer4_timer0>; + drive-strength = "high"; + slew-rate = "fast"; + }; + }; +}; + +&qtmr4 { + compatible = "nxp,qtmr-pwm"; + pinctrl-0 = <&qtmr4_timer0_default>; + pinctrl-names = "default"; + #pwm-cells = <3>; + prescaler = <32>; + status = "okay"; +}; From d957f428dffd872844008258acdc448f0812d124 Mon Sep 17 00:00:00 2001 From: Felix Wang Date: Tue, 14 Oct 2025 14:54:41 +0800 Subject: [PATCH 149/397] drivers: pwm: enable pwm capture for qtmr driver Supported mode: single capture, continus capture, pulse capture, period capture. Signed-off-by: Felix Wang --- drivers/pwm/Kconfig.mcux_qtmr | 22 ++- drivers/pwm/pwm_mcux_qtmr.c | 271 ++++++++++++++++++++++++++++++++-- 2 files changed, 280 insertions(+), 13 deletions(-) diff --git a/drivers/pwm/Kconfig.mcux_qtmr b/drivers/pwm/Kconfig.mcux_qtmr index 150473ddae89c..d091d63a0b4e8 100644 --- a/drivers/pwm/Kconfig.mcux_qtmr +++ b/drivers/pwm/Kconfig.mcux_qtmr @@ -1,4 +1,4 @@ -# Copyright 2024 NXP +# Copyright 2024-2025 NXP # SPDX-License-Identifier: Apache-2.0 config PWM_MCUX_QTMR @@ -9,3 +9,23 @@ config PWM_MCUX_QTMR select PINCTRL help Enable QTMR based pwm driver. + +config PWM_CAPTURE_MCUX_QTMR_FILTER_PERIOD + int "MCUX QMTR PWM Input Filter Sample Period" + depends on PWM_MCUX_QTMR && PWM_CAPTURE + range 0 255 + default 0 + help + Indicates the sampling period (in IP bus clock cycles) of + the TMR input signals. If the value is 0x00 (default), then + the input filter is bypassed. + +config PWM_CAPTURE_MCUX_QTMR_FILTER_COUNT + int "MCUX QMTR PWM Input Filter Sample Count" + depends on PWM_MCUX_QTMR && PWM_CAPTURE + range 0 7 + default 0 + help + Indicates the number of consecutive samples that must agree prior to the + input filter accepting an input transition. The real number of samples is + (value +3). For example, a value of 0x0 indicates 3 samples. diff --git a/drivers/pwm/pwm_mcux_qtmr.c b/drivers/pwm/pwm_mcux_qtmr.c index 44b33b829f718..1e70bad12ff91 100644 --- a/drivers/pwm/pwm_mcux_qtmr.c +++ b/drivers/pwm/pwm_mcux_qtmr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, NXP + * Copyright (c) 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -26,10 +27,29 @@ struct pwm_mcux_qtmr_config { const struct pinctrl_dev_config *pincfg; const struct device *clock_dev; clock_control_subsys_t clock_subsys; +#ifdef CONFIG_PWM_CAPTURE + void (*irq_config_func)(const struct device *dev); +#endif /* CONFIG_PWM_CAPTURE */ }; +#ifdef CONFIG_PWM_CAPTURE +struct pwm_mcux_qtmr_capture_data { + pwm_capture_callback_handler_t callback; + void *user_data; + uint32_t overflow_count; + uint32_t channel; + bool continuous : 1; + bool overflowed : 1; + bool pulse_capture: 1; + bool first_edge_captured : 1; +}; +#endif /* CONFIG_PWM_CAPTURE */ + struct pwm_mcux_qtmr_data { struct k_mutex lock; +#ifdef CONFIG_PWM_CAPTURE + struct pwm_mcux_qtmr_capture_data capture; +#endif /* CONFIG_PWM_CAPTURE */ }; static int mcux_qtmr_pwm_set_cycles(const struct device *dev, uint32_t channel, @@ -124,6 +144,198 @@ static int mcux_qtmr_pwm_get_cycles_per_sec(const struct device *dev, uint32_t c return 0; } +#ifdef CONFIG_PWM_CAPTURE +static inline bool mcux_qtmr_channel_is_active(const struct device *dev, uint32_t channel) +{ + const struct pwm_mcux_qtmr_config *config = dev->config; + + return (config->base->CHANNEL[channel].CTRL & TMR_CTRL_CM_MASK) != 0U; +} + +static int mcux_qtmr_configure_capture(const struct device *dev, + uint32_t channel, pwm_flags_t flags, + pwm_capture_callback_handler_t cb, + void *user_data) +{ + const struct pwm_mcux_qtmr_config *config = dev->config; + struct pwm_mcux_qtmr_data *data = dev->data; + bool inverted = (flags & PWM_POLARITY_MASK) == PWM_POLARITY_INVERTED; + + if (channel >= CHANNEL_COUNT) { + LOG_ERR("invalid channel %d", channel); + return -EINVAL; + } + + if (mcux_qtmr_channel_is_active(dev, channel)) { + LOG_ERR("pwm capture in progress"); + return -EBUSY; + } + + if (!(flags & PWM_CAPTURE_TYPE_MASK)) { + LOG_ERR("No capture type specified"); + return -EINVAL; + } + + if ((flags & PWM_CAPTURE_TYPE_MASK) == PWM_CAPTURE_TYPE_BOTH) { + LOG_ERR("Cannot capture both period and pulse width"); + return -ENOTSUP; + } + + data->capture.callback = cb; + data->capture.user_data = user_data; + data->capture.channel = channel; + data->capture.continuous = + (flags & PWM_CAPTURE_MODE_MASK) == PWM_CAPTURE_MODE_CONTINUOUS; + + if (flags & PWM_CAPTURE_TYPE_PERIOD) { + data->capture.pulse_capture = false; + /* set reloadOnCapture to true to reload counter when capture event happends, + * so only second caputre value is needed when calculating ticks + */ + QTMR_SetupInputCapture(config->base, + (qtmr_channel_selection_t)channel, + (qtmr_input_source_t)channel, + inverted, true, kQTMR_RisingEdge); + } else { + data->capture.pulse_capture = true; + QTMR_SetupInputCapture(config->base, + (qtmr_channel_selection_t)channel, + (qtmr_input_source_t)channel, + inverted, true, kQTMR_RisingAndFallingEdge); + } + QTMR_EnableInterrupts(config->base, channel, + kQTMR_EdgeInterruptEnable | kQTMR_OverflowInterruptEnable); + + return 0; +} + +static int mcux_qtmr_enable_capture(const struct device *dev, uint32_t channel) +{ + const struct pwm_mcux_qtmr_config *config = dev->config; + struct pwm_mcux_qtmr_data *data = dev->data; + + if (channel >= CHANNEL_COUNT) { + LOG_ERR("invalid channel %d", channel); + return -EINVAL; + } + + if (!data->capture.callback) { + LOG_ERR("PWM capture not configured"); + return -EINVAL; + } + + if (mcux_qtmr_channel_is_active(dev, channel)) { + LOG_ERR("PWM capture already enabled"); + return -EBUSY; + } + + data->capture.overflowed = false; + data->capture.first_edge_captured = false; + data->capture.overflow_count = 0; + QTMR_StartTimer(config->base, channel, kQTMR_PriSrcRiseEdge); + + return 0; +} + +static int mcux_qtmr_disable_capture(const struct device *dev, uint32_t channel) +{ + const struct pwm_mcux_qtmr_config *config = dev->config; + + if (channel >= CHANNEL_COUNT) { + LOG_ERR("invalid channel %d", channel); + return -EINVAL; + } + + QTMR_StopTimer(config->base, channel); + return 0; +} + +static int mcux_qtmr_calc_ticks(uint32_t overflows, uint32_t capture, + uint32_t *result) +{ + uint32_t pulse; + + /* Calculate cycles from overflow counter */ + if (u32_mul_overflow(overflows, 0xFFFFU, &pulse)) { + return -ERANGE; + } + + /* Add pulse width */ + if (u32_add_overflow(pulse, capture, &pulse)) { + return -ERANGE; + } + + *result = pulse; + + return 0; +} + +static void mcux_qtmr_isr(const struct device *dev) +{ + const struct pwm_mcux_qtmr_config *config = dev->config; + struct pwm_mcux_qtmr_data *data = dev->data; + uint32_t ticks = 0; + uint32_t timeCapt = 0; + int err = 0; + uint32_t flags; + + flags = QTMR_GetStatus(config->base, data->capture.channel); + QTMR_ClearStatusFlags(config->base, data->capture.channel, flags); + + if ((flags & kQTMR_OverflowFlag) != 0U) { + data->capture.overflowed |= u32_add_overflow(1, + data->capture.overflow_count, &data->capture.overflow_count); + } + + if ((flags & kQTMR_EdgeFlag) == 0U) { + return; + } + + if (!data->capture.first_edge_captured) { + data->capture.first_edge_captured = true; + data->capture.overflow_count = 0; + data->capture.overflowed = false; + return; + } + + if (data->capture.overflowed) { + err = -ERANGE; + } else { + /* calculate ticks from second capture */ + timeCapt = config->base->CHANNEL[data->capture.channel].CAPT; + err = mcux_qtmr_calc_ticks(data->capture.overflow_count, timeCapt, &ticks); + } + + if (data->capture.pulse_capture) { + data->capture.callback(dev, data->capture.channel, + 0, ticks, err, data->capture.user_data); + } else { + data->capture.callback(dev, data->capture.channel, + ticks, 0, err, data->capture.user_data); + } + + /* Prepare for next capture */ + data->capture.overflowed = false; + data->capture.overflow_count = 0; + + if (data->capture.continuous) { + if (data->capture.pulse_capture) { + data->capture.first_edge_captured = false; + } else { + /* No action required. In continuous period capture mode, + * first edge of next period captureis second edge of this + * capture (this edge) + */ + } + } else { + /* Stop timer and disable interrupts for single capture*/ + data->capture.first_edge_captured = false; + QTMR_DisableInterrupts(config->base, data->capture.channel, + kQTMR_EdgeInterruptEnable | kQTMR_OverflowInterruptEnable); + QTMR_StopTimer(config->base, data->capture.channel); + } +} +#endif /* CONFIG_PWM_CAPTURE */ static int mcux_qtmr_pwm_init(const struct device *dev) { @@ -142,6 +354,13 @@ static int mcux_qtmr_pwm_init(const struct device *dev) QTMR_GetDefaultConfig(&qtmr_config); qtmr_config.primarySource = kQTMR_ClockDivide_1 + (31 - __builtin_clz(config->prescaler)); +#ifdef CONFIG_PWM_CAPTURE + config->irq_config_func(dev); + + qtmr_config.faultFilterCount = CONFIG_PWM_CAPTURE_MCUX_QTMR_FILTER_COUNT; + qtmr_config.faultFilterPeriod = CONFIG_PWM_CAPTURE_MCUX_QTMR_FILTER_PERIOD; +#endif /* CONFIG_PWM_CAPTURE */ + for (int i = 0; i < CHANNEL_COUNT; i++) { QTMR_Init(config->base, i, &qtmr_config); } @@ -152,22 +371,50 @@ static int mcux_qtmr_pwm_init(const struct device *dev) static DEVICE_API(pwm, pwm_mcux_qtmr_driver_api) = { .set_cycles = mcux_qtmr_pwm_set_cycles, .get_cycles_per_sec = mcux_qtmr_pwm_get_cycles_per_sec, +#ifdef CONFIG_PWM_CAPTURE + .configure_capture = mcux_qtmr_configure_capture, + .enable_capture = mcux_qtmr_enable_capture, + .disable_capture = mcux_qtmr_disable_capture, +#endif }; -#define PWM_MCUX_QTMR_DEVICE_INIT(n) \ - PINCTRL_DT_INST_DEFINE(n); \ - static struct pwm_mcux_qtmr_data pwm_mcux_qtmr_data_##n; \ - \ - static const struct pwm_mcux_qtmr_config pwm_mcux_qtmr_config_##n = { \ +#ifdef CONFIG_PWM_CAPTURE +#define QTMR_CONFIG_FUNC(n) \ +static void mcux_qtmr_config_func_##n(const struct device *dev) \ +{ \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + mcux_qtmr_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ +} +#define QTMR_CFG_CAPTURE_INIT(n) \ + .irq_config_func = mcux_qtmr_config_func_##n +#define QTMR_INIT_CFG(n) QTMR_DECLARE_CFG(n, QTMR_CFG_CAPTURE_INIT(n)) +#else /* !CONFIG_PWM_CAPTURE */ +#define QTMR_CONFIG_FUNC(n) +#define QTMR_CFG_CAPTURE_INIT +#define QTMR_INIT_CFG(n) QTMR_DECLARE_CFG(n, QTMR_CFG_CAPTURE_INIT) +#endif /* !CONFIG_PWM_CAPTURE */ + +#define QTMR_DECLARE_CFG(n, CAPTURE_INIT) \ + static const struct pwm_mcux_qtmr_config pwm_mcux_qtmr_config_##n = { \ .base = (TMR_Type *)DT_INST_REG_ADDR(n), \ .prescaler = DT_INST_PROP(n, prescaler), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(n, mcux_qtmr_pwm_init, NULL, &pwm_mcux_qtmr_data_##n, \ - &pwm_mcux_qtmr_config_##n, POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \ - &pwm_mcux_qtmr_driver_api); + CAPTURE_INIT \ + } -DT_INST_FOREACH_STATUS_OKAY(PWM_MCUX_QTMR_DEVICE_INIT) +#define QTMR_DEVICE(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static const struct pwm_mcux_qtmr_config pwm_mcux_qtmr_config_##n; \ + static struct pwm_mcux_qtmr_data pwm_mcux_qtmr_data_##n; \ + DEVICE_DT_INST_DEFINE(n, &mcux_qtmr_pwm_init, NULL, \ + &pwm_mcux_qtmr_data_##n, \ + &pwm_mcux_qtmr_config_##n, \ + POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \ + &pwm_mcux_qtmr_driver_api); \ + QTMR_CONFIG_FUNC(n) \ + QTMR_INIT_CFG(n); + +DT_INST_FOREACH_STATUS_OKAY(QTMR_DEVICE) From d2a7d612ece16038d20fb0b1d094086196e10a60 Mon Sep 17 00:00:00 2001 From: Felix Wang Date: Thu, 16 Oct 2025 15:00:40 +0800 Subject: [PATCH 150/397] drivers: pwm: Fix qtmr set cycles bug. The mcux_qtmr_pwm_set_cycles can not set 100% and 0% duty cycle PWM wave. Set output compare setting based on pulse_cycles and period_cycles: 1. If pulse_cycles is 0, generate 0% duty cycle wave. 2. If pulse_cycles equals period_cycles but not 0, generate 100% duty cycle wave. 3. Otherwise toggle output when compare value matched. Signed-off-by: Felix Wang --- drivers/pwm/pwm_mcux_qtmr.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/pwm_mcux_qtmr.c b/drivers/pwm/pwm_mcux_qtmr.c index 1e70bad12ff91..670adf52a96fc 100644 --- a/drivers/pwm/pwm_mcux_qtmr.c +++ b/drivers/pwm/pwm_mcux_qtmr.c @@ -58,7 +58,7 @@ static int mcux_qtmr_pwm_set_cycles(const struct device *dev, uint32_t channel, { const struct pwm_mcux_qtmr_config *config = dev->config; struct pwm_mcux_qtmr_data *data = dev->data; - uint32_t periodCount, highCount, lowCount; + uint32_t highCount, lowCount; uint16_t reg; if (channel >= CHANNEL_COUNT) { @@ -67,7 +67,6 @@ static int mcux_qtmr_pwm_set_cycles(const struct device *dev, uint32_t channel, } /* Counter values to generate a PWM signal */ - periodCount = period_cycles; highCount = pulse_cycles; lowCount = period_cycles - pulse_cycles; @@ -110,12 +109,12 @@ static int mcux_qtmr_pwm_set_cycles(const struct device *dev, uint32_t channel, reg = config->base->CHANNEL[channel].CTRL; reg &= ~(uint16_t)TMR_CTRL_OUTMODE_MASK; - if (highCount == periodCount) { - /* Set OFLAG output on compare */ - reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_SetOnCompare)); - } else if (periodCount == 0U) { - /* Clear OFLAG output on compare */ + if (pulse_cycles == 0U) { + /* 0% duty cycle, clear OFLAG output on compare */ reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ClearOnCompare)); + } else if (pulse_cycles == period_cycles) { + /* 100% duty cycle, set OFLAG output on compare */ + reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_SetOnCompare)); } else { /* Toggle OFLAG output using alternating compare register */ reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg)); From a3f749085783b110a632f2a333b64a85f6b363a9 Mon Sep 17 00:00:00 2001 From: Felix Wang Date: Thu, 16 Oct 2025 15:52:03 +0800 Subject: [PATCH 151/397] tests: drivers: pwm: pwm_loopback: test improvement. Move TEST_PWM_PERIOD and TEST_PWM_PULSE to kconfig and update macro name with "CONFIG_" prefix. The default timing parameters may be too big for timer peripheral, because they have high frequence, can not generate such slow PWM wave. To keep compatibility, the default value in kconfig are consistent with the code. Signed-off-by: Felix Wang --- tests/drivers/pwm/pwm_loopback/Kconfig | 23 ++++++++++++ .../pwm/pwm_loopback/src/test_pwm_loopback.c | 37 +++++++++---------- 2 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 tests/drivers/pwm/pwm_loopback/Kconfig diff --git a/tests/drivers/pwm/pwm_loopback/Kconfig b/tests/drivers/pwm/pwm_loopback/Kconfig new file mode 100644 index 0000000000000..de8a07138c4f0 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/Kconfig @@ -0,0 +1,23 @@ +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "PWM loopback test" + +config TEST_PWM_PERIOD_NSEC + int "Test PWM period in nanoseconds" + default 100000000 + +config TEST_PWM_PULSE_NSEC + int "Test PWM pulse in nanoseconds" + default 15000000 + +config TEST_PWM_PERIOD_USEC + int "Test PWM period in microseconds" + default 100000 + +config TEST_PWM_PULSE_USEC + int "Test PWM pulse in microseconds" + default 75000 + +source "Kconfig.zephyr" diff --git a/tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.c b/tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.c index 73448d018d630..c0a58231f1a80 100644 --- a/tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.c +++ b/tests/drivers/pwm/pwm_loopback/src/test_pwm_loopback.c @@ -10,11 +10,6 @@ #include "test_pwm_loopback.h" -#define TEST_PWM_PERIOD_NSEC 100000000 -#define TEST_PWM_PULSE_NSEC 15000000 -#define TEST_PWM_PERIOD_USEC 100000 -#define TEST_PWM_PULSE_USEC 75000 - enum test_pwm_unit { TEST_PWM_UNIT_NSEC, TEST_PWM_UNIT_USEC, @@ -107,50 +102,50 @@ static void test_capture(uint32_t period, uint32_t pulse, enum test_pwm_unit uni ZTEST_USER(pwm_loopback, test_pulse_capture) { - test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC, + test_capture(CONFIG_TEST_PWM_PERIOD_NSEC, CONFIG_TEST_PWM_PULSE_NSEC, TEST_PWM_UNIT_NSEC, PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_NORMAL); - test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC, + test_capture(CONFIG_TEST_PWM_PERIOD_USEC, CONFIG_TEST_PWM_PULSE_USEC, TEST_PWM_UNIT_USEC, PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_NORMAL); } ZTEST_USER(pwm_loopback, test_pulse_capture_inverted) { - test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC, + test_capture(CONFIG_TEST_PWM_PERIOD_NSEC, CONFIG_TEST_PWM_PULSE_NSEC, TEST_PWM_UNIT_NSEC, PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_INVERTED); - test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC, + test_capture(CONFIG_TEST_PWM_PERIOD_USEC, CONFIG_TEST_PWM_PULSE_USEC, TEST_PWM_UNIT_USEC, PWM_CAPTURE_TYPE_PULSE | PWM_POLARITY_INVERTED); } ZTEST_USER(pwm_loopback, test_period_capture) { - test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC, + test_capture(CONFIG_TEST_PWM_PERIOD_NSEC, CONFIG_TEST_PWM_PULSE_NSEC, TEST_PWM_UNIT_NSEC, PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_NORMAL); - test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC, + test_capture(CONFIG_TEST_PWM_PERIOD_USEC, CONFIG_TEST_PWM_PULSE_USEC, TEST_PWM_UNIT_USEC, PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_NORMAL); } ZTEST_USER(pwm_loopback, test_period_capture_inverted) { - test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC, + test_capture(CONFIG_TEST_PWM_PERIOD_NSEC, CONFIG_TEST_PWM_PULSE_NSEC, TEST_PWM_UNIT_NSEC, PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_INVERTED); - test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC, + test_capture(CONFIG_TEST_PWM_PERIOD_USEC, CONFIG_TEST_PWM_PULSE_USEC, TEST_PWM_UNIT_USEC, PWM_CAPTURE_TYPE_PERIOD | PWM_POLARITY_INVERTED); } ZTEST_USER(pwm_loopback, test_pulse_and_period_capture) { - test_capture(TEST_PWM_PERIOD_NSEC, TEST_PWM_PULSE_NSEC, + test_capture(CONFIG_TEST_PWM_PERIOD_NSEC, CONFIG_TEST_PWM_PULSE_NSEC, TEST_PWM_UNIT_NSEC, PWM_CAPTURE_TYPE_BOTH | PWM_POLARITY_NORMAL); - test_capture(TEST_PWM_PERIOD_USEC, TEST_PWM_PULSE_USEC, + test_capture(CONFIG_TEST_PWM_PERIOD_USEC, CONFIG_TEST_PWM_PULSE_USEC, TEST_PWM_UNIT_USEC, PWM_CAPTURE_TYPE_BOTH | PWM_POLARITY_NORMAL); } @@ -234,8 +229,8 @@ ZTEST(pwm_loopback, test_continuous_capture) memset(buffer, 0, sizeof(buffer)); k_sem_init(&data.sem, 0, 1); - err = pwm_set(out.dev, out.pwm, PWM_USEC(TEST_PWM_PERIOD_USEC), - PWM_USEC(TEST_PWM_PULSE_USEC), out.flags); + err = pwm_set(out.dev, out.pwm, PWM_USEC(CONFIG_TEST_PWM_PERIOD_USEC), + PWM_USEC(CONFIG_TEST_PWM_PULSE_USEC), out.flags); zassert_equal(err, 0, "failed to set pwm output (err %d)", err); err = pwm_configure_capture(in.dev, in.pwm, @@ -259,7 +254,7 @@ ZTEST(pwm_loopback, test_continuous_capture) err = pwm_enable_capture(in.dev, in.pwm); zassert_equal(err, 0, "failed to enable pwm capture (err %d)", err); - err = k_sem_take(&data.sem, K_USEC(TEST_PWM_PERIOD_USEC * data.buffer_len * 10)); + err = k_sem_take(&data.sem, K_USEC(CONFIG_TEST_PWM_PERIOD_USEC * data.buffer_len * 10)); zassert_equal(err, 0, "pwm capture timed out (err %d)", err); zassert_equal(data.status, 0, "pwm capture failed (err %d)", err); @@ -271,10 +266,12 @@ ZTEST(pwm_loopback, test_continuous_capture) zassert_equal(err, 0, "failed to calculate usec (err %d)", err); if (data.pulse_capture) { - zassert_within(usec, TEST_PWM_PULSE_USEC, TEST_PWM_PULSE_USEC / 100, + zassert_within(usec, CONFIG_TEST_PWM_PULSE_USEC, + CONFIG_TEST_PWM_PULSE_USEC / 100, "pulse capture off by more than 1%%"); } else { - zassert_within(usec, TEST_PWM_PERIOD_USEC, TEST_PWM_PERIOD_USEC / 100, + zassert_within(usec, CONFIG_TEST_PWM_PERIOD_USEC, + CONFIG_TEST_PWM_PERIOD_USEC / 100, "period capture off by more than 1%%"); } } From 5b7745b80ef1113f3470b813d99b4bc5f55638c9 Mon Sep 17 00:00:00 2001 From: Felix Wang Date: Thu, 16 Oct 2025 16:00:50 +0800 Subject: [PATCH 152/397] tests: drivers: pwm: pwm_loopback: Enable QTMR test. Provide kconfig conf file to set timing parameters. Provide overlay file for QTMR channel and pin configuration. Signed-off-by: Felix Wang --- .../mimxrt1180_evk_mimxrt1189_cm33.conf | 5 ++ .../mimxrt1180_evk_mimxrt1189_cm33.overlay | 53 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.conf create mode 100644 tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.conf b/tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.conf new file mode 100644 index 0000000000000..bda6fb5c4e018 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.conf @@ -0,0 +1,5 @@ +CONFIG_TEST_PWM_PERIOD_NSEC=10000000 +CONFIG_TEST_PWM_PULSE_NSEC=1500000 + +CONFIG_TEST_PWM_PERIOD_USEC=10000 +CONFIG_TEST_PWM_PULSE_USEC=7500 diff --git a/tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay b/tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay new file mode 100644 index 0000000000000..3a871d12513cc --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/mimxrt1180_evk_mimxrt1189_cm33.overlay @@ -0,0 +1,53 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + qtmr4_timer0_default: qtmr4_timer0_default { + group0 { + pinmux = <&iomuxc_gpio_ad_00_qtimer4_timer0>; + drive-strength = "normal"; + slew-rate = "fast"; + }; + }; + + qtmr5_timer0_default: qtmr5_timer0_default { + group0 { + pinmux = <&iomuxc_gpio_ad_04_qtimer5_timer0>; + drive-strength = "normal"; + slew-rate = "fast"; + }; + }; +}; + +/* To test this sample, connect + * GPIO_AD_00(J45-15) ---> GPIO_AD_04(J45-5) + */ + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + pwms = <&qtmr4 0 0 PWM_POLARITY_NORMAL>, /* GPIO_AD_00, J45 pin 15, out */ + <&qtmr5 0 0 PWM_POLARITY_NORMAL>; /* GPIO_AD_04, J45 pin 5, in */ + }; +}; + +&qtmr4 { + compatible = "nxp,qtmr-pwm"; + pinctrl-0 = <&qtmr4_timer0_default>; + pinctrl-names = "default"; + #pwm-cells = <3>; + prescaler = <128>; + status = "okay"; +}; + +&qtmr5 { + compatible = "nxp,qtmr-pwm"; + pinctrl-0 = <&qtmr5_timer0_default>; + pinctrl-names = "default"; + #pwm-cells = <3>; + prescaler = <128>; + status = "okay"; +}; From 083565bcaabe33a0395f42ba2b5b853a1e7d549b Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 7 Oct 2025 18:39:04 +0200 Subject: [PATCH 153/397] samples: subsys: usb: testusb: improve usage instructions Add some content in the testusb sample's README to provide a few more hints that can be handy for USB newcomers trying to get the sample running along with testusb. Signed-off-by: Mathieu Choplain --- samples/subsys/usb/testusb/README.rst | 56 ++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/samples/subsys/usb/testusb/README.rst b/samples/subsys/usb/testusb/README.rst index 52a124e05e6fc..3dcaa79a3714a 100644 --- a/samples/subsys/usb/testusb/README.rst +++ b/samples/subsys/usb/testusb/README.rst @@ -25,7 +25,8 @@ To run USB tests: $ sudo modprobe usbtest vendor=0x2fe3 product=0x0009 - The ``usbtest`` module should claim the device: + By checking the kernel diagnostic messages, you should see that the ``usbtest`` + module has claimed the device: .. code-block:: console @@ -39,6 +40,18 @@ To run USB tests: [21746.306153] usbtest 9-1:1.0: Generic USB device [21746.306156] usbtest 9-1:1.0: full-speed {control} tests + .. note:: + The kernel diagnostic messages can be displayed using a command such as + ``journalctl -k -n 20`` or ``dmesg`` (these commands may need to be + executed as root - e.g., ``sudo dmesg``). + + The first line of the diagnostic messages above contains two important + pieces of information that will be needed later on: + + * The USB bus number: ``9`` in ``usb 9-1: [...]`` + + * The device under testing (DUT)'s USB device number: ``16`` in ``USB device number 16`` + #. Use the ``testusb`` tool in ``linux/tools/usb`` inside Linux kernel source directory to start the tests. @@ -49,17 +62,45 @@ To run USB tests: /dev/bus/usb/009/016 test 9, 4.994475 secs /dev/bus/usb/009/016 test 10, 11.990054 secs -#. To run all the tests the Zephyr's VID / PID should be inserted to USB - driver id table. The method for loading the ``usbtest`` driver for our - device is described here: https://lwn.net/Articles/160944/. + .. note:: + In this command, replace ``009`` and ``016`` with the USB bus number and + DUT's device number, respectively, as found in the debugging messages on + your host. Do not forget to pad with zeros. - Since we use the "Gadget Zero" interface we specify reference device - ``0525:a4a0``. +#. The Linux ``usbtest`` driver does not support this Zephyr sample's VID/PID + so we cannot run all the tests by default. To run all the tests, we can use + the feature described in the `"Dynamic USB device IDs" LWN.net article`_ to + write one of the supported VID/PID pair to the ``new_id`` sysfs attribute + of our device. Since the sample implements an interface similar to the + "Gadget Zero" interface, we specify reference device ``0525:a4a0``. .. code-block:: console $ sudo sh -c "echo 0x2fe3 0x0009 0 0x0525 0xa4a0 > /sys/bus/usb/drivers/usbtest/new_id" + .. note:: + This step can be performed right after loading the ``usbtest`` module instead. + Otherwise, you may have to disconnect and reconnect the DUT in order for the + Gadget Zero interface to become enabled. + + Once this step has been performed, the kernel diagnostic messages upon connecting + the DUT should be similar to the following: + + .. code-block:: + + [100458.667241] usb 3-5.3.1: new full-speed USB device number 38 using xhci_hcd + [100458.761743] usb 3-5.3.1: New USB device found, idVendor=2fe3, idProduct=0009, bcdDevice= 4.02 + [100458.761750] usb 3-5.3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + [100458.761753] usb 3-5.3.1: Product: Zephyr testusb sample + [100458.761755] usb 3-5.3.1: Manufacturer: Zephyr Project + [100458.761757] usb 3-5.3.1: SerialNumber: 2034354E32365007003C001C + [100458.773785] usbtest 3-5.3.1:1.0: Linux gadget zero + [100458.773791] usbtest 3-5.3.1:1.0: full-speed {control in/out bulk-in bulk-out} tests (+alt) + [100458.773858] usbtest 3-5.3.1:1.1: Linux gadget zero + [100458.773859] usbtest 3-5.3.1:1.1: full-speed {control in/out int-in int-out} tests (+alt) + [100458.773914] usbtest 3-5.3.1:1.2: Linux gadget zero + [100458.773916] usbtest 3-5.3.1:1.2: full-speed {control in/out iso-in iso-out} tests (+alt) + #. Use the ``testusb`` tool in ``linux/tools/usb`` inside Linux kernel source directory to start the tests. @@ -90,3 +131,6 @@ To run USB tests: /dev/bus/usb/009/017 test 27, 56.911052 secs /dev/bus/usb/009/017 test 28, 34.163089 secs /dev/bus/usb/009/017 test 29, 3.983999 secs + +.. _"Dynamic USB device IDs" LWN.net article: + https://lwn.net/Articles/160944/ From 1ec9339a309ab88be7abfcbb1dfe14e16197dddd Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 2 Oct 2025 14:18:01 -0700 Subject: [PATCH 154/397] soc: intel_adsp/ace: allows more spin relax loop per CPU This allows adding the CPU ID to the number of NOPs in the custom arch_spin_relax(). With the same number of NOPs for all CPUs, it is possible to have them all doing RCW transactions at the same time over and over again if they enter and exit the spin relax loop at the same time. This behavior has been observed when doing lots of context switching, like in the SMP switching stress test. So adds a new kconfig to fine tune the relax loop behavior if needed. The new kconfig allows adding the CPU ID to the number of NOPs which will add some minimal offsetting to workaround the above mentioned situation. Signed-off-by: Daniel Leung --- soc/intel/intel_adsp/ace/Kconfig | 9 +++++++++ soc/intel/intel_adsp/ace/spin_relax.c | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/soc/intel/intel_adsp/ace/Kconfig b/soc/intel/intel_adsp/ace/Kconfig index cdd2749915d3b..a7e225923aa4e 100644 --- a/soc/intel/intel_adsp/ace/Kconfig +++ b/soc/intel/intel_adsp/ace/Kconfig @@ -53,3 +53,12 @@ config SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS help Specify the number of NOPs in Intel Audio DSP specific arch_spin_relax(). + +config SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID + bool "Add CPU ID to offset NOPs" + depends on SOC_SERIES_INTEL_ADSP_ACE_CUSTOM_MORE_SPIN_RELAX_NOPS + help + Add CPU ID to the number of NOPs in arch_spin_relax(). + This is to add some variations to the loop for each CPU to + further avoid them hitting the RCW transactions at the same + time. diff --git a/soc/intel/intel_adsp/ace/spin_relax.c b/soc/intel/intel_adsp/ace/spin_relax.c index 073deb5a6d07d..0abf94398db1b 100644 --- a/soc/intel/intel_adsp/ace/spin_relax.c +++ b/soc/intel/intel_adsp/ace/spin_relax.c @@ -9,13 +9,20 @@ #include #include +#include + #ifdef CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS void arch_spin_relax(void) { register uint32_t remaining = CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS; +#if defined(CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID) + remaining += arch_proc_id(); +#endif /* CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID */ + while (remaining > 0) { -#if (CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS % 4) == 0 +#if !defined(CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID) && \ + (CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS % 4) == 0 remaining -= 4; /* From d68f592e7b2ca56957164b3d29f53712095a094a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 3 Oct 2025 10:11:30 -0700 Subject: [PATCH 155/397] tests: kernel/smp: intel_adsp needs more relaxing NOPs It has been observed that, during the switching stress test, the context switching becomes very slow due to enough CPUs doing RCW transaction on hardware bus (e.g. spin locks). Since the number of NOPs are the same for all CPUs, they are simply entering and exiting the relax loop at the same time, and hitting the bus with RCW transactions at the same time. Not exactly a deadlock but it slows down the execution enough to result in the test timing out. The SoC layer has added an option to offset the number of NOPs per CPU by adding the CPU to the number of NOPs. So enabling it for the Intel ADSP boards to workaround the above mentioned issue. I haven't encountered another slowdown after turning on this option. So hopefully this lowers the probability of that happening such that a simple retry can pass the test. Signed-off-by: Daniel Leung --- tests/kernel/smp/boards/intel_adsp_ace15_mtpm.conf | 3 +++ tests/kernel/smp/boards/intel_adsp_ace20_lnl.conf | 3 +++ tests/kernel/smp/boards/intel_adsp_ace30_ptl.conf | 3 +++ tests/kernel/smp/boards/intel_adsp_ace40_nvl.conf | 3 +++ 4 files changed, 12 insertions(+) create mode 100644 tests/kernel/smp/boards/intel_adsp_ace15_mtpm.conf create mode 100644 tests/kernel/smp/boards/intel_adsp_ace20_lnl.conf create mode 100644 tests/kernel/smp/boards/intel_adsp_ace30_ptl.conf create mode 100644 tests/kernel/smp/boards/intel_adsp_ace40_nvl.conf diff --git a/tests/kernel/smp/boards/intel_adsp_ace15_mtpm.conf b/tests/kernel/smp/boards/intel_adsp_ace15_mtpm.conf new file mode 100644 index 0000000000000..3db4d23770ee0 --- /dev/null +++ b/tests/kernel/smp/boards/intel_adsp_ace15_mtpm.conf @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID=y diff --git a/tests/kernel/smp/boards/intel_adsp_ace20_lnl.conf b/tests/kernel/smp/boards/intel_adsp_ace20_lnl.conf new file mode 100644 index 0000000000000..3db4d23770ee0 --- /dev/null +++ b/tests/kernel/smp/boards/intel_adsp_ace20_lnl.conf @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID=y diff --git a/tests/kernel/smp/boards/intel_adsp_ace30_ptl.conf b/tests/kernel/smp/boards/intel_adsp_ace30_ptl.conf new file mode 100644 index 0000000000000..3db4d23770ee0 --- /dev/null +++ b/tests/kernel/smp/boards/intel_adsp_ace30_ptl.conf @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID=y diff --git a/tests/kernel/smp/boards/intel_adsp_ace40_nvl.conf b/tests/kernel/smp/boards/intel_adsp_ace40_nvl.conf new file mode 100644 index 0000000000000..3db4d23770ee0 --- /dev/null +++ b/tests/kernel/smp/boards/intel_adsp_ace40_nvl.conf @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_INTEL_ADSP_ACE_NUM_SPIN_RELAX_NOPS_ADD_CPU_ID=y From 14503cb7f7690cd6281cbb21caac3b023c9b2559 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 2 Oct 2025 10:57:05 -0700 Subject: [PATCH 156/397] kernel: mem_domain: keep track of threads only if needed Adds a new kconfig CONFIG_MEM_DOMAIN_HAS_THREAD_LIST so that only the architectures requiring to keep track of threads in memory domains will have the necessary list struct inside the memory domain structs. Saves a few bytes for those arch not needing this. Also rename the struct fields to be most descriptive of what they are. Signed-off-by: Daniel Leung --- arch/Kconfig | 1 + arch/arm64/core/cortex_r/arm_mpu.c | 4 ++-- include/zephyr/app_memory/mem_domain.h | 9 +++++++-- include/zephyr/kernel/thread.h | 4 +++- kernel/Kconfig.mem_domain | 9 +++++++++ kernel/mem_domain.c | 18 ++++++++++++++---- 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 7bcfb4d3ffd8d..4fca0c3c60262 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -57,6 +57,7 @@ config ARM64 select ARCH_HAS_DEMAND_MAPPING select ARCH_SUPPORTS_EVICTION_TRACKING select EVICTION_TRACKING if DEMAND_PAGING + select MEM_DOMAIN_HAS_THREAD_LIST if ARM_MPU help ARM64 (AArch64) architecture diff --git a/arch/arm64/core/cortex_r/arm_mpu.c b/arch/arm64/core/cortex_r/arm_mpu.c index 3053d90cb75f6..69fc72acda35a 100644 --- a/arch/arm64/core/cortex_r/arm_mpu.c +++ b/arch/arm64/core/cortex_r/arm_mpu.c @@ -760,8 +760,8 @@ static int configure_domain_partitions(struct k_mem_domain *domain) struct k_thread *thread; int ret; - SYS_DLIST_FOR_EACH_CONTAINER(&domain->mem_domain_q, thread, - mem_domain_info.mem_domain_q_node) { + SYS_DLIST_FOR_EACH_CONTAINER(&domain->thread_mem_domain_list, thread, + mem_domain_info.thread_mem_domain_node) { ret = configure_dynamic_mpu_regions(thread); if (ret != 0) { return ret; diff --git a/include/zephyr/app_memory/mem_domain.h b/include/zephyr/app_memory/mem_domain.h index 1b97ab4d333ff..977d6b2aaec12 100644 --- a/include/zephyr/app_memory/mem_domain.h +++ b/include/zephyr/app_memory/mem_domain.h @@ -83,8 +83,13 @@ struct k_mem_domain { #endif /* CONFIG_ARCH_MEM_DOMAIN_DATA */ /** partitions in the domain */ struct k_mem_partition partitions[CONFIG_MAX_DOMAIN_PARTITIONS]; - /** Doubly linked list of member threads */ - sys_dlist_t mem_domain_q; +#ifdef CONFIG_MEM_DOMAIN_HAS_THREAD_LIST + /** Doubly linked list of member threads, + * pointer to the thread_mem_domain_node inside + * each thread's memory domain info struct. + */ + sys_dlist_t thread_mem_domain_list; +#endif /* CONFIG_MEM_DOMAIN_HAS_THREAD_LIST */ /** number of active partitions in the domain */ uint8_t num_partitions; }; diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index 43721f1249534..db7713d6d407d 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -178,8 +178,10 @@ typedef struct _thread_stack_info _thread_stack_info_t; #if defined(CONFIG_USERSPACE) struct _mem_domain_info { +#ifdef CONFIG_MEM_DOMAIN_HAS_THREAD_LIST /** memory domain queue node */ - sys_dnode_t mem_domain_q_node; + sys_dnode_t thread_mem_domain_node; +#endif /* CONFIG_MEM_DOMAIN_HAS_THREAD_LIST */ /** memory domain of the thread */ struct k_mem_domain *mem_domain; }; diff --git a/kernel/Kconfig.mem_domain b/kernel/Kconfig.mem_domain index ddf8a4cc57a6d..03d6e1239261c 100644 --- a/kernel/Kconfig.mem_domain +++ b/kernel/Kconfig.mem_domain @@ -76,4 +76,13 @@ config MEM_DOMAIN_ISOLATED_STACKS Regardless of this settings, threads cannot access the stacks of threads outside of their domains. +config MEM_DOMAIN_HAS_THREAD_LIST + bool + help + If enabled, there is a doubly linked list in each memory domain + struct to keep track of the threads associated with this + particular memory domain. + + This is selected by architecture needing this to function. + endmenu diff --git a/kernel/mem_domain.c b/kernel/mem_domain.c index 16b337acf011d..dc1cfe01126a1 100644 --- a/kernel/mem_domain.c +++ b/kernel/mem_domain.c @@ -113,7 +113,10 @@ int k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts, domain->num_partitions = 0U; (void)memset(domain->partitions, 0, sizeof(domain->partitions)); - sys_dlist_init(&domain->mem_domain_q); + +#ifdef CONFIG_MEM_DOMAIN_HAS_THREAD_LIST + sys_dlist_init(&domain->thread_mem_domain_list); +#endif /* CONFIG_MEM_DOMAIN_HAS_THREAD_LIST */ #ifdef CONFIG_ARCH_MEM_DOMAIN_DATA ret = arch_mem_domain_init(domain); @@ -265,8 +268,12 @@ static int add_thread_locked(struct k_mem_domain *domain, __ASSERT_NO_MSG(thread != NULL); LOG_DBG("add thread %p to domain %p\n", thread, domain); - sys_dlist_append(&domain->mem_domain_q, - &thread->mem_domain_info.mem_domain_q_node); + +#ifdef CONFIG_MEM_DOMAIN_HAS_THREAD_LIST + sys_dlist_append(&domain->thread_mem_domain_list, + &thread->mem_domain_info.thread_mem_domain_node); +#endif /* CONFIG_MEM_DOMAIN_HAS_THREAD_LIST */ + thread->mem_domain_info.mem_domain = domain; #ifdef CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API @@ -283,7 +290,10 @@ static int remove_thread_locked(struct k_thread *thread) __ASSERT_NO_MSG(thread != NULL); LOG_DBG("remove thread %p from memory domain %p\n", thread, thread->mem_domain_info.mem_domain); - sys_dlist_remove(&thread->mem_domain_info.mem_domain_q_node); + +#ifdef CONFIG_MEM_DOMAIN_HAS_THREAD_LIST + sys_dlist_remove(&thread->mem_domain_info.thread_mem_domain_node); +#endif /* CONFIG_MEM_DOMAIN_HAS_THREAD_LIST */ #ifdef CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API ret = arch_mem_domain_thread_remove(thread); From c577da8865434001c1e95fd7de16cb5b50f5f115 Mon Sep 17 00:00:00 2001 From: John Batch Date: Tue, 30 Sep 2025 09:36:49 -0700 Subject: [PATCH 157/397] dts: infineon: psc3m5 devicetree changes to support HPPASS ADC * Separates HPPASS and HPPASS SAR ADC in the device tree * Makes HPPASS SAR ADC a child of the HPPASS system to reflect hardware architecture. * Adds binding files for HPPASS SAR ADC driver. Signed-off-by: John Batch --- dts/arm/infineon/cat1b/psc3/psc3.dtsi | 20 +++-- dts/arm/infineon/cat1b/psc3/psc3_s.dtsi | 20 +++-- dts/bindings/adc/infineon,hppass-sar-adc.yaml | 77 +++++++++++++++++++ modules/hal_infineon/CMakeLists.txt | 4 + modules/hal_infineon/Kconfig | 12 ++- .../hal_infineon/mtb-pdl-cat1/CMakeLists.txt | 5 ++ .../zephyr-ifx-cycfg/CMakeLists.txt | 8 ++ 7 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 dts/bindings/adc/infineon,hppass-sar-adc.yaml diff --git a/dts/arm/infineon/cat1b/psc3/psc3.dtsi b/dts/arm/infineon/cat1b/psc3/psc3.dtsi index 4fd0e445ba677..e5841caf190b0 100644 --- a/dts/arm/infineon/cat1b/psc3/psc3.dtsi +++ b/dts/arm/infineon/cat1b/psc3/psc3.dtsi @@ -128,12 +128,20 @@ #gpio-cells = <2>; }; - adc0: adc@42b70000 { - compatible = "infineon,adc-hppass-saradc"; - reg = <0x42b70000 0x10000>; - interrupts = <109 4>; - status = "disabled"; - #io-channel-cells = <1>; + hppass_analog0: analog@42b00000 { + reg = <0x42b00000 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + adc0: adc@70000 { + compatible = "infineon,hppass-sar-adc"; + /* Offset within HPPASS analog region => 0x42b70000 physical */ + reg = <0x00070000 0x10000>; + interrupts = <109 4>; + status = "disabled"; + #io-channel-cells = <1>; + }; }; ipc0: ipc@421d0000 { diff --git a/dts/arm/infineon/cat1b/psc3/psc3_s.dtsi b/dts/arm/infineon/cat1b/psc3/psc3_s.dtsi index 22ad1853b7c48..ac013a84dc21d 100644 --- a/dts/arm/infineon/cat1b/psc3/psc3_s.dtsi +++ b/dts/arm/infineon/cat1b/psc3/psc3_s.dtsi @@ -128,12 +128,20 @@ #gpio-cells = <2>; }; - adc0: adc@52b70000 { - compatible = "infineon,adc-hppass-saradc"; - reg = <0x52b70000 0x10000>; - interrupts = <109 4>; - status = "disabled"; - #io-channel-cells = <1>; + hppass_analog0: analog@52b00000 { + reg = <0x52b00000 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + adc0: adc@70000 { + compatible = "infineon,hppass-sar-adc"; + /* Offset within HPPASS analog region */ + reg = <0x00070000 0x10000>; + interrupts = <109 4>; + status = "disabled"; + #io-channel-cells = <1>; + }; }; ipc0: ipc@521d0000 { diff --git a/dts/bindings/adc/infineon,hppass-sar-adc.yaml b/dts/bindings/adc/infineon,hppass-sar-adc.yaml new file mode 100644 index 0000000000000..7e073d891ff00 --- /dev/null +++ b/dts/bindings/adc/infineon,hppass-sar-adc.yaml @@ -0,0 +1,77 @@ +# Copyright (c) 2025 Infineon Technologies AG, +# or an affiliate of Infineon Technologies AG. +# +# SPDX-License-Identifier: Apache-2.0 + +title: PSOC C3 HPPASS SAR ADC + +description: | + Infineon PSOC C3 HPPASS SAR ADC + + The HPPASS (High Performance Programmable Analog Sub-System) SAR ADC + provides high-resolution analog-to-digital conversion capabilities + for the PSOC C3 family of microcontrollers. + + Each ADC channel corresponds to a dedicated analog input pin, except for + the last four sampler inputs which are muxed. See the device datasheet for + pin assignments and mux options. + + Dependency: This ADC node must be a child of the HPPASS analog subsystem + node ("infineon,hppass-analog"), which provides clock, power, and reference + resources. + +compatible: "infineon,hppass-sar-adc" + +include: adc-controller.yaml + +properties: + reg: + required: true + description: Base address of the HPPASS SAR ADC registers + + interrupts: + required: true + description: Interrupt configuration for the HPPASS SAR ADC + + "#io-channel-cells": + const: 1 + description: Number of cells in an io-channel specifier + + clock-frequency: + type: int + description: | + ADC clock frequency in Hz. If not specified, the driver will use + the default clock configuration. + + vref-mv: + type: int + default: 3300 + description: | + Internal reference voltage in millivolts. + + offset-cal: + type: boolean + description: + Enables Self-Calibration for offset correction within the ADC. If left disabled, + the factory calibration for offset correction will be used. + + gain-cal: + type: boolean + description: | + Enables Self-Calibration for gain within the ADC. If left disabled, + the factory calibration for gain will be used. + + linear-cal: + type: boolean + description: | + Enables Self-Calibration for linearity correction within the ADC. If left disabled, + the factory calibration for linearity will be used. + + ref-internal-source: + type: boolean + description: | + Selects whether the ADC uses internal (true) or external (false) reference. + External reference recommended for best performance. + +io-channel-cells: + - input diff --git a/modules/hal_infineon/CMakeLists.txt b/modules/hal_infineon/CMakeLists.txt index dd400d5ef3b00..ac5eb53d7fc00 100644 --- a/modules/hal_infineon/CMakeLists.txt +++ b/modules/hal_infineon/CMakeLists.txt @@ -70,6 +70,10 @@ if(CONFIG_SOC_FAMILY_INFINEON_EDGE) add_subdirectory(mtb-dsl-pse8xxgp) endif() +if(CONFIG_SOC_SERIES_PSC3) + add_subdirectory(zephyr-ifx-cycfg) +endif() + ## Add Wi-Fi assets for AIROC devices if (CONFIG_WIFI_AIROC) add_subdirectory(whd-expansion) diff --git a/modules/hal_infineon/Kconfig b/modules/hal_infineon/Kconfig index 2b54d74265bd4..dd6a637cc6a49 100644 --- a/modules/hal_infineon/Kconfig +++ b/modules/hal_infineon/Kconfig @@ -14,10 +14,20 @@ config USE_INFINEON_ADC help Enable Analog-to-Digital Converter (ADC) HAL module driver for Infineon devices +config USE_INFINEON_HPPASS_SAR_ADC + bool + help + Enable Infineon HPPASS SAR ADC PDL library support + +config USE_INFINEON_HPPASS_ANALOG + bool + help + Enable Infineon HPPASS Analog PDL library support + config USE_INFINEON_DMA bool help - Enable ADC HAL module driver for Infineon devices + Enable DMA HAL module driver for Infineon devices config USE_INFINEON_I2C bool diff --git a/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt b/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt index bbe29ceda3085..feaa7d88799b6 100644 --- a/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt +++ b/modules/hal_infineon/mtb-pdl-cat1/CMakeLists.txt @@ -56,6 +56,11 @@ else() zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_ADC ${pdl_drv_dir}/source/cy_sar.c) endif() +zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_HPPASS_SAR_ADC ${pdl_drv_dir}/source/cy_hppass_sar.c) +zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_HPPASS_SAR_ADC ${pdl_drv_dir}/source/cy_hppass.c) +zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_HPPASS_SAR_ADC ${pdl_drv_dir}/source/cy_hppass_csg.c) +zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_HPPASS_SAR_ADC ${pdl_drv_dir}/source/cy_hppass_ac.c) + if(CONFIG_USE_INFINEON_TRNG) zephyr_library_sources(${pdl_drv_dir}/source/cy_crypto.c) zephyr_library_sources(${pdl_drv_dir}/source/cy_crypto_core_trng_v1.c) diff --git a/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt b/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt index 7884d5d65e52c..1af8accd8c401 100644 --- a/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt +++ b/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt @@ -9,3 +9,11 @@ if(CONFIG_SOC_FAMILY_INFINEON_EDGE) zephyr_include_directories(${zephyr_ifx_cycfg_dir}) zephyr_library_sources(${zephyr_ifx_cycfg_dir}/cycfg_qspi_memslot.c) endif() + +if(CONFIG_SOC_SERIES_PSC3) + set(zephyr_ifx_cycfg_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/zephyr-ifx-cycfg/soc_psc3) + + zephyr_include_directories(${zephyr_ifx_cycfg_dir}) + zephyr_library_sources(${zephyr_ifx_cycfg_dir}/ifx_hppass_analog.c) + zephyr_library_sources(${zephyr_ifx_cycfg_dir}/ifx_cycfg_init.c) +endif() From 2b745c8eb6202f929c5784e8472b0a465dd7296d Mon Sep 17 00:00:00 2001 From: John Batch Date: Tue, 30 Sep 2025 09:56:19 -0700 Subject: [PATCH 158/397] drivers: adc: Infineon HPPASS SAR ADC Driver Adds HPPASS SAR ADC driver and HPPASS Analog driver files to support ADC conversion for the PSOC C3 family of MCUs. Signed-off-by: John Batch --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.ifx_hppass_sar | 31 + drivers/adc/adc_ifx_hppass_sar.c | 765 ++++++++++++++++++ .../zephyr-ifx-cycfg/CMakeLists.txt | 2 +- soc/infineon/cat1b/psc3/soc.c | 11 +- 6 files changed, 802 insertions(+), 10 deletions(-) create mode 100644 drivers/adc/Kconfig.ifx_hppass_sar create mode 100644 drivers/adc/adc_ifx_hppass_sar.c diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index c29b99793e98f..6468638e7057a 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -48,6 +48,7 @@ zephyr_library_sources_ifdef(CONFIG_ADC_GECKO_ADC adc_gecko.c) zephyr_library_sources_ifdef(CONFIG_ADC_SILABS_IADC adc_silabs_iadc.c) zephyr_library_sources_ifdef(CONFIG_ADC_SILABS_SIWX91X adc_silabs_siwx91x.c) zephyr_library_sources_ifdef(CONFIG_ADC_INFINEON_CAT1 adc_ifx_cat1.c) +zephyr_library_sources_ifdef(CONFIG_ADC_INFINEON_HPPASS_SAR adc_ifx_hppass_sar.c) zephyr_library_sources_ifdef(CONFIG_ADC_SMARTBOND_GPADC adc_smartbond_gpadc.c) zephyr_library_sources_ifdef(CONFIG_ADC_SMARTBOND_SDADC adc_smartbond_sdadc.c) zephyr_library_sources_ifdef(CONFIG_ADC_TLA202X adc_tla202x.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 8a4597108c599..e400fcfcb8a96 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -136,6 +136,8 @@ source "drivers/adc/Kconfig.silabs" source "drivers/adc/Kconfig.ifx_cat1" +source "drivers/adc/Kconfig.ifx_hppass_sar" + source "drivers/adc/Kconfig.smartbond" source "drivers/adc/Kconfig.tla202x" diff --git a/drivers/adc/Kconfig.ifx_hppass_sar b/drivers/adc/Kconfig.ifx_hppass_sar new file mode 100644 index 0000000000000..30fc8491db583 --- /dev/null +++ b/drivers/adc/Kconfig.ifx_hppass_sar @@ -0,0 +1,31 @@ +# Copyright (c) 2025 Infineon Technologies AG, +# or an affiliate of Infineon Technologies AG. +# +# SPDX-License-Identifier: Apache-2.0 + +# Infineon HPPASS SAR ADC configuration options + +config ADC_INFINEON_HPPASS_SAR + bool "Infineon HPPASS SAR ADC driver" + default y + depends on DT_HAS_INFINEON_HPPASS_SAR_ADC_ENABLED + select USE_INFINEON_HPPASS_SAR_ADC + select ADC_CONFIGURABLE_INPUTS + help + This option enables the ADC driver for Infineon PSOC C3 + HPPASS (High Performance Programmable Analog Sub-System) SAR ADC. + + The HPPASS SAR ADC provides 12-bit analog-to-digital + conversion capabilities + +if ADC_INFINEON_HPPASS_SAR + +config ADC_INFINEON_HPPASS_SAR_INIT_PRIORITY + int "Infineon HPPASS SAR ADC driver init priority" + default 80 + help + Infineon HPPASS SAR ADC driver initialization priority. + This should be higher than the HPPASS_ANALOG_INIT_PRIORITY + to ensure the analog subsystem is initialized first. + +endif # ADC_INFINEON_HPPASS_SAR diff --git a/drivers/adc/adc_ifx_hppass_sar.c b/drivers/adc/adc_ifx_hppass_sar.c new file mode 100644 index 0000000000000..d3dcf3d8dff1b --- /dev/null +++ b/drivers/adc/adc_ifx_hppass_sar.c @@ -0,0 +1,765 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief ADC HPPASS SAR driver + * + * Driver for the HPPASS SAR ADC used in the Infineon PSOC C3 series. + */ + +#define DT_DRV_COMPAT infineon_hppass_sar_adc + +#include +#include +#include +#include +#include +#include +#include + +#include "ifx_hppass_analog.h" +#include "cy_pdl.h" + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#define IFX_HPPASS_SAR_ADC_RESOLUTION (12u) /* ADC Resolution for this device is fixed at 12-bit*/ + +LOG_MODULE_REGISTER(ifx_hppass_sar_adc, CONFIG_ADC_LOG_LEVEL); + +/** + * @brief HPPASS Configuration Structure + * + * Basic configuration for the HPPASS analog subsystem. By default this structure configures the + * HPPASS AC to enable the ADC. Other functions of the HPPASS system are not enabled by default. + */ +const cy_stc_hppass_sar_t ifx_hppass_sar_pdl_cfg_struct_default = { + .vref = CY_HPPASS_SAR_VREF_EXT, + .lowSupply = false, + .offsetCal = false, + .linearCal = false, + .gainCal = false, + .chanId = false, + .aroute = true, + .dirSampEnMsk = 0, + .muxSampEnMsk = 0, + .holdCount = 29U, + .dirSampGain = { + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + }, + .muxSampGain = { + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + CY_HPPASS_SAR_SAMP_GAIN_1, + }, + .sampTime = { + 32U, + 32U, + 32U, + }, + .chan = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }, + .grp = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + .limit = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + .muxMode = { + CY_HPPASS_SAR_MUX_SEQ, + CY_HPPASS_SAR_MUX_SEQ, + CY_HPPASS_SAR_MUX_SEQ, + CY_HPPASS_SAR_MUX_SEQ, + }, + .fir = { + NULL, + NULL, + }, + .fifo = NULL, +}; + +/* + * Device supports up to 28 channels. Note that channels 12-15, 16-19, 20-23, and 24-27 are + * multiplexed in hardware and share samplers. + */ +#define HPPASS_SAR_ADC_MAX_CHANNELS CY_HPPASS_SAR_CHAN_NUM +#define DIRECT_CHANNEL_CNT CY_HPPASS_SAR_DIR_SAMP_NUM +#define MUXED_CHANNELS_PER_SAMPLER 4 +#define IFX_HPPASS_SAR_SAMPLER_GAIN_MSK 0x03 +#define IFX_HPPASS_SAR_SAMPLER_GAIN_WIDTH 2 + +/* + * Configuration and data structures + */ +struct ifx_hppass_sar_adc_config { + uint8_t irq_priority; + IRQn_Type irq_num; + void (*irq_func)(void); + uint16_t dir_samp_en_mask; + uint16_t mux_samp_en_mask; + bool vref_internal_source; + bool gain_cal; + bool offset_cal; + bool linear_cal; +}; + +/** + * @brief HPPASS SAR ADC channel configuration + */ +struct ifx_hppass_sar_adc_channel_config { + /** Channel number */ + uint8_t id; + uint8_t input_positive; + /* + * PDL channel configuration structure. The PDL will reapply channel configurations for all + * channels any time a change is made to any channel configuration. Store the PDL + * configuration for this channel so we have a copy to be used for this action. + */ + cy_stc_hppass_sar_chan_t pdl_channel_cfg; +}; + +/** + * @brief HPPASS SAR ADC device data + */ +struct ifx_hppass_sar_adc_data { + /* ADC context for async operations */ + struct adc_context ctx; + const struct device *dev; + /* PDL ADC configuration structure */ + cy_stc_hppass_sar_t hppass_sar_obj; + /* channel configurations for all channels (used or not)*/ + struct ifx_hppass_sar_adc_channel_config hppass_sar_chan_obj[HPPASS_SAR_ADC_MAX_CHANNELS]; + /* Bitmask of enabled channels */ + uint32_t enabled_channels; + /* Conversion buffer */ + uint16_t *buffer; + /* Repeat buffer for continuous sampling */ + uint16_t *repeat_buffer; + /** Conversion result */ + int result; +}; + +/* + * ADC Channels 12-28 are grouped together in hardware using a mux. The grouping is as follows: + * Sampler 12: Channels 12-15, + * Sampler 13: Channels 16-19, + * Sampler 14: Channels 20-23, + * Sampler 15: Channels 24-27 + */ +#define ADC_SAMPLER_12_CHANNEL_GROUP 0x0000F000 +#define ADC_SAMPLER_13_CHANNEL_GROUP 0x000F0000 +#define ADC_SAMPLER_14_CHANNEL_GROUP 0x00F00000 +#define ADC_SAMPLER_15_CHANNEL_GROUP 0x0F000000 +#define ADC_SAMPLER_DIRECT_MASK 0x0FFF + +/** + * @brief Configure HPPASS SAR ADC group + * + * @param channels Bitmask of channels to be enabled in the group + * @param group Group number to configure (0-7) + * + * HPPASS SAR ADC has 8 groups. ADC samplers can be added to a group, and will be sampled + * simultaneously and converted sequentially when the group is triggered. Note that only one MUXed + * channel can be included in a mux group. + */ +static int ifx_hppass_sar_configure_group(uint32_t channels, uint32_t group) +{ + cy_stc_hppass_sar_grp_t group_cfg = {0}; + + /* Check that no more than one channel is selected from each muxed group */ + if (POPCOUNT(channels & ADC_SAMPLER_12_CHANNEL_GROUP) > 1 || + POPCOUNT(channels & ADC_SAMPLER_13_CHANNEL_GROUP) > 1 || + POPCOUNT(channels & ADC_SAMPLER_14_CHANNEL_GROUP) > 1 || + POPCOUNT(channels & ADC_SAMPLER_15_CHANNEL_GROUP) > 1) { + + return -EINVAL; + } + + group_cfg.trig = CY_HPPASS_SAR_TRIG_0; /* TRIG_0 used for SW Trigger */ + group_cfg.sampTime = CY_HPPASS_SAR_SAMP_TIME_DISABLED; + + /* Enable directly sampled channels. */ + group_cfg.dirSampMsk = channels & ADC_SAMPLER_DIRECT_MASK; + + /* Enable Muxed channels. We need to determine if each sampler is enabled and what the mux + * should be set to for the sampler. + */ + group_cfg.muxSampMsk = 0; + for (int channel_num = DIRECT_CHANNEL_CNT; channel_num < HPPASS_SAR_ADC_MAX_CHANNELS; + channel_num++) { + if (channels & (1 << channel_num)) { + int sampler_num = + (channel_num - DIRECT_CHANNEL_CNT) / MUXED_CHANNELS_PER_SAMPLER; + int mux_setting = + (channel_num - DIRECT_CHANNEL_CNT) % MUXED_CHANNELS_PER_SAMPLER; + group_cfg.muxSampMsk |= (1 << sampler_num); + group_cfg.muxChanIdx[sampler_num] = mux_setting; + } + } + + if (Cy_HPPASS_SAR_GroupConfig(group, &group_cfg) != 0) { + LOG_ERR("ADC Group configuration failed"); + return -EINVAL; + } + + /* CrossTalkAdjust must be called any time groups are reconfigured. */ + Cy_HPPASS_SAR_CrossTalkAdjust((uint8_t)1U << group); + return 0; +} + +/** + * @brief Read results of the specified group of channels + * + * @param channels Bitmask of channels to read results for + * @param data Pointer to ADC data structure + * + * Helper function to read all the results for the specified channels into the data buffer. + */ +static void ifx_hppass_get_group_results(uint32_t channels, struct ifx_hppass_sar_adc_data *data) +{ + if (data->buffer == NULL) { + LOG_ERR("ADC data buffer is NULL"); + return; + } + + for (size_t i = 0; i < HPPASS_SAR_ADC_MAX_CHANNELS; i++) { + if (channels & (1 << i)) { + int16_t result = Cy_HPPASS_SAR_Result_ChannelRead(i); + *data->buffer++ = result; + } + } +} + +/** + * @brief Start ADC conversion + * + * @param ctx ADC context + * + * The HPPASS SAR ADC uses a grouping functionality to simultaneously sample then convert multiple + * channels with one trigger input. All channels in the ADC Sequence are added to a group and a + * conversion is triggered. + */ +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct ifx_hppass_sar_adc_data *data = + CONTAINER_OF(ctx, struct ifx_hppass_sar_adc_data, ctx); + const struct adc_sequence *sequence = &ctx->sequence; + uint32_t result_status; + + data->repeat_buffer = data->buffer; + if (data->buffer == NULL || sequence->buffer_size == 0) { + data->result = -ENOMEM; + return; + } + + if (sequence->channels == 0) { + LOG_ERR("No channels specified"); + data->result = -EINVAL; + } else if (ifx_hppass_sar_configure_group(sequence->channels, 0) != 0) { + LOG_ERR("Invalid channel group selection"); + data->result = -EINVAL; + } else { + /* Trigger SAR ADC group 0 conversion */ + Cy_HPPASS_SAR_Result_ClearStatus(sequence->channels); + Cy_HPPASS_SetFwTrigger(CY_HPPASS_TRIG_0_MSK); + +#if defined(CONFIG_ADC_ASYNC) + if (!data->ctx.asynchronous) { +#endif /* CONFIG_ADC_ASYNC */ + /* Wait for channel conversion done */ + do { + result_status = Cy_HPPASS_SAR_Result_GetStatus(); + } while ((result_status & sequence->channels) != sequence->channels); + + ifx_hppass_get_group_results(sequence->channels, data); + adc_context_on_sampling_done(&data->ctx, data->dev); +#if defined(CONFIG_ADC_ASYNC) + } +#endif /* CONFIG_ADC_ASYNC */ + + data->result = 0; + } +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct ifx_hppass_sar_adc_data *data = + CONTAINER_OF(ctx, struct ifx_hppass_sar_adc_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +/** + * @brief Start read operation + * + * @param dev Pointer to the device structure for the driver instance. + * @param sequence Pointer to the adc_sequence structure. + * + * This function validates the read parameters, sets up the buffer, and initiates the read + * operation using the ADC context. + */ +static int start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + struct ifx_hppass_sar_adc_data *data = dev->data; + + if (sequence->buffer_size < (sizeof(int16_t) * POPCOUNT(sequence->channels))) { + LOG_ERR("Buffer too small"); + return -ENOMEM; + } + + if (sequence->resolution != IFX_HPPASS_SAR_ADC_RESOLUTION) { + LOG_ERR("Unsupported resolution: %d", sequence->resolution); + return -EINVAL; + } + + if (sequence->channels == 0) { + LOG_ERR("No channels specified"); + return -EINVAL; + } + + if ((sequence->channels ^ (data->enabled_channels & sequence->channels)) != 0) { + LOG_ERR("Channels not configured"); + return -EINVAL; + } + + if (sequence->oversampling != 0) { + LOG_ERR("Oversampling not supported"); + return -EINVAL; + } + + data->buffer = sequence->buffer; + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +/** + * @brief ADC interrupt handler + * + * @param dev Pointer to the device structure for the driver instance. + * + * Interrupt Handler for the combined group results interrupt. This handler is common all group + * completion interrupts. Individual group completion interrupts are available if needed for more + * advanced ADC control. + */ +static void ifx_hppass_sar_adc_isr(const struct device *dev) +{ +#if defined(CONFIG_ADC_ASYNC) + struct ifx_hppass_sar_adc_data *data = dev->data; +#else + ARG_UNUSED(dev); +#endif /* CONFIG_ADC_ASYNC */ + LOG_DBG("SAR ADC combined results interrupt"); + + /* Check which SAR result groups have completed */ + uint32_t result_intr_status = Cy_HPPASS_SAR_Result_GetInterruptStatusMasked(); + + /* Clear the specific SAR result interrupts that fired */ + Cy_HPPASS_SAR_Result_ClearInterrupt(result_intr_status); + + /* Check if Group 0 completed (which is what we're using) */ + if (result_intr_status & CY_HPPASS_INTR_SAR_RESULT_GROUP_0) { + LOG_DBG("SAR Group 0 conversion complete"); + +#if defined(CONFIG_ADC_ASYNC) + if (data->ctx.asynchronous) { + const struct adc_sequence *sequence = &data->ctx.sequence; + uint32_t result_status = Cy_HPPASS_SAR_Result_GetStatus(); + + /* Make sure all requested channels have completed */ + if ((result_status & sequence->channels) == sequence->channels) { + ifx_hppass_get_group_results(sequence->channels, data); + /* Clear the result status for the channels we read */ + Cy_HPPASS_SAR_Result_ClearStatus(result_status & + sequence->channels); + + adc_context_on_sampling_done(&data->ctx, dev); + } else { + /* + * Not all channels have completed yet. This shouldn't happen, if + * configured correctly all channels in the group will be complete + * when this interrupt occurs. + */ + LOG_ERR("SAR Group 0: Not all channels completed."); + } + } +#endif /* CONFIG_ADC_ASYNC */ + } + + /* + * This implementation only uses Group 0. Any other interrupts indicates a configuration + * error. + */ + if (result_intr_status & ~CY_HPPASS_INTR_SAR_RESULT_GROUP_0) { + LOG_ERR("SAR Results Interrupt for unhandled groups: 0x%08X", + (uint32_t)(result_intr_status & ~CY_HPPASS_INTR_SAR_RESULT_GROUP_0)); + } +} + +/** + * @brief Initialize pdl adc configuration structure + * + * This function initializes the pdl adc configuration with values derived from the device tree and + * other default values. Channel and Group configurations are set to NULL intially. Channels will + * be configured later in the channel setup function. Groups are configured when a conversion is + * started. + */ +static void ifx_init_pdl_struct(struct ifx_hppass_sar_adc_data *data, + const struct ifx_hppass_sar_adc_config *cfg) +{ + data->hppass_sar_obj = ifx_hppass_sar_pdl_cfg_struct_default; + data->hppass_sar_obj.vref = + cfg->vref_internal_source ? CY_HPPASS_SAR_VREF_VDDA : CY_HPPASS_SAR_VREF_EXT; + data->hppass_sar_obj.offsetCal = cfg->offset_cal; + data->hppass_sar_obj.linearCal = cfg->linear_cal; + data->hppass_sar_obj.gainCal = cfg->gain_cal; + data->hppass_sar_obj.dirSampEnMsk = cfg->dir_samp_en_mask; + data->hppass_sar_obj.muxSampEnMsk = cfg->mux_samp_en_mask; +} + +/** + * @brief Initialize channel configuration structures + * + * This function initializes the channel configuration structures with default values. All + * channels are initially disabled. Channels will be enabled and configured in the channel setup + * function. + */ +static void ifx_init_channel_cfg(struct ifx_hppass_sar_adc_data *data) +{ + for (int i = 0; i < HPPASS_SAR_ADC_MAX_CHANNELS; i++) { + data->hppass_sar_chan_obj[i] = (struct ifx_hppass_sar_adc_channel_config){ + .id = (uint8_t)i, + .input_positive = 0, + .pdl_channel_cfg = + (cy_stc_hppass_sar_chan_t){ + .diff = false, + .sign = false, + .avg = CY_HPPASS_SAR_AVG_DISABLED, + .limit = CY_HPPASS_SAR_LIMIT_DISABLED, + .result = false, + .fifo = CY_HPPASS_FIFO_DISABLED, + }, + }; + + data->hppass_sar_obj.chan[i] = NULL; + } +} + +/* + * Zephyr Driver API Functions + */ + +/** + * @brief ADC read implementation + */ +static int ifx_hppass_sar_adc_read(const struct device *dev, const struct adc_sequence *sequence) +{ + struct ifx_hppass_sar_adc_data *data = dev->data; + int ret; + + adc_context_lock(&data->ctx, false, NULL); + ret = start_read(dev, sequence); + adc_context_release(&data->ctx, ret); + + return ret; +} + +/** + * @brief ADC read async implementation + */ +#ifdef CONFIG_ADC_ASYNC +static int ifx_hppass_sar_adc_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct ifx_hppass_sar_adc_data *data = dev->data; + int ret; + + adc_context_lock(&data->ctx, true, async); + ret = start_read(dev, sequence); + adc_context_release(&data->ctx, ret); + return ret; +} +#endif + +/** + * @brief Configure ADC channel + * + * Implements the Zephyr ADC channel configuration API. + */ +static int ifx_hppass_sar_adc_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + struct ifx_hppass_sar_adc_data *data = dev->data; + + if (channel_cfg->channel_id >= HPPASS_SAR_ADC_MAX_CHANNELS) { + LOG_ERR("Invalid channel ID: %d", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->differential) { + LOG_ERR("Differential channels not supported"); + return -ENOTSUP; + } + + if (channel_cfg->gain != ADC_GAIN_1 && channel_cfg->gain != ADC_GAIN_3 && + channel_cfg->gain != ADC_GAIN_6 && channel_cfg->gain != ADC_GAIN_12) { + LOG_ERR("Gain setting not supported"); + return -EINVAL; + } + + /* + * The HPPASS SAR hardware block does not support setting the reference individually per + * channel. The device can select internal or external reference that will apply to all ADC + * channels. + */ + if (channel_cfg->reference != ADC_REF_INTERNAL && + channel_cfg->reference != ADC_REF_EXTERNAL0) { + LOG_ERR("Reference setting not supported"); + return -EINVAL; + } + + /* + * The HPPASS SAR Hardware block does not support setting acquisition time per channel. The + * device has three sampling time configuration registers. These registers are used to + * configure the sample time for a group rather than individual channels. + */ + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Invalid channel acquisition time, expected ADC_ACQ_TIME_DEFAULT"); + return -EINVAL; + } + + data->hppass_sar_chan_obj[channel_cfg->channel_id].id = channel_cfg->channel_id; + data->hppass_sar_chan_obj[channel_cfg->channel_id].pdl_channel_cfg = + (cy_stc_hppass_sar_chan_t){ + .diff = (channel_cfg->differential == 0) ? false : true, + .sign = false, + .avg = CY_HPPASS_SAR_AVG_DISABLED, + .limit = CY_HPPASS_SAR_LIMIT_DISABLED, + .result = true, + .fifo = CY_HPPASS_FIFO_DISABLED, + }; + + data->hppass_sar_obj.chan[channel_cfg->channel_id] = + &data->hppass_sar_chan_obj[channel_cfg->channel_id].pdl_channel_cfg; + + if (Cy_HPPASS_SAR_ChannelConfig( + channel_cfg->channel_id, + &data->hppass_sar_chan_obj[channel_cfg->channel_id].pdl_channel_cfg) != + CY_HPPASS_SUCCESS) { + LOG_ERR("Channel %d configuration failed", channel_cfg->channel_id); + return -EIO; + } + + /* + * PDL doesn't support configuring gain except during device initialization. Initialize the + * gain registers directly here. + */ + uint32_t sampler_gain; + + HPPASS_SAR_SAMP_GAIN(HPPASS_BASE) &= + ~(IFX_HPPASS_SAR_SAMPLER_GAIN_MSK + << (channel_cfg->channel_id * IFX_HPPASS_SAR_SAMPLER_GAIN_WIDTH)); + switch (channel_cfg->gain) { + case ADC_GAIN_1: + sampler_gain = 0; + break; + case ADC_GAIN_3: + sampler_gain = 1; + break; + case ADC_GAIN_6: + sampler_gain = 2; + break; + case ADC_GAIN_12: + sampler_gain = 3; + break; + default: + sampler_gain = 0; + break; + } + + HPPASS_SAR_SAMP_GAIN(HPPASS_BASE) |= + (sampler_gain << (channel_cfg->channel_id * IFX_HPPASS_SAR_SAMPLER_GAIN_WIDTH)); + + data->enabled_channels |= BIT(channel_cfg->channel_id); + + return 0; +} + +/** + * @brief Initialize ADC device + */ +static int ifx_hppass_sar_adc_init(const struct device *dev) +{ + const struct ifx_hppass_sar_adc_config *cfg = dev->config; + struct ifx_hppass_sar_adc_data *data = dev->data; + + data->dev = dev; + + LOG_DBG("Initializing HPPASS SAR ADC"); + + /* + * Initialize the data structure. The data structure contains a pdl device initialization + * object which we store to be able to reinitialize the ADC if needed. + */ + ifx_init_pdl_struct(data, cfg); + ifx_init_channel_cfg(data); + + if (Cy_HPPASS_SAR_Init(&data->hppass_sar_obj) != CY_RSLT_SUCCESS) { + LOG_ERR("Failed to initialize HPPASS SAR ADC"); + return -EIO; + } + + if (ifx_hppass_ac_init_adc() != CY_RSLT_SUCCESS) { + LOG_ERR("HPPASS AC failed to initialize ADC"); + return -EIO; + } + +#if defined(CONFIG_ADC_ASYNC) + Cy_HPPASS_SAR_Result_SetInterruptMask(CY_HPPASS_INTR_SAR_RESULT_GROUP_0); + cfg->irq_func(); +#endif /* CONFIG_ADC_ASYNC */ + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +#ifdef CONFIG_ADC_ASYNC +#define ADC_IFX_HPPASS_SAR_DRIVER_API(n) \ + static DEVICE_API(adc, adc_ifx_hppass_sar_driver_api_##n) = { \ + .channel_setup = ifx_hppass_sar_adc_channel_setup, \ + .read = ifx_hppass_sar_adc_read, \ + .read_async = ifx_hppass_sar_adc_read_async, \ + .ref_internal = DT_INST_PROP(n, vref_mv), \ + }; +#else +#define ADC_IFX_HPPASS_SAR_DRIVER_API(n) \ + static DEVICE_API(adc, adc_ifx_hppass_sar_driver_api_##n) = { \ + .channel_setup = ifx_hppass_sar_adc_channel_setup, \ + .read = ifx_hppass_sar_adc_read, \ + .ref_internal = DT_INST_PROP(n, vref_mv), \ + }; +#endif + +/* + * Devicetree channel mask generation + * + * dir_samp_en_mask: + * One bit per direct sampler channel (0..11) that has a child node. + * + * mux_samp_en_mask: + * One bit per mux sampler group: + * Bit0 -> any of channels 12..15 present + * Bit1 -> any of channels 16..19 present + * Bit2 -> any of channels 20..23 present + * Bit3 -> any of channels 24..27 present + */ + +#define IFX_HPPASS_SAR_CH_EXISTS(inst, ch) DT_NODE_EXISTS(DT_CHILD(DT_DRV_INST(inst), channel_##ch)) + +/* Direct sampler bitmap (0..11) */ +#define IFX_HPPASS_SAR_DIR_MASK(inst) \ + ((IFX_HPPASS_SAR_CH_EXISTS(inst, 0) ? BIT(0) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 1) ? BIT(1) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 2) ? BIT(2) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 3) ? BIT(3) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 4) ? BIT(4) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 5) ? BIT(5) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 6) ? BIT(6) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 7) ? BIT(7) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 8) ? BIT(8) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 9) ? BIT(9) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 10) ? BIT(10) : 0) | \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 11) ? BIT(11) : 0)) + +/* Group presence helpers */ +#define IFX_HPPASS_SAR_GRP0_PRESENT(inst) \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 12) || IFX_HPPASS_SAR_CH_EXISTS(inst, 13) || \ + IFX_HPPASS_SAR_CH_EXISTS(inst, 14) || IFX_HPPASS_SAR_CH_EXISTS(inst, 15)) + +#define IFX_HPPASS_SAR_GRP1_PRESENT(inst) \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 16) || IFX_HPPASS_SAR_CH_EXISTS(inst, 17) || \ + IFX_HPPASS_SAR_CH_EXISTS(inst, 18) || IFX_HPPASS_SAR_CH_EXISTS(inst, 19)) + +#define IFX_HPPASS_SAR_GRP2_PRESENT(inst) \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 20) || IFX_HPPASS_SAR_CH_EXISTS(inst, 21) || \ + IFX_HPPASS_SAR_CH_EXISTS(inst, 22) || IFX_HPPASS_SAR_CH_EXISTS(inst, 23)) + +#define IFX_HPPASS_SAR_GRP3_PRESENT(inst) \ + (IFX_HPPASS_SAR_CH_EXISTS(inst, 24) || IFX_HPPASS_SAR_CH_EXISTS(inst, 25) || \ + IFX_HPPASS_SAR_CH_EXISTS(inst, 26) || IFX_HPPASS_SAR_CH_EXISTS(inst, 27)) + +/* Mux sampler enable mask (bit per group if any channel in that group exists) */ +#define IFX_HPPASS_SAR_MUX_MASK(inst) \ + ((IFX_HPPASS_SAR_GRP0_PRESENT(inst) ? BIT(0) : 0) | \ + (IFX_HPPASS_SAR_GRP1_PRESENT(inst) ? BIT(1) : 0) | \ + (IFX_HPPASS_SAR_GRP2_PRESENT(inst) ? BIT(2) : 0) | \ + (IFX_HPPASS_SAR_GRP3_PRESENT(inst) ? BIT(3) : 0)) + +/* Device instantiation */ +#define IFX_HPPASS_SAR_ADC_INIT(n) \ + ADC_IFX_HPPASS_SAR_DRIVER_API(n); \ + static void ifx_hppass_sar_adc_config_func_##n(void); \ + static const struct ifx_hppass_sar_adc_config ifx_hppass_sar_adc_config_##n = { \ + .irq_priority = DT_INST_IRQ(n, priority), \ + .irq_num = DT_INST_IRQN(n), \ + .irq_func = ifx_hppass_sar_adc_config_func_##n, \ + .dir_samp_en_mask = IFX_HPPASS_SAR_DIR_MASK(n), \ + .mux_samp_en_mask = IFX_HPPASS_SAR_MUX_MASK(n), \ + .vref_internal_source = DT_INST_PROP(n, ref_internal_source), \ + .gain_cal = DT_INST_PROP(n, gain_cal), \ + .offset_cal = DT_INST_PROP(n, offset_cal), \ + .linear_cal = DT_INST_PROP(n, linear_cal)}; \ + static struct ifx_hppass_sar_adc_data ifx_hppass_sar_adc_data_##n = { \ + ADC_CONTEXT_INIT_TIMER(ifx_hppass_sar_adc_data_##n, ctx), \ + ADC_CONTEXT_INIT_LOCK(ifx_hppass_sar_adc_data_##n, ctx), \ + ADC_CONTEXT_INIT_SYNC(ifx_hppass_sar_adc_data_##n, ctx), \ + }; \ + DEVICE_DT_INST_DEFINE(n, &ifx_hppass_sar_adc_init, NULL, &ifx_hppass_sar_adc_data_##n, \ + &ifx_hppass_sar_adc_config_##n, POST_KERNEL, \ + CONFIG_ADC_INFINEON_HPPASS_SAR_INIT_PRIORITY, \ + &adc_ifx_hppass_sar_driver_api_##n); \ + static void ifx_hppass_sar_adc_config_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), ifx_hppass_sar_adc_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(IFX_HPPASS_SAR_ADC_INIT) diff --git a/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt b/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt index 1af8accd8c401..d9c3849958df3 100644 --- a/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt +++ b/modules/hal_infineon/zephyr-ifx-cycfg/CMakeLists.txt @@ -14,6 +14,6 @@ if(CONFIG_SOC_SERIES_PSC3) set(zephyr_ifx_cycfg_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/zephyr-ifx-cycfg/soc_psc3) zephyr_include_directories(${zephyr_ifx_cycfg_dir}) - zephyr_library_sources(${zephyr_ifx_cycfg_dir}/ifx_hppass_analog.c) + zephyr_library_sources_ifdef(CONFIG_USE_INFINEON_HPPASS_SAR_ADC ${zephyr_ifx_cycfg_dir}/ifx_hppass_analog.c) zephyr_library_sources(${zephyr_ifx_cycfg_dir}/ifx_cycfg_init.c) endif() diff --git a/soc/infineon/cat1b/psc3/soc.c b/soc/infineon/cat1b/psc3/soc.c index 3676eb0d6b02c..aa0fea00d8018 100644 --- a/soc/infineon/cat1b/psc3/soc.c +++ b/soc/infineon/cat1b/psc3/soc.c @@ -5,16 +5,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include - -#include -#include -#include "cy_pdl.h" +#include void soc_early_init_hook(void) { - /* Initializes the system */ - SystemInit(); + ifx_cycfg_init(); } From 6fa290853e51aed6fcb8faffcfb0fcea5ba55027 Mon Sep 17 00:00:00 2001 From: John Batch Date: Tue, 14 Oct 2025 13:40:01 -0700 Subject: [PATCH 159/397] drivers: adc: Adding Infineon HPPASS ADC samples Adding files to allow running the following samples for the Infineon HPPASS SAR ADC driver on the PSOC C3 family of MCUs: * samples/drivers/adc_dt * samples/drivers/adc_sequence Signed-off-by: John Batch --- .../adc/adc_dt/boards/kit_psc3m5_evk.overlay | 44 +++++++++++++++++++ .../boards/kit_psc3m5_evk.overlay | 44 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 samples/drivers/adc/adc_dt/boards/kit_psc3m5_evk.overlay create mode 100644 samples/drivers/adc/adc_sequence/boards/kit_psc3m5_evk.overlay diff --git a/samples/drivers/adc/adc_dt/boards/kit_psc3m5_evk.overlay b/samples/drivers/adc/adc_dt/boards/kit_psc3m5_evk.overlay new file mode 100644 index 0000000000000..1a2618f827e61 --- /dev/null +++ b/samples/drivers/adc/adc_dt/boards/kit_psc3m5_evk.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + io-channels = <&adc0 1>, <&adc0 2>, <&adc0 12>; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; /* child channels */ + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; + + channel@2 { + reg = <2>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; + + channel@12 { + reg = <12>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/drivers/adc/adc_sequence/boards/kit_psc3m5_evk.overlay b/samples/drivers/adc/adc_sequence/boards/kit_psc3m5_evk.overlay new file mode 100644 index 0000000000000..acc6ff50ad20e --- /dev/null +++ b/samples/drivers/adc/adc_sequence/boards/kit_psc3m5_evk.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + adc0 = &adc0; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; /* child channels */ + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; + + channel@2 { + reg = <2>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; + + channel@12 { + reg = <12>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; +}; From a0c3f16a796c321fe73eab235351f631ab8591ce Mon Sep 17 00:00:00 2001 From: John Batch Date: Tue, 14 Oct 2025 14:17:45 -0700 Subject: [PATCH 160/397] drivers: adc: Adding Infineon HPPASS ADC tests Adding files to allow running the following tests for the Infineon HPPASS SAR ADC driver on the PSOC C3 family of MCUs: * tests/drivers/adc/adc_api * tests/drivers/adc/adc_error_case Modifies the adc_error_cases test to use add a KConfig option for the valid resolution. Signed-off-by: John Batch --- .../adc/adc_api/boards/kit_psc3m5_evk.overlay | 44 +++++++++++++++++++ tests/drivers/adc/adc_error_cases/Kconfig | 11 +++++ .../boards/kit_psc3m5_evk.overlay | 44 +++++++++++++++++++ .../adc/adc_error_cases/src/adc_error_cases.c | 6 +-- 4 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 tests/drivers/adc/adc_api/boards/kit_psc3m5_evk.overlay create mode 100644 tests/drivers/adc/adc_error_cases/Kconfig create mode 100644 tests/drivers/adc/adc_error_cases/boards/kit_psc3m5_evk.overlay diff --git a/tests/drivers/adc/adc_api/boards/kit_psc3m5_evk.overlay b/tests/drivers/adc/adc_api/boards/kit_psc3m5_evk.overlay new file mode 100644 index 0000000000000..2ff1c86efdbf7 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/kit_psc3m5_evk.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + io-channels = <&adc0 1>, <&adc0 2>, <&adc0 12>; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; /* child channels */ + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,resolution = <12>; + }; + + channel@2 { + reg = <2>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,resolution = <12>; + }; + + channel@12 { + reg = <12>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,resolution = <12>; + }; +}; diff --git a/tests/drivers/adc/adc_error_cases/Kconfig b/tests/drivers/adc/adc_error_cases/Kconfig new file mode 100644 index 0000000000000..cdd9b443424a7 --- /dev/null +++ b/tests/drivers/adc/adc_error_cases/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Infineon Technologies AG, +# or an affiliate of Infineon Technologies AG. +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config TEST_ADC_ERROR_CASES_RESOLUTION + int + default 12 if SOC_FAMILY_SILABS_S2 || SOC_SERIES_PSC3 + default 10 diff --git a/tests/drivers/adc/adc_error_cases/boards/kit_psc3m5_evk.overlay b/tests/drivers/adc/adc_error_cases/boards/kit_psc3m5_evk.overlay new file mode 100644 index 0000000000000..5d8e185a1b836 --- /dev/null +++ b/tests/drivers/adc/adc_error_cases/boards/kit_psc3m5_evk.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Infineon Technologies AG, + * or an affiliate of Infineon Technologies AG. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + adc = &adc0; + }; +}; + +&adc0 { + status = "okay"; + #address-cells = <1>; /* child channels */ + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; + + channel@2 { + reg = <2>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; + + channel@12 { + reg = <12>; + zephyr,acquisition-time = ; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,resolution = <12>; + }; +}; diff --git a/tests/drivers/adc/adc_error_cases/src/adc_error_cases.c b/tests/drivers/adc/adc_error_cases/src/adc_error_cases.c index 754d2ad98d7bf..dd6904836d968 100644 --- a/tests/drivers/adc/adc_error_cases/src/adc_error_cases.c +++ b/tests/drivers/adc/adc_error_cases/src/adc_error_cases.c @@ -24,11 +24,7 @@ static const struct adc_channel_cfg valid_channel_cfg = { #endif }; -#if defined(CONFIG_SOC_FAMILY_SILABS_S2) -#define VALID_RESOLUTION 12 -#else -#define VALID_RESOLUTION 10 -#endif +#define VALID_RESOLUTION CONFIG_TEST_ADC_ERROR_CASES_RESOLUTION static const struct adc_sequence valid_seq = { .buffer = m_sample_buffer, From f40324914b155f9d16f6b204fb085be961cd929d Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Wed, 27 Aug 2025 09:49:03 +0800 Subject: [PATCH 161/397] drivers: clock_control: add nxp_mc_cgm clock driver - add clock_init function to initialize clock sources according devicetree settings - finish basic clock api function Signed-off-by: Lucien Zhao --- .../drivers/clock_control/nxp_clock_control.h | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 include/zephyr/drivers/clock_control/nxp_clock_control.h diff --git a/include/zephyr/drivers/clock_control/nxp_clock_control.h b/include/zephyr/drivers/clock_control/nxp_clock_control.h new file mode 100644 index 0000000000000..17d6544053ced --- /dev/null +++ b/include/zephyr/drivers/clock_control/nxp_clock_control.h @@ -0,0 +1,53 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NXP_CLOCK_CONTROL_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NXP_CLOCK_CONTROL_H_ + +#include + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(mc_cgm), nxp_mc_cgm, okay) +#include +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(firc), nxp_firc, okay) +#define NXP_FIRC_DIV DT_ENUM_IDX(DT_NODELABEL(firc), firc_div) +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(fxosc), nxp_fxosc, okay) +#define NXP_FXOSC_FREQ DT_PROP(DT_NODELABEL(fxosc), freq) +#define NXP_FXOSC_WORKMODE \ + (DT_ENUM_IDX(DT_NODELABEL(fxosc), workmode) == 0 ? kFXOSC_ModeCrystal : kFXOSC_ModeBypass) +#define NXP_FXOSC_DELAY DT_PROP(DT_NODELABEL(fxosc), delay) +#define NXP_FXOSC_OVERDRIVE DT_PROP(DT_NODELABEL(fxosc), overdrive) +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), nxp_plldig, okay) +#define NXP_PLL_WORKMODE DT_ENUM_IDX(DT_NODELABEL(pll), workmode) +#define NXP_PLL_PREDIV DT_PROP(DT_NODELABEL(pll), prediv) +#define NXP_PLL_POSTDIV DT_PROP(DT_NODELABEL(pll), postdiv) +#define NXP_PLL_MULTIPLIER DT_PROP(DT_NODELABEL(pll), multiplier) +#define NXP_PLL_FRACLOOPDIV DT_PROP(DT_NODELABEL(pll), fracloopdiv) +#define NXP_PLL_STEPSIZE DT_PROP(DT_NODELABEL(pll), stepsize) +#define NXP_PLL_STEPNUM DT_PROP(DT_NODELABEL(pll), stepnum) +#define NXP_PLL_ACCURACY DT_ENUM_IDX(DT_NODELABEL(pll), accuracy) +#define NXP_PLL_OUTDIV_POINTER DT_PROP(DT_NODELABEL(pll), outdiv) +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(mc_cgm), nxp_mc_cgm, okay) +#define NXP_PLL_MAXIDOCHANGE DT_PROP(DT_NODELABEL(mc_cgm), max_ido_change) +#define NXP_PLL_STEPDURATION DT_PROP(DT_NODELABEL(mc_cgm), step_duration) +#define NXP_PLL_CLKSRCFREQ DT_PROP(DT_NODELABEL(mc_cgm), clk_src_freq) +#define NXP_PLL_MUX_0_DC_0_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_0_div) +#define NXP_PLL_MUX_0_DC_1_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_1_div) +#define NXP_PLL_MUX_0_DC_2_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_2_div) +#define NXP_PLL_MUX_0_DC_3_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_3_div) +#define NXP_PLL_MUX_0_DC_4_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_4_div) +#define NXP_PLL_MUX_0_DC_5_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_5_div) +#define NXP_PLL_MUX_0_DC_6_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_6_div) +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NXP_CLOCK_CONTROL_H_ */ From e062872e1ad9d1318b8c45e7ca7e15244b1cdca6 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Mon, 29 Sep 2025 17:17:11 +0800 Subject: [PATCH 162/397] dts: bindings: flash_controller: add nxp,kinetis-ftfc.yaml - add nxp,kinetis-ftfc.yaml for mcxe24x flash controller Signed-off-by: Lucien Zhao --- .../flash_controller/nxp,kinetis-ftfc.yaml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 dts/bindings/flash_controller/nxp,kinetis-ftfc.yaml diff --git a/dts/bindings/flash_controller/nxp,kinetis-ftfc.yaml b/dts/bindings/flash_controller/nxp,kinetis-ftfc.yaml new file mode 100644 index 0000000000000..4c539864cb9a7 --- /dev/null +++ b/dts/bindings/flash_controller/nxp,kinetis-ftfc.yaml @@ -0,0 +1,22 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Kinetis Flash Memory Module C (FTFC) + +compatible: "nxp,kinetis-ftfc" + +include: flash-controller.yaml + +properties: + fsec: + type: int + description: | + Configures the reset value of the FSEC register, which includes + backdoor key access, mass erase, factory access, and flash security + options. + + fopt: + type: int + description: | + Configures the reset value of the FOPT register, which includes boot, + NMI, and EzPort options. From b8925d67d460edb52aa45c266b0a8b6600908625 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Mon, 29 Sep 2025 17:18:46 +0800 Subject: [PATCH 163/397] drivers: clock_control: adapt clock driver for mcxe24x series - add CONFIG_SOC_SERIES_MCXE24X judgment in driver Signed-off-by: Lucien Zhao --- drivers/clock_control/clock_control_mcux_scg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_mcux_scg.c b/drivers/clock_control/clock_control_mcux_scg.c index c1e7470abb9ab..ae04e73b33e70 100644 --- a/drivers/clock_control/clock_control_mcux_scg.c +++ b/drivers/clock_control/clock_control_mcux_scg.c @@ -46,7 +46,8 @@ static int mcux_scg_get_rate(const struct device *dev, case KINETIS_SCG_BUS_CLK: clock_name = kCLOCK_BusClk; break; -#if !(defined(CONFIG_SOC_MKE17Z7) || defined(CONFIG_SOC_MKE17Z9)) +#if !(defined(CONFIG_SOC_MKE17Z7) || defined(CONFIG_SOC_MKE17Z9) \ + || defined(CONFIG_SOC_SERIES_MCXE24X)) case KINETIS_SCG_FLEXBUS_CLK: clock_name = kCLOCK_FlexBusClk; break; From bb4018eca3d962e8ec7ffe28bd75e457e65024f5 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Mon, 29 Sep 2025 17:22:43 +0800 Subject: [PATCH 164/397] soc: nxp: mcx: add mcxe24x series soc - create 'mcxe' as family and 'mcxe24x' as series - add pinctrl_soc.h - add soc.c/.h to do system initialization - Support flash boot if CONFIG_MCXE_FLASH_CONFIG==1 Signed-off-by: Lucien Zhao --- modules/hal_nxp/mcux/Kconfig.mcux | 3 +- soc/nxp/mcx/mcxe/CMakeLists.txt | 4 ++ soc/nxp/mcx/mcxe/Kconfig | 8 +++ soc/nxp/mcx/mcxe/Kconfig.defconfig | 8 +++ soc/nxp/mcx/mcxe/Kconfig.soc | 10 ++++ soc/nxp/mcx/mcxe/mcxe24x/CMakeLists.txt | 21 +++++++ soc/nxp/mcx/mcxe/mcxe24x/Kconfig | 37 ++++++++++++ soc/nxp/mcx/mcxe/mcxe24x/Kconfig.defconfig | 22 +++++++ soc/nxp/mcx/mcxe/mcxe24x/Kconfig.soc | 60 +++++++++++++++++++ soc/nxp/mcx/mcxe/mcxe24x/flash_config.ld | 9 +++ .../mcx/mcxe/mcxe24x/flash_configuration.c | 44 ++++++++++++++ soc/nxp/mcx/mcxe/mcxe24x/pinctrl_soc.h | 7 +++ soc/nxp/mcx/mcxe/mcxe24x/soc.c | 20 +++++++ soc/nxp/mcx/mcxe/mcxe24x/soc.h | 21 +++++++ soc/nxp/mcx/soc.yml | 7 +++ 15 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 soc/nxp/mcx/mcxe/CMakeLists.txt create mode 100644 soc/nxp/mcx/mcxe/Kconfig create mode 100644 soc/nxp/mcx/mcxe/Kconfig.defconfig create mode 100644 soc/nxp/mcx/mcxe/Kconfig.soc create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/CMakeLists.txt create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/Kconfig create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/Kconfig.defconfig create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/Kconfig.soc create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/flash_config.ld create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/flash_configuration.c create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/pinctrl_soc.h create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/soc.c create mode 100644 soc/nxp/mcx/mcxe/mcxe24x/soc.h diff --git a/modules/hal_nxp/mcux/Kconfig.mcux b/modules/hal_nxp/mcux/Kconfig.mcux index b9e8fd3b2da79..7d53f570a897e 100644 --- a/modules/hal_nxp/mcux/Kconfig.mcux +++ b/modules/hal_nxp/mcux/Kconfig.mcux @@ -8,7 +8,8 @@ config HAS_MCUX bool depends on SOC_FAMILY_KINETIS || SOC_FAMILY_NXP_IMX || SOC_FAMILY_LPC || \ SOC_FAMILY_NXP_S32 || SOC_FAMILY_NXP_IMXRT || SOC_FAMILY_NXP_RW || \ - SOC_FAMILY_MCXN || SOC_FAMILY_MCXA || SOC_FAMILY_MCXW || SOC_FAMILY_MCXC + SOC_FAMILY_MCXN || SOC_FAMILY_MCXA || SOC_FAMILY_MCXW || SOC_FAMILY_MCXC || \ + SOC_FAMILY_MCXE if HAS_MCUX diff --git a/soc/nxp/mcx/mcxe/CMakeLists.txt b/soc/nxp/mcx/mcxe/CMakeLists.txt new file mode 100644 index 0000000000000..e85ff1f432d20 --- /dev/null +++ b/soc/nxp/mcx/mcxe/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/nxp/mcx/mcxe/Kconfig b/soc/nxp/mcx/mcxe/Kconfig new file mode 100644 index 0000000000000..2a1d867fd5876 --- /dev/null +++ b/soc/nxp/mcx/mcxe/Kconfig @@ -0,0 +1,8 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_MCXE + +rsource "*/Kconfig" + +endif #SOC_FAMILY_MCXE diff --git a/soc/nxp/mcx/mcxe/Kconfig.defconfig b/soc/nxp/mcx/mcxe/Kconfig.defconfig new file mode 100644 index 0000000000000..d7a6613d4a183 --- /dev/null +++ b/soc/nxp/mcx/mcxe/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_MCXE + +rsource "*/Kconfig.defconfig" + +endif # SOC_FAMILY_MCXE diff --git a/soc/nxp/mcx/mcxe/Kconfig.soc b/soc/nxp/mcx/mcxe/Kconfig.soc new file mode 100644 index 0000000000000..f1755af7e2c54 --- /dev/null +++ b/soc/nxp/mcx/mcxe/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_MCXE + bool + +config SOC_FAMILY + default "mcxe" if SOC_FAMILY_MCXE + +rsource "*/Kconfig.soc" diff --git a/soc/nxp/mcx/mcxe/mcxe24x/CMakeLists.txt b/soc/nxp/mcx/mcxe/mcxe24x/CMakeLists.txt new file mode 100644 index 0000000000000..e01a54ecc0abb --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_MCXE_FLASH_CONFIG flash_configuration.c) + +zephyr_include_directories(.) + +zephyr_sources(soc.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_linker_sources_ifdef(CONFIG_MCXE_FLASH_CONFIG + ROM_START + SORT_KEY 0x400 + flash_config.ld + ) + +# CMSIS SystemInit will disable watchdog unless instructed not to. +# Add a compiler definition here to leave watchdog untouched +# if this Kconfig is set +zephyr_compile_definitions_ifdef(CONFIG_WDOG_ENABLE_AT_BOOT DISABLE_WDOG=0) diff --git a/soc/nxp/mcx/mcxe/mcxe24x/Kconfig b/soc/nxp/mcx/mcxe/mcxe24x/Kconfig new file mode 100644 index 0000000000000..f40f2ff28a4bb --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/Kconfig @@ -0,0 +1,37 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MCXE24X + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select HAS_MCUX + select CLOCK_CONTROL + select SOC_RESET_HOOK + +if SOC_SERIES_MCXE24X + +config MCXE_FLASH_CONFIG + bool "MCXE flash configuration field" + default y if XIP && !BOOTLOADER_MCUBOOT + help + Include the 16-byte flash configuration field that stores default + protection settings (loaded on reset) and security information that + allows the MCU to restrict access to the FTFC module. + +config WDOG_ENABLE_AT_BOOT + bool "Keep watchdog timer enabled at boot" + help + Leave SOC watchdog timer enabled at boot. The specific timeout + and clock configuration of the watchdog at boot is SOC dependent. + Note: if the watchdog timer is enabled at boot, the user will + need to configure the watchdog using z_arm_watchdog_init, as + the SOC requires watchdog configuration before initial expiration + +# Enable watchdog configuration function if watchdog is left enabled at boot +config WDOG_INIT + bool + default WDOG_ENABLE_AT_BOOT + +endif # SOC_SERIES_MCXE24X diff --git a/soc/nxp/mcx/mcxe/mcxe24x/Kconfig.defconfig b/soc/nxp/mcx/mcxe/mcxe24x/Kconfig.defconfig new file mode 100644 index 0000000000000..a044901f3e401 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/Kconfig.defconfig @@ -0,0 +1,22 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_MCXE24X + +config CORTEX_M_SYSTICK + default n if MCUX_LPTMR_TIMER + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if CORTEX_M_SYSTICK + default $(dt_node_int_prop_int,/soc/lptmr@40040000,clock-frequency) if MCUX_LPTMR_TIMER + +config NUM_IRQS + default 146 + +config CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + default y + +config GPIO + default y + +endif # SOC_SERIES_MCXE24X diff --git a/soc/nxp/mcx/mcxe/mcxe24x/Kconfig.soc b/soc/nxp/mcx/mcxe/mcxe24x/Kconfig.soc new file mode 100644 index 0000000000000..6ef5787598afc --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/Kconfig.soc @@ -0,0 +1,60 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MCXE24X + bool + select SOC_FAMILY_MCXE + +config SOC_SERIES + default "mcxe24x" if SOC_SERIES_MCXE24X + +config SOC_MCXE245 + bool + select SOC_SERIES_MCXE24X + +config SOC_MCXE246 + bool + select SOC_SERIES_MCXE24X + +config SOC_MCXE247 + bool + select SOC_SERIES_MCXE24X + +config SOC + default "mcxe245" if SOC_MCXE245 + default "mcxe246" if SOC_MCXE246 + default "mcxe247" if SOC_MCXE247 + +config SOC_PART_NUMBER_MCXE245VLF + bool + +config SOC_PART_NUMBER_MCXE245VLH + bool + +config SOC_PART_NUMBER_MCXE245VLL + bool + +config SOC_PART_NUMBER_MCXE246VLH + bool + +config SOC_PART_NUMBER_MCXE246VLL + bool + +config SOC_PART_NUMBER_MCXE246VLQ + bool + +config SOC_PART_NUMBER_MCXE247VLL + bool + +config SOC_PART_NUMBER_MCXE247VLQ + bool + +config SOC_PART_NUMBER + default "MCXE245VLF" if SOC_PART_NUMBER_MCXE245VLF + default "MCXE245VLH" if SOC_PART_NUMBER_MCXE245VLH + default "MCXE245VLL" if SOC_PART_NUMBER_MCXE245VLL + default "MCXE246VLH" if SOC_PART_NUMBER_MCXE246VLH + default "MCXE246VLL" if SOC_PART_NUMBER_MCXE246VLL + default "MCXE246VLQ" if SOC_PART_NUMBER_MCXE246VLQ + default "MCXE247VLL" if SOC_PART_NUMBER_MCXE247VLL + default "MCXE247VLQ" if SOC_PART_NUMBER_MCXE247VLQ diff --git a/soc/nxp/mcx/mcxe/mcxe24x/flash_config.ld b/soc/nxp/mcx/mcxe/mcxe24x/flash_config.ld new file mode 100644 index 0000000000000..40f44c772d1c9 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/flash_config.ld @@ -0,0 +1,9 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +. = 0x400; +KEEP(*(.kinetis_flash_config)) +KEEP(*(".kinetis_flash_config.*")) diff --git a/soc/nxp/mcx/mcxe/mcxe24x/flash_configuration.c b/soc/nxp/mcx/mcxe/mcxe24x/flash_configuration.c new file mode 100644 index 0000000000000..3cd74b93e5b48 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/flash_configuration.c @@ -0,0 +1,44 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +uint8_t __kinetis_flash_config_section __kinetis_flash_config[] = { + /* Backdoor Comparison Key */ + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + + /* Program flash protection; 1 bit/region - 0=protected, 1=unprotected + */ + 0xFF, + 0xFF, + 0xFF, + 0xFF, + + /* Flash security register (FSEC) enables/disables backdoor key access, + * mass erase, factory access, and flash security + */ + DT_PROP_OR(DT_NODELABEL(ftfc), fsec, 0xFE), + + /* Flash nonvolatile option register (FOPT) enables/disables NMI, + * EzPort, and boot options + */ + DT_PROP_OR(DT_NODELABEL(ftfc), fopt, 0xFF), + + /* EEPROM protection register (FEPROT) */ + 0xFF, + + /* Data flash protection register (FDPROT) */ + 0XFF, +}; diff --git a/soc/nxp/mcx/mcxe/mcxe24x/pinctrl_soc.h b/soc/nxp/mcx/mcxe/mcxe24x/pinctrl_soc.h new file mode 100644 index 0000000000000..a6904bc354685 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/pinctrl_soc.h @@ -0,0 +1,7 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/nxp/mcx/mcxe/mcxe24x/soc.c b/soc/nxp/mcx/mcxe/mcxe24x/soc.c new file mode 100644 index 0000000000000..8d70ec28a0143 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/soc.c @@ -0,0 +1,20 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_SOC_RESET_HOOK + +void soc_reset_hook(void) +{ + SystemInit(); +} + +#endif /* CONFIG_SOC_RESET_HOOK */ diff --git a/soc/nxp/mcx/mcxe/mcxe24x/soc.h b/soc/nxp/mcx/mcxe/mcxe24x/soc.h new file mode 100644 index 0000000000000..9722ad2cc811c --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe24x/soc.h @@ -0,0 +1,21 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +#include +#include + +#define PORT_MUX_GPIO kPORT_MuxAsGpio /* GPIO setting for the Port Mux Register */ + +#ifndef _ASMLANGUAGE + +#include + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC__H_ */ diff --git a/soc/nxp/mcx/soc.yml b/soc/nxp/mcx/soc.yml index fae16fdbd8f8b..6917d7821542d 100644 --- a/soc/nxp/mcx/soc.yml +++ b/soc/nxp/mcx/soc.yml @@ -16,6 +16,13 @@ family: - name: mcxc142 - name: mcxc242 - name: mcxc444 +- name: mcxe + series: + - name: mcxe24x + socs: + - name: mcxe245 + - name: mcxe246 + - name: mcxe247 - name: mcxa socs: - name: mcxa153 From 50e113ff88c0032cacfafa79562515f1e2c46698 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Mon, 29 Sep 2025 17:24:03 +0800 Subject: [PATCH 165/397] dts: arm: nxp: add mcxe24x device tree - Use specific_part.dtsi + full_devices.dtsi way to desribe all devices Signed-off-by: Lucien Zhao --- dts/arm/nxp/nxp_mcxe245.dtsi | 57 +++ dts/arm/nxp/nxp_mcxe246.dtsi | 49 +++ dts/arm/nxp/nxp_mcxe247.dtsi | 36 ++ dts/arm/nxp/nxp_mcxe24x_common.dtsi | 629 ++++++++++++++++++++++++++++ 4 files changed, 771 insertions(+) create mode 100644 dts/arm/nxp/nxp_mcxe245.dtsi create mode 100644 dts/arm/nxp/nxp_mcxe246.dtsi create mode 100644 dts/arm/nxp/nxp_mcxe247.dtsi create mode 100644 dts/arm/nxp/nxp_mcxe24x_common.dtsi diff --git a/dts/arm/nxp/nxp_mcxe245.dtsi b/dts/arm/nxp/nxp_mcxe245.dtsi new file mode 100644 index 0000000000000..d17ea02eba7ce --- /dev/null +++ b/dts/arm/nxp/nxp_mcxe245.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + /* + * SRAM_L and SRAM_U form a continuous block in memory map, + * but misaligned accesses across the 0x20000000 boundary + * are not supported. Therefore two separate memory nodes + * are created. + */ + sram_l: sram@1fff8000 { + compatible = "mmio-sram"; + reg = <0x1fff8000 DT_SIZE_K(32)>; + }; + + sram_u: sram@20000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(28)>; + zephyr,memory-region = "SRAMU"; + }; +}; + +&ftfc { + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_K(512)>; + erase-block-size = ; + write-block-size = <8>; + }; +}; + +&flexcan1 { + compatible = "nxp,flexcan"; + interrupts = <85 0>, <86 0>, <88 0>; + interrupt-names = "ored-warning-bus-off", "error", "mb-0-15"; +}; + +&flexcan2 { + compatible = "nxp,flexcan"; + interrupts = <92 0>, <93 0>, <95 0>; + interrupt-names = "ored-warning-bus-off", "error", "mb-0-15"; +}; + +/delete-node/ &ftm4; +/delete-node/ &ftm5; +/delete-node/ &ftm6; +/delete-node/ &ftm7; +/delete-node/ &enet; +/delete-node/ &lpi2c1; +/delete-node/ &sai0; +/delete-node/ &sai1; diff --git a/dts/arm/nxp/nxp_mcxe246.dtsi b/dts/arm/nxp/nxp_mcxe246.dtsi new file mode 100644 index 0000000000000..342e5384a89fd --- /dev/null +++ b/dts/arm/nxp/nxp_mcxe246.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + /* + * SRAM_L and SRAM_U form a continuous block in memory map, + * but misaligned accesses across the 0x20000000 boundary + * are not supported. Therefore two separate memory nodes + * are created. + */ + sram_l: sram@1fff0000 { + compatible = "mmio-sram"; + reg = <0x1fff0000 DT_SIZE_K(64)>; + }; + + sram_u: sram@20000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(60)>; + zephyr,memory-region = "SRAMU"; + }; +}; + +&ftfc { + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_M(1)>; + erase-block-size = ; + write-block-size = <8>; + }; +}; + +&flexcan2 { + compatible = "nxp,flexcan"; + interrupts = <92 0>, <93 0>, <95 0>; + interrupt-names = "ored-warning-bus-off", "error", "mb-0-15"; +}; + +/delete-node/ &ftm4; +/delete-node/ &ftm5; +/delete-node/ &enet; +/delete-node/ &lpi2c1; +/delete-node/ &sai0; +/delete-node/ &sai1; diff --git a/dts/arm/nxp/nxp_mcxe247.dtsi b/dts/arm/nxp/nxp_mcxe247.dtsi new file mode 100644 index 0000000000000..fbeb9a5f69734 --- /dev/null +++ b/dts/arm/nxp/nxp_mcxe247.dtsi @@ -0,0 +1,36 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + /* + * SRAM_L and SRAM_U form a continuous block in memory map, + * but misaligned accesses across the 0x20000000 boundary + * are not supported. Therefore two separate memory nodes + * are created. + */ + sram_l: sram@1ffe0000 { + compatible = "mmio-sram"; + reg = <0x1ffe0000 DT_SIZE_K(128)>; + }; + + sram_u: sram@20000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(124)>; + zephyr,memory-region = "SRAMU"; + }; +}; + +&ftfc { + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_K(1536)>; + erase-block-size = ; + write-block-size = <8>; + }; +}; diff --git a/dts/arm/nxp/nxp_mcxe24x_common.dtsi b/dts/arm/nxp/nxp_mcxe24x_common.dtsi new file mode 100644 index 0000000000000..3fa43feb3c76d --- /dev/null +++ b/dts/arm/nxp/nxp_mcxe24x_common.dtsi @@ -0,0 +1,629 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +/ { + aliases { + watchdog0 = &wdog; + }; + + chosen { + zephyr,flash-controller = &ftfc; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + /* Dummy pinctrl node, filled with pin mux options at board level */ + pinctrl: pinctrl { + compatible = "nxp,port-pinctrl"; + status = "okay"; + }; + + soc { + scg: scg@40064000 { + compatible = "nxp,kinetis-scg"; + sosc-mode = ; + reg = <0x40064000 0x1000>; + #clock-cells = <1>; + + sosc_clk: sosc_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + status = "disabled"; + }; + + pll: pll { + compatible = "fixed-factor-clock"; + clocks = <&sosc_clk>; + clock-div = <1>; + clock-mult = <40>; + #clock-cells = <0>; + }; + + spll_clk: spll_clk { + compatible = "fixed-factor-clock"; + clocks = <&pll>; + clock-div = <2>; + #clock-cells = <0>; + status = "disabled"; + }; + + sirc_clk: sirc_clk { + compatible = "fixed-clock"; + clock-frequency = <8000000>; + #clock-cells = <0>; + }; + + firc_clk: firc_clk { + compatible = "fixed-clock"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + core_clk: core_clk { + compatible = "fixed-factor-clock"; + clocks = <&firc_clk>; + clock-div = <1>; + #clock-cells = <0>; + }; + + bus_clk: bus_clk { + compatible = "fixed-factor-clock"; + clocks = <&core_clk>; + clock-div = <1>; + #clock-cells = <0>; + }; + + slow_clk: slow_clk { + compatible = "fixed-factor-clock"; + clocks = <&core_clk>; + clock-div = <2>; + #clock-cells = <0>; + }; + + splldiv1_clk: splldiv1_clk { + compatible = "fixed-factor-clock"; + clocks = <&spll_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + splldiv2_clk: splldiv2_clk { + compatible = "fixed-factor-clock"; + clocks = <&spll_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + soscdiv1_clk: soscdiv1_clk { + compatible = "fixed-factor-clock"; + clocks = <&sosc_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + soscdiv2_clk: soscdiv2_clk { + compatible = "fixed-factor-clock"; + clocks = <&sosc_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + sircdiv1_clk: sircdiv1_clk { + compatible = "fixed-factor-clock"; + clocks = <&sirc_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + sircdiv2_clk: sircdiv2_clk { + compatible = "fixed-factor-clock"; + clocks = <&sirc_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + fircdiv1_clk: fircdiv1_clk { + compatible = "fixed-factor-clock"; + clocks = <&firc_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + fircdiv2_clk: fircdiv2_clk { + compatible = "fixed-factor-clock"; + clocks = <&firc_clk>; + clock-div = <0>; + #clock-cells = <0>; + }; + + }; + + pcc: pcc@40065000 { + compatible = "nxp,kinetis-pcc"; + reg = <0x40065000 0x1000>; + #clock-cells = <2>; + }; + + ftfc: flash-controller@40020000 { + compatible = "nxp,kinetis-ftfc"; + reg = <0x40020000 0x1000>; + interrupts = <18 0>, <19 0>, <21 0>; + interrupt-names = "command-complete", "read-collision", "double-bit"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + + edma: dma-controller@40008000 { + compatible = "nxp,mcux-edma"; + nxp,version = <2>; + dma-channels = <16>; + dma-requests = <64>; + nxp,mem2mem; + reg = <0x40008000 0x1000>, <0x40021000 0x1000>; + interrupts = <0 0>, <1 0>, <2 0>, <3 0>, + <4 0>, <5 0>, <6 0>, <7 0>, + <8 0>, <9 0>, <10 0>, <11 0>, + <12 0>, <13 0>, <14 0>, <15 0>, + <16 0>; + #dma-cells = <2>; + status = "disabled"; + }; + + adc0: adc@4003b000 { + compatible = "nxp,adc12"; + reg = <0x4003b000 0x1000>; + interrupts = <39 0>; + clocks = <&pcc 0xec KINETIS_PCC_SRC_FIRC_ASYNC>; + clk-source = <0>; + clk-divider = <1>; + #io-channel-cells = <1>; + status = "disabled"; + }; + + adc1: adc@40027000 { + compatible = "nxp,adc12"; + reg = <0x40027000 0x1000>; + interrupts = <40 0>; + clocks = <&pcc 0x9c KINETIS_PCC_SRC_FIRC_ASYNC>; + clk-source = <0>; + clk-divider = <1>; + #io-channel-cells = <1>; + status = "disabled"; + }; + + cmp0: cmp@40073000 { + compatible = "nxp,kinetis-acmp"; + reg = <0x40073000 0x1000>; + interrupts = <41 0>; + clocks = <&scg KINETIS_SCG_BUS_CLK>; + status = "disabled"; + }; + + enet: ethernet@40079000 { + compatible = "nxp,enet"; + reg = <0x40079000 0x620>; + clocks = <&core_clk>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <73 0>, <74 0>, <75 0>; + interrupt-names = "TX", "RX", "ERR"; + nxp,mdio = <&enet_mdio>; + ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <72 0>; + interrupt-names = "IEEE1588_TMR"; + clocks = <&pcc 0x1e4 KINETIS_PCC_SRC_SPLL_ASYNC>; + status = "disabled"; + }; + }; + + ewm0: ewm@40061000 { + compatible = "nxp,ewm"; + reg = <0x40061000 0x6>; + interrupts = <22 0>; + clk-divider = <0x0>; + status = "disabled"; + }; + + flexcan0: can@40024000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40024000 0x1000>; + interrupts = <78 0>, <79 0>, <80 0>, <81 0>, <82 0>; + interrupt-names = "ored-warning-bus-off", "error", + "wake-up", "mb-0-15", "mb-16-31"; + clocks = <&scg KINETIS_SCG_CORESYS_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexcan1: can@40025000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40025000 0x1000>; + interrupts = <85 0>, <86 0>, <88 0>, <89 0>; + interrupt-names = "ored-warning-bus-off", "error", "mb-0-15", "mb-16-31"; + clocks = <&scg KINETIS_SCG_CORESYS_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexcan2: can@4002b000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x4002b000 0x1000>; + interrupts = <92 0>, <93 0>, <95 0>, <96 0>; + interrupt-names = "ored-warning-bus-off", "error", "mb-0-15", "mb-16-31"; + clocks = <&scg KINETIS_SCG_CORESYS_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexio0: flexio@4005a000 { + compatible = "nxp,flexio"; + reg = <0x4005a000 0x1000>; + interrupts = <69 0>; + clocks = <&pcc 0x168 KINETIS_PCC_SRC_FIRC_ASYNC>; + status = "disabled"; + }; + + ftm0: ftm@40038000 { + compatible = "nxp,ftm"; + reg = <0x40038000 0x1000>; + interrupts = <99 0>, <100 0>, <101 0>, <102 0>, <104 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0xe0 KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + ftm1: ftm@40039000 { + compatible = "nxp,ftm"; + reg = <0x40039000 0x1000>; + interrupts = <105 0>, <106 0>, <107 0>, <108 0>, <110 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0xe4 KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + ftm2: ftm@4003a000 { + compatible = "nxp,ftm"; + reg = <0x4003a000 0x1000>; + interrupts = <111 0>, <112 0>, <113 0>, <114 0>, <116 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0xe8 KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + ftm3: ftm@40026000 { + compatible = "nxp,ftm"; + reg = <0x40026000 0x1000>; + interrupts = <117 0>, <118 0>, <119 0>, <120 0>, <122 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0x98 KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + ftm4: ftm@4006e000 { + compatible = "nxp,ftm"; + reg = <0x4006e000 0x1000>; + interrupts = <123 0>, <124 0>, <125 0>, <126 0>, <128 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0x1b8 KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + ftm5: ftm@4006f000 { + compatible = "nxp,ftm"; + reg = <0x4006f000 0x1000>; + interrupts = <129 0>, <130 0>, <131 0>, <132 0>, <134 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0x1bc KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + ftm6: ftm@40070000 { + compatible = "nxp,ftm"; + reg = <0x40070000 0x1000>; + interrupts = <135 0>, <136 0>, <137 0>, <138 0>, <140 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0x1c0 KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + ftm7: ftm@40071000 { + compatible = "nxp,ftm"; + reg = <0x40071000 0x1000>; + interrupts = <141 0>, <142 0>, <143 0>, <144 0>, <146 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&pcc 0x1c4 KINETIS_PCC_SRC_FIRC_ASYNC>; + prescaler = <1>; + status = "disabled"; + }; + + gpioa: gpio@400ff000 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff000 0x40>; + interrupts = <59 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porta>; + status = "disabled"; + }; + + gpiob: gpio@400ff040 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff040 0x40>; + interrupts = <60 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portb>; + status = "disabled"; + }; + + gpioc: gpio@400ff080 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff080 0x40>; + interrupts = <61 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portc>; + status = "disabled"; + }; + + gpiod: gpio@400ff0c0 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff0c0 0x40>; + interrupts = <62 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portd>; + status = "disabled"; + }; + + gpioe: gpio@400ff100 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff100 0x40>; + interrupts = <63 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porte>; + status = "disabled"; + }; + + lpi2c0: i2c@40066000 { + compatible = "nxp,lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40066000 0x1000>; + interrupts = <24 0>, <25 0>; + interrupt-names = "controller", "target"; + clocks = <&pcc 0x198 KINETIS_PCC_SRC_FIRC_ASYNC>; + status = "disabled"; + }; + + lpi2c1: i2c@40067000 { + compatible = "nxp,lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40067000 0x1000>; + interrupts = <29 0>, <30 0>; + interrupt-names = "controller", "target"; + clocks = <&pcc 0x19c KINETIS_PCC_SRC_FIRC_ASYNC>; + status = "disabled"; + }; + + lpspi0: spi@4002c000 { + compatible = "nxp,lpspi"; + reg = <0x4002c000 0x1000>; + interrupts = <26 0>; + clocks = <&pcc 0xb0 KINETIS_PCC_SRC_FIRC_ASYNC>; + #address-cells = <1>; + #size-cells = <0>; + tx-fifo-size = <4>; + rx-fifo-size = <4>; + status = "disabled"; + }; + + lpspi1: spi@4002d000 { + compatible = "nxp,lpspi"; + reg = <0x4002d000 0x1000>; + interrupts = <27 0>; + clocks = <&pcc 0xb4 KINETIS_PCC_SRC_FIRC_ASYNC>; + #address-cells = <1>; + #size-cells = <0>; + tx-fifo-size = <4>; + rx-fifo-size = <4>; + status = "disabled"; + }; + + lpspi2: spi@4002e000 { + compatible = "nxp,lpspi"; + reg = <0x4002e000 0x1000>; + interrupts = <28 0>; + clocks = <&pcc 0xb8 KINETIS_PCC_SRC_FIRC_ASYNC>; + #address-cells = <1>; + #size-cells = <0>; + tx-fifo-size = <4>; + rx-fifo-size = <4>; + status = "disabled"; + }; + + lptmr0: lptmr@40040000 { + compatible = "nxp,lptmr"; + reg = <0x40040000 0x1000>; + interrupts = <58 0>; + clock-frequency = <1000>; + prescale-glitch-filter = <0>; + clk-source = <1>; + resolution = <16>; + status = "disabled"; + }; + + lpuart0: uart@4006a000 { + compatible = "nxp,lpuart"; + reg = <0x4006a000 0x1000>; + interrupts = <31 0>; + clocks = <&pcc 0x1a8 KINETIS_PCC_SRC_FIRC_ASYNC>; + dmas = <&edma 0 2>, <&edma 1 3>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + lpuart1: uart@4006b000 { + compatible = "nxp,lpuart"; + reg = <0x4006b000 0x1000>; + interrupts = <33 0>; + clocks = <&pcc 0x1ac KINETIS_PCC_SRC_FIRC_ASYNC>; + dmas = <&edma 2 4>, <&edma 3 5>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + lpuart2: uart@4006c000 { + compatible = "nxp,lpuart"; + reg = <0x4006c000 0x1000>; + interrupts = <35 0>; + clocks = <&pcc 0x1b0 KINETIS_PCC_SRC_FIRC_ASYNC>; + dmas = <&edma 4 6>, <&edma 5 7>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + mpu: mpu@4000d000 { + compatible = "nxp,sysmpu"; + reg = <0x4000d000 0x1000>; + status = "disabled"; + }; + + pmc: pmc@4007d000 { + reg = <0x4007d000 0x1000>; + + lpo: lpo128k { + compatible = "fixed-clock"; + clock-frequency = <128000>; + #clock-cells = <0>; + }; + }; + + porta: pinmux@40049000 { + compatible = "nxp,port-pinmux"; + reg = <0x40049000 0x1000>; + clocks = <&pcc 0x124 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + portb: pinmux@4004a000 { + compatible = "nxp,port-pinmux"; + reg = <0x4004a000 0x1000>; + clocks = <&pcc 0x128 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + portc: pinmux@4004b000 { + compatible = "nxp,port-pinmux"; + reg = <0x4004b000 0x1000>; + clocks = <&pcc 0x12c KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + portd: pinmux@4004c000 { + compatible = "nxp,port-pinmux"; + reg = <0x4004c000 0x1000>; + clocks = <&pcc 0x130 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + porte: pinmux@4004d000 { + compatible = "nxp,port-pinmux"; + reg = <0x4004d000 0x1000>; + clocks = <&pcc 0x134 KINETIS_PCC_SRC_NONE_OR_EXT>; + }; + + rtc: rtc@4003d000 { + compatible = "nxp,rtc"; + reg = <0x4003d000 0x1000>; + interrupts = <46 0>, <47 0>; + interrupt-names = "alarm", "seconds"; + clock-source = "LPO"; + clock-frequency = <1000>; + prescaler = <1000>; + status = "disabled"; + }; + + sai0: sai@40054000 { + compatible = "nxp,mcux-i2s"; + reg = < 0x40054000 0x1000>; + clocks = <&scg KINETIS_SCG_BUS_CLK>; + interrupts = <70 0>, <71 0>; + dmas = <&edma 6 60>, <&edma 7 61>; + dma-names = "rx", "tx"; + nxp,rx-dma-channel = <6>; + nxp,tx-dma-channel = <7>; + #address-cells = <1>; + #size-cells = <0>; + #pinmux-cells = <2>; + status = "disabled"; + }; + + sai1: sai@40055000 { + compatible = "nxp,mcux-i2s"; + reg = < 0x40055000 0x1000>; + clocks = <&scg KINETIS_SCG_BUS_CLK>; + interrupts = <55 0>, <56 0>; + dmas = <&edma 8 12>, <&edma 9 13>; + dma-names = "rx", "tx"; + nxp,rx-dma-channel = <8>; + nxp,tx-dma-channel = <9>; + #address-cells = <1>; + #size-cells = <0>; + #pinmux-cells = <2>; + status = "disabled"; + }; + + wdog: watchdog@40052000 { + compatible = "nxp,wdog32"; + reg = <0x40052000 0x1000>; + interrupts = <22 0>; + clocks = <&lpo>; + clk-source = <1>; + clk-divider = <256>; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; From ad5b3494aad8cf0b07c087996ae3445ac26ebef9 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Mon, 29 Sep 2025 17:29:18 +0800 Subject: [PATCH 166/397] boards: nxp: add frdm_mcxe247 board support - support XIP way to boot - add board doc and picture - enable cases below: hello_world/blinky/button/ philosophers/synchronization/ gpio_basic_api/uart_async_api Signed-off-by: Lucien Zhao --- boards/nxp/frdm_mcxe247/CMakeLists.txt | 8 + boards/nxp/frdm_mcxe247/Kconfig | 5 + boards/nxp/frdm_mcxe247/Kconfig.frdm_mcxe247 | 6 + boards/nxp/frdm_mcxe247/board.c | 280 ++++++++++++++++++ boards/nxp/frdm_mcxe247/board.cmake | 11 + boards/nxp/frdm_mcxe247/board.yml | 6 + boards/nxp/frdm_mcxe247/doc/frdm_mcxe247.webp | Bin 0 -> 48446 bytes boards/nxp/frdm_mcxe247/doc/index.rst | 184 ++++++++++++ .../frdm_mcxe247/frdm_mcxe247-pinctrl.dtsi | 29 ++ boards/nxp/frdm_mcxe247/frdm_mcxe247.dts | 164 ++++++++++ boards/nxp/frdm_mcxe247/frdm_mcxe247.yaml | 20 ++ .../nxp/frdm_mcxe247/frdm_mcxe247_defconfig | 10 + .../drivers/gpio/gpio_basic_api/testcase.yaml | 1 + .../uart_async_api/nxp/dut_lpuart1.overlay | 3 +- .../drivers/uart/uart_async_api/testcase.yaml | 1 + 15 files changed, 727 insertions(+), 1 deletion(-) create mode 100644 boards/nxp/frdm_mcxe247/CMakeLists.txt create mode 100644 boards/nxp/frdm_mcxe247/Kconfig create mode 100644 boards/nxp/frdm_mcxe247/Kconfig.frdm_mcxe247 create mode 100644 boards/nxp/frdm_mcxe247/board.c create mode 100644 boards/nxp/frdm_mcxe247/board.cmake create mode 100644 boards/nxp/frdm_mcxe247/board.yml create mode 100644 boards/nxp/frdm_mcxe247/doc/frdm_mcxe247.webp create mode 100644 boards/nxp/frdm_mcxe247/doc/index.rst create mode 100644 boards/nxp/frdm_mcxe247/frdm_mcxe247-pinctrl.dtsi create mode 100644 boards/nxp/frdm_mcxe247/frdm_mcxe247.dts create mode 100644 boards/nxp/frdm_mcxe247/frdm_mcxe247.yaml create mode 100644 boards/nxp/frdm_mcxe247/frdm_mcxe247_defconfig diff --git a/boards/nxp/frdm_mcxe247/CMakeLists.txt b/boards/nxp/frdm_mcxe247/CMakeLists.txt new file mode 100644 index 0000000000000..c06b9273965c0 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_library() +zephyr_library_sources(board.c) diff --git a/boards/nxp/frdm_mcxe247/Kconfig b/boards/nxp/frdm_mcxe247/Kconfig new file mode 100644 index 0000000000000..b3a99a089cd22 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/Kconfig @@ -0,0 +1,5 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FRDM_MCXE247 + select BOARD_EARLY_INIT_HOOK diff --git a/boards/nxp/frdm_mcxe247/Kconfig.frdm_mcxe247 b/boards/nxp/frdm_mcxe247/Kconfig.frdm_mcxe247 new file mode 100644 index 0000000000000..57182b0ef1432 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/Kconfig.frdm_mcxe247 @@ -0,0 +1,6 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FRDM_MCXE247 + select SOC_MCXE247 + select SOC_PART_NUMBER_MCXE247VLQ diff --git a/boards/nxp/frdm_mcxe247/board.c b/boards/nxp/frdm_mcxe247/board.c new file mode 100644 index 0000000000000..845925a3c32c2 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/board.c @@ -0,0 +1,280 @@ +/* + * Copyright 2025 NXP + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define ASSERT_WITHIN_RANGE(val, min, max, str) \ + BUILD_ASSERT(val >= min && val <= max, str) + +#define ASSERT_ASYNC_CLK_DIV_VALID(val, str) \ + BUILD_ASSERT(val == 0 || val == 1 || val == 2 || val == 4 || \ + val == 8 || val == 16 || val == 2 || val == 64, str) + +#define kSCG_AsyncClkDivBy0 kSCG_AsyncClkDisable + +#define TO_SYS_CLK_DIV(val) _DO_CONCAT(kSCG_SysClkDivBy, val) +#define TO_ASYNC_CLK_DIV(val) _DO_CONCAT(kSCG_AsyncClkDivBy, val) + +#define SCG_CLOCK_NODE(name) DT_CHILD(DT_INST(0, nxp_kinetis_scg), name) +#define SCG_CLOCK_DIV(name) DT_PROP(SCG_CLOCK_NODE(name), clock_div) +#define SCG_CLOCK_MULT(name) DT_PROP(SCG_CLOCK_NODE(name), clock_mult) + +/* System Clock configuration */ +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(slow_clk), 2, 8, + "Invalid SCG slow clock divider value"); +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(bus_clk), 1, 16, + "Invalid SCG bus clock divider value"); +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(core_clk), 1, 16, + "Invalid SCG core clock divider value"); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +static const scg_sys_clk_config_t scg_sys_clk_config = { + .divSlow = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(slow_clk)), + .divBus = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(bus_clk)), + .divCore = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(core_clk)), +#if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sosc_clk)) + .src = kSCG_SysClkSrcSysOsc, +#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sirc_clk)) + .src = kSCG_SysClkSrcSirc, +#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(firc_clk)) + .src = kSCG_SysClkSrcFirc, +#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(spll_clk)) + .src = kSCG_SysClkSrcSysPll, +#else +#error Invalid SCG core clock source +#endif +}; + +#if DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) +/* System Oscillator (SOSC) configuration */ +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv1_clk), + "Invalid SCG SOSC divider 1 value"); +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv2_clk), + "Invalid SCG SOSC divider 2 value"); +static const scg_sosc_config_t scg_sosc_config = { + .freq = DT_PROP(SCG_CLOCK_NODE(sosc_clk), clock_frequency), + .monitorMode = kSCG_SysOscMonitorDisable, + .enableMode = kSCG_SysOscEnable, + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv1_clk)), + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv2_clk)), + .workMode = DT_PROP(DT_INST(0, nxp_kinetis_scg), sosc_mode) +}; +#endif /* DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) */ + +/* Slow Internal Reference Clock (SIRC) configuration */ +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv1_clk), + "Invalid SCG SIRC divider 1 value"); +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv2_clk), + "Invalid SCG SIRC divider 2 value"); +static const scg_sirc_config_t scg_sirc_config = { + .enableMode = kSCG_SircEnable | kSCG_SircEnableInLowPower, + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv1_clk)), + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv2_clk)), +#if MHZ(8) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency) + .range = kSCG_SircRangeHigh +#else +#error Invalid SCG SIRC clock frequency +#endif +}; + +/* Fast Internal Reference Clock (FIRC) configuration */ +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv1_clk), + "Invalid SCG FIRC divider 1 value"); +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv2_clk), + "Invalid SCG FIRC divider 2 value"); +static const scg_firc_config_t scg_firc_config = { + .enableMode = kSCG_FircEnable, + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv1_clk)), + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv2_clk)), +#if MHZ(48) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency) + .range = kSCG_FircRange48M, +#else +#error Invalid SCG FIRC clock frequency +#endif + .trimConfig = NULL +}; + +/* System Phase-Locked Loop (SPLL) configuration */ +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(spll_clk), 2, 2, + "Invalid SCG SPLL fixed divider value"); +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv1_clk), + "Invalid SCG SPLL divider 1 value"); +ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv2_clk), + "Invalid SCG SPLL divider 2 value"); +ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(pll), 1, 8, + "Invalid SCG PLL pre divider value"); +ASSERT_WITHIN_RANGE(SCG_CLOCK_MULT(pll), 16, 47, + "Invalid SCG PLL multiplier value"); +#if (DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) && \ + DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(spll_clk))) +static const scg_spll_config_t scg_spll_config = { + .enableMode = kSCG_SysPllEnable, + .monitorMode = kSCG_SysPllMonitorDisable, + .div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv1_clk)), + .div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv2_clk)), +#if !DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(pll)), SCG_CLOCK_NODE(sosc_clk)) +#error Invalid SCG PLL clock source +#endif + .prediv = (SCG_CLOCK_DIV(pll) - 1U), + .mult = (SCG_CLOCK_MULT(pll) - 16U) +}; +#endif + +__weak void clock_init(void) +{ + scg_sys_clk_config_t current; + + const scg_sys_clk_config_t scg_sys_clk_config_safe = { + .divSlow = kSCG_SysClkDivBy4, + .divBus = kSCG_SysClkDivBy1, + .divCore = kSCG_SysClkDivBy1, + .src = kSCG_SysClkSrcSirc + }; + +#if DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) + /* Optionally initialize system oscillator */ + CLOCK_InitSysOsc(&scg_sosc_config); + CLOCK_SetXtal0Freq(scg_sosc_config.freq); +#endif + + /* Configure SIRC */ + CLOCK_InitSirc(&scg_sirc_config); + + /* Temporary switch to safe SIRC in order to configure FIRC */ + CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config_safe); + do { + CLOCK_GetCurSysClkConfig(¤t); + } while (current.src != scg_sys_clk_config_safe.src); + CLOCK_InitFirc(&scg_firc_config); + + #if (DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) && \ + DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(spll_clk))) + /* Configure System PLL only if system oscilator is initialized */ + /* as the oscillator is the only SPLL clock source.*/ + CLOCK_InitSysPll(&scg_spll_config); + #endif + + /* Only RUN mode supported for now */ + CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config); + do { + CLOCK_GetCurSysClkConfig(¤t); + } while (current.src != scg_sys_clk_config.src); + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart0)) + CLOCK_SetIpSrc(kCLOCK_Lpuart0, + DT_CLOCKS_CELL(DT_NODELABEL(lpuart0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart1)) + CLOCK_SetIpSrc(kCLOCK_Lpuart1, + DT_CLOCKS_CELL(DT_NODELABEL(lpuart1), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart2)) + CLOCK_SetIpSrc(kCLOCK_Lpuart2, + DT_CLOCKS_CELL(DT_NODELABEL(lpuart2), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c0)) + CLOCK_SetIpSrc(kCLOCK_Lpi2c0, + DT_CLOCKS_CELL(DT_NODELABEL(lpi2c0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c1)) + CLOCK_SetIpSrc(kCLOCK_Lpi2c1, + DT_CLOCKS_CELL(DT_NODELABEL(lpi2c1), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi0)) + CLOCK_SetIpSrc(kCLOCK_Lpspi0, + DT_CLOCKS_CELL(DT_NODELABEL(lpspi0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi1)) + CLOCK_SetIpSrc(kCLOCK_Lpspi1, + DT_CLOCKS_CELL(DT_NODELABEL(lpspi1), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi2)) + CLOCK_SetIpSrc(kCLOCK_Lpspi2, + DT_CLOCKS_CELL(DT_NODELABEL(lpspi2), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(adc0)) + CLOCK_SetIpSrc(kCLOCK_Adc0 + DT_CLOCKS_CELL(DT_NODELABEL(adc0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(adc1)) + CLOCK_SetIpSrc(kCLOCK_Adc1, + DT_CLOCKS_CELL(DT_NODELABEL(adc1), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm0)) + CLOCK_SetIpSrc(kCLOCK_Ftm0, + DT_CLOCKS_CELL(DT_NODELABEL(ftm0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm1)) + CLOCK_SetIpSrc(kCLOCK_Ftm1, + DT_CLOCKS_CELL(DT_NODELABEL(ftm1), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm2)) + CLOCK_SetIpSrc(kCLOCK_Ftm2, + DT_CLOCKS_CELL(DT_NODELABEL(ftm2), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm3)) + CLOCK_SetIpSrc(kCLOCK_Ftm3, + DT_CLOCKS_CELL(DT_NODELABEL(ftm3), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm4)) + CLOCK_SetIpSrc(kCLOCK_Ftm4, + DT_CLOCKS_CELL(DT_NODELABEL(ftm4), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm5)) + CLOCK_SetIpSrc(kCLOCK_Ftm5, + DT_CLOCKS_CELL(DT_NODELABEL(ftm5), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm6)) + CLOCK_SetIpSrc(kCLOCK_Ftm6, + DT_CLOCKS_CELL(DT_NODELABEL(ftm6), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm7)) + CLOCK_SetIpSrc(kCLOCK_Ftm7, + DT_CLOCKS_CELL(DT_NODELABEL(ftm7), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ewm0)) + CLOCK_SetIpSrc(kCLOCK_Ewm0, + DT_CLOCKS_CELL(DT_NODELABEL(ewm0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio0)) + CLOCK_SetIpSrc(kCLOCK_Flexio0, + DT_CLOCKS_CELL(DT_NODELABEL(flexio0), ip_source)); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet_ptp_clock)) + CLOCK_SetIpSrc(kCLOCK_Enet, + DT_CLOCKS_CELL(DT_NODELABEL(enet_ptp_clock), ip_source)); +#endif +} + +void board_early_init_hook(void) +{ +#if !defined(CONFIG_ARM_MPU) + uint32_t temp_reg; +#endif /* !CONFIG_ARM_MPU */ + +#if !defined(CONFIG_ARM_MPU) + /* + * Disable memory protection and clear slave port errors. + * MCXE24x does not implement the optional ARMv7-M memory + * protection unit (MPU), specified by the architecture (PMSAv7), in the + * Cortex-M4 core. Instead, the processor includes its own MPU module. + */ + temp_reg = SYSMPU->CESR; + temp_reg &= ~SYSMPU_CESR_VLD_MASK; + temp_reg |= SYSMPU_CESR_SPERR_MASK; + SYSMPU->CESR = temp_reg; +#endif /* !CONFIG_ARM_MPU */ + + clock_init(); +} diff --git a/boards/nxp/frdm_mcxe247/board.cmake b/boards/nxp/frdm_mcxe247/board.cmake new file mode 100644 index 0000000000000..948436a6df9f6 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/board.cmake @@ -0,0 +1,11 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_runner_args(linkserver "--device=MCXE247:FRDM-MCXE247") +board_runner_args(jlink "--device=MCXE247") + +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/nxp/frdm_mcxe247/board.yml b/boards/nxp/frdm_mcxe247/board.yml new file mode 100644 index 0000000000000..91abc6945b247 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/board.yml @@ -0,0 +1,6 @@ +board: + name: frdm_mcxe247 + full_name: FRDM-MCXE247 + vendor: nxp + socs: + - name: mcxe247 diff --git a/boards/nxp/frdm_mcxe247/doc/frdm_mcxe247.webp b/boards/nxp/frdm_mcxe247/doc/frdm_mcxe247.webp new file mode 100644 index 0000000000000000000000000000000000000000..9e3df04f39d07ce467e91cac1137743e01023433 GIT binary patch literal 48446 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 + +&pinctrl { + pinmux_lpuart1: pinmux_lpuart1 { + group0 { + pinmux = , + ; + drive-strength = "low"; + slew-rate = "fast"; + input-enable; + }; + }; + + pinmux_lpuart2: pinmux_lpuart2 { + group0 { + pinmux = , + ; + drive-strength = "low"; + slew-rate = "slow"; + }; + }; +}; diff --git a/boards/nxp/frdm_mcxe247/frdm_mcxe247.dts b/boards/nxp/frdm_mcxe247/frdm_mcxe247.dts new file mode 100644 index 0000000000000..e7ae5b968abb7 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/frdm_mcxe247.dts @@ -0,0 +1,164 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "frdm_mcxe247-pinctrl.dtsi" +#include +#include + +/ { + model = "NXP FRDM-MCXE247 board"; + compatible = "nxp,mcxe247", "nxp,mcx"; + + aliases { + led0 = &red_led; + led1 = &green_led; + led2 = &blue_led; + sw0 = &user_button_2; + sw1 = &user_button_3; + }; + + chosen { + zephyr,sram = &sram_l; + zephyr,flash = &flash0; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + zephyr,canbus = &flexcan0; + }; + + leds { + compatible = "gpio-leds"; + red_led: led_0 { + gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + label = "Red LED"; + }; + green_led: led_1 { + gpios = <&gpiob 11 GPIO_ACTIVE_LOW>; + label = "Green LED"; + }; + blue_led: led_2 { + gpios = <&gpioc 12 GPIO_ACTIVE_LOW>; + label = "Blue LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button_2: button_2 { + label = "User SW2"; + gpios = <&gpioa 9 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + user_button_3: button_3 { + label = "User SW3"; + gpios = <&gpioc 10 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; + +&cpu0 { + clock-frequency = <80000000>; +}; + +&sosc_clk { + clock-frequency = <8000000>; + status = "okay"; +}; + +&spll_clk { + status = "okay"; +}; + +&core_clk { + clocks = <&spll_clk>; + clock-div = <2>; +}; + +&bus_clk { + clock-div = <2>; +}; + +&slow_clk { + clock-div = <4>; +}; + +&fircdiv2_clk { + clock-div = <1>; +}; + +&soscdiv2_clk { + clock-div = <1>; +}; + +&gpioa { + status = "okay"; +}; + +&gpiob { + status = "okay"; +}; + +&gpioc { + status = "okay"; +}; + +&gpiod { + status = "okay"; +}; + +&gpioe { + status = "okay"; +}; + +&lpuart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart1>; + pinctrl-names = "default"; +}; + +&lpuart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart2>; + pinctrl-names = "default"; +}; + +&edma { + status = "okay"; +}; diff --git a/boards/nxp/frdm_mcxe247/frdm_mcxe247.yaml b/boards/nxp/frdm_mcxe247/frdm_mcxe247.yaml new file mode 100644 index 0000000000000..1946cb7b28012 --- /dev/null +++ b/boards/nxp/frdm_mcxe247/frdm_mcxe247.yaml @@ -0,0 +1,20 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: frdm_mcxe247 +name: NXP FRDM-MCXE247 +type: mcu +arch: arm +ram: 128 +flash: 1536 +toolchain: + - zephyr + - gnuarmemb +supported: + - uart + - gpio + - arduino_gpio +vendor: nxp diff --git a/boards/nxp/frdm_mcxe247/frdm_mcxe247_defconfig b/boards/nxp/frdm_mcxe247/frdm_mcxe247_defconfig new file mode 100644 index 0000000000000..a13393c8e5dcd --- /dev/null +++ b/boards/nxp/frdm_mcxe247/frdm_mcxe247_defconfig @@ -0,0 +1,10 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y diff --git a/tests/drivers/gpio/gpio_basic_api/testcase.yaml b/tests/drivers/gpio/gpio_basic_api/testcase.yaml index 03de83aaa5d0b..3dc1580e6f773 100644 --- a/tests/drivers/gpio/gpio_basic_api/testcase.yaml +++ b/tests/drivers/gpio/gpio_basic_api/testcase.yaml @@ -58,6 +58,7 @@ tests: - frdm_k64f platform_exclude: # below boards are customized + - frdm_mcxe247 - mimxrt595_evk/mimxrt595s/cm33 - mimxrt1020_evk - mimxrt1040_evk diff --git a/tests/drivers/uart/uart_async_api/nxp/dut_lpuart1.overlay b/tests/drivers/uart/uart_async_api/nxp/dut_lpuart1.overlay index f39495eaff84c..e7257cfe798cf 100644 --- a/tests/drivers/uart/uart_async_api/nxp/dut_lpuart1.overlay +++ b/tests/drivers/uart/uart_async_api/nxp/dut_lpuart1.overlay @@ -1,11 +1,12 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * SPDX-License-Identifier: Apache-2.0 */ /* * To test this sample * frdm_mcxa156 connect P3_20 to P3_21 + * frdm_mcxe247 connect J5-3 to J5-4 */ dut: &lpuart1 {}; diff --git a/tests/drivers/uart/uart_async_api/testcase.yaml b/tests/drivers/uart/uart_async_api/testcase.yaml index 843c03d2a6839..9b3bfcbda552b 100644 --- a/tests/drivers/uart/uart_async_api/testcase.yaml +++ b/tests/drivers/uart/uart_async_api/testcase.yaml @@ -75,6 +75,7 @@ tests: extra_args: - platform:frdm_k82f/mk82f25615:"DTC_OVERLAY_FILE=nxp/dut_lpuart0_loopback.overlay" - platform:frdm_mcxa156/mcxa156:"DTC_OVERLAY_FILE=nxp/dut_lpuart1.overlay" + - platform:frdm_mcxe247/mcxe247:"DTC_OVERLAY_FILE=nxp/dut_lpuart1.overlay" - platform:frdm_mcxa153/mcxa153:"DTC_OVERLAY_FILE=nxp/dut_lpuart2_loopback.overlay;nxp/enable_edma0.overlay" - platform:frdm_mcxa346/mcxa346:"DTC_OVERLAY_FILE=nxp/dut_lpuart3_loopback.overlay;nxp/enable_edma0.overlay" - platform:frdm_mcxa266/mcxa266:"DTC_OVERLAY_FILE=nxp/dut_lpuart3_loopback.overlay;nxp/enable_edma0.overlay" From 45e81b4461b82498bc950341343a294c35155cc5 Mon Sep 17 00:00:00 2001 From: Titouan Christophe Date: Thu, 7 Aug 2025 10:03:34 +0200 Subject: [PATCH 167/397] crypto: hash: in_buf should be constant Hashing takes an input buffer, and writes the result in a separate output buffer. Therefore, the input can be marked as constant, so that constants can be supplied directly to the hashing context without any intermediate copy, and without having to perform a type-unsafe cast from (const uint8_t *) to (uint8_t *) Signed-off-by: Titouan Christophe --- doc/releases/migration-guide-4.3.rst | 7 +++++++ doc/releases/release-notes-4.3.rst | 4 ++++ include/zephyr/crypto/hash.h | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/releases/migration-guide-4.3.rst b/doc/releases/migration-guide-4.3.rst index b5a4a81afdda4..930bcf3d60d2b 100644 --- a/doc/releases/migration-guide-4.3.rst +++ b/doc/releases/migration-guide-4.3.rst @@ -334,6 +334,13 @@ Cellular * :c:enum:`cellular_access_technology` values have been redefined to align with 3GPP TS 27.007. * :c:enum:`cellular_registration_status` values have been extended to align with 3GPP TS 27.007. +Crypto +====== + +* Hashing operations now require a constant input in the :c:struct:`hash_pkt`. + This shouldn't affect any existing code, unless an out-of-tree hashing backend actually + performs that operation in-place (see :github:`94218`) + Flash Map ========= diff --git a/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index 814c0f6bab5f8..6d300cfea7a30 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -51,6 +51,10 @@ API Changes .. Only removed, deprecated and new APIs, changes go in migration guide. +* Crypto + + * The input buffer in :c:struct:`hash_pkt` is now constant + Removed APIs and options ======================== diff --git a/include/zephyr/crypto/hash.h b/include/zephyr/crypto/hash.h index c2f548406c86f..015b8887d1143 100644 --- a/include/zephyr/crypto/hash.h +++ b/include/zephyr/crypto/hash.h @@ -88,7 +88,7 @@ struct hash_ctx { struct hash_pkt { /** Start address of input buffer */ - uint8_t *in_buf; + const uint8_t *in_buf; /** Bytes to be operated upon */ size_t in_len; From 527e2edaf3b85721476feb8ca0c3d0e0645bee98 Mon Sep 17 00:00:00 2001 From: Titouan Christophe Date: Thu, 7 Aug 2025 14:52:18 +0200 Subject: [PATCH 168/397] drivers: crypto: hash_pkt.in_buf is now constant Previous commit made the input buffer of the hash packet constant. Let's therefore adapt typing where used, and remove inappropriate casts of constant buffers to non-constant ones. All the "backend" hashing functions already take a constant input, these changes only affect the "plumbing" between the Zephyr crypto API and the actual implementation where applicable. Signed-off-by: Titouan Christophe --- drivers/crypto/crypto_mchp_xec_symcr.c | 2 +- drivers/crypto/crypto_rts5912_sha.c | 2 +- drivers/crypto/crypto_smartbond.c | 2 +- .../microchip/mec172xevb_assy6906/rom_api/src/main.c | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/crypto_mchp_xec_symcr.c b/drivers/crypto/crypto_mchp_xec_symcr.c index 0845009802457..3d3ea836475f2 100644 --- a/drivers/crypto/crypto_mchp_xec_symcr.c +++ b/drivers/crypto/crypto_mchp_xec_symcr.c @@ -358,7 +358,7 @@ static int xec_symcr_do_hash(struct hash_ctx *ctx, struct hash_pkt *pkt, bool fi hs->blklen = 0; /* consumed */ } - ret = mchp_xec_rom_hash_feed_wrapper(c, (const uint8_t *)pkt->in_buf, fill_len); + ret = mchp_xec_rom_hash_feed_wrapper(c, pkt->in_buf, fill_len); if (ret) { LOG_ERR("ROM hash feed error %d", ret); return ret; diff --git a/drivers/crypto/crypto_rts5912_sha.c b/drivers/crypto/crypto_rts5912_sha.c index 113c8d8a90b56..dc4ab4ec89e9e 100644 --- a/drivers/crypto/crypto_rts5912_sha.c +++ b/drivers/crypto/crypto_rts5912_sha.c @@ -122,7 +122,7 @@ static int rts5912_sha256_process(const struct device *dev, uint8_t *input, size return 0; } -static int rts5912_sha256_update(const struct device *dev, uint8_t *input, size_t len) +static int rts5912_sha256_update(const struct device *dev, const uint8_t *input, size_t len) { struct rts5912_sha256_context *rts5912_sha256_ctx = dev->data; uint32_t remain, fill, blk_size = 0, ret_val = 0; diff --git a/drivers/crypto/crypto_smartbond.c b/drivers/crypto/crypto_smartbond.c index 1cff9f046c4bc..3861e74409aa4 100644 --- a/drivers/crypto/crypto_smartbond.c +++ b/drivers/crypto/crypto_smartbond.c @@ -390,7 +390,7 @@ static int crypto_smartbond_hash_set_algo(enum hash_algo algo) return 0; } -static int crypto_smartbond_set_in_out_buf(uint8_t *in_buf, uint8_t *out_buf, int len) +static int crypto_smartbond_set_in_out_buf(const uint8_t *in_buf, uint8_t *out_buf, int len) { if (in_buf == NULL) { return -EIO; diff --git a/samples/boards/microchip/mec172xevb_assy6906/rom_api/src/main.c b/samples/boards/microchip/mec172xevb_assy6906/rom_api/src/main.c index 9fe0fbc5a4d8e..0c3fcce0d8f9d 100644 --- a/samples/boards/microchip/mec172xevb_assy6906/rom_api/src/main.c +++ b/samples/boards/microchip/mec172xevb_assy6906/rom_api/src/main.c @@ -441,7 +441,7 @@ static int test_zephyr_hash_chunk_block_size(const struct hash_tp *htbl, size_t /* SHA algorithms block sizes are powers of 2 */ updatesz = msgsz & ~(blocksz - 1u); printf(" Update size is %d\n", updatesz); - zhash_pkt.in_buf = (uint8_t *)msgptr; + zhash_pkt.in_buf = msgptr; zhash_pkt.in_len = updatesz; zhash_pkt.out_buf = digest; zhash_pkt.ctx = &zhash_ctx; @@ -459,7 +459,7 @@ static int test_zephyr_hash_chunk_block_size(const struct hash_tp *htbl, size_t printf(" Final size is %u\n", msgsz); - zhash_pkt.in_buf = (uint8_t *)msgptr; + zhash_pkt.in_buf = msgptr; zhash_pkt.in_len = msgsz; zhash_pkt.out_buf = digest; zhash_pkt.ctx = &zhash_ctx; @@ -536,7 +536,7 @@ static int test_zephyr_hash_chunk(const struct hash_tp *htbl, size_t nentries, s while (chunksz && ((msgsz - total_updatesz) > chunksz)) { chunk_cnt++; - zhash_pkt.in_buf = (uint8_t *)msgptr; + zhash_pkt.in_buf = msgptr; zhash_pkt.in_len = updatesz; zhash_pkt.out_buf = digest; zhash_pkt.ctx = &zhash_ctx; @@ -553,7 +553,7 @@ static int test_zephyr_hash_chunk(const struct hash_tp *htbl, size_t nentries, s } remsz = msgsz - total_updatesz; - zhash_pkt.in_buf = (uint8_t *)msgptr; + zhash_pkt.in_buf = msgptr; zhash_pkt.in_len = remsz; zhash_pkt.out_buf = digest; zhash_pkt.ctx = &zhash_ctx; From a8bfb253eabf02f7add7ddeffcf12df54aa5bb01 Mon Sep 17 00:00:00 2001 From: Scott Worley Date: Mon, 16 Jun 2025 11:53:26 -0400 Subject: [PATCH 169/397] dts: arm: microchip: mec: Add MEC5 HAL based GIRQ information Microchip MEC SoC's include an interrupt aggregator affecting the routing of interrupt to the ARM NVIC. IA can not be treated as a true second level interrupt controller. All interrupt sources with the exception of GPIOs and eSPI virtual wires can be routed by IA to individial NVIC inputs. Each bank of GPIOs and VWires are aggregated into a single NVIC input per bank. For the NVIC to receive the interrupt signal the respective GIRQ enable must be set. We attempted to add this informatation by encoding the DT irq property. This exeperiment failed due to how Zephyr builds the interrupt tables and MEC IA is not a true second level interrupt controller. Therefore, drivers for MEC peripherals need to GIRQ number and bit position to pass to HAL API's or if a driver is implemented in the linux style without using the full MEC HAL the GIRQ information is present in DT. Signed-off-by: Scott Worley --- dts/arm/microchip/mec/mec5.dtsi | 164 +++++++++++++----- .../microchip/mec/mec5/mec5_pkg176_uarts.dtsi | 25 --- dts/arm/microchip/mec/mec5_mec1743qlj.dtsi | 29 +++- dts/arm/microchip/mec/mec5_mec1743qsz.dtsi | 15 +- dts/arm/microchip/mec/mec5_mec1753qlj.dtsi | 28 ++- dts/arm/microchip/mec/mec5_mec1753qsz.dtsi | 15 +- dts/arm/microchip/mec/mec5_mech1723nlj.dtsi | 1 + dts/arm/microchip/mec/mec5_mech1723nsz.dtsi | 1 + dts/bindings/gpio/microchip,mec5-gpio.yaml | 2 +- dts/bindings/serial/microchip,mec5-uart.yaml | 2 +- dts/bindings/spi/microchip,mec5-qspi.yaml | 2 +- 11 files changed, 205 insertions(+), 79 deletions(-) delete mode 100644 dts/arm/microchip/mec/mec5/mec5_pkg176_uarts.dtsi diff --git a/dts/arm/microchip/mec/mec5.dtsi b/dts/arm/microchip/mec/mec5.dtsi index b0e3ad69cf82c..87b9345e37692 100644 --- a/dts/arm/microchip/mec/mec5.dtsi +++ b/dts/arm/microchip/mec/mec5.dtsi @@ -34,6 +34,7 @@ reg = <0x40080100 0x100 0x4000a400 0x100>; reg-names = "pcrr", "vbatr"; interrupts = <174 0>; + girqs = <20 9>; status = "disabled"; }; @@ -171,6 +172,7 @@ reg = <0x40081000 0x80 0x40081300 0x04 0x40081380 0x04 0x400813fc 0x04>; interrupts = <3 2>; + girqs = <11 255>; gpio-controller; #gpio-cells = <2>; }; @@ -180,6 +182,7 @@ reg = <0x40081080 0x80 0x40081304 0x04 0x40081384 0x04 0x400813f8 0x4>; interrupts = <2 2>; + girqs = <10 255>; gpio-controller; #gpio-cells = <2>; }; @@ -190,7 +193,8 @@ 0x40081388 0x04 0x400813f4 0x04>; gpio-controller; interrupts = <1 2>; - #gpio-cells = <2>; + girqs = <9 255>; + #gpio-cells=<2>; }; gpio_140_176: gpio@40081180 { @@ -199,7 +203,8 @@ 0x4008138c 0x04 0x400813f0 0x04>; gpio-controller; interrupts = <0 2>; - #gpio-cells = <2>; + girqs = <8 255>; + #gpio-cells=<2>; }; gpio_200_236: gpio@40081200 { @@ -208,7 +213,8 @@ 0x40081390 0x04 0x400813ec 0x04>; gpio-controller; interrupts = <4 2>; - #gpio-cells = <2>; + girqs = <12 255>; + #gpio-cells=<2>; }; gpio_240_276: gpio@40081280 { @@ -217,25 +223,29 @@ 0x40081394 0x04 0x400813e8 0x04>; gpio-controller; interrupts = <17 2>; - #gpio-cells = <2>; + girqs = <26 255>; + #gpio-cells=<2>; }; }; uart0: uart@400f2400 { reg = <0x400f2400 0x400>; interrupts = <40 1>; + girqs = <15 0>; status = "disabled"; }; uart1: uart@400f2800 { reg = <0x400f2800 0x400>; interrupts = <41 1>; + girqs = <15 1>; status = "disabled"; }; watchdog0: watchdog@40000400 { reg = <0x40000400 0x400>; interrupts = <171 0>; + girqs = <21 2>; status = "disabled"; }; @@ -253,6 +263,7 @@ compatible = "microchip,xec-basic-timer"; reg = <0x40000c00 0x20>; interrupts = <136 0>; + girqs = <23 0>; clock-frequency = <48000000>; prescaler = <0>; max-value = <0xffff>; @@ -263,6 +274,7 @@ compatible = "microchip,xec-basic-timer"; reg = <0x40000c20 0x20>; interrupts = <137 0>; + girqs = <23 1>; clock-frequency = <48000000>; prescaler = <0>; max-value = <0xffff>; @@ -273,6 +285,7 @@ compatible = "microchip,xec-basic-timer"; reg = <0x40000c40 0x20>; interrupts = <138 0>; + girqs = <23 2>; clock-frequency = <48000000>; prescaler = <0>; max-value = <0xffff>; @@ -283,6 +296,7 @@ compatible = "microchip,xec-basic-timer"; reg = <0x40000c60 0x20>; interrupts = <139 0>; + girqs = <23 3>; clock-frequency = <48000000>; prescaler = <0>; max-value = <0xffff>; @@ -293,6 +307,7 @@ compatible = "microchip,xec-basic-timer"; reg = <0x40000c80 0x20>; interrupts = <140 0>; + girqs = <23 4>; clock-frequency = <48000000>; prescaler = <0>; max-value = <0xffffffff>; @@ -303,6 +318,7 @@ compatible = "microchip,xec-basic-timer"; reg = <0x40000ca0 0x20>; interrupts = <141 0>; + girqs = <23 5>; clock-frequency = <48000000>; prescaler = <0>; max-value = <0xffffffff>; @@ -312,57 +328,69 @@ cntr0: timer@40000d00 { reg = <0x40000d00 0x20>; interrupts = <142 0>; + girqs = <23 6>; status = "disabled"; }; cntr1: timer@40000d20 { reg = <0x40000d20 0x20>; interrupts = <143 0>; + girqs = <23 7>; status = "disabled"; }; cntr2: timer@40000d40 { reg = <0x40000d40 0x20>; interrupts = <144 0>; + girqs = <23 8>; status = "disabled"; }; cntr3: timer@40000d60 { reg = <0x40000d60 0x20>; interrupts = <145 0>; + girqs = <23 9>; status = "disabled"; }; cctmr0: timer@40001000 { reg = <0x40001000 0x40>; interrupts = <146 0>, <147 0>, <148 0>, <149 0>, - <150 0>, <151 0>, <152 0>, <153 0>, - <154 0>; + <150 0>, <151 0>, <152 0>, <153 0>, <154 0>; + interrupt-names = "counter", "cap0", "cap1", "cap2", "cap3", + "cap4", "cap5", "comp0", "comp1"; + girqs = <18 20>, <18 21>, <18 22>, <18 23>, + <18 24>, <18 25>, <18 26>, <18 27>, <18 28>; status = "disabled"; }; hibtimer0: timer@40009800 { reg = <0x40009800 0x20>; interrupts = <112 0>; + girqs = <23 16>; status = "disabled"; }; hibtimer1: timer@40009820 { reg = <0x40009820 0x20>; interrupts = <113 0>; + girqs = <23 17>; status = "disabled"; }; weektmr0: timer@4000ac80 { reg = <0x4000ac80 0x80>; - interrupts = <114 0>, <115 0>, <116 0>, - <117 0>, <118 0>; + interrupts = <114 0>, <115 0>, <116 0>, <117 0>, <118 0>; + interrupt-names = "wk_alarm", "subwk_alarm", "one_sec", "sub_sec", "syspp"; + girqs = <21 3>, <21 4>, <21 5>, <21 6>, <21 7>; status = "disabled"; }; rtc0: rtc@400f5000 { reg = <0x400f5000 0x100>; interrupts = <119 3>, <120 3>; + interrupt-names = "rtc", "rtc_alarm"; + girqs = <21 8>, <21 9>; status = "disabled"; }; @@ -374,15 +402,18 @@ vci0: vci@4000ae00 { reg = <0x4000ae00 0x40>; - interrupts = <121 0>, <122 0>, <123 0>, - <124 0>, <125 0>; + interrupts = <121 2>, <122 2>, <123 2>, <124 2>, <125 2>, <126 2>; + interrupt-names = "vci_ovrd_in", "vci_in0", "vci_in1", "vci_in2", + "vci_in3", "vci_in4"; + girqs = <21 10>, <21 11>, <21 12>, <21 13>, <21 14>, <21 15>; status = "disabled"; }; i2c_smb_0: i2c@40004000 { reg = <0x40004000 0x80>; clock-frequency = ; - interrupts = <20 1>; + interrupts = <20 2>; + girqs = <13 0>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -391,7 +422,8 @@ i2c_smb_1: i2c@40004400 { reg = <0x40004400 0x80>; clock-frequency = ; - interrupts = <21 1>; + interrupts = <21 2>; + girqs = <13 1>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -400,7 +432,8 @@ i2c_smb_2: i2c@40004800 { reg = <0x40004800 0x80>; clock-frequency = ; - interrupts = <22 1>; + interrupts = <22 2>; + girqs = <13 2>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -409,7 +442,8 @@ i2c_smb_3: i2c@40004c00 { reg = <0x40004C00 0x80>; clock-frequency = ; - interrupts = <23 1>; + interrupts = <23 2>; + girqs = <13 3>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -418,7 +452,8 @@ i2c_smb_4: i2c@40005000 { reg = <0x40005000 0x80>; clock-frequency = ; - interrupts = <158 1>; + interrupts = <158 2>; + girqs = <13 4>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -426,7 +461,8 @@ ps2_0: ps2@40009000 { reg = <0x40009000 0x40>; - interrupts = <100 1>; + interrupts = <100 3>; + girqs = <18 10>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -488,7 +524,8 @@ tach0: tach@40006000 { reg = <0x40006000 0x10>; - interrupts = <71 4>; + interrupts = <71 3>; + girqs = <17 1>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -496,7 +533,8 @@ tach1: tach@40006010 { reg = <0x40006010 0x10>; - interrupts = <72 4>; + interrupts = <72 3>; + girqs = <17 2>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -504,7 +542,8 @@ tach2: tach@40006020 { reg = <0x40006020 0x10>; - interrupts = <73 4>; + interrupts = <73 3>; + girqs = <17 3>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -512,7 +551,8 @@ tach3: tach@40006030 { reg = <0x40006030 0x10>; - interrupts = <159 4>; + interrupts = <159 3>; + girqs = <17 4>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -520,19 +560,25 @@ rpmfan0: rpmfan@4000a000 { reg = <0x4000a000 0x80>; - interrupts = <74 1>, <75 1>; + interrupts = <74 3>, <75 3>; + interrupt-names = "stall", "spin"; + girqs = <17 20>, <17 21>; status = "disabled"; }; rpmfan1: rpmfan@4000a080 { reg = <0x4000a080 0x80>; - interrupts = <76 1>, <77 1>; + interrupts = <76 3>, <77 3>; + interrupt-names = "stall", "spin"; + girqs = <17 22>, <17 23>; status = "disabled"; }; adc0: adc@40007c00 { reg = <0x40007c00 0x90>; - interrupts = <78 0>, <79 0>; + interrupts = <78 3>, <79 3>; + interrupt-names = "single", "repeat"; + girqs = <17 8>, <17 9>; interrupt-names = "single", "repeat"; status = "disabled"; #io-channel-cells = <1>; @@ -541,7 +587,8 @@ peci0: peci@40006400 { reg = <0x40006400 0x80>; - interrupts = <70 4>; + interrupts = <70 3>; + girqs = <17 0>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -550,6 +597,7 @@ qspi0: spi@40070000 { reg = <0x40070000 0x400>; interrupts = <91 2>; + girqs = <18 1>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -557,55 +605,65 @@ prochot0: prochot@40003400 { reg = <0x40003400 0x20>; - interrupts = <87 0>; + interrupts = <87 3>; + girqs = <17 17>; status = "disabled"; }; rcid0: rcid@40001400 { reg = <0x40001400 0x80>; - interrupts = <80 0>; + interrupts = <80 3>; + girqs = <17 10>; status = "disabled"; }; rcid1: rcid@40001480 { reg = <0x40001480 0x80>; - interrupts = <81 0>; + interrupts = <81 3>; + girqs = <17 11>; status = "disabled"; }; rcid2: rcid@40001500 { reg = <0x40001500 0x80>; - interrupts = <82 0>; + interrupts = <82 3>; + girqs = <17 12>; status = "disabled"; }; bbled0: bbled@4000b800 { reg = <0x4000b800 0x100>; - interrupts = <83 0>; + interrupts = <83 3>; + girqs = <17 13>; status = "disabled"; }; bbled1: bbled@4000b900 { reg = <0x4000b900 0x100>; - interrupts = <84 0>; + interrupts = <84 3>; + girqs = <17 14>; status = "disabled"; }; bbled2: bbled@4000ba00 { reg = <0x4000ba00 0x100>; - interrupts = <85 0>; + interrupts = <85 3>; + girqs = <17 15>; status = "disabled"; }; bbled3: bbled@4000bb00 { reg = <0x4000bb00 0x100>; - interrupts = <86 0>; + interrupts = <86 3>; + girqs = <17 16>; status = "disabled"; }; bclink0: bclink@4000cd00 { reg = <0x4000cd00 0x20>; - interrupts = <96 0>, <97 0>; + interrupts = <96 3>, <97 3>; + interrupt-names = "bcm_err", "bcm_done"; + girqs = <18 7>, <18 6>; status = "disabled"; }; @@ -632,6 +690,8 @@ interrupt-names = "pc", "bm1", "bm2", "ltr", "oob_up", "oob_dn", "fc", "erst", "vw_chan_en", "vwct_0_6", "vwct_7_10"; + girqs = <19 0>, <19 1>, <19 2>, <19 3>, <19 4>, <19 5>, + <19 6>, <19 7>, <19 8>, <24 255>, <25 255>; status = "disabled"; /* Devices accessible to the Host via Logical Device mechanism. @@ -642,6 +702,7 @@ mbox0: mbox@400f0000 { reg = <0x400f0000 0x200>; interrupts = <60 3>; + girqs = <15 20>; status = "disabled"; }; @@ -649,6 +710,7 @@ reg = <0x400f0400 0x400>, <0x400f2000 0x400>; interrupts = <59 3>, <58 3>; interrupt-names = "ibf", "obe"; + girqs = <15 19>, <15 18>; status = "disabled"; }; @@ -656,6 +718,7 @@ reg = <0x400f0800 0x400>; interrupts = <45 3>, <46 3>; interrupt-names = "ibf", "obe"; + girqs = <15 5>, <15 6>; status = "disabled"; }; @@ -663,6 +726,7 @@ reg = <0x400f0c00 0x400>; interrupts = <47 3>, <48 3>; interrupt-names = "ibf", "obe"; + girqs = <15 7>, <15 8>; status = "disabled"; }; @@ -670,6 +734,7 @@ reg = <0x400f1000 0x400>; interrupts = <49 3>, <50 3>; interrupt-names = "ibf", "obe"; + girqs = <15 9>, <15 10>; status = "disabled"; }; @@ -677,6 +742,7 @@ reg = <0x400f1400 0x400>; interrupts = <51 3>, <52 3>; interrupt-names = "ibf", "obe"; + girqs = <15 11>, <15 12>; status = "disabled"; }; @@ -684,6 +750,7 @@ reg = <0x400f1800 0x400>; interrupts = <53 3>, <54 3>; interrupt-names = "ibf", "obe"; + girqs = <15 13>, <15 14>; status = "disabled"; }; @@ -691,30 +758,35 @@ reg = <0x400f1c00 0x400>; interrupts = <55 3>, <56 3>, <57 3>; interrupt-names = "ctl", "en", "sts"; + girqs = <15 15>, <15 16>, <15 17>; status = "disabled"; }; glue: glue_logic@400f3c00 { reg = <0x400f3c00 0x200>; interrupts = <172 1>; + girqs = <21 26>; status = "disabled"; }; emi0: emi@400f4000 { reg = <0x400f4000 0x400>; interrupts = <42 3>; + girqs = <15 2>; status = "disabled"; }; emi1: emi@400f4400 { reg = <0x400f4400 0x400>; interrupts = <43 3>; + girqs = <15 3>; status = "disabled"; }; emi2: emi@400f4800 { reg = <0x400f4800 0x400>; interrupts = <44 3>; + girqs = <15 4>; status = "disabled"; }; @@ -725,21 +797,23 @@ p80bd0: p80bd@400f8000 { reg = <0x400f8000 0x400>; interrupts = <62 0>; + girqs = <15 22>; status = "disabled"; }; - }; - /* eSPI target attached flash controller. - * When this device is fully activated via its driver, it takes - * ownership of the QSPI controller. EC access to QSPI - * registers is discarded by hardware. - */ - espi_taf0: espi_taf@40008000 { - reg = <0x40008000 0x400>, <0x40070000 0x400>, <0x40071000 0x400>; - reg-names = "tafbr", "tafqspi", "tafcomm"; - interrupts = <166 3>, <167 3>; - interrupt-names = "done", "err"; - status = "disabled"; + /* eSPI target attached flash controller. + * When this device is fully activated via its driver, it takes + * ownership of the QSPI controller. EC access to QSPI + * registers is discarded by hardware. + */ + espi_taf0: espi_taf@40008000 { + reg = <0x40008000 0x400>, <0x40071000 0x400>; + reg-names = "tafbr", "tafcomm"; + interrupts = <166 3>, <167 3>; + interrupt-names = "done", "err"; + girqs = <19 9>, <19 10>; + status = "disabled"; + }; }; }; }; diff --git a/dts/arm/microchip/mec/mec5/mec5_pkg176_uarts.dtsi b/dts/arm/microchip/mec/mec5/mec5_pkg176_uarts.dtsi deleted file mode 100644 index b1ebea4552707..0000000000000 --- a/dts/arm/microchip/mec/mec5/mec5_pkg176_uarts.dtsi +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2024 Microchip Technology Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* Microchip MEC5 MEC174x, MEC540x, MEC175x, and MEC550x add two more UART's - * in the 176-pin (LJ) package. - * Include this file in the soc {} section in the above chip DTSI files. - */ -uart2: uart@400f2c00 { - reg = <0x400f2c00 0x400>; - interrupts = <183 1>; - clock-frequency = <1843200>; - current-speed = <38400>; - status = "disabled"; -}; - -uart3: uart@400f3000 { - reg = <0x400f3000 0x400>; - interrupts = <184 1>; - clock-frequency = <1843200>; - current-speed = <38400>; - status = "disabled"; -}; diff --git a/dts/arm/microchip/mec/mec5_mec1743qlj.dtsi b/dts/arm/microchip/mec/mec5_mec1743qlj.dtsi index 694e95fa885ef..3cc2cc8d2d567 100644 --- a/dts/arm/microchip/mec/mec5_mec1743qlj.dtsi +++ b/dts/arm/microchip/mec/mec5_mec1743qlj.dtsi @@ -23,11 +23,38 @@ #include "mec5/mec5_gpspi_v2.dtsi" #include "mec5/mec5_eeprom_8kb.dtsi" #include "mec5/mec5_pkg176_pwms.dtsi" - #include "mec5/mec5_pkg176_uarts.dtsi" + + ps2_1: ps2@40009040 { + reg = <0x40009040 0x40>; + interrupts = <101 3>; + girqs = <18 11>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; kscan0: kscan@40009c00 { reg = <0x40009c00 0x18>; interrupts = <135 0>; + girqs = <21 25>; + status = "disabled"; + }; + + uart2: uart@400f2c00 { + reg = <0x400f2c00 0x400>; + interrupts = <183 2>; + girqs = <15 25>; + clock-frequency = <1843200>; + current-speed = <115200>; + status = "disabled"; + }; + + uart3: uart@400f3000 { + reg = <0x400f3000 0x400>; + interrupts = <184 2>; + girqs = <15 26>; + clock-frequency = <1843200>; + current-speed = <115200>; status = "disabled"; }; }; diff --git a/dts/arm/microchip/mec/mec5_mec1743qsz.dtsi b/dts/arm/microchip/mec/mec5_mec1743qsz.dtsi index 5d16b727bf5c3..e5b18db3e2f82 100644 --- a/dts/arm/microchip/mec/mec5_mec1743qsz.dtsi +++ b/dts/arm/microchip/mec/mec5_mec1743qsz.dtsi @@ -23,17 +23,28 @@ #include "mec5/mec5_gpspi_v2.dtsi" #include "mec5/mec5_eeprom_8kb.dtsi" + ps2_1: ps2@40009040 { + reg = <0x40009040 0x40>; + interrupts = <101 3>; + girqs = <18 11>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + kscan0: kscan@40009c00 { reg = <0x40009c00 0x18>; interrupts = <135 0>; + girqs = <21 25>; status = "disabled"; }; uart2: uart@400f2c00 { reg = <0x400f2c00 0x400>; - interrupts = <183 1>; + interrupts = <183 2>; + girqs = <15 25>; clock-frequency = <1843200>; - current-speed = <38400>; + current-speed = <115200>; status = "disabled"; }; }; diff --git a/dts/arm/microchip/mec/mec5_mec1753qlj.dtsi b/dts/arm/microchip/mec/mec5_mec1753qlj.dtsi index 1d278d3e7db8a..cd9fa15534c6e 100644 --- a/dts/arm/microchip/mec/mec5_mec1753qlj.dtsi +++ b/dts/arm/microchip/mec/mec5_mec1753qlj.dtsi @@ -23,13 +23,39 @@ #include "mec5/mec5_eeprom_8kb.dtsi" #include "mec5/mec5_gpspi_v2.dtsi" #include "mec5/mec5_pkg176_pwms.dtsi" - #include "mec5/mec5_pkg176_uarts.dtsi" #include "mec5/mec5_i3c.dtsi" + ps2_1: ps2@40009040 { + reg = <0x40009040 0x40>; + interrupts = <101 3>; + girqs = <18 11>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + kscan0: kscan@40009c00 { reg = <0x40009c00 0x18>; interrupts = <135 0>; status = "disabled"; }; + + uart2: uart@400f2c00 { + reg = <0x400f2c00 0x400>; + interrupts = <183 2>; + girqs = <15 25>; + clock-frequency = <1843200>; + current-speed = <115200>; + status = "disabled"; + }; + + uart3: uart@400f3000 { + reg = <0x400f3000 0x400>; + interrupts = <184 2>; + girqs = <15 26>; + clock-frequency = <1843200>; + current-speed = <115200>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/microchip/mec/mec5_mec1753qsz.dtsi b/dts/arm/microchip/mec/mec5_mec1753qsz.dtsi index df30851445728..f80e73d29f640 100644 --- a/dts/arm/microchip/mec/mec5_mec1753qsz.dtsi +++ b/dts/arm/microchip/mec/mec5_mec1753qsz.dtsi @@ -24,17 +24,28 @@ #include "mec5/mec5_gpspi_v2.dtsi" #include "mec5/mec5_i3c.dtsi" + ps2_1: ps2@40009040 { + reg = <0x40009040 0x40>; + interrupts = <101 3>; + girqs = <18 11>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + kscan0: kscan@40009c00 { reg = <0x40009c00 0x18>; interrupts = <135 0>; + girqs = <21 25>; status = "disabled"; }; uart2: uart@400f2c00 { reg = <0x400f2c00 0x400>; - interrupts = <183 1>; + interrupts = <183 2>; + girqs = <15 25>; clock-frequency = <1843200>; - current-speed = <38400>; + current-speed = <115200>; status = "disabled"; }; }; diff --git a/dts/arm/microchip/mec/mec5_mech1723nlj.dtsi b/dts/arm/microchip/mec/mec5_mech1723nlj.dtsi index 82a0aa2b2e048..ef52a56ea76d9 100644 --- a/dts/arm/microchip/mec/mec5_mech1723nlj.dtsi +++ b/dts/arm/microchip/mec/mec5_mech1723nlj.dtsi @@ -27,6 +27,7 @@ kscan0: kscan@40009c00 { reg = <0x40009c00 0x18>; interrupts = <135 0>; + girqs = <21 25>; status = "disabled"; }; }; diff --git a/dts/arm/microchip/mec/mec5_mech1723nsz.dtsi b/dts/arm/microchip/mec/mec5_mech1723nsz.dtsi index 02cdbab26fc69..8184582e83c1b 100644 --- a/dts/arm/microchip/mec/mec5_mech1723nsz.dtsi +++ b/dts/arm/microchip/mec/mec5_mech1723nsz.dtsi @@ -26,6 +26,7 @@ kscan0: kscan@40009c00 { reg = <0x40009c00 0x18>; interrupts = <135 0>; + girqs = <21 25>; status = "disabled"; }; }; diff --git a/dts/bindings/gpio/microchip,mec5-gpio.yaml b/dts/bindings/gpio/microchip,mec5-gpio.yaml index d9ae269a5d708..da82c417e01db 100644 --- a/dts/bindings/gpio/microchip,mec5-gpio.yaml +++ b/dts/bindings/gpio/microchip,mec5-gpio.yaml @@ -5,7 +5,7 @@ description: Microchip MEC5 GPIO compatible: "microchip,mec5-gpio" -include: [gpio-controller.yaml, base.yaml] +include: ["gpio-controller.yaml", "base.yaml", "microchip,dmec-ecia-girq.yaml"] properties: reg: diff --git a/dts/bindings/serial/microchip,mec5-uart.yaml b/dts/bindings/serial/microchip,mec5-uart.yaml index d37c196d046bc..701ec588db5bb 100644 --- a/dts/bindings/serial/microchip,mec5-uart.yaml +++ b/dts/bindings/serial/microchip,mec5-uart.yaml @@ -5,7 +5,7 @@ description: Microchip MEC5 UART compatible: "microchip,mec5-uart" -include: [uart-controller.yaml, pinctrl-device.yaml] +include: [uart-controller.yaml, pinctrl-device.yaml, "microchip,dmec-ecia-girq.yaml"] properties: reg: diff --git a/dts/bindings/spi/microchip,mec5-qspi.yaml b/dts/bindings/spi/microchip,mec5-qspi.yaml index b7cff7fb8d9bf..01adeadbfd4b6 100644 --- a/dts/bindings/spi/microchip,mec5-qspi.yaml +++ b/dts/bindings/spi/microchip,mec5-qspi.yaml @@ -5,7 +5,7 @@ description: Microchip MEC5 series QSPI controller compatible: "microchip,mec5-qspi" -include: [spi-controller.yaml, pinctrl-device.yaml] +include: ["spi-controller.yaml", "pinctrl-device.yaml", "microchip,dmec-ecia-girq.yaml"] properties: reg: From 8183636ff418eb45ea2227a52ecaa3e035e66403 Mon Sep 17 00:00:00 2001 From: Stanley Huang Date: Fri, 8 Aug 2025 11:53:11 +0800 Subject: [PATCH 170/397] board: Rename raytac_an54l15q_db to raytac_an54lq_db_15 Renamed raytac_an54l15q_db to raytac_an54lq_db_15. Signed-off-by: Stanley Huang --- boards/deprecated.cmake | 3 ++ boards/raytac/an54l15q_db/Kconfig.defconfig | 25 --------- .../an54l15q_db/Kconfig.raytac_an54l15q_db | 8 --- boards/raytac/an54l15q_db/board.yml | 45 ---------------- .../doc/img/raytac_an54l15q_db.webp | Bin 55756 -> 0 bytes .../{an54l15q_db => an54lq_db_15}/Kconfig | 6 +-- boards/raytac/an54lq_db_15/Kconfig.defconfig | 28 ++++++++++ .../an54lq_db_15/Kconfig.raytac_an54lq_db_15 | 8 +++ .../{an54l15q_db => an54lq_db_15}/board.cmake | 4 +- boards/raytac/an54lq_db_15/board.yml | 48 ++++++++++++++++++ .../doc/img/raytac_an54lq_db_15.webp | Bin 0 -> 58832 bytes .../doc/index.rst | 24 ++++----- .../raytac_an54lq_db_15-pinctrl.dtsi} | 0 .../raytac_an54lq_db_15_common.dtsi} | 6 ++- .../raytac_an54lq_db_15_cpuapp_common.dtsi} | 24 ++++++++- .../raytac_an54lq_db_15_nrf54l15_cpuapp.dts} | 7 ++- .../raytac_an54lq_db_15_nrf54l15_cpuapp.yaml} | 6 +-- ...ac_an54lq_db_15_nrf54l15_cpuapp_defconfig} | 3 -- ...aytac_an54lq_db_15_nrf54l15_cpuapp_ns.dts} | 7 +-- ...ytac_an54lq_db_15_nrf54l15_cpuapp_ns.yaml} | 4 +- ...an54lq_db_15_nrf54l15_cpuapp_ns_defconfig} | 1 - .../raytac_an54lq_db_15_nrf54l15_cpuflpr.dts} | 6 +-- ...raytac_an54lq_db_15_nrf54l15_cpuflpr.yaml} | 4 +- ...c_an54lq_db_15_nrf54l15_cpuflpr_defconfig} | 0 ...tac_an54lq_db_15_nrf54l15_cpuflpr_xip.dts} | 2 +- ...ac_an54lq_db_15_nrf54l15_cpuflpr_xip.yaml} | 4 +- ...54lq_db_15_nrf54l15_cpuflpr_xip_defconfig} | 0 doc/_scripts/redirects.py | 1 + doc/releases/release-notes-4.2.rst | 2 +- ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 samples/drivers/adc/adc_dt/sample.yaml | 2 +- ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 samples/drivers/adc/adc_sequence/sample.yaml | 2 +- ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 ...tac_an54lq_db_15_nrf54l15_cpuflpr.overlay} | 0 ...an54lq_db_15_nrf54l15_cpuflpr_xip.overlay} | 0 samples/drivers/watchdog/sample.yaml | 2 +- ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 2 +- tests/drivers/adc/adc_api/testcase.yaml | 3 +- ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 ...tac_an54lq_db_15_nrf54l15_cpuflpr.overlay} | 0 ...an54lq_db_15_nrf54l15_cpuflpr_xip.overlay} | 0 .../watchdog/wdt_basic_api/testcase.yaml | 2 +- ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 .../watchdog/wdt_error_cases/testcase.yaml | 4 +- ...ytac_an54lq_db_15_nrf54l15_cpuapp.overlay} | 0 48 files changed, 159 insertions(+), 134 deletions(-) delete mode 100644 boards/raytac/an54l15q_db/Kconfig.defconfig delete mode 100644 boards/raytac/an54l15q_db/Kconfig.raytac_an54l15q_db delete mode 100644 boards/raytac/an54l15q_db/board.yml delete mode 100644 boards/raytac/an54l15q_db/doc/img/raytac_an54l15q_db.webp rename boards/raytac/{an54l15q_db => an54lq_db_15}/Kconfig (87%) create mode 100644 boards/raytac/an54lq_db_15/Kconfig.defconfig create mode 100644 boards/raytac/an54lq_db_15/Kconfig.raytac_an54lq_db_15 rename boards/raytac/{an54l15q_db => an54lq_db_15}/board.cmake (82%) create mode 100644 boards/raytac/an54lq_db_15/board.yml create mode 100644 boards/raytac/an54lq_db_15/doc/img/raytac_an54lq_db_15.webp rename boards/raytac/{an54l15q_db => an54lq_db_15}/doc/index.rst (81%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_pinctrl.dtsi => an54lq_db_15/raytac_an54lq_db_15-pinctrl.dtsi} (100%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_common.dtsi => an54lq_db_15/raytac_an54lq_db_15_common.dtsi} (96%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi => an54lq_db_15/raytac_an54lq_db_15_cpuapp_common.dtsi} (84%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.dts => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.dts} (70%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.yaml => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.yaml} (75%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_defconfig => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_defconfig} (81%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.dts => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.dts} (90%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.yaml => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.yaml} (74%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns_defconfig => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns_defconfig} (97%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.dts => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.dts} (86%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.yaml => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.yaml} (68%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_defconfig => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_defconfig} (100%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.dts => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.dts} (81%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.yaml => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.yaml} (65%) rename boards/raytac/{an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip_defconfig => an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip_defconfig} (100%) rename samples/drivers/adc/adc_dt/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) rename samples/drivers/adc/adc_sequence/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) rename samples/drivers/watchdog/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) rename samples/drivers/watchdog/boards/{raytac_an54l15q_db_nrf54l15_cpuflpr.overlay => raytac_an54lq_db_15_nrf54l15_cpuflpr.overlay} (100%) rename samples/drivers/watchdog/boards/{raytac_an54l15q_db_nrf54l15_cpuflpr_xip.overlay => raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.overlay} (100%) rename tests/drivers/adc/adc_accuracy_test/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) rename tests/drivers/adc/adc_api/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (95%) rename tests/drivers/adc/adc_error_cases/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) rename tests/drivers/watchdog/wdt_basic_api/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) rename tests/drivers/watchdog/wdt_basic_api/boards/{raytac_an54l15q_db_nrf54l15_cpuflpr.overlay => raytac_an54lq_db_15_nrf54l15_cpuflpr.overlay} (100%) rename tests/drivers/watchdog/wdt_basic_api/boards/{raytac_an54l15q_db_nrf54l15_cpuflpr_xip.overlay => raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.overlay} (100%) rename tests/drivers/watchdog/wdt_error_cases/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) rename tests/drivers/watchdog/wdt_variables/boards/{raytac_an54l15q_db_nrf54l15_cpuapp.overlay => raytac_an54lq_db_15_nrf54l15_cpuapp.overlay} (100%) diff --git a/boards/deprecated.cmake b/boards/deprecated.cmake index 1cc3856cee8ad..871cd600f8053 100644 --- a/boards/deprecated.cmake +++ b/boards/deprecated.cmake @@ -67,3 +67,6 @@ set(esp32_devkitc_wrover/esp32/appcpu_DEPRECATED set(scobc_module1_DEPRECATED scobc_a1 ) +set(raytac_an54l15q_db/nrf54l15/cpuapp_DEPRECATED + raytac_an54lq_db_15/nrf54l15/cpuapp +) diff --git a/boards/raytac/an54l15q_db/Kconfig.defconfig b/boards/raytac/an54l15q_db/Kconfig.defconfig deleted file mode 100644 index 0d903ea091d05..0000000000000 --- a/boards/raytac/an54l15q_db/Kconfig.defconfig +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2024 Nordic Semiconductor ASA -# Copyright (c) 2025 Raytac Corporation. -# SPDX-License-Identifier: Apache-2.0 - -# Workaround for not being able to have commas in macro arguments -DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition -DT_CHOSEN_Z_SRAM_PARTITION := zephyr,sram-secure-partition - -if BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUAPP_NS - -config HAS_BT_CTLR - default BT - -config FLASH_LOAD_OFFSET - default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) - -config FLASH_LOAD_SIZE - default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) - -# By default, if we build for a Non-Secure version of the board, -# enable building with TF-M as the Secure Execution Environment. -config BUILD_WITH_TFM - default y - -endif # BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUAPP_NS diff --git a/boards/raytac/an54l15q_db/Kconfig.raytac_an54l15q_db b/boards/raytac/an54l15q_db/Kconfig.raytac_an54l15q_db deleted file mode 100644 index 58f42ef31d9d9..0000000000000 --- a/boards/raytac/an54l15q_db/Kconfig.raytac_an54l15q_db +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2024 Nordic Semiconductor ASA -# Copyright (c) 2025 Raytac Corporation. -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_RAYTAC_AN54L15Q_DB - select SOC_NRF54L15_CPUAPP if BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUAPP || BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUAPP_NS - select SOC_NRF54L15_CPUFLPR if BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUFLPR || \ - BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUFLPR_XIP diff --git a/boards/raytac/an54l15q_db/board.yml b/boards/raytac/an54l15q_db/board.yml deleted file mode 100644 index 08d0e2398e7bc..0000000000000 --- a/boards/raytac/an54l15q_db/board.yml +++ /dev/null @@ -1,45 +0,0 @@ -board: - name: raytac_an54l15q_db - full_name: AN54L15Q-DB - vendor: raytac - socs: - - name: nrf54l15 - variants: - - name: xip - cpucluster: cpuflpr - - name: ns - cpucluster: cpuapp -runners: - run_once: - '--recover': - - runners: - - nrfjprog - - nrfutil - run: first - groups: - - boards: - - raytac_an54l15q_db/nrf54l15/cpuapp - - raytac_an54l15q_db/nrf54l15/cpuflpr - - raytac_an54l15q_db/nrf54l15/cpuflpr/xip - '--erase': - - runners: - - nrfjprog - - jlink - - nrfutil - run: first - groups: - - boards: - - raytac_an54l15q_db/nrf54l15/cpuapp - - raytac_an54l15q_db/nrf54l15/cpuflpr - - raytac_an54l15q_db/nrf54l15/cpuflpr/xip - '--reset': - - runners: - - nrfjprog - - jlink - - nrfutil - run: last - groups: - - boards: - - raytac_an54l15q_db/nrf54l15/cpuapp - - raytac_an54l15q_db/nrf54l15/cpuflpr - - raytac_an54l15q_db/nrf54l15/cpuflpr/xip diff --git a/boards/raytac/an54l15q_db/doc/img/raytac_an54l15q_db.webp b/boards/raytac/an54l15q_db/doc/img/raytac_an54l15q_db.webp deleted file mode 100644 index 35ecd0b4e90da0eecfce73f55c1d09f6db927d5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55756 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 lCDH%@00000000000000000000000000000000000004jjjXwYY diff --git a/boards/raytac/an54l15q_db/Kconfig b/boards/raytac/an54lq_db_15/Kconfig similarity index 87% rename from boards/raytac/an54l15q_db/Kconfig rename to boards/raytac/an54lq_db_15/Kconfig index 69aa54f32207a..091071d266a1e 100644 --- a/boards/raytac/an54l15q_db/Kconfig +++ b/boards/raytac/an54lq_db_15/Kconfig @@ -2,9 +2,9 @@ # Copyright (c) 2025 Raytac Corporation. # SPDX-License-Identifier: Apache-2.0 -# Raytac AN54L15Q-DB board configuration +# Raytac AN54LQ-DB-15 board configuration -if BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUAPP_NS +if BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP_NS DT_NRF_MPC := $(dt_nodelabel_path,nrf_mpc) @@ -28,4 +28,4 @@ config NRF_TRUSTZONE_RAM_REGION_SIZE This abstraction allows us to configure TrustZone without depending on peripheral specific symbols. -endif #BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUAPP_NS +endif # BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP_NS diff --git a/boards/raytac/an54lq_db_15/Kconfig.defconfig b/boards/raytac/an54lq_db_15/Kconfig.defconfig new file mode 100644 index 0000000000000..ca2937b18b044 --- /dev/null +++ b/boards/raytac/an54lq_db_15/Kconfig.defconfig @@ -0,0 +1,28 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# Copyright (c) 2025 Raytac Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config HW_STACK_PROTECTION + default ARCH_HAS_STACK_PROTECTION + +if BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP + +config ROM_START_OFFSET + default 0x800 if BOOTLOADER_MCUBOOT + +endif # BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP + +if BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP_NS + +config BOARD_RAYTAC_AN54LQ_DB_15 + select USE_DT_CODE_PARTITION if BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP_NS + +config HAS_BT_CTLR + default BT + +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y + +endif # BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP_NS diff --git a/boards/raytac/an54lq_db_15/Kconfig.raytac_an54lq_db_15 b/boards/raytac/an54lq_db_15/Kconfig.raytac_an54lq_db_15 new file mode 100644 index 0000000000000..6a590ffc75b11 --- /dev/null +++ b/boards/raytac/an54lq_db_15/Kconfig.raytac_an54lq_db_15 @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# Copyright (c) 2025 Raytac Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RAYTAC_AN54LQ_DB_15 + select SOC_NRF54L15_CPUAPP if BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP || BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP_NS + select SOC_NRF54L15_CPUFLPR if BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUFLPR || \ + BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUFLPR_XIP diff --git a/boards/raytac/an54l15q_db/board.cmake b/boards/raytac/an54lq_db_15/board.cmake similarity index 82% rename from boards/raytac/an54l15q_db/board.cmake rename to boards/raytac/an54lq_db_15/board.cmake index 368bcc9d2fee1..522a505cf5c39 100644 --- a/boards/raytac/an54l15q_db/board.cmake +++ b/boards/raytac/an54lq_db_15/board.cmake @@ -3,12 +3,12 @@ # SPDX-License-Identifier: Apache-2.0 if(CONFIG_SOC_NRF54L15_CPUAPP) - board_runner_args(jlink "--device=nRF54L15_M33" "--speed=4000") + board_runner_args(jlink "--device=nRF54L15_M33" "--speed=4000") elseif (CONFIG_SOC_NRF54L15_CPUFLPR) board_runner_args(jlink "--device=nRF54L15_RV32") endif() -if(BOARD_RAYTAC_AN54L15Q_DB_NRF54L15_CPUAPP_NS) +if(BOARD_RAYTAC_AN54LQ_DB_15_NRF54L15_CPUAPP_NS) set(TFM_PUBLIC_KEY_FORMAT "full") endif() diff --git a/boards/raytac/an54lq_db_15/board.yml b/boards/raytac/an54lq_db_15/board.yml new file mode 100644 index 0000000000000..e9d165d9b7cf9 --- /dev/null +++ b/boards/raytac/an54lq_db_15/board.yml @@ -0,0 +1,48 @@ +board: + name: raytac_an54lq_db_15 + full_name: AN54LQ-DB-15 + vendor: raytac + socs: + - name: nrf54l15 + variants: + - name: xip + cpucluster: cpuflpr + - name: ns + cpucluster: cpuapp +runners: + run_once: + '--recover': + - runners: + - nrfjprog + - nrfutil + run: first + groups: + - boards: + - raytac_an54lq_db_15/nrf54l15/cpuapp + - raytac_an54lq_db_15/nrf54l15/cpuapp/ns + - raytac_an54lq_db_15/nrf54l15/cpuflpr + - raytac_an54lq_db_15/nrf54l15/cpuflpr/xip + '--erase': + - runners: + - nrfjprog + - jlink + - nrfutil + run: first + groups: + - boards: + - raytac_an54lq_db_15/nrf54l15/cpuapp + - raytac_an54lq_db_15/nrf54l15/cpuapp/ns + - raytac_an54lq_db_15/nrf54l15/cpuflpr + - raytac_an54lq_db_15/nrf54l15/cpuflpr/xip + '--reset': + - runners: + - nrfjprog + - jlink + - nrfutil + run: last + groups: + - boards: + - raytac_an54lq_db_15/nrf54l15/cpuapp + - raytac_an54lq_db_15/nrf54l15/cpuapp/ns + - raytac_an54lq_db_15/nrf54l15/cpuflpr + - raytac_an54lq_db_15/nrf54l15/cpuflpr/xip diff --git a/boards/raytac/an54lq_db_15/doc/img/raytac_an54lq_db_15.webp b/boards/raytac/an54lq_db_15/doc/img/raytac_an54lq_db_15.webp new file mode 100644 index 0000000000000000000000000000000000000000..a31e8cd06341cbcae8e9d7609cfb9feda5165040 GIT binary patch literal 58832 zcmV(*K;FMnNk&G< z{~PNa=S}Nx{zLJbi~pj&E&h4^U;MwzPdk4!`ycfm;lI-VzW*EZclz)8{xE(6{4d+D zRKCT&*Zeo+pU$uDf9wCO@=xZU`oDEwAs?N8Q2%-T|JUE}zxMy2|C{4IxqrO;ZxxGST5tx3+r?toR-6H$_VHM@6{i4b zeY{pJg=7RZwkAL_8d920mxn27%WZjMk*G|VOIQu@(bmcKaww&U_>Gg z5GzUG2{-(pO3QziU_>GZ>C8WBCZBSsD^2H%+xQvvoTo6~`G!~Jtl8{&`RRX!(U9L> zK%v)&FhY3R4Q{|5Ow&|9cFOL;Ul*;~PUw$-{0Cy^$5fRGz+;oPNWm%nv3N;GvwWN- zGxrIu$t%v7n~>~zKT64OvZ#jqdD0B>q~pGio$Ao)2HkuhT^ew-JGN15L1#9` zG=w^AvOS4oZM%zFfg@4RcNSj!V1%qRx*83&=i4i z{pVzo%{tFp{^3AC(Bb^3@1R0@gqCZmx`|SBrQd%fF8V`>5G4Xu53$iNh2^d6&}sMC z;#R{N4V?y$PrRzWL%+o2z;P{|0J0h`{#Q4xuguStjRZXuQ5QZTq37d^cOTsdbOHSo z5?)jK8RDffe*xNc;iQxN+*!MK?A zhEd|gh?E8qkeP_W>_DgwcxVYT0~j;rU_*s8O2V%aE1WA{?+W;TNti_SkpqyqB5ZKDP+>ss9m}{Zk+{*oC9{{^1G~hX>NSvnny?{>)LQdaNbu|gqjIH(TdpK4 zfk}8BB7V-@Z(|=8r6(h6k>gfPrzgsYHAC&TC>Mr=67f zyHk0$hy+8@3I;jQqIY~n@H%*j@n)&nj7`JjY61@AugHEZa<7;*j9m|D0!fT3dq^8z zSYzW&6CNNoM|H7@wT9enU$wr`DV5Q^4veaWQ*8JC>|nv zggL>`0KTBnx3H7X0Y#}tn|_VlhBx5@XS|)DbvhoJ07R}gnkeIjr^oO(bD&>*j4=|u z$sou&siaabP@HOCw|KMXCpjrOJ~CCr8F`e*f;VX(M{~{v3G$^R2f>05V07sv>F5;{D3l%)h7&U?7_9)BTHwD#S(ZXi;m;FhgW-DhpP>XTQ`n zD|;gGsOlTCzFKb*_zi@5Qcu$kwnPT^+AyHlSu?^oj2u1xyH%rymO3BJZvGCGI%lD3 zaN)quMZT3IH4?Vg^TS_;A4kwP$ClKC2p4>T9GrhK9?veks<@E_PWJ5Uo=nvF+(Dmg zZ+3jE@Eu+?b1KdDkrQeA%#HwMcQ1Ys2|^=>RnxMp3SFt!g4*(=5>9IMUM>*$SC1>F zBGf|#D3~P46x4PnxxAx?aUqYPDJTq6pC-C;AIJ9qb^>CuC*rLQhqIcT`=26wKUWHLQY z^;>lX?BUN8tFv6yH0TArZpsra7J4T6=cz8Y9SVGjHX0-lRAr}<& zqQ;qX`o72NbJgGKB8Mw9wW|Uet;u^L-1o~u<6G3;F6h*iglI;N-ms*ix4yUQ;E@Xv zbQ9RAqC9z|^%@}Mf97v=nxY`B!ydj|$y9^V!QS+v`8e&uA@`K+HHgB8V%Rm)bCxkv zj}+0QyL8i6l%LpeIk~D??Ay7j0WNKd8{`F>nGDDatGS~OnT4m*%ly^SZDzQ>agUj! z>iH~_{=;bn88?#t8hn_`)yIFD#L7hyil-MYSrYB3Ds<-$Y-$RDZBd4_yV57s+Vu{B zz&LQQC&!z>j|aZ6!ctuDpLWHrt@@Z|#bO%`qXLDhb(RrIT<722loC#eh}E7OpgC$S zOdA=ZoU9toaltMcFiS%DdRcC-zM=Z$}^^|566Nq zDlKnALlcbQP$KU$?-v0M;mwTrOEpe=8GAR#Xba9@InOo;-Haa?dWQ2le{ZmFG*ZlX zR^$$%jb2cB6F$K6tQyZ%;j=z{>C1QA?Z!Ti{Vk4FY808IMb`)#6DIOnbVoPun6$Ar;!;#M?sYctQqe-GzB>l;hDcD zD~itdb*?zF3ZU}FV(=m9gQ%wHxH@A(*{XHM`(9=77FXbTp{Q{AUn}e@N;nIZ$v<&g z#u=DA!HI%zo~pP1`y+N)*i+>;ChPBZ`GDvB7JV~m=n-e zQasqbfc-$C>-hGzo7ESBpPX(a!gmf-%Wwj~SuxZYs#5cIP`Ng3%AcAa`5k-@+Wvk2e4&njlm79me>ti z9!rK`r(jEA>8J9^HFh1>(~)%0x(6kDD}5@8EKjEo5l;NVF3wLQsHTC*Y${!u3p6|M zEU3+KZ|<>2t?IryPodAb4IP6oFs^YO%85s`K5mV>Sr_P?>zdOk*5$~J+Sthd0P;nn zKjf-wHCC1`Kf3;Oez`$Kkk`72K9om(21B^ZZxp`o&xD=iMy>Qk4E(t-lgO($Hy5yN z@I0jA{ZmAuBP=8Pw1dDF@^rFm2rrbSXVJQK9h3~7taZ5{qNuE?=T3_n$g=Y75c9_# zz{SCHoQu8sf>Jgmjf|MK`+QQNu|S{slut73?h#Zysbb^&fvL+)W{F@B-Xb17-La=3 zq2_nLaFY*Hgj%!;A8pAZV?^j}6RGI1q}ZVL|HZC3m94x@j=cvU!N{HaJ`8NXOW>pV z3*pxK`Y1*Ia6FjiJSmc%J-Y-mzsuH;|1f;hox#lL&j%9#N8l=*RbsLD-}tE9^DR}S zi;waNq2qOol&1hHppcX_!zPSzD9m&7i9e5AxPuBle zxImh|+kkqRdW{B$(J_UNK*@ts1a}n5wTjU@uL#J|Qa{xi#3XC z^%U^Q@!a)-h?|}2rD>G|ef$*1xK-yW3`I@j{39?IU&{~x5v3*B48BIAj_(p}1a|!b#MOg{9>Sa-bkJ$nV@w>| zw-%@5R|Y{+rCUEDYUbL4wBA9oGK~0qw7d^m+-NIeX7TCgan(iWRU-&a==?~yms>Ah zvU}SRy#POU@Vam#_+Aw6XJUccKnt6Rj#A|w)l|3?yP1~uF&j}R{X1dtZPCVjOPX#4 z?&jSOCM8y;`)unU7_F}2@;<4A$qJY&>;9iXW5tZ-y1QcgRd%SKoGd;FB#odMCr1(HY~5`Tz~wa=sizMjE?Si0l=M zIP{iy@i96N2j>#B7one@&Z2+pm!meO$30*!seRX5k3s=5NE9x zdsC&r)28hv{)f8}zBCUJL^PnnLMJ{jQqJG&qJMLk?X9tr?^kU?YdsO?wjL(s3;HD| z1_O$+Pz(l+;-IZJkImzz)y=i1Sa2N-ZOn81Gj_(kH?=djkE4X>{_E3Ku!&eT-mb8O z;_0PLI>v^el0m~MKWGsq*lYq*%?Qvwl;8UMlMMTA6G(=zQO!$7j+SNdLn+!*B!W#< zGuYM5vUtz%Ia#k+9>3+K_bwcB(P@-2!Q@D}$`wPy zcaxckQRzEQ-X)90Sq?62vN}^AUqOa|PP`SOYaCoAYe$xkbz*ju8;WppB!^ z@2KYC{V+`r8}`l(PDmMuX}hFpa=wKb?~HGjNZ2r^-2bTB)~kvT-p4-%A#*W(hOx#v zm<%&TMrQ9PHuXyjg}uO7?fyZbIs1Jah#~)h`AxVz&v&e_xZGfA!khg~myNEV>f4hM zpp`~F2pJ=px*;l%Q7;t4M`dms7*V)#WP?0B@Nr9R3kv;7qu2U@+xUW)^l{tviP-om zMCm3@7RjUOUm9iUS;)wN@L4xB+sK;Gp#I(V?NEz)d(X=lo6Ia~K%!GiN9DtoOt#bP zp}Wm8w(qy4_Rt!5lY%PG5G*A-)LZ^rWoBWc1rKy3GpkoDPjHV8=X({-wFP!dV;z<` ze-uU+XaL5T;B{<n6$0H$|$}+hEPlbH{>ayF;LrMV?NiCGOLmz(hoYG zzULI@{#1u=zo_;(Jv=}RgkuRBe~6bNx4ZR2K(}kyLo7M!&Rb6HssCfMJLX@OO#YL{ zDa7khEIxsMqr0r1jq<>>Dmbwr=(62>0OGhCO(`Cgc2u=LN>jI~G*;;x)n=7psBp@! z$^z9;MLRf??xFUXrg@9Iaze825#mVww_RwyKO{&`&`-(_vT0v|ya9wMcEQaxm7-vk zRAPgmnjEDHMMj(XGmyCuak;W`()@O| zdS84lz%~)Zq{ns2?(#jV$W?8xe&<&4rbERvN1D{?ZxMQ6iYXYi&qp%5$2mk2-WjxQ zCoAN0m(usa?6%ya>G|4t_`eJw%<+nz;O9`(VbnJ4Ubg({SmxpX<>uJZh0}rcGEwL0 zgWn~JGriA~TbsfR>BiB%*Q+pA5YfRftPwVhKQVsu3w;WgdnudpnyPMMtA_zAgC| z<;edw;@YEAT%SG3nG1t|F1~u!02fb&k>J5BUm-d_=CE?Z{|Mgs@3$>@*s53P|EU4p z6|%0?dl_ap_BKSk5LH#A_e*x>tInL4rvg`r=I+jmAM`!B%r8}zvrxQ1@Tuma(+d!d4A*FBmNc4z%t7FQM?sm+V<|-11L-*`!6G5 zy%tu_iF2+s3`7a$MfdX?`Z?_GtJ7F0VwDMO%?p-SYriVHy3br>2{7m4SGrZf0#BKg z^!a6#twNr|K6T@{C%=p2tGM>xOg~$weeG03?qv*3C>l~;)qFTQv|o}d$1!SOnlqN! zfA5((Skj8s84n~-FG8)Ogon@U5odzx>DL1qGV4=#CE?+NG;uyX_bUQ%dY?%OH4NTo z;cZ&Eb@hS$lZa2N*oBi<+4GM&Imw%@utIIj6=5XqK;^h_ZLFr4qEjybzMK@D+43Xk ztUZ2**=SZGL>JDm<%Hdg>f}{FXzZDTnuN>fPzJwA6$aK@-!Z$^xCC7WRH~g5PCyYM zc!&krJDx+A=CB}D!K#A(4k+1Kb_&hI&%tkAjJfW1j>vE)%=ps2^Q1uGW1)PE#jZEo z2qyE$yF}O-CA-bQ*&pajC$7=9K)DwalHstT;z^)4bjZ^eBMkmCIXs4W1ZGAm+Jok3 z{HhP+8rYQP{L+h=xlCh3VXNLCAw-V8UL!{tP})Ieh@q{|+I{75Yq%uraDyTMylWA< z`Il4|WpC^zQNKTCV7_=8V{`vc~t z^!5ad@AE)c5gMN?_Xj+f@E+1s2=!aIoZHDpuKa7Y<~!KJ1?sPOY3&O~Jai^rBq=MA zm4>>G`gm%iv;Stgy>Y`(;O(Xr<0@L(uM$oEu-9EN7Q&l2(Xe!YtbD*pQkW9tG%&%`sDYnp5|(L?T6HQ%ru z5}1EZ?>p+Mm=)J!F4u@LQktMegh5i%lf?c~JRbi64m29xIjn?foR%ZDM75d8rn!E` zgF#3zM2y{{gZ9V`8;SouTFz!a$(8zJ)h@b3npmMVMGn*sPbU+tHSi&ZaEv_<7`U6N z)rqdNius$RWB!h&i+BDSOhd(WB zUqtZY>IWfzOh#pi*A&D&X3Vqvf@f_o@ymU56UmQ|D-h`_g^VLn2t6PT58NbD3JKbw z_Y|pj!O~#+!Sq(eskuz7ByUb-lxoML?+4PQ#-`)#;<0QiP5{vRc&u9r(||NS-YXWu zwBQX7w~EEEsel0f{?;G>000000000000000000Hb4nWZ~j2LdCm|aQY0pX1-ChqWz zu_%hT(uBc7J9N%QPi-96-DtU{QPdWYRi`(CDkyNovH%hn%I(Tf$~wPT9OcN3HH04G zeERk<^x#phCW=+xLo{rUXI_3;w6J+ZCbY?!VIkauiaZ& zZBFi#sT|ynm*LVap{%>2r)&}UbpzgqlHd+p86QGBCI?a>zw&aSC}*73od8jQEc}cT z<}GYC+c%xi0S!?LV<-to&P+SBW*}v%NmYr*8QU4-a;EZiQQrZ0nFIRQ2s)l6v;s7` zX=B|Fajw8Xf$H%(bx%Wz16hCY>a2T!ph}69DSP!6Br6R)Vu3z=Ko_h_xOVP;{LA0<}i&xjd%k$_e9{EJ+ujD zuflE}WJ297eRS5HdG$&Z<_S!$&=17aLcl>^17)I0F>Ui@_}vpbe}HKPFIE~%A}0*`^#g4|@+0>To|ztf`}3v$ZQMU@silv$m8m4 zi|QEU$cQ3v(B@nt{6lDYLl(jbXMz9RNONZR;r@S5W$5l>Xrvp_w9bN@i@lcamo>0* zd$1wk5=xJ_2nyNDvzoG9SHQU}6K|*<$40!fW&mh{GZ+}3e8GLR(L~=(=#{e*Fly~4 zLYZs0%~(RU-gPM1V+I6YXCD_~^g0*Pk2}>I&iAHg?vcN$rtS)XVBn&B(p@}`OR2*h@PMPE7sKWhs7%L27ZHMKf|3kt1PDsO53qev^Q zm~u;ze28LRbFObYlM}*zKuCm+C}UUG+|u?>3`ZAyIKqH&3?+A#_Zxec`eih&IsjNt zuj0^(>T$&;#V(02-@{|=%>K&I=KMJ>g=R(B7^#FKm?>8J9d@*528gjF&@kkB0p$Sp zlz$@hW_945Mro2T!Q`8MElrnp5VaItTPMEjO?Q|7_4VoYLrxOAD`hm!%GLA`P@4j@ z{C%08&e$A7=2=;&L{?r0%BS`=5I@?qa6Eo0s>t=id-$71Itkh9ld$!+uvohH z_&Pg|dY;)ULK%CHr{jN}FlD3YUtoMkHp8_|2+!=5|6!bxi(SSFMMnf&%;BNOO~BMZP~Xr&(LvE5k_|J;>`LM*xxx%~hESdX6&K*n)Jj8Sv-U{jYy zBKkrZxX4xZO*laV@!9L(69aKZXSdCyPpiej+24T?hI>IV+b+!lleyae!scRKVjIfW zY7)Ml&mbE&!VDa@6g)KhWMH_st*i~lOlO|26AAF-P-iH&8>D(wpNav!gv**6h6O2- z1m7#0r-WQoXoHVw82tLx1!MihHv|U9po*sYW@4e*(wCLbb-%RgozNf#lhk{u;1&0$ zfkFG)lWw{cFu>c};&?>ly)h2GR?s^L_S|f6L@Z@40`sNfcMqtuRj97jojlPxY$vIHN*k6Wp2E|~Qi+2p5r(SOb2ba0lA8>~4IELQ7`>7o#AaY1{V+ZF+LE(-YBV!I&x z$fI2d06rp$peW%rk{i}q90F&mf9G)3hL-zA1Kh;kj-R$%^F7JKo1?03?WHXn=V{j% z=*G4lr;>T!Heh=|>~+FVT9rP)o*WlBfeRp(i7_A?Gy#F_edX;d5-eiTh1xR9&(50L z#%D99aTLlSE{sE z(#Nm4)}G_zqnIEQf0NxERTgMnl&N>z;(h)R;?dgC|Yt7B2l8bCDB7}hO( zq@cJ}?B>8iV;T1_h3$pT_&c6@OiJ4=3D)rAk(Nk^19g(5ym_02Df$k@_&x8#&IeXa z_3|nEgK^!#S$~~P1w;zNaHOOH9qhE~t>CbIBQS!6tn#z0U~iNXuH7`Ih5O>^7%jF~ zU;E`0r&ZocIv#q3E)pKGyxrj#0=g{RAO&xRdlJossxA{kNJ6EH@6#*5GU75plQgPR8*~sVDWcT;2$qB}feVD_C zsc<&?pBs)^W!W%KXF=IO;JgyYA79V}yXa2EFn@GVk_<8yYL2jhXylo7-ci7T*Vx?T zv36j1oWzscUGJqQ2rF6!lLyowM32KhQT+WOC0%MHjI~r=)4I?xvQ?c964W0bin_QW z;><`txV4yDjqTzjS3Jfu>DpDQ{Zqq~JFeY9EB}XwxK_i~QF{DW^5@#>mGr6+ullKH zwAM-^@BJm@@)8usZ%JwX`p%@ImdX#LXb@?DJgPgn8(YQiNhQZ&OdA3%^sGpGBhjNe zkS&j~k2u+r=;)J@eH9vCbwkB+7%|T^B!iV*{wQRz93kmXqEcY56u@s2IFwzD6|cCU zB+vl>C~&0lFld}1!^2zRkJ2o$@B1+Q^8#5+&^o-XFnY-Y5$LfBvg}J;7b;+WgVYQL ze92g2>t(^Sqgvv`UR?lWLch{EOvVud*AC((t^m-Ke}B8%FR!51t79c+BJW%^Taedd222=h5imCW85eaN-$D$E0*t2IAfOEttf|t=YZB>o!ewRmr^fXbf_*A_;dj^~(3GiQ z>&e90yiItO9M*_FP46l4YDE^B=6wWDft-@u<3w2c+s3=JwrhKxKYcig_Jy~IN8Hnq zk?Sc{$CDrjpS>TN1ELs&j{|z0?{^Awrd-uX00>43S@G2Rv$`V`Z-jd8QU?J=e8soG zOjV+&c+RM2z2vy5dI{K)w2Hoyl}kLdOSbG)ze*ShQ5TPh z*sgAuYI*%Ep4J|7hXW8IsAOfAp-_>V7TIatnbrzq%tZA_UH|8g`az+HPkv&j4Hg4{f#B6j*DI|+UKK#SuOAluAOdl4?Y^{2|1%!{wpnwep!8)*U?DA*EWaigjDuOdtNL_u0 zAl*vF!a=W3#j+vbvIN0vwS^`?RmM-Wo}zE42yTev#4wt6MiLsF9b3Oda>ZnDdB)fBwL#Ba75SlfLXg94IcP zZS{(shC)5;;l!VqDz2(9Zkz z9cu$p8$)3q>JV%3hyw$E5*;Y@8rBlP+WSWKMT1p23QC64zng3;QZAYsh)X;*r5qZ# zr5e9`^M&&NnItHmIy|#AP$ra!6$lDQVC$wx(RE9`CG7r(MI~_`a#F6NRt`;tTmJOU z^F$SEf9o%g^)*gx@!m^@N;l9uxOAnLJ%ML& z&5fn!V~m=jgm2^h)HB;G(Gqeg>6a$< z15poF5A)%$Wp!-{xrD>W+Fvj<%?X)=vE-syA}*}V02sW`6Gx-q8LG4$A+-vzCoFx9 z0%xp?w8k7k0|#eVqXg*0L&2VNpT z;eC0X71j~%VD#8(ueqgkUJsHVf5BSsTfM%obX0lw**Td!omJ2IyE+Ds=o|vLrjU)G zMWZC@k3Yr&{KqYnY&i3^dx(T!E*f7^6DGkJ0yo^4&V!d#SNd`LDrj;>8%w^ujB$d! zC3A?UG47nQP1)L#v_c8FLTT15uJMOb{URR0lh*P+;DjImf{N0|lm*Avk}LP%^S0t0 zsW9GK>@`aN+XdE=*^`KBHl>mar8bdbR3oRh&~YhBH=O2migfTh_aXr^+FAw}RO+-J zdK&o9j*dcF=VMk}I`z^^;Y}PJ1Du_CkHYB1T?C@N4QT^VA?{rl5XhfFbMXta7xx+qH|y)4Z+*a^Gq=5q@vpTA~V_O%GvOG;c%=g+g}&oTz%fmM*GF`Y2M} zY>#2T53I7s$a&SjUzyur{9|-Y5rhXol)2nu2B3K2J%|AY6!+Oa=SNGUsWlHl%bc_( z#z;zyv`Dv*RuU+;D#=sni?>7GuROyyhnYBxepYn4GID>XTp8;gkqzs{)l2Y8BkI3f zbC27}g+V7o+=0#$!1)4i601EG=1O=ACmAlJ6!_- z6%bB;xycz@E2MCz z#G#0B9RQzw;2)L*Cbgr@YqtfNHKi6Ju5b)9YQ>$YgVFg*-Z$b+x!xUtZhA}1oZwM? zj?s&f%TXucGWJ>ga3fI(Jx-?LP+n;Htq^QC8U6Igf+SC^Wu!FfxhXege zRCc0CfivDYpmb9soGCxN*;9xo^h+jx?f%&2qzhel59b{0s6bRb7@4Wp&Ry+=gD{weBY z?iGmlq%7SJLtTE7vlMI*uE?iqVMxjW2w+2{GmQsmpZw#K@c%cxv#UPC zeiHgdK_zW|{!liN@Utd`${tv(#7q^vG8JIGO(A5LFYb9AH10BD>OukVLA$=d`#biOOcz%uy`%edJ+b>S250s3Gn=`n(nP6WZ;CfN5Fjr+5|53I z0FDZ}^Rd3n^9@^};>NRrIQTeO`thNW?_o!|l%O$v;fZ<^v+APnmep4)bW9hg85Qau z#x>ra?{YyLaWxnoEROUXD~;yINV4=3QJAQnMToO;fbgyVqjRrAnlf$?yEO~U#m?Nn zWr=l z$f=4vs-dj;=AHF#)x}oF^#csc-XPX_cA?t^$SekpCVUrX?n)F86)leU*Q1gJ*j3)U z@e(6@$ydm1fdE-veB*?haNeLr0=y)L)a#`sIuQt>B=212ruosD-zwwWog3?3?FyGM z_}NLhod`r+_7{13rbFly#UBNhyFWfh{`?VOX!<^}6=6((wOz&!ZGpP>?t+~bg}2PJ z0qv9p2IskFs7GSEKLCro%G5r}WDz(SyGcN_43X&~SorS>;QRQK(Wr1%s4|VOTC<-> zY+4QTav38ck6;R3`jzzxCt$Y}!^u(~%PA1kE04+D-BkctVhM+YJuEGP z@lhUs{LBc6lC^7j!!rG}Hf#5+CrH>y;9E2r`Zcor^rQjeQ8l9VW%gdcpBGW@ul1%e zw~eg`?|uKKH`m+qW72PtI-f0kzs@IxhBT%#`b)vNnby~-uTFFDN$riyg`EB(zwd!s z%&fE0Zz^4q+;tLC00t4Fb_lQ$aaf&t%(il(_9N}_TT#^+ z9r!G8VexU!3NvTo^-*EJ5*r;a zk*5>A*?(}l9BixuKZH;nL6TO97#ItGV) z#SKt|>5NhUTaGV18vPh$NFj#2)Gn4IJVM!Aw($Bbjgq;TF)j)YBV$T6fHCv9UI`4o zky+hIDa3U|EiL!IaK3Q97Zp}EuMOGY;#8#lIbL;|HWwr2Z6vtxwyA2Qh1lPDRsbSR zLMlr`Wdhg2#I^^ihH>t&(~e7y4l}#|m*-okppy&2LvHZTzS}+EQ~k{pVnEvTn_a&r z%J~}d4P?MpC1{=3sGBq8BBe8qTn0 z4nzb0;?tRojY|$p2VNlN<3kqQpTRneZ*rqsDQT^kNB#1IGeDdAd;gW?qu_Xiplx#& z3M|-1u>$p~Kmwmi(uEfaZ5R-9P(oC~lY~mk|CMGnOk#&{UA%><%`(yTDmUoEP{%fY zN{pyN*-Yy_ASp031hZkKlQN|Ymj)Z{a`#}Hc2b&f(0unB-C|IsGT|ONy*v0RAHXH( zh&u(9Zp8gqysE+cx`~{$?rmCm+GZ zeD+rfL3N|FMXgqQxj+;+wj`=Pi1Avw)XOA{lq66O+*ah3Xu}wFPoU1n$X0q#_M@Wo z%4Ur(z{_0xc^SZr-##5jfp=VC;vZq&uJ^Dr3EbbF+Sn4aCNXc0Mltyv-0<&K-R;Q) z5htGWX_ZO8TX|ux9j>M7RTt)`DGrP5*YuTZE?%UgL{}v%>YE8cQIXs(aevXI9>wO`LSk~QVxR%>TxTw>TYy7!eZ=|fU;fZ2ep;wbR_pAW+<&3OakUEZ66 z3l64SQD@WKgIkP>)hx>BS%P{9UTgSuA^K?PkSW z=5e|g2A|q1aV|#y=WJkfOV*$g;aUs#_@orC)(o=LQl)j43%N&p-1tl$$BeK4nDSp2 zzDAA0Uv@gGd5N@~`g*9pjze5jNyM6@S;Zsf#WIeLk5tyw!+X=9FSnE3@5))2mEG_D zB-C3E$n@ANN(v|YK$``g=Rr2f9RC((m)<;XHJ?`nxGf_&&1RWRq^OAeMhwQpiz#Tz z@ElX-b{vO>rt2iVi<-p$u}prEjA+}(Q&S6&a@WSiJ89caZpv+u;P>5++`4oNf7NK() zHg$77S0!0QK`=NmLOWZQ%*}VKA?_3BiZtRiAh@E&Mc!?fFR_xyV8G{L*86h4u$=ep+9lkJ7$Ak^bUeK1w zoTk#S^DC-=&ZX{ve+M{*1fWfOiN$7)g7_a~=n@_pTS3uFcOir$vYTSx#|X^|+Oe#` z@f#7`TFKWN-w@`vHLLptxp+kJsG}WU4iAII*OzHHL_Dh{>r}fb)e@t1na$@Z=a}tb z4C{Nx3+IxhVj4bqmhk$R4vZked-n09ZQGMnE=*iZxVB6yD2AefNY3aCM6%3kP4sMa zYlI3BTtSO`AHB(Jhjw~h&mbOq@XJO6CB3&HMk^lMkYh#nDeRXEIjS7r{rz5eEbjwK zZjlkg?#A_=plcEmc?<8TM~$+>QbRYRwOby+A-Gfpq1IPVYov6E?Um5fE4#!$TNC7yqjT$ zp6yY^o!1Yi4W2YZM#?`pyKxMxv4>qu4FyS0H;jzR;^G$amA?Ve`WNrJHiwFIRT379 z4f)+YKTls9tA5)Yuh!!F5_uwRL0vnL29Ggy+Vn_hKl^|{DaDgq2PF4SeM6F{aE~eR z9Ys~0EFtz(A7T16?&Z5s5V>?|`iFCy{m>#A4E*z*>)S&G3i8ESS5!z0$lEgN9UmW( zTRYxfMxlo%H5i(%_v~v&OEsUr2@Cc)MVacU+;7f#v-kR}mXUe81p_3u;3giL&o)Pk zc(nY70T@op4g$?0tXG!_W|fWpa0|Gkq+tv`7&%Ku5o5pv)-_a~BB?Iw&=2PyK_{nr zXxOpW6PbNIu%|Q8JlypdR6e9Y`&O9jEc%y}Fzdu2YWyfZojH&P%-e?T2&9)Us-N{} zDWI*|c%6LSAcE^M6Fed`*^#&6G6olew?GBWfW|crk5=l>P!b`tiO3(LCkefbAm~ZDq!PUgA;apTM7`nQ8 zmfJ_!m+PN~!#c7)G4SZkuZ2;X>5Z<{`|7~o{Qz@$e;u3L7>-*6hqEvPjsb6MgN>`I zVF3-G4SN7!YjB~}vm}*MOC8dY0`6d_zO`*|9w-`;K=^St#B!0<{uNvgPF%o}vkfgo zF@SGev?>}j5`pOJ*aqxdM`Qn88{@dsBb!|CT860lUBbylb>v*)pWq``JcJ_Z`Iwa+ zC8ko^Jj}_>Fjn4M41Q=iv?u25KV?wxWOzsn%>n2!Zc%{|D8&X#UzRtU)|d=pfAc6y zbII&|aRsUa85`{^9Mi4p9b2lX3)U?HXcxmBKQ$;()bvMz5eMV!@4*&hm5CTM9OOQb(aGpE%0>YInimSt-tAB?~p{?9YOIoulw*dJYb ziMTc}Eu0V_<;S@;=vOZpXg&rWJ-Yx#L(#lI@Q z{khlE+2-qmy%Ap3-*J2X+HFR-)vLOFR)2{|3?S4~hw$qt47AkIvvQZ!V(cgwZga z&1D4~djScEGWT1rQ4**4ZyLBY%&IONo*m1cX(jezvu_^Wm=YSxP6F!G#Jl8Z(#N8| zfkj)f2+2kcdLBFeFOvVfXK+8HMMd;WOc;JKYJ-r<(&w zod4|2a)D`+Cg!Ar`eDa2-FLvXBSF4iDH~WOo5moJuHttW68N-ORZchg9z)~1o1ddo zkBH8m*tS&rAv(-VLDu_{XD?#4bo zx>dZc!!VZ7M;A}LLi$9LFo5YVQ$!86+ZC8=HP6f_{-0lDG7U(kIScZo>~c29e`Y)M zx^J$n@0cc{s=o=O?&*=)*Yug35-a0aMxE@@jt6PoI6X#(8(ucrTNXwqnz3&4LE^R2 zN9A$qBt#z0g{}MmgGr=?(zfhaLCS3Z)H%Ir5hulzQr4~Wtu|*}DkQ{1*NfLLxeD{3 zV#N4J^Y53{YP?CQUTF1!2>3eCo-VPEHLZIbNp7G0>$OQbjxWTt$6zzshd_iHb;x1= zlBdz_)ni+nCn}+MAbOMj z&n5}jXVhfC38}DE%`&>oi6)bM}P^JXD3cQnbShuCj2L@a@KHF)y(B#KO(Bf}xOwMfJBK@TEqx{-J z%+OI&pU1fN#4J7=fq`Oxf$4SjY9URmo#24NACcAJRr))$y*bin$U@1j03kr$zf0wD zBSKb-$L>BJb-zDvtfN9Ua-SXA{Uy~+<(T4+aRJ(EOwk0$e>q^s6YBs;thT>D$FME4 zyfS-cO{nU>7ffw{UE=nq?Tx+a-;mZ**bkELgE)dHUVk?2ss=Pml3O5nHbx{X2{i zQMRU^iB8x2D_ADfRWj!~0M`k#C0T7@abUBj=``eiEHdVLw<|G|_Z;|{+$T@Kf!Sp0 zSy9K)$Z;o*r)k6F_Q!xCXg+5h+ty|qrn@CUNfk}jWa``!Cci}B9$kZU+9Uop zUSwBfawL7w36xJJ#4-A&AHS22iS}z8Y;XS`5QvA6kAACIX`&!zmmPF_1kwc9KxH_` zCyrRoF3fcY;A`b{~Hgx(JOT1Nz}U=}%$+sbY0mJ6%zDhU>M}-NrTn_jmHz%=X>3tJW5= zO^$P}zBtVopnqNP-s|}ksgMp17eF~|FkCVQ`}x)-EJ6MEShk%8iWLx%_WB1;24)wx z@^^kP$7l7WCQ`x>aog^M12-`N?Me(-P$_qPgTB%_odJV|txcfqMgwo{Wt5r_$c&gl z;I&cz(|^_cW-P|12D{81n(FYZXk64+nf9XAE#SZ75i;Pw1Gswg?W4atvX-}A*hVhs zCH98dT_I6^!`6TEHWhECAkHfZneGeaVK%hM_?5Z1aOTCHBiFTwm#(GrNq6z$1|A#` zGZ#szD5^e~xu+gR5}M$(HWL#-~Y4Nb5n))bUlx z-^ow|Fb|TC%hvYA&(CZ)dzq{L!&to0o=I)D^VQ3x1nlkaE>o4P(XPn?&pbGUZ=>BN zKlLYu12a~F4nrrJ(JpcFw1uQ$0zzof*q)ARSSeWKn?X|_-#<9ie7#V}Qz-hV;IGUctPC;83D2Dm__lC9?y z3da4l|M4qsvY_8^ZGp%cKzhGEVTmm-NJT&2nn!6oTdgafZnn;#V#d9SA!yF>JK5PPAuE*R6eN5stx zRoSXD-;2tp)xYt1rcOe1blJPgizNeJiI5^sozYj@2{r%%od1|x_b2Lw@{0k}C((o= zlRo$0(tJw9Tl-^9j&QTBkoTkDwXz=ttmqer=| z4g*PR>lmVTTM(uI6Af>d%E&VwvdvI$R-BdvWHqYNdw)oV6kZjV*`{~kM}J#g97$Fs z9=l>H3s*cvwq5?+xAE!hZjt&^l;LBre$%%Rc?#Yj1h^HAI4f5bjSp1nB^_CoN0+H? zjZp+K^FmE*6*|C{6zIaq>`smuhK(aIq>#S3BTk65>EV zX=P$HkZ%ICD<7ZhVXjRVV;NL_nApxg_yO0be?b2|5d~gJbg9ti(6GViH#l2B5Gb?L zv(T0jF+-3{1VA=j)5mG`-{if_a}oo>W3Md2%wt-hXLEf@V~ABvs4#bEaappDeCbKw zr-{@r0{sSYSqK}cmhkRN_N_86VxqYz+?U$X$n1m-SAkW=^YkS4p4V+8z1cKWsS4_M z$T$<1USb5f@#tP_ok#+sMk|4u?rV=(?J1SqfN{}?8epF5q-^NLdnj8`7!Ws)ePSmQ zcsvz|ACjEFWX|*{`|%BTfE|bR+fnTDnxos+;HT}h2r%Qmad`eyUd@O$4DS30-u0Xj zCyuOc&OAJ_qY>Drnho_Vv2pR&^RT4hW{aaQa~Csk6l0(x`cu=fSY!$Dpl`D8E-333Zp!;pVv$0;i|v6yle zGz3k`B@`9)?~C5HVVFh_kpEn|#kM>GPa&l81sz~nu(Ba#sY?=9zs-j)8*YDjv zEMLbugl}qMlSq@6)$W*1`dyE=ejhz5jVQfMokxTgD>Myq_%d!S=nG(Wb{oMWpo|kP z#>tc5+h33+SBO4ocihG|6w&@(q$<$8@x(nX#9shHUM{b0h&U&3g`m9{gVLb%wV&al!%!6Q5ZU)14^_Ep3_p{7{}bK#^w#vR>vp+ z6WyNrrs2ulrXUnhK8L0cM%Le_*~CnWL-6^a-)|VwPoP}wev2Yw!mQxVuqw+2nyj5b zy_{1&UCBvqW%nv3op@x`(m|%vrhn~-=VBGfrF<9_#Ub+jD{$R4si1>a_x$Y5$3wYr zB>F%3KpGla&X1ves>Uh*U{6nTYkIMzVabUaS_d3MqY!AP#RuUOAr4?d*r7Ug=nRk_ zkQK`mb)SE}z@X+TOnKo}@H%oqq1z*Nds06{O{FNZnEA5&eDK%MR}vPn-@mmdv;60P zc;#Vd3_K8CxnE{3&{9{mN_(c6G@0Le^Lp3wKp@-(lRD8mLyEHJ=w!SV*HoX%00^yY zlyWboku}`9`#={SO}IUxJOCCj=&2QyawSE7#Xn(4cChbM-Z(nS%T{v!2w&eVFn6LEdmi@y z6tc(l&ht#olBt9Igx&LlHUNe|_>pcu{8oTkRj74s02V|(M&4gG00Ori@1CgJ9=aUS zBWZ&gP!PWs0}}uk4V5X`2~82><3;hde`6!l@kcy{dYl|+n-s12DoWu+Tneq{T{8h3tvAC{%1$=(gKS&D?dq&5klH6m=YkvcVM1L6bxfN4_RC8W!q}P^!=P+FR7K~d&nDgC~a0;xP7oFvGB#Ulu?{sLy z7`!=eG5)1XrGA&PX|VSp7t?CTNXRgEd1i_h<30a!QkIo$Jgi&z>r_=bCMUCGX#YVf z8p2$#0OUkPuCz9Qa={Sg!-|U9M`p6v{^T*!o#Z=SPizgMW(vJKj^KW~rtI@en4`;E z-@lnKEp|O$d*OeR1ThC?Dr@^Ftg@N@q>>ts5={VG-uCEiJIL=Zs?Yg^ebVv)AhH=rP95FroG21)Qb-=q*L4t+I3aWh zL9Ph@5=!lO^0c5o3|r6oj&F0WiV%Jd?n0O2-=OlxmQCAjbO)6CC>!iYkP}~{auB1B z42|rl5yAc&vsh=Xx|CrHEUnZ$nFsv=Ox~bBZElOxyE5ekFz|cXfo5Ma{Q~eHGt5l* z6;$J=2S+=|C5P@BxrmVLD|yHQ)nU+5IR7`irDXBP>fe?7;)!x1fx7P`6bkVU)v16^ zLv5xHOz2H7`LRWqlRYUs1kLynkBRtO-qGW$a=_jf>G0LXh|QL-tCu1gZp!s+h~OS( z{VaUu+ZX5AI=!68d6*EG`*CWBi{58=qiDr2Ti-0saQ$B857r&LWpb1}2yQ;J?YT2-NFd z^wZu&0D9)-8jaV^_=O?08WAo3DMXm+R-S;$Va06{2is13!G9brEoXbJg&_sHw}eC3Jk+Sm0zPqY#uV88X?2g5x?1Q9EZi4?U|wf7#xk^nhGZcLI9z& zID={}1h&A5p4X67jcn)C1$D}Jz%|3F1EOwJrS8lHEz9aQ9OyK<;7 zE1MJueo#D60VvRRQHd|A{ffc)pW_a9Ra`#P@1G3+k9>3rY+O81nkvUsD~s1j%n9il zN^)U-Un3S18*_(g#dhQK1?!aP9iQWv zGKlCMBi#w_n5`{IpTwfjHbLXgWigPCLaB!|IE2ZPZe^oWl-+lt`N8f2gP;V$(RL64 z9ihMh5v!%)H=WWJom2G&OzB3qfnGj}pay-J0vk{_t5vidUGdh`Z^62cJpJDqJ2Tfk zJAj^HkVNLwO8CJ&TcX?jQtojqh>#BXB=1dU-M!+XFq`DcV>Q1JF!`<9W*X!=k7YE$ zw|l!Nycn>5_I+dmBJB0Cl1Vg+51gC5*a2bUP0IHhu9ebYAuY{%bj!NzwQWPs^ zn8F{(K05_@T$9!0A*;giI}b8Js2BHK`l6^lg`(ChC(=L&oDmq9(+u>-6@A&TY0h7R zr|`o_H+SPI*&27E@`Wf6qyRZx3aW6j&iC^+&wzP&0xAOQU9W~>a$W8wnxowGq`2b3 zBb-y1C%P&k;KvU;kCt0WL@1X5N7)e7U1^z`8v(vC!H6`iUpt9O^+CPKx1KW&1=~pw z03A}}FSX#CWBbDW8KkA|wbB3dlb11yu)M=1ig6G?gz;bbh&&?}8@< zqQn5!HCJtTP{*$}o>1=qhf*go&>8ximlBuk1I8HlSlm~+@h-aMP=cQ;U4=WQ<2tZZ z!k|;{pOXUHOR{lOk)bY)kVUtBCTt`^aia`f$*tFNFHb;$Z4toIfuKL*kUhu1;Pq1I zbl97*jXb`4hJHhFWN}P_$O5!!5Ee2n6L!lHh8wFOj-`gJNQ+l_kilmhfj3Vy!Le|I zYPb$df!4gvXVE_j088xQzc=G~>dEj=O2Ct|C*@Gg-p%XPxQ@%nVb&FC&49Xge#I*3 zc73>T)BYdx#gJJL@kE3;t2=vGrND81b&C7c44zlr=qR8465*=C;AlczRPu@tykQKZ ziEes}@p*X*PFMrgk|V|d!f}X8=WmMndn5ycbA%UsTL5yP*Z zW0mp3cmNA_DafA$!7wZ9(H4}lo1Dtb%nTw-LUs6u(9Ud!gMQPG`uNv|&^#R)sUDvE*{|rYF&sjvlR&Ak?e7>|sCN(II0IAQmUCa7 zplM0dk|}lN-#=3)cdpxIW2wfuRt-elT{;KWB_)ttqV2UP|C3Q0W`p%Gk&)RUQks?bsas3mTK|v& z3k-8(nTepJX%f+FpcQBm7Tb@1RBZ_K{&uN-AH_>Z`sp0{YP4E(eUe~N*{mgq_-k`v zUJqTmPJYyO#NoH3xMt{gt5FF4)UP$ShT@pS`lX|bioH3|eJ{?@8?IC0RHzkte1MCn zAwp>UyR38rjv2#5wpm28;W~lF(KQhj!99=;#a+s2xmcyi-I6-g*nH*nGA>~a1`hfIs=-7Q?k*m^Ev=YD`|+4%>i9>3rgpYs zo0}7^dN~RO^Kn}$K(Snehhz|i7&<3Pr|Ffr(@!lyvPr1DWcf7{Uwf>kvX@pY+mO@l z?B&^6xf;ZWMw*j@QD%FS9Vm|gy+_ZbG}r%(`-0xw3*x&h9KyF?dJH2SRMWgiW<~}W zG<$8PorY<7(;N~%Oh7c&|95=ea&*zO?0|!S44+ z94NLaijz8j?6u5+099j;BpOFKL(s3a>e>l-MG`-hCbjnvxR-o$6BMvG$Qi70rR%p$ z`!^`AH?GLRA7t@|IMZrZ+F%XvT1yHpGU$80wT9h(b|s&Y($_2uyiD3)F#SI!)S8 zVg055P2I3mBzHY`uXWyjo?JFfM-AY3eu-S=&9+?4PO_LwdU7`kg0E2GCxd#C)F8>6 zD2*zR`)~&25QX{_k;Lj1jOW_f-MQ?jbHO8={L`ydK*u6I2zrIX%$vz?J0)#Sq9E1~ zLKsifvV}H|AWZ+;?-Fo6!DEh2;VUkq9r(5-8fxiv2ypXSK93Ou*eD!UMA})#z@+JK zR0zZu_;UDJiY$rS;#3gw!n-xki1-z!Q|zuZc?W25kG2(WSskPG@Ei!P4-W<`dRw!P znzLuMRCIM`?STvW*+}X{^+4P9PZrmUZ@~aIfzA~?%O}kXQ^z5 z$W!C?QkS`Ax~2Bx5l%w2UoY0UrV#((6?Zx$BDP6>hEPOXBV>!m_|uX)OL2+H-ZzwD zewR{Joz=G1eWi?2eUgYijUU1X0*wq(*7!G}f_e#Mx0>?Lg0*~MQKN*a{&xe*o~M~Y zDXYy1A$-)yIpna!xAR)1b38}kIKwzLcIO}GLnZyhL{e~QoSHukokH+`lZ2lI`taxS z6so`esq){boc6RR0;+F0#2?#d)n}DxmhgJl7B!1JBs?EPq70PNn6D{BZunXtZTqcr z^Lb1++s)kRx>BLkKsM-ce2FKsl3c88hP=sx`->DXY5R$~9K1-MiJX{lx|1l zmoF3tp@b)L@wE~^^;S0}_0PkAD~0VuE!vrxNu@z~m(CbBRE+Wf^aA|7@8tC3f{AbW ze8&Y*W#;yII$u>B*NOmiUZ!2$YYYd8Cf<`3wy2Y)L9XXRZ{~~S!*~soynrzJ8DqaZ zDxB9py#(j1LE}{$xOA=B0c;PVk6Tt4qj+gZ?et{RE5mqP`2EJIiH8Ki4%#ugS@1P! zQ~$41;>Nz}4MS(gf(7+D6`T!Pn=@(Jr{2*e20sJ%FKzL`gOEoSQuwL?u}`$Kmx&27 z=lZB#a*2TkeB#}tMM#pHibCv!(9dc!qX(3klfb~jxc}4tyqL!oB=n2v!6CsX0+V|n$uxZrlEg(AHa*;6mqn6B@gGhsM zt4%xmW$Co;a(03!4xa$diPkE6DJ~ePy=f!wbZ5o zTqB4~{0aPhbo%sm^6Vj|$uZWPrp1%m(pDc}{^da*(;xkeQrvCg!Iw^J$$0P@lk+`4 zq6sYqOc#0G^Lo*LRm=*@Nj!Qu-1zlG*(U3Q6XB&dd00{U+l?f(b|p^A{y2ES^rbaC zOhXtKdUkIxn@izviZz1~3*bTi1x9cYI64E8cQ4@dC@d#Zv;8GMd}JL4@}%2Jyt;iW zcXJ7z4ln@@^wwHrFuf#dR|@?Lk{^t~H?4H5VBink$-BQJXg)fAR((nPS5VtXFZ zX>!`5v!x*{DH2wGzfU({l(?925{$CV%>qie!PRYp{QYDVHS#xtpsK@n_DgT@qZ|0l z00Iqw7^0$Q$1z5M9jb3YUb4lP5LAP6k6O*}A_gy1zpiFzYx1vGYWvHa-O&gg3UY1jzJ}j7p?P4NlHqz z*ZZ7)o^gG%aKLgJfDt0&Y|Jjj zok|1If9l-u22{4GaiI^$g-{|hHe}LGXRLcWhNHSLBqOK~u~mvAp0Bc?x`wsDY0R7~ zd)f7-5Pk8y^vrd_LE420l5-D$!ZhekoFP+Yk2I?Z^D-2hx4#>ZIUYi;k%IZ<|I z1$?){#7>q$!RlHx^8%XwH!VS}Uov@oq+O5)a?gcED(XK)T^lN>C5xpz%Ecd91!UZa z(tC`ITE9tqx(A4PB6YLRg=9NHO{xAy+jK>7@Wy;pKpgC}&`i9zSl-=@O{{K{vSDeX zpq@QP+p1;9_S&%}M)bSJRG9qC@4`&FvYEG*?)nh0*=q7AchgpB$vz5{PG2VOcygK6p_bBifd-~)nf{?gzyFQk z$*t5!&he~a#+*RZA?sTI2xZ*O70C4Z=MuPVT50)V*dVMBe4!+Cl2P-iuXzJWf#_MC zmWsy(Vr6B^P7e;31j!JcwZjtr%p~-d=81itJI=+SXh0aR1?cIM-iR_)Ic8vDU!jnS z@iC&2s`@-3+e_f~t3ctSR1?px=%h1{gbBc5C+fIl-JEJLzl6xz4LciLQ8qT}dWa@O z6NSn#Z)2X(s0BtPxdvzl(}gR2glpSDnL@VK$v zMlbGL%UuGD&YjR1$f*U3?+WT}mn7_Lw}*e0Ve8)PQ*PwtGcys!t*%p;xqb4r-7sxA zaT`YIZr0)AhtJw~kzdwdGC0!}$~e`mRz$hjtW6zM1G%DFYMPP6cws!ga)J=jS?Bx2%1FDnk3GHO zF|nZw30e2s#~by;NLv4@g-$4%&z#j&oYO8iqK+Q5@X_N-Dg~dLX#Af=Uk@kbh4T=a z38i>UzQ&_}8+yW$YMry@CMb3|m*qkjV9CS^l+|PMOz8pHB(pLkbF3|?6VJHgMJi}V zp|iNC3NmFYKZ&-P^yI|y{XN$|KRt>{gvw^(}uxk+zX&U7lf5aNb` z=i5Y=_7ir2$~f!U&DfEVk|-=a52%V!`Jbk?R>np8d>Cr_=w|S!Vim)4+8l$-IT+qL zBk3fZj+OrDDH;-UI`-KefcKj*uc6fcg^KB@mkvc!){ESO8TKzHW?4%isnM%x?$OZ4 zEzf%7#=Qk++Y9om!ecN80>gu_`RgC;eWIdzKHzK2 zP|dp1X0Tp#xMw6anoOb+z8a2nSS<@P=(W=qqe_tX)=U+pm!zrqdaHby@cH&iuwkP8 zAyLNjh8UcfQB}K*E$`@<2hl7&tPiqnR{E-t=(6-mmK446W8~Gr!VDl72~f-?SqmUj zfPaA##iD`H6RP7NK0X#1iO-=iuJ27fiP!L_R@p~Bl!Q|~v_L76&WvQKeZ_)UqFwN~ zZFu@xo3h^2WXU11%P-jnVkHp^eR6niOv8KasUqfW_t!Y@Ur zIDi2{O`yXM%H@MNlKeb2b;(a&P>AhWhtpae&5L4f_wGXPYFEGbOe0+w1gI+vra`dXSBov zTy7pWbjFGq@$oR;8>bnCvik--d*1CUH$^64QN$FZ_6Ud{haprqgXo#~u#;Ja@T8MM$kL=6gy&|hqHHSr{c29?`5K+p{# z77X8n5sOoT^o<34?DnwF*K zv#=1Z?L1BqN$8_LH1^GBXW>YNGoXBXm(hNRB8ff>@43A>2<0^{>6DaTR~$pkHELK( zb^IhQHR#N5GTP}&Hys1xWOm0?a5_ZpJ(<1Of%t(I3NN|7LHX5?;O$JCF>Y)j)?N)$EH*?W zqSJVWB;H>p7%aE>00HYTEddL1-9Y`~_pF6EH~gs7uN5QM^ng$B=Q;k<4im3yhb7T# zKuI4X5K{IL$a%QNZj6h@0 zw_I%zkLnN*K2w%zH?)zEjz^H;2%(s<``yhrsf;Tq4{YFfZ&P#@w|gJ&#IyMO!nSlN zQ`f@DbYy>4-4566`sx^#(tOp@!n;X#|^e$XG6N_`a zjSiubvf_{!%!rK8NxnAkbka(H+<*ioK{_qxt&7%dJ=y%}0Z~}yyAu@4*l{Hd*wVDf zvHsng$$AkdV)7Y8sLRl;G*z8D{jS?Jfa8>SVsP*3s^-F1B2Xs z&Er2_Q~?V{J!183FfOR2{v;5`#Nvc-%Je0Og_yb(Qb*pA-yHg|LcB-{ zpoRe&JY9V7W;^IAp1~&gSG|IShXynWT?74GA$mI7wYlBKYU4lreXv)!iRigC!BoOc z(g70)r}ff&{-~ZUPRjw=vR!3F7G4W1I>G=VQjzb^E{}_rnezGtI-_!HnjB)-ZWtHI z7k&l&#lZdnW|wNw$zU({qlycxoN&~{&AA0%wj`*}cOX?$N=fNaf4#ZirFkId40o+ zd32HKT$a@%5ulKcp+-`Ankr_G6-kH4#MS51A-{pm(am-}VnZ$1rLIRN7b#-|K&Y#Q z;=jwwT~C3_IW1Uzzt?yIpMb~ouW$li_e7kZKghh0I(S`w$&#}1ps4g<-e^*Jc<3K#Juj=sf! zpzd#BFS0s?t?6mh4_=|eF52CZ*DI+Rlmua%)iH%drI&mp&A_VX+CrbT<$9GiwKNz<+2{=uRo0E}!hi zkVDWJ&3h*h4Aj)vUC~QOPGih?cnk+CVOm82ea|+Wa+MSvG~_hT_KMz4o54eNh=b5` zt22Y_AKFgtX6Tl2?q=yj}aNt@Z(Tzy-&Z@Af#g*|7+Oz7}dF=6zz+Q^wOy!E!?4f#>)g_h?62rfSFWm?}>LDVe=yTF@Dh*SRqjwLaeB zo;mJV`a5;<*H-sL`8R)a)Rd*dt6VGVhmIfokYNpWee2Eo0~}CkNbDhRZ`qPO3F8po z`)oa2Ju}b2{+}#g*yXcY7tA11)EgKK6J#_!-2;i|6n!|M>NjDfEQf7AUl=>TshHtA z>RAQ~Ly+%D*baAHVx%6AA#|ufpaEI! zl}^m1K{ZjwqWl21XF)7-5hfjOnG+!$mopX~Qy!ywN{F6hOVkU$c%bG=t8Cl#W`x+x zF9piyEsro(LJ-~PbNeeUJ*yK!zN)Y@{+(7g;p#Ya>gUJCMLF;kZwB-QWTFM)FLlhc z{dz-6c7PrH3+u8M&G0W_PpBVN*qEO9G=57SFlxN1e0KL&W;J}~A1mCs=aD#n zSOSx@Q&CU&+A&bPNLz@xU|C|GmC<+9oe3v@!IU+~ocFdXm&BwKLAgzo`NExZ$Svt5 z+LKaM2>})@Gzy$s3u#d=4IC`z(s`p@c0lCI^)uYHwVG(>pm>>%R^XzaSlLyHEe+R| z{_RQSxOZjL*WTR$J3!zB{fRavKc@3lr)OvHFatE3n=j6+k~FWKB|5wj*Fk|ROlH5NozaCB}|Ta)|68FH~;u5)-)gj%T z%t;guKqup=6lfE9Ize2$N-vlOy#?y0Yslc9Ms`i5uXv_PtPFXpMBbA}>+8_v14u5l zSN(fsh;Zb!6d!lR6!71YFjf^w`RBpcOo6VR@}%Oj;!9MUA(rvRKCroRjpI$7Ry|?9 z$+|(>O;OhmEVJ-CPK`IYzqUkS3pIjIKu7M^R3D8nF@K{Rgrfi9Ce?hK_JJUu6d&iC z==o-^AC^YNEe?0%%?C9w)Pu1r0f|TivN;2`c+4qw8P>&~-s~7^{YsxU&g+S}4wgzAK9m33re`2i^;tUCOUX zmz(f3=75su$NZ%u(oAae$~WJWUGg@)>k!ZSvA!+m8C=HuD73GPs<365e$xy!dQ7B@K;#!osO#(N_PT(V0IlueUtkT(#jmr6xH;LBVgXf>N@bGO~3k4cS{4g%Qajt%tRqb9;bu?7yQGAl^jUi~W8wG){yN;uC zm)y;Oi`pj)Xq#R$TIRy&?{SIPk_ZFHxe9z|UQb%^Re~bx9Ot&!Ec;c=xYkwYVG4rS z(1djiie~u2wh1{)FK!9H%|dy$J2|#5NlcZ+SAN;Hm;`71hHQJ-^#z6>ru+){b4%@_ z`(-4F8HZTLkdEXBmDPwo6t1_`6#hacmbKx$a{KLU=EHuHB(NY6nx>8Ns&4{X_v60 zsFNSAK(vr<1e=_#PD1`QK)^l0x))AJNw$4=tNYLuvQNz5npV6FZu6y^Dqmcz68^|t z*=8v;4hhoE&RK5C;?%hlt5#dug4pvi&<3^NP&K2B5-BQ@uph>|5ZwsunQ?Tkmgc-N zan`$Qz<`}dmF>azQebL2qNj;C zrRcyIpd|h4(=kLw+V5uI)xo;6odNazW#G%$h1QKoONzz73Uk$(%Z<3my@PW&^X3ZR z$1E_d)?1!6c+9FJETeePWMKk$z+|t2E@rOT4HSH--%-A*>?2VwHSQ8_2=H=qt0NPp zFwGTW_FO3{5~dTrN=K+^i$#!;_=N4UAs+1u=^{c$+lbOES^P*|s|uMKrI7WLN^~0f zIt7Ry5c6Y-5`-QAtS8oAG(6zvpLT_e-_39e?x>rW#=yU${#oBB^kL4BaEe1*w+%0> zPX#D{0zU85_)G1(v~6kQnX-*{EO?_e=&a7fi5a7&{)iF1t$mcN`8sBt3*zHh(t5^e z1rB+|VqT>GZ#Pf`T(K_fk>YDzn&%bNC@zD$!c5M^wy^BsVKtQ9F$Sk#Sh$8OaqFfK z9qY}JXq77s#^cQ?p zb+MoTAnEhHv+cfm)liyFkXXYbQbt8hVQ4N~5fN%#<)1DEgxhGR!WrPs$ZS(XtGn@t z{Qp0z@GeEl7Ld?j{HDdIGB*5K(Qwq%;IZ%|TfqS4*R0yR_cgrEq9GcW;y{M%yC|?@ zFweE5HhC3zWd5#p?a^rTz>evBKY*60JJ|$li!=UBCDC%JBF+l_gSohMvvYWk367W#|pgi2RxXlhoDS`qS^kPpyLHNpL-;g=0kH3d8f?$3tI&UHj-y`z*@L zF4XSe%2ZmFLN{Q>{o=@5*1P5~t&c;Nr7Y(;Xx6{7SPguC>C8YUWq3kwMgCWU3g0jl zIdqIi=2s8`!f)&oZ&-=s9t`e9>;~{zA^8>_j9EWgr+yQ$2#?zh^^G_H7`NSu=)-ik zgodrfa&89OoWA-Z&*@39-n15drbeBmFMpPqy^4nk{wORRYV{QE@< zjOnszEQTHIUh;tbx930krs{1w`_n%3XgFX68dd>yk@VDnKH#(Aze6}^ zYd*Yl*5+uuOzJ4wO3W7BAV1bRNQ4l5sH>ZLj=OEMj%x`bpQZ@`zlN~4EPovk&#T+h zw7_rt;7qi>yG{aB?dh=u1O+fu7$iO{FMiPjv$5c4L8rWgV0>At{QD}L)qcD0-WYpK zGgyVXknEfLZp&FvdcSD7s%@}tEvnt!z34!&>m;;@iEa3-8|r@p_DT|K@w> zU*5FDD zb_%Z5GGYvk31jb|1oBzc6r8Bi1mt{33Fl@tZ0`%4j&F`Zf={^@ot!s^H%D()NS?KJ z>&~bCE-U_))an5xUg4QEosu2|Q@Yb~#qssMiZAE?1bt=j`?QgrtSuLlC(AoMrK#}A zgO^Gl5(j{$=IAi!86+e9J$u^&UlWe|Uin-=#RBiy*gu5SE$$!MO#d!&08*zlFbJI# z%~{LvP-IE%(14&+CAvcIGpG{5v2MieY_%NCM{JWX_XBK~NtB@cg)V2L2V7R)bo?CAGD~wtXn!5m)7tiFd&&CPUxtMDf4> z-WRg;AxL#Ix*~ zE@oJbKP{;0X}&@SaxRV03_e~ zO0sP;;w%aT@bz9mU$xnGF!7Rp0{e}%q!*F1@!xA}aU=XXj1^;7j(W)u#;LHTYukXg zA)C-0wC4JAT>%(h5`1t^g6Y!xtVuAAX*WtO6Yf6(*)5S%QJ;c9D8`yzBIOJLlao(40ZrgK&`(eq|yvf9N8-{O?#%k z$CiNDIta_85^z|NaGy2_(SSVqs_<8}moy7nd~RBcWkE2-LrLV#6=Rg)e1*edA8!<@ zkQZHjtbv-f{7m()FJiZRDVV|QN$)M43mxctY_fr#i@PvUQCmhbx%<)zclc1Yz7sC1 zQ%t$LqFyk0m{&NJ)}e}*!nDm)IaTjhgWC9YN#n8IW<9`dq6j%Lj_nHP9rc@CB)WPN zufK4BYPD9QVO&YVqwUk*E&=whY4m01mW1W&i%zU}eTi1W;VPwkc9XW?6w+>( zj13fpiiYgL?Mz7?iAoBBoNW;izkc2{Tldt_hVA6^h9=#`0M zL1;Y?!u&s|F%O8@6lg?itV}Y{xJ^u`p$Lyw!%qNqG*__>AA&41j3@6b8In41!fD(BzpfE9E+; zMh;53V(u0>a=25RZ{>cKL?w#!;W_*zer(GC!$-gb+FbwxI=EQas@H7RsOXZd zF~5m--Vmis9+fhM3GJ_{lNQcDm%2-1z10T=+U@5AF!P?~@icWSC7ee_l!A})ixoj; ze<}GS;*fFy*KB0QH)+`ZC1MFr_uc>PdWuGjf-NB3*r2JjR1GE(cP{C0Mi_!1u1mgGv53&=?hXS>LpBk<^k{)LC!0 zq>7Jx{-9O%)w|UIsBhF#s1`C;QC>fe(Mz>f-nIz?f8%@S>8(-y=prmzDh}p1*ufwZ z!fW(e?}w1qd*f1ycYWqT*;h_VuD$oT=^OI9KBm`s2CKCZN*$w49PvO?8Cpb7tm5fw zWA;Ok6?5lD#^0qO<9`WpzjXtX%$a~F-wykhxL&)X8lp`3-;mpu()n_+Yq23#h+z%g zJlK;F`oULt-iD507=km+q(x>}_l)AOJ^{`EJgMqPV}A3H$3_TN3yMWvB8zPCW{w*0 z+UwB00R3$M@u#2ehKwf?cXH-Xn2xhF3b@vWLy?zX;^ukGmS-t-)GYP zVqj82CV^5Lt;R``|4Y^!FMMaXYv*sVCx+(f1JZn}yx5`!j}(-JE}Z{gE(eAAN`(ve z=|1TBQhL_shrY^;ah^(S!&sy3X7@Kz!q?m94DDB$247Gy|4U7{IVcs+s4NWI6G?%ab*NFo_@c zrs|`u_3sWz*2aX@g?@A{Ze1Xv4u&lMgfb8&dT)tbsHt*fJR&&^GR5zfd)jvnz>+Ua zo`J}JZser2eY`BT!oDsPesLO_y;Z#kmEoVm>$bUklwj|Hy8@!)2&2kMxlIw>1Q*vn_#M9fB-YL6%NyaOsep>cy$vkbR`UB z?-ADiXltzH#-AE2PZ#WXgJHcwn}@&>#oo2c@j;~94PHN;&Qcla-R#zWk>ugj)!^Hd zl*EVtBW(XU>XdTpq=e z{8=n`B#qPE=S1$HyJVIHIP;9xbpCnU2={#fxzp@qUZRwS;ClnDpMTPLinQk7P4o5e zYbxf6!x?9yg)ho znBPB-Fo3Ua1WNvQk^DKy-~!Z1Fdo#WItXDP|5RU_u}h7`-#m^f5)f)3Xm`E6FLX}r zcvNN?w_uM`OYWm@?HwR_=au2ZSdpX2OPpJhu{MoR=E@DRe-7qb1A#I?T-pmIR_vP% z$G#x4B6`TN&H(T`dK|4dQA$VokCF)RQLJlH615M5x9u^Hu50e=CU)=U<7D_~nfo`w z2^yr6#mfvPdgz2*Tf^mLAdZ#=Ih*MlX3j;U=P&ScJ+f7Jk*xDxvLQmmXxR-zY1Y7N zeclImM+=?#ywGP!DHEcTJxpw)Blo{{tSJwCzC*WJ1yAvBfDz!bDpgL~+7^G}7gx&I z^nTz{cUR-nvDy5FXSU9Gtn{im?a#mYA&Gq1))!N51LBk-hqtLj#Bam>?g_m9Fja)b z206m4c1WS>9&6a5XJ@1IzZD}Nu|FDe8e}{@AP*crHu~S@fB{o3XWGhQPU?zv(Vs@M zX3$z#wn|G`%4{NVTi>zyO~rG%EHd%Pi{&!#Dm5d%D^me7&&b{s($C+X>&BF!%oAd1 zx13H$0HuMSS~~{x3B2?XNkllbPMvXGyVnaaLrbjBiCnD7%Qsx=9C1(9)rU*h-yqlJ%Ln=Rnh?@LDZm5;A;$OoB0J5l;` z-&v>+r_FGJ|7CZ12Es(05z;=!FNPJeG=HA!4%@%qz5O4d5>C7noVCKv21nodjAU!} zQX_jtBU2m|!bZnm(!>;h{b~Bj6fUE6T`pMvw=DK{;|4)``Ngajj_9cNy;QH6BWU={ zeytgvllQJ4+j1*aNjTFD&et}{ApcknA99R>5Zf0#o%bU~)2HW#iO=I`%{WWsDA5uI z4}X&a1P}-~7Z>|{@m)EBSQCCXY~pJ+`RL?*&u!3W9jKdgv^ zKIzKr_tSzP*U(UJdR(hjcWAl7=i67=p72>iuMB}2RAGb7ZnU)$@8T+&ev;Ov8x4D&f;f$;%9+(?pFfYprc zf~i4{3un`*DE#66{nILypan2E(S=%xfly110=F zjBK{oL(;>>Pjj-JcC|OhlpB0SEYx5zA(`+gjQHU@qW8aF8ezkDgG5Eur}}BD*^xAl zk#!CG6>0ZS+slhCVbzKhDCNfz55HPWX*i2_w)jj)hG%^4oPj>)`td%h|4yE|Seq6> z&@z>z=t~SJ?Ipu-Cj!Q}idAgWSlY2ybbuoL zqT7HfRYTK!ja|#`N{t^d{`m$M$8tO4H?EJ7YgLzV$84zX*-%xgq&*Ietfof~GDyH#=LRQosWDrCNOK6T)pDAY>5zqQgP^3)AEI4itrrf< zL;*-IM~)E&f|@VKQ?(*^#h1>G#P2GvG@}4+*2m9ZIa5e1@hzKz9*Dr*$ zV1cyE+c+77Y9Igtj6Ao-*?`?X*K4(|EIt3ccc~hq^@EJp^oFs#3v*3G9UPZ4yd=tgHX!u~WSCl;CoE#d8^@k?R!?7T*_7UHew_01E{n zL6iRjQO0#l7xbZaxA)s&vASEUTm1y+lQDm$!e)^7cqm^lo0)_v{~zXjB|B6^s)iMK zW4zvi46Xf;4sQBFRwkS15A{=~)4r+j?JEnvcpt8Xcg=dkWS!a~5TzLO~D;)oZXA+`F2ps7(n@Mm3O=u~4Um1LslO zmuK6ivCeg(;7uoTlFmGD3S=zvto7p4^bc-tov~+ki3FUsp({=O9wmE4cZ)@(dq(k7Wk+UGx^K*s z!p7}?bu1!pOIlvE23dpt>kCcIrcA@J^??BNZg(8(K>tb?#0OVmLvIuCsSEtjL_{7f zt3vho+ZzxOh0O1jepyhJEJCdfE)UrHh)#?YAdl@Qm4wU+E8@KA*;Zv(o>-;*Q{~xw zs}N_FGIiS-ZczeAK`*M+6LK8Rj@mupEItex?!)h;NMT_g9=7uo#pf38ZNW1vCpIP| zR))ChGB@{J1O&n(@CY)hX0R)vR7m)!#)zm&*kdrC_yWp;vm^^fpAnuUMc%*Q}@Kt1jZ1e%CKPr10&Q4j;@_kRIx1gp zT(sqOI^-82M5nZX7cmp&XPVr@$Xa<->do zv-hX}ykZfxMT4<7Oq#^7C;aIu%jkrH!bv380V3HtyA*$!d;R2ag)MDcSM2eNf6`w7 zWXVbT9wMZV{lBbcn=T$*38@l26(!5|s75^;`*5FQjiue>I2-I&c$D1lSXLIoczV$j zRP;pzW;GIbsEMzHe+Vmog*Xfoa!-*^ZE7%&m<_4Uk9^+d#G7%O`T&&zf~B-?mRST9 zXV&8uB0lqn^&Woy03_8D5LXUNuDzlC7*n|rSWxBHCao8qPro{!0(DPTPk0=YH|e># zu^Gkf>5IJ>@e_6*8>xLbAPTCqZgQ5rs4F$u@uoiIFY5(zf{gpmgwRwq2B+A@arjGT zx8b!&F-L-QAlW1Y#(g)8mXqc5ruXdEa~O1O>|Rz4z zUK?{Xf1Nk00s3(dU@xTsr4-W`t2!%)Il|sui!7n%hJMYh1}V;M)6y;CsrY0ZBVM8b zZ{br~=6JXXSe|S;vo2odiHZUJ2DxwG2Gg9V5>rhixT^!ac(K*V?^tA& zE96Z`b@P8+2LJanoW||HW-&G#d;`Ah0q@U__DDP6jVW(1?+JCzpFE0o_t0w{JI#L< z+T=baGgfG?{CciD)Qi<3+ae7Ix_@d`-{?<-wSolBc9Ig_ML@IY-g#E|^1`4ZP^*)5 z@0WC5n+7#|lK@V z^plP4G)zspnKjY8v9*lD+vV)TPi-96YRwr~NQd#R+;cr{8;--aR%Aov!R6l$OAs&yZvG?!aOIPK|jI8OiO^xs)_R&mu_zsVx*wl-!Z$PX`FA<@LxvSQ|gwjhnB>M zf9g(gnCKK-nc%WH!P~3TbzRbsYqY$#yZt+^d`pf&xT$&4ZnbW&#Wx&8C|(EgOq zykny6^J_3?b(^PjRx^hc??zh;LW48XNXdN#ZD_~|blU};>tm7P_i+*CYji1h?wds` zO=$&h*yaD`_92}bdazX~v3#l#`n8Cft{n@-=^RYS>y0T30DM!H|$KypMfQ-muQ>r5uICr6x3t$!t1nV z53f?D2s7XPQeF#z09LG`{LI$S<>wA{x#gHk>+6Xr99Vva15UI~Y`;rXkTZ6qY*JXA|2Ww+sUAe*r2i3SZLO;i{jAYZKr6@9<0>a}5VOLFFR2iZV} z6D}3YF$d`w9rqRIBqRt-WTOy&HBdz{M*`--7TL76L)wMv4~X}U3u#u%|xRtky9 zE#m0Z+%L@!xuXhbBCktTi_oA$sg%G6tHhCRkh_Zf+L{N3k9rCSwU0cuX7qXNLVg)A zAGO)B7hGN$tHUKKA7crX{{5rNc1WQ~Tc(X={n67#hb-8C(Y4Uh9RjS4O95>qc14VkqkRhxoI>>v+nP|f9Hwrsz-ut9KY*n3R$uQ7a zcy%2vEe2o7JpU2&%|+8s8-_Y@R*f;zr8cGXx(~eNx5~kc6K9foY}bl)poklca?w$P zymrN4geeU+_;Rbnhuy|jtfcO%2gV`#3R<&Rg|h`0+1%Xc73x|~+IOg|{F-CzbOZXF zoiR{RJnItCF-C>II-m)B_z;2m29?0(lF^CKV*sfv825hD0g)5&jmISdrq$ZwVIqxCS>uE4l@eMP!NoAi=R6#iginL^jT5RD? z_589Z?5le{@=GY}N(Kh;hrVop2I1+`|Nk#grNTy6xmlpT0Y*<=G!75r1KXRt^2si` zeQwWJ*uVn~UE&Iv+_r__C@me7iwVAe+MD}dgV~%7R@L4Fm09m3VUKa|zw2p*fa zd)N$1se^8s|Fi@Z1LKr`@vPd;8Ota*Vqb zP$f!{dA&(9BXps_DvoF^)hk*8QEq@WvO^jwd=KsTfFy^OhIwrP9v+}J=#dEmt z>ux&&#Tl5OWYSSXKEwYFl7A#&v0r_vYAlhOA7~soQr*-MDqs7(_^Po#hM}`3jeMoY zRlt2}I+#)oG?LfFZq)wFFl~K2vZKy$*Pr{}w27nU6R}Sb_+O% z!du%cb*zea&RBOKf1Vc<)n9G3#hQYSD-VgCW~E^=xW5CLsu`dsT+->%;R&+;E6z~N zD_u#V9g_yASTdP(^)JXBLL!+2RBwsC!lC=kA^YR9hRyZu%Og)i@L*tt>o#t{)SW+b zDG>r#+)(2*^+clxbI0QQ>o{n+=0vGd{#E^cz*;n&iC;P;r9duZ18cKw)IWs1_h$QO zq?F_^KQQ8_s(}lK;DBHbao6i_u67}Y_h>?T+4|65f+WprzXND_PT$;KHBHI8-ZrLp zpEXt3s9pN!J+&o(op;x57SYEzhE`8phGHQYZulWoJocVj+tE7$3@~WAHhL!CFDK=U(uyn#x zoJA=xsl*RtJozu{%AnNMp)g*B`l<~l$viFA{6)XGoCM>PL=AVtPAxe`fND!Qq9qRz zKwns!4Dptt-{+b<=vJ>)3uvUKBasiEkmuc*$dkvM%h5o2fVyuDOa5WzBTxcusbmg` zd)jZ_U0=bNS@#NftNgS5XUU=?Up@0(+MOS!<)o~hses7cgO zuXdS)Y}y@h2K>2V!$@A&5}c<|2x4@pEE=Pt(3PO;p$%Dp6U^4f3xXB7;!2?(j)u`% zMlc4tyvQ?YgYMhHDly2O+e(OJW9ckcNFYlWgu>BJ%Jq2(Ofl!zX z{j37jK=hBSlqyH!hjp;>*V^a^^MNEvc$=SE1;6BxhJ=tRB zD1q2o=Fp}k)R`q?j6?IHs>nJqSn_E8 z__FDlp8Rj23C|+8z6g|lR#O~=F*fP4KaTD9N%r+j0~EqHB7)r05e`*`Q~+Ne-I7Ai zrk&Y0B8+Ie|2Qf8t>{xHTR`WkxcsT7t$?D3l-IWoG~iM$-JJjcZOoLKzyl4!8puLK zCHMkTtOR!bxptAg&{|ho2yj>kX%BS`4M<+Vh$Zmq2S#%@$*w(UPK)TGt#e%4Fbq+Y z7&^aXz}Y_O9~J297uuBW7UIVy_92n z7q%clmjFuRB$!l=G@6LrHp`(aKcef_b0wNQ>52d__-a$7hK0}s9Ug(F$GI;sksRnln>-Ffa1;9(W zjl%3&3E;dA4N0lXr&P-R%CJW}Q+y%ZBg&)Qu)`iAw2+8NxDg#$R%5Z%ar7%(GkwVJ zYLp_)BGo0fW5FxdXGx&mMPiRF6@Z6 zJjPRuf|)A~kuCw4a4KcNp%*W28AqTvB4%ofs(ZC$GP7LXEN}I6RVN~k5+rwW zh@FprT;Cj4~lU%UN7wTdMXX;7szgnQFMT-+0puvcl35gI1WR<%*<%*bfwO-KG68%*RCYZXYM0s z$0?UZvMJ*P#=$!d#fqj7zE^8OZBW7Ump9jsT*4G|>y#b=L&=R1J z!=F|g?$D^g$=V_bd{;dL?!&4UP$zK+aobLYYEDRqK*M!ZZm7bz)etzEkY-# zib zCzFfJULS{wTxp$3@l^X876U~I&sJG;8vA?x-MB=EoasTPmdU~THmish$bb?eb&OP> zfRL@vnqJi9(iJ1r7uW9_dKnG^La3W9%@(vl96yrptzR3b>@Z~?t z{`G$zXy~_20GdY@DyHWU>#hucou`zGulUryszm>X__EW2OA}6NF8_3oJSCGNe)y}p z8;Fi>Zfu)Sgvj$kMD34tbP>(?5Zb!ya-Dnt__dCjj{P-O>@SgN80pHb-c0+d^Up{m zaB#H_h)!~TO@Ct60wlR-LlKoT1WPG*O;8IwAQc?YTDgXQVlu)oszmnV(cjw-j)l<9 zhU74OVrqbkEbd6~;G=~V?pYdWrKo}BnuN<(D3h@ixZqK$KmyVJ&=laKfOSBTz{zb2 zdCHe!%m1i2rj@^u`8!;d;tj9z#xWW?C*xI<> z7NIGSs2T8y1@<6wKtXz9ea|=)_$kisggud>hB^z}c1k}g!0fD0F1~lMELqCaZ#_xU zSAAnU3^v=E7sv=tcIEA>-JkUV>gNkLI&cP8J3=b08c{yg$ktAdfsGlyIvavr2>9fy zheWPvCLmt{{V}@5j5ZjP6UqkE|J-BZXo#Dx#xVbJaptb((W6c z-Du!)t5HtpsggR+_oxP&_YXm&F(t(A*4Hq|udoCgc)>~O_G=9^Gi0M5^qv6Mg8sfW zV0I<400oWnYjA60h3m4Ma6moCB)gX_oV1ut--{Fyi{`QujRW}izGWtP%}OQ#N94}9 z9dB}1JcS$f48#OIGqJ1Ue_mXFWym)Qoa~x-oYR!=;t7uM>E_&5q@$O7P*p9I-_wb2NOKvB|~b=^;SDDnAUc=T^s&ZfV z-et4}4sTB%IB(Ex%sY2aQ%Z9mijH zRSt?=hlbX0=GE0o%FfLHeaU>080}=zMdPM*Q7d|-A5Sw1J7J|VW_%{mnjBto zlj>XU>C>2HB-=N5y#7EmRS+xkH=DVD%U~a=WU5&JX+AxrJCnA_#-Cee-L{Tw@S6bU zjGFpqUbE=T=)Efu)S>)1mdpcV<|28qy_32_h(9Z4u9Cr4elHs*-5<8|)05yz-`bTOr%kqImuyPjROQ~bmt1V1%&1_i8 zJU)s}Kf}2(xe0}FYKN&Y-t$a>`wEWV5PBtEq8y{(^Zn=H!GL>vhNEbhM98V6K0Vb6 z$RCPbAw5bV3eV7s=4@W9-5_e7xb%>Xy2DXbNcE=wz^nXzAWM_XM?cBOQAN)kbHnjZ zNi2l4Puj2(H^9M1lfAv*D1MVC6uN5jt2a~QTk$QGP;P?aikh~4e7|uE(py1+^Td3& zQZ{GeAVZwhs{5K5IFr2Rm^k*5zL->zE6yQCdQkabi z`qj!*VPN3)(J;7f09<`<glJ%x>J>U)vq_l5K$XU;a9_ou;s*@dEQHq zUoxLSVSy8}9rI|e34($DATN`~4h+*td^$NY7JqtscRlC#l*~enicW}Q(vYNjv4l*> zIv>e&X%Z?b7AH3m`x@6p1{CU<16B;IM2|MRx|mp_?fZp;?1n$O^$+6eSt$>OY4l1b z>j_cLBk#Fw$G2AFO$DAG^wZ;K#x+Oy5`*RQo~V?%cK0;wz~0buR95RJGjRQQf5+N;fo$a(n3s31wR?&Ck+HWVhK{L?qkf_Q^FvH)N~ z#-Ad|c9||LmBTRd;m0FA{zclZ_Md&PsT`-BT6aRM){4eKr3QB?xp>M%P6h@dHc*Dz zu;VaBqGrB#CX@6P@X_uqscn!#&MBs25WH7uJ6nfjGo1HZUp-)PviH%B%2C8K`liAj zk>zMLy`uNy*Pd91Qpvsi@#p9iGIc%wfe873}PHq1bPHpvT~yAg_b z_2{yNp0Sy5?gPZPQj2@!Fq=Y^?*WD)5w!^-wY|SS%fZr zban{bG;y_Zi_n|?j(>KP#m2x0@>bX_UHPwzMHNjOUMuQ)tBxiksh~-lZhY^ z#F z81}`88GQqgR{hY$Bkv#IEh!hA6tuThD6#_khM~u&B*|*pg+-eOBaWG9UT!>rh)r*6Pa4zL{qJ+Or}lff+o?EbYIBiF!A%&k{ZlfF8+Xjw0m zqq^hgkh@EdP}Weqb@x}te4*6bhIr9t5P?7&s+sbbc^{Ga7P_ALHJXz6X#5vF0no#^ zo)$mhWa^r|L-nrk6<$|FVqd0$t}25A%r=OupuLzo2>|(!wIL&0!Tqz3lBx$FaUC%) zgy`yf&?4GVFr2B;)ZsX)qWJL3gpV|E6kZNKpdK|7dA5Vm;O7J==UjR3-`@ zZ?CIok<{%Wy~ufF28x56$Cv{MWam_%qu1?yswcqeDRFXwAEUnw4y#%{LN=DRFG_BHWW*6)8 zi^A!F1iIAuVQI%&+Tl*Oy)hq=^%-AaUVKCKFYG0P_!w2DfD50`bcl&|->*=9 z7F4q>BhS5B_*}e$4)3}B=X%Xm%X%(tYFnBB)ohen&^;Vu!t@+*Lcz%~EHHV5rZ(rx zfpGX%Q3(6Wh<<;=I(}s%FAfFd?7OyEfQB%VB)luprH6ep!*$;U7FFE0Iv*b1c2EgV zLkzOWY@R7_K4xA8i8x2iy*H7w7qGWinwPQwVO46Bh>M)y$AWvl z1}urOilpEUwVI=58}C_u=HKEpsgR1A_J2|lyca|1zUsMVwg$$40!C-&Wm^VF)bcdN zsqYCU9`5|Tv$EUKlt}#0t1>Nzb$cSEIc~*l zzj+q&(sElq%3F~nmceW@a1g27Hum8Ygz+N{;1{dqL&7{Q9dQPqh-M9<@?)6LO(6G& zMtoaM6S(SV+*y7yCk2T13=jq>8(nfFskK34iSwFP$nIRu zAfFUDz&O^Bsj(w!1}GV5SubmO(NgnJo+AU>m%#elkG9XO#8bp^Pil<-0P~)2e3dz% z|KWg2Y$Z|bj?j2dpb}SZsW@OtRLmR^PNyjM_zEKihkWTWGX4}? z9vc~HtR0W{SqrOPzkpz$I_~a4m<)eKvX^J{Im8#FfH#fn)QLc35wsbuF{=~?T~cu4 z>$^Hk78z1HSa!hCj*`_v>)eB&on{(p32XVvEz#SfM@8gFA8R2|9%?w`$avXVrq7vW zn;w!bpryP9SH%pFho+{khpRwy(Ng@g>&Az_DYNFfe>-r&-{~>HAEjO)(tJBJA_sOK z$@h~wwvUMLWJ44&tgaIY20DNg7Gm&V8{!$-iGL&Y zaFl<0`4EWK$@Dxc;0Q`qF_Tx-l$DFN;l51rnK+n-pe_2z$~0bwebtop zGL|G`DUMDcW#7Jn?03q1G+>byRd<(PjShjWaJv2O3-%L**ADEsmPqRnZXQ4A@l>hfD_5`-x{L&m0mrE6k{S@2%zi0(D-~iG@PWi#B0K~XOaORqAgSGQNu z_DUl$Rge1lp}au*XfHQ7Oqcy9_ZJp8obSDTLp`6W5w-iNXrtyq*WLxq47OBReTptG zDwjvke^}5E`adRl8E^B!RJso7IuMCm0TB0xFnS@5)_BZ$zg3prdxnCa+R5(>)-wMf zy`@L1hX-flJriR&_5Hk3UPkFj>4Q6Y09l3yU# zqN3taOe}zklP@|Vk*Ik;d+%2Hy}@KpR#xYo?a~RuqZhE-W|lHd1gDsEJACwUcPTNy z5X^!1dzE7oo9t50~L1EO=yf?Hnr*2W_fkL0Om=m%h%)x^^Q<*WMpisFOzupAci^aes@XN?WsNxd@cw-wqu|k#5kpPhkX!$C z2e=boLw!ZhBAK!_f4_v?Mew+2XCwTS#%^RkXM}Q1*ZO0e(H1ZH^NezOc*$DupCWdM zfFDvBO&f4a-$6><(>|K{{QL5g8h<0y&ps9!Jd?K(ZGRI=2d&xZwfC}Nk{h9;{-y0j zjPOfq$e+ThgWZHE&)@G^juX%}HYlL>*+H?gyZlMAR%khA!iUJl`T@?lX1IzQUNtl} zN@^vxd>b@Mu&E{01l+bR#^qteVNLTC@~`pG($dE$_VpwksB`469~`-7+Y#G)%Mk%( zd}O*SPlLq>Kqs`3+x+W=@aSl=hWT>e=2+EIb6cC~K6Z~anc?u1gkx}nf%XRHfEc_` z%iTEDPoWDPAg*q3?RaduZ$gREYP&+RXT9Ace497iEQbwrt;>SftngXndC$6uWrD&c zCo5`iWmh6e%ia9pApnALpO)0-zo5xwLdYb- za>b~-cYs5M$RXX|ZeI27E7h!N(myes9j`9ffArC%7|6k2s05<`5xMD{uw_2KxDvjg(6ylZ5q zN57cZXoez$HO7Wy&vxTR5=jT!K)>pG-B95lj4_d1NW$a?{L<&w?z1pk;P+F7;k&Pj z(&o9YW3(!Dc9Nd`K;opFuZOj2ud;JmKh$4Gmw{J8#ZF%g6VMY^4~nm?AMeQQiDV$? zWoN^sy}9Doe+y;T$z10_TQww=nf;wfl*VF{d>Jg@O|@0a;EZ-+706B|UGy5*e{ddQ z&i*M%$WYW&E2!;?GUg=9=3TRW6D^hNr)*!ik6jmgR0sULBx!Kd&Aj$xoYpRuTNLq2 zlhVKP!_9VWzLTB7ALY{xMxdnREgq*pw%YYXIWgr$Y3K)*oBkg`S>yX;Xi9pVlZFnH1@lEo7^+=S{MKYa8#Y zJq(_B9BjG0E~nYsZ~zBt8;aIEr4AejkE%s_(xDtEvS6^&f@@c8;JS9}UU%fS^_#nl zpMKU5cHroeS=yV(0@&<;d%(aPrxbnS>Hc--U7JOnWa!=++G3<$rFI zq^QeohoJ_AW?AFP$6G$=+X?t(sz`zUXHYQ=*L@h{RVQF(QMG{>zlI%+@8XCa>?~Va zOlz~nMHq;SpC77AkDogUa2QkcoP(^a2^!GDUJLOo&9D9*Y>8OkXKl%qxc|^;p+pka z#rIA7=V|8K>-EEt(mA2D&ro5mleqdgR!plb=05hmPMEY;vgqCW?-hN>VvQ^N4MM}z z!fV$-25MkKATNswPM;S(3OAF8nZ+_CXOzLg&Wcn%5E+-xTd()zq zc&wH20*kK97{TO4`LXYT-6K}?i;E~MqfVt}g7jR}3P>xzp1b<>6bC!5(0I0eOW7S? zCT2EtMEi+VC@VMKE+H1KvAO(U>32xCf6#DJ`i{Br*xDL~Obl(!46dtQBoO_rG}AB) z@@)gnxPy+BeKSlyJ_KpP`93LK;bBgqgnEco z|KQv#Ct5i)k^?w0xQpHn4W;HCM*I$*6Sq_{Qy_>vY;Q3L1UM+f$Me7cE6*$55JzZH zC_h**FLvqX_3#~4dyn+zSr2ryIJtRoJ}y{^F0+>82HJ3;qM_`;>w_q@B>>Q?k~RiL zT5OhUzcL6o?g8P~5Drp|Ka2&@E+YS9k4N7IBTZ$wKVPUL??HFOYnn&g^MVnT7V}yn z^l*%9JfkcTZq$u3>jkE(9!S|rk%&9lh9~K(E5oVcG^?+r1jWz0V_s8{NSt0ie{nft zbEi@hep5n9A5Bk9y@no!A2#D+uM+~mc!WFMc3h1-;i@E$usLm^1O&_mn8GB^qz?@n zNt^vzu?&%-7Z_G%tt{!_V&am8>?3{*$_d=?N<+GoXk>-Q0huIwtUfEn=C(znK&fkQ zYe419Pwu_3E)i#5(W5@L3hhPN#6%`zGuDB2-sQsFUaJ@8o`g zc!dez1?lGY&1(?+3K37oz~5KSLH{Ocs!RYmu(OsAyg2@FgLyr+mVf3@Y)4_cR9Bck zMEUuhr3$B867m*J0qr2PI;iM*9U{ym@Jp0X*nXG4AL<>}vv}^m^b#>8lB!clk!7?0 z1_dI**cxBT4^NV=gd4EK%^}+VJZp>BA`5xnQuxYePj66;fq+RxYcdoY?vWMQ@8#U-J45O zmI0g`K_h?o9pXzc+U*aVpwf$Z3*B1qCfx?)SrL}sBxr&fv;Byvv)%&4Xt*!>BYKct z{|YXgz&Asyjo5Gi3d~i6Xe-_DCCh%-Kdmc~FYq~lYJk?WVJdCF&o}9qG{et(c9DtD zq~nP_wxR>#DT^J>Jia8$aEvxstkx=+D!*!wA^$_fWqJA!bs)tX2+oGHZM66#*7v}X zEL)Jw$sbCF^yK&5ryK6}2N~j!T4j{;A%u#*{2`!df@>>btCG~&to$72z4g&P^v}yM{QvkrpIs=`tN67Tv{mX z;fzBB>o}MCG8d)m#~BkC2-cgRhu1*t&j+`rSn)g56$aYL`vl(ZB3A5DI*x9*>3@C9 zc^p&B2|;cEg=1R=znZCSdLpEOo<1+&`HRAdPJg(w@18U<8g1gK-N_9S-xkQ;SmPgR z(T!Iv{zbgLRxs6jiXkztaNVHsH2I6on42Hj9LO?)%KsJJqV*EY^X2l zNW0ep1;_-!D{$X;R0W$`bZLIerlOI4w(PqRry{puTAcs%?{zf zpG@lwyNdI)^hlDPu}u5SutEIPoVjJpC*I*g*#qzbQ{9X^@Rvrfh5vHt%%MACJb?AH z?fC#EouJIqpCHEm1v2jj(-Eh}Ouk~{=!5-3R0X(-2=y6kFOLb7o&k=u(%v5c|x zX@32yB+XTljZFz^7h(nAqJ;@*HcsH{Q?eB{2qVpj+y}@`6m_~WiYy;CkFVq71Yf@6 z#l@R)DXG~v(GqV8^UH$tqUYM#TIbQO-!%Fu!i+2*gtPrY9eV?|bc8jJTP#PM{KT06 zFWFc@Y?vsC#{T8l-MkE0icBA%2awR|T?DT~>-ogpk5lJ?!mdYWc;xV4C4hnq#J_bG zptrE-8$ktQwUPwC3YyLy5qn=~aqNnl?8kohCh=*zQ8PZ>vFW;pMBI%&e?=A+MRSG-k!^;e6B|B}*!76hbn$#A}c9~-49 zc$tcS1k&}C>qFEQk}OP2iMCu#GMOSS`7K7-xgyc&{3xf)B+@yuuQSj*kq}NVv(Rbr zOa_VZ79(~8`_oq#kK-KZ{b1EMk(Hf;dL@b$gKOKiZQHhO+qP{_&0S4xTT|P%?R#F~ zuBXVilKkPibFLq;TK)k_!!TPHny>Pt1==OFT0k#|@>+0K0A6*0)a3x6*0lxf5E<7+<1saKU`qnq>5OuE%a?3a42h*UYn_GK1%uq$$0F_@;d=(1iD85ev}&VDv_VGz+g z%fP1Y+xpg)2u=dxjcT08!fV9|2F(`aDYM}~suBHKGKKfYROr^HJ|erZ(mhBP~j%9q%}!k@@1t2E;^aALlkw|AN< zt{Hl~x$9^4(s zR+I`%{;u^1i_bTr)`-Qpd*(lWz|+7xtf&PI{>7DIdT=?APF%?MNm)gW^e$q#VXPb8 z;m|SXXS-*E(2y&gvMkfPjV^ zy4{I{^0IhJn%RUoA%0$@yFZhOTfHbIQ$vPq7YKGWcdGd`D$76|fs|Vk>fGTYRF?>F z?{!Mn6@E<5Q{L26k!r@f6bOEodqAn3QRs#(6WArAf<}vp!#pmBZ(xu7Z41H>(CmFa> za=&Tao<^DVNO5Np*=@9c;7G;}0lv83igve?^K402#;)I>i|@e2W9 z3U}f8ZI^c|7bW?I?dfCWy>rJ|_Pf;6M+52!<$?Pz)MqAF7Ui7=9ZY;vB1TRA$NB-( zW%Ot{>rq2GNj9s@aG2Co%G@5NplzIDhU~pSI>ub4;rr>eyo=GJr}?bwpMH-r7%c1dCmwcuBXuDxgUqFXK8~Sy6|#PNl)d+d3re3u2Ztt?VDv_P+#8L zVOxT|T(9{Ys0Jg7Wo1mi=okAO>5c7ujpTB-8+zX_L6GCUQEwX0H7+IU1>;}P~G)mPT^^nHvAZ2#A?p-0b*`5r_ZLDftDmh^JrlgH(K=Nl;AK>b+G?U}#?oo4P;F6_3|YrKko@);_qSUnRPlrS z?e|#V;e|K|M4pIz+|~*jx1)SGXH)oYGdR();R_#OckXb-Z>Fdz(6!=54T%yCi7E<8zw?~=D zc8N}EjsiVut?23kYx7K!KHymqKyPlWEQ}jeU9ZJC>9h53wApS1);JQJCoZa=+fW8S z+*+_q?&XzvKcp9K1pVMI#g)xev(Vv+W<7;Qqn1&0 z7uLc>A*((d<}p2c|Aom0%4Bg@dg-|X-bvrW3*l^c@8Q#rX%=TtW%AJF;Q?uTI-XtJ zEtiuHtc$Z}ts~}gBtC?lykt};L%)y)CfjD=k zOIKklc3-(GILVZ;>c{`9T+TvHWeLRA=}WCVhd)==?c_lghasEONm$WEeCMA3+;rM) z5>HMu&KQFC{B~!H-KAQS#L>KPiy21i}4=5T_8@>}q^ zd%llx{Q3V{nPGM{xYzdsDA7;FZYgIuh=WQ_BBIe(8eG} zl~7P2<%K!Q3;{+YM7VF&x*pnvv|^M-85x^lw7+_D@2tB&KTC}1Bk&=HOLzwjtOSvR zlDV%7bMg;*fD0IuzKsKfKE@<=Bm~h|PZsEEmMy00arkjcIIXT_SeUEBE~LhIj8~7FQ?P(GlUP z{;3(Bd)kmRkT{hp{daW7iQ5FM0wZIUR))EV9S0JT3fuRgIZI|G5cVU*CpK;T-!dsk}7_|qskGkl!$JRFs1WpaL!TK^!m zgl{04j5r*)&D0QT_-;!}L!*VtB;A`~8cunu?#i00eW+sxK9Qg~Ax>jkqBi7);B2{Tn26KZV@ND?Q{v&p`yozV5gtMaD6Vs3sr>;_k)y(uH?$Nn&N|x2 zuFeQaTr%&@F%o=V+oa3`1WIl@7w3r}&HW^q;W$^PXxs?J%J z;D(FCKXrN$}!=L${P99xD>yk{zm6(Mvd{u@>>PFJz| z+WMiOlSYF0c+cCx?rm4KV(J%8YoFm`N)i168QfOc5JV&0m8G0Nt`ic{YS7iqNdQ2c zD*y=GyvY{laMQe`!iH5^*{yI6J&OjopxN~LapP7YXkF@W8Ho{hUB%~c(*Gi5+$lPSd-#epc1Um(?>|7+;K^1@iyvzS2(-flVR6Lnkf@7&ZMBt2_W za?OMTz9&e9EG%YK(F7Tn1zD#BTb6X`~Vu%61Ut$o>U%KvV~ zH&v|HMVg}TcC}y&{+i#sJn4djF_L_XV^%qrGX-d>HqeRnqhLjAWg9_lLNrmgW zvm(aj&OzBtAy33w+`y<%H-_BJg^|SZV7^B{_3hW>O`co#$CvOwpVz7t$&4e5!wdM)YNOBe|-$tF=l;DjVn7!0eWAr}0x%J@9*0JJTPX$ZPvDyaaBMVSN zUtGj0tcE9ISy&loSy?k{+LT_+uiXk;-vm}08j)EFl(SYQ&fqeA_JZ1FA~T`L8=mPy zdc;=+{lW=2n^z8t211RsVFd$v&2Dwc!1Cp^!{pS&LV3(7Djua`w49aKJTe47-XUlP6NQZepj95x?eR&3tH9lQEr!{crn3556^`Fmi z;Y4kM9v;dfVh`s-z$Gt;cC=r-9Bq**2yP-<32B5OKIOq`0&?pYRq%gbrfO(arT$%U z{ioJp7B~Ohd5pUxLVk@L6xhjkXm#6m5IFKrxRDevV{^MJTdXdWCN`4RRoH>LI`_2R zX*&)AnUbr6mY8{(pKDTYr6oBg=Z=mG&NF+_x1V6JFRj0Pzb|}mTo+1^pm$r*a zX>79af)66f)F5%l7!8B9A8E!07&g*Ot2#mV8S((g3C2b%xJEMw9ZK&`X`>U|?EdY` zB8d9R&o+j>>|a9h)ylQdXTx}Xs~`^KYp)YX1In3=>%vmd<1Mk zgeVmJ%gO2cj8u*J*J5Wq%Q6l1fL)G#s6Tw*lhp_2+Xc zZkG(qRWAhyf$2VRXk6Hhlu(5LOWs5Q-?HFlnpJ|;qWjMrVzqRk7PE6Iv9{7med6xN z48rCCe}2W?TjmX_t-BaOS8jIy}uK3Y>rpNKt?sPp5?0=>8Koj*K4E&`Z zC)?`-WysDoT5#@X7E5u>9n4!8+NTxFT_{+Tb-R2#WTWq5GqBq=&v`$sO1jyb3*f6I zxMZ_XeFClpnl!d#*-Fk4&Sp-DYjw_Ugax2N7Iy-D$l&tZOeGrR)^&Z!?N+H7u}NvD z1J8f1G)pULBiJn(9R9+YRj#;Eq&g2Lcok9@CLY>A&l-x;v|DaPex)0^C{Pi`7~KCn&rt|uQZP>^nl8yG*x*e2rO8 zwH2oElP?S#cn)Pn1TKWNxrqn6p4|TY=Mxp&hBX0@+c|yM`!8iGRAkSPU)QGKy)W4| zKBPT{l_?*MU3_*a1r)ivp4+Iw3_}(zBNV$AFjX9H`#G}PiF*&F2&7KLIaNki)j)Su zPRj3`;EGFP3v6+bB}*S7$<0|5IRGStwd|p)(U zHvmD`GU2sUQ%K|>s8H0hAdED~#HRrXe^{iIgIL1ceH5SGs2zCZs8!EZtTdl1yLucsVPLF<`}(Jyv`1=qWyJ9?R0~!^f^#pv%BqKD>N%rrT0(Gc15m zQ-HSM9;zx3n7_IUOTU3;nZp5MC;Lv|HiVosV~;4qC2h#CW#vV~O!XOO;~N=+ej7w- zfq5Jthb~QDr)^J_p>SbztQ0U`+THaa4NcCsqS{sDL~#6AqCyIl)p`4AzaS%@qD5Sw zsH-O)Q~L+W?^GI~b0{cj8jH!GuvA5gDp(&_MYLg{S#}{zYRjo?$uye#i>%VgiqWyu zEI0b`y`5J;H|NTa7CMZ7%df%fP_O&~N92<&Ddt;b-3|*!5i!&ZP?}Ecd?eex2S%UP z^zBpZL~M^)M@YW1)*lNDD8YObuuKe$@i34s`SY1pK-^*1l%IxX1ZlMg4&U+pS3m>% zt;xbhoc3|U_4T9#>PgHCpUky%`dSC`R_7J@r4nPVrFykhH@wY3(=m}Y2{$Un*#ifi zS`&Jx!e-37YTc!Yw5*HiLs}H=on4^a_<6vLP+(cDm$to+!M=i0Jr&9u?K!A_G97AY zUe<_r8lqutE?Z{-{d zXo*MAx+B`Zl&S|3?Z=He`zrdhk%8KRwDaDKZyX?Eufre+WdOZ>RH4vIl3zlp_@?{s zTJAID$eVymLS8FrH;bt9*!zeqq$lsiN?P^zV|e9+hJA=-Le6D2S6YjZT&X&uUf7(> z6-B{UK2D`sC|Bysz~nC4lcxcNA=rynx7M^vx)qNXc+PWRjoJFB-cJRA;bCRZ;CO@z zcyJLh4*^+1l-qu5e%I_e^H&IXS4G z?0KHsPq}!A=TcI9W=#v1&qHqK5GwARsO*55V2z`S42K2!2aUzfv8QtwMJ8UJtQY-S z<(CqwN8J7qzbtxKvRmbq^2Ne%bQ)hMZfRL)CcpPkkO*a$eur-q@E;bmEynGXBqF8S z!5=`JhkbPwm_Y~A;X`VEmr;_5gofTY`eQbFCxeKb@^{?@zC0|GW{Q%y;-oi-RDw>c z6oOBh3FOBLtgyrgAkfMO+0><67F9T&D^X{_LP>6st!Z5)|a zDvS7j14O|ydrij-!K*iO%<5p5oi*YG#Eld1?`YL5MNaf^%}?fbt(-2Pn2FO^B1*Qg zCzU;m%W5*Rzw`@|&pBAp-Nlmn+bLw76~2vJ$clxATR+|vU!;avE~E&NpMVBMDa)X? z>5ZA45jb~Ih(!tGxAvi>CBhg&OHo83Vdn9lRpF8;487>bNG@&U&|HOOOVKVZZ&h|fg#a5 z7H)UW%N96spKluOEf-8tOKRsm4|A#TC^EO#3>R}4ByN%3aF9)w)A1@4yhPe>|m@ZaV~$$nCXM?;x^S8VWbO=lp@H6_MJkcHRDy=(39JUURtpbB>lN6MQ^MeM zfEtlqZykCX=u~o^Vte=XLMOzaVhmY_qXt(Bj~w2}12Ci44R9|`@>&YJcPz&Q5RD$! zrhOnV8viPgUe*{Rzcc8fa9ghmS1ZIeQxYc*vM+`x2jP=8e9srArVuz72e8^`gzSIZ z>4~9y((V*x*p6MD>OS9J+v_y-{yKd|A3btkIhVs!vL3MrgFpGGor=FOE;7oaTapy!xvnP)_&n6;GqWtwoTV|Kc zy2H0)bI25A#U3{q)2R&zfOV7JosjuV!j6L?%+3nkn z?P#>cH|6t6#|A6uRGVwdc~mbY)~wz6sc=IL`-c0xZZnG1`g%I+6h_qh-OB-cN&T@Q z{^a69Qy>l<@L9N=F$PVva)-m{G#NbQ=J$0_CZ09?N}+Ucc^0NNR1O`qB#0ROZ3ieI z|4@rG;{|U_hJNdhFPOwFeCkMie+GHX zJ*+!g9K+}e3Dgq^`3u(0!d(W6{@l2&S#G$iI$1ZkL@Z(eUVCk4dglj7frsN(*zb1V;`G z204<*XD?GFX=d99o1tN&w{Yl10f@ViL6~E2JAwInP!BD9lhBHo)?*d?cJ1r`;AQ`H z0RO6n;chds9hPjxi~yH6E^|D*kD{yxH)uuZ;TCVkJ)&&rx5WCrD7Wk1p108cfQqK0 zbcQ;)xyS7ChPa}wCfSc7!?=-H$%)G?BNTnRky&YXH{ zX$PC*h#A`-oWjY$%^tHl7jJg!j0G%b6sRiwZPqw=dsh3sLAy5ehM$ zHy$fM?rF8u*1V2y&-ZWm86W9h1?#}W&VwiIW{0+!S*;LWqjFw|1QWqbHwM%}Ag-Pq zp)c-#vShB%&haOE1W%fRaats%pUh2y_o)}BPr{9mT6gG!C1N%7rvdh}oz-;F8Ej#G zV+_M$wTEx1t!ES@5alxoY@+r6`pO%9)7*-YQ7Wi82)XrgUVA~Z6WUp3~!{(*EwwjKXJaagv0qERAzw| zdHIh^V3{)KSV@G;E&3^U;9wbAUX|evsmhV*ds#*hJnbt^CgJCVZB*pOU(Ur@o*5#1 zh$7{I`bFs1J}P}-i4+ke+vi>G+g>^v2Lh$SXr1q1{HVjTN%XV`hnVTSszTgCP{-9) zvs=8XTS~78y{St^EAqE<UJRBovd^v&N82ns-~0iOKbu zsM*PukL%!%=HzgPy2gU+ZBq1mq9rsoxzN`6>gw;6I;gwHto)vW?MlPJS$dV(fhoF1 zcg`2NB|)5prob^lQ2@v*no%foQv@6mm(1kd4CR)Zqw6{^-V26V9^*;-bvdZlz7;<_ zsc(^Iagf-4$J3J;J(erfx=OH(m~7+heK@IwhWF>l^NUG7iHbcO`maBg91j? zV8bmENV$&;s=Ee|@D>;i+dX;2cV{|h6v*whz})q zI&Out;<@-e;c`Pn+K_k%A76+?@Dw=Upr9y$j-Dt)B|KM-rw~sa2e7lg&Yr3B=B{vr zg*+tcn#`oxQCTh-;c&@=P4(*zwhz#c$=H}gaZaqpI_X&egiMC`;Jm5KGiUEMeuL`c ztOK1J&Xz8@h1~XMrd>8jJZHd(OP)++^&VFrzS{yNC`O$pORNaiB0KOIKv#-i;CICZ zyWoc5miO$b$%i$(B;nVmB%K$;Vb~jRNy8a>q zJCA?axgdF>{TuHc419<-X2pj4MAV4+V1|YqC=hI-6`#b+iX=v<;(<*1HjQTe#yU52 zELqjKflEPzMBJ2#1IOMnbAmVP=*u`s+K?4RTsNJc9j=u z2;*M3hOLqf|4~v3cjE#k4x8mVJM8d3NQBtEwZM;mQ1CxNL){760~LFv0*x?Ctnrdq zSrFl<=&V>6)SIV1^b9PVeqEM!+D>L^>R-Sw)M}Ogfk?d$TtMNi3`*qF=Xv3YcPJMq zw;s#7&mBVla&t;Z6aMMcS1-}AXq7Atd{3dhtWtoNi-Nwk5)@)p9=_AA(|nY^8G#1> z^a1DgS}m=Pj0uRhL1666jW%7ydVj`8QwIF#WDhxaP6q~KF5wXfp>H&+?bTpf)#0#^o7BsWXhQYMTI7*k^{akH8K+v2Q`yJ!m`pP&zBqCC|HJ68&Zx`EMZ zgKvCch&>5)NVm8q<7c>9P5yq$i1ENecE>L9rSGFP&cq}YbetX9_D&sm6gmWn`i~w$ zFH!c^83*q6}O^ir&a^>f8757%D7IQ literal 0 HcmV?d00001 diff --git a/boards/raytac/an54l15q_db/doc/index.rst b/boards/raytac/an54lq_db_15/doc/index.rst similarity index 81% rename from boards/raytac/an54l15q_db/doc/index.rst rename to boards/raytac/an54lq_db_15/doc/index.rst index 415b8ef51df39..8de880acc4f90 100644 --- a/boards/raytac/an54l15q_db/doc/index.rst +++ b/boards/raytac/an54lq_db_15/doc/index.rst @@ -1,9 +1,9 @@ -.. zephyr:board:: raytac_an54l15q_db +.. zephyr:board:: raytac_an54lq_db_15 Overview ******** -The Raytac AN54L15Q-DB demonstration board is a development board based on the Raytac AN54L15Q module. +The Raytac AN54LQ-DB-15 demonstration board is a development board based on the Raytac AN54LQ-15 module. It uses the Nordic Semiconductor nRF54L15 SoC solution. The idea is to connect all the module's pins to a 2.54mm pin header. It can easily open the verification module functions and connect with other peripheral devices and sensor pins, making it a useful tool for early software development. @@ -16,7 +16,7 @@ peripheral devices and sensor pins, making it a useful tool for early software d Hardware ******** -The Raytac AN54L15Q-DB has two crystal oscillators: +The Raytac AN54LQ-DB-15 has two crystal oscillators: * High-frequency 32 MHz crystal oscillator (HFXO) * Low-frequency 32.768 kHz crystal oscillator (LFXO) @@ -24,7 +24,7 @@ The Raytac AN54L15Q-DB has two crystal oscillators: The crystal oscillators can be configured to use either internal or external capacitors. -- Module Demo Board built by AN54L15Q +- Module Demo Board built by AN54LQ-15 - Nordic nRF54L15 SoC Solution - A recommended 3rd-party module by Nordic Semiconductor. - Intended for Bluetooth specification BT6 @@ -75,13 +75,13 @@ Programming and Debugging .. zephyr:board-supported-runners:: -Applications for the ``raytac_an54l15q_db/nrf54l15/cpuapp`` board can be +Applications for the ``raytac_an54lq_db_15/nrf54l15/cpuapp`` board can be built, flashed, and debugged in the usual way. See :ref:`build_an_application` and :ref:`application_run` for more details on building and running. .. note:: - The ``raytac_an54l15q_db`` board does not have an on-board J-Link debug IC; + The ``raytac_an54lq_db_15`` board does not have an on-board J-Link debug IC; Use the Debug out connector of the nRF5340-DK or nRF54L15-DK to connect to the J1 or J9 SWD connector, and use SEGGER J-Link OB IF to debug. @@ -114,9 +114,9 @@ Follow the instructions in the :ref:`nordic_segger` page to install and configure all the necessary software. Further information can be found in :ref:`nordic_segger_flashing`. -To build and program the sample to the Raytac AN54L15Q-DB, complete the following steps: +To build and program the sample to the Raytac AN54LQ-DB-15, complete the following steps: -First, connect the Raytac AN54L15Q-DB's J10 connector to you computer using a USB to TTL +First, connect the Raytac AN54LQ-DB-15's J10 connector to you computer using a USB to TTL converter. Then run your favorite terminal program to listen for output. .. code-block:: console @@ -130,7 +130,7 @@ Next, build the sample by running the following command: .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: raytac_an54l15q_db/nrf54l15/cpuapp + :board: raytac_an54lq_db_15/nrf54l15/cpuapp :goals: build flash References @@ -138,12 +138,6 @@ References .. target-notes:: -.. _Raytac AN54L15Q-DB website: - https://www.raytac.com/product/ins.php?index_id=139 -.. _Raytac AN54L15Q-DB Specification: - https://www.raytac.com/download/index.php?index_id=60 -.. _Raytac AN54L15Q-DB Schematic: - https://www.raytac.com/upload/catalog_b/8b5e364600a9cc8c53a869733e97f07e.jpg .. _nRF54L15 website: https://www.nordicsemi.com/Products/nRF54L15 .. _nRF54L15 documentation: https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/device_guides/nrf54l/index.html .. _J-Link Software and documentation pack: diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_pinctrl.dtsi b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15-pinctrl.dtsi similarity index 100% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_pinctrl.dtsi rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15-pinctrl.dtsi diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_common.dtsi b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_common.dtsi similarity index 96% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_common.dtsi rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_common.dtsi index 98eec9d2fe7f4..cbc24af075d62 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_common.dtsi +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_common.dtsi @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "raytac_an54l15q_db_pinctrl.dtsi" +#include "raytac_an54lq_db_15-pinctrl.dtsi" / { leds { @@ -110,5 +110,9 @@ pinctrl-names = "default", "sleep"; }; +&hfxo { + startup-time-us = <854>; +}; + /* Get a node label for wi-fi spi to use in shield files */ wifi_spi: &spi22 {}; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_cpuapp_common.dtsi similarity index 84% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_cpuapp_common.dtsi index 2029662e892ff..328397d3157e8 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_cpuapp_common.dtsi +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_cpuapp_common.dtsi @@ -7,7 +7,7 @@ /* This file is common to the secure and non-secure domain */ -#include "raytac_an54l15q_db_common.dtsi" +#include "raytac_an54lq_db_15_common.dtsi" / { chosen { @@ -19,6 +19,12 @@ zephyr,flash-controller = &rram_controller; zephyr,flash = &cpuapp_rram; zephyr,ieee802154 = &ieee802154; + zephyr,boot-mode = &boot_mode0; + }; + + aliases { + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; }; }; @@ -28,7 +34,7 @@ &lfxo { load-capacitors = "internal"; - load-capacitance-femtofarad = <15500>; + load-capacitance-femtofarad = <17000>; }; &hfxo { @@ -56,6 +62,10 @@ status = "okay"; }; +&nfct { + status = "okay"; +}; + &gpio0 { status = "okay"; }; @@ -92,6 +102,16 @@ status = "okay"; }; +&gpregret1 { + status = "okay"; + + boot_mode0: boot_mode@0 { + compatible = "zephyr,retention"; + status = "okay"; + reg = <0x0 0x1>; + }; +}; + &spi00 { status = "okay"; cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.dts b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.dts similarity index 70% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.dts rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.dts index d347ef16ac14b..7fa21fafd0216 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.dts +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.dts @@ -8,12 +8,11 @@ /dts-v1/; #include -#include "raytac_an54l15q_db_cpuapp_common.dtsi" +#include "raytac_an54lq_db_15_cpuapp_common.dtsi" / { - compatible = "raytac,an54l15q_db_nrf54l15-cpuapp"; - - model = "Raytac AN54L15Q-DB nRF54L15 Application MCU"; + compatible = "raytac,an54lq_db_15_nrf54l15-cpuapp"; + model = "Raytac AN54LQ-DB-15 nRF54L15 Application MCU"; chosen { zephyr,code-partition = &slot0_partition; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.yaml b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.yaml similarity index 75% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.yaml rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.yaml index 7a5e9a84f960c..6676ea96a29e1 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp.yaml +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp.yaml @@ -2,13 +2,12 @@ # Copyright (c) 2024 Raytac Corporation. # SPDX-License-Identifier: Apache-2.0 -identifier: raytac_an54l15q_db/nrf54l15/cpuapp -name: Raytac-AN54L15Q-DB-nRF54l15-Application +identifier: raytac_an54lq_db_15/nrf54l15/cpuapp +name: Raytac-AN54LQ-DB-15-nRF54l15-Application type: mcu arch: arm toolchain: - gnuarmemb - - xtools - zephyr sysbuild: true ram: 188 @@ -16,6 +15,7 @@ flash: 1428 supported: - adc - counter + - dmic - gpio - i2c - pwm diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_defconfig b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_defconfig similarity index 81% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_defconfig rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_defconfig index 299496280d227..d8efa7c1be2b9 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_defconfig +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_defconfig @@ -14,6 +14,3 @@ CONFIG_GPIO=y # Enable MPU CONFIG_ARM_MPU=y - -# Enable hardware stack protection -CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.dts b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.dts similarity index 90% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.dts rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.dts index d6395d7fd71a3..8582e62d2f238 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.dts +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.dts @@ -10,11 +10,11 @@ #define USE_NON_SECURE_ADDRESS_MAP 1 #include -#include "raytac_an54l15q_db_cpuapp_common.dtsi" +#include "raytac_an54lq_db_15_cpuapp_common.dtsi" / { - compatible = "raytac,raytac_an54l15q_db_nrf54l15-cpuapp"; - model = "Raytac AN54L15Q-DB nRF54L15 Application MCU"; + compatible = "raytac,raytac_an54lq_db_15_nrf54l15-cpuapp"; + model = "Raytac AN54LQ-DB-15 nRF54L15 Application MCU"; chosen { zephyr,code-partition = &slot0_ns_partition; @@ -61,6 +61,7 @@ &uart30 { /* Disable so that TF-M can use this UART */ status = "disabled"; + current-speed = <115200>; pinctrl-0 = <&uart30_default>; pinctrl-1 = <&uart30_sleep>; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.yaml b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.yaml similarity index 74% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.yaml rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.yaml index 8662a82fad603..2f26145805c75 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns.yaml +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns.yaml @@ -2,8 +2,8 @@ # Copyright (c) 2025 Raytac Corporation. # SPDX-License-Identifier: Apache-2.0 -identifier: raytac_an54l15q_db/nrf54l15/cpuapp/ns -name: Raytac-AN54L15Q-DB-nRF54l15-Application-Non-Secure +identifier: raytac_an54lq_db_15/nrf54l15/cpuapp/ns +name: Raytac-AN54LQ-DB-15-nRF54l15-Application-Non-Secure type: mcu arch: arm toolchain: diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns_defconfig b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns_defconfig similarity index 97% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns_defconfig rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns_defconfig index 0df2316b45024..c364a395a2479 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuapp_ns_defconfig +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuapp_ns_defconfig @@ -3,7 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_ARM_MPU=y -CONFIG_HW_STACK_PROTECTION=y CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y CONFIG_ARM_TRUSTZONE_M=y diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.dts b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.dts similarity index 86% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.dts rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.dts index d7c1a0cbbe007..582bbf6d7c3a1 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.dts +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.dts @@ -7,11 +7,11 @@ /dts-v1/; #include -#include "raytac_an54l15q_db_common.dtsi" +#include "raytac_an54lq_db_15_common.dtsi" / { - model = "Raytac AN54L15Q-DB nRF54L15 FLPR MCU"; - compatible = "raytac,raytac_an54l15q_db_nrf54l15-cpuflpr"; + model = "Raytac AN54LQ-DB-15 nRF54L15 FLPR MCU"; + compatible = "raytac,raytac_an54lq_db_15_nrf54l15-cpuflpr"; chosen { zephyr,console = &uart30; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.yaml b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.yaml similarity index 68% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.yaml rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.yaml index 3a4f07f907e84..02bbe34aaaf52 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr.yaml +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr.yaml @@ -2,8 +2,8 @@ # Copyright (c) 2025 Raytac Corporation. # SPDX-License-Identifier: Apache-2.0 -identifier: raytac_an54l15q_db/nrf54l15/cpuflpr -name: Raytac-AN54L15Q-DB-nRF54L15-Fast-Lightweight-Peripheral-Processor +identifier: raytac_an54lq_db_15/nrf54l15/cpuflpr +name: Raytac-AN54LQ-DB-15-nRF54L15-Fast-Lightweight-Peripheral-Processor type: mcu arch: riscv toolchain: diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_defconfig b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_defconfig similarity index 100% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_defconfig rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_defconfig diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.dts b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.dts similarity index 81% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.dts rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.dts index 3e700be42dae4..7509267b8262c 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.dts +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.dts @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "raytac_an54l15q_db_nrf54l15_cpuflpr.dts" +#include "raytac_an54lq_db_15_nrf54l15_cpuflpr.dts" &cpuflpr_sram { reg = <0x2002f000 DT_SIZE_K(68)>; diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.yaml b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.yaml similarity index 65% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.yaml rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.yaml index ee996f4a9a1db..5f2bf3fe9ac27 100644 --- a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.yaml +++ b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.yaml @@ -2,8 +2,8 @@ # Copyright (c) 2025 Raytac Corporation. # SPDX-License-Identifier: Apache-2.0 -identifier: raytac_an54l15q_db/nrf54l15/cpuflpr/xip -name: Raytac-AN54L15Q-DB-nRF54L15-Fast-Lightweight-Peripheral-Processor (RRAM XIP) +identifier: raytac_an54lq_db_15/nrf54l15/cpuflpr/xip +name: Raytac-AN54LQ-DB-15-nRF54L15-Fast-Lightweight-Peripheral-Processor (RRAM XIP) type: mcu arch: riscv toolchain: diff --git a/boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip_defconfig b/boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip_defconfig similarity index 100% rename from boards/raytac/an54l15q_db/raytac_an54l15q_db_nrf54l15_cpuflpr_xip_defconfig rename to boards/raytac/an54lq_db_15/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip_defconfig diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index b7ab9b27ec57f..6cccbb20cb5ac 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -27,6 +27,7 @@ ('boards/rak/rak11720/doc/index', 'boards/rakwireless/rak11720/doc/index'), ('boards/rak/rak4631/doc/index', 'boards/rakwireless/rak4631/doc/index'), ('boards/rak/rak5010/doc/index', 'boards/rakwireless/rak5010/doc/index'), + ('boards/raytac/an54l15q_db/doc/index', 'boards/raytac/an54lq_db_15/doc/index'), ('boards/x86/ehl_crb/doc/index', 'boards/x86/intel_ehl/doc/index'), ('boards/x86/intel_ehl/doc/index', 'boards/intel/ehl/doc/index'), ('boards/x86/intel_rpl/doc/index', 'boards/intel/rpl/doc/index'), diff --git a/doc/releases/release-notes-4.2.rst b/doc/releases/release-notes-4.2.rst index 048c32ba9fdc7..b73d345acb01b 100644 --- a/doc/releases/release-notes-4.2.rst +++ b/doc/releases/release-notes-4.2.rst @@ -650,7 +650,7 @@ New Boards * Raytac Corporation - * :zephyr:board:`raytac_an54l15q_db` (``raytac_an54l15q_db``) + * :zephyr:board:`raytac_an54lq_db_15` (``raytac_an54lq_db_15``) * :zephyr:board:`raytac_an7002q_db` (``raytac_an7002q_db``) * :zephyr:board:`raytac_mdbt50q_cx_40_dongle` (``raytac_mdbt50q_cx_40_dongle``) diff --git a/samples/drivers/adc/adc_dt/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/samples/drivers/adc/adc_dt/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from samples/drivers/adc/adc_dt/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to samples/drivers/adc/adc_dt/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay diff --git a/samples/drivers/adc/adc_dt/sample.yaml b/samples/drivers/adc/adc_dt/sample.yaml index ec22c4e2a4596..9167b2d2c5015 100644 --- a/samples/drivers/adc/adc_dt/sample.yaml +++ b/samples/drivers/adc/adc_dt/sample.yaml @@ -45,11 +45,11 @@ tests: - slwrb4180a - xg27_rb4194a - xg29_rb4412a - - raytac_an54l15q_db/nrf54l15/cpuapp - frdm_mcxa346 - frdm_mcxa266 - frdm_mcxa366 - s32k148_evb + - raytac_an54lq_db_15/nrf54l15/cpuapp integration_platforms: - nucleo_l073rz - nrf52840dk/nrf52840 diff --git a/samples/drivers/adc/adc_sequence/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/samples/drivers/adc/adc_sequence/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from samples/drivers/adc/adc_sequence/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to samples/drivers/adc/adc_sequence/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay diff --git a/samples/drivers/adc/adc_sequence/sample.yaml b/samples/drivers/adc/adc_sequence/sample.yaml index cdfafef91cd32..52f1971664ecb 100644 --- a/samples/drivers/adc/adc_sequence/sample.yaml +++ b/samples/drivers/adc/adc_sequence/sample.yaml @@ -24,7 +24,6 @@ tests: - nrf54l15dk/nrf54l15/cpuapp - nrf54lm20dk/nrf54lm20a/cpuapp - ophelia4ev/nrf54l15/cpuapp - - raytac_an54l15q_db/nrf54l15/cpuapp - ucans32k1sic - s32k148_evb - frdm_mcxc242 @@ -32,6 +31,7 @@ tests: - slwrb4180a - xg27_rb4194a - xg29_rb4412a + - raytac_an54lq_db_15/nrf54l15/cpuapp integration_platforms: - nrf52840dk/nrf52840 sample.drivers.adc.adc_sequence.8bit: diff --git a/samples/drivers/watchdog/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/samples/drivers/watchdog/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from samples/drivers/watchdog/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to samples/drivers/watchdog/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay diff --git a/samples/drivers/watchdog/boards/raytac_an54l15q_db_nrf54l15_cpuflpr.overlay b/samples/drivers/watchdog/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr.overlay similarity index 100% rename from samples/drivers/watchdog/boards/raytac_an54l15q_db_nrf54l15_cpuflpr.overlay rename to samples/drivers/watchdog/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr.overlay diff --git a/samples/drivers/watchdog/boards/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.overlay b/samples/drivers/watchdog/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.overlay similarity index 100% rename from samples/drivers/watchdog/boards/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.overlay rename to samples/drivers/watchdog/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.overlay diff --git a/samples/drivers/watchdog/sample.yaml b/samples/drivers/watchdog/sample.yaml index b89590cac86a4..09276e644d6a9 100644 --- a/samples/drivers/watchdog/sample.yaml +++ b/samples/drivers/watchdog/sample.yaml @@ -32,7 +32,7 @@ tests: - bl54l15_dvk/nrf54l10/cpuapp/ns - bl54l15_dvk/nrf54l15/cpuapp/ns - bl54l15u_dvk/nrf54l15/cpuapp/ns - - raytac_an54l15q_db/nrf54l15/cpuapp/ns + - raytac_an54lq_db_15/nrf54l15/cpuapp/ns sample.drivers.watchdog.stm32_wwdg: extra_args: DTC_OVERLAY_FILE=boards/stm32_wwdg.overlay filter: dt_compat_enabled("st,stm32-window-watchdog") diff --git a/tests/drivers/adc/adc_accuracy_test/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/tests/drivers/adc/adc_accuracy_test/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from tests/drivers/adc/adc_accuracy_test/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to tests/drivers/adc/adc_accuracy_test/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay diff --git a/tests/drivers/adc/adc_api/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/tests/drivers/adc/adc_api/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 95% rename from tests/drivers/adc/adc_api/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to tests/drivers/adc/adc_api/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay index 5248c25ae7a4a..87707847eeab2 100644 --- a/tests/drivers/adc/adc_api/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay +++ b/tests/drivers/adc/adc_api/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay @@ -6,7 +6,7 @@ / { zephyr,user { - io-channels = <&adc 0>, <&adc 1>, <&adc 2>; + io-channels = <&adc 0>, <&adc 1> , <&adc 2>; }; }; diff --git a/tests/drivers/adc/adc_api/testcase.yaml b/tests/drivers/adc/adc_api/testcase.yaml index 3cb2711665512..92caafb10ce1e 100644 --- a/tests/drivers/adc/adc_api/testcase.yaml +++ b/tests/drivers/adc/adc_api/testcase.yaml @@ -19,11 +19,12 @@ tests: - bl54l15_dvk/nrf54l10/cpuapp/ns - bl54l15_dvk/nrf54l15/cpuapp/ns - bl54l15u_dvk/nrf54l15/cpuapp/ns - - raytac_an54l15q_db/nrf54l15/cpuapp/ns - rpi_pico/rp2040/mcuboot - rpi_pico/rp2040/w/mcuboot - rpi_pico2/rp2350a/m33/mcuboot - rpi_pico2/rp2350a/m33/w/mcuboot + - raytac_an54lq_db_15/nrf54l15/cpuapp/ns + drivers.adc.b_u585i_iot02a_adc4: extra_args: - platform:b_u585i_iot02a/stm32u585xx:DTC_OVERLAY_FILE="boards/b_u585i_iot02a_adc4.overlay" integration_platforms: diff --git a/tests/drivers/adc/adc_error_cases/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/tests/drivers/adc/adc_error_cases/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from tests/drivers/adc/adc_error_cases/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to tests/drivers/adc/adc_error_cases/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54l15q_db_nrf54l15_cpuflpr.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr.overlay similarity index 100% rename from tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54l15q_db_nrf54l15_cpuflpr.overlay rename to tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr.overlay diff --git a/tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.overlay b/tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.overlay similarity index 100% rename from tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54l15q_db_nrf54l15_cpuflpr_xip.overlay rename to tests/drivers/watchdog/wdt_basic_api/boards/raytac_an54lq_db_15_nrf54l15_cpuflpr_xip.overlay diff --git a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml index 608d058fb35f3..76c37f7be19c0 100644 --- a/tests/drivers/watchdog/wdt_basic_api/testcase.yaml +++ b/tests/drivers/watchdog/wdt_basic_api/testcase.yaml @@ -32,9 +32,9 @@ tests: - bl54l15_dvk/nrf54l10/cpuapp/ns - bl54l15_dvk/nrf54l15/cpuapp/ns - bl54l15u_dvk/nrf54l15/cpuapp/ns - - raytac_an54l15q_db/nrf54l15/cpuapp/ns - frdm_mcxw71 - frdm_mcxw72/mcxw727c/cpu0 + - raytac_an54lq_db_15/nrf54l15/cpuapp/ns drivers.watchdog.stm32wwdg: filter: dt_compat_enabled("st,stm32-window-watchdog") or dt_compat_enabled("st,stm32-watchdog") extra_args: DTC_OVERLAY_FILE="boards/stm32_wwdg.overlay" diff --git a/tests/drivers/watchdog/wdt_error_cases/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/tests/drivers/watchdog/wdt_error_cases/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from tests/drivers/watchdog/wdt_error_cases/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to tests/drivers/watchdog/wdt_error_cases/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay diff --git a/tests/drivers/watchdog/wdt_error_cases/testcase.yaml b/tests/drivers/watchdog/wdt_error_cases/testcase.yaml index 5325d73a88ce6..c48dc0b08bb15 100644 --- a/tests/drivers/watchdog/wdt_error_cases/testcase.yaml +++ b/tests/drivers/watchdog/wdt_error_cases/testcase.yaml @@ -16,13 +16,13 @@ tests: - nrf9280pdk/nrf9280/cpuapp - nrf9280pdk/nrf9280/cpurad - ophelia4ev/nrf54l15/cpuapp - - raytac_an54l15q_db/nrf54l15/cpuapp - xg24_rb4187c - xg27_dk2602a + - raytac_an54lq_db_15/nrf54l15/cpuapp integration_platforms: - nrf54l15dk/nrf54l15/cpuapp - ophelia4ev/nrf54l15/cpuapp - - raytac_an54l15q_db/nrf54l15/cpuapp + - raytac_an54lq_db_15/nrf54l15/cpuapp drivers.watchdog.wdt_error_cases_pm: platform_allow: - xg24_rb4187c diff --git a/tests/drivers/watchdog/wdt_variables/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay b/tests/drivers/watchdog/wdt_variables/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay similarity index 100% rename from tests/drivers/watchdog/wdt_variables/boards/raytac_an54l15q_db_nrf54l15_cpuapp.overlay rename to tests/drivers/watchdog/wdt_variables/boards/raytac_an54lq_db_15_nrf54l15_cpuapp.overlay From b9dcd718ad01f2fed7c416a519d89f18bc905b4f Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Wed, 6 Aug 2025 18:17:16 -0400 Subject: [PATCH 171/397] icm4268x: Expand Bus RTIO queue Based on performance observed when cranking the sensor at +1000 Hz ODR, otherwise is not able to keep up with the pace. Signed-off-by: Luis Ubieda --- drivers/sensor/tdk/icm4268x/icm4268x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/tdk/icm4268x/icm4268x.c b/drivers/sensor/tdk/icm4268x/icm4268x.c index 8dcbe50d0b1e4..d9628035e0814 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x.c @@ -339,7 +339,7 @@ void icm4268x_unlock(const struct device *dev) #define ICM4268X_RTIO_DEFINE(inst) \ SPI_DT_IODEV_DEFINE(icm4268x_spi_iodev_##inst, DT_DRV_INST(inst), ICM4268X_SPI_CFG); \ - RTIO_DEFINE(icm4268x_rtio_##inst, 8, 4); + RTIO_DEFINE(icm4268x_rtio_##inst, 32, 32); #define ICM42688_DT_CONFIG_INIT(inst) \ { \ From d3d51a6030d00825e0237807ed6e7297693015ed Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Wed, 6 Aug 2025 18:31:16 -0400 Subject: [PATCH 172/397] icm4268x: Add defensive code to prevent invalid submissions Missing packets or overrunning/underrunning the queue should not result in a system crash. Signed-off-by: Luis Ubieda --- .../tdk/icm4268x/icm4268x_rtio_stream.c | 90 +++++++++++-------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c b/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c index 5013c6af1357c..0a86b7c7f9e22 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "icm4268x.h" #include "icm4268x_decoder.h" @@ -61,12 +62,19 @@ static void icm4268x_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, int const struct device *dev = arg; struct icm4268x_dev_data *drv_data = dev->data; - const struct icm4268x_dev_cfg *drv_cfg = dev->config; struct rtio_iodev_sqe *iodev_sqe = sqe->userdata; - rtio_iodev_sqe_ok(iodev_sqe, drv_data->fifo_count); + /* Flush out completions */ + struct rtio_cqe *cqe; - gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + do { + cqe = rtio_cqe_consume(r); + if (cqe != NULL) { + rtio_cqe_release(r, cqe); + } + } while (cqe != NULL); + + rtio_iodev_sqe_ok(iodev_sqe, drv_data->fifo_count); } static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, @@ -76,7 +84,6 @@ static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, const struct device *dev = arg; struct icm4268x_dev_data *drv_data = dev->data; - const struct icm4268x_dev_cfg *drv_cfg = dev->config; struct rtio_iodev *spi_iodev = drv_data->spi_iodev; uint8_t *fifo_count_buf = (uint8_t *)&drv_data->fifo_count; uint16_t fifo_count = ((fifo_count_buf[0] << 8) | fifo_count_buf[1]); @@ -90,8 +97,7 @@ static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, /* Not inherently an underrun/overrun as we may have a buffer to fill next time */ if (iodev_sqe == NULL) { - LOG_DBG("No pending SQE"); - gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + LOG_ERR("No pending SQE"); return; } @@ -162,25 +168,21 @@ static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, uint8_t *read_buf = buf + sizeof(hdr); - /* Flush out completions */ - struct rtio_cqe *cqe; - - do { - cqe = rtio_cqe_consume(r); - if (cqe != NULL) { - rtio_cqe_release(r, cqe); - } - } while (cqe != NULL); - /* Setup new rtio chain to read the fifo data and report then check the * result */ struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(r); - __ASSERT_NO_MSG(write_fifo_addr != NULL); struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(r); - __ASSERT_NO_MSG(read_fifo_data != NULL); struct rtio_sqe *complete_op = rtio_sqe_acquire(r); - __ASSERT_NO_MSG(complete_op != NULL); + + CHECKIF(!write_fifo_addr || !read_fifo_data || !complete_op) { + LOG_ERR("Could not allocate SQEs for SPI RTIO... Please resize SQs in icm4268x.c"); + drv_data->streaming_sqe = NULL; + rtio_sqe_drop_all(r); + rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); + return; + } + const uint8_t reg_addr = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_DATA); rtio_sqe_prep_tiny_write(write_fifo_addr, spi_iodev, RTIO_PRIO_NORM, ®_addr, 1, NULL); @@ -213,12 +215,12 @@ static void icm4268x_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, const struct device *dev = arg; struct icm4268x_dev_data *drv_data = dev->data; - const struct icm4268x_dev_cfg *drv_cfg = dev->config; struct rtio_iodev *spi_iodev = drv_data->spi_iodev; struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; struct sensor_read_config *read_config; if (streaming_sqe == NULL) { + LOG_WRN("int-status triggered with no streaming handle associated. Ignoring"); return; } @@ -241,21 +243,12 @@ static void icm4268x_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, FIELD_GET(BIT_FIFO_FULL_INT, drv_data->int_status) != 0; if (!has_fifo_ths_trig && !has_fifo_full_trig) { - LOG_DBG("No FIFO trigger is configured"); - gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + drv_data->streaming_sqe = NULL; + LOG_ERR("No FIFO trigger is configured"); + rtio_iodev_sqe_err(streaming_sqe, -EIO); return; } - /* Flush completions */ - struct rtio_cqe *cqe; - - do { - cqe = rtio_cqe_consume(r); - if (cqe != NULL) { - rtio_cqe_release(r, cqe); - } - } while (cqe != NULL); - enum sensor_stream_data_opt data_opt; if (has_fifo_ths_trig && !has_fifo_full_trig) { @@ -287,11 +280,15 @@ static void icm4268x_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, data->header.timestamp = drv_data->timestamp; data->int_status = drv_data->int_status; data->fifo_count = 0; - rtio_iodev_sqe_ok(streaming_sqe, 0); - gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); if (data_opt == SENSOR_STREAM_DATA_DROP) { /* Flush the FIFO */ struct rtio_sqe *write_signal_path_reset = rtio_sqe_acquire(r); + + CHECKIF(!write_signal_path_reset) { + rtio_sqe_drop_all(r); + rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); + return; + } uint8_t write_buffer[] = { FIELD_GET(REG_ADDRESS_MASK, REG_SIGNAL_PATH_RESET), BIT_FIFO_FLUSH, @@ -303,6 +300,7 @@ static void icm4268x_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, rtio_submit(r, 1); ARG_UNUSED(rtio_cqe_consume(r)); } + rtio_iodev_sqe_ok(streaming_sqe, 0); return; } @@ -310,6 +308,15 @@ static void icm4268x_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, struct rtio_sqe *write_fifo_count_reg = rtio_sqe_acquire(r); struct rtio_sqe *read_fifo_count = rtio_sqe_acquire(r); struct rtio_sqe *check_fifo_count = rtio_sqe_acquire(r); + + CHECKIF(!write_fifo_count_reg || !read_fifo_count || !check_fifo_count) { + LOG_ERR("Could not allocate SQEs for SPI RTIO... Please resize SQs in icm4268x.c"); + drv_data->streaming_sqe = NULL; + rtio_sqe_drop_all(r); + rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); + return; + } + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_COUNTH); uint8_t *read_buf = (uint8_t *)&drv_data->fifo_count; @@ -336,8 +343,10 @@ void icm4268x_fifo_event(const struct device *dev) rc = sensor_clock_get_cycles(&cycles); if (rc != 0) { + struct rtio_iodev_sqe *iodev_sqe = drv_data->streaming_sqe; LOG_ERR("Failed to get sensor clock cycles"); - rtio_iodev_sqe_err(drv_data->streaming_sqe, rc); + drv_data->streaming_sqe = NULL; + rtio_iodev_sqe_err(iodev_sqe, rc); return; } @@ -355,6 +364,17 @@ void icm4268x_fifo_event(const struct device *dev) struct rtio_sqe *write_int_reg = rtio_sqe_acquire(r); struct rtio_sqe *read_int_reg = rtio_sqe_acquire(r); struct rtio_sqe *check_int_status = rtio_sqe_acquire(r); + + CHECKIF(!write_int_reg || !read_int_reg || !check_int_status) { + struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; + + LOG_ERR("Could not allocate SQEs for SPI RTIO... Please resize SQs in icm4268x.c"); + drv_data->streaming_sqe = NULL; + rtio_sqe_drop_all(r); + rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); + return; + } + uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_INT_STATUS); rtio_sqe_prep_tiny_write(write_int_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); From a0a20ab6377c48f2342b29b291867cb17b5b9931 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 11 Aug 2025 07:38:08 -0400 Subject: [PATCH 173/397] icm4268x: Remove RTIO Workqueue usage in streaming mode As it introduces latencies due to switching to the threads pool. Moreover, this is not required for streaming as it executes in a non-blocking path. Signed-off-by: Luis Ubieda --- drivers/sensor/tdk/icm4268x/icm4268x_rtio.c | 34 ++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c index c59aff475d4fb..1edf2a8be51bc 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c @@ -45,9 +45,10 @@ static int icm4268x_rtio_sample_fetch(const struct device *dev, int16_t readings return 0; } -static void icm4268x_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +void icm4268x_submit_one_shot_sync(struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + const struct device *dev = cfg->sensor; const struct sensor_chan_spec *const channels = cfg->channels; const size_t num_channels = cfg->count; uint32_t min_buf_len = sizeof(struct icm4268x_encoded_data); @@ -84,21 +85,7 @@ static void icm4268x_submit_one_shot(const struct device *dev, struct rtio_iodev rtio_iodev_sqe_ok(iodev_sqe, 0); } -void icm4268x_submit_sync(struct rtio_iodev_sqe *iodev_sqe) -{ - const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; - const struct device *dev = cfg->sensor; - - if (!cfg->is_streaming) { - icm4268x_submit_one_shot(dev, iodev_sqe); - } else if (IS_ENABLED(CONFIG_ICM4268X_STREAM)) { - icm4268x_submit_stream(dev, iodev_sqe); - } else { - rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); - } -} - -void icm4268x_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +static void icm4268x_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { struct rtio_work_req *req = rtio_work_req_alloc(); @@ -109,7 +96,20 @@ void icm4268x_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) return; } - rtio_work_req_submit(req, iodev_sqe, icm4268x_submit_sync); + rtio_work_req_submit(req, iodev_sqe, icm4268x_submit_one_shot_sync); +} + +void icm4268x_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + + if (!cfg->is_streaming) { + icm4268x_submit_one_shot(dev, iodev_sqe); + } else if (IS_ENABLED(CONFIG_ICM4268X_STREAM)) { + icm4268x_submit_stream(dev, iodev_sqe); + } else { + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); + } } BUILD_ASSERT(sizeof(struct icm4268x_decoder_header) == 15, From e8f9d457b25945444c1571999e84cc440a837034 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 11 Aug 2025 07:42:28 -0400 Subject: [PATCH 174/397] icm4268x: Remove padding from Decoder struct This induces extra-cycles in the encoding path while streaming, which make it difficult to achieve high-bandidth performance. The use-case being dealt with involves cranking the IMU at 8000 ODR in batches of 1.25 ms (10 samples at 800 Hz). Signed-off-by: Luis Ubieda --- drivers/sensor/tdk/icm4268x/icm4268x_decoder.h | 4 ++-- drivers/sensor/tdk/icm4268x/icm4268x_rtio.c | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_decoder.h b/drivers/sensor/tdk/icm4268x/icm4268x_decoder.h index 6d2cace1a5cb3..0f7cd6c32104c 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x_decoder.h +++ b/drivers/sensor/tdk/icm4268x/icm4268x_decoder.h @@ -18,7 +18,7 @@ struct icm4268x_decoder_header { uint8_t accel_fs: 3; uint8_t variant: 1; struct alignment axis_align[3]; -} __attribute__((__packed__)); +}; struct icm4268x_fifo_data { struct icm4268x_decoder_header header; @@ -28,7 +28,7 @@ struct icm4268x_fifo_data { uint16_t fifo_count: 11; uint16_t padding1: 5; uint16_t rtc_freq; -} __attribute__((__packed__)); +}; struct icm4268x_encoded_data { struct icm4268x_decoder_header header; diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c index 1edf2a8be51bc..22e5915ca37c4 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_rtio.c @@ -111,6 +111,3 @@ void icm4268x_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); } } - -BUILD_ASSERT(sizeof(struct icm4268x_decoder_header) == 15, - "icm4268x_decoder_header size is not equal to 15"); From 23a6cba718ac816984fa92172ac410255be0d041 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 11 Aug 2025 07:46:34 -0400 Subject: [PATCH 175/397] icm4268x: Do not enable GPIO Interrupts on trigger_init Wait until the trigger or streaming mode is configured. Otherwise, rebooting in-between runs may cause multiple callbacks invoked when the trigger may have not been enabled yet. Signed-off-by: Luis Ubieda --- drivers/sensor/tdk/icm4268x/icm4268x_trigger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_trigger.c b/drivers/sensor/tdk/icm4268x/icm4268x_trigger.c index cbbd6b9205e16..d844a3be391cd 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x_trigger.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_trigger.c @@ -147,7 +147,7 @@ int icm4268x_trigger_init(const struct device *dev) #elif defined(CONFIG_ICM4268X_TRIGGER_GLOBAL_THREAD) data->work.handler = icm4268x_work_handler; #endif - return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); + return 0; } int icm4268x_trigger_enable_interrupt(const struct device *dev, struct icm4268x_cfg *new_cfg) From cb86bec8a361dd72336995b5868098c922c7fc8b Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Mon, 11 Aug 2025 08:15:21 -0400 Subject: [PATCH 176/397] icm4268x: Various driver Improvements for streaming mode This patch makes the following improvements: - Helper APIs for simplifying RTIO transfers. - Simplify RTIO Streaming implementation to reduce processing time. - Add streaming mode atomic state, in order to track overruning the callback events generation. - Add device pointer address to logging on error-occurrences, as it is useful when the app has multiple instances of the driver (e.g: NXP's VMU RT1170 has two). Signed-off-by: Luis Ubieda --- drivers/sensor/tdk/icm4268x/CMakeLists.txt | 1 + drivers/sensor/tdk/icm4268x/icm4268x.c | 9 +- drivers/sensor/tdk/icm4268x/icm4268x.h | 13 +- drivers/sensor/tdk/icm4268x/icm4268x_bus.c | 120 ++++++ drivers/sensor/tdk/icm4268x/icm4268x_bus.h | 32 ++ drivers/sensor/tdk/icm4268x/icm4268x_common.c | 8 +- .../tdk/icm4268x/icm4268x_rtio_stream.c | 382 +++++++----------- 7 files changed, 310 insertions(+), 255 deletions(-) create mode 100644 drivers/sensor/tdk/icm4268x/icm4268x_bus.c create mode 100644 drivers/sensor/tdk/icm4268x/icm4268x_bus.h diff --git a/drivers/sensor/tdk/icm4268x/CMakeLists.txt b/drivers/sensor/tdk/icm4268x/CMakeLists.txt index 76a814f2baa81..e3db420ccce22 100644 --- a/drivers/sensor/tdk/icm4268x/CMakeLists.txt +++ b/drivers/sensor/tdk/icm4268x/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_sources( icm4268x.c icm4268x_common.c icm4268x_spi.c + icm4268x_bus.c ) zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API icm4268x_rtio.c) diff --git a/drivers/sensor/tdk/icm4268x/icm4268x.c b/drivers/sensor/tdk/icm4268x/icm4268x.c index d9628035e0814..60e63d98b8ccc 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x.c @@ -374,8 +374,13 @@ void icm4268x_unlock(const struct device *dev) IF_ENABLED(CONFIG_ICM4268X_STREAM, (ICM4268X_RTIO_DEFINE(inst))); \ static struct icm4268x_dev_data icm4268x_driver_##inst = { \ .cfg = ICM42688_DT_CONFIG_INIT(inst), \ - IF_ENABLED(CONFIG_ICM4268X_STREAM, (.r = &icm4268x_rtio_##inst, \ - .spi_iodev = &icm4268x_spi_iodev_##inst,)) \ + IF_ENABLED(CONFIG_ICM4268X_STREAM, \ + ( \ + .bus.rtio = { \ + .ctx = &icm4268x_rtio_##inst, \ + .iodev = &icm4268x_spi_iodev_##inst, \ + }, \ + )) \ }; /** The rest of the Device-tree configuration is validated in the YAML diff --git a/drivers/sensor/tdk/icm4268x/icm4268x.h b/drivers/sensor/tdk/icm4268x/icm4268x.h index 032eeabc302b0..9af998ea335c3 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x.h +++ b/drivers/sensor/tdk/icm4268x/icm4268x.h @@ -14,6 +14,7 @@ #include #include #include +#include "icm4268x_bus.h" struct alignment { int8_t index; @@ -341,6 +342,7 @@ struct icm4268x_cfg { bool fifo_en; int32_t batch_ticks; + uint16_t fifo_wm; bool fifo_hires; /* TODO additional FIFO options */ @@ -358,6 +360,12 @@ struct icm4268x_trigger_entry { sensor_trigger_handler_t handler; }; +enum icm4268x_stream_state { + ICM4268X_STREAM_OFF = 0, + ICM4268X_STREAM_ON = 1, + ICM4268X_STREAM_BUSY = 2, +}; + /** * @brief Device data (struct device) */ @@ -373,12 +381,11 @@ struct icm4268x_dev_data { #endif #ifdef CONFIG_ICM4268X_STREAM struct rtio_iodev_sqe *streaming_sqe; - struct rtio *r; - struct rtio_iodev *spi_iodev; + struct icm4268x_bus bus; uint8_t int_status; uint16_t fifo_count; uint64_t timestamp; - atomic_t reading_fifo; + atomic_t state; #endif /* CONFIG_ICM4268X_STREAM */ const struct device *dev; struct gpio_callback gpio_cb; diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_bus.c b/drivers/sensor/tdk/icm4268x/icm4268x_bus.c new file mode 100644 index 0000000000000..ffbbb75aeb129 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_bus.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "icm4268x_bus.h" + +int icm4268x_prep_reg_read_rtio_async(const struct icm4268x_bus *bus, + uint8_t reg, uint8_t *buf, size_t size, + struct rtio_sqe **out) +{ + struct rtio *ctx = bus->rtio.ctx; + struct rtio_iodev *iodev = bus->rtio.iodev; + struct rtio_sqe *write_reg_sqe = rtio_sqe_acquire(ctx); + struct rtio_sqe *read_buf_sqe = rtio_sqe_acquire(ctx); + + if (!write_reg_sqe || !read_buf_sqe) { + rtio_sqe_drop_all(ctx); + return -ENOMEM; + } + + rtio_sqe_prep_tiny_write(write_reg_sqe, iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_reg_sqe->flags |= RTIO_SQE_TRANSACTION; + rtio_sqe_prep_read(read_buf_sqe, iodev, RTIO_PRIO_NORM, buf, size, NULL); + + /** Send back last SQE so it can be concatenated later. */ + if (out) { + *out = read_buf_sqe; + } + + return 2; +} + +int icm4268x_prep_reg_write_rtio_async(const struct icm4268x_bus *bus, + uint8_t reg, const uint8_t *buf, size_t size, + struct rtio_sqe **out) +{ + struct rtio *ctx = bus->rtio.ctx; + struct rtio_iodev *iodev = bus->rtio.iodev; + struct rtio_sqe *write_reg_sqe = rtio_sqe_acquire(ctx); + struct rtio_sqe *write_buf_sqe = rtio_sqe_acquire(ctx); + + if (!write_reg_sqe || !write_buf_sqe) { + rtio_sqe_drop_all(ctx); + return -ENOMEM; + } + + /** More than 7 won't work with tiny-write */ + if (size > 7) { + return -EINVAL; + } + + rtio_sqe_prep_tiny_write(write_reg_sqe, iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_reg_sqe->flags |= RTIO_SQE_TRANSACTION; + rtio_sqe_prep_tiny_write(write_buf_sqe, iodev, RTIO_PRIO_NORM, buf, size, NULL); + + /** Send back last SQE so it can be concatenated later. */ + if (out) { + *out = write_buf_sqe; + } + + return 2; +} + +int icm4268x_reg_read_rtio(const struct icm4268x_bus *bus, uint8_t start, uint8_t *buf, int size) +{ + struct rtio *ctx = bus->rtio.ctx; + struct rtio_cqe *cqe; + int ret; + + ret = icm4268x_prep_reg_read_rtio_async(bus, start, buf, size, NULL); + if (ret < 0) { + return ret; + } + + ret = rtio_submit(ctx, ret); + if (ret) { + return ret; + } + + do { + cqe = rtio_cqe_consume(ctx); + if (cqe != NULL) { + ret = cqe->result; + rtio_cqe_release(ctx, cqe); + } + } while (cqe != NULL); + + return ret; +} + +int icm4268x_reg_write_rtio(const struct icm4268x_bus *bus, uint8_t reg, const uint8_t *buf, + int size) +{ + struct rtio *ctx = bus->rtio.ctx; + struct rtio_cqe *cqe; + int ret; + + ret = icm4268x_prep_reg_write_rtio_async(bus, reg, buf, size, NULL); + if (ret < 0) { + return ret; + } + + ret = rtio_submit(ctx, ret); + if (ret) { + return ret; + } + + do { + cqe = rtio_cqe_consume(ctx); + if (cqe != NULL) { + ret = cqe->result; + rtio_cqe_release(ctx, cqe); + } + } while (cqe != NULL); + + return ret; +} diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_bus.h b/drivers/sensor/tdk/icm4268x/icm4268x_bus.h new file mode 100644 index 0000000000000..6ee94cc0d66a8 --- /dev/null +++ b/drivers/sensor/tdk/icm4268x/icm4268x_bus.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM4268X_ICM4268X_BUS_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM4268X_ICM4268X_BUS_H_ + +#include +#include + +struct icm4268x_bus { + struct { + struct rtio *ctx; + struct rtio_iodev *iodev; + } rtio; +}; + +int icm4268x_prep_reg_read_rtio_async(const struct icm4268x_bus *bus, uint8_t reg, uint8_t *buf, + size_t size, struct rtio_sqe **out); + +int icm4268x_prep_reg_write_rtio_async(const struct icm4268x_bus *bus, uint8_t reg, + const uint8_t *buf, size_t size, struct rtio_sqe **out); + +int icm4268x_reg_read_rtio(const struct icm4268x_bus *bus, uint8_t start, uint8_t *buf, int size); + +int icm4268x_reg_write_rtio(const struct icm4268x_bus *bus, uint8_t reg, const uint8_t *buf, + int size); + +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM4268X_ICM4268X_BUS_H_ */ diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_common.c b/drivers/sensor/tdk/icm4268x/icm4268x_common.c index a89e81b601e82..7d20b906e4f55 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x_common.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_common.c @@ -329,8 +329,10 @@ int icm4268x_configure(const struct device *dev, struct icm4268x_cfg *cfg) } /* Set watermark and interrupt handling first */ - uint16_t fifo_wm = icm4268x_compute_fifo_wm(cfg); - uint8_t fifo_wml = fifo_wm & 0xFF; + cfg->fifo_wm = icm4268x_compute_fifo_wm(cfg); + + uint8_t fifo_wml = cfg->fifo_wm & 0xFF; + uint8_t fifo_wmh = (cfg->fifo_wm >> 8) & 0x0F; LOG_DBG("FIFO_CONFIG2( (0x%x)) (WM Low) 0x%x", REG_FIFO_CONFIG2, fifo_wml); res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG2, fifo_wml); @@ -339,8 +341,6 @@ int icm4268x_configure(const struct device *dev, struct icm4268x_cfg *cfg) return -EINVAL; } - uint8_t fifo_wmh = (fifo_wm >> 8) & 0x0F; - LOG_DBG("FIFO_CONFIG3 (0x%x) (WM High) 0x%x", REG_FIFO_CONFIG3, fifo_wmh); res = icm4268x_spi_single_write(&dev_cfg->spi, REG_FIFO_CONFIG3, fifo_wmh); if (res != 0) { diff --git a/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c b/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c index 0a86b7c7f9e22..83f332d7c9b83 100644 --- a/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c +++ b/drivers/sensor/tdk/icm4268x/icm4268x_rtio_stream.c @@ -11,12 +11,14 @@ #include "icm4268x_decoder.h" #include "icm4268x_reg.h" #include "icm4268x_rtio.h" +#include "icm4268x_bus.h" LOG_MODULE_DECLARE(ICM4268X_RTIO, CONFIG_SENSOR_LOG_LEVEL); void icm4268x_submit_stream(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe) { const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + const struct icm4268x_dev_cfg *dev_cfg = (const struct icm4268x_dev_cfg *)sensor->config; struct icm4268x_dev_data *data = sensor->data; struct icm4268x_cfg new_config = data->cfg; @@ -47,73 +49,62 @@ void icm4268x_submit_stream(const struct device *sensor, struct rtio_iodev_sqe * int rc = icm4268x_safely_configure(sensor, &new_config); if (rc != 0) { - LOG_ERR("Failed to configure sensor"); + LOG_ERR("%p Failed to configure sensor", sensor); rtio_iodev_sqe_err(iodev_sqe, rc); return; } } + (void)atomic_set(&data->state, ICM4268X_STREAM_ON); data->streaming_sqe = iodev_sqe; + (void)gpio_pin_interrupt_configure_dt(&dev_cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE); } -static void icm4268x_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, int result, void *arg) +static struct sensor_stream_trigger * +icm4268x_get_read_config_trigger(const struct sensor_read_config *cfg, + enum sensor_trigger_type trig) { - ARG_UNUSED(result); + for (int i = 0; i < cfg->count; ++i) { + if (cfg->triggers[i].trigger == trig) { + return &cfg->triggers[i]; + } + } + LOG_DBG("Unsupported trigger (%d)", trig); + return NULL; +} - const struct device *dev = arg; +static inline void icm4268x_stream_result(const struct device *dev, int result) +{ struct icm4268x_dev_data *drv_data = dev->data; - struct rtio_iodev_sqe *iodev_sqe = sqe->userdata; - - /* Flush out completions */ - struct rtio_cqe *cqe; - - do { - cqe = rtio_cqe_consume(r); - if (cqe != NULL) { - rtio_cqe_release(r, cqe); - } - } while (cqe != NULL); + struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; - rtio_iodev_sqe_ok(iodev_sqe, drv_data->fifo_count); + drv_data->streaming_sqe = NULL; + if (result < 0) { + rtio_iodev_sqe_err(streaming_sqe, result); + } else { + rtio_iodev_sqe_ok(streaming_sqe, result); + } } -static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, - int result, void *arg) +static void icm4268x_complete_cb(struct rtio *r, const struct rtio_sqe *sqe, int result, void *arg) { ARG_UNUSED(result); const struct device *dev = arg; struct icm4268x_dev_data *drv_data = dev->data; - struct rtio_iodev *spi_iodev = drv_data->spi_iodev; - uint8_t *fifo_count_buf = (uint8_t *)&drv_data->fifo_count; - uint16_t fifo_count = ((fifo_count_buf[0] << 8) | fifo_count_buf[1]); - - drv_data->fifo_count = fifo_count; - - /* Pull a operation from our device iodev queue, validated to only be reads */ - struct rtio_iodev_sqe *iodev_sqe = drv_data->streaming_sqe; - - drv_data->streaming_sqe = NULL; - - /* Not inherently an underrun/overrun as we may have a buffer to fill next time */ - if (iodev_sqe == NULL) { - LOG_ERR("No pending SQE"); - return; - } - - const size_t packet_size = drv_data->cfg.fifo_hires ? 20 : 16; - const size_t min_read_size = sizeof(struct icm4268x_fifo_data) + packet_size; - const size_t ideal_read_size = sizeof(struct icm4268x_fifo_data) + fifo_count; + const struct icm4268x_dev_cfg *dev_cfg = (const struct icm4268x_dev_cfg *)dev->config; + struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; uint8_t *buf; uint32_t buf_len; + int rc; - if (rtio_sqe_rx_buf(iodev_sqe, min_read_size, ideal_read_size, &buf, &buf_len) != 0) { - LOG_ERR("Failed to get buffer"); - rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); + if (drv_data->streaming_sqe == NULL || + FIELD_GET(RTIO_SQE_CANCELED, drv_data->streaming_sqe->sqe.flags)) { + LOG_ERR("%p Complete CB triggered with NULL handle. Disabling Interrupt", dev); + (void)gpio_pin_interrupt_configure_dt(&dev_cfg->gpio_int1, GPIO_INT_DISABLE); + (void)atomic_set(&drv_data->state, ICM4268X_STREAM_OFF); return; } - LOG_DBG("Requesting buffer [%u, %u] got %u", (unsigned int)min_read_size, - (unsigned int)ideal_read_size, buf_len); /** FSR are fixed for high-resolution, at which point we should * override driver FS config. @@ -132,11 +123,17 @@ static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, default: CODE_UNREACHABLE; } + /* Even if we flushed the fifo, we still need room for the header to return result info */ + size_t required_len = sizeof(struct icm4268x_fifo_data); - /* Read FIFO and call back to rtio with rtio_sqe completion */ - /* TODO is packet format even needed? the fifo has a header per packet - * already - */ + rc = rtio_sqe_rx_buf(streaming_sqe, required_len, required_len, &buf, &buf_len); + CHECKIF(rc < 0 || !buf) { + LOG_ERR("%p Failed to obtain SQE buffer: %d", dev, rc); + icm4268x_stream_result(dev, -ENOMEM); + return; + } + + struct icm4268x_fifo_data *edata = (struct icm4268x_fifo_data *)buf; struct icm4268x_fifo_data hdr = { .header = { .is_fifo = true, @@ -151,236 +148,129 @@ static void icm4268x_fifo_count_cb(struct rtio *r, const struct rtio_sqe *sqe, .int_status = drv_data->int_status, .gyro_odr = drv_data->cfg.gyro_odr, .accel_odr = drv_data->cfg.accel_odr, + .fifo_count = drv_data->cfg.fifo_wm, .rtc_freq = drv_data->cfg.rtc_freq, }; - uint32_t buf_avail = buf_len; - - memcpy(buf, &hdr, sizeof(hdr)); - buf_avail -= sizeof(hdr); - - uint32_t read_len = MIN(fifo_count, buf_avail); - uint32_t pkts = read_len / packet_size; - - read_len = pkts * packet_size; - ((struct icm4268x_fifo_data *)buf)->fifo_count = read_len; + *edata = hdr; - __ASSERT_NO_MSG(read_len % packet_size == 0); + if (FIELD_GET(BIT_FIFO_FULL_INT, edata->int_status) == true) { + uint8_t val = BIT_FIFO_FLUSH; - uint8_t *read_buf = buf + sizeof(hdr); - - /* Setup new rtio chain to read the fifo data and report then check the - * result - */ - struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(r); - struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(r); - struct rtio_sqe *complete_op = rtio_sqe_acquire(r); - - CHECKIF(!write_fifo_addr || !read_fifo_data || !complete_op) { - LOG_ERR("Could not allocate SQEs for SPI RTIO... Please resize SQs in icm4268x.c"); - drv_data->streaming_sqe = NULL; - rtio_sqe_drop_all(r); - rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); - return; - } - - const uint8_t reg_addr = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_DATA); - - rtio_sqe_prep_tiny_write(write_fifo_addr, spi_iodev, RTIO_PRIO_NORM, ®_addr, 1, NULL); - write_fifo_addr->flags = RTIO_SQE_TRANSACTION; - rtio_sqe_prep_read(read_fifo_data, spi_iodev, RTIO_PRIO_NORM, read_buf, read_len, - iodev_sqe); - read_fifo_data->flags = RTIO_SQE_CHAINED; - rtio_sqe_prep_callback(complete_op, icm4268x_complete_cb, (void *)dev, iodev_sqe); - - rtio_submit(r, 0); -} - -static struct sensor_stream_trigger * -icm4268x_get_read_config_trigger(const struct sensor_read_config *cfg, - enum sensor_trigger_type trig) -{ - for (int i = 0; i < cfg->count; ++i) { - if (cfg->triggers[i].trigger == trig) { - return &cfg->triggers[i]; - } - } - LOG_DBG("Unsupported trigger (%d)", trig); - return NULL; -} - -static void icm4268x_int_status_cb(struct rtio *r, const struct rtio_sqe *sqr, - int result, void *arg) -{ - ARG_UNUSED(result); - - const struct device *dev = arg; - struct icm4268x_dev_data *drv_data = dev->data; - struct rtio_iodev *spi_iodev = drv_data->spi_iodev; - struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; - struct sensor_read_config *read_config; - - if (streaming_sqe == NULL) { - LOG_WRN("int-status triggered with no streaming handle associated. Ignoring"); - return; - } - - read_config = (struct sensor_read_config *)streaming_sqe->sqe.iodev->data; - __ASSERT_NO_MSG(read_config != NULL); - - if (!read_config->is_streaming) { - /* Oops, not really configured for streaming data */ - return; - } - - struct sensor_stream_trigger *fifo_ths_cfg = - icm4268x_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_WATERMARK); - bool has_fifo_ths_trig = fifo_ths_cfg != NULL && - FIELD_GET(BIT_FIFO_THS_INT, drv_data->int_status) != 0; - - struct sensor_stream_trigger *fifo_full_cfg = - icm4268x_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_FULL); - bool has_fifo_full_trig = fifo_full_cfg != NULL && - FIELD_GET(BIT_FIFO_FULL_INT, drv_data->int_status) != 0; - - if (!has_fifo_ths_trig && !has_fifo_full_trig) { - drv_data->streaming_sqe = NULL; - LOG_ERR("No FIFO trigger is configured"); - rtio_iodev_sqe_err(streaming_sqe, -EIO); - return; - } - - enum sensor_stream_data_opt data_opt; - - if (has_fifo_ths_trig && !has_fifo_full_trig) { - /* Only care about fifo threshold */ - data_opt = fifo_ths_cfg->opt; - } else if (!has_fifo_ths_trig && has_fifo_full_trig) { - /* Only care about fifo full */ - data_opt = fifo_full_cfg->opt; - } else { - /* Both fifo threshold and full */ - data_opt = MIN(fifo_ths_cfg->opt, fifo_full_cfg->opt); - } - - if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) { - uint8_t *buf; - uint32_t buf_len; - - /* Clear streaming_sqe since we're done with the call */ - drv_data->streaming_sqe = NULL; - if (rtio_sqe_rx_buf(streaming_sqe, sizeof(struct icm4268x_fifo_data), - sizeof(struct icm4268x_fifo_data), &buf, &buf_len) != 0) { - rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); + LOG_WRN("%p FIFO Full bit is set. Flushing FIFO...", dev); + rc = icm4268x_prep_reg_write_rtio_async(&drv_data->bus, REG_SIGNAL_PATH_RESET, + &val, 1, NULL); + CHECKIF(rc < 0) { + LOG_ERR("%p Failed to flush the FIFO buffer: %d", dev, rc); + icm4268x_stream_result(dev, rc); return; } + rtio_submit(drv_data->bus.rtio.ctx, 0); + } - struct icm4268x_fifo_data *data = (struct icm4268x_fifo_data *)buf; - - memset(buf, 0, buf_len); - data->header.timestamp = drv_data->timestamp; - data->int_status = drv_data->int_status; - data->fifo_count = 0; - if (data_opt == SENSOR_STREAM_DATA_DROP) { - /* Flush the FIFO */ - struct rtio_sqe *write_signal_path_reset = rtio_sqe_acquire(r); + struct rtio_cqe *cqe; - CHECKIF(!write_signal_path_reset) { - rtio_sqe_drop_all(r); - rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); - return; + do { + cqe = rtio_cqe_consume(drv_data->bus.rtio.ctx); + if (cqe != NULL) { + if (rc >= 0) { + rc = cqe->result; } - uint8_t write_buffer[] = { - FIELD_GET(REG_ADDRESS_MASK, REG_SIGNAL_PATH_RESET), - BIT_FIFO_FLUSH, - }; - - rtio_sqe_prep_tiny_write(write_signal_path_reset, spi_iodev, RTIO_PRIO_NORM, - write_buffer, ARRAY_SIZE(write_buffer), NULL); - /* TODO Add a new flag for fire-and-forget so we don't have to block here */ - rtio_submit(r, 1); - ARG_UNUSED(rtio_cqe_consume(r)); + rtio_cqe_release(drv_data->bus.rtio.ctx, cqe); } - rtio_iodev_sqe_ok(streaming_sqe, 0); - return; - } - - /* We need the data, read the fifo length */ - struct rtio_sqe *write_fifo_count_reg = rtio_sqe_acquire(r); - struct rtio_sqe *read_fifo_count = rtio_sqe_acquire(r); - struct rtio_sqe *check_fifo_count = rtio_sqe_acquire(r); - - CHECKIF(!write_fifo_count_reg || !read_fifo_count || !check_fifo_count) { - LOG_ERR("Could not allocate SQEs for SPI RTIO... Please resize SQs in icm4268x.c"); - drv_data->streaming_sqe = NULL; - rtio_sqe_drop_all(r); - rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); - return; - } - - uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_FIFO_COUNTH); - uint8_t *read_buf = (uint8_t *)&drv_data->fifo_count; - - rtio_sqe_prep_tiny_write(write_fifo_count_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); - write_fifo_count_reg->flags = RTIO_SQE_TRANSACTION; - rtio_sqe_prep_read(read_fifo_count, spi_iodev, RTIO_PRIO_NORM, read_buf, 2, NULL); - read_fifo_count->flags = RTIO_SQE_CHAINED; - rtio_sqe_prep_callback(check_fifo_count, icm4268x_fifo_count_cb, arg, NULL); + } while (cqe != NULL); - rtio_submit(r, 0); + (void)atomic_set(&drv_data->state, ICM4268X_STREAM_OFF); + icm4268x_stream_result(dev, rc); } void icm4268x_fifo_event(const struct device *dev) { struct icm4268x_dev_data *drv_data = dev->data; - struct rtio_iodev *spi_iodev = drv_data->spi_iodev; - struct rtio *r = drv_data->r; + const struct icm4268x_dev_cfg *dev_cfg = (const struct icm4268x_dev_cfg *)dev->config; + struct rtio_sqe *sqe; uint64_t cycles; int rc; - if (drv_data->streaming_sqe == NULL) { + if (drv_data->streaming_sqe == NULL || + FIELD_GET(RTIO_SQE_CANCELED, drv_data->streaming_sqe->sqe.flags)) { + LOG_ERR("%p FIFO event triggered with no stream submisssion. Disabling IRQ", dev); + (void)gpio_pin_interrupt_configure_dt(&dev_cfg->gpio_int1, GPIO_INT_DISABLE); + (void)atomic_set(&drv_data->state, ICM4268X_STREAM_OFF); + return; + } + if (atomic_cas(&drv_data->state, ICM4268X_STREAM_ON, ICM4268X_STREAM_BUSY) == false) { + LOG_WRN("%p Callback triggered while stream is busy. Ignoring request", dev); return; } rc = sensor_clock_get_cycles(&cycles); if (rc != 0) { - struct rtio_iodev_sqe *iodev_sqe = drv_data->streaming_sqe; - LOG_ERR("Failed to get sensor clock cycles"); - drv_data->streaming_sqe = NULL; - rtio_iodev_sqe_err(iodev_sqe, rc); + LOG_ERR("%p Failed to get sensor clock cycles", dev); + icm4268x_stream_result(dev, rc); return; } - drv_data->timestamp = sensor_clock_cycles_to_ns(cycles); - /* - * Setup rtio chain of ops with inline calls to make decisions - * 1. read int status - * 2. call to check int status and get pending RX operation - * 4. read fifo len - * 5. call to determine read len - * 6. read fifo - * 7. call to report completion - */ - struct rtio_sqe *write_int_reg = rtio_sqe_acquire(r); - struct rtio_sqe *read_int_reg = rtio_sqe_acquire(r); - struct rtio_sqe *check_int_status = rtio_sqe_acquire(r); + rc = icm4268x_prep_reg_read_rtio_async(&drv_data->bus, REG_INT_STATUS | REG_SPI_READ_BIT, + &drv_data->int_status, 1, &sqe); + CHECKIF(rc < 0 || !sqe) { + LOG_ERR("%p Could not prepare async read: %d", dev, rc); + icm4268x_stream_result(dev, -ENOMEM); + return; + } + sqe->flags |= RTIO_SQE_CHAINED; - CHECKIF(!write_int_reg || !read_int_reg || !check_int_status) { - struct rtio_iodev_sqe *streaming_sqe = drv_data->streaming_sqe; + struct sensor_read_config *read_config = + (struct sensor_read_config *)drv_data->streaming_sqe->sqe.iodev->data; + struct sensor_stream_trigger *fifo_ths_cfg = + icm4268x_get_read_config_trigger(read_config, SENSOR_TRIG_FIFO_WATERMARK); - LOG_ERR("Could not allocate SQEs for SPI RTIO... Please resize SQs in icm4268x.c"); - drv_data->streaming_sqe = NULL; - rtio_sqe_drop_all(r); - rtio_iodev_sqe_err(streaming_sqe, -ENOMEM); - return; + if (fifo_ths_cfg && fifo_ths_cfg->opt == SENSOR_STREAM_DATA_INCLUDE) { + uint8_t *buf; + uint32_t buf_len; + uint16_t payload_read_len = drv_data->cfg.fifo_wm; + size_t required_len = sizeof(struct icm4268x_fifo_data) + payload_read_len; + + rc = rtio_sqe_rx_buf(drv_data->streaming_sqe, required_len, required_len, &buf, + &buf_len); + if (rc < 0) { + LOG_ERR("%p Failed to allocate buffer for the FIFO read: %d", dev, rc); + icm4268x_stream_result(dev, rc); + return; + } + + /** We fill we data first, the header we'll fill once we have + * read all the data. + */ + uint8_t *read_buf = buf + sizeof(struct icm4268x_fifo_data); + + rc = icm4268x_prep_reg_read_rtio_async(&drv_data->bus, + REG_FIFO_DATA | REG_SPI_READ_BIT, + read_buf, payload_read_len, &sqe); + if (rc < 0 || !sqe) { + LOG_ERR("%p Could not prepare async read: %d", dev, rc); + icm4268x_stream_result(dev, -ENOMEM); + return; + } + sqe->flags |= RTIO_SQE_CHAINED; + } else { + /** Because we don't want the data, flush it and be done with + * it. The trigger can be passed on to the user regardless. + */ + uint8_t val = BIT_FIFO_FLUSH; + + rc = icm4268x_prep_reg_write_rtio_async(&drv_data->bus, REG_SIGNAL_PATH_RESET, + &val, 1, &sqe); + if (rc < 0 || !sqe) { + LOG_ERR("%p Could not prepare async read: %d", dev, rc); + icm4268x_stream_result(dev, -ENOMEM); + return; + } + sqe->flags |= RTIO_SQE_CHAINED; } - uint8_t reg = REG_SPI_READ_BIT | FIELD_GET(REG_ADDRESS_MASK, REG_INT_STATUS); + struct rtio_sqe *cb_sqe = rtio_sqe_acquire(drv_data->bus.rtio.ctx); - rtio_sqe_prep_tiny_write(write_int_reg, spi_iodev, RTIO_PRIO_NORM, ®, 1, NULL); - write_int_reg->flags = RTIO_SQE_TRANSACTION; - rtio_sqe_prep_read(read_int_reg, spi_iodev, RTIO_PRIO_NORM, &drv_data->int_status, 1, NULL); - read_int_reg->flags = RTIO_SQE_CHAINED; - rtio_sqe_prep_callback(check_int_status, icm4268x_int_status_cb, (void *)dev, NULL); - rtio_submit(r, 0); + rtio_sqe_prep_callback(cb_sqe, icm4268x_complete_cb, (void *)dev, NULL); + rtio_submit(drv_data->bus.rtio.ctx, 0); } From 1d93c1cb13de931251c1f5f0d028dba888247985 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Sat, 30 Aug 2025 05:31:34 +0200 Subject: [PATCH 177/397] west.yml: Update hal_bouffalolab revision Update hal revision to fix double defines and missing bl70x dma defines Signed-off-by: Camille BAUD --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 33f2ebc3dc7d0..cb6a50b6c6d1a 100644 --- a/west.yml +++ b/west.yml @@ -165,7 +165,7 @@ manifest: - hal - name: hal_bouffalolab path: modules/hal/bouffalolab - revision: 9f2ab1b6b4e8f0dce589b56ea908dc47b5c62385 + revision: 89df8327276755b5935dc4cc2f2f68e27a8dba3d groups: - hal - name: hal_espressif From 4809f5e4277c85d0933b71273f99110de1f88dc2 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Tue, 26 Aug 2025 23:19:43 +0200 Subject: [PATCH 178/397] dts: bflb: Add DMA node for BFLB SoCs Adds the DMA node Signed-off-by: Camille BAUD --- dts/bindings/dma/bflb,dma.yaml | 31 +++++++++++++++++++++++++++++++ dts/riscv/bflb/bl60x.dtsi | 10 ++++++++++ dts/riscv/bflb/bl61x.dtsi | 10 ++++++++++ dts/riscv/bflb/bl70x.dtsi | 10 ++++++++++ 4 files changed, 61 insertions(+) create mode 100644 dts/bindings/dma/bflb,dma.yaml diff --git a/dts/bindings/dma/bflb,dma.yaml b/dts/bindings/dma/bflb,dma.yaml new file mode 100644 index 0000000000000..4aa94a196e2d1 --- /dev/null +++ b/dts/bindings/dma/bflb,dma.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2025 MASSDRIVER EI +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bouffalo Lab DMA + + BFLB platforms support 4 (BL60x and BL61x) to 8 (BL70x) independent DMA channels. + Every channel is capable of memory-to-memory, memory-to-peripheral, peripheral-to-memory and + peripheral-to-peripheral access. + All channels support 8, 16, and 32 bit width memory access. + Each channel can be triggered by independent peripheral hardware or software. + +compatible: "bflb,dma" + +include: dma-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + dma-channels: + required: true + + "#dma-cells": + const: 1 + +dma-cells: + - channel diff --git a/dts/riscv/bflb/bl60x.dtsi b/dts/riscv/bflb/bl60x.dtsi index 3b2e018232eb0..65d6ba11982cd 100644 --- a/dts/riscv/bflb/bl60x.dtsi +++ b/dts/riscv/bflb/bl60x.dtsi @@ -187,6 +187,16 @@ interrupt-parent = <&clic>; }; + dma0: dma@4000c000 { + compatible = "bflb,dma"; + reg = <0x4000c000 0x1000>; + #dma-cells = <1>; + dma-channels = <4>; + + interrupts = <31 0>; + interrupt-parent = <&clic>; + }; + retram: memory@40010000 { compatible = "mmio-sram"; reg = <0x40010000 DT_SIZE_K(4)>; diff --git a/dts/riscv/bflb/bl61x.dtsi b/dts/riscv/bflb/bl61x.dtsi index b2936b8b901c0..0e6d6ff2dcf39 100644 --- a/dts/riscv/bflb/bl61x.dtsi +++ b/dts/riscv/bflb/bl61x.dtsi @@ -180,6 +180,16 @@ interrupt-parent = <&clic>; }; + dma0: dma@2000c000 { + compatible = "bflb,dma"; + reg = <0x2000c000 0x1000>; + #dma-cells = <1>; + dma-channels = <4>; + + interrupts = <31 1>; + interrupt-parent = <&clic>; + }; + retram: memory@20010000 { compatible = "mmio-sram"; reg = <0x20010000 DT_SIZE_K(4)>; diff --git a/dts/riscv/bflb/bl70x.dtsi b/dts/riscv/bflb/bl70x.dtsi index a80dae7991ec0..3dab3f9cc73a0 100644 --- a/dts/riscv/bflb/bl70x.dtsi +++ b/dts/riscv/bflb/bl70x.dtsi @@ -181,6 +181,16 @@ interrupt-parent = <&clic>; }; + dma0: dma@4000c000 { + compatible = "bflb,dma"; + reg = <0x4000c000 0x1000>; + #dma-cells = <1>; + dma-channels = <8>; + + interrupts = <31 0>; + interrupt-parent = <&clic>; + }; + retram: memory@40010000 { compatible = "mmio-sram"; reg = <0x40010000 DT_SIZE_K(4)>; From 3c5b8c30103269b275504bd79a1eced8e0235d04 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Tue, 26 Aug 2025 23:20:36 +0200 Subject: [PATCH 179/397] drivers: dma: Introduce BFLB DMA driver Introduce BFLB's DMA. Signed-off-by: Camille BAUD --- drivers/dma/CMakeLists.txt | 1 + drivers/dma/Kconfig | 2 + drivers/dma/Kconfig.bflb | 9 + drivers/dma/dma_bflb.c | 424 +++++++++++++++++++++++++++++++++++++ 4 files changed, 436 insertions(+) create mode 100644 drivers/dma/Kconfig.bflb create mode 100644 drivers/dma/dma_bflb.c diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 240e7f364e182..8186dc8963c61 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -56,3 +56,4 @@ zephyr_library_sources_ifdef(CONFIG_DMA_WCH dma_wch.c) zephyr_library_sources_ifdef(CONFIG_DMA_TI_CC23X0 dma_ti_cc23x0.c) zephyr_library_sources_ifdef(CONFIG_DMA_NPCX_GDMA dma_npcx_gdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_SF32LB dma_sf32lb.c) +zephyr_library_sources_ifdef(CONFIG_DMA_BFLB dma_bflb.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 47254e3ba3372..8612da612f7f2 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -103,4 +103,6 @@ source "drivers/dma/Kconfig.npcx" source "drivers/dma/Kconfig.sf32lb" +source "drivers/dma/Kconfig.bflb" + endif # DMA diff --git a/drivers/dma/Kconfig.bflb b/drivers/dma/Kconfig.bflb new file mode 100644 index 0000000000000..61a0bc081371f --- /dev/null +++ b/drivers/dma/Kconfig.bflb @@ -0,0 +1,9 @@ +# Copyright (c) 2025 MASSDRIVER EI +# SPDX-License-Identifier: Apache-2.0 + +config DMA_BFLB + bool "Bouffalo Lab DMA driver" + default y + depends on DT_HAS_BFLB_DMA_ENABLED + help + DMA driver for Bouffalo Lab SoCs diff --git a/drivers/dma/dma_bflb.c b/drivers/dma/dma_bflb.c new file mode 100644 index 0000000000000..18ec33ba66b22 --- /dev/null +++ b/drivers/dma/dma_bflb.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2025 MASSDRIVER EI + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bflb_dma + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(dma_bflb, CONFIG_DMA_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#ifdef CONFIG_SOC_SERIES_BL61X +#define BFLB_DMA_CLOCK_ADDR (GLB_BASE + GLB_DMA_CFG0_OFFSET) +#else +#define BFLB_DMA_CLOCK_ADDR (GLB_BASE + GLB_CLK_CFG2_OFFSET) +#endif + +#define BFLB_DMA_CH_OFFSET(n) ((n + 1) * 0x100) + +#define BFLB_DMA_CH_NB DT_INST_PROP(0, dma_channels) + +#define BFLB_DMA_WIDTH_BYTE 0 +#define BFLB_DMA_WIDTH_2BYTE 1 +#define BFLB_DMA_WIDTH_WORD 2 +#define BFLB_DMA_WIDTH_2WORD 3 + +#define BFLB_DMA_BURST_1 0 +#define BFLB_DMA_BURST_4 1 +#define BFLB_DMA_BURST_8 2 +#define BFLB_DMA_BURST_16 3 + +#define BFLB_DMA_FLOW_M_M 0 +#define BFLB_DMA_FLOW_M_P 1 +#define BFLB_DMA_FLOW_P_M 2 +#define BFLB_DMA_FLOW_P_P 3 +#define BFLB_DMA_FLOW_SOFT 0 +#define BFLB_DMA_FLOW_PERI 4 + +struct dma_bflb_channel { + dma_callback_t cb; + void *user_data; +}; + +struct dma_bflb_data { + struct dma_bflb_channel channels[BFLB_DMA_CH_NB]; +}; + +struct dma_bflb_config { + uint32_t base_reg; +}; + +static size_t dma_bflb_get_transfer_size(const struct device *dev, uint32_t channel) +{ + const struct dma_bflb_config *cfg = dev->config; + uint32_t control; + size_t size = 1; + uint32_t width; + + control = sys_read32(cfg->base_reg + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + width = (control & DMA_SWIDTH_MASK) >> DMA_SWIDTH_SHIFT; + /* Using SOURCE data width */ + switch (width) { + case BFLB_DMA_WIDTH_BYTE: + break; + case BFLB_DMA_WIDTH_2BYTE: + size *= 2U; + break; + case BFLB_DMA_WIDTH_WORD: + size *= 4U; + break; + case BFLB_DMA_WIDTH_2WORD: + size *= 8U; + break; + default: + return 0; + } + + return size; +} + +static void dma_bflb_isr(const struct device *dev) +{ + const struct dma_bflb_config *cfg = dev->config; + struct dma_bflb_data *data = dev->data; + uint32_t status, error; + + status = sys_read32(cfg->base_reg + DMA_INTTCSTATUS_OFFSET); + error = sys_read32(cfg->base_reg + DMA_INTERRORSTATUS_OFFSET); + + for (uint8_t i = 0; i < BFLB_DMA_CH_NB; i++) { + if (data->channels[i].cb) { + if (error & (1 << i)) { + data->channels[i].cb(dev, data->channels[i].user_data, i, -1); + } else if (status & (1 << i)) { + data->channels[i].cb(dev, data->channels[i].user_data, i, 0); + } + } + } + + sys_write32(error, cfg->base_reg + DMA_INTERRCLR_OFFSET); + sys_write32(status, cfg->base_reg + DMA_INTTCCLEAR_OFFSET); +} + +static int dma_bflb_configure(const struct device *dev, uint32_t channel, + struct dma_config *config) +{ + struct dma_bflb_data *data = dev->data; + const struct dma_bflb_config *cfg = dev->config; + struct dma_block_config *block = config->head_block; + struct dma_bflb_channel *channel_control; + uint32_t ch_config; + uint32_t control = 0; + uint16_t size; + + if (channel >= BFLB_DMA_CH_NB) { + LOG_ERR("Unsupported channel"); + return -EINVAL; + } + + if (config->block_count > 1) { + LOG_ERR("Chained transfers not supported"); + /* TODO: add support for LLI chained transfers. */ + return -ENOTSUP; + } + + if (block->source_addr_adj == 1 || block->dest_addr_adj == 1) { + LOG_ERR("Decrement not supported"); + return -EINVAL; + } + + ch_config = sys_read32(cfg->base_reg + + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + ch_config &= ~DMA_LLICOUNTER_MASK; + + ch_config &= ~DMA_FLOWCNTRL_MASK; + if (config->channel_direction == MEMORY_TO_MEMORY) { + ch_config |= BFLB_DMA_FLOW_M_M << DMA_FLOWCNTRL_SHIFT; + } else if (config->channel_direction == PERIPHERAL_TO_MEMORY) { + ch_config |= BFLB_DMA_FLOW_P_M << DMA_FLOWCNTRL_SHIFT; + } else if (config->channel_direction == MEMORY_TO_PERIPHERAL) { + ch_config |= BFLB_DMA_FLOW_M_P << DMA_FLOWCNTRL_SHIFT; + } else if (config->channel_direction == PERIPHERAL_TO_PERIPHERAL) { + ch_config |= BFLB_DMA_FLOW_P_P << DMA_FLOWCNTRL_SHIFT; + } else { + LOG_ERR("Direction error. %d", config->channel_direction); + return -EINVAL; + } + + /* For memory we write here */ + sys_write32(block->source_address, cfg->base_reg + DMA_CxSRCADDR_OFFSET + + BFLB_DMA_CH_OFFSET(channel)); + sys_write32(block->dest_address, cfg->base_reg + DMA_CxDSTADDR_OFFSET + + BFLB_DMA_CH_OFFSET(channel)); + + /* For peripherals we treat the address as the peripheral ID */ + ch_config &= ~DMA_SRCPERIPHERAL_MASK; + ch_config &= ~DMA_DSTPERIPHERAL_MASK; + ch_config |= (block->source_address << DMA_SRCPERIPHERAL_SHIFT) + & DMA_SRCPERIPHERAL_MASK; + ch_config |= (block->dest_address << DMA_DSTPERIPHERAL_SHIFT) + & DMA_DSTPERIPHERAL_MASK; + + if (!block->source_addr_adj) { + control |= DMA_SI; + } + if (!block->dest_addr_adj) { + control |= DMA_DI; + } + + if (config->source_data_size == 1) { + control |= BFLB_DMA_WIDTH_BYTE << DMA_SWIDTH_SHIFT; + } else if (config->source_data_size == 2) { + control |= BFLB_DMA_WIDTH_2BYTE << DMA_SWIDTH_SHIFT; + } else if (config->source_data_size == 4) { + control |= BFLB_DMA_WIDTH_WORD << DMA_SWIDTH_SHIFT; + } else if (config->source_data_size == 8) { + control |= BFLB_DMA_WIDTH_2WORD << DMA_SWIDTH_SHIFT; + } else { + LOG_ERR("Invalid source data size"); + return -EINVAL; + } + + if (config->dest_data_size == 1) { + control |= BFLB_DMA_WIDTH_BYTE << DMA_DWIDTH_SHIFT; + } else if (config->dest_data_size == 2) { + control |= BFLB_DMA_WIDTH_2BYTE << DMA_DWIDTH_SHIFT; + } else if (config->dest_data_size == 4) { + control |= BFLB_DMA_WIDTH_WORD << DMA_DWIDTH_SHIFT; + } else if (config->dest_data_size == 8) { + control |= BFLB_DMA_WIDTH_2WORD << DMA_DWIDTH_SHIFT; + } else { + LOG_ERR("Invalid destination data size"); + return -EINVAL; + } + + if (config->source_burst_length == 1) { + control |= BFLB_DMA_BURST_1 << DMA_SBSIZE_SHIFT; + } else if (config->source_burst_length == 4) { + control |= BFLB_DMA_BURST_4 << DMA_SBSIZE_SHIFT; + } else if (config->source_burst_length == 8) { + control |= BFLB_DMA_BURST_8 << DMA_SBSIZE_SHIFT; + } else if (config->source_burst_length == 16) { + control |= BFLB_DMA_BURST_16 << DMA_SBSIZE_SHIFT; + } else { + LOG_ERR("Invalid source burst size"); + return -EINVAL; + } + + if (config->dest_burst_length == 1) { + control |= BFLB_DMA_BURST_1 << DMA_DBSIZE_SHIFT; + } else if (config->dest_burst_length == 4) { + control |= BFLB_DMA_BURST_4 << DMA_DBSIZE_SHIFT; + } else if (config->dest_burst_length == 8) { + control |= BFLB_DMA_BURST_8 << DMA_DBSIZE_SHIFT; + } else if (config->dest_burst_length == 16) { + control |= BFLB_DMA_BURST_16 << DMA_DBSIZE_SHIFT; + } else { + LOG_ERR("Invalid destination burst size"); + return -EINVAL; + } + + size = block->block_size / config->dest_data_size; + control |= (size << DMA_TRANSFERSIZE_SHIFT) & DMA_TRANSFERSIZE_MASK; + + /* Clear interrupts */ + sys_write32(1U << channel, cfg->base_reg + DMA_INTERRCLR_OFFSET); + sys_write32(1U << channel, cfg->base_reg + DMA_INTTCCLEAR_OFFSET); + + /* Unmask interrupts */ + ch_config &= ~(DMA_ITC | DMA_IE); + + sys_write32(control, cfg->base_reg + + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + sys_write32(ch_config, cfg->base_reg + + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + channel_control = &data->channels[channel]; + channel_control->cb = config->dma_callback; + channel_control->user_data = config->user_data; + + LOG_DBG("Configured channel %d for %08X to %08X (%u)", + channel, + block->source_address, + block->dest_address, + block->block_size); + + return 0; +} + +static int dma_bflb_start(const struct device *dev, uint32_t channel) +{ + const struct dma_bflb_config *cfg = dev->config; + uint32_t config; + +#ifdef CONFIG_SOC_SERIES_BL61X + /* on BL61x, we must invalidate the output address to update the memory data */ + uint32_t control = sys_read32( + cfg->base_reg + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + size_t pending_length = (control & DMA_TRANSFERSIZE_MASK) >> DMA_TRANSFERSIZE_SHIFT; + uintptr_t addr = sys_read32( + cfg->base_reg + DMA_CxDSTADDR_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + pending_length *= dma_bflb_get_transfer_size(dev, channel); + sys_cache_data_flush_and_invd_range((void *)addr, pending_length); +#endif + + config = sys_read32(cfg->base_reg + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + config |= DMA_E; + sys_write32(config, cfg->base_reg + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + return 0; +} + +static int dma_bflb_stop(const struct device *dev, uint32_t channel) +{ + const struct dma_bflb_config *cfg = dev->config; + uint32_t config; + + config = sys_read32(cfg->base_reg + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + config &= ~DMA_E; + sys_write32(config, cfg->base_reg + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + return 0; +} + +static int dma_bflb_reload(const struct device *dev, uint32_t channel, + uint32_t src, uint32_t dst, size_t size) +{ + const struct dma_bflb_config *cfg = dev->config; + uint32_t control; + size_t sizediv; + + control = sys_read32(cfg->base_reg + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + sizediv = dma_bflb_get_transfer_size(dev, channel); + if (!sizediv) { + return -EINVAL; + } + + sys_write32(src, cfg->base_reg + DMA_CxSRCADDR_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + sys_write32(dst, cfg->base_reg + DMA_CxDSTADDR_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + size /= sizediv; + control &= ~DMA_TRANSFERSIZE_MASK; + control |= (size << DMA_TRANSFERSIZE_SHIFT) & DMA_TRANSFERSIZE_MASK; + sys_write32(control, cfg->base_reg + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + LOG_DBG("Reloaded channel %d for %08X to %08X (%u)", + channel, src, dst, size); + + return 0; +} + +static int dma_bflb_get_status(const struct device *dev, uint32_t channel, + struct dma_status *stat) +{ + const struct dma_bflb_config *cfg = dev->config; + uint32_t config, control, direction; + + if (channel >= BFLB_DMA_CH_NB || stat == NULL) { + return -EINVAL; + } + + config = sys_read32(cfg->base_reg + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + control = sys_read32(cfg->base_reg + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(channel)); + + if (config & DMA_E) { + stat->busy = true; + } else { + stat->busy = false; + } + + stat->pending_length = (control & DMA_TRANSFERSIZE_MASK) >> DMA_TRANSFERSIZE_SHIFT; + stat->pending_length *= dma_bflb_get_transfer_size(dev, channel); + if (!stat->pending_length) { + return -EINVAL; + } + + direction = ((config & DMA_FLOWCNTRL_MASK) >> DMA_FLOWCNTRL_SHIFT) & BFLB_DMA_FLOW_P_P; + switch (direction) { + case BFLB_DMA_FLOW_M_M: + stat->dir = MEMORY_TO_MEMORY; + break; + case BFLB_DMA_FLOW_M_P: + stat->dir = MEMORY_TO_PERIPHERAL; + break; + case BFLB_DMA_FLOW_P_M: + stat->dir = PERIPHERAL_TO_MEMORY; + break; + case BFLB_DMA_FLOW_P_P: + stat->dir = PERIPHERAL_TO_PERIPHERAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dma_bflb_init(const struct device *dev) +{ + const struct dma_bflb_config *cfg = dev->config; + uint32_t tmp; + + /* Ensure DMA clocks are enabled*/ + tmp = sys_read32(BFLB_DMA_CLOCK_ADDR); + tmp |= 0xFF << GLB_DMA_CLK_EN_POS; + sys_write32(tmp, BFLB_DMA_CLOCK_ADDR); + + /* Enable DMA controller */ + tmp = sys_read32(cfg->base_reg + DMA_TOP_CONFIG_OFFSET); + tmp |= DMA_E; + sys_write32(tmp, cfg->base_reg + DMA_TOP_CONFIG_OFFSET); + + /* Ensure all channels are disabled and their interrupts masked */ + for (int i = 0; i < BFLB_DMA_CH_NB; i++) { + tmp = sys_read32(cfg->base_reg + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(i)); + tmp &= ~DMA_E; + tmp |= DMA_ITC | DMA_IE; + sys_write32(tmp, cfg->base_reg + DMA_CxCONFIG_OFFSET + BFLB_DMA_CH_OFFSET(i)); + tmp = sys_read32(cfg->base_reg + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(i)); + tmp &= ~DMA_I; + sys_write32(tmp, cfg->base_reg + DMA_CxCONTROL_OFFSET + BFLB_DMA_CH_OFFSET(i)); + } + + /* Ensure all interrupts are cleared */ + sys_write32(0xFF, cfg->base_reg + DMA_INTERRCLR_OFFSET); + sys_write32(0xFF, cfg->base_reg + DMA_INTTCCLEAR_OFFSET); + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), dma_bflb_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); + + return 0; +} + +static struct dma_bflb_data bflb_dma_data = {0}; +static struct dma_bflb_config bflb_dma_config = { + .base_reg = DT_INST_REG_ADDR(0), +}; + +static DEVICE_API(dma, dma_bflb_api) = { + .config = dma_bflb_configure, + .start = dma_bflb_start, + .stop = dma_bflb_stop, + .reload = dma_bflb_reload, + .get_status = dma_bflb_get_status, +}; + +DEVICE_DT_INST_DEFINE(0, dma_bflb_init, NULL, + &bflb_dma_data, &bflb_dma_config, PRE_KERNEL_1, + CONFIG_DMA_INIT_PRIORITY, &dma_bflb_api); From 54ef5c3bf2fa4a43b38dfe6eee2077bfbbd86e75 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Tue, 26 Aug 2025 23:21:14 +0200 Subject: [PATCH 180/397] drivers: clock_control: Update clock control to support new peripherals Guarantees De-gating the peripherals. Signed-off-by: Camille BAUD --- drivers/clock_control/clock_control_bl60x.c | 4 ++++ drivers/clock_control/clock_control_bl61x.c | 4 ++++ drivers/clock_control/clock_control_bl70x.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/drivers/clock_control/clock_control_bl60x.c b/drivers/clock_control/clock_control_bl60x.c index 1d51cb663d508..64b905c748837 100644 --- a/drivers/clock_control/clock_control_bl60x.c +++ b/drivers/clock_control/clock_control_bl60x.c @@ -650,10 +650,14 @@ static void clock_control_bl60x_peripheral_clock_init(void) /* enable ADC clock routing */ regval |= (1 << 2); + /* enable SEC clock routing */ + regval |= (1 << 3); /* enable UART0 clock routing */ regval |= (1 << 16); /* enable I2C0 clock routing */ regval |= (1 << 19); + /* enable DMA clock routing */ + regval |= (1 << 12); sys_write32(regval, GLB_BASE + GLB_CGEN_CFG1_OFFSET); diff --git a/drivers/clock_control/clock_control_bl61x.c b/drivers/clock_control/clock_control_bl61x.c index f6e7f0b81b76e..034916b820d96 100644 --- a/drivers/clock_control/clock_control_bl61x.c +++ b/drivers/clock_control/clock_control_bl61x.c @@ -1005,6 +1005,8 @@ static void clock_control_bl61x_peripheral_clock_init(void) /* enable ADC clock routing */ regval |= (1 << 2); + /* enable SEC clock routing */ + regval |= (1 << 3); /* enable UART0 clock routing */ regval |= (1 << 16); /* enable UART1 clock routing */ @@ -1017,6 +1019,8 @@ static void clock_control_bl61x_peripheral_clock_init(void) regval |= (1 << 18); /* enable USB clock routing */ regval |= (1 << 13); + /* enable DMA clock routing */ + regval |= (1 << 12); sys_write32(regval, GLB_BASE + GLB_CGEN_CFG1_OFFSET); diff --git a/drivers/clock_control/clock_control_bl70x.c b/drivers/clock_control/clock_control_bl70x.c index 5568bbe5dfd87..898385d5e9fa2 100644 --- a/drivers/clock_control/clock_control_bl70x.c +++ b/drivers/clock_control/clock_control_bl70x.c @@ -530,10 +530,14 @@ static void clock_control_bl70x_peripheral_clock_init(void) /* enable ADC clock routing */ regval |= (1 << 2); + /* enable SEC clock routing */ + regval |= (1 << 3); /* enable UART0 clock routing */ regval |= (1 << 16); /* enable I2C0 clock routing */ regval |= (1 << 19); + /* enable DMA clock routing */ + regval |= (1 << 12); sys_write32(regval, GLB_BASE + GLB_CGEN_CFG1_OFFSET); From 8b417df4d69bcbaf856af0e34d55a5b625c028b6 Mon Sep 17 00:00:00 2001 From: Camille BAUD Date: Fri, 10 Oct 2025 20:23:09 +0200 Subject: [PATCH 181/397] boards: Add DMA to supported for bflb boards Adds the dma to supported for testing Signed-off-by: Camille BAUD --- boards/aithinker/ai_m62_12f/ai_m62_12f.yaml | 1 + boards/aithinker/ai_wb2_12f/ai_wb2_12f.yaml | 1 + boards/bflb/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml | 1 + boards/doiting/dt_bl10_devkit/dt_bl10_devkit.yaml | 1 + boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml | 1 + 5 files changed, 5 insertions(+) diff --git a/boards/aithinker/ai_m62_12f/ai_m62_12f.yaml b/boards/aithinker/ai_m62_12f/ai_m62_12f.yaml index 7d242d4766461..3b7748f228f9b 100644 --- a/boards/aithinker/ai_m62_12f/ai_m62_12f.yaml +++ b/boards/aithinker/ai_m62_12f/ai_m62_12f.yaml @@ -17,4 +17,5 @@ supported: - gpio - pinctrl - uart + - dma vendor: bflb diff --git a/boards/aithinker/ai_wb2_12f/ai_wb2_12f.yaml b/boards/aithinker/ai_wb2_12f/ai_wb2_12f.yaml index e9dc0bc4f68a4..82bf92b4bcedc 100644 --- a/boards/aithinker/ai_wb2_12f/ai_wb2_12f.yaml +++ b/boards/aithinker/ai_wb2_12f/ai_wb2_12f.yaml @@ -17,4 +17,5 @@ supported: - gpio - pinctrl - uart + - dma vendor: bflb diff --git a/boards/bflb/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml b/boards/bflb/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml index 1400cf1c4881b..4547744c446a1 100644 --- a/boards/bflb/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml +++ b/boards/bflb/bl60x/bl604e_iot_dvk/bl604e_iot_dvk.yaml @@ -17,4 +17,5 @@ supported: - gpio - pinctrl - uart + - dma vendor: bflb diff --git a/boards/doiting/dt_bl10_devkit/dt_bl10_devkit.yaml b/boards/doiting/dt_bl10_devkit/dt_bl10_devkit.yaml index 79ee2e8c1f734..0b3b645a5afd8 100644 --- a/boards/doiting/dt_bl10_devkit/dt_bl10_devkit.yaml +++ b/boards/doiting/dt_bl10_devkit/dt_bl10_devkit.yaml @@ -16,4 +16,5 @@ supported: - gpio - pinctrl - uart + - dma vendor: doiting diff --git a/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml index 40f8b0f81b3c9..6c2b9bb6fcf15 100644 --- a/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml +++ b/boards/doiting/dt_xt_zb1_devkit/dt_xt_zb1_devkit.yaml @@ -16,4 +16,5 @@ supported: - gpio - pinctrl - uart + - dma vendor: doiting From 8b3bb467eed9c8040818f15a15381829a663eb18 Mon Sep 17 00:00:00 2001 From: Henrik Grunmach Date: Fri, 12 Sep 2025 14:14:55 +0200 Subject: [PATCH 182/397] dts: soc: nxp lpc55xxx: Add SWO support Add ITM to common device tree and set the correct clock config when using SWO as a logging backend Signed-off-by: Henrik Grunmach --- dts/arm/nxp/nxp_lpc55S2x_common.dtsi | 5 +++++ soc/nxp/lpc/lpc55xxx/Kconfig | 1 + soc/nxp/lpc/lpc55xxx/soc.c | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index 3ad260e4b5d55..1889513eed11e 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -38,6 +38,11 @@ compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; }; + + itm: itm@e0000000 { + compatible = "arm,armv8m-itm"; + reg = <0xe0000000 0x1000>; + }; }; }; }; diff --git a/soc/nxp/lpc/lpc55xxx/Kconfig b/soc/nxp/lpc/lpc55xxx/Kconfig index 3d92329c0b346..5e4124f5e6418 100644 --- a/soc/nxp/lpc/lpc55xxx/Kconfig +++ b/soc/nxp/lpc/lpc55xxx/Kconfig @@ -3,6 +3,7 @@ config SOC_SERIES_LPC55XXX select HAS_MCUX + select HAS_SWO select CPU_CORTEX_M_HAS_SYSTICK select CPU_CORTEX_M_HAS_DWT select SOC_RESET_HOOK diff --git a/soc/nxp/lpc/lpc55xxx/soc.c b/soc/nxp/lpc/lpc55xxx/soc.c index 235aeb96bc21c..648dc45c7f070 100644 --- a/soc/nxp/lpc/lpc55xxx/soc.c +++ b/soc/nxp/lpc/lpc55xxx/soc.c @@ -433,6 +433,12 @@ DT_FOREACH_STATUS_OKAY(nxp_ctimer_pwm, CTIMER_CLOCK_SETUP) #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(opamp2)) POWER_DisablePD(kPDRUNCFG_PD_OPAMP2); #endif + +#ifdef CONFIG_LOG_BACKEND_SWO + CLOCK_AttachClk(kTRACE_DIV_to_TRACE); + CLOCK_SetClkDiv(kCLOCK_DivArmTrClkDiv, 1U, true); +#endif + } /** From 6fbbe490b4769b687c43681dc97aa4635d9eb7ab Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Tue, 30 Sep 2025 16:48:16 +0700 Subject: [PATCH 183/397] hal: renesas: manifest: Update commit id for hal_renesas Update commit id for hal_renesas to support Flash driver for Renesas RZ/A, T, N series Signed-off-by: Tien Nguyen --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index cb6a50b6c6d1a..4ca483350b2ff 100644 --- a/west.yml +++ b/west.yml @@ -226,7 +226,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: 5ab2c84af5cbdbc2b1f0a41e08b8f311bd4eafa8 + revision: 3ce2bdc7f5cb19b961c015ba561b0cf15f7df3b4 groups: - hal - name: hal_rpi_pico From 44be35a5d3485c27b24f98084462de30a80252be Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 09:44:30 +0700 Subject: [PATCH 184/397] driver: flash: initial support for Renesas RZ/A3UL, T2M, N2L This driver is based on the XSPI driver for Renesas RZ/T2M and N2L, and the SPIBSC driver for Renesas RZ/A3UL from the HAL. Signed-off-by: Tien Nguyen --- drivers/flash/CMakeLists.txt | 2 + drivers/flash/Kconfig | 1 + drivers/flash/Kconfig.renesas_rz_qspi | 37 ++ drivers/flash/flash_renesas_rz_qspi.c | 612 ++++++++++++++++++ .../renesas,rz-qspi-spibsc.yaml | 36 ++ .../renesas,rz-qspi-xspi.yaml | 36 ++ dts/bindings/qspi/renesas,rz-spibsc.yaml | 14 + dts/bindings/qspi/renesas,rz-xspi.yaml | 20 + modules/Kconfig.renesas | 10 + 9 files changed, 768 insertions(+) create mode 100644 drivers/flash/Kconfig.renesas_rz_qspi create mode 100644 drivers/flash/flash_renesas_rz_qspi.c create mode 100644 dts/bindings/flash_controller/renesas,rz-qspi-spibsc.yaml create mode 100644 dts/bindings/flash_controller/renesas,rz-qspi-xspi.yaml create mode 100644 dts/bindings/qspi/renesas,rz-spibsc.yaml create mode 100644 dts/bindings/qspi/renesas,rz-xspi.yaml diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index b7352f2458360..3ed0fdaf9879f 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -42,6 +42,8 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_RENESAS_RA_OSPI_B flash_renesas_ra_ospi_b.c) zephyr_library_sources_ifdef(CONFIG_FLASH_RENESAS_RA_QSPI flash_renesas_ra_qspi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_RENESAS_RZ_QSPI_SPIBSC flash_renesas_rz_qspi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI flash_renesas_rz_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_RPI_PICO flash_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_FLASH_SF32LB_MPI_QSPI_NOR flash_sf32lb_mpi_qspi_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_OSPI flash_stm32_ospi.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 04740b078905c..f563bf703aafe 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -198,6 +198,7 @@ source "drivers/flash/Kconfig.renesas_ra" source "drivers/flash/Kconfig.renesas_ra_ospi" source "drivers/flash/Kconfig.renesas_ra_qspi" source "drivers/flash/Kconfig.renesas_rx" +source "drivers/flash/Kconfig.renesas_rz_qspi" source "drivers/flash/Kconfig.rpi_pico" source "drivers/flash/Kconfig.rts5912" source "drivers/flash/Kconfig.rv32m1" diff --git a/drivers/flash/Kconfig.renesas_rz_qspi b/drivers/flash/Kconfig.renesas_rz_qspi new file mode 100644 index 0000000000000..ae9ca41297540 --- /dev/null +++ b/drivers/flash/Kconfig.renesas_rz_qspi @@ -0,0 +1,37 @@ +# Renesas RZ Family + +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config FLASH_RENESAS_RZ_QSPI_XSPI + bool "Renesas RZ Quad-SPI XSPI driver" + default y + depends on DT_HAS_RENESAS_RZ_QSPI_XSPI_ENABLED + select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_EXPLICIT_ERASE + select USE_RZ_FSP_QSPI_XSPI + select FLASH_JESD216 + select PINCTRL + help + Enable Quad-SPI XSPI Nor flash driver for RZ series + +config FLASH_RENESAS_RZ_QSPI_SPIBSC + bool "Renesas RZ Quad-SPI SPIBSC driver" + default y + depends on DT_HAS_RENESAS_RZ_QSPI_SPIBSC_ENABLED + select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_EXPLICIT_ERASE + select USE_RZ_FSP_QSPI_SPIBSC + select FLASH_JESD216 + select PINCTRL + help + Enable Quad-SPI SPIBSC Nor flash driver for RZ series + +config FLASH_RENESAS_RZ_MIRROR_OFFSET + hex + default 0x0 if SOC_SERIES_RZA3UL + default 0x20000000 if SOC_SERIES_RZT2M || SOC_SERIES_RZN2L + help + Offset of mirror area in flash memory diff --git a/drivers/flash/flash_renesas_rz_qspi.c b/drivers/flash/flash_renesas_rz_qspi.c new file mode 100644 index 0000000000000..5c744b499263e --- /dev/null +++ b/drivers/flash/flash_renesas_rz_qspi.c @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "spi_nor.h" +#include "r_spi_flash_api.h" + +#if defined(CONFIG_FLASH_RENESAS_RZ_QSPI_SPIBSC) +#include "r_spibsc.h" +#else +#include "r_xspi_qspi.h" +#endif + +LOG_MODULE_REGISTER(renesas_rz_qspi, CONFIG_FLASH_LOG_LEVEL); + +#if defined(CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI) +#define QSPI_DEFAULT_SR (0x40) +#define QSPI_UPDATE_CR (0xC0) /* Configuration register (DC0=1, DC1=1 (Dummy cycle = 10)) */ +#define QSPI_DATA_CR_UPDATE (QSPI_UPDATE_CR << 8 | QSPI_DEFAULT_SR) +#endif /* CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI */ + +#define FLASH_RZ_BASE_ADDRESS (CONFIG_FLASH_BASE_ADDRESS - CONFIG_FLASH_RENESAS_RZ_MIRROR_OFFSET) + +/* QSPI COMMANDS */ +#define QSPI_CMD_RDSFDP (0x5A) /* Read SFDP */ + +/* XIP (Execute In Place) mode */ +#define QSPI_CMD_XIP_ENTER (0xA5) /* XIP Enter command */ +#define QSPI_CMD_XIP_EXIT (0xFF) /* XIP Exit command */ + +#define QSPI_CMD_QUAD_PAGE_PROGRAM (0x33) + +/* One byte data transfer */ +#define DATA_LENGTH_DEFAULT_BYTE (0U) +#define ONE_BYTE (1U) +#define TWO_BYTE (2U) +#define THREE_BYTE (3U) +#define FOUR_BYTE (4U) + +/* Default erase value */ +#define QSPI_ERASE_VALUE (0xFF) + +/* Maximum memory buffer size of write operation in memory-map mode */ +#if defined(CONFIG_FLASH_RENESAS_RZ_QSPI_SPIBSC) +#define QSPI_MAX_BUFFER_SIZE 256U +#else +#define QSPI_MAX_BUFFER_SIZE 64U +#endif + +struct flash_renesas_rz_data { + spi_flash_ctrl_t *fsp_ctrl; + spi_flash_cfg_t *fsp_cfg; + + struct k_sem sem; +}; + +struct flash_renesas_rz_config { + const struct pinctrl_dev_config *pin_cfg; + const spi_flash_api_t *fsp_api; + + uint32_t erase_block_size; + uint32_t flash_size; + struct flash_parameters flash_param; +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + struct flash_pages_layout layout; +#endif +}; + +static const spi_flash_erase_command_t g_erase_command_list[4] = { + {.command = SPI_NOR_CMD_SE, .size = SPI_NOR_SECTOR_SIZE}, + {.command = SPI_NOR_CMD_BE_32K, .size = SPI_NOR_BLOCK_32K_SIZE}, + {.command = SPI_NOR_CMD_BE, .size = SPI_NOR_BLOCK_SIZE}, + {.command = SPI_NOR_CMD_CE, .size = SPI_FLASH_ERASE_SIZE_CHIP_ERASE}, +}; + +static void acquire_device(const struct device *dev) +{ + struct flash_renesas_rz_data *dev_data = dev->data; + + k_sem_take(&dev_data->sem, K_FOREVER); +} + +static void release_device(const struct device *dev) +{ + struct flash_renesas_rz_data *dev_data = dev->data; + + k_sem_give(&dev_data->sem); +} + +static int qspi_wait_until_ready(const struct device *dev) +{ + const struct flash_renesas_rz_config *config = dev->config; + struct flash_renesas_rz_data *data = dev->data; + spi_flash_status_t status = {.write_in_progress = true}; + uint32_t timeout = 0xFFFFFF; + fsp_err_t err; + + while ((status.write_in_progress) && (timeout > 0)) { + err = config->fsp_api->statusGet(data->fsp_ctrl, &status); + if (err != FSP_SUCCESS) { + LOG_ERR("Status get failed"); + return -EIO; + } + timeout--; + } + + return 0; +} + +#if CONFIG_FLASH_PAGE_LAYOUT +void flash_renesas_rz_page_layout(const struct device *dev, + const struct flash_pages_layout **layout, size_t *layout_size) +{ + const struct flash_renesas_rz_config *config = dev->config; + + *layout = &config->layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +#if defined(CONFIG_FLASH_JESD216_API) +static int qspi_flash_rz_read_jedec_id(const struct device *dev, uint8_t *id) +{ + const struct flash_renesas_rz_config *config = dev->config; + struct flash_renesas_rz_data *data = dev->data; + int ret = 0; + + if (id == NULL) { + return -EINVAL; + } + + spi_flash_direct_transfer_t trans = { + .command = SPI_NOR_CMD_RDID, + .address = 0, + .data = 0, + .command_length = 1U, + .address_length = 0U, + .data_length = THREE_BYTE, + .dummy_cycles = 0U, + }; + + acquire_device(dev); + ret = config->fsp_api->directTransfer(data->fsp_ctrl, &trans, + SPI_FLASH_DIRECT_TRANSFER_DIR_READ); + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("Failed to read device id"); + release_device(dev); + return -EIO; + } + + /* Get flash device ID */ + memcpy(id, &trans.data, sizeof(trans.data)); + release_device(dev); + + return ret; +} + +static int qspi_flash_renesas_rz_sfdp_read(const struct device *dev, off_t addr, void *data, + size_t len) +{ + const struct flash_renesas_rz_config *config = dev->config; + struct flash_renesas_rz_data *dev_data = dev->data; + int ret = 0; + size_t size; + + spi_flash_direct_transfer_t trans = { + .command = QSPI_CMD_RDSFDP, + .address = addr, + .data = 0, + .command_length = 1U, + .address_length = 3U, + .data_length = FOUR_BYTE, + .dummy_cycles = SPI_NOR_DUMMY_RD, + }; + + acquire_device(dev); + while (len > 0) { + size = MIN(len, trans.data_length); + trans.address = addr; + trans.data_length = size; + + ret = config->fsp_api->directTransfer(dev_data->fsp_ctrl, &trans, + SPI_FLASH_DIRECT_TRANSFER_DIR_READ); + + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("Failed to read SFDP id"); + release_device(dev); + return -EIO; + } + + memcpy(data, &trans.data, size); + + len -= size; + addr += size; + data = (uint8_t *)data + size; + } + + release_device(dev); + return ret; +} +#endif + +static bool qspi_flash_rz_valid(uint32_t area_size, off_t offset, size_t len) +{ + if ((offset < 0) || (offset >= area_size) || ((area_size - offset) < len)) { + return false; + } + + return true; +} + +static int qspi_flash_rz_erase(const struct device *dev, off_t offset, size_t len) +{ + const struct flash_renesas_rz_config *config = dev->config; + struct flash_renesas_rz_data *data = dev->data; + int err = 0; + struct flash_pages_info page_info_start, page_info_end; + uint32_t erase_size; + int rc; + + if (!len) { + return 0; + } + + if (!qspi_flash_rz_valid(config->flash_size, offset, len)) { + LOG_ERR("The offset 0x%lx is invalid", (long)offset); + return -EINVAL; + } + + if (0 != (len % config->erase_block_size)) { + LOG_ERR("The size %zu is not align with block size (%u)", len, + config->erase_block_size); + return -EINVAL; + } + + rc = flash_get_page_info_by_offs(dev, offset, &page_info_start); + if ((rc != 0) || (offset != page_info_start.start_offset)) { + LOG_ERR("The offset 0x%lx is not aligned with the starting sector", (long)offset); + return -EINVAL; + } + + rc = flash_get_page_info_by_offs(dev, (offset + len), &page_info_end); + if ((rc != 0) || ((offset + len) != page_info_end.start_offset)) { + LOG_ERR("The size %zu is not aligned with the ending sector", len); + return -EINVAL; + } + + acquire_device(dev); + while (len > 0) { + if (len < SPI_NOR_BLOCK_32K_SIZE) { + erase_size = SPI_NOR_SECTOR_SIZE; + } else if (len < SPI_NOR_BLOCK_SIZE) { + erase_size = SPI_NOR_BLOCK_32K_SIZE; + } else { + erase_size = SPI_NOR_BLOCK_SIZE; + } + + uint8_t *dest = (uint8_t *)FLASH_RZ_BASE_ADDRESS; + + dest += (size_t)offset; + err = config->fsp_api->erase(data->fsp_ctrl, dest, erase_size); + if (FSP_SUCCESS != (fsp_err_t)err) { + LOG_ERR("Erase failed"); + err = -EIO; + break; + } + + err = qspi_wait_until_ready(dev); + if (err) { + LOG_ERR("Failed to get status for QSPI operation"); + err = -EIO; + break; + } + + offset += erase_size; + len -= erase_size; + +#if defined(CONFIG_FLASH_RENESAS_RZ_QSPI_SPIBSC) + spibsc_instance_ctrl_t *p_ctrl = (spibsc_instance_ctrl_t *)data->fsp_ctrl; + + /* Invalidating SPIBSC cache */ + p_ctrl->p_reg->DRCR_b.RCF = 1; + sys_cache_data_invd_range((void *)dest, erase_size); +#endif + } + release_device(dev); + + return err; +} + +static int qspi_flash_rz_read(const struct device *dev, off_t offset, void *data, size_t len) +{ + const struct flash_renesas_rz_config *config = dev->config; + + if (!len) { + return 0; + } + + if (!data) { + return -EINVAL; + } + + if (!qspi_flash_rz_valid(config->flash_size, offset, len)) { + return -EINVAL; + } + + acquire_device(dev); + + uint8_t *dest = (uint8_t *)FLASH_RZ_BASE_ADDRESS; + + dest += (size_t)offset; + memcpy(data, dest, len); + release_device(dev); + + return 0; +} + +static int qspi_flash_rz_write(const struct device *dev, off_t offset, const void *data, size_t len) +{ + const struct flash_renesas_rz_config *config = dev->config; + struct flash_renesas_rz_data *dev_data = dev->data; + int err = 0; + uint32_t remaining_bytes = len; + uint32_t size = (uint32_t)len; + + if (!len) { + return 0; + } + + if (!data) { + return -EINVAL; + } + + if (!qspi_flash_rz_valid(config->flash_size, offset, len)) { + return -EINVAL; + } + + acquire_device(dev); + while (remaining_bytes > 0) { + size = MIN(remaining_bytes, QSPI_MAX_BUFFER_SIZE); + uint8_t *dest = (uint8_t *)FLASH_RZ_BASE_ADDRESS; + + dest += (size_t)offset; + err = config->fsp_api->write(dev_data->fsp_ctrl, (const uint8_t *)data, dest, size); + if (FSP_SUCCESS != (fsp_err_t)err) { + LOG_ERR("Flash write failed"); + err = -EIO; + break; + } + + err = qspi_wait_until_ready(dev); + if (err) { + LOG_ERR("Failed to get status for QSPI operation"); + err = -EIO; + break; + } + + remaining_bytes -= size; + offset += size; + data = (const uint8_t *)data + size; + +#if defined(CONFIG_FLASH_RENESAS_RZ_QSPI_SPIBSC) + spibsc_instance_ctrl_t *p_ctrl = (spibsc_instance_ctrl_t *)dev_data->fsp_ctrl; + + /* Invalidating SPIBSC cache */ + p_ctrl->p_reg->DRCR_b.RCF = 1; + sys_cache_data_invd_range((void *)dest, size); +#endif + } + release_device(dev); + return err; +} + +static int qspi_flash_rz_get_size(const struct device *dev, uint64_t *size) +{ + const struct flash_renesas_rz_config *config = dev->config; + + *size = (uint64_t)config->flash_size; + + return 0; +} + +static const struct flash_parameters *qspi_flash_rz_get_parameters(const struct device *dev) +{ + const struct flash_renesas_rz_config *config = dev->config; + + return &config->flash_param; +} + +#if CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI +static int spi_flash_direct_write(const struct device *dev, uint8_t command, uint32_t tx_data, + uint8_t data_length) +{ + const struct flash_renesas_rz_config *config = dev->config; + struct flash_renesas_rz_data *data = dev->data; + int ret; + + spi_flash_direct_transfer_t trans = { + .command = command, + .address = 0U, + .data = tx_data, + .command_length = 1U, + .address_length = 0U, + .data_length = data_length, + .dummy_cycles = 0U, + }; + + ret = config->fsp_api->directTransfer(data->fsp_ctrl, &trans, + SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("Failed to write command"); + return -EIO; + }; + + return ret; +} +#endif + +static int flash_renesas_rz_init(const struct device *dev) +{ + const struct flash_renesas_rz_config *config = dev->config; + struct flash_renesas_rz_data *data = dev->data; + int ret = 0; + +#if CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI + ret = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT); + if (ret) { + LOG_ERR("Failed to configure pins for QSPI with code: %d", ret); + return -EIO; + } +#endif + k_sem_init(&data->sem, 1, 1); + + ret = config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg); + if (FSP_SUCCESS != (fsp_err_t)ret) { + LOG_ERR("Open failed"); + return -EIO; + } + +#if CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI + /* Write Enable Command */ + ret = spi_flash_direct_write(dev, data->fsp_cfg->write_enable_command, 0U, + DATA_LENGTH_DEFAULT_BYTE); + if (ret) { + return ret; + } + + /* Write Status Command */ + ret = spi_flash_direct_write(dev, SPI_NOR_CMD_WRSR, QSPI_DATA_CR_UPDATE, TWO_BYTE); + if (ret) { + return ret; + } +#endif + return ret; +} + +static DEVICE_API(flash, flash_renesas_rz_qspi_driver_api) = { + .erase = qspi_flash_rz_erase, + .write = qspi_flash_rz_write, + .read = qspi_flash_rz_read, + .get_parameters = qspi_flash_rz_get_parameters, + .get_size = qspi_flash_rz_get_size, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_renesas_rz_page_layout, +#endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = qspi_flash_renesas_rz_sfdp_read, + .read_jedec_id = qspi_flash_rz_read_jedec_id, +#endif +}; + +#define DT_DRV_COMPAT renesas_rz_qspi_xspi + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +#define FLASH_RENESAS_RZ_QSPI_XSPI_DEFINE(n) \ + PINCTRL_DT_DEFINE(DT_INST_PARENT(n)); \ + static xspi_qspi_timing_setting_t g_qspi##n##_timing_settings = { \ + .command_to_command_interval = XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_2, \ + .cs_pullup_lag = XSPI_QSPI_CS_PULLUP_CLOCKS_1, \ + .cs_pulldown_lead = XSPI_QSPI_CS_PULLDOWN_CLOCKS_1}; \ + static xspi_qspi_address_space_t g_qspi##n##_address_space_settings = { \ + .unit0_cs0_end_address = XSPI_QSPI_CFG_UNIT_0_CS_0_END_ADDRESS, \ + .unit0_cs1_start_address = XSPI_QSPI_CFG_UNIT_0_CS_1_START_ADDRESS, \ + .unit0_cs1_end_address = XSPI_QSPI_CFG_UNIT_0_CS_1_END_ADDRESS, \ + .unit1_cs0_end_address = XSPI_QSPI_CFG_UNIT_1_CS_0_END_ADDRESS, \ + .unit1_cs1_start_address = XSPI_QSPI_CFG_UNIT_1_CS_1_START_ADDRESS, \ + .unit1_cs1_end_address = XSPI_QSPI_CFG_UNIT_1_CS_1_END_ADDRESS, \ + }; \ + static const xspi_qspi_extended_cfg_t g_qspi##n##_extended_cfg = { \ + .unit = n, \ + .chip_select = XSPI_QSPI_CHIP_SELECT_##n, \ + .memory_size = XSPI_QSPI_MEMORY_SIZE_64MB, \ + .p_timing_settings = &g_qspi##n##_timing_settings, \ + .prefetch_en = \ + (xspi_qspi_prefetch_function_t)XSPI_QSPI_CFG_UNIT_##n##_PREFETCH_FUNCTION, \ + .p_address_space = &g_qspi##n##_address_space_settings, \ + }; \ + static spi_flash_cfg_t g_qspi##n##_cfg = { \ + .spi_protocol = SPI_FLASH_PROTOCOL_1S_1S_1S, \ + .read_mode = SPI_FLASH_READ_MODE_FAST_READ, \ + .address_bytes = SPI_FLASH_ADDRESS_BYTES_3, \ + .dummy_clocks = SPI_FLASH_DUMMY_CLOCKS_10, \ + .read_command = SPI_NOR_CMD_READ_FAST, \ + .page_program_command = SPI_NOR_CMD_PP, \ + .page_program_address_lines = SPI_FLASH_DATA_LINES_4, \ + .page_size_bytes = SPI_NOR_PAGE_SIZE, \ + .write_enable_command = SPI_NOR_CMD_WREN, \ + .status_command = SPI_NOR_CMD_RDSR, \ + .write_status_bit = 0, \ + .xip_enter_command = QSPI_CMD_XIP_ENTER, \ + .xip_exit_command = QSPI_CMD_XIP_EXIT, \ + .p_erase_command_list = &g_erase_command_list[0], \ + .erase_command_list_length = ARRAY_SIZE(g_erase_command_list), \ + .p_extend = &g_qspi##n##_extended_cfg, \ + }; \ + static xspi_qspi_instance_ctrl_t g_qspi##n##_ctrl; \ + static struct flash_renesas_rz_data flash_renesas_rz_data_##n = { \ + .fsp_ctrl = &g_qspi##n##_ctrl, \ + .fsp_cfg = &g_qspi##n##_cfg, \ + }; \ + static const struct flash_renesas_rz_config flash_renesas_rz_config_##n = { \ + .pin_cfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(n)), \ + .fsp_api = &g_spi_flash_on_xspi_qspi, \ + .flash_size = DT_INST_REG_SIZE(n), \ + .erase_block_size = DT_INST_PROP_OR(n, erase_block_size, 4096), \ + .flash_param = \ + { \ + .write_block_size = DT_INST_PROP(n, write_block_size), \ + .erase_value = QSPI_ERASE_VALUE, \ + }, \ + IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, \ + (.layout = { \ + .pages_count = \ + DT_INST_REG_SIZE(n) / DT_INST_PROP_OR(n, erase_block_size, 4096), \ + .pages_size = DT_INST_PROP_OR(n, erase_block_size, 4096), \ + },))}; \ + DEVICE_DT_INST_DEFINE(n, flash_renesas_rz_init, NULL, &flash_renesas_rz_data_##n, \ + &flash_renesas_rz_config_##n, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_renesas_rz_qspi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(FLASH_RENESAS_RZ_QSPI_XSPI_DEFINE) +#endif + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT renesas_rz_qspi_spibsc + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +#define FLASH_RENESAS_RZ_QSPI_SPIBSC_DEFINE(n) \ + static const spibsc_extended_cfg_t g_qspi##n##_extended_cfg = { \ + .delay = \ + { \ + .slch = 0, \ + .clsh = 0, \ + .shsl = 6, \ + }, \ + .io_fix_mask = (0u << 2) | (1u << 3), \ + .io_fix_value = (1u << 2) | (1u << 3), \ + }; \ + static spi_flash_cfg_t g_qspi##n##_cfg = { \ + .spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI, \ + .read_mode = SPI_FLASH_READ_MODE_FAST_READ_QUAD_IO, \ + .address_bytes = SPI_FLASH_ADDRESS_BYTES_3, \ + .dummy_clocks = SPI_FLASH_DUMMY_CLOCKS_DEFAULT, \ + .read_command = SPI_NOR_CMD_4READ, \ + .page_program_command = QSPI_CMD_QUAD_PAGE_PROGRAM, \ + .page_program_address_lines = SPI_FLASH_DATA_LINES_4, \ + .page_size_bytes = SPI_NOR_PAGE_SIZE, \ + .write_enable_command = SPI_NOR_CMD_WREN, \ + .status_command = SPI_NOR_CMD_RDSR, \ + .write_status_bit = 0, \ + .xip_enter_command = QSPI_CMD_XIP_ENTER, \ + .xip_exit_command = QSPI_CMD_XIP_EXIT, \ + .p_erase_command_list = &g_erase_command_list[0], \ + .erase_command_list_length = ARRAY_SIZE(g_erase_command_list), \ + .p_extend = &g_qspi##n##_extended_cfg, \ + }; \ + static spibsc_instance_ctrl_t g_qspi##n##_ctrl; \ + static struct flash_renesas_rz_data flash_renesas_rz_data_##n = { \ + .fsp_ctrl = &g_qspi##n##_ctrl, \ + .fsp_cfg = &g_qspi##n##_cfg, \ + }; \ + static const struct flash_renesas_rz_config flash_renesas_rz_config_##n = { \ + .pin_cfg = NULL, \ + .fsp_api = &g_spi_flash_on_spibsc, \ + .flash_size = DT_INST_REG_SIZE(n), \ + .erase_block_size = DT_INST_PROP_OR(n, erase_block_size, 4096), \ + .flash_param = \ + { \ + .write_block_size = DT_INST_PROP(n, write_block_size), \ + .erase_value = QSPI_ERASE_VALUE, \ + }, \ + IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, \ + (.layout = { \ + .pages_count = \ + DT_INST_REG_SIZE(n) / DT_INST_PROP_OR(n, erase_block_size, 4096), \ + .pages_size = DT_INST_PROP_OR(n, erase_block_size, 4096), \ + },))}; \ + DEVICE_DT_INST_DEFINE(n, flash_renesas_rz_init, NULL, &flash_renesas_rz_data_##n, \ + &flash_renesas_rz_config_##n, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_renesas_rz_qspi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(FLASH_RENESAS_RZ_QSPI_SPIBSC_DEFINE) +#endif diff --git a/dts/bindings/flash_controller/renesas,rz-qspi-spibsc.yaml b/dts/bindings/flash_controller/renesas,rz-qspi-spibsc.yaml new file mode 100644 index 0000000000000..2c20187b4bacc --- /dev/null +++ b/dts/bindings/flash_controller/renesas,rz-qspi-spibsc.yaml @@ -0,0 +1,36 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + Renesas RZ SPIBSC NOR FLASH supporting the JEDEC CFI interface + + Representation of a serial flash on a quadspi bus: + + at25ql128a: qspi-nor-flash@20000000 { + compatible = "renesas,rz-qspi-spibsc"; + reg = <0x20000000 DT_SIZE_M(16)>; /* 128 Mbits */ + write-block-size = <1>; + erase-block-size = <4096>; + status = "okay"; + }; + +compatible: "renesas,rz-qspi-spibsc" + +include: ["flash-controller.yaml", "jedec,jesd216.yaml"] + +on-bus: qspi + +properties: + reg: + required: true + description: Flash Memory base address and size in bytes + + erase-block-size: + type: int + default: 4096 + description: Address alignment required by flash erase operations + + write-block-size: + type: int + default: 1 + description: Address alignment required by flash write operations diff --git a/dts/bindings/flash_controller/renesas,rz-qspi-xspi.yaml b/dts/bindings/flash_controller/renesas,rz-qspi-xspi.yaml new file mode 100644 index 0000000000000..6cc10e282a843 --- /dev/null +++ b/dts/bindings/flash_controller/renesas,rz-qspi-xspi.yaml @@ -0,0 +1,36 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + Renesas RZ XSPI NOR FLASH supporting the JEDEC CFI interface + + Representation of a serial flash on a quadspi bus: + + mx25u51245g: qspi-nor-flash@60000000 { + compatible = "renesas,rz-qspi-xspi"; + reg = <0x60000000 DT_SIZE_M(64)>; /* 512 Mbits */ + write-block-size = <1>; + erase-block-size = <4096>; + status = "okay"; + }; + +compatible: "renesas,rz-qspi-xspi" + +include: ["flash-controller.yaml", "jedec,jesd216.yaml"] + +on-bus: qspi + +properties: + reg: + required: true + description: Flash Memory base address and size in bytes + + erase-block-size: + type: int + default: 4096 + description: Address alignment required by flash erase operations + + write-block-size: + type: int + default: 1 + description: Address alignment required by flash write operations diff --git a/dts/bindings/qspi/renesas,rz-spibsc.yaml b/dts/bindings/qspi/renesas,rz-spibsc.yaml new file mode 100644 index 0000000000000..c3053a0fa9874 --- /dev/null +++ b/dts/bindings/qspi/renesas,rz-spibsc.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RZ SPIBSC + +compatible: "renesas,rz-spibsc" + +include: [base.yaml, pinctrl-device.yaml] + +bus: qspi + +properties: + reg: + required: true diff --git a/dts/bindings/qspi/renesas,rz-xspi.yaml b/dts/bindings/qspi/renesas,rz-xspi.yaml new file mode 100644 index 0000000000000..27f7e6d9e8acf --- /dev/null +++ b/dts/bindings/qspi/renesas,rz-xspi.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RZ XSPI + +compatible: "renesas,rz-xspi" + +include: [base.yaml, pinctrl-device.yaml] + +bus: qspi + +properties: + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index 90ddd3a8d5b20..cfca82cb3e1f6 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -352,6 +352,16 @@ config USE_RZ_FSP_WDT help Enable RZ FSP WDT driver +config USE_RZ_FSP_QSPI_XSPI + bool + help + Enable RZ FSP QSPI XSPI driver + +config USE_RZ_FSP_QSPI_SPIBSC + bool + help + Enable RZ FSP QSPI SPIBSC driver + endif config HAS_RENESAS_RX_RDP From 74092ec128ea4faa18744799c08878a19d870e27 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 09:57:00 +0700 Subject: [PATCH 185/397] dts: renesas: Add flash support for RZ/A3UL, N2L, T2M Add SPIBSC node for RZ/A3UL Add XSPI node for RZ/T2M, N2L Signed-off-by: Tien Nguyen --- dts/arm/renesas/rz/rzn/r9a07g084.dtsi | 20 ++++++++++++++++++++ dts/arm/renesas/rz/rzt/r9a07g075.dtsi | 21 +++++++++++++++++++++ dts/arm64/renesas/rz/rza/r9a07g063.dtsi | 9 +++++++++ 3 files changed, 50 insertions(+) diff --git a/dts/arm/renesas/rz/rzn/r9a07g084.dtsi b/dts/arm/renesas/rz/rzn/r9a07g084.dtsi index 10fd7985a5036..438dc16b3935d 100644 --- a/dts/arm/renesas/rz/rzn/r9a07g084.dtsi +++ b/dts/arm/renesas/rz/rzn/r9a07g084.dtsi @@ -1266,5 +1266,25 @@ interrupts = ; status = "disabled"; }; + + xspi0: xspi@80220000 { + compatible = "renesas,rz-xspi"; + reg = <0x80220000 0x1000>; + interrupts = , + ; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + + xspi1: xspi@80221000 { + compatible = "renesas,rz-xspi"; + reg = <0x80221000 0x1000>; + interrupts = , + ; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/renesas/rz/rzt/r9a07g075.dtsi b/dts/arm/renesas/rz/rzt/r9a07g075.dtsi index f436cec154058..38832f7f25025 100644 --- a/dts/arm/renesas/rz/rzt/r9a07g075.dtsi +++ b/dts/arm/renesas/rz/rzt/r9a07g075.dtsi @@ -1270,5 +1270,26 @@ interrupts = ; status = "disabled"; }; + + xspi0: xspi@80220000 { + compatible = "renesas,rz-xspi"; + reg = <0x80220000 0x1000>; + interrupts = , + ; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + + xspi1: xspi@80221000 { + compatible = "renesas,rz-xspi"; + reg = <0x80221000 0x1000>; + interrupts = , + ; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + }; }; diff --git a/dts/arm64/renesas/rz/rza/r9a07g063.dtsi b/dts/arm64/renesas/rz/rza/r9a07g063.dtsi index 50b7f13114fb8..a50ceb37ee9ee 100644 --- a/dts/arm64/renesas/rz/rza/r9a07g063.dtsi +++ b/dts/arm64/renesas/rz/rza/r9a07g063.dtsi @@ -957,5 +957,14 @@ clock-freq = ; status = "disabled"; }; + + spibsc: spibsc@10060000 { + compatible = "renesas,rz-spibsc"; + reg = <0x10060000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + }; }; From dd0e7b7b076a7ede0bf897d092116623a56d19f7 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 10:21:28 +0700 Subject: [PATCH 186/397] soc: renesas: Add flash memory regions for RZ/A3UL Add flash memory regions for RZ/A3UL Signed-off-by: Tien Nguyen --- soc/renesas/rz/rza3ul/mmu_regions.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/soc/renesas/rz/rza3ul/mmu_regions.c b/soc/renesas/rz/rza3ul/mmu_regions.c index 3f07572e5804a..20c39e69dd7af 100644 --- a/soc/renesas/rz/rza3ul/mmu_regions.c +++ b/soc/renesas/rz/rza3ul/mmu_regions.c @@ -10,6 +10,10 @@ static const struct arm_mmu_region mmu_regions[] = { MMU_REGION_FLAT_ENTRY("IO_REG", 0x10000000, 0x10000000, MT_DEVICE_nGnRnE | MT_RW | MT_DEFAULT_SECURE_STATE), + MMU_REGION_FLAT_ENTRY("SPI Multi Area", 0x20000000, 0x10000000, + MT_NORMAL | MT_RW | MT_DEFAULT_SECURE_STATE), + MMU_REGION_FLAT_ENTRY("SRAM", 0x00000000, 0x00200000, + MT_NORMAL | MT_RW | MT_DEFAULT_SECURE_STATE), }; const struct arm_mmu_config mmu_config = { From 71b5d50caff09fe19c5f795667dbce85e404a8c6 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 10:00:34 +0700 Subject: [PATCH 187/397] boards: renesas: Add flash support for RZ/A3UL, N2L, T2M Add flash support for RZ/A3UL, N2L, T2M Signed-off-by: Tien Nguyen --- boards/renesas/rza3ul_smarc/Kconfig.defconfig | 5 ++ boards/renesas/rza3ul_smarc/rza3ul_smarc.dts | 59 +++++++++++-------- .../renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi | 14 +++++ boards/renesas/rzn2l_rsk/rzn2l_rsk.dts | 16 ++++- .../renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi | 15 +++++ .../rzt2m_rsk_r9a07g075m24gbg_cr520.dts | 16 ++++- soc/renesas/rz/rza3ul/sections.ld | 2 +- 7 files changed, 101 insertions(+), 26 deletions(-) create mode 100644 boards/renesas/rza3ul_smarc/Kconfig.defconfig diff --git a/boards/renesas/rza3ul_smarc/Kconfig.defconfig b/boards/renesas/rza3ul_smarc/Kconfig.defconfig new file mode 100644 index 0000000000000..8df5fc7719245 --- /dev/null +++ b/boards/renesas/rza3ul_smarc/Kconfig.defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config FLASH_LOAD_OFFSET + default $(dt_nodelabel_reg_addr_hex,header) diff --git a/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts b/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts index f6644ebfb0215..e4901c6a24f46 100644 --- a/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts +++ b/boards/renesas/rza3ul_smarc/rza3ul_smarc.dts @@ -18,7 +18,7 @@ chosen { zephyr,sram = &ddr; - zephyr,flash = &spi_flash; + zephyr,flash = &at25ql128a; zephyr,console = &scif0; zephyr,shell-uart = &scif0; zephyr,code-partition = &slot0_partition; @@ -40,28 +40,6 @@ zephyr,memory-region = "SRAM"; }; - spi_flash: memory@20020000 { - compatible = "mmio-sram"; - reg = <0x20020000 (DT_SIZE_M(16) - 0x20000)>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - header: partition@0 { - label = "header"; - reg = <0x00000000 0x200>; - read-only; - }; - - slot0_partition: partition@200 { - label = "image-0"; - reg = <0x00000200 (DT_SIZE_M(16) - 0x20200)>; - read-only; - }; - }; - }; }; &scif0 { @@ -90,3 +68,38 @@ &wdt0 { status = "okay"; }; + +&spibsc { + status = "okay"; + + at25ql128a: qspi-nor-flash@20000000 { + compatible = "renesas,rz-qspi-spibsc"; + reg = <0x20000000 DT_SIZE_M(16)>; /* 128 Mbits */ + write-block-size = <1>; + erase-block-size = <4096>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + reserved: partition@0 { + reg = <0x00000000 0x20000>; + read-only; + }; + + header: partition@20000 { + label = "header"; + reg = <0x00020000 0x200>; + read-only; + }; + + slot0_partition: partition@20200 { + label = "image-0"; + reg = <0x00020200 (DT_SIZE_M(16) - 0x20200)>; + read-only; + }; + }; + }; +}; diff --git a/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi b/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi index 2b338491a4bb3..2aa6728c77f0c 100644 --- a/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi +++ b/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi @@ -48,4 +48,18 @@ ; /* SDA */ }; }; + + /omit-if-no-ref/ xspi0_default: xspi0_default { + xspi0-pinmux { + pinmux = , /* XSPI0_CKP */ + , /* XSPI0_CKN */ + , /* XSPI0_CS0 */ + , /* XSPI0_IO0 */ + , /* XSPI0_IO1 */ + , /* XSPI0_IO2 */ + , /* XSPI0_IO3 */ + , /* XSPI0_RESET0 */ + ; /* XSPI0_RSTO0 */ + }; + }; }; diff --git a/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts b/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts index da0e1eec63c8b..265c2f092d7a2 100644 --- a/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts +++ b/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts @@ -14,7 +14,7 @@ chosen { zephyr,sram = &atcm; - zephyr,flash = &xspi0_cs0; + zephyr,flash = &mx25u51245g; zephyr,code-partition = &slot0_partition; zephyr,console = &uart0; zephyr,shell-uart = &uart0; @@ -128,3 +128,17 @@ &wdt0 { status = "okay"; }; + +&xspi0 { + pinctrl-0 = <&xspi0_default>; + pinctrl-names = "default"; + status = "okay"; + + mx25u51245g: qspi-nor-flash@60000000 { + compatible = "renesas,rz-qspi-xspi"; + reg = <0x60000000 DT_SIZE_M(64)>; /* 512 Mbits */ + write-block-size = <1>; + erase-block-size = <4096>; + status = "okay"; + }; +}; diff --git a/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi b/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi index 9b48e978a3cce..079e524948559 100644 --- a/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi +++ b/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi @@ -40,4 +40,19 @@ ; /* SDA */ }; }; + + /omit-if-no-ref/ xspi0_default: xspi0_default { + xspi0-pinmux { + pinmux = , /* XSPI0_CKP */ + , /* XSPI0_CKN */ + , /* XSPI0_CS0 */ + , /* XSPI0_IO0 */ + , /* XSPI0_IO1 */ + , /* XSPI0_IO2 */ + , /* XSPI0_IO3 */ + , /* XSPI0_RESET0 */ + ; /* XSPI0_RSTO0 */ + }; + }; + }; diff --git a/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts b/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts index c64faaaa656d9..3ec08a9689834 100644 --- a/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts +++ b/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts @@ -16,7 +16,7 @@ chosen { zephyr,sram = &cpu0_atcm; - zephyr,flash = &xspi0_cs0; + zephyr,flash = &mx25u51245g; zephyr,code-partition = &slot0_partition; zephyr,console = &uart0; zephyr,shell-uart = &uart0; @@ -125,3 +125,17 @@ &wdt0 { status = "okay"; }; + +&xspi0 { + pinctrl-0 = <&xspi0_default>; + pinctrl-names = "default"; + status = "okay"; + + mx25u51245g: qspi-nor-flash@60000000 { + compatible = "renesas,rz-qspi-xspi"; + reg = <0x60000000 DT_SIZE_M(64)>; /* 512 Mbits */ + write-block-size = <1>; + erase-block-size = <4096>; + status = "okay"; + }; +}; diff --git a/soc/renesas/rz/rza3ul/sections.ld b/soc/renesas/rz/rza3ul/sections.ld index bdc29c67e39d2..ad475214f901f 100644 --- a/soc/renesas/rz/rza3ul/sections.ld +++ b/soc/renesas/rz/rza3ul/sections.ld @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -SECTION_PROLOGUE(.header, CONFIG_FLASH_BASE_ADDRESS,) +SECTION_PROLOGUE(.header, CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET,) { QUAD(__start) QUAD(0xFFFFFFFFFFFFFFFF-__start) From 64c80f72f2aa096a7bd6cacf66569f97663c9b93 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 10:12:30 +0700 Subject: [PATCH 188/397] tests: driver: flash: Add Flash driver for RZ/A3UL, T2M, N2L Add Flash driver for RZ/A3UL, T2M, N2L Signed-off-by: Tien Nguyen --- tests/drivers/flash/common/boards/rza3ul_smarc.conf | 4 ++++ tests/drivers/flash/common/boards/rza3ul_smarc.overlay | 8 ++++++++ tests/drivers/flash/common/boards/rzn2l_rsk.conf | 4 ++++ tests/drivers/flash/common/boards/rzn2l_rsk.overlay | 8 ++++++++ .../common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf | 4 ++++ .../common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay | 8 ++++++++ tests/drivers/flash/common/src/main.c | 4 ++++ 7 files changed, 40 insertions(+) create mode 100644 tests/drivers/flash/common/boards/rza3ul_smarc.conf create mode 100644 tests/drivers/flash/common/boards/rza3ul_smarc.overlay create mode 100644 tests/drivers/flash/common/boards/rzn2l_rsk.conf create mode 100644 tests/drivers/flash/common/boards/rzn2l_rsk.overlay create mode 100644 tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf create mode 100644 tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay diff --git a/tests/drivers/flash/common/boards/rza3ul_smarc.conf b/tests/drivers/flash/common/boards/rza3ul_smarc.conf new file mode 100644 index 0000000000000..d8d3631c5d59c --- /dev/null +++ b/tests/drivers/flash/common/boards/rza3ul_smarc.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_TEST_DRIVER_FLASH_SIZE=16777216 diff --git a/tests/drivers/flash/common/boards/rza3ul_smarc.overlay b/tests/drivers/flash/common/boards/rza3ul_smarc.overlay new file mode 100644 index 0000000000000..a427cde3b5aae --- /dev/null +++ b/tests/drivers/flash/common/boards/rza3ul_smarc.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&at25ql128a { + status = "okay"; +}; diff --git a/tests/drivers/flash/common/boards/rzn2l_rsk.conf b/tests/drivers/flash/common/boards/rzn2l_rsk.conf new file mode 100644 index 0000000000000..349d703d783c2 --- /dev/null +++ b/tests/drivers/flash/common/boards/rzn2l_rsk.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_TEST_DRIVER_FLASH_SIZE=67108864 diff --git a/tests/drivers/flash/common/boards/rzn2l_rsk.overlay b/tests/drivers/flash/common/boards/rzn2l_rsk.overlay new file mode 100644 index 0000000000000..bc059c7cb3bf9 --- /dev/null +++ b/tests/drivers/flash/common/boards/rzn2l_rsk.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&mx25u51245g { + status = "okay"; +}; diff --git a/tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf b/tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf new file mode 100644 index 0000000000000..349d703d783c2 --- /dev/null +++ b/tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_TEST_DRIVER_FLASH_SIZE=67108864 diff --git a/tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay b/tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay new file mode 100644 index 0000000000000..bc059c7cb3bf9 --- /dev/null +++ b/tests/drivers/flash/common/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&mx25u51245g { + status = "okay"; +}; diff --git a/tests/drivers/flash/common/src/main.c b/tests/drivers/flash/common/src/main.c index e9d4a1c15bac3..8d9265d0bf361 100644 --- a/tests/drivers/flash/common/src/main.c +++ b/tests/drivers/flash/common/src/main.c @@ -25,6 +25,10 @@ #define TEST_AREA_DEV_NODE DT_INST(0, jedec_mspi_nor) #elif defined(CONFIG_FLASH_RENESAS_RA_QSPI) #define TEST_AREA_DEV_NODE DT_INST(0, renesas_ra_qspi_nor) +#elif defined(CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI) +#define TEST_AREA_DEV_NODE DT_INST(0, renesas_rz_qspi_xspi) +#elif defined(CONFIG_FLASH_RENESAS_RZ_QSPI_SPIBSC) +#define TEST_AREA_DEV_NODE DT_INST(0, renesas_rz_qspi_spibsc) #else #define TEST_AREA storage_partition #endif From 8690b01a0a4066a99d95bfdc1666bba8a920204a Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 10:15:03 +0700 Subject: [PATCH 189/397] samples: driver: jesd216: Add Flash driver for RZ/A3UL, T2M, N2L Add Flash driver for RZ/A3UL, T2M, N2L Signed-off-by: Tien Nguyen --- samples/drivers/jesd216/src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/samples/drivers/jesd216/src/main.c b/samples/drivers/jesd216/src/main.c index 249b6374b55a8..0d7ec299655ca 100644 --- a/samples/drivers/jesd216/src/main.c +++ b/samples/drivers/jesd216/src/main.c @@ -34,6 +34,10 @@ #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(renesas_ra_ospi_b_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_qspi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(renesas_ra_qspi_nor) +#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_qspi_xspi) +#define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(renesas_rz_qspi_xspi) +#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_qspi_spibsc) +#define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(renesas_rz_qspi_spibsc) #elif DT_HAS_COMPAT_STATUS_OKAY(sifli_sf32lb_mpi_qspi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(sifli_sf32lb_mpi_qspi_nor) #else From 4e901c1e6688a5d2db34858ae48dba27b51c0239 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 10:16:14 +0700 Subject: [PATCH 190/397] samples: drivers: spi_flash: Add Flash driver for RZ/A3UL, T2M, N2L Add Flash driver for RZ/A3UL, T2M, N2L Signed-off-by: Tien Nguyen --- samples/drivers/spi_flash/src/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/samples/drivers/spi_flash/src/main.c b/samples/drivers/spi_flash/src/main.c index 07adf7739becc..2fd493338420e 100644 --- a/samples/drivers/spi_flash/src/main.c +++ b/samples/drivers/spi_flash/src/main.c @@ -38,7 +38,8 @@ #if defined(CONFIG_FLASH_STM32_OSPI) || defined(CONFIG_FLASH_STM32_QSPI) || \ defined(CONFIG_FLASH_STM32_XSPI) || defined(CONFIG_FLASH_RENESAS_RA_OSPI_B) || \ - defined(CONFIG_FLASH_RENESAS_RA_QSPI) + defined(CONFIG_FLASH_RENESAS_RA_QSPI) || defined(CONFIG_FLASH_RENESAS_RZ_QSPI_XSPI) || \ + defined(CONFIG_FLASH_RENESAS_RZ_QSPI_SPIBSC) #define SPI_FLASH_MULTI_SECTOR_TEST #endif @@ -58,6 +59,10 @@ #define SPI_FLASH_COMPAT renesas_ra_ospi_b_nor #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_qspi_nor) #define SPI_FLASH_COMPAT renesas_ra_qspi_nor +#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_qspi_xspi) +#define SPI_FLASH_COMPAT renesas_rz_qspi_xspi +#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_qspi_spibsc) +#define SPI_FLASH_COMPAT renesas_rz_qspi_spibsc #else #define SPI_FLASH_COMPAT invalid #endif From 26cd689024d1012db34458d1171fd75c26e7f581 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 29 Sep 2025 10:17:27 +0700 Subject: [PATCH 191/397] driver: flash: Add a macro to define the 32KB block size in spi_nor.h Add a macro to define the 32KB block size in spi_nor.h Signed-off-by: Tien Nguyen --- drivers/flash/spi_nor.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/flash/spi_nor.h b/drivers/flash/spi_nor.h index 6952d7ea4d70d..3dd66642290de 100644 --- a/drivers/flash/spi_nor.h +++ b/drivers/flash/spi_nor.h @@ -91,9 +91,10 @@ #define SPI_NOR_OCMD_BULKE 0x609F /* Octa Bulk Erase */ /* Page, sector, and block size are standard, not configurable. */ - #define SPI_NOR_PAGE_SIZE 0x0100U - #define SPI_NOR_SECTOR_SIZE 0x1000U - #define SPI_NOR_BLOCK_SIZE 0x10000U +#define SPI_NOR_PAGE_SIZE 0x0100U +#define SPI_NOR_SECTOR_SIZE 0x1000U +#define SPI_NOR_BLOCK_32K_SIZE 0x8000U +#define SPI_NOR_BLOCK_SIZE 0x10000U /* Flash Auto-polling values */ #define SPI_NOR_WREN_MATCH 0x02 From 625f8565164377bd76ddeb62949674f4331911a6 Mon Sep 17 00:00:00 2001 From: Venkatesh Odela Date: Mon, 13 Oct 2025 17:58:42 +0530 Subject: [PATCH 192/397] drivers: ethernet: phy: ti_dp83867: Fix warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrapp the 'done:' label with #if DT_ANY_INST_HAS_PROP_STATUS_OKAY to avoid unused label warnings when reset_gpios is not defined. Move declaration of 'val' under the corresponding #if block to limit its scope and prevent “unused variable” warnings. Signed-off-by: Venkatesh Odela --- drivers/ethernet/phy/phy_ti_dp83867.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/phy/phy_ti_dp83867.c b/drivers/ethernet/phy/phy_ti_dp83867.c index 24d54520092c9..8c105641f6e04 100644 --- a/drivers/ethernet/phy/phy_ti_dp83867.c +++ b/drivers/ethernet/phy/phy_ti_dp83867.c @@ -295,8 +295,10 @@ static int phy_ti_dp83867_reset(const struct device *dev) if (ret < 0) { LOG_ERR("Error writing phy (%d) basic control register", config->addr); } - +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) done: +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) */ + /* POR release time (minimum specified is T4=195us) */ k_busy_wait(PHY_TI_DP83867_POR_DELAY); @@ -313,7 +315,7 @@ static int phy_ti_dp83867_cfg_link(const struct device *dev, enum phy_link_speed const struct ti_dp83867_config *config = dev->config; struct ti_dp83867_data *data = dev->data; int ret; - uint32_t val; + __maybe_unused uint32_t val; if (flags & PHY_FLAG_AUTO_NEGOTIATION_DISABLED) { LOG_ERR("Disabling auto-negotiation is not supported by this driver"); From 35c90e44421d9a57c276e117a6ccd9f671271a3e Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 30 May 2025 14:40:56 +0700 Subject: [PATCH 193/397] drivers: misc: ethos_u: Add support NPU on Renesas devices Add support NPU driver on Renesas devices Signed-off-by: Khoa Nguyen --- drivers/misc/ethos_u/CMakeLists.txt | 1 + drivers/misc/ethos_u/Kconfig | 6 ++ drivers/misc/ethos_u/ethos_u_renesas.c | 129 +++++++++++++++++++++++++ dts/bindings/arm/renesas,ra-npu.yaml | 17 ++++ 4 files changed, 153 insertions(+) create mode 100644 drivers/misc/ethos_u/ethos_u_renesas.c create mode 100644 dts/bindings/arm/renesas,ra-npu.yaml diff --git a/drivers/misc/ethos_u/CMakeLists.txt b/drivers/misc/ethos_u/CMakeLists.txt index 975fbc8deb77b..3ec600b5ada3f 100644 --- a/drivers/misc/ethos_u/CMakeLists.txt +++ b/drivers/misc/ethos_u/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library() zephyr_library_sources(ethos_u_common.c) zephyr_library_sources_ifdef(CONFIG_ETHOS_U_ARM ethos_u_arm.c) zephyr_library_sources_ifdef(CONFIG_ETHOS_U_NUMAKER ethos_u_numaker.c) +zephyr_library_sources_ifdef(CONFIG_ETHOS_U_RENESAS ethos_u_renesas.c) diff --git a/drivers/misc/ethos_u/Kconfig b/drivers/misc/ethos_u/Kconfig index 24aacb0b81817..eb65ba5d3eb71 100644 --- a/drivers/misc/ethos_u/Kconfig +++ b/drivers/misc/ethos_u/Kconfig @@ -6,6 +6,7 @@ choice depends on ETHOS_U default ETHOS_U_ARM if DT_HAS_ARM_ETHOS_U_ENABLED default ETHOS_U_NUMAKER if DT_HAS_NUVOTON_NUMAKER_NPU_ENABLED + default ETHOS_U_RENESAS if DT_HAS_RENESAS_RA_NPU_ENABLED config ETHOS_U_ARM bool "Arm Ethos-U NPU driver" @@ -17,6 +18,11 @@ config ETHOS_U_NUMAKER help Enables Nuvoton NuMaker frontend of Arm Ethos-U NPU driver +config ETHOS_U_RENESAS + bool "Renesas RA Ethos-U NPU driver" + help + Enables Renesas RA frontend of Arm Ethos-U NPU driver. + endchoice config ETHOS_U_DCACHE diff --git a/drivers/misc/ethos_u/ethos_u_renesas.c b/drivers/misc/ethos_u/ethos_u_renesas.c new file mode 100644 index 0000000000000..c57efc4280e4a --- /dev/null +++ b/drivers/misc/ethos_u/ethos_u_renesas.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ethos_u_common.h" + +#define DT_DRV_COMPAT renesas_ra_npu +LOG_MODULE_REGISTER(renesas_ra_npu, CONFIG_ETHOS_U_LOG_LEVEL); + +struct ethos_u_renesas_config { + const struct ethosu_dts_info ethosu_dts_info; + const struct device *clock_dev; + const struct clock_control_ra_subsys_cfg clock_subsys; +}; + +void ethos_u_renesas_ra_irq_handler(const struct device *dev) +{ + struct ethosu_data *data = dev->data; + struct ethosu_driver *drv = &data->drv; + IRQn_Type irq = R_FSP_CurrentIrqGet(); + + ethosu_irq_handler(drv); + + R_BSP_IrqStatusClear(irq); +} + +static int ethos_u_renesas_ra_init(const struct device *dev) +{ + const struct ethos_u_renesas_config *config = dev->config; + const struct ethosu_dts_info ethosu_dts_info = config->ethosu_dts_info; + struct ethosu_data *data = dev->data; + struct ethosu_driver *drv = &data->drv; + struct ethosu_driver_version version; + int err; + + if (!device_is_ready(config->clock_dev)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + err = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->clock_subsys); + if (err < 0) { + LOG_ERR("Could not initialize clock (%d)", err); + return err; + } + + if ((((0 == R_SYSTEM->PGCSAR_b.NONSEC2) && FSP_PRIV_TZ_USE_SECURE_REGS) || + ((1 == R_SYSTEM->PGCSAR_b.NONSEC2) && BSP_TZ_NONSECURE_BUILD)) && + (0 != R_SYSTEM->PDCTRNPU)) { + /* Turn on NPU power domain */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT); + FSP_HARDWARE_REGISTER_WAIT((R_SYSTEM->PDCTRNPU & (R_SYSTEM_PDCTRNPU_PDCSF_Msk | + R_SYSTEM_PDCTRGD_PDPGSF_Msk)), + R_SYSTEM_PDCTRGD_PDPGSF_Msk); + R_SYSTEM->PDCTRNPU = 0; + FSP_HARDWARE_REGISTER_WAIT((R_SYSTEM->PDCTRNPU & (R_SYSTEM_PDCTRNPU_PDCSF_Msk | + R_SYSTEM_PDCTRGD_PDPGSF_Msk)), + 0); + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT); + } + + LOG_DBG("Ethos-U DTS info. base_address=0x%p, secure_enable=%u, privilege_enable=%u", + ethosu_dts_info.base_addr, ethosu_dts_info.secure_enable, + ethosu_dts_info.privilege_enable); + + ethosu_get_driver_version(&version); + + LOG_DBG("Version. major=%u, minor=%u, patch=%u", version.major, version.minor, + version.patch); + + if (ethosu_init(drv, ethosu_dts_info.base_addr, NULL, 0, ethosu_dts_info.secure_enable, + ethosu_dts_info.privilege_enable)) { + LOG_ERR("Failed to initialize NPU with ethosu_init()."); + return -EINVAL; + } + + ethosu_dts_info.irq_config(); + + return 0; +} + +#define ETHOSU_RENESAS_RA_DEVICE_INIT(idx) \ + static struct ethosu_data ethosu_data_##idx; \ + \ + static void ethosu_zephyr_irq_config_##idx(void) \ + { \ + R_ICU->IELSR_b[DT_INST_IRQ_BY_NAME(idx, npu_irq, irq)].IELS = \ + BSP_PRV_IELS_ENUM(EVENT_NPU_IRQ); \ + \ + BSP_ASSIGN_EVENT_TO_CURRENT_CORE(BSP_PRV_IELS_ENUM(EVENT_NPU_IRQ)); \ + \ + IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), \ + ethos_u_renesas_ra_irq_handler, DEVICE_DT_INST_GET(idx), 0); \ + \ + irq_enable(DT_INST_IRQN(idx)); \ + } \ + \ + static const struct ethos_u_renesas_config ethos_u_renesas_config##idx = { \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clock_subsys = \ + { \ + .mstp = (uint32_t)DT_INST_CLOCKS_CELL_BY_IDX(idx, 0, mstp), \ + .stop_bit = DT_INST_CLOCKS_CELL_BY_IDX(idx, 0, stop_bit), \ + }, \ + .ethosu_dts_info = \ + { \ + .base_addr = (void *)DT_INST_REG_ADDR(idx), \ + .secure_enable = DT_INST_PROP(idx, secure_enable), \ + .privilege_enable = DT_INST_PROP(idx, privilege_enable), \ + .irq_config = ðosu_zephyr_irq_config_##idx, \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, ethos_u_renesas_ra_init, NULL, ðosu_data_##idx, \ + ðos_u_renesas_config##idx, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); + +DT_INST_FOREACH_STATUS_OKAY(ETHOSU_RENESAS_RA_DEVICE_INIT); diff --git a/dts/bindings/arm/renesas,ra-npu.yaml b/dts/bindings/arm/renesas,ra-npu.yaml new file mode 100644 index 0000000000000..1604c0bb918d8 --- /dev/null +++ b/dts/bindings/arm/renesas,ra-npu.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA frontend of Arm Ethos-U NPU + +compatible: "renesas,ra-npu" + +include: "arm,ethos-u.yaml" + +properties: + clocks: + required: true + + interrupt-names: + required: true + enum: + - "npu-irq" From 91ecf65b721bbfa427a61c91154bdfe2948a9c39 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Thu, 16 Oct 2025 04:24:52 +0000 Subject: [PATCH 194/397] soc: renesas: ra: Select the Ethos-U NPU configuration for RA8P1 Select the Ethos-U NPU configuration for RA8P1 Signed-off-by: Khoa Nguyen --- soc/renesas/ra/ra8p1/Kconfig.defconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/soc/renesas/ra/ra8p1/Kconfig.defconfig b/soc/renesas/ra/ra8p1/Kconfig.defconfig index 27ef391a9080a..23e976fd3002c 100644 --- a/soc/renesas/ra/ra8p1/Kconfig.defconfig +++ b/soc/renesas/ra/ra8p1/Kconfig.defconfig @@ -39,4 +39,12 @@ config DCACHE config CACHE_MANAGEMENT default n +if ETHOS_U + +choice ETHOS_U_NPU_CONFIG + default ETHOS_U55_256 +endchoice + +endif # ETHOS_U + endif # SOC_SERIES_RA8P1 From d298783fc905d32be89495a146af6659d2e61e90 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 30 May 2025 14:42:49 +0700 Subject: [PATCH 195/397] dts: arm: renesas: ra: Add support NPU on Renesas ra8p1 SoC dts Add support NPU on Renesas ra8p1 SoC dts Signed-off-by: Khoa Nguyen --- dts/arm/renesas/ra/ra8/r7ka8p1xf.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dts/arm/renesas/ra/ra8/r7ka8p1xf.dtsi b/dts/arm/renesas/ra/ra8/r7ka8p1xf.dtsi index 92530eed96074..6f7a3e5a2d66e 100644 --- a/dts/arm/renesas/ra/ra8/r7ka8p1xf.dtsi +++ b/dts/arm/renesas/ra/ra8/r7ka8p1xf.dtsi @@ -8,6 +8,17 @@ #include / { + soc { + npu0: npu@40140000 { + compatible = "renesas,ra-npu"; + reg = <0x40140000 0x1000>; + clocks = <&npuclk MSTPA 16>; + secure-enable; + privilege-enable; + status = "disabled"; + }; + }; + clocks: clocks { #address-cells = <1>; #size-cells = <1>; From 2b0068a728e2faa5bf7b513fc410c181a92ae604 Mon Sep 17 00:00:00 2001 From: Khoa Nguyen Date: Fri, 30 May 2025 14:54:48 +0700 Subject: [PATCH 196/397] samples: modules: tflite-micro: Support tflm_ethosu for ek_ra8p1 Add support sample app `tflm_ethosu` for Renesas ek_ra8p1 board Signed-off-by: Khoa Nguyen --- samples/modules/tflite-micro/tflm_ethosu/Kconfig | 2 +- .../boards/ek_ra8p1_r7ka8p1kflcac_cm33.overlay | 10 ++++++++++ .../boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm33.overlay create mode 100644 samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay diff --git a/samples/modules/tflite-micro/tflm_ethosu/Kconfig b/samples/modules/tflite-micro/tflm_ethosu/Kconfig index 3e976735b4d81..32357d58ec0f8 100644 --- a/samples/modules/tflite-micro/tflm_ethosu/Kconfig +++ b/samples/modules/tflite-micro/tflm_ethosu/Kconfig @@ -9,7 +9,7 @@ config TAINT_BLOBS_TFLM config TAINT_BLOBS_TFLM_ETHOSU bool "Choose Vela-compiled model targeting Ethos-U" default y - depends on ETHOS_U_ARM || ETHOS_U_NUMAKER + depends on ETHOS_U_ARM || ETHOS_U_NUMAKER || ETHOS_U_RENESAS select TAINT_BLOBS_TFLM source "Kconfig.zephyr" diff --git a/samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm33.overlay b/samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm33.overlay new file mode 100644 index 0000000000000..98c38a8cb7180 --- /dev/null +++ b/samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm33.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&npu0 { + interrupts = <95 1>; + interrupt-names = "npu-irq"; + status = "okay"; +}; diff --git a/samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay b/samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay new file mode 100644 index 0000000000000..98c38a8cb7180 --- /dev/null +++ b/samples/modules/tflite-micro/tflm_ethosu/boards/ek_ra8p1_r7ka8p1kflcac_cm85.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&npu0 { + interrupts = <95 1>; + interrupt-names = "npu-irq"; + status = "okay"; +}; From 6b86cce2fbf00df196b4e8bf02e4387fcad8271d Mon Sep 17 00:00:00 2001 From: Tom Chang Date: Fri, 26 Sep 2025 09:35:00 +0800 Subject: [PATCH 197/397] drivers: ps2: npcx: update registers for NPCKn variant This commit updates register definition for NPCKn variant to match the datasheet. Signed-off-by: Tom Chang --- drivers/ps2/ps2_npcx_controller.c | 4 ++++ dts/arm/nuvoton/npck/npck.dtsi | 4 ++-- .../npcx/common/npckn/include/reg_def.h | 23 ++++++++----------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/ps2/ps2_npcx_controller.c b/drivers/ps2/ps2_npcx_controller.c index e121ff5e3688f..358708b972bfa 100644 --- a/drivers/ps2/ps2_npcx_controller.c +++ b/drivers/ps2/ps2_npcx_controller.c @@ -252,7 +252,11 @@ static void ps2_npcx_ctrl_isr(const struct device *dev) * ACH = 5 : Channel 3 */ active_ch = GET_FIELD(inst->PSTAT, NPCX_PSTAT_ACH); +#if defined(CONFIG_NPCX_SOC_VARIANT_NPCKN) + active_ch = active_ch > 2 ? (active_ch - 1) : active_ch; +#else active_ch = active_ch > 2 ? (active_ch - 2) : (active_ch - 1); +#endif LOG_DBG("ACH: %d\n", active_ch); /* diff --git a/dts/arm/nuvoton/npck/npck.dtsi b/dts/arm/nuvoton/npck/npck.dtsi index 4fbb9cfcbeea8..ad083a755eb5d 100644 --- a/dts/arm/nuvoton/npck/npck.dtsi +++ b/dts/arm/nuvoton/npck/npck.dtsi @@ -535,13 +535,13 @@ /* PS2 Channels - Please use them as PS2 node */ ps2_channel2: io_ps2_channel2 { compatible = "nuvoton,npcx-ps2-channel"; - channel = <0x01>; + channel = <0x02>; status = "disabled"; }; ps2_channel3: io_ps2_channel3 { compatible = "nuvoton,npcx-ps2-channel"; - channel = <0x02>; + channel = <0x03>; status = "disabled"; }; }; diff --git a/soc/nuvoton/npcx/common/npckn/include/reg_def.h b/soc/nuvoton/npcx/common/npckn/include/reg_def.h index 3ab3ef85cb181..313ac130ce690 100644 --- a/soc/nuvoton/npcx/common/npckn/include/reg_def.h +++ b/soc/nuvoton/npcx/common/npckn/include/reg_def.h @@ -1490,20 +1490,15 @@ struct ps2_reg { #define NPCX_PSCON_IDB FIELD(4, 3) #define NPCX_PSCON_WPUED 7 -#define NPCX_PSOSIG_WDAT0 0 -#define NPCX_PSOSIG_WDAT1 1 -#define NPCX_PSOSIG_WDAT2 2 -#define NPCX_PSOSIG_CLK0 3 -#define NPCX_PSOSIG_CLK1 4 -#define NPCX_PSOSIG_CLK2 5 -#define NPCX_PSOSIG_WDAT3 6 -#define NPCX_PSOSIG_CLK3 7 -#define NPCX_PSOSIG_CLK(n) (((n) < 3) ? ((n) + 3) : 7) -#define NPCX_PSOSIG_WDAT(n) (((n) < 3) ? ((n) + 0) : 6) -#define NPCX_PSOSIG_CLK_MASK_ALL \ - (BIT(NPCX_PSOSIG_CLK0) | \ - BIT(NPCX_PSOSIG_CLK1) | \ - BIT(NPCX_PSOSIG_CLK2) | \ +#define NPCX_PSOSIG_WDAT2 1 +#define NPCX_PSOSIG_WDAT3 2 +#define NPCX_PSOSIG_CLK2 4 +#define NPCX_PSOSIG_CLK3 5 +#define NPCX_PSOSIG_CLK(n) (((n) == 2) ? NPCX_PSOSIG_CLK2 : \ + NPCX_PSOSIG_CLK3) +#define NPCX_PSOSIG_WDAT(n) (((n) == 2) ? NPCX_PSOSIG_WDAT2 : \ + NPCX_PSOSIG_WDAT3) +#define NPCX_PSOSIG_CLK_MASK_ALL (BIT(NPCX_PSOSIG_CLK2) | \ BIT(NPCX_PSOSIG_CLK3)) #define NPCX_PSIEN_SOTIE 0 From 9d18e991f22b9e992b13f3d4b1685c93e207f4ff Mon Sep 17 00:00:00 2001 From: Mario Paja Date: Fri, 17 Oct 2025 19:36:09 +0200 Subject: [PATCH 198/397] dts: st: f4: enable sai1 in stm32f4xx series These changes enable SAI1 A & B nodes in STM32F4xx series. Signed-off-by: Mario Paja --- dts/arm/st/f4/stm32f413.dtsi | 23 +++++++++++++++++++++++ dts/arm/st/f4/stm32f427.dtsi | 23 +++++++++++++++++++++++ dts/arm/st/f4/stm32f446.dtsi | 23 +++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/dts/arm/st/f4/stm32f413.dtsi b/dts/arm/st/f4/stm32f413.dtsi index 4cfe6a4587c8a..a410152e7a263 100644 --- a/dts/arm/st/f4/stm32f413.dtsi +++ b/dts/arm/st/f4/stm32f413.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Florian Vaussard, HEIG-VD + * Copyright (c) 2025 Mario Paja * * SPDX-License-Identifier: Apache-2.0 */ @@ -80,5 +81,27 @@ clocks = <&rcc STM32_CLOCK(APB1, 27)>; status = "disabled"; }; + + sai1_a: sai1@40015804 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015804 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 22)>; + dmas = <&dma2 1 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; + status = "disabled"; + }; + + sai1_b: sai1@40015824 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015824 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 22)>; + dmas = <&dma2 5 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/st/f4/stm32f427.dtsi b/dts/arm/st/f4/stm32f427.dtsi index 4baf3a1f8317e..0ce973cc21228 100644 --- a/dts/arm/st/f4/stm32f427.dtsi +++ b/dts/arm/st/f4/stm32f427.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Linaro Limited + * Copyright (c) 2025 Mario Paja * * SPDX-License-Identifier: Apache-2.0 */ @@ -111,6 +112,28 @@ status = "disabled"; }; }; + + sai1_a: sai1@40015804 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015804 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 22)>; + dmas = <&dma2 1 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; + status = "disabled"; + }; + + sai1_b: sai1@40015824 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015824 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 22)>; + dmas = <&dma2 5 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; + status = "disabled"; + }; }; die_temp: dietemp { diff --git a/dts/arm/st/f4/stm32f446.dtsi b/dts/arm/st/f4/stm32f446.dtsi index fb5ec329579b4..2ed9145bc09d4 100644 --- a/dts/arm/st/f4/stm32f446.dtsi +++ b/dts/arm/st/f4/stm32f446.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Philémon Jaermann + * Copyright (c) 2025 Mario Paja * * SPDX-License-Identifier: Apache-2.0 */ @@ -169,6 +170,28 @@ status = "disabled"; }; }; + + sai1_a: sai1@40015804 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015804 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 22)>; + dmas = <&dma2 1 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; + status = "disabled"; + }; + + sai1_b: sai1@40015824 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015824 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 22)>; + dmas = <&dma2 5 0 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS) 0>; + status = "disabled"; + }; }; die_temp: dietemp { From 420f3f8c763963233f708d02c6b6f659a202573a Mon Sep 17 00:00:00 2001 From: Mario Paja Date: Fri, 17 Oct 2025 20:32:46 +0200 Subject: [PATCH 199/397] drivers: i2s: stm32 sai add support for stm32f4xx series STM32F4xx series shares several DMA configurations with the other platforms. These changes aim to enable platform specific DMA configuration and align them to other platforms. Signed-off-by: Mario Paja --- drivers/i2s/Kconfig.stm32 | 1 + drivers/i2s/i2s_stm32_sai.c | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/i2s/Kconfig.stm32 b/drivers/i2s/Kconfig.stm32 index 697aee3b08462..68961d873f491 100644 --- a/drivers/i2s/Kconfig.stm32 +++ b/drivers/i2s/Kconfig.stm32 @@ -35,6 +35,7 @@ menuconfig I2S_STM32_SAI select USE_STM32_HAL_DMA select USE_STM32_HAL_DMA_EX select USE_STM32_HAL_SAI + select USE_STM32_HAL_SAI_EX if SOC_SERIES_STM32F4X help Enable SAI support on the STM32 family of processors. diff --git a/drivers/i2s/i2s_stm32_sai.c b/drivers/i2s/i2s_stm32_sai.c index e80fdd41dc425..9a5ee27d10d3b 100644 --- a/drivers/i2s/i2s_stm32_sai.c +++ b/drivers/i2s/i2s_stm32_sai.c @@ -283,11 +283,17 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) } hdma->Instance = STM32_DMA_GET_INSTANCE(stream->reg, stream->dma_channel); +#if defined(CONFIG_SOC_SERIES_STM32F4X) + hdma->Init.Channel = dma_cfg.dma_slot * DMA_CHANNEL_1; +#else hdma->Init.Request = dma_cfg.dma_slot; +#endif hdma->Init.Mode = DMA_NORMAL; #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32L4X) || \ - defined(CONFIG_SOC_SERIES_STM32G4X) || defined(CONFIG_SOC_SERIES_STM32L5X) + defined(CONFIG_SOC_SERIES_STM32G4X) || defined(CONFIG_SOC_SERIES_STM32L5X) || \ + defined(CONFIG_SOC_SERIES_STM32F4X) + hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma->Init.Priority = DMA_PRIORITY_HIGH; @@ -304,7 +310,7 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) hdma->Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; #endif -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32F4X) hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE; #endif @@ -312,7 +318,8 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) hdma->Init.Direction = DMA_MEMORY_TO_PERIPH; #if !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32L4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) + !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) && \ + !defined(CONFIG_SOC_SERIES_STM32F4X) hdma->Init.SrcInc = DMA_SINC_INCREMENTED; hdma->Init.DestInc = DMA_DINC_FIXED; #endif @@ -322,7 +329,8 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) hdma->Init.Direction = DMA_PERIPH_TO_MEMORY; #if !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32L4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) + !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) && \ + !defined(CONFIG_SOC_SERIES_STM32F4X) hdma->Init.SrcInc = DMA_SINC_FIXED; hdma->Init.DestInc = DMA_DINC_INCREMENTED; #endif @@ -342,7 +350,8 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) return -EIO; } #elif !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32L4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) + !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) && \ + !defined(CONFIG_SOC_SERIES_STM32F4X) if (HAL_DMA_ConfigChannelAttributes(&dev_data->hdma, DMA_CHANNEL_NPRIV) != HAL_OK) { LOG_ERR("HAL_DMA_ConfigChannelAttributes: "); return -EIO; @@ -458,7 +467,7 @@ static int i2s_stm32_sai_configure(const struct device *dev, enum i2s_dir dir, } /* Control of MCLK output from SAI configuration is not possible on STM32L4xx MCUs */ -#if !defined(CONFIG_SOC_SERIES_STM32L4X) +#if !defined(CONFIG_SOC_SERIES_STM32L4X) && !defined(CONFIG_SOC_SERIES_STM32F4X) if (cfg->mclk_enable && stream->master) { hsai->Init.MckOutput = SAI_MCK_OUTPUT_ENABLE; } else { @@ -472,7 +481,7 @@ static int i2s_stm32_sai_configure(const struct device *dev, enum i2s_dir dir, hsai->Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; /* MckOverSampling is not supported by all STM32L4xx MCUs */ -#if !defined(CONFIG_SOC_SERIES_STM32L4X) +#if !defined(CONFIG_SOC_SERIES_STM32L4X) && !defined(CONFIG_SOC_SERIES_STM32F4X) if (cfg->mclk_div == (enum mclk_divider)MCLK_DIV_256) { hsai->Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE; } else { From 1dbc2f6975e3da97556573a87ca38391d1d2f6bf Mon Sep 17 00:00:00 2001 From: Mario Paja Date: Fri, 17 Oct 2025 20:13:50 +0200 Subject: [PATCH 200/397] samples: i2s: output: add nucleo_f429zi Add nucleo_f429zi board in samples/drivers/i2s/output Signed-off-by: Mario Paja --- .../i2s/output/boards/nucleo_f429zi.conf | 1 + .../i2s/output/boards/nucleo_f429zi.overlay | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 samples/drivers/i2s/output/boards/nucleo_f429zi.conf create mode 100644 samples/drivers/i2s/output/boards/nucleo_f429zi.overlay diff --git a/samples/drivers/i2s/output/boards/nucleo_f429zi.conf b/samples/drivers/i2s/output/boards/nucleo_f429zi.conf new file mode 100644 index 0000000000000..4f3f73a1e06a5 --- /dev/null +++ b/samples/drivers/i2s/output/boards/nucleo_f429zi.conf @@ -0,0 +1 @@ +CONFIG_HEAP_MEM_POOL_SIZE=4192 diff --git a/samples/drivers/i2s/output/boards/nucleo_f429zi.overlay b/samples/drivers/i2s/output/boards/nucleo_f429zi.overlay new file mode 100644 index 0000000000000..edb91c5bbc090 --- /dev/null +++ b/samples/drivers/i2s/output/boards/nucleo_f429zi.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Mario Paja + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2s-tx = &sai1_b; + }; +}; + +/* 43.836KHz (-0.37% Error) */ +&pllsai{ + div-m = <8>; + mul-n = <101>; + div-q = <9>; + div-divq = <1>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&sai1_b { + pinctrl-0 = <&sai1_mclk_b_pf7 &sai1_sd_b_pe3 &sai1_fs_b_pf9 &sai1_sck_b_pf8>; + pinctrl-names = "default"; + status = "okay"; + mclk-enable; + mclk-divider = "div-256"; + dma-names = "tx"; +}; + +&dma2 { + status = "okay"; +}; From dc90b956da866934207fbff1c0ed53f43cdfdd72 Mon Sep 17 00:00:00 2001 From: Zhaoxiang Jin Date: Tue, 21 Oct 2025 21:44:34 +0800 Subject: [PATCH 201/397] boards: nxp: Unify the use of macros For nxp's board.c, the macro used in some places is 'DT_NODE_HAS_STATUS(DT_NODELABEL(),okay)', and the macro used in some places is 'DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL())'. The purpose of this PR is to unify the use of macros and use the latter. Signed-off-by: Zhaoxiang Jin --- boards/nxp/frdm_mcxn947/board.c | 4 +- boards/nxp/mcx_nx4x_evk/board.c | 4 +- boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c | 12 +-- boards/nxp/mimxrt700_evk/board.c | 110 ++++++++++---------- 4 files changed, 65 insertions(+), 65 deletions(-) diff --git a/boards/nxp/frdm_mcxn947/board.c b/boards/nxp/frdm_mcxn947/board.c index 321941863d03f..2ac3f1696774d 100644 --- a/boards/nxp/frdm_mcxn947/board.c +++ b/boards/nxp/frdm_mcxn947/board.c @@ -422,7 +422,7 @@ void board_early_init_hook(void) CLOCK_AttachClk(kPLL0_to_FLEXIO); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(i3c1)) /* Enable 1MHz clock. */ SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_FRO1MHZ_CLK_ENA_MASK; @@ -436,7 +436,7 @@ void board_early_init_hook(void) CLOCK_AttachClk(kI3C1FCLK_to_I3C1FCLKSTC); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(sc_timer), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sc_timer)) /* attach FRO HF to SCT */ CLOCK_SetClkDiv(kCLOCK_DivSctClk, 1u); CLOCK_AttachClk(kFRO_HF_to_SCT); diff --git a/boards/nxp/mcx_nx4x_evk/board.c b/boards/nxp/mcx_nx4x_evk/board.c index 760812971a3ad..27557d88546ac 100644 --- a/boards/nxp/mcx_nx4x_evk/board.c +++ b/boards/nxp/mcx_nx4x_evk/board.c @@ -418,7 +418,7 @@ void board_early_init_hook(void) CLOCK_AttachClk(kPLL0_to_FLEXIO); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(i3c1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(i3c1)) /* Enable 1MHz clock. */ SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_FRO1MHZ_CLK_ENA_MASK; @@ -432,7 +432,7 @@ void board_early_init_hook(void) CLOCK_AttachClk(kI3C1FCLK_to_I3C1FCLKSTC); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(sc_timer), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sc_timer)) /* attach FRO HF to SCT */ CLOCK_SetClkDiv(kCLOCK_DivSctClk, 1u); CLOCK_AttachClk(kFRO_HF_to_SCT); diff --git a/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c b/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c index 0671843514ddb..ac4e838fca30e 100644 --- a/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c +++ b/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c @@ -48,32 +48,32 @@ static const struct arm_mpu_region mpu_regions[] = { MPU_REGION_ENTRY("UNMAPPED", 0, {REGION_4G | MPU_RASR_XN_Msk | P_NA_U_NA_Msk}), -#if DT_NODE_HAS_STATUS(DT_NODELABEL(itcm), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(itcm)) MPU_REGION_ENTRY("ITCM", REGION_ITCM_BASE_ADDRESS, REGION_FLASH_ATTR(REGION_ITCM_SIZE)), #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(dtcm), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(dtcm)) MPU_REGION_ENTRY("DTCM", REGION_DTCM_BASE_ADDRESS, REGION_RAM_NOCACHE_ATTR(REGION_DTCM_SIZE)), #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ocram1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ocram1)) MPU_REGION_ENTRY("OCRAM1", REGION_OCRAM1_SHM_BASE_ADDRESS, REGION_RAM_ATTR(REGION_OCRAM1_SHM_SIZE)), #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ocram2), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ocram2)) MPU_REGION_ENTRY("OCRAM2", REGION_OCRAM2_SHM_BASE_ADDRESS, REGION_RAM_NOCACHE_ATTR(REGION_OCRAM2_SHM_SIZE)), #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(hyperram0), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(hyperram0)) MPU_REGION_ENTRY("HYPER_RAM", REGION_HYPER_RAM_BASE_ADDRESS, REGION_RAM_ATTR(REGION_HYPER_RAM_SIZE)), #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(w25q128jw), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(w25q128jw)) MPU_REGION_ENTRY("QSPI_FLASH", REGION_QSPI_FLASH_BASE_ADDRESS, REGION_FLASH_ATTR(REGION_QSPI_FLASH_SIZE)), #endif diff --git a/boards/nxp/mimxrt700_evk/board.c b/boards/nxp/mimxrt700_evk/board.c index 07b66dbaf6057..85b6fc8166687 100644 --- a/boards/nxp/mimxrt700_evk/board.c +++ b/boards/nxp/mimxrt700_evk/board.c @@ -189,29 +189,29 @@ void board_early_init_hook(void) POWER_ApplyPD(); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(edma0), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(edma0)) CLOCK_EnableClock(kCLOCK_Dma0); RESET_ClearPeripheralReset(kDMA0_RST_SHIFT_RSTn); edma_enable_all_request(0); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(edma1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(edma1)) CLOCK_EnableClock(kCLOCK_Dma1); RESET_ClearPeripheralReset(kDMA1_RST_SHIFT_RSTn); edma_enable_all_request(1); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(iocon), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(iocon)) RESET_ClearPeripheralReset(kIOPCTL0_RST_SHIFT_RSTn); CLOCK_EnableClock(kCLOCK_Iopctl0); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(iocon1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(iocon1)) RESET_ClearPeripheralReset(kIOPCTL1_RST_SHIFT_RSTn); CLOCK_EnableClock(kCLOCK_Iopctl1); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(iocon2), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(iocon2)) RESET_ClearPeripheralReset(kIOPCTL2_RST_SHIFT_RSTn); CLOCK_EnableClock(kCLOCK_Iopctl2); #endif @@ -221,203 +221,203 @@ void board_early_init_hook(void) CLOCK_SetClkDiv(kCLOCK_DivFcclk0Clk, 1U); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm0), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm0)) SET_UP_FLEXCOMM_CLOCK(0); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm1)) SET_UP_FLEXCOMM_CLOCK(1); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm2), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm2)) SET_UP_FLEXCOMM_CLOCK(2); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm3), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm3)) SET_UP_FLEXCOMM_CLOCK(3); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm4), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm4)) SET_UP_FLEXCOMM_CLOCK(4); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm5), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm5)) SET_UP_FLEXCOMM_CLOCK(5); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm6), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm6)) SET_UP_FLEXCOMM_CLOCK(6); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm7), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm7)) SET_UP_FLEXCOMM_CLOCK(7); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm8), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm8)) SET_UP_FLEXCOMM_CLOCK(8); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm9), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm9)) SET_UP_FLEXCOMM_CLOCK(9); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm10), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm10)) SET_UP_FLEXCOMM_CLOCK(10); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm11), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm11)) SET_UP_FLEXCOMM_CLOCK(11); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm12), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm12)) SET_UP_FLEXCOMM_CLOCK(12); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm13), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm13)) SET_UP_FLEXCOMM_CLOCK(13); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpspi14), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi14)) CLOCK_AttachClk(kFRO1_DIV1_to_LPSPI14); CLOCK_SetClkDiv(kCLOCK_DivLpspi14Clk, 3U); CLOCK_EnableClock(kCLOCK_LPSpi14); RESET_ClearPeripheralReset(kLPSPI14_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpi2c15), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c15)) CLOCK_AttachClk(kSENSE_BASE_to_LPI2C15); CLOCK_SetClkDiv(kCLOCK_DivLpi2c15Clk, 2U); CLOCK_EnableClock(kCLOCK_LPI2c15); RESET_ClearPeripheralReset(kLPI2C15_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpspi16), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi16)) CLOCK_AttachClk(kFRO0_DIV1_to_LPSPI16); CLOCK_SetClkDiv(kCLOCK_DivLpspi16Clk, 1U); CLOCK_EnableClock(kCLOCK_LPSpi16); RESET_ClearPeripheralReset(kLPSPI16_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm17), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm17)) CLOCK_AttachClk(kSENSE_BASE_to_FLEXCOMM17); CLOCK_SetClkDiv(kCLOCK_DivLPFlexComm17Clk, 4U); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm18), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm18)) CLOCK_AttachClk(kSENSE_BASE_to_FLEXCOMM18); CLOCK_SetClkDiv(kCLOCK_DivLPFlexComm18Clk, 4U); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm19), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm19)) CLOCK_AttachClk(kSENSE_BASE_to_FLEXCOMM19); CLOCK_SetClkDiv(kCLOCK_DivLPFlexComm19Clk, 4U); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexcomm20), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm20)) CLOCK_AttachClk(kSENSE_BASE_to_FLEXCOMM20); CLOCK_SetClkDiv(kCLOCK_DivLPFlexComm20Clk, 4U); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexio), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio)) CLOCK_AttachClk(kFRO0_DIV1_to_FLEXIO); CLOCK_SetClkDiv(kCLOCK_DivFlexioClk, 1U); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio0), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio0)) CLOCK_EnableClock(kCLOCK_Gpio0); RESET_ClearPeripheralReset(kGPIO0_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio1)) CLOCK_EnableClock(kCLOCK_Gpio1); RESET_ClearPeripheralReset(kGPIO1_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio2), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio2)) CLOCK_EnableClock(kCLOCK_Gpio2); RESET_ClearPeripheralReset(kGPIO2_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio3), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio3)) CLOCK_EnableClock(kCLOCK_Gpio3); RESET_ClearPeripheralReset(kGPIO3_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio4), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio4)) CLOCK_EnableClock(kCLOCK_Gpio4); RESET_ClearPeripheralReset(kGPIO4_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio5), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio5)) CLOCK_EnableClock(kCLOCK_Gpio5); RESET_ClearPeripheralReset(kGPIO5_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio6), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio6)) CLOCK_EnableClock(kCLOCK_Gpio6); RESET_ClearPeripheralReset(kGPIO6_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio7), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio7)) CLOCK_EnableClock(kCLOCK_Gpio7); RESET_ClearPeripheralReset(kGPIO7_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio8), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio8)) CLOCK_EnableClock(kCLOCK_Gpio8); RESET_ClearPeripheralReset(kGPIO8_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio9), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio9)) CLOCK_EnableClock(kCLOCK_Gpio9); RESET_ClearPeripheralReset(kGPIO9_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio10), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(gpio10)) CLOCK_EnableClock(kCLOCK_Gpio10); RESET_ClearPeripheralReset(kGPIO10_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer0), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer0)) SET_UP_CTIMER_CLOCK(0); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer1), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer1)) SET_UP_CTIMER_CLOCK(1); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer2), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer2)) SET_UP_CTIMER_CLOCK(2); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer3), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer3)) SET_UP_CTIMER_CLOCK(3); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer4), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer4)) SET_UP_CTIMER_CLOCK(4); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer5), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer5)) SET_UP_CTIMER_CLOCK(5); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer6), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer6)) SET_UP_CTIMER_CLOCK(6); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ctimer7), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ctimer7)) SET_UP_CTIMER_CLOCK(7); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpadc0), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpadc0)) CLOCK_AttachClk(kFRO1_DIV1_to_SENSE_MAIN); CLOCK_AttachClk(kSENSE_BASE_to_ADC); CLOCK_SetClkDiv(kCLOCK_DivAdcClk, 1U); #endif -#if (DT_NODE_HAS_STATUS(DT_NODELABEL(os_timer_cpu0), okay) || \ - DT_NODE_HAS_STATUS(DT_NODELABEL(os_timer_cpu1), okay)) +#if (DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(os_timer_cpu0)) || \ + DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(os_timer_cpu1))) CLOCK_AttachClk(kLPOSC_to_OSTIMER); CLOCK_SetClkDiv(kCLOCK_DivOstimerClk, 1U); #endif @@ -449,7 +449,7 @@ void board_early_init_hook(void) DT_PROP_BY_PHANDLE(DT_NODELABEL(usb0), clocks, clock_frequency)); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc0), okay) && CONFIG_IMX_USDHC +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usdhc0)) && CONFIG_IMX_USDHC /*Make sure USDHC ram buffer has power up*/ POWER_DisablePD(kPDRUNCFG_APD_SDHC0_SRAM); POWER_DisablePD(kPDRUNCFG_PPD_SDHC0_SRAM); @@ -469,7 +469,7 @@ void board_early_init_hook(void) CLOCK_AttachClk(kLPOSC_to_WWDT0); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(sai0), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai0)) /* SAI clock 368.64 / 15 = 24.576MHz */ CLOCK_AttachClk(kAUDIO_PLL_PFD3_to_AUDIO_VDD2); CLOCK_AttachClk(kAUDIO_VDD2_to_SAI012); @@ -477,7 +477,7 @@ void board_early_init_hook(void) RESET_ClearPeripheralReset(kSAI0_RST_SHIFT_RSTn); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(sc_timer), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sc_timer)) CLOCK_AttachClk(kFRO0_DIV6_to_SCT); #endif @@ -537,13 +537,13 @@ void board_early_init_hook(void) RESET_ClearPeripheralReset(kLCDIF_RST_SHIFT_RSTn); #endif -#if (DT_NODE_HAS_STATUS(DT_NODELABEL(i3c2), okay) || \ - DT_NODE_HAS_STATUS(DT_NODELABEL(i3c3), okay)) +#if (DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(i3c2)) || \ + DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(i3c3))) CLOCK_AttachClk(kSENSE_BASE_to_I3C23); CLOCK_SetClkDiv(kCLOCK_DivI3c23Clk, 4U); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(acmp), okay) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(acmp)) CLOCK_EnableClock(kCLOCK_Acmp0); RESET_ClearPeripheralReset(kACMP0_RST_SHIFT_RSTn); #endif From f7ee70f8ce11ed256c419402077e054dbf95ed20 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 21 Oct 2025 11:23:05 +0200 Subject: [PATCH 202/397] dts: bindings: mtd: sifli,sf32lb-mpi-qspi-nor: set qspi bus type This node defines a QSPI bus type. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/mtd/sifli,sf32lb-mpi-qspi-nor.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dts/bindings/mtd/sifli,sf32lb-mpi-qspi-nor.yaml b/dts/bindings/mtd/sifli,sf32lb-mpi-qspi-nor.yaml index 6a81106aa4924..a70e742fd721e 100644 --- a/dts/bindings/mtd/sifli,sf32lb-mpi-qspi-nor.yaml +++ b/dts/bindings/mtd/sifli,sf32lb-mpi-qspi-nor.yaml @@ -7,6 +7,8 @@ compatible: "sifli,sf32lb-mpi-qspi-nor" include: base.yaml +bus: qspi + properties: reg: required: true From df827ef85bf15496cb6125d74ed86c506a272067 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 21 Oct 2025 11:23:57 +0200 Subject: [PATCH 203/397] dts: bindings: mtd: jedec,qspi-nor: set qspi bus This binding is meant to sit on a QSPI bus. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/mtd/jedec,qspi-nor.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dts/bindings/mtd/jedec,qspi-nor.yaml b/dts/bindings/mtd/jedec,qspi-nor.yaml index 79f5ef2aeb0e4..a3d038c0fbf5a 100644 --- a/dts/bindings/mtd/jedec,qspi-nor.yaml +++ b/dts/bindings/mtd/jedec,qspi-nor.yaml @@ -5,4 +5,6 @@ description: Generic NOR flash on QSPI bus compatible: "jedec,qspi-nor" +on-bus: qspi + include: [base.yaml, "jedec,spi-nor-common.yaml"] From be464c4425aa4faba0bb97e8dadf2f48e1e11d3c Mon Sep 17 00:00:00 2001 From: Dan Kalowsky Date: Fri, 17 Oct 2025 18:31:47 -0700 Subject: [PATCH 204/397] MAINTAINERS: move TF-A to non-maintained Former maintainers povergoing and sgrrzhf have not been active for several releases despite attempts to contact them. Instead of keeping PRs and releases gating on having them respond remove them from the maintainers list until they can return. Unfortunately this moves TF-A from maintained to odd fixes. Signed-off-by: Dan Kalowsky --- MAINTAINERS.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 896af776573d4..2176e228089b4 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -6100,10 +6100,7 @@ West: - thrift "West project: trusted-firmware-a": - status: maintained - maintainers: - - povergoing - - sgrrzhf + status: odd fixes collaborators: - wearyzen - ithinuel From 053154da64f954fe9456154b304cb8a47fa45553 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Tue, 14 Oct 2025 09:37:24 +0200 Subject: [PATCH 205/397] samples: basic: blinky: fix readme Update description to match code snippet. Signed-off-by: Adrian Friedli --- samples/basic/blinky/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/basic/blinky/README.rst b/samples/basic/blinky/README.rst index ec23fe5403f14..a67a4b71116d9 100644 --- a/samples/basic/blinky/README.rst +++ b/samples/basic/blinky/README.rst @@ -78,8 +78,8 @@ To add support for your board, add something like this to your devicetree: }; The above sets your board's ``led0`` alias to use pin 13 on GPIO controller -``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_HIGH` mean the LED is on when -the pin is set to its high state, and off when the pin is in its low state. +``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_LOW` mean the LED is on when +the pin is set to its low state, and off when the pin is in its high state. Tips: From 0e6b6f3743dfeeab54b6907e3c05409f679d3f87 Mon Sep 17 00:00:00 2001 From: Alexander Apostolu Date: Fri, 17 Oct 2025 16:15:46 -0400 Subject: [PATCH 206/397] include: zephyr: drivers: sensor.h: updated doxygen for get_frame_count Updated Doxygen for sensor_decoder_api.get_frame_count(). * Reworded grammar * Changed channel to chan_spec to reflect data type * Changed return value from ENOTSUP to EINVAL to be consistent with sensor_decoder_api.decode() Signed-off-by: Alexander Apostolu --- include/zephyr/drivers/sensor.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 2e92f100542f4..1ebd5d255477e 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -489,15 +489,16 @@ static inline bool sensor_chan_spec_eq(struct sensor_chan_spec chan_spec0, */ struct sensor_decoder_api { /** - * @brief Get the number of frames in the current buffer. + * @brief Get the @p frame_count for a specified @p chan_spec from the @p buffer * - * @param[in] buffer The buffer provided on the @ref rtio context. - * @param[in] channel The channel to get the count for - * @param[out] frame_count The number of frames on the buffer (at least 1) - * @return 0 on success - * @return -ENOTSUP if the channel/channel_idx aren't found + * @param[in] buffer The buffer provided via the @ref rtio context + * @param[in] chan_spec The channel specification to count + * @param[out] frame_count The frame count for a specified @p chan_spec + * + * @retval 0 On success + * @retval -EINVAL Invalid channel specification */ - int (*get_frame_count)(const uint8_t *buffer, struct sensor_chan_spec channel, + int (*get_frame_count)(const uint8_t *buffer, struct sensor_chan_spec chan_spec, uint16_t *frame_count); /** From 026b82cb7b816393ffbff7b3209da397ce84611a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 18 Oct 2025 06:53:28 -0400 Subject: [PATCH 207/397] lib: move cpu_load into lib/os Move cpu_load to lib/os, as this functionality on its own does not justify being a subsystem on its own. Fixes #95498 Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 2 -- doc/services/cpu_freq/policies/on_demand.rst | 2 +- doc/services/cpu_load/index.rst | 2 +- include/zephyr/{cpu_load => sys}/cpu_load.h | 0 lib/os/CMakeLists.txt | 1 + lib/os/Kconfig | 1 + {subsys => lib/os}/cpu_load/CMakeLists.txt | 0 {subsys => lib/os}/cpu_load/Kconfig | 4 ++-- {subsys => lib/os}/cpu_load/cpu_load.c | 0 subsys/CMakeLists.txt | 1 - subsys/Kconfig | 1 - subsys/cpu_freq/policies/on_demand/on_demand.c | 2 +- 12 files changed, 7 insertions(+), 9 deletions(-) rename include/zephyr/{cpu_load => sys}/cpu_load.h (100%) rename {subsys => lib/os}/cpu_load/CMakeLists.txt (100%) rename {subsys => lib/os}/cpu_load/Kconfig (87%) rename {subsys => lib/os}/cpu_load/cpu_load.c (100%) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 2176e228089b4..0a996a1d7253f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -855,8 +855,6 @@ CPU Frequency Scaling: - seankyer files: - include/zephyr/cpu_freq/ - - include/zephyr/cpu_load/ - - subsys/cpu_load/ - subsys/cpu_freq/ - dts/bindings/p_state/ labels: diff --git a/doc/services/cpu_freq/policies/on_demand.rst b/doc/services/cpu_freq/policies/on_demand.rst index ea1d3e15b093a..63026bc454715 100644 --- a/doc/services/cpu_freq/policies/on_demand.rst +++ b/doc/services/cpu_freq/policies/on_demand.rst @@ -4,7 +4,7 @@ On-Demand CPU Frequency Scaling Policy ###################################### The On-Demand policy evaluates the current CPU load using the -:ref:`CPU Load subsystem `, and compares it to the trigger threshold defined by the +:ref:`CPU Load metric `, and compares it to the trigger threshold defined by the SoC P-state definition. The On-Demand policy will iterate through the defined P-states and select the first P-state of which diff --git a/doc/services/cpu_load/index.rst b/doc/services/cpu_load/index.rst index 68fb257ebba20..5ed96621a05ee 100644 --- a/doc/services/cpu_load/index.rst +++ b/doc/services/cpu_load/index.rst @@ -1,4 +1,4 @@ -.. _cpu_load_subsys: +.. _cpu_load_metric: CPU Load ######## diff --git a/include/zephyr/cpu_load/cpu_load.h b/include/zephyr/sys/cpu_load.h similarity index 100% rename from include/zephyr/cpu_load/cpu_load.h rename to include/zephyr/sys/cpu_load.h diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index 7fc5f23ff4748..c1be6613ab039 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -50,6 +50,7 @@ zephyr_syscall_header_ifdef(CONFIG_FDTABLE zephyr_sources_ifdef(CONFIG_CBPRINTF_COMPLETE cbprintf_complete.c) zephyr_sources_ifdef(CONFIG_CBPRINTF_NANO cbprintf_nano.c) +add_subdirectory_ifdef(CONFIG_CPU_LOAD_METRIC cpu_load) if(NOT CONFIG_PICOLIBC) zephyr_sources(cbprintf.c) diff --git a/lib/os/Kconfig b/lib/os/Kconfig index eb1433e09d1e3..ece806dcdea43 100644 --- a/lib/os/Kconfig +++ b/lib/os/Kconfig @@ -151,5 +151,6 @@ config POWEROFF rsource "Kconfig.cbprintf" rsource "zvfs/Kconfig" +rsource "cpu_load/Kconfig" endmenu diff --git a/subsys/cpu_load/CMakeLists.txt b/lib/os/cpu_load/CMakeLists.txt similarity index 100% rename from subsys/cpu_load/CMakeLists.txt rename to lib/os/cpu_load/CMakeLists.txt diff --git a/subsys/cpu_load/Kconfig b/lib/os/cpu_load/Kconfig similarity index 87% rename from subsys/cpu_load/Kconfig rename to lib/os/cpu_load/Kconfig index 7772a6695e717..4941cf8b1a47e 100644 --- a/subsys/cpu_load/Kconfig +++ b/lib/os/cpu_load/Kconfig @@ -3,14 +3,14 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig CPU_LOAD_METRIC - bool "CPU Load Subsystem" + bool "CPU Load Metric" select EXPERIMENTAL select THREAD_RUNTIME_STATS select SCHED_THREAD_USAGE select SCHED_THREAD_USAGE_ALL select SCHED_THREAD_USAGE_AUTO_ENABLE help - CPU Load subsystem + Tracking of CPU load statistics. if CPU_LOAD_METRIC diff --git a/subsys/cpu_load/cpu_load.c b/lib/os/cpu_load/cpu_load.c similarity index 100% rename from subsys/cpu_load/cpu_load.c rename to lib/os/cpu_load/cpu_load.c diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 756214ad752d4..979fb92f5f442 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -41,7 +41,6 @@ add_subdirectory_ifdef(CONFIG_BINDESC bindesc) add_subdirectory_ifdef(CONFIG_BT bluetooth) add_subdirectory_ifdef(CONFIG_CONSOLE_SUBSYS console) add_subdirectory_ifdef(CONFIG_CPU_FREQ cpu_freq) -add_subdirectory_ifdef(CONFIG_CPU_LOAD_METRIC cpu_load) add_subdirectory_ifdef(CONFIG_CRC crc) add_subdirectory_ifdef(CONFIG_DAP dap) add_subdirectory_ifdef(CONFIG_DEMAND_PAGING demand_paging) diff --git a/subsys/Kconfig b/subsys/Kconfig index f35a0d1c90680..380c0e5d94439 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -12,7 +12,6 @@ source "subsys/bluetooth/Kconfig" source "subsys/canbus/Kconfig" source "subsys/console/Kconfig" source "subsys/cpu_freq/Kconfig" -source "subsys/cpu_load/Kconfig" source "subsys/crc/Kconfig" source "subsys/dap/Kconfig" source "subsys/debug/Kconfig" diff --git a/subsys/cpu_freq/policies/on_demand/on_demand.c b/subsys/cpu_freq/policies/on_demand/on_demand.c index 41b9b733eabad..1cc1cdec78d62 100644 --- a/subsys/cpu_freq/policies/on_demand/on_demand.c +++ b/subsys/cpu_freq/policies/on_demand/on_demand.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include LOG_MODULE_REGISTER(cpu_freq_policy_on_demand, CONFIG_CPU_FREQ_LOG_LEVEL); From 7a3e6fbc7878cecef72877e73ab2d3707f715f12 Mon Sep 17 00:00:00 2001 From: Lauren Murphy Date: Mon, 29 Sep 2025 14:17:07 -0700 Subject: [PATCH 208/397] soc: intel_adsp: send fwready msg for sim Sends FWREADY message for simulator. Signed-off-by: Lauren Murphy --- soc/intel/intel_adsp/Kconfig | 7 ++ soc/intel/intel_adsp/ace/CMakeLists.txt | 4 + soc/intel/intel_adsp/ace/fw_ready.c | 113 ++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 soc/intel/intel_adsp/ace/fw_ready.c diff --git a/soc/intel/intel_adsp/Kconfig b/soc/intel/intel_adsp/Kconfig index 7523f167fad2e..9987a54c01f9a 100644 --- a/soc/intel/intel_adsp/Kconfig +++ b/soc/intel/intel_adsp/Kconfig @@ -33,6 +33,13 @@ config INTEL_ADSP_SIM_NO_SECONDARY_CORE_FLOW endif # INTEL_ADSP_SIM +config INTEL_ADSP_FWREADY_MSG + bool "Send firmware ready message to host" + default y if INTEL_ADSP_SIM + help + Send a firmware ready message to the host once the system is up + and running. + config INTEL_ADSP_IPC bool "Driver for the host IPC interrupt delivery" select DEPRECATED diff --git a/soc/intel/intel_adsp/ace/CMakeLists.txt b/soc/intel/intel_adsp/ace/CMakeLists.txt index fdc0519da69dd..306746a8f9b30 100644 --- a/soc/intel/intel_adsp/ace/CMakeLists.txt +++ b/soc/intel/intel_adsp/ace/CMakeLists.txt @@ -33,3 +33,7 @@ if (CONFIG_XTENSA_MMU) endif() set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") + +if (CONFIG_INTEL_ADSP_FWREADY_MSG) + zephyr_library_sources(fw_ready.c) +endif() diff --git a/soc/intel/intel_adsp/ace/fw_ready.c b/soc/intel/intel_adsp/ace/fw_ready.c new file mode 100644 index 0000000000000..c2bf1087d1d09 --- /dev/null +++ b/soc/intel/intel_adsp/ace/fw_ready.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +struct ipc_hdr { + uint32_t size; /**< size of structure */ +} __packed __aligned(4); + +struct ipc_cmd_hdr { + uint32_t size; /**< size of structure */ + uint32_t cmd; /**< SOF_IPC_GLB_ + cmd */ +} __packed __aligned(4); + +struct ipc_fw_version { + struct ipc_hdr hdr; + uint16_t major; + uint16_t minor; + uint16_t micro; + uint16_t build; + uint8_t date[12]; + uint8_t time[10]; + uint8_t tag[6]; + uint32_t abi_version; + uint32_t src_hash; + uint32_t reserved[3]; +} __packed __aligned(4); + +struct ipc_fw_ready { + struct ipc_cmd_hdr hdr; + uint32_t dspbox_offset; + uint32_t hostbox_offset; + uint32_t dspbox_size; + uint32_t hostbox_size; + struct ipc_fw_version version; + uint64_t flags; + uint32_t reserved[4]; +} __packed __aligned(4); + +static const struct ipc_fw_ready ready + Z_GENERIC_DOT_SECTION(fw_ready) __used = { + .hdr = { + .cmd = (0x7U << 28), /* SOF_IPC_FW_READY */ + .size = sizeof(struct ipc_fw_ready), + }, + + .version = { + .hdr.size = sizeof(struct ipc_fw_version), + .micro = 0, + .minor = 0, + .major = 0, + + .build = 0xBEEF, + .date = __DATE__, + .time = __TIME__, + + .tag = "zephyr", + .abi_version = 0, + .src_hash = 0, + }, + + .flags = 0, +}; + +#define IPC4_NOTIFY_FW_READY 8 + +#define IPC4_GLB_NOTIFICATION 27 + +#define IPC4_GLB_NOTIFY_DIR_MASK BIT(29) +#define IPC4_REPLY_STATUS_MASK 0xFFFFFF +#define IPC4_GLB_NOTIFY_TYPE_SHIFT 16 +#define IPC4_GLB_NOTIFY_MSG_TYPE_SHIFT 24 + +#define IPC4_FW_READY \ + (((IPC4_NOTIFY_FW_READY) << (IPC4_GLB_NOTIFY_TYPE_SHIFT)) |\ + ((IPC4_GLB_NOTIFICATION) << (IPC4_GLB_NOTIFY_MSG_TYPE_SHIFT))) + +#define SRAM_SW_REG_BASE (L2_SRAM_BASE + 0x4000) +#define SRAM_SW_REG_SIZE 0x1000 + +#define SRAM_OUTBOX_BASE (SRAM_SW_REG_BASE + SRAM_SW_REG_SIZE) +#define SRAM_OUTBOX_SIZE 0x1000 + +int notify_host_boot_complete(void) +{ + memcpy((void *)SRAM_OUTBOX_BASE, &ready, sizeof(ready)); + + sys_cache_data_flush_range((void *)SRAM_OUTBOX_BASE, SRAM_OUTBOX_SIZE); + + intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, + IPC4_FW_READY, 0); + + return 0; +} + +SYS_INIT(notify_host_boot_complete, POST_KERNEL, 0); From a6dc99853d79682c45292c5a5e7959e0acfa2baa Mon Sep 17 00:00:00 2001 From: Lauren Murphy Date: Mon, 29 Sep 2025 14:18:43 -0700 Subject: [PATCH 209/397] boards: intel_adsp/ace: remove kconfig to skip 2nd core flow This removes CONFIG_INTEL_ADSP_SIM_NO_SECONDARY_CORE_FLOW for both ACE15 and ACE30 simulator, as the latest simulator no longer requires this workaround. Signed-off-by: Lauren Murphy --- boards/intel/adsp/intel_adsp_ace15_mtpm_sim_defconfig | 1 - boards/intel/adsp/intel_adsp_ace30_ptl_sim_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/boards/intel/adsp/intel_adsp_ace15_mtpm_sim_defconfig b/boards/intel/adsp/intel_adsp_ace15_mtpm_sim_defconfig index 8c36c0e39dda9..17279c64c5be1 100644 --- a/boards/intel/adsp/intel_adsp_ace15_mtpm_sim_defconfig +++ b/boards/intel/adsp/intel_adsp_ace15_mtpm_sim_defconfig @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_INTEL_ADSP_SIM=y -CONFIG_INTEL_ADSP_SIM_NO_SECONDARY_CORE_FLOW=y CONFIG_GEN_ISR_TABLES=y CONFIG_GEN_IRQ_VECTOR_TABLE=n diff --git a/boards/intel/adsp/intel_adsp_ace30_ptl_sim_defconfig b/boards/intel/adsp/intel_adsp_ace30_ptl_sim_defconfig index 5373f0c0bf841..03a0eff15fcc9 100644 --- a/boards/intel/adsp/intel_adsp_ace30_ptl_sim_defconfig +++ b/boards/intel/adsp/intel_adsp_ace30_ptl_sim_defconfig @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_INTEL_ADSP_SIM=y -CONFIG_INTEL_ADSP_SIM_NO_SECONDARY_CORE_FLOW=y CONFIG_GEN_ISR_TABLES=y CONFIG_GEN_IRQ_VECTOR_TABLE=n From 9bead6231c0bd11d2443fd38be86d59697ff72c8 Mon Sep 17 00:00:00 2001 From: Lauren Murphy Date: Mon, 29 Sep 2025 14:20:30 -0700 Subject: [PATCH 210/397] soc: intel_adsp: winstream only if not sim Simulator console will not be used if winstream is selected for simulators. Signed-off-by: Lauren Murphy --- soc/intel/intel_adsp/Kconfig.defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/intel/intel_adsp/Kconfig.defconfig b/soc/intel/intel_adsp/Kconfig.defconfig index 1d8312e7fb6ce..313ab14931293 100644 --- a/soc/intel/intel_adsp/Kconfig.defconfig +++ b/soc/intel/intel_adsp/Kconfig.defconfig @@ -36,7 +36,7 @@ endif # XTENSA_RPO_CACHE config CONSOLE def_bool y -if CONSOLE +if CONSOLE && !SIMULATOR_XTENSA config WINSTREAM_CONSOLE def_bool y endif From 33f136c78dc050d7e285a3187b2d4ff519b73744 Mon Sep 17 00:00:00 2001 From: Lauren Murphy Date: Wed, 15 Oct 2025 10:11:14 -0700 Subject: [PATCH 211/397] boards: intel_adsp: add ace40 sim .dts Adds missing intel_adsp_ace40_nvl_sim.dts. Signed-off-by: Lauren Murphy --- .../intel/adsp/intel_adsp_ace40_nvl_sim.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 boards/intel/adsp/intel_adsp_ace40_nvl_sim.dts diff --git a/boards/intel/adsp/intel_adsp_ace40_nvl_sim.dts b/boards/intel/adsp/intel_adsp_ace40_nvl_sim.dts new file mode 100644 index 0000000000000..312f4b3f8ba97 --- /dev/null +++ b/boards/intel/adsp/intel_adsp_ace40_nvl_sim.dts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "intel_adsp_ace40_nvl_sim"; + compatible = "intel"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &mem_window3; + }; +}; From 236f9acfb64db71af91bb4c3b46bcd1244293ef9 Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sat, 18 Oct 2025 17:38:40 +0200 Subject: [PATCH 212/397] boards: silabs: Remove unused defconfig symbols Remove DCDC defconfigs from Series 2 boards. These have no effect, Series 2 derives DCDC configuration from devicetree. Signed-off-by: Aksel Skauge Mellbye --- boards/silabs/dev_kits/sltb010a/sltb010a_defconfig | 2 -- boards/silabs/dev_kits/xg24_dk2601b/xg24_dk2601b_defconfig | 2 -- boards/silabs/dev_kits/xg24_ek2703a/xg24_ek2703a_defconfig | 2 -- boards/silabs/dev_kits/xg27_dk2602a/xg27_dk2602a_defconfig | 2 -- boards/silabs/radio_boards/xg23_rb4210a/xg23_rb4210a_defconfig | 2 -- 5 files changed, 10 deletions(-) diff --git a/boards/silabs/dev_kits/sltb010a/sltb010a_defconfig b/boards/silabs/dev_kits/sltb010a/sltb010a_defconfig index b7da445368cb1..3f81ba69cff1d 100644 --- a/boards/silabs/dev_kits/sltb010a/sltb010a_defconfig +++ b/boards/silabs/dev_kits/sltb010a/sltb010a_defconfig @@ -5,6 +5,4 @@ CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y CONFIG_GPIO=y -CONFIG_SOC_GECKO_EMU_DCDC=y -CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/silabs/dev_kits/xg24_dk2601b/xg24_dk2601b_defconfig b/boards/silabs/dev_kits/xg24_dk2601b/xg24_dk2601b_defconfig index ea3fbea0c139f..7e2172f28aaeb 100644 --- a/boards/silabs/dev_kits/xg24_dk2601b/xg24_dk2601b_defconfig +++ b/boards/silabs/dev_kits/xg24_dk2601b/xg24_dk2601b_defconfig @@ -8,5 +8,3 @@ CONFIG_SERIAL=y CONFIG_GPIO=y CONFIG_HW_STACK_PROTECTION=y CONFIG_REGULATOR=y -CONFIG_SOC_GECKO_EMU_DCDC=y -CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y diff --git a/boards/silabs/dev_kits/xg24_ek2703a/xg24_ek2703a_defconfig b/boards/silabs/dev_kits/xg24_ek2703a/xg24_ek2703a_defconfig index ea3fbea0c139f..7e2172f28aaeb 100644 --- a/boards/silabs/dev_kits/xg24_ek2703a/xg24_ek2703a_defconfig +++ b/boards/silabs/dev_kits/xg24_ek2703a/xg24_ek2703a_defconfig @@ -8,5 +8,3 @@ CONFIG_SERIAL=y CONFIG_GPIO=y CONFIG_HW_STACK_PROTECTION=y CONFIG_REGULATOR=y -CONFIG_SOC_GECKO_EMU_DCDC=y -CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y diff --git a/boards/silabs/dev_kits/xg27_dk2602a/xg27_dk2602a_defconfig b/boards/silabs/dev_kits/xg27_dk2602a/xg27_dk2602a_defconfig index b7da445368cb1..3f81ba69cff1d 100644 --- a/boards/silabs/dev_kits/xg27_dk2602a/xg27_dk2602a_defconfig +++ b/boards/silabs/dev_kits/xg27_dk2602a/xg27_dk2602a_defconfig @@ -5,6 +5,4 @@ CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y CONFIG_GPIO=y -CONFIG_SOC_GECKO_EMU_DCDC=y -CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/silabs/radio_boards/xg23_rb4210a/xg23_rb4210a_defconfig b/boards/silabs/radio_boards/xg23_rb4210a/xg23_rb4210a_defconfig index d937f7c3052ba..e70f8f5c5197d 100644 --- a/boards/silabs/radio_boards/xg23_rb4210a/xg23_rb4210a_defconfig +++ b/boards/silabs/radio_boards/xg23_rb4210a/xg23_rb4210a_defconfig @@ -5,5 +5,3 @@ CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y CONFIG_GPIO=y -CONFIG_SOC_GECKO_EMU_DCDC=y -CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y From dadd6e0ebeafab1a4859f494ed4a33c79149aa34 Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 18:53:31 +0200 Subject: [PATCH 213/397] soc: silabs: Sort Series 2 dependencies Sort symbol selections for Series 2 SoCs. Signed-off-by: Aksel Skauge Mellbye --- soc/silabs/silabs_s2/xg21/Kconfig | 10 ++++------ soc/silabs/silabs_s2/xg22/Kconfig | 8 ++++---- soc/silabs/silabs_s2/xg23/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg24/Kconfig | 12 ++++++------ soc/silabs/silabs_s2/xg27/Kconfig | 6 +++--- soc/silabs/silabs_s2/xg28/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg29/Kconfig | 12 ++++++------ 7 files changed, 27 insertions(+), 29 deletions(-) diff --git a/soc/silabs/silabs_s2/xg21/Kconfig b/soc/silabs/silabs_s2/xg21/Kconfig index eb393c3c7d1b9..00c0f4445e992 100644 --- a/soc/silabs/silabs_s2/xg21/Kconfig +++ b/soc/silabs/silabs_s2/xg21/Kconfig @@ -3,20 +3,18 @@ config SOC_SILABS_XG21 select ARM - select CPU_CORTEX_M33 select CPU_CORTEX_M_HAS_DWT - select ARMV8_M_DSP - select ARM_TRUSTZONE_M - select CPU_HAS_FPU + select CPU_CORTEX_M33 select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU + select CPU_HAS_FPU + select HAS_PM select HAS_SWO select SOC_GECKO_CMU + select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_DEV_INIT select SOC_GECKO_SE - select HAS_PM config SOC_SERIES_EFR32MG21 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg22/Kconfig b/soc/silabs/silabs_s2/xg22/Kconfig index 3d8fc9d6a3ba6..05f48845c6ae8 100644 --- a/soc/silabs/silabs_s2/xg22/Kconfig +++ b/soc/silabs/silabs_s2/xg22/Kconfig @@ -3,20 +3,20 @@ config SOC_SILABS_XG22 select ARM - select ARMV8_M_DSP select ARM_TRUSTZONE_M + select ARMV8_M_DSP select CPU_CORTEX_M33 select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU select CPU_HAS_FPU + select HAS_PM select HAS_SWO - select SOC_GECKO_GPIO select SOC_GECKO_CMU - select SOC_GECKO_EMU select SOC_GECKO_CORE select SOC_GECKO_DEV_INIT + select SOC_GECKO_EMU + select SOC_GECKO_GPIO select SOC_GECKO_SE - select HAS_PM config SOC_SERIES_EFR32BG22 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg23/Kconfig b/soc/silabs/silabs_s2/xg23/Kconfig index d52bff007194c..9a74f488d735d 100644 --- a/soc/silabs/silabs_s2/xg23/Kconfig +++ b/soc/silabs/silabs_s2/xg23/Kconfig @@ -3,10 +3,10 @@ config SOC_SILABS_XG23 select ARM - select ARMV8_M_DSP select ARM_TRUSTZONE_M - select CPU_CORTEX_M33 + select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT + select CPU_CORTEX_M33 select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU select CPU_HAS_FPU diff --git a/soc/silabs/silabs_s2/xg24/Kconfig b/soc/silabs/silabs_s2/xg24/Kconfig index e42474c1d4857..7ddc2073c05df 100644 --- a/soc/silabs/silabs_s2/xg24/Kconfig +++ b/soc/silabs/silabs_s2/xg24/Kconfig @@ -5,20 +5,20 @@ config SOC_SILABS_XG24 select ARM + select ARM_TRUSTZONE_M + select ARMV8_M_DSP + select CPU_CORTEX_M_HAS_DWT select CPU_CORTEX_M33 - select CPU_HAS_FPU select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU - select CPU_CORTEX_M_HAS_DWT - select ARMV8_M_DSP - select ARM_TRUSTZONE_M + select CPU_HAS_FPU + select HAS_PM select HAS_SWO select SOC_GECKO_CMU + select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_DEV_INIT select SOC_GECKO_SE - select HAS_PM config SOC_SERIES_EFR32MG24 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg27/Kconfig b/soc/silabs/silabs_s2/xg27/Kconfig index 0e277ab26d40d..1fa84284b4b81 100644 --- a/soc/silabs/silabs_s2/xg27/Kconfig +++ b/soc/silabs/silabs_s2/xg27/Kconfig @@ -3,20 +3,20 @@ config SOC_SILABS_XG27 select ARM - select ARMV8_M_DSP select ARM_TRUSTZONE_M + select ARMV8_M_DSP select CPU_CORTEX_M33 select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU select CPU_HAS_FPU + select HAS_PM select HAS_SWO select SOC_GECKO_CMU - select SOC_GECKO_GPIO select SOC_GECKO_CORE select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU + select SOC_GECKO_GPIO select SOC_GECKO_SE - select HAS_PM config SOC_SERIES_EFR32BG27 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg28/Kconfig b/soc/silabs/silabs_s2/xg28/Kconfig index 397a62e8ccc93..f82dd5b4e89d2 100644 --- a/soc/silabs/silabs_s2/xg28/Kconfig +++ b/soc/silabs/silabs_s2/xg28/Kconfig @@ -3,10 +3,10 @@ config SOC_SILABS_XG28 select ARM - select ARMV8_M_DSP select ARM_TRUSTZONE_M - select CPU_CORTEX_M33 + select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT + select CPU_CORTEX_M33 select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU select CPU_HAS_FPU diff --git a/soc/silabs/silabs_s2/xg29/Kconfig b/soc/silabs/silabs_s2/xg29/Kconfig index 58fe9f42a7de3..e8233b7e72454 100644 --- a/soc/silabs/silabs_s2/xg29/Kconfig +++ b/soc/silabs/silabs_s2/xg29/Kconfig @@ -3,20 +3,20 @@ config SOC_SILABS_XG29 select ARM + select ARM_TRUSTZONE_M + select ARMV8_M_DSP + select CPU_CORTEX_M_HAS_DWT select CPU_CORTEX_M33 - select CPU_HAS_FPU select CPU_HAS_ARM_MPU select CPU_HAS_ARM_SAU - select CPU_CORTEX_M_HAS_DWT - select ARMV8_M_DSP - select ARM_TRUSTZONE_M + select CPU_HAS_FPU + select HAS_PM select HAS_SWO select SOC_GECKO_CMU + select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_DEV_INIT select SOC_GECKO_SE - select HAS_PM config SOC_SERIES_EFR32BG29 select SOC_GECKO_HAS_RADIO From 8b12ec5c3cb22365aad9763303c71bc120dfed3b Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 19:11:37 +0200 Subject: [PATCH 214/397] soc: silabs: Move Kconfig symbol for sleeptimer to HAL Kconfig symbols for selecting HAL content should be part of the HAL module integration, not defined in the SoC tree. Define the sleeptimer symbol for WiSeConnect and SiSDK since both use it. In the future, WiSeConnect should include the SiSDK configuration and reuse it instead of redefining everything itself. This is a larger scale refactor that this commit doesn't start tackling. Signed-off-by: Aksel Skauge Mellbye --- drivers/counter/Kconfig.gecko | 2 +- drivers/timer/Kconfig.silabs | 2 +- modules/hal_silabs/simplicity_sdk/CMakeLists.txt | 2 +- modules/hal_silabs/simplicity_sdk/Kconfig | 9 +++++++++ modules/hal_silabs/wiseconnect/CMakeLists.txt | 4 ++-- modules/hal_silabs/wiseconnect/Kconfig | 12 ++++++++++++ soc/silabs/Kconfig | 7 ------- soc/silabs/silabs_siwx91x/Kconfig | 5 ----- 8 files changed, 26 insertions(+), 17 deletions(-) create mode 100644 modules/hal_silabs/wiseconnect/Kconfig diff --git a/drivers/counter/Kconfig.gecko b/drivers/counter/Kconfig.gecko index ded39e296855f..529d2f8b5bf3f 100644 --- a/drivers/counter/Kconfig.gecko +++ b/drivers/counter/Kconfig.gecko @@ -17,7 +17,7 @@ config COUNTER_GECKO_STIMER bool "Silicon Labs Gecko Counter Sleep Timer driver" default y depends on DT_HAS_SILABS_GECKO_STIMER_ENABLED - select SOC_SILABS_SLEEPTIMER + select SILABS_SISDK_SLEEPTIMER help Enable the counter driver for Sleep Timer module for Silicon Labs Gecko chips. diff --git a/drivers/timer/Kconfig.silabs b/drivers/timer/Kconfig.silabs index aa7a013e9c005..f84fa7ec8ccc9 100644 --- a/drivers/timer/Kconfig.silabs +++ b/drivers/timer/Kconfig.silabs @@ -5,7 +5,7 @@ config SILABS_SLEEPTIMER_TIMER bool "Silabs Sleeptimer system clock driver" depends on SOC_FAMILY_SILABS_S2 || SOC_FAMILY_SILABS_SIWX91X depends on DT_HAS_SILABS_GECKO_STIMER_ENABLED - select SOC_SILABS_SLEEPTIMER + select SILABS_SISDK_SLEEPTIMER select TICKLESS_CAPABLE select TIMER_READS_ITS_FREQUENCY_AT_RUNTIME help diff --git a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt index 0c5aae2e48cec..3d00de8672f44 100644 --- a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt +++ b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt @@ -202,7 +202,7 @@ if(NOT SILABS_DEVICE_FAMILY_NUMBER EQUAL "21") endif() # Sleeptimer -if(CONFIG_SOC_SILABS_SLEEPTIMER) +if(CONFIG_SILABS_SISDK_SLEEPTIMER) zephyr_library_sources( ${PERIPHERAL_DIR}/src/sl_hal_sysrtc.c ${SERVICE_DIR}/sleeptimer/src/sl_sleeptimer_hal_rtcc.c diff --git a/modules/hal_silabs/simplicity_sdk/Kconfig b/modules/hal_silabs/simplicity_sdk/Kconfig index 16ba4cb33c813..2a3aca5740b32 100644 --- a/modules/hal_silabs/simplicity_sdk/Kconfig +++ b/modules/hal_silabs/simplicity_sdk/Kconfig @@ -26,6 +26,15 @@ config SILABS_SISDK_TIMER config SILABS_SISDK_VDAC bool "Peripheral HAL for VDAC" +config SILABS_SISDK_SLEEPTIMER + bool + select SOC_GECKO_PRS + select SOC_GECKO_RTCC if $(dt_nodelabel_enabled,rtcc0) + help + Set if the Sleeptimer HAL module is used. + +# Radio + config SILABS_SISDK_RAIL_PA_CURVE_HEADER string "RAIL PA custom curve header file" default "pa_curves_efr32.h" diff --git a/modules/hal_silabs/wiseconnect/CMakeLists.txt b/modules/hal_silabs/wiseconnect/CMakeLists.txt index 1edfb7e76d410..ffd7a5847df9f 100644 --- a/modules/hal_silabs/wiseconnect/CMakeLists.txt +++ b/modules/hal_silabs/wiseconnect/CMakeLists.txt @@ -200,7 +200,7 @@ if(CONFIG_SILABS_SIWX91X_NWP) zephyr_include_directories(.) endif() # CONFIG_SILABS_SIWX91X_NWP -if(CONFIG_SOC_SILABS_SLEEPTIMER) +if(CONFIG_SILABS_SISDK_SLEEPTIMER) zephyr_include_directories( ${SISDK_DIR}/platform/service/sleeptimer/inc ${SISDK_DIR}/platform/service/sleeptimer/src @@ -216,7 +216,7 @@ if(CONFIG_SOC_SILABS_SLEEPTIMER) SL_CODE_COMPONENT_SLEEPTIMER=sleeptimer SL_CODE_COMPONENT_HAL_SYSRTC=hal_sysrtc ) -endif() # CONFIG_SOC_SILABS_SLEEPTIMER +endif() # CONFIG_SILABS_SISDK_SLEEPTIMER if(CONFIG_SOC_SIWX91X_PM_BACKEND_PMGR) zephyr_library_sources( diff --git a/modules/hal_silabs/wiseconnect/Kconfig b/modules/hal_silabs/wiseconnect/Kconfig new file mode 100644 index 0000000000000..61c111206bea9 --- /dev/null +++ b/modules/hal_silabs/wiseconnect/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +menu "WiSeConnect configuration" + depends on HAS_SILABS_WISECONNECT + +config SILABS_SISDK_SLEEPTIMER + bool "Sleeptimer service" + help + Set if the Sleeptimer HAL module is used. + +endmenu diff --git a/soc/silabs/Kconfig b/soc/silabs/Kconfig index 1bc6ca673f993..30a6d6cf5681a 100644 --- a/soc/silabs/Kconfig +++ b/soc/silabs/Kconfig @@ -125,13 +125,6 @@ config SOC_GECKO_TRNG help Set if the SoC has a True Random Number Generator (TRNG) module. -config SOC_SILABS_SLEEPTIMER - bool - select SOC_GECKO_PRS - select SOC_GECKO_RTCC if SOC_FAMILY_SILABS_S2 && $(dt_nodelabel_enabled,rtcc0) - help - Set if the Sleeptimer HAL module is used. - config SOC_SILABS_HFXO_MANAGER bool default y if PM && $(dt_nodelabel_enabled,sysrtc0) && $(dt_nodelabel_enabled,hfxo) diff --git a/soc/silabs/silabs_siwx91x/Kconfig b/soc/silabs/silabs_siwx91x/Kconfig index 7deef76782dc8..4c2d53557cfb6 100644 --- a/soc/silabs/silabs_siwx91x/Kconfig +++ b/soc/silabs/silabs_siwx91x/Kconfig @@ -15,11 +15,6 @@ if SOC_FAMILY_SILABS_SIWX91X rsource "*/Kconfig" -config SOC_SILABS_SLEEPTIMER - bool - help - The Sleeptimer HAL module is used for SIWX91X. - config SILABS_SIWX91X_NWP bool "Silabs Network Coprocessor" depends on DT_HAS_SILABS_SIWX91X_NWP_ENABLED From 9c804bf58bd1640ff633a7f76816b857788745ec Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 19:29:09 +0200 Subject: [PATCH 215/397] soc: silabs: Select PM implementation per family directly The indirection through a backend symbol for PM implementation isn't necessary. Define symbol for PM HAL in HAL Kconfig, and leverage it at SoC level. Signed-off-by: Aksel Skauge Mellbye --- drivers/bluetooth/hci/Kconfig | 1 - .../hal_silabs/simplicity_sdk/CMakeLists.txt | 6 ++-- modules/hal_silabs/simplicity_sdk/Kconfig | 19 ++++++++++++ soc/silabs/Kconfig | 30 ------------------- soc/silabs/Kconfig.defconfig | 6 ---- soc/silabs/common/CMakeLists.txt | 6 ++-- soc/silabs/silabs_s2/Kconfig | 9 ++++++ soc/silabs/silabs_s2/Kconfig.defconfig | 12 ++++++++ soc/silabs/silabs_s2/soc.c | 4 +-- 9 files changed, 49 insertions(+), 44 deletions(-) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 294a99baa05b9..21aeeb98ee242 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -156,7 +156,6 @@ config BT_SILABS_EFR32 default y depends on DT_HAS_SILABS_BT_HCI_EFR32_ENABLED depends on ZEPHYR_HAL_SILABS_MODULE_BLOBS || BUILD_ONLY_NO_BLOBS - depends on !PM || SOC_GECKO_PM_BACKEND_PMGR depends on SOC_GECKO_HAS_RADIO select SOC_GECKO_USE_RAIL select PSA_CRYPTO diff --git a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt index 3d00de8672f44..a62396b38cfe3 100644 --- a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt +++ b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt @@ -233,7 +233,7 @@ if(CONFIG_SOC_GECKO_DEV_INIT) endif() # Power Manager -if(CONFIG_SOC_GECKO_PM_BACKEND_PMGR) +if(CONFIG_SILABS_SISDK_POWER_MANAGER) zephyr_library_sources( ${SERVICE_DIR}/power_manager/src/common/sl_power_manager_common.c ${SERVICE_DIR}/power_manager/src/common/sl_power_manager_em4.c @@ -250,7 +250,7 @@ if(CONFIG_SOC_GECKO_PM_BACKEND_PMGR) endif() # HFXO Manager -if(CONFIG_SOC_SILABS_HFXO_MANAGER) +if(CONFIG_SILABS_SISDK_HFXO_MANAGER) zephyr_library_sources( ${SERVICE_DIR}/hfxo_manager/src/sl_hfxo_manager.c ${SERVICE_DIR}/hfxo_manager/src/sl_hfxo_manager_hal_s2.c @@ -260,7 +260,7 @@ if(CONFIG_SOC_SILABS_HFXO_MANAGER) ) endif() -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_DEV_INIT ${COMMON_DIR}/src/sl_slist.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_SLIST ${COMMON_DIR}/src/sl_slist.c) if(CONFIG_SOC_GECKO_CORE) zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_CORE ${COMMON_DIR}/src/sl_core_cortexm.c diff --git a/modules/hal_silabs/simplicity_sdk/Kconfig b/modules/hal_silabs/simplicity_sdk/Kconfig index 2a3aca5740b32..fc96f678b0f2a 100644 --- a/modules/hal_silabs/simplicity_sdk/Kconfig +++ b/modules/hal_silabs/simplicity_sdk/Kconfig @@ -26,6 +26,25 @@ config SILABS_SISDK_TIMER config SILABS_SISDK_VDAC bool "Peripheral HAL for VDAC" +# Utilities + +config SILABS_SISDK_SLIST + bool + +# Services + +config SILABS_SISDK_HFXO_MANAGER + bool "HFXO Manager service" + help + Set if the HFXO Manager HAL module is used. + +config SILABS_SISDK_POWER_MANAGER + bool "Power Manager service" + select SOC_GECKO_EMU + select SILABS_SISDK_SLIST + help + Set if the Power Manager HAL module is used. + config SILABS_SISDK_SLEEPTIMER bool select SOC_GECKO_PRS diff --git a/soc/silabs/Kconfig b/soc/silabs/Kconfig index 30a6d6cf5681a..3ffc9eec1e137 100644 --- a/soc/silabs/Kconfig +++ b/soc/silabs/Kconfig @@ -125,36 +125,6 @@ config SOC_GECKO_TRNG help Set if the SoC has a True Random Number Generator (TRNG) module. -config SOC_SILABS_HFXO_MANAGER - bool - default y if PM && $(dt_nodelabel_enabled,sysrtc0) && $(dt_nodelabel_enabled,hfxo) - help - Set if the HFXO Manager HAL module is used. - -if PM - -config SOC_GECKO_PM_BACKEND_PMGR - bool - depends on SOC_GECKO_DEV_INIT - default y if SOC_FAMILY_SILABS_S2 - help - Implement PM using sl_power_manager service from Gecko SDK - -config SOC_GECKO_PM_BACKEND_EMU - bool - default y if !SOC_GECKO_PM_BACKEND_PMGR - help - Implement PM using direct calls to EMU driver in emlib - -config SOC_SILABS_PM_LOW_INTERRUPT_LATENCY - bool "Low interrupt latency mode" - default y if SOC_GECKO_PM_BACKEND_PMGR - help - Enabling low interrupt latency allows interrupts to be executed - before the high frequency clock is restored after sleep. - -endif # PM - config SOC_GECKO_EMU_DCDC bool "SoC DC/DC regulator" select SOC_GECKO_EMU diff --git a/soc/silabs/Kconfig.defconfig b/soc/silabs/Kconfig.defconfig index a2cf6b7b26dc4..4331ce63884e2 100644 --- a/soc/silabs/Kconfig.defconfig +++ b/soc/silabs/Kconfig.defconfig @@ -13,12 +13,6 @@ config SOC_GECKO_EMU config CORTEX_M_SYSTICK default n if GECKO_BURTC_TIMER -# With sl_power_manager, pm_state_set()'s stack footrpting is noticeably -# large, especially with logs enabled. Since it is called from IDLE task, -# its stack size has to be increased -config IDLE_STACK_SIZE - default 512 if SOC_GECKO_PM_BACKEND_PMGR - configdefault NUM_METAIRQ_PRIORITIES default 1 if BT_SILABS_EFR32 diff --git a/soc/silabs/common/CMakeLists.txt b/soc/silabs/common/CMakeLists.txt index e19ac55906181..3782f46ccf5d7 100644 --- a/soc/silabs/common/CMakeLists.txt +++ b/soc/silabs/common/CMakeLists.txt @@ -2,10 +2,12 @@ if(CONFIG_SOC_FAMILY_SILABS_S0 OR CONFIG_SOC_FAMILY_SILABS_S1) zephyr_sources(soc.c) + zephyr_sources_ifdef(CONFIG_PM soc_power.c) endif() -zephyr_sources_ifdef(CONFIG_SOC_GECKO_PM_BACKEND_EMU soc_power.c) -zephyr_sources_ifdef(CONFIG_SOC_GECKO_PM_BACKEND_PMGR soc_power_pmgr.c) +if(CONFIG_SOC_FAMILY_SILABS_S2) + zephyr_sources_ifdef(CONFIG_PM soc_power_pmgr.c) +endif() zephyr_include_directories(.) diff --git a/soc/silabs/silabs_s2/Kconfig b/soc/silabs/silabs_s2/Kconfig index c617183644a14..57ff65c4d45b8 100644 --- a/soc/silabs/silabs_s2/Kconfig +++ b/soc/silabs/silabs_s2/Kconfig @@ -23,6 +23,15 @@ config SOC_SILABS_IMAGE_PROPERTIES verify the application. If Gecko bootloader is used, the Zephyr application image also needs the data structure. +if PM +config SOC_SILABS_PM_LOW_INTERRUPT_LATENCY + bool "Low interrupt latency mode" + default y + help + Enabling low interrupt latency allows interrupts to be executed + before the high frequency clock is restored after sleep. +endif + rsource "*/Kconfig" config ARM_SECURE_FIRMWARE diff --git a/soc/silabs/silabs_s2/Kconfig.defconfig b/soc/silabs/silabs_s2/Kconfig.defconfig index 339b1df67783c..bc0985026819a 100644 --- a/soc/silabs/silabs_s2/Kconfig.defconfig +++ b/soc/silabs/silabs_s2/Kconfig.defconfig @@ -33,4 +33,16 @@ configdefault ZERO_LATENCY_IRQS configdefault ZERO_LATENCY_LEVELS default 2 +configdefault SILABS_SISDK_HFXO_MANAGER + default y if PM && $(dt_nodelabel_enabled,sysrtc0) && $(dt_nodelabel_enabled,hfxo) + +configdefault SILABS_SISDK_POWER_MANAGER + default y if PM + +# With sl_power_manager, pm_state_set()'s stack footprint is noticeably +# large, especially with logs enabled. Since it is called from IDLE task, +# its stack size has to be increased +configdefault IDLE_STACK_SIZE + default 512 if PM + endif diff --git a/soc/silabs/silabs_s2/soc.c b/soc/silabs/silabs_s2/soc.c index 95d6c78c58282..f9af455d8452b 100644 --- a/soc/silabs/silabs_s2/soc.c +++ b/soc/silabs/silabs_s2/soc.c @@ -34,7 +34,7 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); -#if defined(CONFIG_SOC_SILABS_HFXO_MANAGER) +#if defined(CONFIG_SILABS_SISDK_HFXO_MANAGER) Z_ISR_DECLARE_DIRECT(DT_IRQ(DT_NODELABEL(hfxo), irq), 0, sl_hfxo_manager_irq_handler); #endif @@ -48,7 +48,7 @@ void soc_early_init_hook(void) } sl_clock_manager_init(); - if (IS_ENABLED(CONFIG_SOC_SILABS_HFXO_MANAGER)) { + if (IS_ENABLED(CONFIG_SILABS_SISDK_HFXO_MANAGER)) { sl_hfxo_manager_init_hardware(); sl_hfxo_manager_init(); } From 860def64c8c4236db00b145e6a60218c9e9d2cce Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 19:40:24 +0200 Subject: [PATCH 216/397] soc: silabs: Move Kconfig symbol for clock/device init to HAL Kconfig symbols for selecting HAL content should be part of the HAL module integration, not defined in the SoC tree. Signed-off-by: Aksel Skauge Mellbye --- drivers/clock_control/Kconfig.silabs | 1 + drivers/gpio/gpio_gecko.c | 6 ----- .../hal_silabs/simplicity_sdk/CMakeLists.txt | 22 +++++++++++++------ modules/hal_silabs/simplicity_sdk/Kconfig | 12 ++++++++++ soc/silabs/Kconfig | 10 --------- soc/silabs/silabs_s2/xg21/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg22/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg23/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg24/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg27/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg28/Kconfig | 4 ++-- soc/silabs/silabs_s2/xg29/Kconfig | 4 ++-- 12 files changed, 42 insertions(+), 37 deletions(-) diff --git a/drivers/clock_control/Kconfig.silabs b/drivers/clock_control/Kconfig.silabs index 83926fe465cda..52e8ed7a4b0ed 100644 --- a/drivers/clock_control/Kconfig.silabs +++ b/drivers/clock_control/Kconfig.silabs @@ -5,5 +5,6 @@ config CLOCK_CONTROL_SILABS_SERIES bool "Silicon Labs Series 2+ clock control driver" default y depends on DT_HAS_SILABS_SERIES_CLOCK_ENABLED + select SILABS_SISDK_CLOCK_MANAGER help Enable Silicon Labs Series 2+ Clock Management Unit clock control driver. diff --git a/drivers/gpio/gpio_gecko.c b/drivers/gpio/gpio_gecko.c index a95bed6cbb86d..5f65645bf9691 100644 --- a/drivers/gpio/gpio_gecko.c +++ b/drivers/gpio/gpio_gecko.c @@ -12,9 +12,6 @@ #include #include #include -#ifdef CONFIG_SOC_GECKO_DEV_INIT -#include -#endif #include @@ -391,9 +388,6 @@ DEVICE_DT_DEFINE(DT_INST(0, silabs_gecko_gpio), static int gpio_gecko_common_init(const struct device *dev) { -#ifdef CONFIG_SOC_GECKO_DEV_INIT - CMU_ClockEnable(cmuClock_GPIO, true); -#endif gpio_gecko_common_data.count = 0; IRQ_CONNECT(GPIO_EVEN_IRQn, DT_IRQ_BY_NAME(DT_INST(0, silabs_gecko_gpio), gpio_even, priority), diff --git a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt index a62396b38cfe3..4013f01bec981 100644 --- a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt +++ b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt @@ -175,7 +175,6 @@ zephyr_include_directories( zephyr_compile_definitions( ${SILABS_DEVICE_PART_NUMBER} - SL_CODE_COMPONENT_CLOCK_MANAGER=clock_manager SL_CODE_COMPONENT_DEVICE_PERIPHERAL=peripheral SL_CODE_COMPONENT_HAL_COMMON=hal_common SL_CODE_COMPONENT_SYSTEM=system @@ -184,10 +183,6 @@ zephyr_compile_definitions( zephyr_library_sources( ${DEVICE_DIR}/SiliconLabs/${SILABS_DEVICE_FAMILY}/Source/system_${CONFIG_SOC_SERIES}.c ${EMLIB_DIR}/src/em_system.c - ${SERVICE_DIR}/clock_manager/src/sl_clock_manager.c - ${SERVICE_DIR}/clock_manager/src/sl_clock_manager_hal_s2.c - ${SERVICE_DIR}/clock_manager/src/sl_clock_manager_init.c - ${SERVICE_DIR}/clock_manager/src/sl_clock_manager_init_hal_s2.c ${SERVICE_DIR}/device_manager/devices/sl_device_peripheral_hal_efr32xg${SILABS_DEVICE_FAMILY_NUMBER}.c ${SERVICE_DIR}/device_manager/src/sl_device_clock.c ${SERVICE_DIR}/device_manager/src/sl_device_gpio.c @@ -216,6 +211,20 @@ if(CONFIG_SILABS_SISDK_SLEEPTIMER) ) endif() +# Clock Manager +if(CONFIG_SILABS_SISDK_CLOCK_MANAGER) + zephyr_library_sources( + ${EMLIB_DIR}/src/em_cmu.c + ${SERVICE_DIR}/clock_manager/src/sl_clock_manager.c + ${SERVICE_DIR}/clock_manager/src/sl_clock_manager_hal_s2.c + ${SERVICE_DIR}/clock_manager/src/sl_clock_manager_init.c + ${SERVICE_DIR}/clock_manager/src/sl_clock_manager_init_hal_s2.c + ) + zephyr_compile_definitions( + SL_CODE_COMPONENT_CLOCK_MANAGER=clock_manager + ) +endif() + zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_SYSTEM ${PERIPHERAL_DIR}/src/sl_hal_system.c) #Keep em_iadc.c for compatibility for now. Not used anymore. @@ -223,10 +232,9 @@ zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_IADC ${EMLIB_DIR}/src/e zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_IADC ${PERIPHERAL_DIR}/src/sl_hal_iadc.c) zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_BURTC ${EMLIB_DIR}/src/em_burtc.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_CMU ${EMLIB_DIR}/src/em_cmu.c) # Device Init -if(CONFIG_SOC_GECKO_DEV_INIT) +if(CONFIG_SILABS_SISDK_DEVICE_INIT) zephyr_library_sources_ifdef(CONFIG_DT_HAS_SILABS_SERIES2_DCDC_ENABLED ${SERVICE_DIR}/device_init/src/sl_device_init_dcdc_s2.c ) diff --git a/modules/hal_silabs/simplicity_sdk/Kconfig b/modules/hal_silabs/simplicity_sdk/Kconfig index fc96f678b0f2a..64554a1ee23dc 100644 --- a/modules/hal_silabs/simplicity_sdk/Kconfig +++ b/modules/hal_silabs/simplicity_sdk/Kconfig @@ -33,6 +33,18 @@ config SILABS_SISDK_SLIST # Services +config SILABS_SISDK_CLOCK_MANAGER + bool "Clock Manager service" + help + Set if the Clock Manager HAL module is used. + +config SILABS_SISDK_DEVICE_INIT + bool "Device Init service" + select SOC_GECKO_EMU + help + Use the device initialization routines from the device_init service + in Silicon Labs HAL. + config SILABS_SISDK_HFXO_MANAGER bool "HFXO Manager service" help diff --git a/soc/silabs/Kconfig b/soc/silabs/Kconfig index 3ffc9eec1e137..0ed8e109d9730 100644 --- a/soc/silabs/Kconfig +++ b/soc/silabs/Kconfig @@ -156,16 +156,6 @@ config CRYPTO_ACC_GECKO_TRNG Enable Entropy driver based on the CRYPTO_ACC module for Silicon Labs Gecko chips. -config SOC_GECKO_DEV_INIT - bool - help - Use the device initialization routines from the device_init service - in Silicon Labs HAL. These routines initialize and tune HFXOs, - configures DPLLs and manages the Energy Management Unit. - - Disabling these services may negatively impact counter and timer - routines in Silabs SoCs. - config COUNTER_GECKO_STIMER bool help diff --git a/soc/silabs/silabs_s2/xg21/Kconfig b/soc/silabs/silabs_s2/xg21/Kconfig index 00c0f4445e992..775d2b300fe36 100644 --- a/soc/silabs/silabs_s2/xg21/Kconfig +++ b/soc/silabs/silabs_s2/xg21/Kconfig @@ -10,8 +10,8 @@ config SOC_SILABS_XG21 select CPU_HAS_FPU select HAS_PM select HAS_SWO - select SOC_GECKO_CMU - select SOC_GECKO_DEV_INIT + select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE diff --git a/soc/silabs/silabs_s2/xg22/Kconfig b/soc/silabs/silabs_s2/xg22/Kconfig index 05f48845c6ae8..de8b2f25d5afe 100644 --- a/soc/silabs/silabs_s2/xg22/Kconfig +++ b/soc/silabs/silabs_s2/xg22/Kconfig @@ -11,9 +11,9 @@ config SOC_SILABS_XG22 select CPU_HAS_FPU select HAS_PM select HAS_SWO - select SOC_GECKO_CMU + select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_CORE - select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE diff --git a/soc/silabs/silabs_s2/xg23/Kconfig b/soc/silabs/silabs_s2/xg23/Kconfig index 9a74f488d735d..db0e4ad6b71db 100644 --- a/soc/silabs/silabs_s2/xg23/Kconfig +++ b/soc/silabs/silabs_s2/xg23/Kconfig @@ -12,9 +12,9 @@ config SOC_SILABS_XG23 select CPU_HAS_FPU select HAS_PM select HAS_SWO - select SOC_GECKO_CMU + select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_CORE - select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE diff --git a/soc/silabs/silabs_s2/xg24/Kconfig b/soc/silabs/silabs_s2/xg24/Kconfig index 7ddc2073c05df..1b4bfff9c8aae 100644 --- a/soc/silabs/silabs_s2/xg24/Kconfig +++ b/soc/silabs/silabs_s2/xg24/Kconfig @@ -14,8 +14,8 @@ config SOC_SILABS_XG24 select CPU_HAS_FPU select HAS_PM select HAS_SWO - select SOC_GECKO_CMU - select SOC_GECKO_DEV_INIT + select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE diff --git a/soc/silabs/silabs_s2/xg27/Kconfig b/soc/silabs/silabs_s2/xg27/Kconfig index 1fa84284b4b81..4985d45fc1862 100644 --- a/soc/silabs/silabs_s2/xg27/Kconfig +++ b/soc/silabs/silabs_s2/xg27/Kconfig @@ -11,9 +11,9 @@ config SOC_SILABS_XG27 select CPU_HAS_FPU select HAS_PM select HAS_SWO - select SOC_GECKO_CMU + select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_CORE - select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE diff --git a/soc/silabs/silabs_s2/xg28/Kconfig b/soc/silabs/silabs_s2/xg28/Kconfig index f82dd5b4e89d2..6075ac59d0779 100644 --- a/soc/silabs/silabs_s2/xg28/Kconfig +++ b/soc/silabs/silabs_s2/xg28/Kconfig @@ -12,9 +12,9 @@ config SOC_SILABS_XG28 select CPU_HAS_FPU select HAS_PM select HAS_SWO - select SOC_GECKO_CMU + select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_CORE - select SOC_GECKO_DEV_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE diff --git a/soc/silabs/silabs_s2/xg29/Kconfig b/soc/silabs/silabs_s2/xg29/Kconfig index e8233b7e72454..83d2033dab518 100644 --- a/soc/silabs/silabs_s2/xg29/Kconfig +++ b/soc/silabs/silabs_s2/xg29/Kconfig @@ -12,8 +12,8 @@ config SOC_SILABS_XG29 select CPU_HAS_FPU select HAS_PM select HAS_SWO - select SOC_GECKO_CMU - select SOC_GECKO_DEV_INIT + select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE From aecc87dae86f59f10c881db36a151330e03250a3 Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 19:41:40 +0200 Subject: [PATCH 217/397] soc: silabs: Remove duplicate Kconfig symbol COUNTER_GECKO_STIMER is defined by the counter driver. It should not be present in SoC Kconfig. Signed-off-by: Aksel Skauge Mellbye --- soc/silabs/Kconfig | 6 ------ 1 file changed, 6 deletions(-) diff --git a/soc/silabs/Kconfig b/soc/silabs/Kconfig index 0ed8e109d9730..824d1fa9ba4aa 100644 --- a/soc/silabs/Kconfig +++ b/soc/silabs/Kconfig @@ -156,12 +156,6 @@ config CRYPTO_ACC_GECKO_TRNG Enable Entropy driver based on the CRYPTO_ACC module for Silicon Labs Gecko chips. -config COUNTER_GECKO_STIMER - bool - help - Enable counter driver based on the Sleep Timer driver for Silicon Labs - Gecko chips. - config SOC_GECKO_CMU bool help From dbbb008321d1bc9258e253999ddab279506e365c Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 19:42:50 +0200 Subject: [PATCH 218/397] soc: silabs: Move Series 2 specific TRNG symbol to Series 2 Kconfig CRYPTO_ACC_GECKO_TRNG only applies to Series 2. Don't define it at the top level. Signed-off-by: Aksel Skauge Mellbye --- soc/silabs/Kconfig | 6 ------ soc/silabs/silabs_s2/Kconfig | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/soc/silabs/Kconfig b/soc/silabs/Kconfig index 824d1fa9ba4aa..677a10c4072a7 100644 --- a/soc/silabs/Kconfig +++ b/soc/silabs/Kconfig @@ -150,12 +150,6 @@ choice SOC_GECKO_EMU_DCDC_MODE bool "Bypass" endchoice -config CRYPTO_ACC_GECKO_TRNG - bool - help - Enable Entropy driver based on the CRYPTO_ACC module for Silicon Labs - Gecko chips. - config SOC_GECKO_CMU bool help diff --git a/soc/silabs/silabs_s2/Kconfig b/soc/silabs/silabs_s2/Kconfig index 57ff65c4d45b8..4f03a01b339ae 100644 --- a/soc/silabs/silabs_s2/Kconfig +++ b/soc/silabs/silabs_s2/Kconfig @@ -23,6 +23,12 @@ config SOC_SILABS_IMAGE_PROPERTIES verify the application. If Gecko bootloader is used, the Zephyr application image also needs the data structure. +config CRYPTO_ACC_GECKO_TRNG + bool + help + Enable Entropy driver based on the CRYPTO_ACC module for Silicon Labs + Gecko chips. + if PM config SOC_SILABS_PM_LOW_INTERRUPT_LATENCY bool "Low interrupt latency mode" From 2428a17b8a47ed614564dfe3568e21b7955da84b Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 20:13:32 +0200 Subject: [PATCH 219/397] soc: silabs: Move Kconfig symbol for SE to HAL Move the Kconfig symbol for the SE HAL to hal_silabs. Select the symbol in the entropy driver rather than unconditionally at the SoC level. Signed-off-by: Aksel Skauge Mellbye --- drivers/entropy/Kconfig.gecko | 1 + modules/hal_silabs/simplicity_sdk/CMakeLists.txt | 8 ++++---- modules/hal_silabs/simplicity_sdk/Kconfig | 3 +++ soc/silabs/Kconfig | 5 ----- soc/silabs/silabs_s2/xg21/Kconfig | 1 - soc/silabs/silabs_s2/xg22/Kconfig | 1 - soc/silabs/silabs_s2/xg23/Kconfig | 1 - soc/silabs/silabs_s2/xg24/Kconfig | 1 - soc/silabs/silabs_s2/xg27/Kconfig | 1 - soc/silabs/silabs_s2/xg29/Kconfig | 1 - 10 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/entropy/Kconfig.gecko b/drivers/entropy/Kconfig.gecko index e096cb33a851c..621e82326f8e3 100644 --- a/drivers/entropy/Kconfig.gecko +++ b/drivers/entropy/Kconfig.gecko @@ -19,6 +19,7 @@ config ENTROPY_GECKO_SE default y depends on DT_HAS_SILABS_GECKO_SEMAILBOX_ENABLED select ENTROPY_HAS_DRIVER + select SILABS_SISDK_SE help This option enables the true random number generator driver based on the Secure Element (SE) module. diff --git a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt index 4013f01bec981..9f5e5678f35bb 100644 --- a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt +++ b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt @@ -170,6 +170,7 @@ zephyr_include_directories( ${SERVICE_DIR}/udelay/inc ${SECURITY_DIR}/sl_component/sl_protocol_crypto/src ${SECURITY_DIR}/sl_component/sli_crypto/inc + ${SECURITY_DIR}/sl_component/sli_psec_osal/inc ${BOARD_DIR} ) @@ -328,19 +329,18 @@ zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_EUSART ${EMLIB_DIR}/src/em_e zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_USART ${EMLIB_DIR}/src/em_usart.c) zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_WDOG ${EMLIB_DIR}/src/em_wdog.c) -zephyr_include_directories_ifdef(CONFIG_SOC_GECKO_SE +zephyr_include_directories_ifdef(CONFIG_SILABS_SISDK_SE ${SECURITY_DIR}/sl_component/se_manager/src ${SECURITY_DIR}/sl_component/se_manager/inc - ${SECURITY_DIR}/sl_component/sli_psec_osal/inc ) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_SE +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_SE ${SECURITY_DIR}/sl_component/se_manager/src/sl_se_manager.c ${SECURITY_DIR}/sl_component/se_manager/src/sl_se_manager_util.c ${SECURITY_DIR}/sl_component/se_manager/src/sli_se_manager_mailbox.c ) -zephyr_compile_definitions_ifdef(CONFIG_SOC_GECKO_SE +zephyr_compile_definitions_ifdef(CONFIG_SILABS_SISDK_SE SL_CODE_COMPONENT_SE_MANAGER=se_manager SL_CODE_COMPONENT_PSEC_OSAL=psec_osal ) diff --git a/modules/hal_silabs/simplicity_sdk/Kconfig b/modules/hal_silabs/simplicity_sdk/Kconfig index 64554a1ee23dc..6cc29af7627c3 100644 --- a/modules/hal_silabs/simplicity_sdk/Kconfig +++ b/modules/hal_silabs/simplicity_sdk/Kconfig @@ -20,6 +20,9 @@ config SILABS_SISDK_IADC config SILABS_SISDK_LETIMER bool "Peripheral HAL for LETIMER" +config SILABS_SISDK_SE + bool "Peripheral HAL for SE (Secure Engine)" + config SILABS_SISDK_TIMER bool "Peripheral HAL for TIMER" diff --git a/soc/silabs/Kconfig b/soc/silabs/Kconfig index 677a10c4072a7..298855561d702 100644 --- a/soc/silabs/Kconfig +++ b/soc/silabs/Kconfig @@ -93,11 +93,6 @@ config SOC_GECKO_RTCC help Set if the Real Time Counter and Calendar (RTCC) HAL module is used. -config SOC_GECKO_SE - bool - help - Set if the Secure Element (SE) HAL module is used. - config SOC_GECKO_TIMER bool help diff --git a/soc/silabs/silabs_s2/xg21/Kconfig b/soc/silabs/silabs_s2/xg21/Kconfig index 775d2b300fe36..41d159e94ccea 100644 --- a/soc/silabs/silabs_s2/xg21/Kconfig +++ b/soc/silabs/silabs_s2/xg21/Kconfig @@ -14,7 +14,6 @@ config SOC_SILABS_XG21 select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_SE config SOC_SERIES_EFR32MG21 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg22/Kconfig b/soc/silabs/silabs_s2/xg22/Kconfig index de8b2f25d5afe..966c4e3488b49 100644 --- a/soc/silabs/silabs_s2/xg22/Kconfig +++ b/soc/silabs/silabs_s2/xg22/Kconfig @@ -16,7 +16,6 @@ config SOC_SILABS_XG22 select SOC_GECKO_CORE select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_SE config SOC_SERIES_EFR32BG22 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg23/Kconfig b/soc/silabs/silabs_s2/xg23/Kconfig index db0e4ad6b71db..32270b9ba6d40 100644 --- a/soc/silabs/silabs_s2/xg23/Kconfig +++ b/soc/silabs/silabs_s2/xg23/Kconfig @@ -17,7 +17,6 @@ config SOC_SILABS_XG23 select SOC_GECKO_CORE select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_SE config SOC_SERIES_EFR32ZG23 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg24/Kconfig b/soc/silabs/silabs_s2/xg24/Kconfig index 1b4bfff9c8aae..3a15c9d1c6348 100644 --- a/soc/silabs/silabs_s2/xg24/Kconfig +++ b/soc/silabs/silabs_s2/xg24/Kconfig @@ -18,7 +18,6 @@ config SOC_SILABS_XG24 select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_SE config SOC_SERIES_EFR32MG24 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg27/Kconfig b/soc/silabs/silabs_s2/xg27/Kconfig index 4985d45fc1862..082e1b674b0a7 100644 --- a/soc/silabs/silabs_s2/xg27/Kconfig +++ b/soc/silabs/silabs_s2/xg27/Kconfig @@ -16,7 +16,6 @@ config SOC_SILABS_XG27 select SOC_GECKO_CORE select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_SE config SOC_SERIES_EFR32BG27 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg29/Kconfig b/soc/silabs/silabs_s2/xg29/Kconfig index 83d2033dab518..d6c901aff62f7 100644 --- a/soc/silabs/silabs_s2/xg29/Kconfig +++ b/soc/silabs/silabs_s2/xg29/Kconfig @@ -16,7 +16,6 @@ config SOC_SILABS_XG29 select SILABS_SISDK_DEVICE_INIT select SOC_GECKO_EMU select SOC_GECKO_GPIO - select SOC_GECKO_SE config SOC_SERIES_EFR32BG29 select SOC_GECKO_HAS_RADIO From 88913f4e6910a14c0ec8c08a37eca0d7c3d8edcc Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sun, 19 Oct 2025 20:16:24 +0200 Subject: [PATCH 220/397] soc: silabs: Move Series 2 specific defconfigs to Series 2 Series 2 specific defconfigs for Bluetooth related options should be set in the Series 2 specific defconfig file. Signed-off-by: Aksel Skauge Mellbye --- soc/silabs/Kconfig.defconfig | 12 ------------ soc/silabs/silabs_s2/Kconfig.defconfig | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/soc/silabs/Kconfig.defconfig b/soc/silabs/Kconfig.defconfig index 4331ce63884e2..4bce1fdbe9e51 100644 --- a/soc/silabs/Kconfig.defconfig +++ b/soc/silabs/Kconfig.defconfig @@ -13,16 +13,4 @@ config SOC_GECKO_EMU config CORTEX_M_SYSTICK default n if GECKO_BURTC_TIMER -configdefault NUM_METAIRQ_PRIORITIES - default 1 if BT_SILABS_EFR32 - -if BT_LONG_WQ -configdefault BT_LONG_WQ_STACK_SIZE - # Hidden config item. We require a slightly larger stack than the - # default values are. As of this writing, we have a bit less than - # 200 bytes of headroom for future increases here, before we hit - # the limit again. - default 1600 if BT_ECC -endif - endif diff --git a/soc/silabs/silabs_s2/Kconfig.defconfig b/soc/silabs/silabs_s2/Kconfig.defconfig index bc0985026819a..32f6fbc214ce9 100644 --- a/soc/silabs/silabs_s2/Kconfig.defconfig +++ b/soc/silabs/silabs_s2/Kconfig.defconfig @@ -45,4 +45,16 @@ configdefault SILABS_SISDK_POWER_MANAGER configdefault IDLE_STACK_SIZE default 512 if PM +configdefault NUM_METAIRQ_PRIORITIES + default 1 if BT_SILABS_EFR32 + +if BT_LONG_WQ +configdefault BT_LONG_WQ_STACK_SIZE + # Hidden config item. We require a slightly larger stack than the + # default values are. As of this writing, we have a bit less than + # 200 bytes of headroom for future increases here, before we hit + # the limit again. + default 1600 if BT_ECC +endif + endif From a8a3b8ae4e788cb177d5cb7ccedfb57a29247e83 Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Sat, 18 Oct 2025 17:45:59 +0200 Subject: [PATCH 221/397] soc: silabs: Move Kconfig symbols for HAL selection to HAL The Kconfig symbols for selecting HAL content should be part of the HAL module integration, not defined by the SoC. Split the symbols between the Series 0/1 Gecko HAL and Series 2 SiSDK HAL when moving them. For now, the Series 0/1 HAL symbols retain their name, while new names consistent with the symbols already defined in the module integration layer are used for the Series 2 HAL. Signed-off-by: Aksel Skauge Mellbye --- drivers/comparator/Kconfig.silabs_acmp | 2 +- drivers/dma/Kconfig.silabs | 2 +- drivers/flash/Kconfig.silabs | 2 +- drivers/hwinfo/Kconfig.silabs_series2 | 2 +- drivers/serial/Kconfig.silabs_eusart | 2 +- drivers/serial/Kconfig.silabs_usart | 2 +- drivers/spi/Kconfig.silabs_eusart | 2 +- drivers/spi/Kconfig.silabs_usart | 3 +- drivers/timer/Kconfig.gecko | 2 +- drivers/watchdog/Kconfig.gecko | 3 +- modules/hal_silabs/gecko/Kconfig | 104 ++++++++++++ .../hal_silabs/simplicity_sdk/CMakeLists.txt | 41 +++-- modules/hal_silabs/simplicity_sdk/Kconfig | 54 +++++- soc/silabs/Kconfig | 157 +++--------------- soc/silabs/Kconfig.defconfig | 2 +- soc/silabs/silabs_s2/xg21/Kconfig | 6 +- soc/silabs/silabs_s2/xg22/Kconfig | 5 +- soc/silabs/silabs_s2/xg23/Kconfig | 5 +- soc/silabs/silabs_s2/xg24/Kconfig | 4 +- soc/silabs/silabs_s2/xg27/Kconfig | 5 +- soc/silabs/silabs_s2/xg28/Kconfig | 6 +- soc/silabs/silabs_s2/xg29/Kconfig | 4 +- 22 files changed, 218 insertions(+), 197 deletions(-) diff --git a/drivers/comparator/Kconfig.silabs_acmp b/drivers/comparator/Kconfig.silabs_acmp index db684e91f9b39..79f574b017471 100644 --- a/drivers/comparator/Kconfig.silabs_acmp +++ b/drivers/comparator/Kconfig.silabs_acmp @@ -5,7 +5,7 @@ config COMPARATOR_SILABS_ACMP default y depends on DT_HAS_SILABS_ACMP_ENABLED select PINCTRL - select SOC_SILABS_ACMP + select SILABS_SISDK_ACMP help Enable the comparator driver for the Analog Comparator hardware block present on Silicon Labs devices. This block is commonly used to diff --git a/drivers/dma/Kconfig.silabs b/drivers/dma/Kconfig.silabs index 54d617b4ab743..f6f1d2086c3cd 100644 --- a/drivers/dma/Kconfig.silabs +++ b/drivers/dma/Kconfig.silabs @@ -5,7 +5,7 @@ config DMA_SILABS_LDMA bool "Silabs DMA driver" default y select SYS_MEM_BLOCKS - select SOC_GECKO_LDMA + select SILABS_SISDK_LDMA depends on DT_HAS_SILABS_LDMA_ENABLED help Driver for Silabs DMA. diff --git a/drivers/flash/Kconfig.silabs b/drivers/flash/Kconfig.silabs index 5890f98ed340f..2f36eb5699317 100644 --- a/drivers/flash/Kconfig.silabs +++ b/drivers/flash/Kconfig.silabs @@ -7,7 +7,7 @@ config SOC_FLASH_SILABS_S2 depends on DT_HAS_SILABS_SERIES2_FLASH_CONTROLLER_ENABLED select FLASH_HAS_DRIVER_ENABLED select FLASH_HAS_PAGE_LAYOUT - select SOC_GECKO_MSC + select SILABS_SISDK_MSC select FLASH_HAS_EXPLICIT_ERASE select MPU_ALLOW_FLASH_WRITE if ARM_MPU help diff --git a/drivers/hwinfo/Kconfig.silabs_series2 b/drivers/hwinfo/Kconfig.silabs_series2 index d898f94afbd87..0d5b7864a6aa3 100644 --- a/drivers/hwinfo/Kconfig.silabs_series2 +++ b/drivers/hwinfo/Kconfig.silabs_series2 @@ -6,6 +6,6 @@ config HWINFO_SILABS_S2 default y depends on SOC_FAMILY_SILABS_S2 select HWINFO_HAS_DRIVER - select SOC_GECKO_RMU + select SILABS_SISDK_RMU help Enable Silabs Series 2 hwinfo driver. diff --git a/drivers/serial/Kconfig.silabs_eusart b/drivers/serial/Kconfig.silabs_eusart index e13d80d37ec69..0d206f6624327 100644 --- a/drivers/serial/Kconfig.silabs_eusart +++ b/drivers/serial/Kconfig.silabs_eusart @@ -8,7 +8,7 @@ config UART_SILABS_EUSART depends on DT_HAS_SILABS_EUSART_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT - select SOC_GECKO_EUSART + select SILABS_SISDK_EUSART select SERIAL_SUPPORT_ASYNC \ if DT_HAS_SILABS_LDMA_ENABLED select DMA if UART_ASYNC_API diff --git a/drivers/serial/Kconfig.silabs_usart b/drivers/serial/Kconfig.silabs_usart index a2088577d42af..6d0a9318929f6 100644 --- a/drivers/serial/Kconfig.silabs_usart +++ b/drivers/serial/Kconfig.silabs_usart @@ -7,7 +7,7 @@ config UART_SILABS_USART depends on DT_HAS_SILABS_USART_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT - select SOC_GECKO_USART + select SILABS_SISDK_USART select SERIAL_SUPPORT_ASYNC \ if DT_HAS_SILABS_LDMA_ENABLED select DMA if UART_ASYNC_API diff --git a/drivers/spi/Kconfig.silabs_eusart b/drivers/spi/Kconfig.silabs_eusart index a2644fd13ed8e..408f2460eecdf 100644 --- a/drivers/spi/Kconfig.silabs_eusart +++ b/drivers/spi/Kconfig.silabs_eusart @@ -9,7 +9,7 @@ config SPI_SILABS_EUSART default y depends on DT_HAS_SILABS_EUSART_SPI_ENABLED depends on GPIO - select SOC_GECKO_EUSART + select SILABS_SISDK_EUSART select PINCTRL if SOC_FAMILY_SILABS_S2 help Enable the EUSART SPI driver diff --git a/drivers/spi/Kconfig.silabs_usart b/drivers/spi/Kconfig.silabs_usart index 23a93a5784720..2ad5843bdd983 100644 --- a/drivers/spi/Kconfig.silabs_usart +++ b/drivers/spi/Kconfig.silabs_usart @@ -8,7 +8,8 @@ config SPI_SILABS_USART default y depends on DT_HAS_SILABS_USART_SPI_ENABLED depends on GPIO - select SOC_GECKO_USART + select SOC_GECKO_USART if SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 + select SILABS_SISDK_USART if SOC_FAMILY_SILABS_S2 select CLOCK_CONTROL_SILABS_SERIES if SOC_FAMILY_SILABS_S2 select PINCTRL if SOC_FAMILY_SILABS_S2 help diff --git a/drivers/timer/Kconfig.gecko b/drivers/timer/Kconfig.gecko index cd53f9977b5cc..80f4dc22ae676 100644 --- a/drivers/timer/Kconfig.gecko +++ b/drivers/timer/Kconfig.gecko @@ -5,7 +5,7 @@ config GECKO_BURTC_TIMER bool "SiLabs Gecko BURTC system clock driver" depends on SOC_FAMILY_SILABS_S2 depends on DT_HAS_SILABS_GECKO_BURTC_ENABLED - select SOC_GECKO_BURTC + select SILABS_SISDK_BURTC select TICKLESS_CAPABLE select TIMER_READS_ITS_FREQUENCY_AT_RUNTIME help diff --git a/drivers/watchdog/Kconfig.gecko b/drivers/watchdog/Kconfig.gecko index 55fbd7b8e1755..e0b55fac846cd 100644 --- a/drivers/watchdog/Kconfig.gecko +++ b/drivers/watchdog/Kconfig.gecko @@ -10,6 +10,7 @@ config WDT_GECKO default y depends on DT_HAS_SILABS_GECKO_WDOG_ENABLED select HAS_WDT_DISABLE_AT_BOOT - select SOC_GECKO_WDOG + select SOC_GECKO_WDOG if SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 + select SILABS_SISDK_WDOG if SOC_FAMILY_SILABS_S2 help Enable WDOG driver for Silicon Labs Gecko MCUs. diff --git a/modules/hal_silabs/gecko/Kconfig b/modules/hal_silabs/gecko/Kconfig index 12c74f17c16ac..f04f07ce35013 100644 --- a/modules/hal_silabs/gecko/Kconfig +++ b/modules/hal_silabs/gecko/Kconfig @@ -12,4 +12,108 @@ config SILABS_GECKO_RAIL_MULTIPROTOCOL coexistence and arbitration between multiple wireless protocols (for example, Bluetooth LE and a proprietary 2.4 GHz stack) on Gecko SoCs. +config SOC_GECKO_CMU + bool + help + Set if the clock management unit (CMU) HAL module is used. + +config SOC_GECKO_BURTC + bool + help + Set if the Back-Up Real Time Counter (BURTC) HAL module is used. + +config SOC_GECKO_CORE + bool + default y + help + Set if the Core interrupt handling (CORE) HAL module is used. + +config SOC_GECKO_ADC + bool + help + Set if the Analog to Digital Converter (ADC) HAL module is used. + +config SOC_GECKO_CRYOTIMER + bool + help + Set if the Ultra Low Energy Timer/Counter (CRYOTIMER) HAL module is used. + +config SOC_GECKO_EMU + bool + help + Set if the Energy Management Unit (EMU) HAL module is used. + +config SOC_GECKO_GPIO + bool + help + Set if the General Purpose Input/Output (GPIO) HAL module is used. + +config SOC_GECKO_I2C + bool + help + Set if the Inter-Integrated Circuit Interface (I2C) HAL module is used. + +config SOC_GECKO_LETIMER + bool + help + Set if the Low Energy Timer (LETIMER) HAL module is used. + +config SOC_GECKO_LEUART + bool + help + Set if the Low Energy Universal Asynchronous Receiver/Transmitter (LEUART) + HAL module is used. + +config SOC_GECKO_MSC + bool + help + Set if the Memory System Controller (MSC) HAL module is used. + +config SOC_GECKO_PRS + bool + help + Set if the Peripheral Reflex System (PRS) HAL module is used. + +config SOC_GECKO_RMU + bool + help + Set if the Reset Management Unit (RMU) HAL module is used. + +config SOC_GECKO_RTC + bool + help + Set if the Real Time Counter (RTC) HAL module is used. + +config SOC_GECKO_RTCC + bool + help + Set if the Real Time Counter and Calendar (RTCC) HAL module is used. + +config SOC_GECKO_TIMER + bool + help + Set if the Timer/Counter (TIMER) HAL module is used. + +config SOC_GECKO_USART + bool + help + Set if the Universal Synchronous Asynchronous Receiver/Transmitter (USART) + HAL module is used. + +config SOC_GECKO_EUSART + bool + help + Set if the Extended Universal Synchronous Asynchronous Receiver/Transmitter (EUSART) + HAL module is used. + +config SOC_GECKO_WDOG + bool + help + Set if the Watchdog Timer (WDOG) HAL module is used. + +config SOC_GECKO_TRNG + bool + help + Set if the SoC has a True Random Number Generator (TRNG) module. + endmenu diff --git a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt index 9f5e5678f35bb..68f3bf0fc8716 100644 --- a/modules/hal_silabs/simplicity_sdk/CMakeLists.txt +++ b/modules/hal_silabs/simplicity_sdk/CMakeLists.txt @@ -232,7 +232,7 @@ zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_SYSTEM ${PERIPHERAL_DIR zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_IADC ${EMLIB_DIR}/src/em_iadc.c) zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_IADC ${PERIPHERAL_DIR}/src/sl_hal_iadc.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_BURTC ${EMLIB_DIR}/src/em_burtc.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_BURTC ${EMLIB_DIR}/src/em_burtc.c) # Device Init if(CONFIG_SILABS_SISDK_DEVICE_INIT) @@ -253,7 +253,7 @@ if(CONFIG_SILABS_SISDK_POWER_MANAGER) SL_CATALOG_POWER_MANAGER_PRESENT SL_CODE_COMPONENT_POWER_MANAGER=power_manager ) - zephyr_compile_definitions_ifdef(CONFIG_SOC_GECKO_RTCC + zephyr_compile_definitions_ifdef(CONFIG_SILABS_SISDK_RTCC SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT ) endif() @@ -270,18 +270,18 @@ if(CONFIG_SILABS_SISDK_HFXO_MANAGER) endif() zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_SLIST ${COMMON_DIR}/src/sl_slist.c) -if(CONFIG_SOC_GECKO_CORE) - zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_CORE + +if(CONFIG_SILABS_SISDK_CORE) + zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_CORE ${COMMON_DIR}/src/sl_core_cortexm.c ) zephyr_compile_definitions( SL_CODE_COMPONENT_CORE=core ) endif() -zephyr_library_sources_ifdef(CONFIG_SOC_SILABS_ACMP ${EMLIB_DIR}/src/em_acmp.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_CRYOTIMER ${EMLIB_DIR}/src/em_cryotimer.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_EMU ${EMLIB_DIR}/src/em_emu.c) -if(CONFIG_SOC_GECKO_GPIO) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_ACMP ${EMLIB_DIR}/src/em_acmp.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_EMU ${EMLIB_DIR}/src/em_emu.c) +if(CONFIG_SILABS_SISDK_GPIO) zephyr_library_sources( ${EMLIB_DIR}/src/em_gpio.c ${DRIVER_DIR}/gpio/src/sl_gpio.c @@ -315,19 +315,18 @@ zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_LETIMER ${PERIPHERAL_DIR}/src zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_TIMER ${PERIPHERAL_DIR}/src/sl_hal_timer.c) zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_VDAC ${PERIPHERAL_DIR}/src/sl_hal_vdac.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_LDMA ${EMDRV_DIR}/dmadrv/src/dmadrv.c) - -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_I2C ${EMLIB_DIR}/src/em_i2c.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_LEUART ${EMLIB_DIR}/src/em_leuart.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_MSC ${EMLIB_DIR}/src/em_msc.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_LDMA ${EMLIB_DIR}/src/em_ldma.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_PRS ${EMLIB_DIR}/src/em_prs.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_RMU ${EMLIB_DIR}/src/em_rmu.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_RTC ${EMLIB_DIR}/src/em_rtc.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_RTCC ${EMLIB_DIR}/src/em_rtcc.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_EUSART ${EMLIB_DIR}/src/em_eusart.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_USART ${EMLIB_DIR}/src/em_usart.c) -zephyr_library_sources_ifdef(CONFIG_SOC_GECKO_WDOG ${EMLIB_DIR}/src/em_wdog.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_LDMA + ${EMDRV_DIR}/dmadrv/src/dmadrv.c + ${EMLIB_DIR}/src/em_ldma.c +) + +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_MSC ${EMLIB_DIR}/src/em_msc.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_PRS ${EMLIB_DIR}/src/em_prs.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_RMU ${EMLIB_DIR}/src/em_rmu.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_RTCC ${EMLIB_DIR}/src/em_rtcc.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_EUSART ${EMLIB_DIR}/src/em_eusart.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_USART ${EMLIB_DIR}/src/em_usart.c) +zephyr_library_sources_ifdef(CONFIG_SILABS_SISDK_WDOG ${EMLIB_DIR}/src/em_wdog.c) zephyr_include_directories_ifdef(CONFIG_SILABS_SISDK_SE ${SECURITY_DIR}/sl_component/se_manager/src diff --git a/modules/hal_silabs/simplicity_sdk/Kconfig b/modules/hal_silabs/simplicity_sdk/Kconfig index 6cc29af7627c3..3ad364481296e 100644 --- a/modules/hal_silabs/simplicity_sdk/Kconfig +++ b/modules/hal_silabs/simplicity_sdk/Kconfig @@ -4,12 +4,26 @@ menu "SiSDK configuration" depends on HAS_SILABS_SISDK +# Peripherals + +config SILABS_SISDK_ACMP + bool "Peripheral HAL for ACMP" + +config SILABS_SISDK_BURTC + bool "Peripheral HAL for BURTC" + +config SILABS_SISDK_CORE + bool "Peripheral HAL for CORE" + +config SILABS_SISDK_EMU + bool "Peripheral HAL for EMU" + +config SILABS_SISDK_EUSART + bool "Peripheral HAL for EUSART" + config SILABS_SISDK_GPIO bool "Peripheral HAL for GPIO" -config SILABS_SISDK_SYSTEM - bool "Peripheral HAL for SYSTEM (device info)" - config SILABS_SISDK_I2C bool "Peripheral HAL for I2C" @@ -17,18 +31,42 @@ config SILABS_SISDK_IADC bool "Peripheral HAL for IADC" select SILABS_SISDK_SYSTEM +config SILABS_SISDK_LDMA + bool "Peripheral HAL for LDMA" + config SILABS_SISDK_LETIMER bool "Peripheral HAL for LETIMER" +config SILABS_SISDK_MSC + bool "Peripheral HAL for MSC" + +config SILABS_SISDK_PRS + bool "Peripheral HAL for PRS" + +config SILABS_SISDK_RMU + bool "Peripheral HAL for RMU" + +config SILABS_SISDK_RTCC + bool "Peripheral HAL for RTCC" + config SILABS_SISDK_SE bool "Peripheral HAL for SE (Secure Engine)" +config SILABS_SISDK_SYSTEM + bool "Peripheral HAL for SYSTEM (device info)" + config SILABS_SISDK_TIMER bool "Peripheral HAL for TIMER" +config SILABS_SISDK_USART + bool "Peripheral HAL for USART" + config SILABS_SISDK_VDAC bool "Peripheral HAL for VDAC" +config SILABS_SISDK_WDOG + bool "Peripheral HAL for WDOG" + # Utilities config SILABS_SISDK_SLIST @@ -43,7 +81,7 @@ config SILABS_SISDK_CLOCK_MANAGER config SILABS_SISDK_DEVICE_INIT bool "Device Init service" - select SOC_GECKO_EMU + select SILABS_SISDK_EMU help Use the device initialization routines from the device_init service in Silicon Labs HAL. @@ -55,15 +93,15 @@ config SILABS_SISDK_HFXO_MANAGER config SILABS_SISDK_POWER_MANAGER bool "Power Manager service" - select SOC_GECKO_EMU + select SILABS_SISDK_EMU select SILABS_SISDK_SLIST help Set if the Power Manager HAL module is used. config SILABS_SISDK_SLEEPTIMER - bool - select SOC_GECKO_PRS - select SOC_GECKO_RTCC if $(dt_nodelabel_enabled,rtcc0) + bool "Sleeptimer service" + select SILABS_SISDK_PRS + select SILABS_SISDK_RTCC if $(dt_nodelabel_enabled,rtcc0) help Set if the Sleeptimer HAL module is used. diff --git a/soc/silabs/Kconfig b/soc/silabs/Kconfig index 298855561d702..b752b3a4b9712 100644 --- a/soc/silabs/Kconfig +++ b/soc/silabs/Kconfig @@ -4,121 +4,33 @@ rsource "*/Kconfig" -if SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 || SOC_FAMILY_SILABS_S2 +if SOC_FAMILY_SILABS_S1 || SOC_FAMILY_SILABS_S2 -config SOC_GECKO_BURTC - bool - help - Set if the Back-Up Real Time Counter (BURTC) HAL module is used. - -config SOC_GECKO_CORE - bool - default y - help - Set if the Core interrupt handling (CORE) HAL module is used. - -config SOC_SILABS_ACMP - bool - help - Set if the Analog comparator (ACMP) HAL module is used. - -config SOC_GECKO_ADC - bool - help - Set if the Analog to Digital Converter (ADC) HAL module is used. - -config SOC_GECKO_IADC - bool - help - Set if the Incremental Analog to Digital Converter (IADC) HAL module is used. - -config SOC_GECKO_CRYOTIMER - bool - help - Set if the Ultra Low Energy Timer/Counter (CRYOTIMER) HAL module is used. - -config SOC_GECKO_EMU - bool - help - Set if the Energy Management Unit (EMU) HAL module is used. - -config SOC_GECKO_GPIO - bool - help - Set if the General Purpose Input/Output (GPIO) HAL module is used. - -config SOC_GECKO_I2C - bool - help - Set if the Inter-Integrated Circuit Interface (I2C) HAL module is used. - -config SOC_GECKO_LETIMER - bool - help - Set if the Low Energy Timer (LETIMER) HAL module is used. - -config SOC_GECKO_LEUART - bool - help - Set if the Low Energy Universal Asynchronous Receiver/Transmitter (LEUART) - HAL module is used. - -config SOC_GECKO_LDMA - bool - help - Set if the Linked Direct Memory Access (LDMA) HAL module is used. - -config SOC_GECKO_MSC - bool - help - Set if the Memory System Controller (MSC) HAL module is used. - -config SOC_GECKO_PRS - bool - help - Set if the Peripheral Reflex System (PRS) HAL module is used. - -config SOC_GECKO_RMU - bool - help - Set if the Reset Management Unit (RMU) HAL module is used. - -config SOC_GECKO_RTC - bool - help - Set if the Real Time Counter (RTC) HAL module is used. - -config SOC_GECKO_RTCC - bool - help - Set if the Real Time Counter and Calendar (RTCC) HAL module is used. - -config SOC_GECKO_TIMER +config SOC_GECKO_HAS_RADIO bool help - Set if the Timer/Counter (TIMER) HAL module is used. + If enabled, indicates that the SoC has a Radio PHY. -config SOC_GECKO_USART - bool +config SOC_GECKO_USE_RAIL + bool "Use RAIL (Radio Abstraction Interface Layer)" + depends on SOC_GECKO_HAS_RADIO help - Set if the Universal Synchronous Asynchronous Receiver/Transmitter (USART) - HAL module is used. + RAIL (Radio Abstraction Interface Layer) is a library needed to use the EFR radio + hardware. This option enable the proper set of features to allow to properly compile + with the RAIL blob. -config SOC_GECKO_EUSART - bool +config SOC_GECKO_CUSTOM_RADIO_PHY + bool "Use RAIL for custom radio phy packet sending and receiving" + depends on SOC_GECKO_HAS_RADIO + select SOC_GECKO_USE_RAIL help - Set if the Extended Universal Synchronous Asynchronous Receiver/Transmitter (EUSART) - HAL module is used. + If enabled, RAIL can be used for user generated custom radio phy + management, sending and receiving packets on radio phy. User has + to provide the radio_config.c and radio_config.h files for the phy. -config SOC_GECKO_WDOG - bool - help - Set if the Watchdog Timer (WDOG) HAL module is used. +endif # SOC_FAMILY_SILABS_S1 || SOC_FAMILY_SILABS_S2 -config SOC_GECKO_TRNG - bool - help - Set if the SoC has a True Random Number Generator (TRNG) module. +if SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 config SOC_GECKO_EMU_DCDC bool "SoC DC/DC regulator" @@ -145,13 +57,6 @@ choice SOC_GECKO_EMU_DCDC_MODE bool "Bypass" endchoice -config SOC_GECKO_CMU - bool - help - Set if the clock management unit (CMU) is present in the SoC. - -if SOC_GECKO_CMU && (SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1) - config CMU_NEED_LFXO bool help @@ -205,8 +110,6 @@ config CMU_HFRCO_FREQ the bootloader already configured it properly or the device's default clock source should be used with it's default configuration. -endif # SOC_GECKO_CMU - config SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION bool help @@ -231,26 +134,4 @@ config SOC_GECKO_HAS_HFRCO_FREQRANGE If disabled, indicates that configuration of HFRCO frequency for corresponding SOC is not supported via this field. This is the case for e.g. efm32hg, efm32wg series. -config SOC_GECKO_HAS_RADIO - bool - help - If enabled, indicates that the SoC has a Radio PHY. - -config SOC_GECKO_USE_RAIL - bool "Use RAIL (Radio Abstraction Interface Layer)" - depends on SOC_GECKO_HAS_RADIO - help - RAIL (Radio Abstraction Interface Layer) is a library needed to use the EFR radio - hardware. This option enable the proper set of features to allow to properly compile - with the RAIL blob. - -config SOC_GECKO_CUSTOM_RADIO_PHY - bool "Use RAIL for custom radio phy packet sending and receiving" - depends on SOC_GECKO_HAS_RADIO - select SOC_GECKO_USE_RAIL - help - If enabled, RAIL can be used for user generated custom radio phy - management, sending and receiving packets on radio phy. User has - to provide the radio_config.c and radio_config.h files for the phy. - -endif # SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 || SOC_FAMILY_SILABS_S2 +endif # SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 diff --git a/soc/silabs/Kconfig.defconfig b/soc/silabs/Kconfig.defconfig index 4bce1fdbe9e51..8e08c1667331f 100644 --- a/soc/silabs/Kconfig.defconfig +++ b/soc/silabs/Kconfig.defconfig @@ -3,7 +3,7 @@ rsource "*/Kconfig.defconfig" -if SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 || SOC_FAMILY_SILABS_S2 +if SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 config SOC_GECKO_EMU default y diff --git a/soc/silabs/silabs_s2/xg21/Kconfig b/soc/silabs/silabs_s2/xg21/Kconfig index 41d159e94ccea..23ceb71eb2ea3 100644 --- a/soc/silabs/silabs_s2/xg21/Kconfig +++ b/soc/silabs/silabs_s2/xg21/Kconfig @@ -3,6 +3,8 @@ config SOC_SILABS_XG21 select ARM + select ARM_TRUSTZONE_M + select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select CPU_CORTEX_M33 select CPU_HAS_ARM_MPU @@ -11,9 +13,9 @@ config SOC_SILABS_XG21 select HAS_PM select HAS_SWO select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_CORE select SILABS_SISDK_DEVICE_INIT - select SOC_GECKO_EMU - select SOC_GECKO_GPIO + select SILABS_SISDK_GPIO config SOC_SERIES_EFR32MG21 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg22/Kconfig b/soc/silabs/silabs_s2/xg22/Kconfig index 966c4e3488b49..9de819b5fac28 100644 --- a/soc/silabs/silabs_s2/xg22/Kconfig +++ b/soc/silabs/silabs_s2/xg22/Kconfig @@ -12,10 +12,9 @@ config SOC_SILABS_XG22 select HAS_PM select HAS_SWO select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_CORE select SILABS_SISDK_DEVICE_INIT - select SOC_GECKO_CORE - select SOC_GECKO_EMU - select SOC_GECKO_GPIO + select SILABS_SISDK_GPIO config SOC_SERIES_EFR32BG22 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg23/Kconfig b/soc/silabs/silabs_s2/xg23/Kconfig index 32270b9ba6d40..45181d163dd24 100644 --- a/soc/silabs/silabs_s2/xg23/Kconfig +++ b/soc/silabs/silabs_s2/xg23/Kconfig @@ -13,10 +13,9 @@ config SOC_SILABS_XG23 select HAS_PM select HAS_SWO select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_CORE select SILABS_SISDK_DEVICE_INIT - select SOC_GECKO_CORE - select SOC_GECKO_EMU - select SOC_GECKO_GPIO + select SILABS_SISDK_GPIO config SOC_SERIES_EFR32ZG23 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg24/Kconfig b/soc/silabs/silabs_s2/xg24/Kconfig index 3a15c9d1c6348..952afdbb91df6 100644 --- a/soc/silabs/silabs_s2/xg24/Kconfig +++ b/soc/silabs/silabs_s2/xg24/Kconfig @@ -15,9 +15,9 @@ config SOC_SILABS_XG24 select HAS_PM select HAS_SWO select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_CORE select SILABS_SISDK_DEVICE_INIT - select SOC_GECKO_EMU - select SOC_GECKO_GPIO + select SILABS_SISDK_GPIO config SOC_SERIES_EFR32MG24 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg27/Kconfig b/soc/silabs/silabs_s2/xg27/Kconfig index 082e1b674b0a7..e9c30461807e4 100644 --- a/soc/silabs/silabs_s2/xg27/Kconfig +++ b/soc/silabs/silabs_s2/xg27/Kconfig @@ -12,10 +12,9 @@ config SOC_SILABS_XG27 select HAS_PM select HAS_SWO select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_CORE select SILABS_SISDK_DEVICE_INIT - select SOC_GECKO_CORE - select SOC_GECKO_EMU - select SOC_GECKO_GPIO + select SILABS_SISDK_GPIO config SOC_SERIES_EFR32BG27 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg28/Kconfig b/soc/silabs/silabs_s2/xg28/Kconfig index 6075ac59d0779..214ea020ed6d9 100644 --- a/soc/silabs/silabs_s2/xg28/Kconfig +++ b/soc/silabs/silabs_s2/xg28/Kconfig @@ -13,11 +13,9 @@ config SOC_SILABS_XG28 select HAS_PM select HAS_SWO select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_CORE select SILABS_SISDK_DEVICE_INIT - select SOC_GECKO_CORE - select SOC_GECKO_EMU - select SOC_GECKO_GPIO - select SOC_GECKO_SE + select SILABS_SISDK_GPIO config SOC_SERIES_EFR32ZG28 select SOC_GECKO_HAS_RADIO diff --git a/soc/silabs/silabs_s2/xg29/Kconfig b/soc/silabs/silabs_s2/xg29/Kconfig index d6c901aff62f7..c462750cb3b90 100644 --- a/soc/silabs/silabs_s2/xg29/Kconfig +++ b/soc/silabs/silabs_s2/xg29/Kconfig @@ -13,9 +13,9 @@ config SOC_SILABS_XG29 select HAS_PM select HAS_SWO select SILABS_SISDK_CLOCK_MANAGER + select SILABS_SISDK_CORE select SILABS_SISDK_DEVICE_INIT - select SOC_GECKO_EMU - select SOC_GECKO_GPIO + select SILABS_SISDK_GPIO config SOC_SERIES_EFR32BG29 select SOC_GECKO_HAS_RADIO From 42a089239d7306ba60bd61fec298a0e4aa2047d9 Mon Sep 17 00:00:00 2001 From: Jonas Berg Date: Sat, 18 Oct 2025 23:50:32 +0200 Subject: [PATCH 222/397] boards: shields: Add Adafruit LPS22 pressure sensor shield Product photo from https://learn.adafruit.com/assets/91880 Tested with the command in the index.rst file. Compile testing of the overlay file is done with the samples/sensor/pressure_polling sample. Signed-off-by: Jonas Berg --- boards/shields/adafruit_lps22/Kconfig.shield | 5 ++ .../adafruit_lps22/adafruit_lps22.overlay | 21 ++++++ .../adafruit_lps22/doc/adafruit_lps22.webp | Bin 0 -> 47962 bytes boards/shields/adafruit_lps22/doc/index.rst | 66 ++++++++++++++++++ boards/shields/adafruit_lps22/shield.yml | 10 +++ samples/sensor/pressure_polling/sample.yaml | 2 + 6 files changed, 104 insertions(+) create mode 100644 boards/shields/adafruit_lps22/Kconfig.shield create mode 100644 boards/shields/adafruit_lps22/adafruit_lps22.overlay create mode 100644 boards/shields/adafruit_lps22/doc/adafruit_lps22.webp create mode 100644 boards/shields/adafruit_lps22/doc/index.rst create mode 100644 boards/shields/adafruit_lps22/shield.yml diff --git a/boards/shields/adafruit_lps22/Kconfig.shield b/boards/shields/adafruit_lps22/Kconfig.shield new file mode 100644 index 0000000000000..f89d32183b34e --- /dev/null +++ b/boards/shields/adafruit_lps22/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Jonas Berg +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_ADAFRUIT_LPS22 + def_bool $(shields_list_contains,adafruit_lps22) diff --git a/boards/shields/adafruit_lps22/adafruit_lps22.overlay b/boards/shields/adafruit_lps22/adafruit_lps22.overlay new file mode 100644 index 0000000000000..500ac3a819e97 --- /dev/null +++ b/boards/shields/adafruit_lps22/adafruit_lps22.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Jonas Berg + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + pressure-sensor = &adafruit_lps22; + }; +}; + +&zephyr_i2c { + status = "okay"; + + adafruit_lps22: lps22@5d { + compatible = "st,lps22hb-press"; + status = "okay"; + reg = <0x5d>; + }; +}; diff --git a/boards/shields/adafruit_lps22/doc/adafruit_lps22.webp b/boards/shields/adafruit_lps22/doc/adafruit_lps22.webp new file mode 100644 index 0000000000000000000000000000000000000000..928a8d793c77bf1b3961dc721c238d321bbd14f8 GIT binary patch literal 47962 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≺&AOfr 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 literal 0 HcmV?d00001 diff --git a/boards/shields/adafruit_lps22/doc/index.rst b/boards/shields/adafruit_lps22/doc/index.rst new file mode 100644 index 0000000000000..f52b5d0540d82 --- /dev/null +++ b/boards/shields/adafruit_lps22/doc/index.rst @@ -0,0 +1,66 @@ +.. _adafruit_lps22: + +Adafruit LPS22 Shield +##################### + +Overview +******** + +The `Adafruit LPS22 Pressure Sensor Shield`_ features +a `ST Microelectronics LPS22HB Pressure Sensor`_ and two STEMMA QT connectors. +It measures air pressure and temperature. + +.. figure:: adafruit_lps22.webp + :align: center + :alt: Adafruit LPS22 Shield + + Adafruit LPS22 Shield (Credit: Adafruit) + + +Requirements +************ + +This shield can be used with boards which provide an I2C connector, for +example STEMMA QT or Qwiic connectors. +The target board must define a ``zephyr_i2c`` node label. +See :ref:`shields` for more details. + + +Pin Assignments +=============== + ++--------------+-------------------------------------+ +| Shield Pin | Function | ++==============+=====================================+ +| SCK | LPS22 I2C SCL | ++--------------+-------------------------------------+ +| SDI | LPS22 I2C SDA | ++--------------+-------------------------------------+ +| SDO | LPS22 I2C address adjust | ++--------------+-------------------------------------+ +| CS | LPS22 mode. Pulled high to use I2C. | ++--------------+-------------------------------------+ +| INT | LPS22 interrupt out | ++--------------+-------------------------------------+ + +See :dtcompatible:`st,lps22hb-press` for documentation on how to adjust the +devicetree file. + + +Programming +*********** + +Set ``--shield adafruit_lps22`` when you invoke ``west build``. For example +when running the :zephyr:code-sample:`pressure_polling` pressure and temperature sample: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/pressure_polling + :board: adafruit_feather_rp2040 + :shield: adafruit_lps22 + :goals: build flash + +.. _Adafruit LPS22 Pressure Sensor Shield: + https://learn.adafruit.com/adafruit-lps25-pressure-sensor + +.. _ST Microelectronics LPS22HB Pressure Sensor: + https://www.st.com/en/mems-and-sensors/lps22hb.html diff --git a/boards/shields/adafruit_lps22/shield.yml b/boards/shields/adafruit_lps22/shield.yml new file mode 100644 index 0000000000000..4655afd3cc838 --- /dev/null +++ b/boards/shields/adafruit_lps22/shield.yml @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2025, Jonas Berg + +shield: + name: adafruit_lps22 + full_name: Adafruit LPS22 Pressure Sensor Shield + vendor: adafruit + supported_features: + - sensor diff --git a/samples/sensor/pressure_polling/sample.yaml b/samples/sensor/pressure_polling/sample.yaml index c063b12562c1b..7459ba0b9e44b 100644 --- a/samples/sensor/pressure_polling/sample.yaml +++ b/samples/sensor/pressure_polling/sample.yaml @@ -8,7 +8,9 @@ tests: integration_platforms: - nrf52dk/nrf52832 - adafruit_qt_py_rp2040/rp2040 # adafruit_dps310 shield + - adafruit_feather_rp2040/rp2040 # adafruit_lps22 shield - mikroe_clicker_ra4m1/r7fa4m1ab3cfm # mikroe_pressure_3_click shield extra_args: - platform:adafruit_qt_py_rp2040/rp2040:SHIELD="adafruit_dps310" + - platform:adafruit_feather_rp2040/rp2040:SHIELD="adafruit_lps22" - platform:mikroe_clicker_ra4m1/r7fa4m1ab3cfm:SHIELD="mikroe_pressure_3_click" From 36a9f386ae929275da03d1b36ee1c9b49e5d0ea7 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 18 Oct 2025 11:39:36 +1000 Subject: [PATCH 223/397] modem: cellular: configurable initialisation priority Make the initialisation priority of cellular modems configurable, and move it earlier in the sequence by default to provide room for devices to be initialised later. The updated default value is set to one earlier than `GNSS_INIT_PRIORITY`, as LTE modems often embed a GNSS modem, whose driver may depend on the baseline modem driver (GNSS user pipes, etc). Signed-off-by: Jordan Yates --- drivers/modem/Kconfig.cellular | 9 +++++++++ drivers/modem/modem_cellular.c | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index cc746ff9770e5..2d5a97ec76437 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -40,6 +40,15 @@ config MODEM_CELLULAR if MODEM_CELLULAR +config MODEM_CELLULAR_INIT_PRIORITY + int "Cellular modem driver initialization priority" + default 79 + range 0 99 + help + Driver initialization priority for cellular modem drivers. + Defaults to less than GNSS_INIT_PRIORITY, as LTE modems often + integrate a GNSS modem. + config MODEM_CELLULAR_APN string "Static APN" default "internet" diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index dc4c8cb53e738..c09c9a12795ad 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -3009,8 +3009,8 @@ MODEM_CHAT_SCRIPT_DEFINE(sqn_gm02s_periodic_chat_script, \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ - &modem_cellular_api); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, \ + CONFIG_MODEM_CELLULAR_INIT_PRIORITY, &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_QUECTEL_BG9X(inst) \ MODEM_DT_INST_PPP_DEFINE(inst, MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ From 6f05aa034223c360db4fdb09f4da06da171d0a36 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sun, 19 Oct 2025 18:45:28 +0100 Subject: [PATCH 224/397] shell: modules: devmem: support 64-bit read & write Add support for 64-bit devmem operations for 64-bit devices. Signed-off-by: Sergii Vystoropskyi Signed-off-by: Yong Cong Sin Signed-off-by: Yong Cong Sin --- subsys/shell/modules/devmem_service.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/subsys/shell/modules/devmem_service.c b/subsys/shell/modules/devmem_service.c index 559a946d6d677..c5781faf9dd70 100644 --- a/subsys/shell/modules/devmem_service.c +++ b/subsys/shell/modules/devmem_service.c @@ -253,7 +253,7 @@ static int cmd_load(const struct shell *sh, size_t argc, char **argv) static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) { - uint32_t value; + uint64_t value; int err = 0; switch (width) { @@ -266,6 +266,11 @@ static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) case 32: value = sys_read32(addr); break; +#ifdef CONFIG_64BIT + case 64: + value = sys_read64(addr); + break; +#endif /* CONFIG_64BIT */ default: shell_fprintf(sh, SHELL_NORMAL, "Incorrect data width\n"); err = -EINVAL; @@ -273,7 +278,7 @@ static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) } if (err == 0) { - shell_fprintf(sh, SHELL_NORMAL, "Read value 0x%x\n", value); + shell_fprintf(sh, SHELL_NORMAL, "Read value 0x%llx\n", value); } return err; @@ -293,6 +298,11 @@ static int memory_write(const struct shell *sh, mem_addr_t addr, uint8_t width, case 32: sys_write32(value, addr); break; +#ifdef CONFIG_64BIT + case 64: + sys_write64(value, addr); + break; +#endif /* CONFIG_64BIT */ default: shell_fprintf(sh, SHELL_NORMAL, "Incorrect data width\n"); err = -EINVAL; @@ -306,7 +316,7 @@ static int memory_write(const struct shell *sh, mem_addr_t addr, uint8_t width, static int cmd_devmem(const struct shell *sh, size_t argc, char **argv) { mem_addr_t phys_addr, addr; - uint32_t value = 0; + uint64_t value = 0; uint8_t width; phys_addr = strtoul(argv[1], NULL, 16); @@ -335,9 +345,9 @@ static int cmd_devmem(const struct shell *sh, size_t argc, char **argv) * this value at the address provided */ - value = strtoul(argv[3], NULL, 16); + value = (uint64_t)strtoull(argv[3], NULL, 16); - shell_fprintf(sh, SHELL_NORMAL, "Writing value 0x%x\n", value); + shell_fprintf(sh, SHELL_NORMAL, "Writing value 0x%llx\n", value); return memory_write(sh, addr, width, value); } From 38e86366c719d169582ed436cbecc8f5053331bd Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 18 Oct 2025 19:34:14 -0400 Subject: [PATCH 225/397] kernel: usage: Fix CPU stats retrieval in z_sched_cpu_usage() The z_sched_cpu_usage() function was incorrectly using _current_cpu instead of the requested cpu_id parameter when retrieving CPU usage statistics. This caused it to always return stats from the current CPU rather than the specified CPU. This bug manifested in SMP systems when k_thread_runtime_stats_all_get() looped through all CPUs - it would get stats from the wrong CPU for each iteration, leading to inconsistent time values. For example, in the times() POSIX function, this caused time to appear to move backwards: t0: utime: 59908 t1: utime: 824 The fix ensures that: 1. cpu pointer is set to &_kernel.cpus[cpu_id] (the requested CPU) 2. The check for "is this the current CPU" is correctly written as (cpu == _current_cpu) This fixes the portability.posix.muti_process.newlib test failure on FVP SMP platforms where times() was reporting backwards time. Signed-off-by: Nicolas Pitre --- kernel/usage.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/usage.c b/kernel/usage.c index ad40e3ffd48a0..86ba6aa4d850e 100644 --- a/kernel/usage.c +++ b/kernel/usage.c @@ -125,10 +125,9 @@ void z_sched_cpu_usage(uint8_t cpu_id, struct k_thread_runtime_stats *stats) struct _cpu *cpu; key = k_spin_lock(&usage_lock); - cpu = _current_cpu; - + cpu = &_kernel.cpus[cpu_id]; - if (&_kernel.cpus[cpu_id] == cpu) { + if (cpu == _current_cpu) { uint32_t now = usage_now(); uint32_t cycles = now - cpu->usage0; From 5bbe98ecb2860f54f36dfbd6204ed9a5b4c1c04e Mon Sep 17 00:00:00 2001 From: Felix Wang Date: Mon, 20 Oct 2025 10:42:20 +0800 Subject: [PATCH 226/397] drivers: timer: Use prescale_glitch_filter for prescale setting In eb785ef, "prescaler" has been deprecated and "prescale_glitch_filter" is used for prescale setting. This patch removes "prescaler" parameter and use "prescale_glitch_filter" to simplify code and fix build error caused by "precsaler" parameter. Signed-off-by: Felix Wang --- drivers/timer/mcux_lptmr_timer.c | 33 ++++---------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/drivers/timer/mcux_lptmr_timer.c b/drivers/timer/mcux_lptmr_timer.c index f83e4c39e26a7..9e95503b44f00 100644 --- a/drivers/timer/mcux_lptmr_timer.c +++ b/drivers/timer/mcux_lptmr_timer.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Vestas Wind Systems A/S + * Copyright (c) 2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,33 +18,13 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "No LPTMR instance enabled in devicetree"); -/* Prescaler mapping */ -#define LPTMR_PRESCALER_2 kLPTMR_Prescale_Glitch_0 -#define LPTMR_PRESCALER_4 kLPTMR_Prescale_Glitch_1 -#define LPTMR_PRESCALER_8 kLPTMR_Prescale_Glitch_2 -#define LPTMR_PRESCALER_16 kLPTMR_Prescale_Glitch_3 -#define LPTMR_PRESCALER_32 kLPTMR_Prescale_Glitch_4 -#define LPTMR_PRESCALER_64 kLPTMR_Prescale_Glitch_5 -#define LPTMR_PRESCALER_128 kLPTMR_Prescale_Glitch_6 -#define LPTMR_PRESCALER_256 kLPTMR_Prescale_Glitch_7 -#define LPTMR_PRESCALER_512 kLPTMR_Prescale_Glitch_8 -#define LPTMR_PRESCALER_1024 kLPTMR_Prescale_Glitch_9 -#define LPTMR_PRESCALER_2048 kLPTMR_Prescale_Glitch_10 -#define LPTMR_PRESCALER_4096 kLPTMR_Prescale_Glitch_11 -#define LPTMR_PRESCALER_8192 kLPTMR_Prescale_Glitch_12 -#define LPTMR_PRESCALER_16384 kLPTMR_Prescale_Glitch_13 -#define LPTMR_PRESCALER_32768 kLPTMR_Prescale_Glitch_14 -#define LPTMR_PRESCALER_65536 kLPTMR_Prescale_Glitch_15 -#define TO_LPTMR_PRESCALER(val) _DO_CONCAT(LPTMR_PRESCALER_, val) - /* Prescaler clock mapping */ #define TO_LPTMR_CLK_SEL(val) _DO_CONCAT(kLPTMR_PrescalerClock_, val) /* Devicetree properties */ #define LPTMR_BASE ((LPTMR_Type *)(DT_INST_REG_ADDR(0))) -#define LPTMR_CLK_SOURCE TO_LPTMR_CLK_SEL(DT_INST_PROP(0, clk_source)); -#define LPTMR_PRESCALER TO_LPTMR_PRESCALER(DT_INST_PROP(0, prescaler)); -#define LPTMR_BYPASS_PRESCALER DT_INST_PROP(0, prescaler) == 1 +#define LPTMR_CLK_SOURCE TO_LPTMR_CLK_SEL(DT_INST_PROP_OR(0, clk_source, 0)) +#define LPTMR_PRESCALER BIT(DT_INST_PROP_OR(0, prescale_glitch_filter, 0)) #define LPTMR_IRQN DT_INST_IRQN(0) #define LPTMR_IRQ_PRIORITY DT_INST_IRQ(0, priority) @@ -100,18 +81,12 @@ static int sys_clock_driver_init(void) { lptmr_config_t config; - LPTMR_GetDefaultConfig(&config); config.timerMode = kLPTMR_TimerModeTimeCounter; config.enableFreeRunning = false; config.prescalerClockSource = LPTMR_CLK_SOURCE; - -#if LPTMR_BYPASS_PRESCALER - config.bypassPrescaler = true; -#else /* LPTMR_BYPASS_PRESCALER */ - config.bypassPrescaler = false; + config.bypassPrescaler = !LPTMR_PRESCALER; config.value = LPTMR_PRESCALER; -#endif /* !LPTMR_BYPASS_PRESCALER */ LPTMR_Init(LPTMR_BASE, &config); From f8a9f360238c53832825c2c5eb9400d3e85a247d Mon Sep 17 00:00:00 2001 From: Maochen Wang Date: Mon, 20 Oct 2025 12:36:37 +0800 Subject: [PATCH 227/397] hostap: fix cmd error for wifi reg_domain When CONFIG_WIFI_NM_HOSTAPD_AP is enabled, input 'wifi reg_domain', there is error log shows 'zephyr_get_hapd_handle_by_ifname: Unable to get hapd hanl, Interface ml not found'. The reason is the parameter dev of hostapd_ap_reg_domain is from STA not SAP interface. Getting the correct SAP dev can fix this issue. Signed-off-by: Maochen Wang --- modules/hostap/src/supp_api.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index ed749d3351ff3..c1ee6d14e0dd7 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -1740,7 +1740,9 @@ int supplicant_reg_domain(const struct device *dev, } if (IS_ENABLED(CONFIG_WIFI_NM_HOSTAPD_AP)) { - if (!hostapd_ap_reg_domain(dev, reg_domain)) { + const struct device *dev2 = net_if_get_device(net_if_get_wifi_sap()); + + if (!hostapd_ap_reg_domain(dev2, reg_domain)) { goto out; } } From ba74a2901055b889714a50ddaa55733be0b14354 Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Sat, 11 Oct 2025 22:58:24 +0200 Subject: [PATCH 228/397] boards: nxp: frdm_mcxn947: add arduino labels Added arduino_serial, arduino_i2c, arduino_spi and arduino_header node labels to FRDM-MCXN947 device tree board definition, allowing compatible shield boards to be used. Also extend the board YAML file with related support tags arduino_gpio, arduino_i2c, arduino_serial and arduino_spi. Signed-off-by: Stephan Linz --- boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi | 22 ++++++++++++------- .../frdm_mcxn947_mcxn947_cpu0.yaml | 4 ++++ .../frdm_mcxn947_mcxn947_cpu0_qspi.yaml | 4 ++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi index 6fd415f581c75..d65b15646f9b8 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi @@ -70,8 +70,8 @@ , , , - , - , + , /* RX */ + , /* TX */ , , , @@ -80,12 +80,12 @@ , , , - , - , - , - , - , - ; + , /* CS */ + , /* MOSI */ + , /* MISO */ + , /* SCK */ + , /* SDA */ + ; /* SCL */ }; /* @@ -116,18 +116,24 @@ pinctrl-names = "default"; }; +arduino_spi: &flexcomm1_lpspi1 {}; + nxp_8080_touch_panel_i2c: &flexcomm2_lpi2c2 { pinctrl-0 = <&pinmux_flexcomm2_lpi2c>; pinctrl-names = "default"; clock-frequency = ; }; +arduino_i2c: &flexcomm2_lpi2c2 {}; + &flexcomm2_lpuart2 { current-speed = <115200>; pinctrl-0 = <&pinmux_flexcomm2_lpuart>; pinctrl-names = "default"; }; +arduino_serial: &flexcomm2_lpuart2 {}; + &flexcomm4_lpuart4 { current-speed = <115200>; pinctrl-0 = <&pinmux_flexcomm4_lpuart>; diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml index 462e1eb809fd5..0fd1ac9dbb0a8 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.yaml @@ -15,6 +15,10 @@ toolchain: - gnuarmemb supported: - adc + - arduino_gpio + - arduino_i2c + - arduino_serial + - arduino_spi - can - counter - dac diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0_qspi.yaml b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0_qspi.yaml index 438ed72869304..ca5461e8df4c3 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0_qspi.yaml +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0_qspi.yaml @@ -15,6 +15,10 @@ toolchain: - gnuarmemb supported: - adc + - arduino_gpio + - arduino_i2c + - arduino_serial + - arduino_spi - can - counter - dac From f3d579e2ca4f6d0dab25a544013ed55d8736bcef Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Sun, 12 Oct 2025 11:03:22 +0200 Subject: [PATCH 229/397] boards: nxp: frdm_mcxn947: add mikrobus labels Added mikrobus_i2c, mikrobus_spi and mikrobus_header node labels to FRDM-MCXN947 device tree board definition, allowing compatible shield boards to be used. Also add new FlexComm SPI pinmux for the LPSPI6 on LPFLEXCOMM6 and enable required GPIO3 and GPIO5. Signed-off-by: Stephan Linz --- .../frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi | 12 +++++ boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi | 34 ++++++++++++ .../frdm_mcxn947_mcxn947_cpu0.dtsi | 53 ++++++++++++++++--- 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi index 8df1c3d4df029..36101b40a6358 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947-pinctrl.dtsi @@ -18,6 +18,18 @@ }; }; + pinmux_flexcomm6_lpspi: pinmux_flexcomm6_lpspi { + group0 { + pinmux = , /* SAI1_TXD0 */ + , /* SAI1_RXD0 */ + , + ; + slew-rate = "fast"; + drive-strength = "low"; + input-enable; + }; + }; + pinmux_flexcomm2_lpi2c: pinmux_flexcomm2_lpi2c { group0 { pinmux = , diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi index d65b15646f9b8..e4018e362a40e 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947.dtsi @@ -61,6 +61,25 @@ }; }; + mikrobus_header: mikrobus-connector { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = /* ANA_4/ADC1_A0 AN */ + <1 0 &gpio1 3 0>, /* RST */ + <2 0 &gpio3 23 0>, /* CS */ + <3 0 &gpio3 21 0>, /* SCK */ + <4 0 &gpio3 22 0>, /* MISO */ + <5 0 &gpio3 20 0>, /* MOSI */ + <6 0 &gpio3 19 0>, /* PWM */ + <7 0 &gpio5 7 0>, /* INT */ + <8 0 &gpio1 16 0>, /* GPIO, Not a RX */ + <9 0 &gpio1 17 0>, /* GPIO, Not a TX */ + <10 0 &gpio1 1 0>, /* SCL */ + <11 0 &gpio1 0 0>; /* SDA */ + }; + arduino_header: arduino-connector { compatible = "arduino-header-r3"; #gpio-cells = <2>; @@ -118,6 +137,13 @@ arduino_spi: &flexcomm1_lpspi1 {}; +&flexcomm6_lpspi6 { + pinctrl-0 = <&pinmux_flexcomm6_lpspi>; + pinctrl-names = "default"; +}; + +mikrobus_spi: &flexcomm6_lpspi6 {}; + nxp_8080_touch_panel_i2c: &flexcomm2_lpi2c2 { pinctrl-0 = <&pinmux_flexcomm2_lpi2c>; pinctrl-names = "default"; @@ -126,6 +152,14 @@ nxp_8080_touch_panel_i2c: &flexcomm2_lpi2c2 { arduino_i2c: &flexcomm2_lpi2c2 {}; +&flexcomm3_lpi2c3 { + pinctrl-0 = <&pinmux_flexcomm3_lpi2c>; + pinctrl-names = "default"; + clock-frequency = ; +}; + +mikrobus_i2c: &flexcomm3_lpi2c3 {}; + &flexcomm2_lpuart2 { current-speed = <115200>; pinctrl-0 = <&pinmux_flexcomm2_lpuart>; diff --git a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi index 00666335086d1..cd40cd6e56e6d 100644 --- a/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi +++ b/boards/nxp/frdm_mcxn947/frdm_mcxn947_mcxn947_cpu0.dtsi @@ -56,22 +56,36 @@ status = "okay"; }; -&gpio4 { +/* Required on MikroBus connector. */ +&gpio5 { status = "okay"; }; -&gpio1 { +/* Required on Arduino connector. */ +&gpio4 { status = "okay"; }; -&gpio0 { +/* Required on MikroBus connector. */ +&gpio3 { status = "okay"; }; +/* Required on SD card. */ &gpio2 { status = "okay"; }; +/* Required on Arduino and MikroBus connector. */ +&gpio1 { + status = "okay"; +}; + +/* Required on Arduino connector. */ +&gpio0 { + status = "okay"; +}; + &green_led { status = "okay"; }; @@ -92,38 +106,63 @@ status = "okay"; }; +/* Required on Arduino connector. */ &flexcomm1_lpspi1 { status = "okay"; }; +/* + * LPFLEXCOMM supports UART and I2C on the same instance, enable this for + * LPLEXCOMM2 with LPUART2 and LPI2C2. + */ &flexcomm2 { status = "okay"; }; +/* Required on Arduino and FlexIO LCD (touch panel) connector. */ &flexcomm2_lpi2c2 { status = "okay"; }; -/* - *LPFLEXCOMM supports UART and I2C on the same instance, enable this for - * LFLEXCOMM2 - */ +/* Required on Arduino connector. */ &flexcomm2_lpuart2 { status = "okay"; }; +&flexcomm3 { + status = "okay"; +}; + +/* Required on MikroBus connector. */ +&flexcomm3_lpi2c3 { + status = "okay"; +}; + &flexcomm4 { status = "okay"; }; +/* Required for serial console and on Camera connector. */ &flexcomm4_lpuart4 { status = "okay"; }; +/* + * LPFLEXCOMM6 supports SPI for MikroBus. Enable this for LPSPI6 but let + * LPSPI6 disabled as long as it is not needed because of two shared signals + * with SAI1 (P3_20 for SAI1_TXD0 and FC6_SPI_MOSI and P3_21 for SAI1_RXD0 + * and FC6_SPI_SCK). There is also an additional MikroBus signal shared + * with SAI1 (P3_19 for SAI1_RX_FS and MikroBus:PWM). + */ +&flexcomm6 { + status = "okay"; +}; + &flexcomm7 { status = "okay"; }; +/* Required on Camera connector. */ &flexcomm7_lpi2c7 { status = "okay"; }; From 64796a089ab46156335890adbc14c87392e6ffb4 Mon Sep 17 00:00:00 2001 From: Bill Waters Date: Thu, 11 Sep 2025 16:53:44 -0700 Subject: [PATCH 230/397] soc: infineon: cat1b: psc3: noinit linker update This device needs a custom noinit.ld file to account for how ROM uses RAM during boot. Signed-off-by: Bill Waters --- soc/infineon/cat1b/psc3/CMakeLists.txt | 1 + soc/infineon/cat1b/psc3/Kconfig | 1 + soc/infineon/cat1b/psc3/noinit.ld | 15 +++++++++++++++ 3 files changed, 17 insertions(+) create mode 100644 soc/infineon/cat1b/psc3/noinit.ld diff --git a/soc/infineon/cat1b/psc3/CMakeLists.txt b/soc/infineon/cat1b/psc3/CMakeLists.txt index b97d1ccfb14b4..0251e3ebc7eca 100644 --- a/soc/infineon/cat1b/psc3/CMakeLists.txt +++ b/soc/infineon/cat1b/psc3/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_sources(soc.c) zephyr_include_directories(.) +zephyr_linker_sources(NOINIT noinit.ld) # CAT1B family defines zephyr_compile_definitions_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1 CY_USING_HAL) diff --git a/soc/infineon/cat1b/psc3/Kconfig b/soc/infineon/cat1b/psc3/Kconfig index 7913c201046b9..8ca1975b8e214 100644 --- a/soc/infineon/cat1b/psc3/Kconfig +++ b/soc/infineon/cat1b/psc3/Kconfig @@ -28,3 +28,4 @@ config SOC_SERIES_PSC3 select CPU_CORTEX_M_HAS_CMSE select SOC_EARLY_INIT_HOOK select CPU_CORTEX_M33 + select NOINIT_SNIPPET_FIRST diff --git a/soc/infineon/cat1b/psc3/noinit.ld b/soc/infineon/cat1b/psc3/noinit.ld new file mode 100644 index 0000000000000..3f206e782cb30 --- /dev/null +++ b/soc/infineon/cat1b/psc3/noinit.ld @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* The boot ROM in this device uses the first 8k of SRAM while running. Applications like + * tests\drivers\watchdog\wdt_basic_api expect that variables placed in noint memory will retain + * there value through a reset. This means that the noinit memory region must be located after + * the first 8k of SRAM. The line below is added to the noinit linker section to ensure that. + * It must be used in conjunction with the NOINIT_SNIPPET_FIRST configuration option that has + * been added to the Kconfig file. + */ +. = MAX(ABSOLUTE(.), 0x34002000); From bee8c953e2357a6f965f13a737fb8305f4a3c1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 22 Oct 2025 10:26:57 +0200 Subject: [PATCH 231/397] drivers: sensor: adxl345: fix uninitialized variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix -Wsometimes-uninitialized warning by initializing data_opt directly from fifo_wmark_cfg->opt. At this point in the code flow, fifo_wmark_cfg is guaranteed to be non-NULL because we can only reach this code after fifo_full_irq is true, which requires fifo_wmark_cfg to be non-NULL. Added an assertion to document this invariant. Signed-off-by: Benjamin Cabé --- drivers/sensor/adi/adxl345/adxl345_stream.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/sensor/adi/adxl345/adxl345_stream.c b/drivers/sensor/adi/adxl345/adxl345_stream.c index 9550efb43bdd3..6de0df79699ef 100644 --- a/drivers/sensor/adi/adxl345/adxl345_stream.c +++ b/drivers/sensor/adi/adxl345/adxl345_stream.c @@ -309,11 +309,9 @@ static void adxl345_process_status1_cb(struct rtio *r, const struct rtio_sqe *sq return; } - enum sensor_stream_data_opt data_opt; - - if (fifo_wmark_cfg != NULL) { - data_opt = fifo_wmark_cfg->opt; - } + /* fifo_wmark_cfg is guaranteed to be non-NULL here since fifo_full_irq is true */ + __ASSERT_NO_MSG(fifo_wmark_cfg != NULL); + enum sensor_stream_data_opt data_opt = fifo_wmark_cfg->opt; if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) { uint8_t *buf; From f6c94bc0dc3e062deb8b2f34be31fabfb8b7a28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 22 Oct 2025 10:33:36 +0200 Subject: [PATCH 232/397] drivers: sensor: pni: rm3100: drop unused inline function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit settings_changed() is not used, causing warnings when building with clang. Drop it Signed-off-by: Benjamin Cabé --- drivers/sensor/pni/rm3100/rm3100_stream.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/sensor/pni/rm3100/rm3100_stream.c b/drivers/sensor/pni/rm3100/rm3100_stream.c index 597585e12ac78..3f633cb924328 100644 --- a/drivers/sensor/pni/rm3100/rm3100_stream.c +++ b/drivers/sensor/pni/rm3100/rm3100_stream.c @@ -183,13 +183,6 @@ static void rm3100_gpio_callback(const struct device *gpio_dev, rm3100_stream_get_data(dev); } -static inline bool settings_changed(const struct rm3100_stream *a, - const struct rm3100_stream *b) -{ - return (a->settings.enabled.drdy != b->settings.enabled.drdy) || - (a->settings.opt.drdy != b->settings.opt.drdy); -} - void rm3100_stream_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { From 8277b0521ab5d84ad3114f36058fb8242cd873e4 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 21 Oct 2025 21:28:45 +0100 Subject: [PATCH 233/397] input: use single evaluation clamp Use single evaluation clamp for few input drivers. No reason not to, make some sense for the input_kbd_matrix call since one of the arguments is a function. Signed-off-by: Fabio Baltieri --- drivers/input/input_analog_axis.c | 2 +- drivers/input/input_kbd_matrix.c | 2 +- drivers/input/input_stmpe811.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/input_analog_axis.c b/drivers/input/input_analog_axis.c index f58d4b77a4025..7a6879c01b313 100644 --- a/drivers/input/input_analog_axis.c +++ b/drivers/input/input_analog_axis.c @@ -204,7 +204,7 @@ static void analog_axis_loop(const struct device *dev) out = analog_axis_out_linear(dev, i, raw_val); } - out = CLAMP(out, axis_cfg->out_min, axis_cfg->out_max); + out = clamp(out, axis_cfg->out_min, axis_cfg->out_max); if (axis_cfg->invert_output) { out = axis_cfg->out_max - out; diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 747749a958b94..7cd8badef3bba 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -309,7 +309,7 @@ static void input_kbd_matrix_poll(const struct device *dev) } else { poll_period_us = cfg->stable_poll_period_us; } - wait_period_us = CLAMP(poll_period_us - k_cyc_to_us_floor32(cycles_diff), + wait_period_us = clamp(poll_period_us - k_cyc_to_us_floor32(cycles_diff), USEC_PER_MSEC, poll_period_us); LOG_DBG("wait_period_us: %d", wait_period_us); diff --git a/drivers/input/input_stmpe811.c b/drivers/input/input_stmpe811.c index b2f95cb5066ce..8c5521dc40c6b 100644 --- a/drivers/input/input_stmpe811.c +++ b/drivers/input/input_stmpe811.c @@ -344,8 +344,8 @@ static void stmpe811_report_touch(const struct device *dev) y = (((int)data->touch_y - config->raw_y_min) * common->screen_height) / (config->raw_y_max - config->raw_y_min); - x = CLAMP(x, 0, common->screen_width); - y = CLAMP(y, 0, common->screen_height); + x = clamp(x, 0, common->screen_width); + y = clamp(y, 0, common->screen_height); } input_touchscreen_report_pos(dev, x, y, K_FOREVER); From 01e978aeafc90c50d61a65c97863f45e12e718d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Tue, 21 Oct 2025 12:05:43 +0200 Subject: [PATCH 234/397] riscv: remove unneeded select ATOMIC_OPERATIONS_BUILTIN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When RISCV_ISA_EXT_A is enabled, ATOMIC_OPERATIONS_BUILTIN automaticly enabled, we don't need to do it at the soc level again. Signed-off-by: Fin Maaß --- soc/andestech/ae350/Kconfig | 1 - soc/egis/et171/Kconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/soc/andestech/ae350/Kconfig b/soc/andestech/ae350/Kconfig index da4cc0193889c..031bc0756c717 100644 --- a/soc/andestech/ae350/Kconfig +++ b/soc/andestech/ae350/Kconfig @@ -19,7 +19,6 @@ config SOC_SERIES_ANDES_AE350 select CPU_HAS_ANDES_PMA select RISCV_SOC_CONTEXT_SAVE if RISCV_CUSTOM_CSR_ANDES_HWDSP select RISCV_SOC_CONTEXT_SAVE if RISCV_CUSTOM_CSR_ANDES_PFT - select ATOMIC_OPERATIONS_BUILTIN select SOC_EARLY_INIT_HOOK if RISCV_CUSTOM_CSR_ANDES_PMA select SOC_PER_CORE_INIT_HOOK if RISCV_CUSTOM_CSR_ANDES_PMA imply XIP diff --git a/soc/egis/et171/Kconfig b/soc/egis/et171/Kconfig index 2d78bc2d8bfc6..88ec3b2d11fac 100644 --- a/soc/egis/et171/Kconfig +++ b/soc/egis/et171/Kconfig @@ -13,7 +13,6 @@ config SOC_EGIS_ET171 select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI - select ATOMIC_OPERATIONS_BUILTIN select CPU_HAS_FPU select CPU_HAS_DCACHE select CPU_HAS_ICACHE From e7ae5494a2d34182119003dd878bd9a8054c3704 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Oct 2025 13:36:39 +0300 Subject: [PATCH 235/397] Bluetooth: Host: Make use of common array helper macros There's a bunch of convenience macros in sys/util.h that are intended to help out with translating array indices and determining if an element is part of an array or not. Use those instead of custom code. Signed-off-by: Johan Hedberg --- subsys/bluetooth/host/adv.c | 6 ++---- subsys/bluetooth/host/conn.c | 15 ++++++--------- subsys/bluetooth/host/scan.c | 7 +++---- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index 07d80b18c03a5..77dc28345987f 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -187,11 +187,9 @@ static struct bt_le_ext_adv adv_pool[CONFIG_BT_EXT_ADV_MAX_ADV_SET]; #if defined(CONFIG_BT_EXT_ADV) uint8_t bt_le_ext_adv_get_index(struct bt_le_ext_adv *adv) { - ptrdiff_t index = adv - adv_pool; + __ASSERT(IS_ARRAY_ELEMENT(adv_pool, adv), "Invalid bt_adv pointer"); - __ASSERT(index >= 0 && index < ARRAY_SIZE(adv_pool), - "Invalid bt_adv pointer"); - return (uint8_t)index; + return (uint8_t)ARRAY_INDEX(adv_pool, adv); } static struct bt_le_ext_adv *adv_new(void) diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 9b6c961cfae6f..220095a895aac 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -1546,23 +1546,20 @@ uint8_t bt_conn_index(const struct bt_conn *conn) switch (conn->type) { #if defined(CONFIG_BT_ISO) case BT_CONN_TYPE_ISO: - index = conn - iso_conns; - __ASSERT(index >= 0 && index < ARRAY_SIZE(iso_conns), - "Invalid bt_conn pointer"); + __ASSERT(IS_ARRAY_ELEMENT(iso_conns, conn), "Invalid bt_conn pointer"); + index = ARRAY_INDEX(iso_conns, conn); break; #endif #if defined(CONFIG_BT_CLASSIC) case BT_CONN_TYPE_SCO: - index = conn - sco_conns; - __ASSERT(index >= 0 && index < ARRAY_SIZE(sco_conns), - "Invalid bt_conn pointer"); + __ASSERT(IS_ARRAY_ELEMENT(sco_conns, conn), "Invalid bt_conn pointer"); + index = ARRAY_INDEX(sco_conns, conn); break; #endif default: #if defined(CONFIG_BT_CONN) - index = conn - acl_conns; - __ASSERT(index >= 0 && index < ARRAY_SIZE(acl_conns), - "Invalid bt_conn pointer"); + __ASSERT(IS_ARRAY_ELEMENT(acl_conns, conn), "Invalid bt_conn pointer"); + index = ARRAY_INDEX(acl_conns, conn); #else __ASSERT(false, "Invalid connection type %u", conn->type); #endif /* CONFIG_BT_CONN */ diff --git a/subsys/bluetooth/host/scan.c b/subsys/bluetooth/host/scan.c index b154729438a0f..bffc5fd907f2e 100644 --- a/subsys/bluetooth/host/scan.c +++ b/subsys/bluetooth/host/scan.c @@ -1841,11 +1841,10 @@ void bt_le_scan_cb_unregister(struct bt_le_scan_cb *cb) #if defined(CONFIG_BT_PER_ADV_SYNC) uint8_t bt_le_per_adv_sync_get_index(struct bt_le_per_adv_sync *per_adv_sync) { - ptrdiff_t index = per_adv_sync - per_adv_sync_pool; - - __ASSERT(index >= 0 && ARRAY_SIZE(per_adv_sync_pool) > index, + __ASSERT(IS_ARRAY_ELEMENT(per_adv_sync_pool, per_adv_sync), "Invalid per_adv_sync pointer"); - return (uint8_t)index; + + return (uint8_t)ARRAY_INDEX(per_adv_sync_pool, per_adv_sync); } struct bt_le_per_adv_sync *bt_le_per_adv_sync_lookup_index(uint8_t index) From 72d3ea705ea6d575685f7006a70818dcfc4ec5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Mon, 20 Oct 2025 12:14:29 +0200 Subject: [PATCH 236/397] scripts: ci: check_compliance: Add missing gen_uicr UNDEF's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing gen_uicr UNDEF's. Signed-off-by: Sebastian Bøe --- scripts/ci/check_compliance.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 5167e568c147f..0e5431da861f3 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1275,6 +1275,8 @@ def check_no_undef_outside_kconfig(self, kconf): "GEN_UICR_PROTECTEDMEM_SIZE_BYTES", "GEN_UICR_SECONDARY", "GEN_UICR_SECONDARY_GENERATE_PERIPHCONF", + "GEN_UICR_SECONDARY_PROCESSOR_APPLICATION", + "GEN_UICR_SECONDARY_PROCESSOR_RADIOCORE", "GEN_UICR_SECONDARY_PROCESSOR_VALUE", "GEN_UICR_SECONDARY_PROTECTEDMEM", "GEN_UICR_SECONDARY_PROTECTEDMEM_SIZE_BYTES", @@ -1288,10 +1290,14 @@ def check_no_undef_outside_kconfig(self, kconf): "GEN_UICR_SECONDARY_WDTSTART", "GEN_UICR_SECONDARY_WDTSTART_CRV", "GEN_UICR_SECONDARY_WDTSTART_INSTANCE_CODE", + "GEN_UICR_SECONDARY_WDTSTART_INSTANCE_WDT0", + "GEN_UICR_SECONDARY_WDTSTART_INSTANCE_WDT1", "GEN_UICR_SECURESTORAGE", "GEN_UICR_WDTSTART", "GEN_UICR_WDTSTART_CRV", "GEN_UICR_WDTSTART_INSTANCE_CODE", + "GEN_UICR_WDTSTART_INSTANCE_WDT0", + "GEN_UICR_WDTSTART_INSTANCE_WDT1", "HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix "HUGETLBFS", # Linux, in boards/xtensa/intel_adsp_cavs25/doc "IAR_BUFFERED_WRITE", From 031ac1d20927bad94a74c78a211c052b0e5ceb65 Mon Sep 17 00:00:00 2001 From: Alexander Svensen Date: Mon, 20 Oct 2025 10:18:38 +0200 Subject: [PATCH 237/397] tests: bluetooth: Recycle ext_adv_sets when stopping adv - We want to reuse ext_advs when first stopped and restarted - This ensures SID is the same - Fixes CAP/CL/ADV/BV-03-C Signed-off-by: Alexander Svensen --- tests/bluetooth/tester/src/btp/btp_gap.h | 1 + tests/bluetooth/tester/src/btp_gap.c | 42 +++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/tests/bluetooth/tester/src/btp/btp_gap.h b/tests/bluetooth/tester/src/btp/btp_gap.h index fb95e77db8356..f1d4bfd1dfc26 100644 --- a/tests/bluetooth/tester/src/btp/btp_gap.h +++ b/tests/bluetooth/tester/src/btp/btp_gap.h @@ -626,6 +626,7 @@ struct bt_le_adv_param; struct bt_data; struct bt_le_ext_adv *tester_gap_ext_adv_get(uint8_t ext_adv_idx); struct bt_le_per_adv_sync *tester_gap_padv_get(void); +int tester_gap_clear_adv_instance(struct bt_le_ext_adv *ext_adv); int tester_gap_create_adv_instance(struct bt_le_adv_param *param, uint8_t own_addr_type, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len, diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index b60b82ccc83ac..da2a0e87c4d9e 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -601,6 +601,21 @@ static int tester_gap_ext_adv_idx_free_get(void) return -ENOMEM; } +static int tester_gap_ext_adv_idx_get(struct bt_le_ext_adv *ext_adv) +{ + if (!IS_ENABLED(CONFIG_BT_EXT_ADV)) { + return -ENOTSUP; + } + + for (int i = 0; i < ARRAY_SIZE(ext_adv_sets); i++) { + if (ext_adv_sets[i] == ext_adv) { + return i; + } + } + + return -EINVAL; +} + int tester_gap_start_ext_adv(struct bt_le_ext_adv *ext_adv) { if (!IS_ENABLED(CONFIG_BT_EXT_ADV)) { @@ -645,6 +660,8 @@ int tester_gap_stop_ext_adv(struct bt_le_ext_adv *ext_adv) return -EINVAL; } + tester_gap_clear_adv_instance(ext_adv); + atomic_clear_bit(¤t_settings, BTP_GAP_SETTINGS_ADVERTISING); return 0; @@ -751,6 +768,29 @@ static uint8_t set_bondable(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } +int tester_gap_clear_adv_instance(struct bt_le_ext_adv *ext_adv) +{ + if (!IS_ENABLED(CONFIG_BT_EXT_ADV)) { + return -ENOTSUP; + } + + if (ext_adv == NULL) { + LOG_ERR("Invalid ext_adv"); + return -EINVAL; + } + + int index = tester_gap_ext_adv_idx_get(ext_adv); + + if (index < 0) { + LOG_ERR("Failed to get ext_adv index"); + return -EINVAL; + } + + ext_adv_sets[index] = NULL; + + return 0; +} + int tester_gap_create_adv_instance(struct bt_le_adv_param *param, uint8_t own_addr_type, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len, uint32_t *settings, @@ -974,7 +1014,7 @@ static uint8_t stop_advertising(const void *cmd, uint16_t cmd_len, if (IS_ENABLED(CONFIG_BT_EXT_ADV) && atomic_test_bit(¤t_settings, BTP_GAP_SETTINGS_EXTENDED_ADVERTISING)) { - err = bt_le_ext_adv_stop(gap_ext_adv); + err = tester_gap_stop_ext_adv(gap_ext_adv); } else { err = bt_le_adv_stop(); } From 04bee5659c32affe4c0a5d78b6d0b9f6161e0cdf Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 20 Oct 2025 10:12:34 +0200 Subject: [PATCH 238/397] scripts: west_commands: Convert sysbuild argument to BooleanOptionalAction Instead of using a mutually exclusive group for sysbuild/no-sysbuild argparse arguments, use the argparse.BooleanOptionalAction to allow passing multiple arguments, where the last one is applied. This is consistent with for example gcc compiler flags. Signed-off-by: Pieter De Gendt --- scripts/west_commands/build.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/scripts/west_commands/build.py b/scripts/west_commands/build.py index 0b2b1965cf394..30fa05805ddef 100644 --- a/scripts/west_commands/build.py +++ b/scripts/west_commands/build.py @@ -170,12 +170,8 @@ def do_add_parser(self, parser_adder): -DEXTRA_DTC_OVERLAY_FILE... cmake arguments: the results are undefined''') - group = parser.add_mutually_exclusive_group() - group.add_argument('--sysbuild', action='store_true', - help='''create multi domain build system''') - group.add_argument('--no-sysbuild', action='store_true', - help='''do not create multi domain build system - (default)''') + group.add_argument('--sysbuild', action=argparse.BooleanOptionalAction, + help='''create multi domain build system or disable it (default)''') group = parser.add_argument_group('pristine builds', PRISTINE_DESCRIPTION) @@ -645,12 +641,12 @@ def _run_cmake(self, board, origin, cmake_opts): cmake_opts.extend(shlex.split(user_args)) config_sysbuild = config_getboolean('sysbuild', False) - if self.args.sysbuild or (config_sysbuild and not self.args.no_sysbuild): + if self.args.sysbuild is True or (config_sysbuild and self.args.sysbuild is not False): cmake_opts.extend([f'-S{SYSBUILD_PROJ_DIR}']) cmake_env = os.environ.copy() cmake_env["APP_DIR"] = str(self.source_dir) else: - # self.args.no_sysbuild == True or config sysbuild False + # self.args.sysbuild == False or config sysbuild False cmake_opts.extend([f'-S{self.source_dir}']) # Invoke CMake from the current working directory using the From 95454a2d8265ae7915f7bba966d44148d7ec43d9 Mon Sep 17 00:00:00 2001 From: Cristian Bulacu Date: Tue, 14 Oct 2025 16:28:01 +0300 Subject: [PATCH 239/397] modules: openthread: platform: Enable mDNS auto enable functionality As per OpenThread API documentation, it is recommended for a Border Router to use this functionality Signed-off-by: Cristian Bulacu --- modules/openthread/platform/openthread-core-zephyr-config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 9a951e8f77a18..7014ed0f24043 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -563,6 +563,7 @@ #ifdef CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER #define OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE 1 +#define OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF 1 #endif /* CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER */ #endif /* OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ */ From 413b7173196cf2ddebd6e90c36599c5c8fe93697 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 20 Oct 2025 08:58:03 +0200 Subject: [PATCH 240/397] dts: bindings: video: stm32: add title entry on stm32 video bindings Add missing title entry in stm32 video device bindings. Signed-off-by: Alain Volmat --- dts/bindings/video/st,mipid02.yaml | 6 +++++- dts/bindings/video/st,stm32-dcmi.yaml | 5 ++++- dts/bindings/video/st,stm32-dcmipp.yaml | 8 +++++++- dts/bindings/video/st,stm32-jpeg.yaml | 4 ++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/dts/bindings/video/st,mipid02.yaml b/dts/bindings/video/st,mipid02.yaml index b78d0df0c2b5a..55d53ea7d0d84 100644 --- a/dts/bindings/video/st,mipid02.yaml +++ b/dts/bindings/video/st,mipid02.yaml @@ -1,7 +1,11 @@ # Copyright (c) 2025 STMicroelectronics. # SPDX-License-Identifier: Apache-2.0 -description: MIPID02 CSI to DVP interface bridge +title: MIPID02 CSI to DVP interface bridge + +description: | + The MIPID02 allows connecting a DVP sensor to a CSI-2–enabled + camera receiver. compatible: "st,mipid02" diff --git a/dts/bindings/video/st,stm32-dcmi.yaml b/dts/bindings/video/st,stm32-dcmi.yaml index 41da6c7659f9a..291a452ae44c3 100644 --- a/dts/bindings/video/st,stm32-dcmi.yaml +++ b/dts/bindings/video/st,stm32-dcmi.yaml @@ -4,8 +4,11 @@ # SPDX-License-Identifier: Apache-2.0 # +title: STM32 DCMI (Digital Camera Memory Interface) + description: | - STM32 Digital Camera Memory Interface (DCMI). + The STM32 DCMI (Digital Camera Memory Interface) allows + capturing data via a parallel interface (DVP). Example of node configuration at board level: diff --git a/dts/bindings/video/st,stm32-dcmipp.yaml b/dts/bindings/video/st,stm32-dcmipp.yaml index 7aaaa8521e0c7..088227f3d3cf5 100644 --- a/dts/bindings/video/st,stm32-dcmipp.yaml +++ b/dts/bindings/video/st,stm32-dcmipp.yaml @@ -4,8 +4,14 @@ # SPDX-License-Identifier: Apache-2.0 # +title: STM32 DCMIPP (Digital Camera Memory Interface Pixel Processor) + description: | - STM32 Digital Camera Memory Interface Pixel Processor (DCMIPP). + The STM32 DCMIPP (Digital Camera Memory Interface Pixel Processor) supports, + depending on the platform, data capture from either parallel (DVP) or + CSI-2 interfaces. It integrates up to three processing pipelines capable of + performing frame operations, including one pipeline with ISP functionality + enabled. Example of node configuration at board level: diff --git a/dts/bindings/video/st,stm32-jpeg.yaml b/dts/bindings/video/st,stm32-jpeg.yaml index b2549f26a3204..8b5ebebb932b2 100644 --- a/dts/bindings/video/st,stm32-jpeg.yaml +++ b/dts/bindings/video/st,stm32-jpeg.yaml @@ -4,9 +4,9 @@ # SPDX-License-Identifier: Apache-2.0 # -description: | - STM32 JPEG HW Codec. +title: STM32 JPEG HW Codec +description: | The STM32 JPEG HW codec can decode JPEG compressed frames and encode uncompressed frames to the JPEG format. From e3276570aeb1e4edce0a20d6641434134451cc65 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 20 Oct 2025 09:00:53 +0200 Subject: [PATCH 241/397] video: stm32: enable STM32 VENC / JPEG build_all tests Allow building the STM32 VENC and STM32 JPEG HW codec as part of the build_all tests. Signed-off-by: Alain Volmat --- tests/drivers/build_all/video/testcase.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/drivers/build_all/video/testcase.yaml b/tests/drivers/build_all/video/testcase.yaml index dc8300b6e37a1..cb3e09527d351 100644 --- a/tests/drivers/build_all/video/testcase.yaml +++ b/tests/drivers/build_all/video/testcase.yaml @@ -44,3 +44,10 @@ tests: drivers.video.stm32_venc.build: platform_allow: - stm32n6570_dk/stm32n657xx/sb + extra_configs: + - CONFIG_VIDEO_ENCODER_H264=y + drivers.video.stm32_jpeg.build: + platform_allow: + - stm32n6570_dk/stm32n657xx/sb + extra_configs: + - CONFIG_VIDEO_ENCODER_JPEG=y From dff83f1ece033fab89766c1fec38e31c4d48d602 Mon Sep 17 00:00:00 2001 From: Diego Herranz Date: Sun, 19 Oct 2025 14:56:48 +0200 Subject: [PATCH 242/397] soc: nxp: imx: imx7d: soc.c: enable uart1/3/4/5/7 if used in DT Only uart2 and uart6 were considered before, so if any other uart was used, it wouldn't work and even worse, it would crash when trying to access it because the RDC wasn't configured. Signed-off-by: Diego Herranz --- soc/nxp/imx/imx7d/soc.c | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/soc/nxp/imx/imx7d/soc.c b/soc/nxp/imx/imx7d/soc.c index 7b98389762533..6f7f0b6ed23a8 100644 --- a/soc/nxp/imx/imx7d/soc.c +++ b/soc/nxp/imx/imx7d/soc.c @@ -84,6 +84,21 @@ static void nxp_mcimx7_gpio_config(void) static void nxp_mcimx7_uart_config(void) { +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(uart1)) + /* We need to grasp board uart exclusively */ + RDC_SetPdapAccess(RDC, rdcPdapUart1, RDC_DT_VAL(uart1), false, false); + /* Select clock derived from OSC clock(24M) */ + CCM_UpdateRoot(CCM, ccmRootUart1, ccmRootmuxUartOsc24m, 0, 0); + /* Enable uart clock */ + CCM_EnableRoot(CCM, ccmRootUart1); + /* + * IC Limitation + * M4 stop will cause A7 UART lose functionality + * So we need UART clock all the time + */ + CCM_ControlGate(CCM, ccmCcgrGateUart1, ccmClockNeededAll); +#endif + #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(uart2)) /* We need to grasp board uart exclusively */ RDC_SetPdapAccess(RDC, rdcPdapUart2, RDC_DT_VAL(uart2), false, false); @@ -99,6 +114,51 @@ static void nxp_mcimx7_uart_config(void) CCM_ControlGate(CCM, ccmCcgrGateUart2, ccmClockNeededAll); #endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(uart3)) + /* We need to grasp board uart exclusively */ + RDC_SetPdapAccess(RDC, rdcPdapUart3, RDC_DT_VAL(uart3), false, false); + /* Select clock derived from OSC clock(24M) */ + CCM_UpdateRoot(CCM, ccmRootUart3, ccmRootmuxUartOsc24m, 0, 0); + /* Enable uart clock */ + CCM_EnableRoot(CCM, ccmRootUart3); + /* + * IC Limitation + * M4 stop will cause A7 UART lose functionality + * So we need UART clock all the time + */ + CCM_ControlGate(CCM, ccmCcgrGateUart3, ccmClockNeededAll); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(uart4)) + /* We need to grasp board uart exclusively */ + RDC_SetPdapAccess(RDC, rdcPdapUart4, RDC_DT_VAL(uart4), false, false); + /* Select clock derived from OSC clock(24M) */ + CCM_UpdateRoot(CCM, ccmRootUart4, ccmRootmuxUartOsc24m, 0, 0); + /* Enable uart clock */ + CCM_EnableRoot(CCM, ccmRootUart4); + /* + * IC Limitation + * M4 stop will cause A7 UART lose functionality + * So we need UART clock all the time + */ + CCM_ControlGate(CCM, ccmCcgrGateUart4, ccmClockNeededAll); +#endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(uart5)) + /* We need to grasp board uart exclusively */ + RDC_SetPdapAccess(RDC, rdcPdapUart5, RDC_DT_VAL(uart5), false, false); + /* Select clock derived from OSC clock(24M) */ + CCM_UpdateRoot(CCM, ccmRootUart5, ccmRootmuxUartOsc24m, 0, 0); + /* Enable uart clock */ + CCM_EnableRoot(CCM, ccmRootUart5); + /* + * IC Limitation + * M4 stop will cause A7 UART lose functionality + * So we need UART clock all the time + */ + CCM_ControlGate(CCM, ccmCcgrGateUart5, ccmClockNeededAll); +#endif + #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(uart6)) /* We need to grasp board uart exclusively */ RDC_SetPdapAccess(RDC, rdcPdapUart6, RDC_DT_VAL(uart6), false, false); @@ -113,6 +173,21 @@ static void nxp_mcimx7_uart_config(void) */ CCM_ControlGate(CCM, ccmCcgrGateUart6, ccmClockNeededAll); #endif + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(uart7)) + /* We need to grasp board uart exclusively */ + RDC_SetPdapAccess(RDC, rdcPdapUart7, RDC_DT_VAL(uart7), false, false); + /* Select clock derived from OSC clock(24M) */ + CCM_UpdateRoot(CCM, ccmRootUart7, ccmRootmuxUartOsc24m, 0, 0); + /* Enable uart clock */ + CCM_EnableRoot(CCM, ccmRootUart7); + /* + * IC Limitation + * M4 stop will cause A7 UART lose functionality + * So we need UART clock all the time + */ + CCM_ControlGate(CCM, ccmCcgrGateUart7, ccmClockNeededAll); +#endif } #endif /* CONFIG_UART_IMX */ From aee1f7fdd5f25a506cc2d0cfe7665a99d82adc2e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 17 Oct 2025 19:02:24 +0200 Subject: [PATCH 243/397] drivers timer nrf_rtc: Fix dependency 8498c39e13845076668aaf42513c1904a969fbb6 seems to have introduce an incorrect dependency which prevents the RTC timer from been built if any of the RTC's are enabled. It should only depend on the rtc1. Signed-off-by: Alberto Escolar Piedras --- drivers/timer/Kconfig.nrf_rtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/timer/Kconfig.nrf_rtc b/drivers/timer/Kconfig.nrf_rtc index c596462a6e28f..1ddd473c01a09 100644 --- a/drivers/timer/Kconfig.nrf_rtc +++ b/drivers/timer/Kconfig.nrf_rtc @@ -7,7 +7,7 @@ config NRF_RTC_TIMER bool "nRF Real Time Counter (NRF_RTC1) Timer" depends on CLOCK_CONTROL depends on SOC_COMPATIBLE_NRF - depends on !DT_HAS_NORDIC_NRF_RTC_ENABLED && !DT_HAS_NORDIC_NRF_GRTC_ENABLED + depends on !$(dt_nodelabel_enabled,rtc1) && !DT_HAS_NORDIC_NRF_GRTC_ENABLED select TICKLESS_CAPABLE select SYSTEM_TIMER_HAS_DISABLE_SUPPORT select NRFX_PPI if SOC_NRF52832 From c6aa9be7176ea2479f285ffa04b3ff01f9196a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo=20Navarro?= Date: Fri, 17 Oct 2025 15:45:16 +0200 Subject: [PATCH 244/397] boards: seeed: xiao_nrf54l15: fix led0 polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit led0 in this board is active low according to the schematic. Tested on a XIAO-nRF54L15 and a XIAO-nRF54L15 sense. Signed-off-by: Ricardo Cañuelo Navarro --- boards/seeed/xiao_nrf54l15/xiao_nrf54l15_common.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/seeed/xiao_nrf54l15/xiao_nrf54l15_common.dtsi b/boards/seeed/xiao_nrf54l15/xiao_nrf54l15_common.dtsi index 595cc808c6394..93c9979a3628f 100644 --- a/boards/seeed/xiao_nrf54l15/xiao_nrf54l15_common.dtsi +++ b/boards/seeed/xiao_nrf54l15/xiao_nrf54l15_common.dtsi @@ -10,7 +10,7 @@ compatible = "gpio-leds"; led0: led_0 { - gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>; + gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; label = "LED 0"; }; }; From 842ebd0c53d4d3df64b660cf88374352360f292d Mon Sep 17 00:00:00 2001 From: Artur Dobrynin Date: Tue, 14 Oct 2025 10:28:08 +0200 Subject: [PATCH 245/397] tests: bsim: bluetooth: host: enable conn_stress Adding some minor modifications in order to be able to run host conn_stress test on CI. Signed-off-by: Artur Dobrynin --- .../misc/conn_stress/central/CMakeLists.txt | 3 + .../host/misc/conn_stress/central/prj.conf | 5 +- .../host/misc/conn_stress/central/src/main.c | 41 ++++++++++-- .../conn_stress/peripheral/CMakeLists.txt | 3 + .../misc/conn_stress/peripheral/src/main.c | 50 +++++++++++--- .../misc/conn_stress/scripts/_conn_stress.sh | 67 ------------------- .../misc/conn_stress/scripts/conn_stress.sh | 28 ++++++++ 7 files changed, 114 insertions(+), 83 deletions(-) delete mode 100755 tests/bsim/bluetooth/host/misc/conn_stress/scripts/_conn_stress.sh create mode 100755 tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt b/tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt index 84c6ff866b1d9..0bdf365cc15fc 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/CMakeLists.txt @@ -5,6 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(conn_stress_central) +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + target_sources(app PRIVATE src/main.c ) diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf index 3255ff8e86f69..1cc7c01132495 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf @@ -23,9 +23,8 @@ CONFIG_ASSERT_VERBOSE=y CONFIG_ASSERT_ON_ERRORS=y # TODO: use default 3 -# we get an ATT timeout if 3 -# we get an SMP timeout if 10 -# CONFIG_BT_L2CAP_TX_BUF_COUNT=10 +# we get an ATT timeout if 3 or SMP timeout if 10 +CONFIG_BT_L2CAP_TX_BUF_COUNT=10 # deadlock on central with the default. # the problem is that `tx_free` is called from both syswq and btwq in that case. diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c b/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c index 7ce3dbfe489d1..9ff3b0a0af636 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c @@ -22,7 +22,7 @@ #include #include -LOG_MODULE_REGISTER(central, LOG_LEVEL_INF); +LOG_MODULE_REGISTER(central, LOG_LEVEL_DBG); #include "bstests.h" #include "bs_types.h" @@ -30,6 +30,8 @@ LOG_MODULE_REGISTER(central, LOG_LEVEL_INF); #include "bstests.h" #include "bs_pc_backchannel.h" +#include "babblekit/testcase.h" + #define DEFAULT_CONN_INTERVAL 20 #define PERIPHERAL_DEVICE_NAME "Zephyr Peripheral" #define PERIPHERAL_DEVICE_NAME_LEN (sizeof(PERIPHERAL_DEVICE_NAME) - 1) @@ -50,6 +52,8 @@ BUILD_ASSERT(NOTIFICATION_DATA_LEN <= CHARACTERISTIC_DATA_MAX_LEN); #define PERIPHERAL_SERVICE_UUID BT_UUID_DECLARE_128(PERIPHERAL_SERVICE_UUID_VAL) #define PERIPHERAL_CHARACTERISTIC_UUID BT_UUID_DECLARE_128(PERIPHERAL_CHARACTERISTIC_UUID_VAL) +#define EXPECTED_CONN_CYCLES 1 + static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdea0)); @@ -89,6 +93,7 @@ struct conn_info { struct bt_gatt_discover_params discover_params; struct bt_gatt_subscribe_params subscribe_params; bt_addr_le_t addr; + atomic_t conn_count; }; static struct conn_info conn_infos[CONFIG_BT_MAX_CONN] = {0}; @@ -232,8 +237,6 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at conn_info_ref = get_connected_conn_info_ref(conn); __ASSERT_NO_MSG(conn_info_ref); - atomic_clear_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED); - if (conn_info_ref->discover_params.type == BT_GATT_DISCOVER_PRIMARY) { LOG_DBG("Primary Service Found"); memcpy(&conn_info_ref->uuid, @@ -295,7 +298,7 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at /* if we're out of buffers or metadata contexts, continue discovery * later. */ - LOG_INF("out of memory/not connected, continuing sub later"); + LOG_INF("out of memory/not connected, continuing sub later (err %d)", err); atomic_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED); return BT_GATT_ITER_STOP; @@ -328,6 +331,17 @@ static bool check_if_peer_connected(const bt_addr_le_t *addr) return false; } +static bool check_if_completed(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(conn_infos); i++) { + if (atomic_get(&conn_infos[i].conn_count) < EXPECTED_CONN_CYCLES) { + return false; + } + } + + return true; +} + static bool parse_ad(struct bt_data *data, void *user_data) { bt_addr_le_t *addr = user_data; @@ -451,6 +465,7 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) bt_conn_unref(conn); clear_info(conn_info_ref); atomic_dec(&conn_count); + atomic_inc(&conn_info_ref->conn_count); } #if defined(CONFIG_BT_SMP) @@ -602,6 +617,8 @@ static void subscribe_to_service(struct bt_conn *conn, void *data) if (err != -ENOMEM && err != -ENOTCONN) { __ASSERT(!err, "Subscribe failed (err %d)", err); } + + atomic_clear_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED); } } @@ -669,7 +686,7 @@ void test_central_main(void) start_scan(); - while (true) { + while (!check_if_completed()) { /* reconnect peripherals when they drop out */ if (atomic_get(&conn_count) < CONFIG_BT_MAX_CONN && !atomic_test_bit(status_flags, DEVICE_IS_SCANNING) && @@ -698,6 +715,8 @@ void test_central_main(void) } k_msleep(10); } + + TEST_PASS("Central tests passed"); } void test_init(void) @@ -705,6 +724,7 @@ void test_init(void) extern enum bst_result_t bst_result; LOG_INF("Initializing Test"); + bst_ticker_set_next_tick_absolute(600*1e6); /* The peripherals determines whether the test passed. */ bst_result = Passed; } @@ -739,12 +759,23 @@ static void test_args(int argc, char **argv) bs_trace_raw(0, "Notification data size : %d\n", notification_size); } +static void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + TEST_FAIL("Test timeout (not passed after %lu seconds)", + (unsigned long)(HW_device_time / USEC_PER_SEC)); + } + + bs_trace_silent_exit(0); +} + static const struct bst_test_instance test_def[] = { { .test_id = "central", .test_descr = "Central Connection Stress", .test_args_f = test_args, .test_pre_init_f = test_init, + .test_tick_f = test_tick, .test_main_f = test_central_main }, BSTEST_END_MARKER diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt index 3b18f1052925f..eec4a5f36524d 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt +++ b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/CMakeLists.txt @@ -5,6 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(conn_stress_peripheral) +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + target_sources(app PRIVATE src/main.c ) diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c index b46d52b60d791..05aff350357c0 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c +++ b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c @@ -24,7 +24,7 @@ #include #include -LOG_MODULE_REGISTER(peripheral, LOG_LEVEL_INF); +LOG_MODULE_REGISTER(peripheral, LOG_LEVEL_DBG); #include "bstests.h" #include "bs_types.h" @@ -33,7 +33,8 @@ LOG_MODULE_REGISTER(peripheral, LOG_LEVEL_INF); #include "bs_pc_backchannel.h" #include "argparse.h" -#define TEST_ROUNDS 10 +#include "babblekit/testcase.h" + #define MIN_NOTIFICATIONS 50 #define NOTIFICATION_DATA_PREFIX "Counter:" @@ -52,6 +53,8 @@ BUILD_ASSERT(NOTIFICATION_DATA_LEN <= CHARACTERISTIC_DATA_MAX_LEN); #define CENTRAL_SERVICE_UUID BT_UUID_DECLARE_128(CENTRAL_SERVICE_UUID_VAL) #define CENTRAL_CHARACTERISTIC_UUID BT_UUID_DECLARE_128(CENTRAL_CHARACTERISTIC_UUID_VAL) +#define EXPECTED_CONN_CYCLES 1 + /* Custom Service Variables */ static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)); @@ -164,7 +167,7 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) memset(&conn_info, 0x00, sizeof(struct active_conn_info)); - if (rounds >= TEST_ROUNDS) { + if (rounds >= EXPECTED_CONN_CYCLES) { LOG_INF("Number of conn/disconn cycles reached, stopping advertiser..."); bt_le_adv_stop(); @@ -400,18 +403,34 @@ void test_peripheral_main(void) sprintf(name, "per-%d", get_device_nbr()); bt_set_name(name); - err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, NULL, 0, NULL, 0); + struct bt_le_adv_param adv_param = { + .id = BT_ID_DEFAULT, + .sid = 0, + .secondary_max_skip = 0, + .options = BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_SCANNABLE, + .interval_min = 0x0020, /* 20 ms */ + .interval_max = 0x0020, /* 20 ms */ + .peer = NULL, + }; + + struct bt_data sd[1]; + + sd[0].type = BT_DATA_NAME_COMPLETE; + sd[0].data_len = sizeof(CONFIG_BT_DEVICE_NAME) - 1; + sd[0].data = CONFIG_BT_DEVICE_NAME; + + err = bt_le_adv_start(&adv_param, sd, 1, sd, 1); if (err) { LOG_ERR("Advertising failed to start (err %d)", err); __ASSERT_NO_MSG(err); } - LOG_INF("Started advertising"); + LOG_DBG("Started advertising"); bt_gatt_cb_register(&gatt_callbacks); vnd_attr = bt_gatt_find_by_uuid(vnd_svc.attrs, vnd_svc.attr_count, &vnd_enc_uuid.uuid); - while (true) { + for (size_t i = 0; i < EXPECTED_CONN_CYCLES; i++) { LOG_DBG("Waiting for connection from central.."); while (!atomic_test_bit(conn_info.flags, CONN_INFO_CONNECTED)) { k_sleep(K_MSEC(10)); @@ -425,11 +444,12 @@ void test_peripheral_main(void) k_sleep(K_MSEC(10)); } + LOG_DBG("Waiting until MTU exchange.."); while (!atomic_test_bit(conn_info.flags, CONN_INFO_MTU_EXCHANGED)) { k_sleep(K_MSEC(10)); } - LOG_INF("Begin sending notifications to central.."); + LOG_DBG("Begin sending notifications to central.."); while (central_subscription && atomic_test_bit(conn_info.flags, CONN_INFO_CONNECTED)) { @@ -448,11 +468,13 @@ void test_peripheral_main(void) if (atomic_get(&conn_info.tx_notify_counter) > MIN_NOTIFICATIONS && atomic_get(&conn_info.notify_counter) > MIN_NOTIFICATIONS) { - LOG_INF("Disconnecting.."); + LOG_DBG("Disconnecting.."); disconnect(); } } } + + TEST_PASS("Peripheral tests passed"); } void test_init(void) @@ -460,6 +482,7 @@ void test_init(void) extern enum bst_result_t bst_result; LOG_INF("Initializing Test"); + bst_ticker_set_next_tick_absolute(600*1e6); bst_result = Failed; } @@ -481,12 +504,23 @@ static void test_args(int argc, char **argv) bs_trace_raw(0, "Notification data size : %d\n", notification_size); } +static void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + TEST_FAIL("Test timeout (not passed after %lu seconds)", + (unsigned long)(HW_device_time / USEC_PER_SEC)); + } + + bs_trace_silent_exit(0); +} + static const struct bst_test_instance test_def[] = { { .test_id = "peripheral", .test_descr = "Peripheral Connection Stress", .test_args_f = test_args, .test_pre_init_f = test_init, + .test_tick_f = test_tick, .test_main_f = test_peripheral_main }, BSTEST_END_MARKER diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/scripts/_conn_stress.sh b/tests/bsim/bluetooth/host/misc/conn_stress/scripts/_conn_stress.sh deleted file mode 100755 index 8e1428e44c04b..0000000000000 --- a/tests/bsim/bluetooth/host/misc/conn_stress/scripts/_conn_stress.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2023 Nordic Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -source ${ZEPHYR_BASE}/tests/bsim/sh_common.source - -simulation_id="conn_stress" -process_ids=""; exit_code=0 - -# We don't use the `Execute` fn from `bsim/sh_common.source` as -# `wait_for_background_jobs` will terminate the script if there's an error, and -# this test will fail often. We still want to run the packet conversion scripts, -# especially if the test was not successful. -function Execute(){ - if [ ! -f $1 ]; then - echo -e "ERR! \e[91m`pwd`/`basename $1` cannot be found (did you forget to\ - compile it?)\e[39m" - exit 1 - fi - timeout 60 $@ & process_ids="$process_ids $!" - - echo "Running $@" -} - -test_path="bsim_bluetooth_host_misc_conn_stress" -bsim_central_exe_name="bs_${BOARD_TS}_${test_path}_central_prj_conf" -bsim_peripheral_exe_name="bs_${BOARD_TS}_${test_path}_peripheral_prj_conf" - -# terminate running simulations (if any) -${BSIM_COMPONENTS_PATH}/common/stop_bsim.sh $simulation_id - -cd ${BSIM_OUT_PATH}/bin - -bsim_args="-RealEncryption=1 -v=2 -s=${simulation_id}" -test_args="-argstest notify_size=220 conn_interval=32" - -nr_of_units=12 - -for device in `seq 1 $nr_of_units`; do - let rs=$device*100 - - Execute "./${bsim_peripheral_exe_name}" ${bsim_args} \ - -d=$device -rs=$rs -testid=peripheral ${test_args} -done - -Execute ./bs_2G4_phy_v1 -dump -v=2 -s=${simulation_id} -D=13 -sim_length=1000e6 & - -Execute "./${bsim_central_exe_name}" ${bsim_args} -d=0 -rs=001 -testid=central ${test_args} - -for process_id in $process_ids; do - wait $process_id || let "exit_code=$?" -done - -for i in `seq -w 0 $nr_of_units`; do - ${BSIM_OUT_PATH}/components/ext_2G4_phy_v1/dump_post_process/csv2pcap -o \ - ${BSIM_OUT_PATH}/results/${simulation_id}/Trace_$i.pcap \ - ${BSIM_OUT_PATH}/results/${simulation_id}/d_2G4_$i.Tx.csv - - ${BSIM_OUT_PATH}/components/ext_2G4_phy_v1/dump_post_process/csv2pcap -o \ - ${BSIM_OUT_PATH}/results/${simulation_id}/Trace_Rx_$i.pcap \ - ${BSIM_OUT_PATH}/results/${simulation_id}/d_2G4_$i.Rx.csv - - echo "${BSIM_OUT_PATH}/results/${simulation_id}/Trace_$i.pcap" - echo "${BSIM_OUT_PATH}/results/${simulation_id}/Trace_Rx_$i.pcap" -done - -exit $exit_code diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh b/tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh new file mode 100755 index 0000000000000..06f16a830e415 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="conn_stress" + +test_path="tests_bsim_bluetooth_host_misc_conn_stress" +bsim_central_exe_name="bs_${BOARD_TS}_${test_path}_central_prj_conf" +bsim_peripheral_exe_name="bs_${BOARD_TS}_${test_path}_peripheral_prj_conf" +bsim_args="-RealEncryption=1 -v=5 -s=${simulation_id}" +test_args="-argstest notify_size=220 conn_interval=32" + +cd ${BSIM_OUT_PATH}/bin + +for device in `seq 1 12`; do + let rs=$device*100 + + Execute "./${bsim_peripheral_exe_name}" ${bsim_args} \ + -d=$device -rs=$rs -testid=peripheral ${test_args} +done + +Execute "./${bsim_central_exe_name}" ${bsim_args} -d=0 -rs=001 -testid=central ${test_args} + +Execute ./bs_2G4_phy_v1 -dump -v=2 -s=${simulation_id} -D=13 -sim_length=10000e6 & + +wait_for_background_jobs From 63874d2e2e2d21d206e203b396f9f2dccb3c8af2 Mon Sep 17 00:00:00 2001 From: Artur Dobrynin Date: Fri, 17 Oct 2025 15:30:48 +0200 Subject: [PATCH 246/397] tests: bsim: bluetooth: host: robust subscription proc GATT subscription in conn_stress test was failing and stalling the test due to lack of TX buffers. Retry mechanism added as a workaround. Removing this workaround would make the test fail due to deadlocks, and require allocating more buffers with CONFIG_BT_L2CAP_TX_BUF_COUNT set to 10 as a workaround. Signed-off-by: Artur Dobrynin --- .../host/misc/conn_stress/central/prj.conf | 4 -- .../host/misc/conn_stress/central/src/main.c | 55 ++++++++++++++----- .../misc/conn_stress/peripheral/src/main.c | 12 ++-- .../misc/conn_stress/scripts/conn_stress.sh | 10 ++-- 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf index 1cc7c01132495..9d1fbd3f5a6d3 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf @@ -22,10 +22,6 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_ASSERT_ON_ERRORS=y -# TODO: use default 3 -# we get an ATT timeout if 3 or SMP timeout if 10 -CONFIG_BT_L2CAP_TX_BUF_COUNT=10 - # deadlock on central with the default. # the problem is that `tx_free` is called from both syswq and btwq in that case. CONFIG_BT_RECV_WORKQ_BT=y diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c b/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c index 9ff3b0a0af636..e17554c3f7f1d 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,7 +22,7 @@ #include #include -LOG_MODULE_REGISTER(central, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(central, LOG_LEVEL_INF); #include "bstests.h" #include "bs_types.h" @@ -73,6 +73,7 @@ enum { CONN_INFO_MTU_EXCHANGED, CONN_INFO_DISCOVERING, CONN_INFO_DISCOVER_PAUSED, + CONN_INFO_SUBSCRIPTION_FAILED, CONN_INFO_SUBSCRIBED, /* Total number of flags - must be at the end of the enum */ @@ -213,6 +214,24 @@ static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params return BT_GATT_ITER_CONTINUE; } +static void subscribe_func(struct bt_conn *conn, uint8_t err, + struct bt_gatt_subscribe_params *params) +{ + struct conn_info *conn_info_ref; + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + __ASSERT(!err, "Subscribe failed for addr %s (err %d)", addr, err); + + conn_info_ref = get_conn_info_ref(conn); + __ASSERT_NO_MSG(conn_info_ref); + + atomic_clear_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIPTION_FAILED); + atomic_set_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIBED); + + LOG_DBG("[SUBSCRIBED] addr %s", addr); +} + static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { @@ -248,6 +267,7 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at err = bt_gatt_discover(conn, &conn_info_ref->discover_params); if (err == -ENOMEM || err == -ENOTCONN) { + atomic_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED); goto retry; } @@ -263,6 +283,7 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at err = bt_gatt_discover(conn, &conn_info_ref->discover_params); if (err == -ENOMEM || err == -ENOTCONN) { + atomic_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED); goto retry; } @@ -270,26 +291,19 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at } else { conn_info_ref->subscribe_params.notify = notify_func; + conn_info_ref->subscribe_params.subscribe = subscribe_func; conn_info_ref->subscribe_params.value = BT_GATT_CCC_NOTIFY; conn_info_ref->subscribe_params.ccc_handle = attr->handle; err = bt_gatt_subscribe(conn, &conn_info_ref->subscribe_params); - if (err == -ENOMEM || err == -ENOTCONN) { + if (err == -ENOMEM || err == -ENOTCONN || err == -EALREADY) { + LOG_DBG("Subcription failed (err %d)", err); + atomic_set_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIPTION_FAILED); goto retry; } - if (err != -EALREADY) { - __ASSERT(!err, "Subscribe failed (err %d)", err); - } - __ASSERT_NO_MSG(atomic_test_bit(conn_info_ref->flags, CONN_INFO_DISCOVERING)); __ASSERT_NO_MSG(!atomic_test_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIBED)); - atomic_set_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIBED); - - char addr[BT_ADDR_LE_STR_LEN]; - - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - LOG_INF("[SUBSCRIBED] addr %s", addr); } return BT_GATT_ITER_STOP; @@ -299,7 +313,6 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at * later. */ LOG_INF("out of memory/not connected, continuing sub later (err %d)", err); - atomic_set_bit(conn_info_ref->flags, CONN_INFO_DISCOVER_PAUSED); return BT_GATT_ITER_STOP; } @@ -579,6 +592,18 @@ static void subscribe_to_service(struct bt_conn *conn, void *data) return; } + /* If subcription attempt failed before (due to most likely lack of TX buffers), + * make a new attempt here. + */ + if (atomic_test_bit(conn_info_ref->flags, CONN_INFO_SUBSCRIPTION_FAILED)) { + err = bt_gatt_subscribe(conn, &conn_info_ref->subscribe_params); + if (err != -ENOMEM) { + __ASSERT(!err, "Subcription failed"); + } else { + return; + } + } + /* start subscription procedure if: * - we haven't started it yet for this conn * - it was suspended due to a lack of resources @@ -724,7 +749,7 @@ void test_init(void) extern enum bst_result_t bst_result; LOG_INF("Initializing Test"); - bst_ticker_set_next_tick_absolute(600*1e6); + bst_ticker_set_next_tick_absolute(100*1e6); /* The peripherals determines whether the test passed. */ bst_result = Passed; } diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c index 05aff350357c0..d9b56cc6c54f8 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c +++ b/tests/bsim/bluetooth/host/misc/conn_stress/peripheral/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,7 +24,7 @@ #include #include -LOG_MODULE_REGISTER(peripheral, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(peripheral, LOG_LEVEL_INF); #include "bstests.h" #include "bs_types.h" @@ -424,7 +424,7 @@ void test_peripheral_main(void) LOG_ERR("Advertising failed to start (err %d)", err); __ASSERT_NO_MSG(err); } - LOG_DBG("Started advertising"); + LOG_INF("Started advertising"); bt_gatt_cb_register(&gatt_callbacks); @@ -449,7 +449,7 @@ void test_peripheral_main(void) k_sleep(K_MSEC(10)); } - LOG_DBG("Begin sending notifications to central.."); + LOG_INF("Begin sending notifications to central.."); while (central_subscription && atomic_test_bit(conn_info.flags, CONN_INFO_CONNECTED)) { @@ -468,7 +468,7 @@ void test_peripheral_main(void) if (atomic_get(&conn_info.tx_notify_counter) > MIN_NOTIFICATIONS && atomic_get(&conn_info.notify_counter) > MIN_NOTIFICATIONS) { - LOG_DBG("Disconnecting.."); + LOG_INF("Disconnecting.."); disconnect(); } } @@ -482,7 +482,7 @@ void test_init(void) extern enum bst_result_t bst_result; LOG_INF("Initializing Test"); - bst_ticker_set_next_tick_absolute(600*1e6); + bst_ticker_set_next_tick_absolute(100*1e6); bst_result = Failed; } diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh b/tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh index 06f16a830e415..e1d81ff85ae89 100755 --- a/tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh +++ b/tests/bsim/bluetooth/host/misc/conn_stress/scripts/conn_stress.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright (c) 2023 Nordic Semiconductor +# Copyright (c) 2023-2025 Nordic Semiconductor # SPDX-License-Identifier: Apache-2.0 source ${ZEPHYR_BASE}/tests/bsim/sh_common.source @@ -9,9 +9,11 @@ simulation_id="conn_stress" test_path="tests_bsim_bluetooth_host_misc_conn_stress" bsim_central_exe_name="bs_${BOARD_TS}_${test_path}_central_prj_conf" bsim_peripheral_exe_name="bs_${BOARD_TS}_${test_path}_peripheral_prj_conf" -bsim_args="-RealEncryption=1 -v=5 -s=${simulation_id}" +bsim_args="-RealEncryption=1 -v=2 -s=${simulation_id}" test_args="-argstest notify_size=220 conn_interval=32" +EXECUTE_TIMEOUT=120 + cd ${BSIM_OUT_PATH}/bin for device in `seq 1 12`; do @@ -21,8 +23,8 @@ for device in `seq 1 12`; do -d=$device -rs=$rs -testid=peripheral ${test_args} done -Execute "./${bsim_central_exe_name}" ${bsim_args} -d=0 -rs=001 -testid=central ${test_args} +Execute "./${bsim_central_exe_name}" ${bsim_args} -d=0 -rs=1 -testid=central ${test_args} -Execute ./bs_2G4_phy_v1 -dump -v=2 -s=${simulation_id} -D=13 -sim_length=10000e6 & +Execute ./bs_2G4_phy_v1 -dump -v=2 -s=${simulation_id} -D=13 -sim_length=100e6 wait_for_background_jobs From 67cc702fb55f669b1beb699d8ec53170c22b3ddb Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Fri, 17 Oct 2025 10:12:25 +0300 Subject: [PATCH 247/397] MAINTAINERS: Add cc23xx and collaborator for TI SimpleLink Platforms - Add cc23xx SoCs to files in TI SimpleLink - Add bogdanovs as colaborator for TI SimpleLink Signed-off-by: Stoyan Bogdanov --- MAINTAINERS.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 0a996a1d7253f..06b7c992d6d7e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -4881,10 +4881,13 @@ TI SimpleLink Platforms: status: maintained maintainers: - vaishnavachath + collaborators: + - bogdanovs files: - boards/ti/cc*/ - boards/ti/msp*/ - drivers/*/*cc13* + - drivers/*/*cc23* - drivers/*/*cc25* - drivers/*/*cc26* - drivers/*/*cc32* From 4ed7210e0657a24e63dabd57f821af3bb28c0fba Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 17 Oct 2025 11:14:30 +1000 Subject: [PATCH 248/397] gnss: gnss_emul: manual data update mode Add an option for the GNSS fix state reported by the emulated GNSS modem to be manually configured by test code, instead of being hardcoded to always achieve a fix of hardcoded parameters after 5 seconds. Signed-off-by: Jordan Yates --- drivers/gnss/Kconfig.emul | 9 ++++ drivers/gnss/gnss_emul.c | 63 +++++++++++++++++-------- include/zephyr/drivers/gnss/gnss_emul.h | 33 +++++++++++++ 3 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 include/zephyr/drivers/gnss/gnss_emul.h diff --git a/drivers/gnss/Kconfig.emul b/drivers/gnss/Kconfig.emul index b6667f36864bd..cb3cfdd3e6647 100644 --- a/drivers/gnss/Kconfig.emul +++ b/drivers/gnss/Kconfig.emul @@ -9,3 +9,12 @@ config GNSS_EMUL select TIMEOUT_64BIT help Enable emulated GNSS driver. + +config GNSS_EMUL_MANUAL_UPDATE + bool "Internal state manually updated through gnss_emul_set_data" + depends on GNSS_EMUL + help + The internal state of the GNSS emulator (location, time, etc) + must be updated through gnss_emul_set_data, instead of automatically + transitioning to hardcoded states at hardcoded times. Once the current + time is set, the published time automatically increments. diff --git a/drivers/gnss/gnss_emul.c b/drivers/gnss/gnss_emul.c index ac1761d84c855..b61cb60dd7feb 100644 --- a/drivers/gnss/gnss_emul.c +++ b/drivers/gnss/gnss_emul.c @@ -73,15 +73,6 @@ static void gnss_emul_update_fix_timestamp(const struct device *dev, bool resumi } } -static bool gnss_emul_fix_is_acquired(const struct device *dev) -{ - struct gnss_emul_data *data = dev->data; - int64_t time_since_resume; - - time_since_resume = data->fix_timestamp_ms - data->resume_timestamp_ms; - return time_since_resume >= GNSS_EMUL_FIX_ACQUIRE_TIME_MS; -} - #ifdef CONFIG_PM_DEVICE static void gnss_emul_clear_fix_timestamp(const struct device *dev) { @@ -346,23 +337,13 @@ static DEVICE_API(gnss, api) = { .get_supported_systems = gnss_emul_api_get_supported_systems, }; -static void gnss_emul_clear_data(const struct device *dev) +void gnss_emul_clear_data(const struct device *dev) { struct gnss_emul_data *data = dev->data; memset(&data->data, 0, sizeof(data->data)); } -static void gnss_emul_set_fix(const struct device *dev) -{ - struct gnss_emul_data *data = dev->data; - - data->data.info.satellites_cnt = 8; - data->data.info.hdop = 100; - data->data.info.fix_status = GNSS_FIX_STATUS_GNSS_FIX; - data->data.info.fix_quality = GNSS_FIX_QUALITY_GNSS_SPS; -} - static void gnss_emul_set_utc(const struct device *dev) { struct gnss_emul_data *data = dev->data; @@ -384,6 +365,40 @@ static void gnss_emul_set_utc(const struct device *dev) data->data.utc.century_year = datetime.tm_year % 100; } +#ifdef CONFIG_GNSS_EMUL_MANUAL_UPDATE + +void gnss_emul_set_data(const struct device *dev, const struct navigation_data *nav, + const struct gnss_info *info, int64_t timestamp_ms) +{ + struct gnss_emul_data *data = dev->data; + + data->data.nav_data = *nav; + data->data.info = *info; + data->fix_timestamp_ms = timestamp_ms; + gnss_emul_set_utc(dev); +} + +#else + +static bool gnss_emul_fix_is_acquired(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + int64_t time_since_resume; + + time_since_resume = data->fix_timestamp_ms - data->resume_timestamp_ms; + return time_since_resume >= GNSS_EMUL_FIX_ACQUIRE_TIME_MS; +} + +static void gnss_emul_set_fix(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + data->data.info.satellites_cnt = 8; + data->data.info.hdop = 100; + data->data.info.fix_status = GNSS_FIX_STATUS_GNSS_FIX; + data->data.info.fix_quality = GNSS_FIX_QUALITY_GNSS_SPS; +} + static void gnss_emul_set_nav_data(const struct device *dev) { struct gnss_emul_data *data = dev->data; @@ -395,6 +410,8 @@ static void gnss_emul_set_nav_data(const struct device *dev) data->data.nav_data.altitude = 20000; } +#endif /* CONFIG_GNSS_EMUL_MANUAL_UPDATE */ + #ifdef CONFIG_GNSS_SATELLITES static void gnss_emul_clear_satellites(const struct device *dev) { @@ -444,6 +461,11 @@ static void gnss_emul_work_handler(struct k_work *work) struct gnss_emul_data *data = CONTAINER_OF(dwork, struct gnss_emul_data, data_dwork); const struct device *dev = data->dev; +#ifdef CONFIG_GNSS_EMUL_MANUAL_UPDATE + /* Tick the timestamp */ + gnss_emul_set_utc(dev); +#else + /* Automatically update internal state if not done manually */ if (!gnss_emul_fix_is_acquired(dev)) { gnss_emul_clear_data(dev); } else { @@ -451,6 +473,7 @@ static void gnss_emul_work_handler(struct k_work *work) gnss_emul_set_utc(dev); gnss_emul_set_nav_data(dev); } +#endif /* CONFIG_GNSS_EMUL_MANUAL_UPDATE */ gnss_publish_data(dev, &data->data); diff --git a/include/zephyr/drivers/gnss/gnss_emul.h b/include/zephyr/drivers/gnss/gnss_emul.h new file mode 100644 index 0000000000000..023642c933ae3 --- /dev/null +++ b/include/zephyr/drivers/gnss/gnss_emul.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Embeint Pty Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_GNSS_GNSS_EMUL_H_ +#define ZEPHYR_DRIVERS_GNSS_GNSS_EMUL_H_ + +#include + +#include +#include + +/** + * @brief Clear all internal GNSS data of the emulator + * + * @param dev GNSS emulator device + */ +void gnss_emul_clear_data(const struct device *dev); + +/** + * @brief Set the internal GNSS data of the emulator + * + * @param dev GNSS emulator device + * @param nav Updated navigation state + * @param info Updated GNSS fix information + * @param timestamp_ms Timestamp associated with the GNSS fix + */ +void gnss_emul_set_data(const struct device *dev, const struct navigation_data *nav, + const struct gnss_info *info, int64_t timestamp_ms); + +#endif /* ZEPHYR_DRIVERS_GNSS_GNSS_EMUL_H_ */ From 554e7c2eee22b807589f9a6730959dae92ea5935 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 17 Oct 2025 11:19:33 +1000 Subject: [PATCH 249/397] gnss: gnss_emul: init with `pm_device_driver_init` Remove the custom initialisation logic that attempts to duplicate `pm_device_driver_init`. Signed-off-by: Jordan Yates --- drivers/gnss/gnss_emul.c | 93 ++++++++++--------------- dts/bindings/gnss/zephyr,gnss-emul.yaml | 2 + 2 files changed, 37 insertions(+), 58 deletions(-) diff --git a/drivers/gnss/gnss_emul.c b/drivers/gnss/gnss_emul.c index b61cb60dd7feb..e898e8e90ddac 100644 --- a/drivers/gnss/gnss_emul.c +++ b/drivers/gnss/gnss_emul.c @@ -73,15 +73,6 @@ static void gnss_emul_update_fix_timestamp(const struct device *dev, bool resumi } } -#ifdef CONFIG_PM_DEVICE -static void gnss_emul_clear_fix_timestamp(const struct device *dev) -{ - struct gnss_emul_data *data = dev->data; - - data->fix_timestamp_ms = 0; -} -#endif - static void gnss_emul_schedule_work(const struct device *dev) { struct gnss_emul_data *data = dev->data; @@ -181,42 +172,6 @@ static int gnss_emul_get_enabled_systems(const struct device *dev, gnss_systems_ return 0; } -#ifdef CONFIG_PM_DEVICE -static void gnss_emul_resume(const struct device *dev) -{ - gnss_emul_update_fix_timestamp(dev, true); -} - -static void gnss_emul_suspend(const struct device *dev) -{ - gnss_emul_clear_fix_timestamp(dev); -} - -static int gnss_emul_pm_action(const struct device *dev, enum pm_device_action action) -{ - int ret = 0; - - gnss_emul_lock(dev); - - switch (action) { - case PM_DEVICE_ACTION_SUSPEND: - gnss_emul_suspend(dev); - break; - - case PM_DEVICE_ACTION_RESUME: - gnss_emul_resume(dev); - break; - - default: - ret = -ENOTSUP; - break; - } - - gnss_emul_unlock(dev); - return ret; -} -#endif - static int gnss_emul_api_set_fix_rate(const struct device *dev, uint32_t fix_interval_ms) { int ret = -ENODEV; @@ -486,27 +441,49 @@ static void gnss_emul_work_handler(struct k_work *work) gnss_emul_schedule_work(dev); } -static void gnss_emul_init_data(const struct device *dev) +static void gnss_emul_resume(const struct device *dev) { - struct gnss_emul_data *data = dev->data; + gnss_emul_update_fix_timestamp(dev, true); +} - data->dev = dev; - k_sem_init(&data->lock, 1, 1); - k_work_init_delayable(&data->data_dwork, gnss_emul_work_handler); +static void gnss_emul_suspend(const struct device *dev) +{ + gnss_emul_clear_data(dev); } -static int gnss_emul_init(const struct device *dev) +static int gnss_emul_pm_action(const struct device *dev, enum pm_device_action action) { - gnss_emul_init_data(dev); + int ret = 0; - if (pm_device_is_powered(dev)) { - gnss_emul_update_fix_timestamp(dev, true); - gnss_emul_schedule_work(dev); - } else { - pm_device_init_off(dev); + gnss_emul_lock(dev); + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + gnss_emul_suspend(dev); + break; + + case PM_DEVICE_ACTION_RESUME: + gnss_emul_resume(dev); + break; + + default: + ret = -ENOTSUP; + break; } - return pm_device_runtime_enable(dev); + gnss_emul_unlock(dev); + return ret; +} + +static int gnss_emul_init(const struct device *dev) +{ + struct gnss_emul_data *data = dev->data; + + data->dev = dev; + k_sem_init(&data->lock, 1, 1); + k_work_init_delayable(&data->data_dwork, gnss_emul_work_handler); + + return pm_device_driver_init(dev, gnss_emul_pm_action); } #define GNSS_EMUL_NAME(inst, name) _CONCAT(name, inst) diff --git a/dts/bindings/gnss/zephyr,gnss-emul.yaml b/dts/bindings/gnss/zephyr,gnss-emul.yaml index eb7d9eec8acc3..10c4659dc0785 100644 --- a/dts/bindings/gnss/zephyr,gnss-emul.yaml +++ b/dts/bindings/gnss/zephyr,gnss-emul.yaml @@ -4,3 +4,5 @@ description: Zephyr emulated GNSS device compatible: "zephyr,gnss-emul" + +include: base.yaml From 41184adbb1b422b0cf726b3d4fe1e4293706ce9d Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 17 Oct 2025 14:14:24 +1000 Subject: [PATCH 250/397] gnss: gnss_emul: halt callbacks when not ACTIVE Ensure that callbacks do not continue to fire after `ACTION_SUSPEND`. Signed-off-by: Jordan Yates --- drivers/gnss/gnss_emul.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gnss/gnss_emul.c b/drivers/gnss/gnss_emul.c index e898e8e90ddac..d7d66b5c0ed4e 100644 --- a/drivers/gnss/gnss_emul.c +++ b/drivers/gnss/gnss_emul.c @@ -39,6 +39,7 @@ struct gnss_emul_data { enum gnss_navigation_mode nav_mode; gnss_systems_t enabled_systems; struct gnss_data data; + bool active; #ifdef CONFIG_GNSS_SATELLITES struct gnss_satellite satellites[GNSS_EMUL_SUPPORTED_SYSTEMS_COUNT]; @@ -92,7 +93,7 @@ static bool gnss_emul_is_resumed(const struct device *dev) { struct gnss_emul_data *data = dev->data; - return data->fix_timestamp_ms > 0; + return data->active; } static void gnss_emul_lock(const struct device *dev) @@ -443,11 +444,19 @@ static void gnss_emul_work_handler(struct k_work *work) static void gnss_emul_resume(const struct device *dev) { + struct gnss_emul_data *data = dev->data; + + data->active = true; gnss_emul_update_fix_timestamp(dev, true); + gnss_emul_schedule_work(dev); } static void gnss_emul_suspend(const struct device *dev) { + struct gnss_emul_data *data = dev->data; + + data->active = false; + gnss_emul_cancel_work(dev); gnss_emul_clear_data(dev); } From bc9e7e4365a9219027b5e181b5ab52441512ed83 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 17 Oct 2025 14:19:54 +1000 Subject: [PATCH 251/397] gnss: gnss_emul: allow direct config queries Provide an escape hatch from the GNSS API requirement that a device be active to run the configuration `get` functions. This is useful in the context of an emulator device to query how other software modules have configured the GNSS. Signed-off-by: Jordan Yates --- drivers/gnss/gnss_emul.c | 7 +++--- include/zephyr/drivers/gnss/gnss_emul.h | 30 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/gnss/gnss_emul.c b/drivers/gnss/gnss_emul.c index d7d66b5c0ed4e..7c0310d8c4492 100644 --- a/drivers/gnss/gnss_emul.c +++ b/drivers/gnss/gnss_emul.c @@ -123,7 +123,7 @@ static int gnss_emul_set_fix_rate(const struct device *dev, uint32_t fix_interva return 0; } -static int gnss_emul_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms) +int gnss_emul_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms) { struct gnss_emul_data *data = dev->data; @@ -144,8 +144,7 @@ static int gnss_emul_set_navigation_mode(const struct device *dev, return 0; } -static int gnss_emul_get_navigation_mode(const struct device *dev, - enum gnss_navigation_mode *mode) +int gnss_emul_get_navigation_mode(const struct device *dev, enum gnss_navigation_mode *mode) { struct gnss_emul_data *data = dev->data; @@ -165,7 +164,7 @@ static int gnss_emul_set_enabled_systems(const struct device *dev, gnss_systems_ return 0; } -static int gnss_emul_get_enabled_systems(const struct device *dev, gnss_systems_t *systems) +int gnss_emul_get_enabled_systems(const struct device *dev, gnss_systems_t *systems) { struct gnss_emul_data *data = dev->data; diff --git a/include/zephyr/drivers/gnss/gnss_emul.h b/include/zephyr/drivers/gnss/gnss_emul.h index 023642c933ae3..dc5802ee40c70 100644 --- a/include/zephyr/drivers/gnss/gnss_emul.h +++ b/include/zephyr/drivers/gnss/gnss_emul.h @@ -30,4 +30,34 @@ void gnss_emul_clear_data(const struct device *dev); void gnss_emul_set_data(const struct device *dev, const struct navigation_data *nav, const struct gnss_info *info, int64_t timestamp_ms); +/** + * @brief Retrieve the last configured fix rate, regardless of PM state + * + * @param dev GNSS emulator device + * @param fix_interval_ms Output fix interval + * + * @retval 0 On success + */ +int gnss_emul_get_fix_rate(const struct device *dev, uint32_t *fix_interval_ms); + +/** + * @brief Retrieve the last configured navigation mode, regardless of PM state + * + * @param dev GNSS emulator device + * @param mode Output navigation mode + * + * @retval 0 On success + */ +int gnss_emul_get_navigation_mode(const struct device *dev, enum gnss_navigation_mode *mode); + +/** + * @brief Retrieve the last configured systems, regardless of PM state + * + * @param dev GNSS emulator device + * @param systems Output GNSS systems + * + * @retval 0 On success + */ +int gnss_emul_get_enabled_systems(const struct device *dev, gnss_systems_t *systems); + #endif /* ZEPHYR_DRIVERS_GNSS_GNSS_EMUL_H_ */ From a360cbe5fd6e2387ed5a334fa8bd7fc084b9b434 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 17 Oct 2025 15:29:15 +1000 Subject: [PATCH 252/397] gnss: gnss_emul: decouple realtime and gnss time Allow the emulator to be set to an arbitrary UTC time, instead of being locked to reporting the current system uptime as UTC. Signed-off-by: Jordan Yates --- drivers/gnss/gnss_emul.c | 12 +++++++----- include/zephyr/drivers/gnss/gnss_emul.h | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gnss/gnss_emul.c b/drivers/gnss/gnss_emul.c index 7c0310d8c4492..5c706c9ce105f 100644 --- a/drivers/gnss/gnss_emul.c +++ b/drivers/gnss/gnss_emul.c @@ -35,6 +35,7 @@ struct gnss_emul_data { struct k_sem lock; int64_t resume_timestamp_ms; int64_t fix_timestamp_ms; + int64_t boot_realtime_ms; uint32_t fix_interval_ms; enum gnss_navigation_mode nav_mode; gnss_systems_t enabled_systems; @@ -302,15 +303,16 @@ void gnss_emul_clear_data(const struct device *dev) static void gnss_emul_set_utc(const struct device *dev) { struct gnss_emul_data *data = dev->data; + int64_t timestamp_realtime; time_t timestamp; struct tm datetime; uint16_t millisecond; - timestamp = (time_t)(data->fix_timestamp_ms / 1000); + timestamp_realtime = data->boot_realtime_ms + data->fix_timestamp_ms; + timestamp = (time_t)(timestamp_realtime / 1000); gmtime_r(×tamp, &datetime); - millisecond = (uint16_t)(data->fix_timestamp_ms % 1000) - + (uint16_t)(datetime.tm_sec * 1000); + millisecond = (uint16_t)(timestamp_realtime % 1000) + (uint16_t)(datetime.tm_sec * 1000); data->data.utc.hour = datetime.tm_hour; data->data.utc.millisecond = millisecond; @@ -323,13 +325,13 @@ static void gnss_emul_set_utc(const struct device *dev) #ifdef CONFIG_GNSS_EMUL_MANUAL_UPDATE void gnss_emul_set_data(const struct device *dev, const struct navigation_data *nav, - const struct gnss_info *info, int64_t timestamp_ms) + const struct gnss_info *info, int64_t boot_realtime_ms) { struct gnss_emul_data *data = dev->data; data->data.nav_data = *nav; data->data.info = *info; - data->fix_timestamp_ms = timestamp_ms; + data->boot_realtime_ms = boot_realtime_ms; gnss_emul_set_utc(dev); } diff --git a/include/zephyr/drivers/gnss/gnss_emul.h b/include/zephyr/drivers/gnss/gnss_emul.h index dc5802ee40c70..4416ce26cfed6 100644 --- a/include/zephyr/drivers/gnss/gnss_emul.h +++ b/include/zephyr/drivers/gnss/gnss_emul.h @@ -25,10 +25,10 @@ void gnss_emul_clear_data(const struct device *dev); * @param dev GNSS emulator device * @param nav Updated navigation state * @param info Updated GNSS fix information - * @param timestamp_ms Timestamp associated with the GNSS fix + * @param boot_realtime_ms Unix timestamp associated with system boot */ void gnss_emul_set_data(const struct device *dev, const struct navigation_data *nav, - const struct gnss_info *info, int64_t timestamp_ms); + const struct gnss_info *info, int64_t boot_realtime_ms); /** * @brief Retrieve the last configured fix rate, regardless of PM state From 073ff97f48effd1607a4c4f32467d190c6bcecf1 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 17 Oct 2025 15:34:58 +1000 Subject: [PATCH 253/397] tests: drivers: gnss: gnss_emul: test driver Test the behaviour of the emulated GNSS driver. Signed-off-by: Jordan Yates --- tests/drivers/gnss/gnss_emul/CMakeLists.txt | 12 ++ tests/drivers/gnss/gnss_emul/app.overlay | 17 +++ tests/drivers/gnss/gnss_emul/prj.conf | 12 ++ tests/drivers/gnss/gnss_emul/src/main.c | 161 ++++++++++++++++++++ tests/drivers/gnss/gnss_emul/testcase.yaml | 11 ++ 5 files changed, 213 insertions(+) create mode 100644 tests/drivers/gnss/gnss_emul/CMakeLists.txt create mode 100644 tests/drivers/gnss/gnss_emul/app.overlay create mode 100644 tests/drivers/gnss/gnss_emul/prj.conf create mode 100644 tests/drivers/gnss/gnss_emul/src/main.c create mode 100644 tests/drivers/gnss/gnss_emul/testcase.yaml diff --git a/tests/drivers/gnss/gnss_emul/CMakeLists.txt b/tests/drivers/gnss/gnss_emul/CMakeLists.txt new file mode 100644 index 0000000000000..03db665f34ab0 --- /dev/null +++ b/tests/drivers/gnss/gnss_emul/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Embeint Pty Ltd +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(gnss_emul) + +target_sources(app PRIVATE + src/main.c +) diff --git a/tests/drivers/gnss/gnss_emul/app.overlay b/tests/drivers/gnss/gnss_emul/app.overlay new file mode 100644 index 0000000000000..1746d8ccb9486 --- /dev/null +++ b/tests/drivers/gnss/gnss_emul/app.overlay @@ -0,0 +1,17 @@ +/* + * Copyright 2025 Embeint Pty Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + gnss = &gnss; + }; + + gnss: gnss { + compatible = "zephyr,gnss-emul"; + status = "okay"; + zephyr,pm-device-runtime-auto; + }; +}; diff --git a/tests/drivers/gnss/gnss_emul/prj.conf b/tests/drivers/gnss/gnss_emul/prj.conf new file mode 100644 index 0000000000000..dde94f372248d --- /dev/null +++ b/tests/drivers/gnss/gnss_emul/prj.conf @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Embeint Pty Ltd +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_ZTEST_STACK_SIZE=4096 + +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y + +CONFIG_GNSS=y +CONFIG_GNSS_EMUL=y +CONFIG_GNSS_EMUL_MANUAL_UPDATE=y diff --git a/tests/drivers/gnss/gnss_emul/src/main.c b/tests/drivers/gnss/gnss_emul/src/main.c new file mode 100644 index 0000000000000..a76f2c4337880 --- /dev/null +++ b/tests/drivers/gnss/gnss_emul/src/main.c @@ -0,0 +1,161 @@ +/* + * Copyright 2025 Embeint Pty Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include + +static void gnss_data_callback(const struct device *dev, const struct gnss_data *data); + +GNSS_DATA_CALLBACK_DEFINE(DEVICE_DT_GET(DT_ALIAS(gnss)), gnss_data_callback); +static K_SEM_DEFINE(gnss_data_published, 0, 1); +static struct gnss_data gnss_published_data; + +static void expected_pm_state(const struct device *dev, enum pm_device_state expected) +{ + enum pm_device_state state; + + zassert_equal(0, pm_device_state_get(dev, &state)); + zassert_equal(expected, state); +} + +static void gnss_data_callback(const struct device *dev, const struct gnss_data *data) +{ + gnss_published_data = *data; + k_sem_give(&gnss_data_published); +} + +static void print_time(const struct gnss_time *utc) +{ + printk("TIME: %02d/%02d/%02d %02d:%02d:%02d.%03d\n", utc->century_year, utc->month, + utc->month_day, utc->hour, utc->minute, utc->millisecond / 1000, + utc->millisecond % 1000); +} + +ZTEST(gnss_emul, test_config_functions) +{ + const struct device *dev = DEVICE_DT_GET(DT_ALIAS(gnss)); + enum gnss_navigation_mode mode; + gnss_systems_t systems; + uint32_t fix_rate; + + /* Booted into suspend mode */ + expected_pm_state(dev, PM_DEVICE_STATE_SUSPENDED); + + /* Configuration get API functions fail when suspended */ + zassert_equal(-ENODEV, gnss_get_enabled_systems(dev, &systems)); + zassert_equal(-ENODEV, gnss_get_navigation_mode(dev, &mode)); + zassert_equal(-ENODEV, gnss_get_fix_rate(dev, &fix_rate)); + + /* Configuration can be queried when enabled */ + zassert_equal(0, pm_device_runtime_get(dev)); + zassert_equal(0, gnss_set_enabled_systems(dev, GNSS_SYSTEM_GPS | GNSS_SYSTEM_GALILEO)); + zassert_equal(0, gnss_set_navigation_mode(dev, GNSS_NAVIGATION_MODE_HIGH_DYNAMICS)); + zassert_equal(0, gnss_set_fix_rate(dev, 1500)); + + zassert_equal(0, gnss_get_enabled_systems(dev, &systems)); + zassert_equal(0, gnss_get_navigation_mode(dev, &mode)); + zassert_equal(0, gnss_get_fix_rate(dev, &fix_rate)); + zassert_equal(GNSS_SYSTEM_GPS | GNSS_SYSTEM_GALILEO, systems); + zassert_equal(GNSS_NAVIGATION_MODE_HIGH_DYNAMICS, mode); + zassert_equal(1500, fix_rate); + + zassert_equal(0, pm_device_runtime_put(dev)); + + /* Fails again when suspended */ + zassert_equal(-ENODEV, gnss_get_enabled_systems(dev, &systems)); + zassert_equal(-ENODEV, gnss_get_navigation_mode(dev, &mode)); + zassert_equal(-ENODEV, gnss_get_fix_rate(dev, &fix_rate)); + + /* But escape hatches work */ + systems = 0; + mode = 0; + fix_rate = 0; + zassert_equal(0, gnss_emul_get_enabled_systems(dev, &systems)); + zassert_equal(0, gnss_emul_get_navigation_mode(dev, &mode)); + zassert_equal(0, gnss_emul_get_fix_rate(dev, &fix_rate)); + zassert_equal(GNSS_SYSTEM_GPS | GNSS_SYSTEM_GALILEO, systems); + zassert_equal(GNSS_NAVIGATION_MODE_HIGH_DYNAMICS, mode); + zassert_equal(1500, fix_rate); +} + +ZTEST(gnss_emul, test_callback_behaviour) +{ + const struct device *dev = DEVICE_DT_GET(DT_ALIAS(gnss)); + const struct navigation_data nav = { + .latitude = 150000000000, + .longitude = -15199000000, + .altitude = 123456, + }; + const struct gnss_info info = { + .satellites_cnt = 7, + .hdop = 1999, + .geoid_separation = 1000, + .fix_status = GNSS_FIX_STATUS_GNSS_FIX, + .fix_quality = GNSS_FIX_QUALITY_GNSS_SPS, + }; + const struct gnss_time *utc; + uint32_t timestamp; + + /* Booted into suspend mode */ + expected_pm_state(dev, PM_DEVICE_STATE_SUSPENDED); + + /* No data published while suspended */ + zassert_equal(-EAGAIN, k_sem_take(&gnss_data_published, K_SECONDS(5))); + + /* Power up and configure for 1Hz */ + zassert_equal(0, pm_device_runtime_get(dev)); + zassert_equal(0, gnss_set_fix_rate(dev, 1000)); + timestamp = k_uptime_get_32(); + + /* Monitor data for a while */ + for (int i = 0; i < 10; i++) { + zassert_equal(0, k_sem_take(&gnss_data_published, K_MSEC(1100))); + zassert_equal(0, gnss_published_data.nav_data.latitude); + zassert_equal(0, gnss_published_data.nav_data.longitude); + zassert_equal(0, gnss_published_data.nav_data.altitude); + zassert_equal(0, gnss_published_data.info.satellites_cnt); + print_time(&gnss_published_data.utc); + } + + /* Set a location, approximately 14th July 2017, 02:40:xx am */ + gnss_emul_set_data(dev, &nav, &info, 1500000000000LL); + for (int i = 0; i < 3; i++) { + utc = &gnss_published_data.utc; + /* Published data should match that configured */ + zassert_equal(0, k_sem_take(&gnss_data_published, K_MSEC(1100))); + zassert_mem_equal(&gnss_published_data.nav_data, &nav, sizeof(nav)); + zassert_mem_equal(&gnss_published_data.info, &info, sizeof(info)); + zassert_equal(17, utc->century_year); + zassert_equal(7, utc->month); + zassert_equal(14, utc->month_day); + zassert_equal(2, utc->hour); + zassert_equal(40, utc->minute); + print_time(&gnss_published_data.utc); + } + + /* Reset back to no location */ + gnss_emul_clear_data(dev); + for (int i = 0; i < 5; i++) { + zassert_equal(0, k_sem_take(&gnss_data_published, K_MSEC(1100))); + zassert_equal(0, gnss_published_data.nav_data.latitude); + zassert_equal(0, gnss_published_data.nav_data.longitude); + zassert_equal(0, gnss_published_data.nav_data.altitude); + zassert_equal(0, gnss_published_data.info.satellites_cnt); + print_time(&gnss_published_data.utc); + } + + /* Once again no callbacks once suspended */ + zassert_equal(0, pm_device_runtime_put(dev)); + zassert_equal(-EAGAIN, k_sem_take(&gnss_data_published, K_SECONDS(5))); +} + +ZTEST_SUITE(gnss_emul, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/gnss/gnss_emul/testcase.yaml b/tests/drivers/gnss/gnss_emul/testcase.yaml new file mode 100644 index 0000000000000..f3a5780fd06c3 --- /dev/null +++ b/tests/drivers/gnss/gnss_emul/testcase.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Embeint Pty Ltd +# SPDX-License-Identifier: Apache-2.0 + +tests: + drivers.gnss.gnss_emul: + platform_allow: + - native_sim + integration_platforms: + - native_sim + tags: + - gnss From 2b7b0ba89d14ee99f864a5b58af1b8afbddc2f9f Mon Sep 17 00:00:00 2001 From: Sudan Landge Date: Thu, 16 Oct 2025 12:08:02 +0100 Subject: [PATCH 254/397] tests: fix arch.arm.user.stack test failure Fixes #97473 by: - Marking the test as passed if the hardware executes user threads for a while without triggering a stack corruption, instead of waiting indefinitely. - Adding a timeout to ensure the test exists gracefully if the issue is not reproduced. Also fixes a stack corruption issue on QEMU targets, caused by insufficient stack size and revealed by the timer change. Signed-off-by: Sudan Landge --- boards/arm/mps2/Kconfig.defconfig | 9 ++++++- tests/arch/arm/arm_user_stack_test/src/main.c | 27 +++++++++++++++++++ .../arm/arm_user_stack_test/testcase.yaml | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/boards/arm/mps2/Kconfig.defconfig b/boards/arm/mps2/Kconfig.defconfig index 367e09c2a9a17..b6c51af651c41 100644 --- a/boards/arm/mps2/Kconfig.defconfig +++ b/boards/arm/mps2/Kconfig.defconfig @@ -33,7 +33,7 @@ config TEST_EXTRA_STACK_SIZE endif # COVERAGE_GCOV -endif +endif # BOARD_MPS2_AN383 || BOARD_MPS2_AN385 || BOARD_MPS2_AN386 || BOARD_MPS2_AN500 if BOARD_MPS2_AN521_CPU0 || BOARD_MPS2_AN521_CPU0_NS || BOARD_MPS2_AN521_CPU1 @@ -58,4 +58,11 @@ config UART_INTERRUPT_DRIVEN endif # SERIAL +endif # BOARD_MPS2_AN521_CPU0 || BOARD_MPS2_AN521_CPU0_NS || BOARD_MPS2_AN521_CPU1 + +if QEMU_TARGET + +config ISR_STACK_SIZE + default 4096 + endif diff --git a/tests/arch/arm/arm_user_stack_test/src/main.c b/tests/arch/arm/arm_user_stack_test/src/main.c index ee7e1ed90bbc1..71d9316aec358 100644 --- a/tests/arch/arm/arm_user_stack_test/src/main.c +++ b/tests/arch/arm/arm_user_stack_test/src/main.c @@ -23,8 +23,13 @@ volatile int *const attack_sp = &attack_stack[128]; const int sysno = K_SYSCALL_K_UPTIME_TICKS; k_tid_t low_tid, hi_tid; +struct k_timer timer; +volatile ZTEST_BMEM uint64_t hi_thread_runs, test_completed; + void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf) { + test_completed = 1; + k_timer_stop(&timer); ztest_test_pass(); k_thread_abort(low_tid); @@ -37,6 +42,24 @@ void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf) } } +static void timeout_handler(struct k_timer *timer) +{ + if (!test_completed) { + + printf("hi_thread_runs: %lld\n", hi_thread_runs); + /* the timer times out after 120s, + * by then hi_fn would have ran multiple times so + * compare against a random number like 1000 to make sure that + * hi_fn actually ran for a while + */ + if (hi_thread_runs > 1000) { + ztest_test_pass(); + } else { + ztest_test_fail(); + } + } +} + void attack_entry(void) { printf("Call %s from %s\n", __func__, k_is_user_context() ? "user" : "kernel"); @@ -79,11 +102,15 @@ void hi_fn(void *arg1, void *arg2, void *arg3) while (1) { attack_sp[-2] = (int)attack_entry; k_msleep(1); + hi_thread_runs++; } } ZTEST(arm_user_stack_test, test_arm_user_stack_corruption) { + k_timer_init(&timer, timeout_handler, NULL); + k_timer_start(&timer, K_SECONDS(120), K_NO_WAIT); + low_tid = k_thread_create(&th0, stk0, K_THREAD_STACK_SIZEOF(stk0), low_fn, NULL, NULL, NULL, 2, #ifdef CONFIG_FPU_SHARING diff --git a/tests/arch/arm/arm_user_stack_test/testcase.yaml b/tests/arch/arm/arm_user_stack_test/testcase.yaml index 49cd8fd3a00e8..0d7bafb8fa124 100644 --- a/tests/arch/arm/arm_user_stack_test/testcase.yaml +++ b/tests/arch/arm/arm_user_stack_test/testcase.yaml @@ -1,6 +1,7 @@ common: tags: - arm + timeout: 120 tests: arch.arm.user.stack: filter: CONFIG_CPU_CORTEX_M From ea459889d4696498f5cecf45fe41e0a8f8d1e539 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 16 Oct 2025 12:53:46 +0100 Subject: [PATCH 255/397] dts: vendor: nordic: nrf54lm20a: Fix invalid reg for USB Fixes an invalid reg value which duplicated the parents range property Signed-off-by: Jamie McCrae --- dts/vendor/nordic/nrf54lm20a.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/vendor/nordic/nrf54lm20a.dtsi b/dts/vendor/nordic/nrf54lm20a.dtsi index 2f3e9b9934ded..7e511c8ff6c68 100644 --- a/dts/vendor/nordic/nrf54lm20a.dtsi +++ b/dts/vendor/nordic/nrf54lm20a.dtsi @@ -224,7 +224,7 @@ usbhs: usbhs@5a000 { compatible = "nordic,nrf-usbhs-nrf54l", "snps,dwc2"; - reg = <0x5a000 0x1000>, <0x50020000 0x1a000>; + reg = <0x5a000 0x1000>, <0x20000 0x1a000>; reg-names = "wrapper", "core"; interrupts = <90 NRF_DEFAULT_IRQ_PRIORITY>; num-in-eps = <16>; From 3b3a52a8eedd179c36c087caba3d5d0dad6d916f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 16 Oct 2025 12:35:37 +0100 Subject: [PATCH 256/397] dts: arm: nordic: nrf5340: Add missing ranges property for QSPI This was missing the XIP region Signed-off-by: Jamie McCrae --- dts/arm/nordic/nrf5340_cpuapp.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index b9762248a5dfd..2dca938eaad66 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -60,7 +60,8 @@ reg = <0x50000000 0x10000000>; #address-cells = <1>; #size-cells = <1>; - ranges = <0x0 0x50000000 0x10000000>; + ranges = <0x0 0x50000000 0x10000000>, + <0x10000000 0x10000000 0x10000000>; /* Common nRF5340 Application MCU * peripheral description From cafe8308f2eb7f4298e37bbb1e5f11de89bad4c9 Mon Sep 17 00:00:00 2001 From: Greter Raffael Date: Fri, 29 Aug 2025 12:50:21 +0000 Subject: [PATCH 257/397] sys: util_macro: Support macros as arguments Adjusted GET_ARG_N and GET_ARGS_LESS_N to use UTIL_CAT instead of simple concatenation. This allows to use a macro as the argument N instead of only numbers. Adjusted the unit tests to showcase this. Signed-off-by: Greter Raffael --- include/zephyr/sys/util_macro.h | 4 ++-- tests/unit/util/main.c | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/zephyr/sys/util_macro.h b/include/zephyr/sys/util_macro.h index c8901e21454ae..c8bc264dce0cd 100644 --- a/include/zephyr/sys/util_macro.h +++ b/include/zephyr/sys/util_macro.h @@ -388,7 +388,7 @@ extern "C" { * * @return Nth argument. */ -#define GET_ARG_N(N, ...) Z_GET_ARG_##N(__VA_ARGS__) +#define GET_ARG_N(N, ...) UTIL_CAT(Z_GET_ARG_, N)(__VA_ARGS__) /** * @brief Strips n first arguments from the argument list. @@ -398,7 +398,7 @@ extern "C" { * * @return argument list without N first arguments. */ -#define GET_ARGS_LESS_N(N, ...) Z_GET_ARGS_LESS_##N(__VA_ARGS__) +#define GET_ARGS_LESS_N(N, ...) UTIL_CAT(Z_GET_ARGS_LESS_, N)(__VA_ARGS__) /** * @brief Like a || b, but does evaluation and diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index 358466f8f9f2e..49295c72a56f9 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -534,20 +534,25 @@ ZTEST(util, test_nested_FOR_EACH) { zassert_equal(a2, 2); } +#define TWO 2 /* to showcase that GET_ARG_N and GET_ARGS_LESS_N also work with macros */ + ZTEST(util, test_GET_ARG_N) { int a = GET_ARG_N(1, 10, 100, 1000); int b = GET_ARG_N(2, 10, 100, 1000); int c = GET_ARG_N(3, 10, 100, 1000); + int d = GET_ARG_N(TWO, 10, 100, 1000); zassert_equal(a, 10); zassert_equal(b, 100); zassert_equal(c, 1000); + zassert_equal(d, 100); } ZTEST(util, test_GET_ARGS_LESS_N) { uint8_t a[] = { GET_ARGS_LESS_N(0, 1, 2, 3) }; uint8_t b[] = { GET_ARGS_LESS_N(1, 1, 2, 3) }; uint8_t c[] = { GET_ARGS_LESS_N(2, 1, 2, 3) }; + uint8_t d[] = { GET_ARGS_LESS_N(TWO, 1, 2, 3) }; zassert_equal(sizeof(a), 3); @@ -557,6 +562,9 @@ ZTEST(util, test_GET_ARGS_LESS_N) { zassert_equal(sizeof(c), 1); zassert_equal(c[0], 3); + + zassert_equal(sizeof(d), 1); + zassert_equal(d[0], 3); } ZTEST(util, test_mixing_GET_ARG_and_FOR_EACH) { From 81daaefc5236780322f702aa099dd3326c04d643 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sat, 11 Oct 2025 14:50:58 +0200 Subject: [PATCH 258/397] boards: st: address recent OpenOCD deprecation of HLA interface This change aims to address a compatibility issue with recent OpenOCD pre-release and what is planned in OpenOCD v1.0.0 planned end of 2025. OpenOCD commit 34ec5536c0ba ("stlink: deprecate HLA support") [1] was merged in December 2024 after release tag 0.12.0 and before coming release v1.0.0. It deprecates the legacy HLA driver interface (also called transport) in favor to the generic DAP interface that is supported by ST-Link firmware v2.1 (that is version v2j24) and later. Since the referred commit, OpenOCD config script must source a new config file (interface/stlink-hla.cfg) in order to select hla_swd transport. This change breaks many ST-Link based OpenOCD config files of Zephyr. Alternatively, already existing interface/stlink-dap.cfg can be used together with dapdirect_swd interface to use direct DAP interface. To overcome the issue and support older and newer OpenOCD releases, this change uses OpenOCD native board config script files when available or if none, we select the dapdirect_swd transport ID that is supported since a long time and still maintained thank to OpenOCD native interface/stlink-dap.cfg config script file. One may potentially face connection issues if using both a recent OpenOCD tool and an ST-Link adapter that embeds a old ST-Link firmware v1.x. This ST-Link firmware only supports HLA interface. It is not shipped by ST in ST-Link adapter since 2015. This situation however may happen with old STM32 L0/L1/L4/F4 Nucleo/Discovery boards or with old ST-Link adapter devices. ST-Link firmware v1.0 do not support DAP direct SWD interface. In such a case, either upgrade the ST-Link firmware (see STM32CubeProgrammer guide), or revert the change made here to explicitly use hla_swd transport based on stlink-hla.cfg. Alternatively, use an older OpenOCD release which may not be desired. Link: https://sourceforge.net/p/openocd/code/ci/34ec5536c0ba3315bc5a841244bbf70141ccfbb4/ [1] Signed-off-by: Etienne Carriere --- boards/st/b_l072z_lrwan1/support/openocd.cfg | 12 ++++++++++-- boards/st/nucleo_g070rb/support/openocd.cfg | 8 +------- boards/st/nucleo_g071rb/support/openocd.cfg | 8 +------- boards/st/nucleo_g0b1re/support/openocd.cfg | 8 +------- boards/st/nucleo_g431kb/support/openocd.cfg | 8 +------- boards/st/nucleo_g431rb/support/openocd.cfg | 8 +------- boards/st/nucleo_g474re/support/openocd.cfg | 8 +------- boards/st/nucleo_l011k4/support/openocd.cfg | 13 +++++++++++-- boards/st/nucleo_l031k6/support/openocd.cfg | 13 +++++++++++-- boards/st/nucleo_l053r8/support/openocd.cfg | 13 +++++++++++-- boards/st/nucleo_l073rz/support/openocd.cfg | 15 +-------------- boards/st/nucleo_l152re/support/openocd.cfg | 14 ++------------ boards/st/nucleo_l412rb_p/support/openocd.cfg | 8 +------- boards/st/nucleo_l432kc/support/openocd.cfg | 8 +------- boards/st/nucleo_l433rc_p/support/openocd.cfg | 8 +------- boards/st/nucleo_l452re/support/openocd.cfg | 8 +------- boards/st/nucleo_l552ze_q/support/openocd.cfg | 9 +-------- boards/st/nucleo_wb55rg/support/openocd.cfg | 8 +------- boards/st/nucleo_wl55jc/support/openocd.cfg | 4 ++-- boards/st/st25dv_mb1283_disco/support/openocd.cfg | 12 ++++++++++-- boards/st/steval_fcu001v1/support/openocd.cfg | 12 ++++++++++-- boards/st/stm32g0316_disco/support/openocd.cfg | 4 ++-- .../support/openocd_stm32h747i_disco_m4.cfg | 4 ++-- .../support/openocd_stm32h747i_disco_m7.cfg | 4 ++-- .../support/openocd_stm32h757i_eval_m4.cfg | 4 ++-- .../support/openocd_stm32h757i_eval_m7.cfg | 4 ++-- boards/st/stm32l562e_dk/support/openocd.cfg | 9 +-------- boards/st/stm32wb5mm_dk/support/openocd.cfg | 9 ++------- boards/st/stm32wb5mmg/support/openocd.cfg | 9 ++------- 29 files changed, 95 insertions(+), 157 deletions(-) diff --git a/boards/st/b_l072z_lrwan1/support/openocd.cfg b/boards/st/b_l072z_lrwan1/support/openocd.cfg index 94e533f721010..40b192cc4080c 100644 --- a/boards/st/b_l072z_lrwan1/support/openocd.cfg +++ b/boards/st/b_l072z_lrwan1/support/openocd.cfg @@ -1,6 +1,14 @@ -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd -transport select hla_swd +# If you use an OpenOCD version higher than 0.12.0 and your target embeds +# an ST-Link firmware earlier than v2j24, connection will not work. +# It is recommended to upgrade the ST-Link firmware of the target, +# however, if not possible, the 2 lines above can be replaced with the +# following to connect successfully: +# +# source [find interface/stlink-hla.cfg] +# transport select hla_swd set WORKAREASIZE 0x2000 diff --git a/boards/st/nucleo_g070rb/support/openocd.cfg b/boards/st/nucleo_g070rb/support/openocd.cfg index 0001c39855b0d..589ea907059b9 100644 --- a/boards/st/nucleo_g070rb/support/openocd.cfg +++ b/boards/st/nucleo_g070rb/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32g0x.cfg] - -reset_config srst_only +source [find board/st_nucleo_g0.cfg] diff --git a/boards/st/nucleo_g071rb/support/openocd.cfg b/boards/st/nucleo_g071rb/support/openocd.cfg index 0001c39855b0d..589ea907059b9 100644 --- a/boards/st/nucleo_g071rb/support/openocd.cfg +++ b/boards/st/nucleo_g071rb/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32g0x.cfg] - -reset_config srst_only +source [find board/st_nucleo_g0.cfg] diff --git a/boards/st/nucleo_g0b1re/support/openocd.cfg b/boards/st/nucleo_g0b1re/support/openocd.cfg index 0001c39855b0d..589ea907059b9 100644 --- a/boards/st/nucleo_g0b1re/support/openocd.cfg +++ b/boards/st/nucleo_g0b1re/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32g0x.cfg] - -reset_config srst_only +source [find board/st_nucleo_g0.cfg] diff --git a/boards/st/nucleo_g431kb/support/openocd.cfg b/boards/st/nucleo_g431kb/support/openocd.cfg index d936f7d353423..613455dc81838 100644 --- a/boards/st/nucleo_g431kb/support/openocd.cfg +++ b/boards/st/nucleo_g431kb/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32g4x.cfg] - -reset_config srst_only +source [find board/st_nucleo_g4.cfg] diff --git a/boards/st/nucleo_g431rb/support/openocd.cfg b/boards/st/nucleo_g431rb/support/openocd.cfg index d936f7d353423..613455dc81838 100644 --- a/boards/st/nucleo_g431rb/support/openocd.cfg +++ b/boards/st/nucleo_g431rb/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32g4x.cfg] - -reset_config srst_only +source [find board/st_nucleo_g4.cfg] diff --git a/boards/st/nucleo_g474re/support/openocd.cfg b/boards/st/nucleo_g474re/support/openocd.cfg index d936f7d353423..613455dc81838 100644 --- a/boards/st/nucleo_g474re/support/openocd.cfg +++ b/boards/st/nucleo_g474re/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32g4x.cfg] - -reset_config srst_only +source [find board/st_nucleo_g4.cfg] diff --git a/boards/st/nucleo_l011k4/support/openocd.cfg b/boards/st/nucleo_l011k4/support/openocd.cfg index a6ca36d73b03f..70aa84294c665 100644 --- a/boards/st/nucleo_l011k4/support/openocd.cfg +++ b/boards/st/nucleo_l011k4/support/openocd.cfg @@ -1,8 +1,17 @@ # This is an ST NUCLEO-L011K4 board with single STM32L011K4 chip. # https://www.st.com/en/evaluation-tools/nucleo-l011k4.html -source [find interface/stlink.cfg] -transport select hla_swd +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd + +# If you use an OpenOCD version higher than 0.12.0 and your target embeds +# an ST-Link firmware earlier than v2j24, connection will not work. +# It is recommended to upgrade the ST-Link firmware of the target, +# however, if not possible, the 2 lines above can be replaced with the +# following to connect successfully: +# +# source [find interface/stlink-hla.cfg] +# transport select hla_swd #set WORKAREASIZE 0x2000 diff --git a/boards/st/nucleo_l031k6/support/openocd.cfg b/boards/st/nucleo_l031k6/support/openocd.cfg index be154d927e4db..e303b7399cecf 100644 --- a/boards/st/nucleo_l031k6/support/openocd.cfg +++ b/boards/st/nucleo_l031k6/support/openocd.cfg @@ -1,8 +1,17 @@ # This is an ST NUCLEO-L031K6 board with single STM32L031K6 chip. # https://www.st.com/en/evaluation-tools/nucleo-l031k6.html -source [find interface/stlink.cfg] -transport select hla_swd +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd + +# If you use an OpenOCD version higher than 0.12.0 and your target embeds +# an ST-Link firmware earlier than v2j24, connection will not work. +# It is recommended to upgrade the ST-Link firmware of the target, +# however, if not possible, the 2 lines above can be replaced with the +# following to connect successfully: +# +# source [find interface/stlink-hla.cfg] +# transport select hla_swd source [find target/stm32l0.cfg] diff --git a/boards/st/nucleo_l053r8/support/openocd.cfg b/boards/st/nucleo_l053r8/support/openocd.cfg index fec9da07d5570..09161f939a4a3 100644 --- a/boards/st/nucleo_l053r8/support/openocd.cfg +++ b/boards/st/nucleo_l053r8/support/openocd.cfg @@ -1,8 +1,17 @@ # This is an ST NUCLEO-L053R8 board with single STM32L053R8 chip. # https://www.st.com/en/evaluation-tools/nucleo-l053r8.html -source [find interface/stlink.cfg] -transport select hla_swd +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd + +# If you use an OpenOCD version higher than 0.12.0 and your target embeds +# an ST-Link firmware earlier than v2j24, connection will not work. +# It is recommended to upgrade the ST-Link firmware of the target, +# however, if not possible, the 2 lines above can be replaced with the +# following to connect successfully: +# +# source [find interface/stlink-hla.cfg] +# transport select hla_swd set WORKAREASIZE 0x2000 diff --git a/boards/st/nucleo_l073rz/support/openocd.cfg b/boards/st/nucleo_l073rz/support/openocd.cfg index b28dd29e5c110..718e20e15e086 100644 --- a/boards/st/nucleo_l073rz/support/openocd.cfg +++ b/boards/st/nucleo_l073rz/support/openocd.cfg @@ -1,19 +1,6 @@ # This is an ST NUCLEO-L073RZ board with single STM32L073RZ chip. # https://www.st.com/en/evaluation-tools/nucleo-l073rz.html -source [find interface/stlink.cfg] - -transport select hla_swd - -set WORKAREASIZE 0x2000 - -source [find target/stm32l0.cfg] - -# Add the second flash bank. -set _FLASHNAME $_CHIPNAME.flash1 -flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME - -# There is only system reset line and JTAG/SWD command can be issued when SRST -reset_config srst_only +source [find board/st_nucleo_l073rz.cfg] $_TARGETNAME configure -event gdb-attach { echo "Debugger attaching: halting execution" diff --git a/boards/st/nucleo_l152re/support/openocd.cfg b/boards/st/nucleo_l152re/support/openocd.cfg index 7e76ff5be9cda..214286330e09a 100644 --- a/boards/st/nucleo_l152re/support/openocd.cfg +++ b/boards/st/nucleo_l152re/support/openocd.cfg @@ -1,15 +1,5 @@ -# TODO: Once official openOCD fix merged and available in zephyr: -# http://openocd.zylin.com/#/c/5829/ -# revert to board/st_nucleo_l1.cfg -# source [find board/st_nucleo_l1.cfg] - -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32l1x_dual_bank.cfg] - -reset_config srst_only +# http://openocd.zylin.com/#/c/5829/ was merged in 2020 +source [find board/st_nucleo_l1.cfg] $_TARGETNAME configure -event gdb-attach { echo "Debugger attaching: halting execution" diff --git a/boards/st/nucleo_l412rb_p/support/openocd.cfg b/boards/st/nucleo_l412rb_p/support/openocd.cfg index cd566c1fa1c97..c4850019587db 100644 --- a/boards/st/nucleo_l412rb_p/support/openocd.cfg +++ b/boards/st/nucleo_l412rb_p/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32l4x.cfg] - -reset_config srst_only +source [find board/st_nucleo_l4.cfg] diff --git a/boards/st/nucleo_l432kc/support/openocd.cfg b/boards/st/nucleo_l432kc/support/openocd.cfg index cd566c1fa1c97..c4850019587db 100644 --- a/boards/st/nucleo_l432kc/support/openocd.cfg +++ b/boards/st/nucleo_l432kc/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32l4x.cfg] - -reset_config srst_only +source [find board/st_nucleo_l4.cfg] diff --git a/boards/st/nucleo_l433rc_p/support/openocd.cfg b/boards/st/nucleo_l433rc_p/support/openocd.cfg index cd566c1fa1c97..c4850019587db 100644 --- a/boards/st/nucleo_l433rc_p/support/openocd.cfg +++ b/boards/st/nucleo_l433rc_p/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32l4x.cfg] - -reset_config srst_only +source [find board/st_nucleo_l4.cfg] diff --git a/boards/st/nucleo_l452re/support/openocd.cfg b/boards/st/nucleo_l452re/support/openocd.cfg index cd566c1fa1c97..c4850019587db 100644 --- a/boards/st/nucleo_l452re/support/openocd.cfg +++ b/boards/st/nucleo_l452re/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32l4x.cfg] - -reset_config srst_only +source [find board/st_nucleo_l4.cfg] diff --git a/boards/st/nucleo_l552ze_q/support/openocd.cfg b/boards/st/nucleo_l552ze_q/support/openocd.cfg index f4ccc5641251a..c7ff4b06e1419 100644 --- a/boards/st/nucleo_l552ze_q/support/openocd.cfg +++ b/boards/st/nucleo_l552ze_q/support/openocd.cfg @@ -1,11 +1,4 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32l5x.cfg] - -# use hardware reset -reset_config srst_only srst_nogate +source [find board/st_nucleo_l5.cfg] $_TARGETNAME configure -event gdb-attach { echo "Debugger attaching: halting execution" diff --git a/boards/st/nucleo_wb55rg/support/openocd.cfg b/boards/st/nucleo_wb55rg/support/openocd.cfg index 2ad582703684c..a324300d395fa 100644 --- a/boards/st/nucleo_wb55rg/support/openocd.cfg +++ b/boards/st/nucleo_wb55rg/support/openocd.cfg @@ -1,7 +1 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32wbx.cfg] - -reset_config srst_only +source [find board/st_nucleo_wb55rg] diff --git a/boards/st/nucleo_wl55jc/support/openocd.cfg b/boards/st/nucleo_wl55jc/support/openocd.cfg index 9d7fe815eba4e..78eadd8d601ad 100644 --- a/boards/st/nucleo_wl55jc/support/openocd.cfg +++ b/boards/st/nucleo_wl55jc/support/openocd.cfg @@ -1,6 +1,6 @@ -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] -transport select hla_swd +transport select dapdirect_swd source [find target/stm32wlx.cfg] diff --git a/boards/st/st25dv_mb1283_disco/support/openocd.cfg b/boards/st/st25dv_mb1283_disco/support/openocd.cfg index 5d6a3772c5cf6..6f67ad513a3d8 100644 --- a/boards/st/st25dv_mb1283_disco/support/openocd.cfg +++ b/boards/st/st25dv_mb1283_disco/support/openocd.cfg @@ -1,6 +1,14 @@ -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd -transport select hla_swd +# If you use an OpenOCD version higher than 0.12.0 and your target embeds +# an ST-Link firmware earlier than v2j24, connection will not work. +# It is recommended to upgrade the ST-Link firmware of the target, +# however, if not possible, the 2 lines above can be replaced with the +# following to connect successfully: +# +# source [find interface/stlink-hla.cfg] +# transport select hla_swd source [find target/stm32f4x.cfg] diff --git a/boards/st/steval_fcu001v1/support/openocd.cfg b/boards/st/steval_fcu001v1/support/openocd.cfg index 8412eea50e738..7dc7362df5457 100644 --- a/boards/st/steval_fcu001v1/support/openocd.cfg +++ b/boards/st/steval_fcu001v1/support/openocd.cfg @@ -1,6 +1,14 @@ -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd -transport select hla_swd +# If you use an OpenOCD version higher than 0.12.0 and your target embeds +# an ST-Link firmware earlier than v2j24, connection will not work. +# It is recommended to upgrade the ST-Link firmware of the target, +# however, if not possible, the 2 lines above can be replaced with the +# following to connect successfully: +# +# source [find interface/stlink-hla.cfg] +# transport select hla_swd set WORKAREASIZE 0x10000 diff --git a/boards/st/stm32g0316_disco/support/openocd.cfg b/boards/st/stm32g0316_disco/support/openocd.cfg index 2d736e0a4089e..101d48c2e0a47 100644 --- a/boards/st/stm32g0316_disco/support/openocd.cfg +++ b/boards/st/stm32g0316_disco/support/openocd.cfg @@ -1,5 +1,5 @@ -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] -transport select hla_swd +transport select dapdirect_swd source [find target/stm32g0x.cfg] diff --git a/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m4.cfg b/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m4.cfg index ddceef92cb191..e090c2462d245 100644 --- a/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m4.cfg +++ b/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m4.cfg @@ -1,7 +1,7 @@ -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] -transport select hla_swd +transport select dapdirect_swd set DUAL_BANK 1 diff --git a/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m7.cfg b/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m7.cfg index 75d441d180926..3ec0a46f323b9 100644 --- a/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m7.cfg +++ b/boards/st/stm32h747i_disco/support/openocd_stm32h747i_disco_m7.cfg @@ -1,7 +1,7 @@ -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] -transport select hla_swd +transport select dapdirect_swd source [find target/stm32h7x.cfg] diff --git a/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m4.cfg b/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m4.cfg index 9958067dfb389..4acfabf2e4175 100644 --- a/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m4.cfg +++ b/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m4.cfg @@ -1,9 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2025 Foss Analytical A/S -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] -transport select hla_swd +transport select dapdirect_swd set DUAL_BANK 1 diff --git a/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m7.cfg b/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m7.cfg index 172b4eb785142..543c160819261 100644 --- a/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m7.cfg +++ b/boards/st/stm32h757i_eval/support/openocd_stm32h757i_eval_m7.cfg @@ -1,9 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2025 Foss Analytical A/S -source [find interface/stlink.cfg] +source [find interface/stlink-dap.cfg] -transport select hla_swd +transport select dapdirect_swd source [find target/stm32h7x.cfg] diff --git a/boards/st/stm32l562e_dk/support/openocd.cfg b/boards/st/stm32l562e_dk/support/openocd.cfg index f4ccc5641251a..c7ff4b06e1419 100644 --- a/boards/st/stm32l562e_dk/support/openocd.cfg +++ b/boards/st/stm32l562e_dk/support/openocd.cfg @@ -1,11 +1,4 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32l5x.cfg] - -# use hardware reset -reset_config srst_only srst_nogate +source [find board/st_nucleo_l5.cfg] $_TARGETNAME configure -event gdb-attach { echo "Debugger attaching: halting execution" diff --git a/boards/st/stm32wb5mm_dk/support/openocd.cfg b/boards/st/stm32wb5mm_dk/support/openocd.cfg index 2ad582703684c..7e5a53e660568 100644 --- a/boards/st/stm32wb5mm_dk/support/openocd.cfg +++ b/boards/st/stm32wb5mm_dk/support/openocd.cfg @@ -1,7 +1,2 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32wbx.cfg] - -reset_config srst_only +# OpenOCD st_nucleo_wb55rg.cfg matches stm32wb55mm_dk support +source [find board/st_nucleo_wb55rg.cfg] diff --git a/boards/st/stm32wb5mmg/support/openocd.cfg b/boards/st/stm32wb5mmg/support/openocd.cfg index 2ad582703684c..7e346846af125 100644 --- a/boards/st/stm32wb5mmg/support/openocd.cfg +++ b/boards/st/stm32wb5mmg/support/openocd.cfg @@ -1,7 +1,2 @@ -source [find interface/stlink.cfg] - -transport select hla_swd - -source [find target/stm32wbx.cfg] - -reset_config srst_only +# OpenOCD st_nucleo_wb55rg.cfg matches stm32wb55mmg support +source [find board/st_nucleo_wb55k.cfg] From 8b8fabbeabf05f038421d123a16ee54cd2c813f9 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Oct 2025 15:32:54 +0200 Subject: [PATCH 259/397] doc: migration guide: OpenOCD deprecation of ST-Link HLA interface A recent change in OpenOCD deprecates ST-Link HLA interface requiring changes in some board OpenOCD configuration files in the Zephyr tree. Since this deprecation, in order to support old and recent OpenOCD tool we needed to change of debug driver interface for these boards, potentially causing trouble to user to have a recent OpenOCD and an old ST-Link adapter firmware. Therefore add an entry in the migration guide to give some hints on the potential issue and how to address it. Signed-off-by: Etienne Carriere --- doc/releases/migration-guide-4.3.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/releases/migration-guide-4.3.rst b/doc/releases/migration-guide-4.3.rst index 930bcf3d60d2b..c9c93b636cc10 100644 --- a/doc/releases/migration-guide-4.3.rst +++ b/doc/releases/migration-guide-4.3.rst @@ -75,6 +75,16 @@ Boards * Panasonic ``panb511evb`` is renamed to ``panb611evb``. +* STM32 boards OpenOCD configuration files have been changed to support latest OpenOCD versions + (> v0.12.0) in which the HLA/SWD transport has been deprecated (see + https://review.openocd.org/c/openocd/+/8523 and commit + https://sourceforge.net/p/openocd/code/ci/34ec5536c0ba3315bc5a841244bbf70141ccfbb4/). + Issues may be encountered when connecting to an ST-Link adapter running firmware prior + v2j24 which do not support the new transport. In this case, the ST-Link firmware should + be upgraded or, if not possible, the OpenOCD configuration script should be changed to + source "interface/stlink-hla.cfg" and select the "hla_swd" interface explicitly. + Backward compatibility with OpenOCD v0.12.0 or older is maintained. + Device Drivers and Devicetree ***************************** From 7436deab8753c95a7ae7c98f96aa54b734484bf9 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 15 Oct 2025 14:36:15 +0200 Subject: [PATCH 260/397] mgmt: mcumgr: remove usage of legacy Mbed TLS crypto for hash The long-term goal of Zephyr is to rely exclusively on PSA Crypto API for crypto support. At the same time Mbed TLS is going to remove legacy crypto support starting from the next relase (v4.0). Therefore this commit removes usage of legacy Mbed TLS crypto in favor of PSA Crypto API. Mbed TLS will still be used in case of a build where TF-M is not enabled. Signed-off-by: Valerio Setti --- subsys/mgmt/mcumgr/grp/fs_mgmt/CMakeLists.txt | 2 +- subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig | 4 +- .../src/fs_mgmt_hash_checksum_sha256.c | 52 ++++--------------- 3 files changed, 12 insertions(+), 46 deletions(-) diff --git a/subsys/mgmt/mcumgr/grp/fs_mgmt/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/fs_mgmt/CMakeLists.txt index 234d6693972f7..a8d819652f51b 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/CMakeLists.txt +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/CMakeLists.txt @@ -15,7 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32 src/fs_mgm zephyr_library_sources_ifdef(CONFIG_MCUMGR_GRP_FS_HASH_SHA256 src/fs_mgmt_hash_checksum_sha256.c) if(CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH AND CONFIG_MCUMGR_GRP_FS_HASH_SHA256) - if(CONFIG_MBEDTLS_SHA256) + if(CONFIG_MBEDTLS) zephyr_library_link_libraries(mbedTLS) endif() endif() diff --git a/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig index 5be0ab44efd38..edac04c4f6c62 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/Kconfig @@ -125,8 +125,8 @@ config MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32 config MCUMGR_GRP_FS_HASH_SHA256 bool "SHA256 hash support" - depends on BUILD_WITH_TFM || MBEDTLS_SHA256 - select PSA_WANT_ALG_SHA_256 if BUILD_WITH_TFM + select PSA_CRYPTO + select PSA_WANT_ALG_SHA_256 help Enable SHA256 hash support for MCUmgr. diff --git a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c index 5005067f38c16..373e17e9ed5a0 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt_hash_checksum_sha256.c @@ -13,25 +13,15 @@ #include #include -#ifdef CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT #include -typedef psa_hash_operation_t hash_ctx_t; -#define SUCCESS_VALUE PSA_SUCCESS -#else -#include -typedef mbedtls_sha256_context hash_ctx_t; -#define SUCCESS_VALUE 0 - -#endif /* CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT */ - -#define SHA256_DIGEST_SIZE 32 +#define SHA256_DIGEST_SIZE PSA_HASH_LENGTH(PSA_ALG_SHA_256) /* The API that the different hash implementations provide further down. */ -static int hash_setup(hash_ctx_t *); -static int hash_update(hash_ctx_t *, const uint8_t *input, size_t ilen); -static int hash_finish(hash_ctx_t *, uint8_t *output); -static void hash_teardown(hash_ctx_t *); +static int hash_setup(psa_hash_operation_t *); +static int hash_update(psa_hash_operation_t *, const uint8_t *input, size_t ilen); +static int hash_finish(psa_hash_operation_t *, uint8_t *output); +static void hash_teardown(psa_hash_operation_t *); static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, size_t *out_len, size_t len) @@ -40,13 +30,13 @@ static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, ssize_t bytes_read = 0; size_t read_size = CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_CHUNK_SIZE; uint8_t buffer[CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_CHUNK_SIZE]; - hash_ctx_t hash_ctx; + psa_hash_operation_t hash_ctx; /* Clear variables prior to calculation */ *out_len = 0; memset(output, 0, SHA256_DIGEST_SIZE); - if (hash_setup(&hash_ctx) != SUCCESS_VALUE) { + if (hash_setup(&hash_ctx) != PSA_SUCCESS) { goto teardown; } @@ -63,7 +53,7 @@ static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, /* Failed to read file data */ goto teardown; } else if (bytes_read > 0) { - if (hash_update(&hash_ctx, buffer, bytes_read) != SUCCESS_VALUE) { + if (hash_update(&hash_ctx, buffer, bytes_read) != PSA_SUCCESS) { goto teardown; } @@ -72,7 +62,7 @@ static int fs_mgmt_hash_checksum_sha256(struct fs_file_t *file, uint8_t *output, } while (bytes_read > 0 && *out_len < len); /* Finalise SHA256 hash calculation and store output in provided output buffer */ - if (hash_finish(&hash_ctx, output) == SUCCESS_VALUE) { + if (hash_finish(&hash_ctx, output) == PSA_SUCCESS) { rc = 0; } @@ -99,8 +89,6 @@ void fs_mgmt_hash_checksum_unregister_sha256(void) fs_mgmt_hash_checksum_unregister_group(&sha256); } -#ifdef CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT - static int hash_setup(psa_hash_operation_t *ctx) { *ctx = psa_hash_operation_init(); @@ -120,25 +108,3 @@ static void hash_teardown(psa_hash_operation_t *ctx) { psa_hash_abort(ctx); } - -#else - -static int hash_setup(mbedtls_sha256_context *ctx) -{ - mbedtls_sha256_init(ctx); - return mbedtls_sha256_starts(ctx, false); -} -static int hash_update(mbedtls_sha256_context *ctx, const uint8_t *input, size_t ilen) -{ - return mbedtls_sha256_update(ctx, input, ilen); -} -static int hash_finish(mbedtls_sha256_context *ctx, uint8_t *output) -{ - return mbedtls_sha256_finish(ctx, output); -} -static void hash_teardown(mbedtls_sha256_context *ctx) -{ - mbedtls_sha256_free(ctx); -} - -#endif /* CONFIG_MBEDTLS_PSA_CRYPTO_CLIENT */ From 58173e05f53fe1353a0d6ac2c76d200046313855 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 15 Oct 2025 15:00:57 +0200 Subject: [PATCH 261/397] tests: subsys: mgmt: mcumgr: remove selection of Mbed TLS in tests MCUMGR_GRP_FS_HASH_SHA256 now already selects Mbed TLS and its PSA Crypto support if TF-M is not enabled in the build, so there is no need to do that in test configuration files. Signed-off-by: Valerio Setti --- tests/subsys/mgmt/mcumgr/all_options/prj.conf | 2 -- .../mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf | 2 -- .../mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf | 2 -- tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/prj.conf | 1 + 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/subsys/mgmt/mcumgr/all_options/prj.conf b/tests/subsys/mgmt/mcumgr/all_options/prj.conf index 3087ce16c3932..695cb6eb5cb43 100644 --- a/tests/subsys/mgmt/mcumgr/all_options/prj.conf +++ b/tests/subsys/mgmt/mcumgr/all_options/prj.conf @@ -4,8 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # CONFIG_ZTEST=y -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_SHA256=y CONFIG_FILE_SYSTEM=y CONFIG_BASE64=y CONFIG_NET_BUF=y diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf index eff5b71007f86..30b59e6f89b03 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/all.conf @@ -5,5 +5,3 @@ # CONFIG_MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32=y CONFIG_MCUMGR_GRP_FS_HASH_SHA256=y -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_SHA256=y diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf index 5f85dda370851..31cb2aaeddd24 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/configuration/sha256.conf @@ -5,5 +5,3 @@ # CONFIG_MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32=n CONFIG_MCUMGR_GRP_FS_HASH_SHA256=y -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_SHA256=y diff --git a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/prj.conf b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/prj.conf index ef6c180ce9fa9..79878cf464bb2 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/prj.conf +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/prj.conf @@ -17,3 +17,4 @@ CONFIG_MCUMGR_GRP_FS=y CONFIG_MCUMGR_GRP_FS_FILE_STATUS=n CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH=y CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_SUPPORTED_CMD=y +CONFIG_MAIN_STACK_SIZE=2048 From a33b9a5726949876c3415babde3abd1e98d94a67 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 15 Oct 2025 15:07:01 +0200 Subject: [PATCH 262/397] doc: migration-guide: add note for crypto updates in McuMGR Add note for the removal of Mbed TLS' legacy crypto support in favor of PSA API. Signed-off-by: Valerio Setti --- doc/releases/migration-guide-4.3.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/migration-guide-4.3.rst b/doc/releases/migration-guide-4.3.rst index c9c93b636cc10..b913c41e34757 100644 --- a/doc/releases/migration-guide-4.3.rst +++ b/doc/releases/migration-guide-4.3.rst @@ -377,6 +377,10 @@ MCUmgr but can still be used by enabling :kconfig:option:`CONFIG_MCUMGR_GRP_OS_INFO_HARDWARE_INFO_SHORT_HARDWARE_PLATFORM`. +* Support for legacy Mbed TLS hash crypto is removed and only PSA Crypto API is used. + :kconfig:option:`CONFIG_MCUMGR_GRP_FS_HASH_SHA256` automatically enables Mbed TLS and its + PSA Crypto implementation if TF-M is not enabled in the build. + RTIO ==== From 9a7227e6a7d20d62f8303a0f04e14e1fb68cef2e Mon Sep 17 00:00:00 2001 From: Quy Tran Date: Wed, 15 Oct 2025 09:59:43 +0000 Subject: [PATCH 263/397] manifest: hal_renesas: Update revision for hal_renesas Update revision for hal_renesas for lpc support Signed-off-by: Quy Tran --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 4ca483350b2ff..744a097602ba8 100644 --- a/west.yml +++ b/west.yml @@ -226,7 +226,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: 3ce2bdc7f5cb19b961c015ba561b0cf15f7df3b4 + revision: 8c5505d957db35816f3f2ddc93f6805fd648a90c groups: - hal - name: hal_rpi_pico From a83c0e161a21a6c40fe473a1b9d45231d0fa0d82 Mon Sep 17 00:00:00 2001 From: Phi Tran Date: Mon, 31 Mar 2025 12:09:29 +0700 Subject: [PATCH 264/397] soc: renesas: rx: initial support pm for RX130 Add initial support power management for Renesas RX130 Signed-off-by: Phi Tran --- dts/rx/renesas/rx130-common.dtsi | 16 ++++++ modules/Kconfig.renesas | 7 +++ soc/renesas/rx/rx130/CMakeLists.txt | 4 ++ soc/renesas/rx/rx130/Kconfig | 1 + soc/renesas/rx/rx130/power.c | 75 +++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 soc/renesas/rx/rx130/power.c diff --git a/dts/rx/renesas/rx130-common.dtsi b/dts/rx/renesas/rx130-common.dtsi index d2a0db56c5f18..58463ba4e165f 100644 --- a/dts/rx/renesas/rx130-common.dtsi +++ b/dts/rx/renesas/rx130-common.dtsi @@ -25,8 +25,24 @@ compatible = "renesas,rxv1"; device_type = "cpu"; reg = <0>; + cpu-power-states = <&idle &standby>; status = "okay"; }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <300>; + }; + + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <3000>; + exit-latency-us = <500>; + }; + }; }; icu: interrupt-controller@87000 { diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index cfca82cb3e1f6..63844e8136d9f 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -421,4 +421,11 @@ config USE_RX_RDP_LVD help Enable RX RDP LVD driver +config USE_RX_RDP_LPC + bool + default y + depends on PM + help + Enable RX RDP LPC driver + endif # HAS_RENESAS_RX_RDP diff --git a/soc/renesas/rx/rx130/CMakeLists.txt b/soc/renesas/rx/rx130/CMakeLists.txt index 44936565508f6..1a707b29571fc 100644 --- a/soc/renesas/rx/rx130/CMakeLists.txt +++ b/soc/renesas/rx/rx130/CMakeLists.txt @@ -11,3 +11,7 @@ zephyr_linker_sources(SECTIONS ofsm.ld) zephyr_linker_sources(RAM_SECTIONS ram_sections.ld) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/rx/linker.ld CACHE INTERNAL "") + +zephyr_sources_ifdef(CONFIG_PM + power.c +) diff --git a/soc/renesas/rx/rx130/Kconfig b/soc/renesas/rx/rx130/Kconfig index 66f481b78cf8a..161a2071447ea 100644 --- a/soc/renesas/rx/rx130/Kconfig +++ b/soc/renesas/rx/rx130/Kconfig @@ -9,6 +9,7 @@ config SOC_SERIES_RX130 select HAS_RENESAS_RX_RDP select CLOCK_CONTROL select SOC_EARLY_INIT_HOOK + select HAS_PM if SOC_SERIES_RX130 if WDT_RENESAS_RX_IWDT_AUTO_START_MODE diff --git a/soc/renesas/rx/rx130/power.c b/soc/renesas/rx/rx130/power.c new file mode 100644 index 0000000000000..56fb9f76560b2 --- /dev/null +++ b/soc/renesas/rx/rx130/power.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +#ifdef CONFIG_RENESAS_RX_DTC +#include +#endif + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +#ifdef CONFIG_RENESAS_RX_DTC +static const struct device *const dtc = DEVICE_DT_GET(DT_NODELABEL(dtc)); +#endif + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + int err = 0; + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + err = R_LPC_LowPowerModeConfigure(LPC_LP_SLEEP); + if (err) { + LOG_DBG("LPC config failed %d", err); + } + err = R_LPC_LowPowerModeActivate(FIT_NO_FUNC); + if (err) { + LOG_DBG("LPC active failed %d", err); + } + break; + case PM_STATE_STANDBY: +#ifdef CONFIG_RENESAS_RX_DTC + err = dtc_renesas_rx_off(dtc); + if (err) { + LOG_DBG("turn off module DTC failed %d", err); + } +#endif + err = R_LPC_LowPowerModeConfigure(LPC_LP_DEEP_SLEEP); + if (err) { + LOG_DBG("LPC config failed %d", err); + } + err = R_LPC_LowPowerModeActivate(FIT_NO_FUNC); + if (err) { + LOG_DBG("LPC active failed %d", err); + } + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + if (state == PM_STATE_STANDBY) { +#ifdef CONFIG_RENESAS_RX_DTC + int err = dtc_renesas_rx_on(dtc); + + if (err) { + LOG_DBG("turn off module DTC failed %d", err); + } +#endif + } +} From d0b262509050b13668b6921911d1ebbc8c0002e4 Mon Sep 17 00:00:00 2001 From: Quy Tran Date: Mon, 20 Oct 2025 04:45:32 +0000 Subject: [PATCH 265/397] drivers: serial: Support PM device for serial driver Support PM for serial driver of Renesas RX Signed-off-by: Quy Tran --- drivers/serial/uart_renesas_rx_sci.c | 72 +++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/drivers/serial/uart_renesas_rx_sci.c b/drivers/serial/uart_renesas_rx_sci.c index aa9de7963c59b..afbc0d003c447 100644 --- a/drivers/serial/uart_renesas_rx_sci.c +++ b/drivers/serial/uart_renesas_rx_sci.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "r_sci_rx_if.h" #include "iodefine_sci.h" @@ -60,6 +62,8 @@ static void uart_rx_sci_txi_isr(const struct device *dev); struct uart_rx_sci_config { uint32_t regs; const struct pinctrl_dev_config *pcfg; + const struct device *clock; + struct clock_control_rx_subsys_cfg clock_subsys; }; struct uart_rx_sci_data { @@ -293,6 +297,9 @@ static void uart_rx_irq_tx_enable(const struct device *dev) sci->SCR.BYTE |= (BIT(R_SCI_SCR_TIE_Pos) | BIT(R_SCI_SCR_TEIE_Pos)); irq_enable(data->tei_irq); +#ifdef CONFIG_PM_DEVICE + pm_device_busy_set(dev); +#endif } static void uart_rx_irq_tx_disable(const struct device *dev) @@ -302,6 +309,9 @@ static void uart_rx_irq_tx_disable(const struct device *dev) sci->SCR.BYTE &= ~(BIT(R_SCI_SCR_TIE_Pos) | BIT(R_SCI_SCR_TEIE_Pos)); irq_disable(data->tei_irq); +#ifdef CONFIG_PM_DEVICE + pm_device_busy_clear(dev); +#endif } static int uart_rx_irq_tx_ready(const struct device *dev) @@ -324,6 +334,9 @@ static void uart_rx_irq_rx_enable(const struct device *dev) volatile struct st_sci *sci = (struct st_sci *)DEV_BASE(dev); sci->SCR.BIT.RIE = 1U; +#ifdef CONFIG_PM_DEVICE + pm_device_busy_set(dev); +#endif } static void uart_rx_irq_rx_disable(const struct device *dev) @@ -331,6 +344,9 @@ static void uart_rx_irq_rx_disable(const struct device *dev) volatile struct st_sci *sci = (struct st_sci *)DEV_BASE(dev); sci->SCR.BIT.RIE = 0U; +#ifdef CONFIG_PM_DEVICE + pm_device_busy_clear(dev); +#endif } static int uart_rx_irq_rx_ready(const struct device *dev) @@ -532,6 +548,11 @@ static int uart_rx_sci_async_tx(const struct device *dev, const uint8_t *buf, si goto end; } +#ifdef CONFIG_PM + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +#endif + enable_tx(dev); data->tx_buffer = (uint8_t *)buf; data->tx_buf_cap = len; @@ -804,14 +825,12 @@ static int uart_rx_init(const struct device *dev) #endif sci_err = R_SCI_Open(data->channel, SCI_MODE_ASYNC, &data->sci_config, NULL, &data->hdl); - if (sci_err) { return -EIO; } /* Set the Asynchronous Start Bit Edge Detection Select to falling edge on the RXDn pin */ sci_err = R_SCI_Control(data->hdl, SCI_CMD_START_BIT_EDGE, FIT_NO_PTR); - if (sci_err) { return -EIO; } @@ -819,6 +838,37 @@ static int uart_rx_init(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE +static int uart_rx_sci_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct uart_rx_sci_config *config = dev->config; + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = clock_control_on(config->clock, + (clock_control_subsys_t)&config->clock_subsys); + if (ret < 0) { + return ret; + } + break; + + case PM_DEVICE_ACTION_SUSPEND: + ret = clock_control_off(config->clock, + (clock_control_subsys_t)&config->clock_subsys); + if (ret < 0) { + return ret; + } + break; + default: + ret = -ENOTSUP; + break; + } + + return ret; +} +#endif + static DEVICE_API(uart, uart_rx_driver_api) = { .poll_in = uart_rx_sci_poll_in, .poll_out = uart_rx_sci_poll_out, @@ -924,6 +974,10 @@ static void uart_rx_sci_tei_isr(const struct device *dev) .data.tx.len = data->tx_buf_cap, }; async_user_callback(dev, &event); +#ifdef CONFIG_PM + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +#endif #endif } @@ -1043,6 +1097,12 @@ static void uart_rx_sci_eri_isr(const struct device *dev) static const struct uart_rx_sci_config uart_rx_sci_config_##index = { \ .regs = DT_REG_ADDR(DT_INST_PARENT(index)), \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(index)), \ + .clock = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(index))), \ + .clock_subsys = \ + { \ + .mstp = DT_CLOCKS_CELL(DT_INST_PARENT(index), mstp), \ + .stop_bit = DT_CLOCKS_CELL(DT_INST_PARENT(index), stop_bit), \ + }, \ }; \ \ static struct uart_rx_sci_data uart_rx_sci_data_##index = { \ @@ -1068,9 +1128,9 @@ static void uart_rx_sci_eri_isr(const struct device *dev) } \ return 0; \ }; \ - \ - DEVICE_DT_INST_DEFINE(index, uart_rx_init_##index, NULL, &uart_rx_sci_data_##index, \ - &uart_rx_sci_config_##index, PRE_KERNEL_1, \ - CONFIG_SERIAL_INIT_PRIORITY, &uart_rx_driver_api); + PM_DEVICE_DT_INST_DEFINE(index, uart_rx_sci_pm_action); \ + DEVICE_DT_INST_DEFINE(index, uart_rx_init_##index, PM_DEVICE_DT_INST_GET(index), \ + &uart_rx_sci_data_##index, &uart_rx_sci_config_##index, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_rx_driver_api); DT_INST_FOREACH_STATUS_OKAY(UART_RX_INIT) From b9fbc29b679c2fd4b26e91ebc28ebe8b453fd5da Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 14 Oct 2025 13:33:50 +0200 Subject: [PATCH 266/397] include: bindings: stm32wba: add OTGHS mux selector Add missing OTGHS_SEL macro to STM32WBA clock header. This macro applies only to certain SoCs of STM32WBA6x series. Signed-off-by: Mathieu Choplain --- include/zephyr/dt-bindings/clock/stm32wba_clock.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h index f1ae4be8fcc15..82deec11ee256 100644 --- a/include/zephyr/dt-bindings/clock/stm32wba_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -70,6 +70,7 @@ #define TIMIC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 31, CCIPR1_REG) /** CCIPR2 devices */ #define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR2_REG) +#define OTGHS_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, CCIPR2_REG) /** CCIPR3 devices */ #define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR3_REG) #define SPI3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 3, CCIPR3_REG) From 44fd2b651f56ab12546babbb7506394f4105308f Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 14 Oct 2025 13:35:10 +0200 Subject: [PATCH 267/397] dts: arm: st: wba: add USB to STM32WBA6x DTSI Add missing nodes for USB feature to STM32WBA6x DTSI. (Note: only WBA65 DTSI exists today, but USB is available in other SoCs of the series - this should be reworked later) Signed-off-by: Mathieu Choplain --- dts/arm/st/wba/stm32wba65.dtsi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dts/arm/st/wba/stm32wba65.dtsi b/dts/arm/st/wba/stm32wba65.dtsi index cd9be8afae588..177d572c8b8bd 100644 --- a/dts/arm/st/wba/stm32wba65.dtsi +++ b/dts/arm/st/wba/stm32wba65.dtsi @@ -77,6 +77,25 @@ #pwm-cells = <3>; }; }; + + usbotg_hs: usb@42040000 { + compatible = "st,stm32-otghs"; + reg = <0x42040000 DT_SIZE_K(128)>; + interrupts = <76 0>; + interrupt-names = "otghs"; + num-bidir-endpoints = <9>; + ram-size = <4096>; + clocks = <&rcc STM32_CLOCK(AHB2, 14)>; + phys = <&otghs_phy>; + status = "disabled"; + }; + }; + + otghs_phy: otghs_phy { + compatible = "st,stm32u5-otghs-phy"; + clocks = <&rcc STM32_CLOCK(AHB2, 15)>; + #phy-cells = <0>; + status = "disabled"; }; /* From 7a9634d6651c5172855627df32dbf7986659eb13 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 14 Oct 2025 13:36:07 +0200 Subject: [PATCH 268/397] drivers: usb: udc: stm32: add support for USB on STM32WBA6x Add support for USB on STM32WBA6x series, along with a tiny rework of how the st,stm32u5-otghs-phy is handled to make the code more generic by actually consuming DT information. Signed-off-by: Mathieu Choplain --- drivers/usb/udc/Kconfig.stm32 | 6 ++++- drivers/usb/udc/udc_stm32.c | 46 ++++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/drivers/usb/udc/Kconfig.stm32 b/drivers/usb/udc/Kconfig.stm32 index 11f885f0dfcc3..e99839ca92b98 100644 --- a/drivers/usb/udc/Kconfig.stm32 +++ b/drivers/usb/udc/Kconfig.stm32 @@ -58,7 +58,11 @@ config UDC_STM32_OTG_RXFIFO_BASELINE_SIZE config UDC_STM32_CLOCK_CHECK bool "Runtime USB 48MHz clock check" - default y if !(SOC_SERIES_STM32F1X || SOC_SERIES_STM32F3X || SOC_SERIES_STM32U5X) + default n if SOC_SERIES_STM32F1X || \ + SOC_SERIES_STM32F3X || \ + SOC_SERIES_STM32U5X || \ + SOC_SERIES_STM32WBAX + default y help Enable USB clock 48MHz configuration runtime check. In specific cases, this check might provide wrong verdict and should diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index 99e7804ebbb48..23c8232f9217e 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -135,7 +135,7 @@ LOG_MODULE_REGISTER(udc_stm32, CONFIG_UDC_DRIVER_LOG_LEVEL); #define USB_USBPHYC_CR_FSEL_24MHZ USB_USBPHYC_CR_FSEL_1 #endif -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) && defined(CONFIG_SOC_SERIES_STM32U5X) +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_otghs_phy) static const int syscfg_otg_hs_phy_clk[] = { SYSCFG_OTG_HS_PHY_CLK_SELECT_1, /* 16Mhz */ SYSCFG_OTG_HS_PHY_CLK_SELECT_2, /* 19.2Mhz */ @@ -1266,6 +1266,29 @@ static int priv_clock_enable(void) /* Enable VDDUSB */ LL_PWR_EnableVddUSB(); +#elif defined(CONFIG_SOC_SERIES_STM32WBAX) + /* Remove VDDUSB power isolation */ + LL_PWR_EnableVddUSB(); + + /* Make sure that voltage scaling is Range 1 */ + __ASSERT_NO_MSG(LL_PWR_GetRegulCurrentVOS() == LL_PWR_REGU_VOLTAGE_SCALE1); + + /* Enable VDD11USB */ + LL_PWR_EnableVdd11USB(); + + /* Enable USB OTG internal power */ + LL_PWR_EnableUSBPWR(); + + while (!LL_PWR_IsActiveFlag_VDD11USBRDY()) { + /* Wait for VDD11USB supply to be ready */ + } + + /* Enable USB OTG booster */ + LL_PWR_EnableUSBBooster(); + + while (!LL_PWR_IsActiveFlag_USBBOOSTRDY()) { + /* Wait for USB OTG booster to be ready */ + } #elif defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) /* * VDDUSB independent USB supply (PWR clock is on) @@ -1331,16 +1354,31 @@ static int priv_clock_enable(void) /* Peripheral OTGPHY clock enable */ LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_OTGPHY1); -#elif defined(CONFIG_SOC_SERIES_STM32U5X) +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_otghs_phy) + const struct stm32_pclken hsphy_clk[] = STM32_DT_CLOCKS(DT_NODELABEL(otghs_phy)); + const uint32_t hsphy_clknum = DT_NUM_CLOCKS(DT_NODELABEL(otghs_phy)); + /* Configure OTG PHY reference clock through SYSCFG */ - LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_SYSCFG); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + HAL_SYSCFG_SetOTGPHYReferenceClockSelection( syscfg_otg_hs_phy_clk[DT_ENUM_IDX(DT_NODELABEL(otghs_phy), clock_reference)] ); /* De-assert reset and enable clock of OTG PHY */ HAL_SYSCFG_EnableOTGPHY(SYSCFG_OTG_HS_PHY_ENABLE); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_USBPHY); + + if (hsphy_clknum > 1) { + if (clock_control_configure(clk, (void *)&hsphy_clk[1], NULL) != 0) { + LOG_ERR("Failed OTGHS PHY mux configuration"); + return -EIO; + } + } + + if (clock_control_on(clk, (void *)&hsphy_clk[0]) != 0) { + LOG_ERR("Failed enabling OTGHS PHY clock"); + return -EIO; + } #elif defined(CONFIG_SOC_SERIES_STM32H7X) /* * If HS PHY (over ULPI) is used, enable ULPI interface clock. From 7c87c6826c936f2c02c6448a4ebe5900148e949f Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Tue, 14 Oct 2025 13:38:56 +0200 Subject: [PATCH 269/397] boards: st: nucleo_wba65ri: add support for USB Configure and enable the USB controller on Nucleo-WBA65RI. Signed-off-by: Mathieu Choplain --- boards/st/nucleo_wba65ri/nucleo_wba65ri.dts | 14 ++++++++++++++ boards/st/nucleo_wba65ri/nucleo_wba65ri.yaml | 1 + 2 files changed, 15 insertions(+) diff --git a/boards/st/nucleo_wba65ri/nucleo_wba65ri.dts b/boards/st/nucleo_wba65ri/nucleo_wba65ri.dts index 0d0742d7e2864..52a6dcd1830d1 100644 --- a/boards/st/nucleo_wba65ri/nucleo_wba65ri.dts +++ b/boards/st/nucleo_wba65ri/nucleo_wba65ri.dts @@ -174,3 +174,17 @@ stm32_lp_tick_source: &lptim1 { }; }; }; + +zephyr_udc0: &usbotg_hs { + clocks = <&rcc STM32_CLOCK(AHB2, 14)>, + <&rcc STM32_SRC_HSE OTGHS_SEL(0)>; + pinctrl-0 = <&usb_otg_hs_dm_pd7 &usb_otg_hs_dp_pd6>; + pinctrl-names = "default"; + status = "okay"; +}; + +&otghs_phy { + /* OTG HS clock source is 32 MHz HSE */ + clock-reference = "SYSCFG_OTG_HS_PHY_CLK_32MHz"; + status = "okay"; +}; diff --git a/boards/st/nucleo_wba65ri/nucleo_wba65ri.yaml b/boards/st/nucleo_wba65ri/nucleo_wba65ri.yaml index 78617e1b26282..a9f9eaa2a7dc0 100644 --- a/boards/st/nucleo_wba65ri/nucleo_wba65ri.yaml +++ b/boards/st/nucleo_wba65ri/nucleo_wba65ri.yaml @@ -11,6 +11,7 @@ supported: - spi - adc - rng + - usbd - arduino_gpio - arduino_i2c - arduino_spi From 3722f10de4477872f57ca503d819c71b002dc11f Mon Sep 17 00:00:00 2001 From: Quang Le Date: Wed, 8 Oct 2025 15:31:35 +0700 Subject: [PATCH 270/397] drivers: spi: Initial support for RZN2L, T2M Add SPI driver support for Renesas RZN2L, T2M Signed-off-by: Quang Le Signed-off-by: Tien Nguyen --- drivers/spi/CMakeLists.txt | 1 + drivers/spi/Kconfig.renesas_rz | 28 +- drivers/spi/spi_renesas_rz.c | 779 +++++++++++++++++++++++++++ dts/bindings/spi/renesas,rz-spi.yaml | 39 ++ modules/Kconfig.renesas | 5 + 5 files changed, 850 insertions(+), 2 deletions(-) create mode 100644 drivers/spi/spi_renesas_rz.c create mode 100644 dts/bindings/spi/renesas,rz-spi.yaml diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 6ceda851b1e17..7171b93726f01 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -54,6 +54,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_PW spi_pw.c) zephyr_library_sources_ifdef(CONFIG_SPI_RENESAS_RA spi_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_SPI_RENESAS_RA8 spi_b_renesas_ra8.c) zephyr_library_sources_ifdef(CONFIG_SPI_RENESAS_RX spi_renesas_rx.c) +zephyr_library_sources_ifdef(CONFIG_SPI_RENESAS_RZ spi_renesas_rz.c) zephyr_library_sources_ifdef(CONFIG_SPI_RENESAS_RZ_RSPI spi_renesas_rz_rspi.c) zephyr_library_sources_ifdef(CONFIG_SPI_RPI_PICO_PIO spi_rpi_pico_pio.c) zephyr_library_sources_ifdef(CONFIG_SPI_RV32M1_LPSPI spi_rv32m1_lpspi.c) diff --git a/drivers/spi/Kconfig.renesas_rz b/drivers/spi/Kconfig.renesas_rz index d379e691767da..fc52532a13672 100644 --- a/drivers/spi/Kconfig.renesas_rz +++ b/drivers/spi/Kconfig.renesas_rz @@ -23,6 +23,32 @@ config SPI_RENESAS_RZ_RSPI_DMAC help Enable the SPI DMA mode for SPI instances +endif # SPI_RENESAS_RZ_RSPI + +config SPI_RENESAS_RZ + bool "Renesas RZ SPI" + default y + depends on DT_HAS_RENESAS_RZ_SPI_ENABLED + select USE_RZ_FSP_SPI + select PINCTRL + help + Enable Renesas RZ SPI Driver. + +if SPI_RENESAS_RZ + +config SPI_RENESAS_RZ_INTERRUPT + bool "RZ SPI Interrupt Support" + help + Enable Interrupt support for the SPI. + +config SPI_USE_HW_SS + bool "RZ SPI Hardware Peripheral Select support" + default y + help + Use Hardware Peripheral Select instead of Software Peripheral Select. + +endif # SPI_RENESAS_RZ + if SPI_RTIO config SPI_RTIO_SQ_SIZE int "Number of available submission queue entries" @@ -40,5 +66,3 @@ config SPI_RTIO_CQ_SIZE default 8 # Sensible default that covers most common spi transactions endif # SPI_RTIO - -endif # SPI_RENESAS_RZ_RSPI diff --git a/drivers/spi/spi_renesas_rz.c b/drivers/spi/spi_renesas_rz.c new file mode 100644 index 0000000000000..34dc519db6b1e --- /dev/null +++ b/drivers/spi/spi_renesas_rz.c @@ -0,0 +1,779 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rz_spi + +#include +#include +#include +#include +#include +#include "r_spi.h" +#ifdef CONFIG_SPI_RTIO +#include +#include +#endif +#include + +LOG_MODULE_REGISTER(rz_spi); + +#define LOG_DEV_ERR(dev, format, ...) LOG_ERR("%s:" #format, (dev)->name, ##__VA_ARGS__) + +#include "spi_context.h" + +#define SPI_RZ_SPSRC_CLR 0xFD80 +#define SPI_RZ_TRANSMIT_RECEIVE 0x0 +#define SPI_RZ_TX_ONLY 0x1 + +struct spi_rz_config { + const struct pinctrl_dev_config *pinctrl_dev; + const spi_api_t *fsp_api; + spi_clock_source_t clock_source; +}; + +struct spi_rz_data { + struct spi_context ctx; + uint8_t dfs; + uint32_t data_len; + spi_cfg_t *fsp_config; + spi_instance_ctrl_t *fsp_ctrl; +#ifdef CONFIG_SPI_RTIO + struct spi_rtio *rtio_ctx; +#endif /* CONFIG_SPI_RTIO */ +}; + +#if defined(CONFIG_SPI_RENESAS_RZ_INTERRUPT) +void spi_rxi_isr(void); +void spi_txi_isr(void); +void spi_tei_isr(void); +void spi_eri_isr(void); +#endif /* CONFIG_SPI_RENESAS_RZ_INTERRUPT */ + +#ifdef CONFIG_SPI_RTIO +static void spi_rz_iodev_complete(const struct device *dev, int status); +#else +static bool spi_rz_transfer_ongoing(struct spi_rz_data *data) +{ +#if defined(CONFIG_SPI_RENESAS_RZ_INTERRUPT) + return (spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx)); +#else + if (spi_context_total_tx_len(&data->ctx) == spi_context_total_rx_len(&data->ctx)) { + return (spi_context_tx_on(&data->ctx) && spi_context_rx_on(&data->ctx)); + } else { + return (spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx)); + } +#endif +} +#endif /* CONFIG_SPI_RTIO */ + +static void spi_callback(spi_callback_args_t *p_args) +{ + struct device *dev = (struct device *)p_args->p_context; + struct spi_rz_data *data = dev->data; + + switch (p_args->event) { + case SPI_EVENT_TRANSFER_COMPLETE: + spi_context_cs_control(&data->ctx, false); +#ifdef CONFIG_SPI_RTIO + struct spi_rtio *rtio_ctx = data->rtio_ctx; + + if (rtio_ctx->txn_head != NULL) { + spi_rz_iodev_complete(dev, 0); + } +#endif + spi_context_complete(&data->ctx, dev, 0); + break; + case SPI_EVENT_ERR_MODE_FAULT: /* Mode fault error */ + case SPI_EVENT_ERR_READ_OVERFLOW: /* Read overflow error */ + case SPI_EVENT_ERR_PARITY: /* Parity error */ + case SPI_EVENT_ERR_OVERRUN: /* Overrun error */ + case SPI_EVENT_ERR_FRAMING: /* Framing error */ + case SPI_EVENT_ERR_MODE_UNDERRUN: /* Underrun error */ + spi_context_cs_control(&data->ctx, false); + spi_context_complete(&data->ctx, dev, -EIO); + break; + default: + break; + } +} + +static int spi_rz_configure(const struct device *dev, const struct spi_config *spi_cfg) +{ + struct spi_rz_data *data = dev->data; + const struct spi_rz_config *config = dev->config; + spi_extended_cfg_t *spi_extend = (spi_extended_cfg_t *)data->fsp_config->p_extend; + fsp_err_t err; + + if (spi_context_configured(&data->ctx, spi_cfg)) { + /* This configuration is already in use */ + return 0; + } + + if (data->fsp_ctrl->open != 0) { + config->fsp_api->close(data->fsp_ctrl); + } + + if (spi_cfg->operation & SPI_FRAME_FORMAT_TI) { + LOG_ERR("TI frame not supported"); + return -ENOTSUP; + } + + if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && + (spi_cfg->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_DEV_ERR(dev, "Only single line mode is supported"); + return -ENOTSUP; + } + + /* SPI mode */ + if (spi_cfg->operation & SPI_OP_MODE_SLAVE) { + data->fsp_config->operating_mode = SPI_MODE_SLAVE; + } else { + data->fsp_config->operating_mode = SPI_MODE_MASTER; + } + + /* SPI POLARITY */ + if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) { + data->fsp_config->clk_polarity = SPI_CLK_POLARITY_HIGH; + } else { + data->fsp_config->clk_polarity = SPI_CLK_POLARITY_LOW; + } + + /* SPI PHASE */ + if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPHA) { + data->fsp_config->clk_phase = SPI_CLK_PHASE_EDGE_EVEN; + } else { + data->fsp_config->clk_phase = SPI_CLK_PHASE_EDGE_ODD; + } + + /* SPI bit order */ + if (spi_cfg->operation & SPI_TRANSFER_LSB) { + data->fsp_config->bit_order = SPI_BIT_ORDER_LSB_FIRST; + } else { + data->fsp_config->bit_order = SPI_BIT_ORDER_MSB_FIRST; + } + + data->dfs = ((SPI_WORD_SIZE_GET(spi_cfg->operation) - 1) / 8) + 1; + data->fsp_ctrl->bit_width = (spi_bit_width_t)(SPI_WORD_SIZE_GET(spi_cfg->operation) - 1); + if ((data->fsp_ctrl->bit_width > SPI_BIT_WIDTH_32_BITS) || + (data->fsp_ctrl->bit_width < SPI_BIT_WIDTH_4_BITS)) { + LOG_ERR("Unsupported SPI word size: %u", SPI_WORD_SIZE_GET(spi_cfg->operation)); + return -ENOTSUP; + } + + /* SPI slave select polarity */ + if (spi_cfg->operation & SPI_CS_ACTIVE_HIGH) { + spi_extend->ssl_polarity = SPI_SSLP_HIGH; + } else { + spi_extend->ssl_polarity = SPI_SSLP_LOW; + } + + /* Calculate bitrate */ + if ((spi_cfg->frequency > 0) && (!(spi_cfg->operation & SPI_OP_MODE_SLAVE))) { + err = R_SPI_CalculateBitrate(spi_cfg->frequency, config->clock_source, + &spi_extend->spck_div); + + if (err != FSP_SUCCESS) { + LOG_DEV_ERR(dev, "spi: bitrate calculate error: %d", err); + return -ENOSYS; + } + } + + spi_extend->spi_comm = SPI_COMMUNICATION_FULL_DUPLEX; + + if (spi_cs_is_gpio(spi_cfg) || !IS_ENABLED(CONFIG_SPI_USE_HW_SS)) { + if ((spi_cfg->operation & SPI_OP_MODE_SLAVE) && + (data->fsp_config->clk_phase == SPI_CLK_PHASE_EDGE_ODD)) { + LOG_DEV_ERR(dev, "The CPHA bit must be set to 1 slave mode"); + return -EIO; + } + spi_extend->spi_clksyn = SPI_SSL_MODE_CLK_SYN; + } else { + spi_extend->spi_clksyn = SPI_SSL_MODE_SPI; + switch (spi_cfg->slave) { + case 0: + spi_extend->ssl_select = SPI_SSL_SELECT_SSL0; + break; + case 1: + spi_extend->ssl_select = SPI_SSL_SELECT_SSL1; + break; + case 2: + spi_extend->ssl_select = SPI_SSL_SELECT_SSL2; + break; + case 3: + spi_extend->ssl_select = SPI_SSL_SELECT_SSL3; + break; + default: + LOG_ERR("Invalid SSL"); + return -EINVAL; + } + } + + spi_extend->receive_fifo_threshold = 0; + spi_extend->transmit_fifo_threshold = 0; + + /* Open module r_spi. */ + err = config->fsp_api->open(data->fsp_ctrl, data->fsp_config); + if (err != FSP_SUCCESS) { + LOG_ERR("R_SPI_Open error: %d", err); + return -EIO; + } + + data->ctx.config = spi_cfg; + + return 0; +} + +#if !defined(CONFIG_SPI_RENESAS_RZ_INTERRUPT) +static int spi_rz_spi_transceive_data(struct spi_rz_data *data) +{ + uint32_t tx; + uint32_t rx; + + if (spi_context_tx_buf_on(&data->ctx)) { + if (data->fsp_ctrl->bit_width > SPI_BIT_WIDTH_16_BITS) { + tx = *(uint32_t *)(data->ctx.tx_buf); + } else if (data->fsp_ctrl->bit_width > SPI_BIT_WIDTH_8_BITS) { + tx = *(uint16_t *)(data->ctx.tx_buf); + } else { + tx = *(uint8_t *)(data->ctx.tx_buf); + } + } else { + tx = 0U; + } + + while (!data->fsp_ctrl->p_regs->SPSR_b.SPTEF) { + } + + /* TX transfer */ + if (data->fsp_ctrl->bit_width > SPI_BIT_WIDTH_16_BITS) { + data->fsp_ctrl->p_regs->SPDR = (uint32_t)tx; + } else if (data->fsp_ctrl->bit_width > SPI_BIT_WIDTH_8_BITS) { + data->fsp_ctrl->p_regs->SPDR = (uint16_t)tx; + } else { + data->fsp_ctrl->p_regs->SPDR = (uint8_t)tx; + } + + data->fsp_ctrl->p_regs->SPSRC_b.SPTEFC = 1; /* Clear SPTEF flag */ + spi_context_update_tx(&data->ctx, data->dfs, 1); + + if (data->fsp_ctrl->p_regs->SPCR_b.TXMD == 0x0) { + while (!data->fsp_ctrl->p_regs->SPSR_b.SPRF) { + } + + if (SPI_BIT_WIDTH_16_BITS < data->fsp_ctrl->bit_width) { + rx = (uint32_t)data->fsp_ctrl->p_regs->SPDR; + } else if (SPI_BIT_WIDTH_8_BITS >= data->fsp_ctrl->bit_width) { + rx = (uint8_t)data->fsp_ctrl->p_regs->SPDR; + } else { + rx = (uint16_t)data->fsp_ctrl->p_regs->SPDR; + } + + /* RX transfer */ + if (spi_context_rx_buf_on(&data->ctx)) { + + /* Read data from Data Register */ + if (data->fsp_ctrl->bit_width > SPI_BIT_WIDTH_16_BITS) { + UNALIGNED_PUT(rx, (uint32_t *)data->ctx.rx_buf); + } else if (data->fsp_ctrl->bit_width > SPI_BIT_WIDTH_8_BITS) { + UNALIGNED_PUT(rx, (uint16_t *)data->ctx.rx_buf); + } else { + UNALIGNED_PUT(rx, (uint8_t *)data->ctx.rx_buf); + } + } + spi_context_update_rx(&data->ctx, data->dfs, 1); + data->fsp_ctrl->p_regs->SPSRC_b.SPRFC = 1; /* Clear SPRF flag */ + } + return 0; +} +#endif /* CONFIG_SPI_RENESAS_RZ_INTERRUPT */ + +static int transceive(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, + bool asynchronous, spi_callback_t cb, void *userdata) +{ + struct spi_rz_data *data = dev->data; + struct spi_context *spi_ctx = &data->ctx; + int ret = 0; + + if (!tx_bufs && !rx_bufs) { + return 0; + } + +#ifndef CONFIG_SPI_RENESAS_RZ_INTERRUPT + if (asynchronous) { + return -ENOTSUP; + } +#endif + spi_context_lock(spi_ctx, asynchronous, cb, userdata, spi_cfg); + /* Configure module SPI. */ + ret = spi_rz_configure(dev, spi_cfg); + if (ret) { + spi_context_release(spi_ctx, ret); + return -EIO; + } +#ifndef CONFIG_SPI_RTIO + /* Setup tx buffer and rx buffer info. */ + spi_context_buffers_setup(spi_ctx, tx_bufs, rx_bufs, data->dfs); + spi_context_cs_control(spi_ctx, true); +#if defined(CONFIG_SPI_RENESAS_RZ_INTERRUPT) + const struct spi_rz_config *config = dev->config; + + if (!spi_context_total_tx_len(&data->ctx) && !spi_context_total_rx_len(&data->ctx)) { + goto end_transceive; + } + if (data->ctx.rx_len == 0) { + data->data_len = spi_context_is_slave(&data->ctx) + ? spi_context_total_tx_len(&data->ctx) + : data->ctx.tx_len; + } else if (data->ctx.tx_len == 0) { + data->data_len = spi_context_is_slave(&data->ctx) + ? spi_context_total_rx_len(&data->ctx) + : data->ctx.rx_len; + } else { + data->data_len = spi_context_is_slave(&data->ctx) + ? MAX(spi_context_total_tx_len(&data->ctx), + spi_context_total_rx_len(&data->ctx)) + : MIN(data->ctx.tx_len, data->ctx.rx_len); + } + + if (data->ctx.tx_buf == NULL) { /* If there is only the rx buffer */ + ret = config->fsp_api->read(data->fsp_ctrl, data->ctx.rx_buf, data->data_len, + data->fsp_ctrl->bit_width); + } else if (data->ctx.rx_buf == NULL) { /* If there is only the tx buffer */ + ret = config->fsp_api->write(data->fsp_ctrl, data->ctx.tx_buf, data->data_len, + data->fsp_ctrl->bit_width); + } else { + ret = config->fsp_api->writeRead(data->fsp_ctrl, data->ctx.tx_buf, data->ctx.rx_buf, + data->data_len, data->fsp_ctrl->bit_width); + } + if (ret) { + LOG_ERR("Async transmit fail: %d", ret); + spi_context_cs_control(spi_ctx, false); + spi_context_release(spi_ctx, ret); + return -EIO; + } + ret = spi_context_wait_for_completion(spi_ctx); +end_transceive: +#else + /* Enable the SPI transfer */ + data->fsp_ctrl->p_regs->SPCR_b.TXMD = SPI_RZ_TRANSMIT_RECEIVE; + if (!spi_context_rx_on(&data->ctx)) { + data->fsp_ctrl->p_regs->SPCR_b.TXMD = SPI_RZ_TX_ONLY; /* tx only */ + } + + /* Configure data length based on the selected bit width . */ + uint32_t spcmd0 = data->fsp_ctrl->p_regs->SPCMD[0]; + + spcmd0 &= (uint32_t)~R_SPI0_SPCMD_SPB_Msk; + spcmd0 |= (uint32_t)(data->fsp_ctrl->bit_width) << R_SPI0_SPCMD_SPB_Pos; + data->fsp_ctrl->p_regs->SPCMD[0] = spcmd0; + + /* FIFO clear */ + data->fsp_ctrl->p_regs->SPFCR_b.SPFRST = 1; + /* Enable the SPI Transfer */ + data->fsp_ctrl->p_regs->SPCR_b.SPE = 1; + + do { + spi_rz_spi_transceive_data(data); + } while (spi_rz_transfer_ongoing(data)); + + /* Wait for transmit complete */ + while (data->fsp_ctrl->p_regs->SPSR_b.IDLNF) { + } + + /* Disable the SPI Transfer */ + data->fsp_ctrl->p_regs->SPCR_b.SPE = 0x0; + +#endif /* CONFIG_SPI_RENESAS_RZ_INTERRUPT */ + +#ifdef CONFIG_SPI_SLAVE + if (spi_context_is_slave(spi_ctx) && !ret) { + ret = spi_ctx->recv_frames; + } +#endif /* CONFIG_SPI_SLAVE */ + + spi_context_cs_control(spi_ctx, false); + +#else + struct spi_rtio *rtio_ctx = data->rtio_ctx; + + ret = spi_rtio_transceive(rtio_ctx, spi_cfg, tx_bufs, rx_bufs); + +#endif + spi_context_release(spi_ctx, ret); + + return ret; +} + +static int spi_rz_transceive_sync(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); +} + +static int spi_rz_release(const struct device *dev, const struct spi_config *config) +{ + struct spi_rz_data *data = dev->data; + + spi_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +#ifdef CONFIG_SPI_ASYNC +static int spi_rz_transceive_async(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, spi_callback_t cb, + void *userdata) +{ + return transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata); +} +#endif /* CONFIG_SPI_ASYNC */ + +#ifdef CONFIG_SPI_RTIO + +static inline void spi_rz_iodev_prepare_start(const struct device *dev) +{ + struct spi_rz_data *data = dev->data; + struct spi_rtio *rtio_ctx = data->rtio_ctx; + struct spi_dt_spec *spi_dt_spec = rtio_ctx->txn_curr->sqe.iodev->data; + struct spi_config *spi_config = &spi_dt_spec->config; + int err; + + err = spi_rz_configure(dev, spi_config); + if (err != 0) { + LOG_ERR("RTIO config spi error: %d", err); + spi_rz_iodev_complete(dev, err); + return; + } + spi_context_cs_control(&data->ctx, true); +} + +static void spi_rz_iodev_start(const struct device *dev) +{ + struct spi_rz_data *data = dev->data; + const struct spi_rz_config *config = dev->config; + struct spi_rtio *rtio_ctx = data->rtio_ctx; + struct rtio_sqe *sqe = &rtio_ctx->txn_curr->sqe; + int ret = 0; + + switch (sqe->op) { + case RTIO_OP_RX: + data->data_len = sqe->rx.buf_len / data->dfs; + ret = config->fsp_api->read(data->fsp_ctrl, sqe->rx.buf, data->data_len, + data->fsp_ctrl->bit_width); + break; + case RTIO_OP_TX: + data->data_len = sqe->tx.buf_len / data->dfs; + ret = config->fsp_api->write(data->fsp_ctrl, sqe->tx.buf, data->data_len, + data->fsp_ctrl->bit_width); + break; + case RTIO_OP_TINY_TX: + data->data_len = sqe->tiny_tx.buf_len / data->dfs; + ret = config->fsp_api->write(data->fsp_ctrl, sqe->tiny_tx.buf, data->data_len, + data->fsp_ctrl->bit_width); + break; + case RTIO_OP_TXRX: + data->data_len = sqe->txrx.buf_len / data->dfs; + ret = config->fsp_api->writeRead(data->fsp_ctrl, sqe->txrx.tx_buf, sqe->txrx.rx_buf, + data->data_len, data->fsp_ctrl->bit_width); + break; + default: + spi_rz_iodev_complete(dev, -EINVAL); + break; + } + + if (ret != 0) { + spi_rz_iodev_complete(dev, ret); + } +} + +static void spi_rz_iodev_complete(const struct device *dev, int status) +{ + struct spi_rz_data *data = dev->data; + struct spi_rtio *rtio_ctx = data->rtio_ctx; + + if (!status && rtio_ctx->txn_curr->sqe.flags & RTIO_SQE_TRANSACTION) { + rtio_ctx->txn_curr = rtio_txn_next(rtio_ctx->txn_curr); + spi_rz_iodev_start(dev); + } else { + spi_context_cs_control(&data->ctx, false); + + /* + * Submit the result of the operation to the completion queue + * This may start the next asynchronous request if one is available + */ + if (spi_rtio_complete(rtio_ctx, status)) { + spi_rz_iodev_prepare_start(dev); + spi_rz_iodev_start(dev); + } + } +} + +static void spi_rz_iodev_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct spi_rz_data *data = dev->data; + struct spi_rtio *rtio_ctx = data->rtio_ctx; + + /* Submit sqe to the queue */ + if (spi_rtio_submit(rtio_ctx, iodev_sqe)) { + spi_rz_iodev_prepare_start(dev); + spi_rz_iodev_start(dev); + } +} + +#endif /* CONFIG_SPI_RTIO */ + +static DEVICE_API(spi, spi_rz_driver_api) = { + .transceive = spi_rz_transceive_sync, + .release = spi_rz_release, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = spi_rz_transceive_async, +#endif /* CONFIG_SPI_ASYNC */ +#ifdef CONFIG_SPI_RTIO + .iodev_submit = spi_rz_iodev_submit, +#endif /* CONFIG_SPI_RTIO */ +}; + +#if defined(CONFIG_SPI_RENESAS_RZ_INTERRUPT) +#if !defined(CONFIG_SPI_RTIO) +static void spi_rz_retransmit(struct spi_rz_data *data) +{ + spi_bit_width_t spi_width = + (spi_bit_width_t)(SPI_WORD_SIZE_GET(data->ctx.config->operation) - 1); + + if (data->ctx.rx_len == 0) { + data->data_len = data->ctx.tx_len; + data->fsp_ctrl->p_tx_data = data->ctx.tx_buf; + data->fsp_ctrl->p_rx_data = NULL; + } else if (data->ctx.tx_len == 0) { + data->data_len = data->ctx.rx_len; + data->fsp_ctrl->p_tx_data = NULL; + data->fsp_ctrl->p_rx_data = data->ctx.rx_buf; + } else { + data->data_len = MIN(data->ctx.tx_len, data->ctx.rx_len); + data->fsp_ctrl->p_tx_data = data->ctx.tx_buf; + data->fsp_ctrl->p_rx_data = data->ctx.rx_buf; + } + + data->fsp_ctrl->bit_width = spi_width; + data->fsp_ctrl->rx_count = 0; + data->fsp_ctrl->tx_count = 0; + data->fsp_ctrl->count = data->data_len; +} +#endif /* !CONFIG_SPI_RTIO */ + +static void spi_rz_rxi_isr(const struct device *dev) +{ +#ifndef CONFIG_SPI_SLAVE + ARG_UNUSED(dev); + spi_rxi_isr(); +#else + struct spi_rz_data *data = dev->data; + + spi_rxi_isr(); + + if (spi_context_is_slave(&data->ctx) && data->fsp_ctrl->rx_count == data->fsp_ctrl->count) { + if (data->ctx.rx_buf != NULL && data->ctx.tx_buf != NULL) { + data->ctx.recv_frames = MIN(spi_context_total_tx_len(&data->ctx), + spi_context_total_rx_len(&data->ctx)); + } else if (data->ctx.tx_buf == NULL) { + data->ctx.recv_frames = data->data_len; + } + R_BSP_IrqDisable(data->fsp_config->tei_irq); + + /* Writing 0 to SPE generatates a TXI IRQ. Disable the TXI IRQ. + * (See Section 38.2.1 SPI Control Register in the RA6T2 manual R01UH0886EJ0100). + */ + R_BSP_IrqDisable(data->fsp_config->txi_irq); + + /* Disable the SPI Transfer. */ + data->fsp_ctrl->p_regs->SPCR_b.SPE = 0; + + /* Re-enable the TXI IRQ and clear the pending IRQ. */ + R_BSP_IrqEnable(data->fsp_config->txi_irq); + + spi_context_cs_control(&data->ctx, false); + spi_context_complete(&data->ctx, dev, 0); + } + +#endif +} + +static void spi_rz_txi_isr(const struct device *dev) +{ + ARG_UNUSED(dev); + spi_txi_isr(); +} + +static void spi_rz_tei_isr(const struct device *dev) +{ +#ifndef CONFIG_SPI_RTIO + struct spi_rz_data *data = dev->data; + + if (data->fsp_ctrl->rx_count == data->fsp_ctrl->count) { + spi_context_update_rx(&data->ctx, data->dfs, data->data_len); + } + if (data->fsp_ctrl->tx_count == data->fsp_ctrl->count) { + spi_context_update_tx(&data->ctx, data->dfs, data->data_len); + } + + if (spi_rz_transfer_ongoing(data)) { + R_BSP_IrqDisable(data->fsp_ctrl->p_cfg->txi_irq); + /* Disable the SPI Transfer. */ + data->fsp_ctrl->p_regs->SPCR_b.SPE = 0U; + data->fsp_ctrl->p_regs->SPSRC = SPI_RZ_SPSRC_CLR; + R_BSP_IrqEnable(data->fsp_ctrl->p_cfg->txi_irq); + data->fsp_ctrl->p_regs->SPCR_b.SPE = 1U; + spi_rz_retransmit(data); + } else { + spi_tei_isr(); + } +#else + spi_tei_isr(); +#endif /* CONFIG_SPI_RTIO */ +} + +static void spi_rz_eri_isr(const struct device *dev) +{ + ARG_UNUSED(dev); + spi_eri_isr(); +} +#endif /* CONFIG_SPI_RENESAS_RZ_INTERRUPT || CONFIG_SPI_RTIO */ + +static int spi_rz_init(const struct device *dev) +{ + const struct spi_rz_config *config = dev->config; + struct spi_rz_data *data = dev->data; + int ret; + + ret = pinctrl_apply_state(config->pinctrl_dev, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("pinctrl_apply_state fail: %d", ret); + return ret; + } + + ret = spi_context_cs_configure_all(&data->ctx); + if (ret < 0) { + LOG_ERR("spi_context_cs_configure_all fail: %d", ret); + return ret; + } +#ifdef CONFIG_SPI_RTIO + spi_rtio_init(data->rtio_ctx, dev); +#endif /* CONFIG_SPI_RTIO */ + spi_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +#if defined(CONFIG_SPI_RTIO) +#define SPI_RZ_RTIO_DEFINE(n) \ + SPI_RTIO_DEFINE(spi_rz_rtio_##n, CONFIG_SPI_RTIO_SQ_SIZE, CONFIG_SPI_RTIO_CQ_SIZE) +#else +#define SPI_RZ_RTIO_DEFINE(n) +#endif + +#if defined(CONFIG_SPI_RENESAS_RZ_INTERRUPT) +#define RZ_SPI_IRQ_INIT(n) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, rxi, irq), \ + DT_INST_IRQ_BY_NAME(n, rxi, priority), spi_rz_rxi_isr, \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ_BY_NAME(n, rxi, flags)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, txi, irq), \ + DT_INST_IRQ_BY_NAME(n, txi, priority), spi_rz_txi_isr, \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ_BY_NAME(n, txi, flags)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, eri, irq), \ + DT_INST_IRQ_BY_NAME(n, eri, priority), spi_rz_eri_isr, \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ_BY_NAME(n, eri, flags)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, tei, irq), \ + DT_INST_IRQ_BY_NAME(n, tei, priority), spi_rz_tei_isr, \ + DEVICE_DT_INST_GET(n), DT_INST_IRQ_BY_NAME(n, tei, flags)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, rxi, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, txi, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, eri, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, tei, irq)); \ + } while (0) + +#else +#define RZ_SPI_IRQ_INIT(n) +#endif /* CONFIG_SPI_RENESAS_RZ_INTERRUPT */ + +#define SPI_RZ_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + SPI_RZ_RTIO_DEFINE(n); \ + static spi_instance_ctrl_t g_spi##n##_ctrl; \ + static spi_extended_cfg_t g_spi_##n##_cfg_extend = { \ + .spi_clksyn = SPI_SSL_MODE_SPI, \ + .spi_comm = SPI_COMMUNICATION_FULL_DUPLEX, \ + .ssl_polarity = SPI_SSLP_LOW, \ + .ssl_select = SPI_SSL_SELECT_SSL0, \ + .mosi_idle = SPI_MOSI_IDLE_VALUE_FIXING_DISABLE, \ + .parity = SPI_PARITY_MODE_DISABLE, \ + .byte_swap = SPI_BYTE_SWAP_DISABLE, \ + .clock_source = SPI_CLOCK_SOURCE_SPI0ASYNCCLK, \ + .spck_div = \ + { \ + .spbr = 4, \ + .brdv = 0, \ + }, \ + .spck_delay = SPI_DELAY_COUNT_1, \ + .ssl_negation_delay = SPI_DELAY_COUNT_1, \ + .next_access_delay = SPI_DELAY_COUNT_1, \ + .transmit_fifo_threshold = 0, \ + .receive_fifo_threshold = 0, \ + .receive_data_ready_detect_adjustment = 0, \ + .master_receive_clock = SPI_MASTER_RECEIVE_CLOCK_MRIOCLK, \ + .mrioclk_analog_delay = SPI_MRIOCLK_ANALOG_DELAY_NODELAY, \ + .mrclk_digital_delay = SPI_MRCLK_DIGITAL_DELAY_CLOCK_0, \ + }; \ + static spi_cfg_t g_spi_##n##_config = { \ + .channel = DT_INST_PROP(n, channel), \ + .eri_irq = DT_INST_IRQ_BY_NAME(n, eri, irq), \ + .rxi_ipl = DT_INST_IRQ_BY_NAME(n, rxi, priority), \ + .txi_ipl = DT_INST_IRQ_BY_NAME(n, txi, priority), \ + .eri_ipl = DT_INST_IRQ_BY_NAME(n, eri, priority), \ + .operating_mode = SPI_MODE_MASTER, \ + .clk_phase = SPI_CLK_PHASE_EDGE_ODD, \ + .clk_polarity = SPI_CLK_POLARITY_LOW, \ + .mode_fault = SPI_MODE_FAULT_ERROR_ENABLE, \ + .bit_order = SPI_BIT_ORDER_MSB_FIRST, \ + .p_callback = spi_callback, \ + .p_context = DEVICE_DT_INST_GET(n), \ + .p_extend = &g_spi_##n##_cfg_extend, \ + .rxi_irq = DT_INST_IRQ_BY_NAME(n, rxi, irq), \ + .txi_irq = DT_INST_IRQ_BY_NAME(n, txi, irq), \ + .tei_irq = DT_INST_IRQ_BY_NAME(n, tei, irq), \ + .p_transfer_tx = NULL, \ + .p_transfer_rx = NULL, \ + }; \ + static const struct spi_rz_config spi_rz_config_##n = { \ + .pinctrl_dev = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .fsp_api = &g_spi_on_spi, \ + .clock_source = (spi_clock_source_t)DT_INST_PROP(n, clk_src), \ + }; \ + \ + static struct spi_rz_data spi_rz_data_##n = { \ + SPI_CONTEXT_INIT_LOCK(spi_rz_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_rz_data_##n, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx).fsp_ctrl = &g_spi##n##_ctrl, \ + .fsp_config = &g_spi_##n##_config, \ + IF_ENABLED(CONFIG_SPI_RTIO, \ + (.rtio_ctx = &spi_rz_rtio_##n,)) }; \ + \ + static int spi_rz_init_##n(const struct device *dev) \ + { \ + int err = spi_rz_init(dev); \ + if (err != 0) { \ + return err; \ + } \ + RZ_SPI_IRQ_INIT(n); \ + return 0; \ + } \ + DEVICE_DT_INST_DEFINE(n, &spi_rz_init_##n, NULL, &spi_rz_data_##n, &spi_rz_config_##n, \ + POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, &spi_rz_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SPI_RZ_INIT) diff --git a/dts/bindings/spi/renesas,rz-spi.yaml b/dts/bindings/spi/renesas,rz-spi.yaml new file mode 100644 index 0000000000000..ebf23d8b265d3 --- /dev/null +++ b/dts/bindings/spi/renesas,rz-spi.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: RENESAS RZ SPI + +compatible: "renesas,rz-spi" + +include: [spi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + interrupt-names: + required: true + + channel: + type: int + required: true + + clk-src: + type: int + required: true + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + description: | + Select clock source supplied to calculate bitrate + - 0: SPI0ASYNCCLK + - 1: SPI1ASYNCCLK + - 2: SPI2ASYNCCLK + - 3: SPI3ASYNCCLK + - 4: PCLKM diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index 63844e8136d9f..290294dfdab91 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -347,6 +347,11 @@ config USE_RZ_FSP_CMTW help Enable RZ FSP CMTW driver +config USE_RZ_FSP_SPI + bool + help + Enable RZ FSP SPI driver + config USE_RZ_FSP_WDT bool help From 5ffd3fd867a788144cb4a14068e513123b4d932d Mon Sep 17 00:00:00 2001 From: Quang Le Date: Wed, 8 Oct 2025 15:32:40 +0700 Subject: [PATCH 271/397] dts: renesas: Add SPI support for RZN2L, T2M Add SPI nodes to Renesas RZN2L, T2M devicetree Signed-off-by: Quang Le Signed-off-by: Tien Nguyen --- dts/arm/renesas/rz/rzn/r9a07g084.dtsi | 64 +++++++++++++++++++++++++++ dts/arm/renesas/rz/rzt/r9a07g075.dtsi | 64 +++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/dts/arm/renesas/rz/rzn/r9a07g084.dtsi b/dts/arm/renesas/rz/rzn/r9a07g084.dtsi index 438dc16b3935d..67cbefd4f0a74 100644 --- a/dts/arm/renesas/rz/rzn/r9a07g084.dtsi +++ b/dts/arm/renesas/rz/rzn/r9a07g084.dtsi @@ -1259,6 +1259,70 @@ }; }; + spi0: spi@80003000 { + compatible = "renesas,rz-spi"; + reg = <0x80003000 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <0>; + clk-src = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@80003400 { + compatible = "renesas,rz-spi"; + reg = <0x80003400 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <1>; + clk-src = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@80003800 { + compatible = "renesas,rz-spi"; + reg = <0x80003800 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <2>; + clk-src = <2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi3: spi@81002000 { + compatible = "renesas,rz-spi"; + reg = <0x81002000 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <3>; + clk-src = <3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + wdt0: watchdog@80042000 { compatible = "renesas,rz-wdt"; reg = <0x80042000 0x1000>; diff --git a/dts/arm/renesas/rz/rzt/r9a07g075.dtsi b/dts/arm/renesas/rz/rzt/r9a07g075.dtsi index 38832f7f25025..353e907fd21d0 100644 --- a/dts/arm/renesas/rz/rzt/r9a07g075.dtsi +++ b/dts/arm/renesas/rz/rzt/r9a07g075.dtsi @@ -1263,6 +1263,70 @@ }; }; + spi0: spi@80003000 { + compatible = "renesas,rz-spi"; + reg = <0x80003000 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <0>; + clk-src = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@80003400 { + compatible = "renesas,rz-spi"; + reg = <0x80003400 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <1>; + clk-src = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@80003800 { + compatible = "renesas,rz-spi"; + reg = <0x80003800 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <2>; + clk-src = <2>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi3: spi@81002000 { + compatible = "renesas,rz-spi"; + reg = <0x81002000 0x74>; + interrupts = , + , + , + , + ; + interrupt-names = "rxi", "txi", "idle", "eri", "tei"; + channel = <3>; + clk-src = <3>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + wdt0: watchdog@80042000 { compatible = "renesas,rz-wdt"; reg = <0x80042000 0x1000>; From 71ad2512e6bc86cb7cb1d27eaefc5b11cc5e7a7b Mon Sep 17 00:00:00 2001 From: Quang Le Date: Wed, 8 Oct 2025 15:34:28 +0700 Subject: [PATCH 272/397] boards: renesas: Add SPI support for RZN2L, T2M Add SPI support for board RZ/N2L-RSK, RZ/T2M-RSK Signed-off-by: Quang Le Signed-off-by: Tien Nguyen --- boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi | 9 +++++++++ boards/renesas/rzn2l_rsk/rzn2l_rsk.dts | 6 ++++++ boards/renesas/rzn2l_rsk/rzn2l_rsk.yaml | 1 + boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi | 9 +++++++++ .../rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts | 6 ++++++ .../rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.yaml | 1 + 6 files changed, 32 insertions(+) diff --git a/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi b/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi index 2aa6728c77f0c..9d0515ec0604f 100644 --- a/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi +++ b/boards/renesas/rzn2l_rsk/rzn2l_rsk-pinctrl.dtsi @@ -49,6 +49,15 @@ }; }; + /omit-if-no-ref/ spi2_pins: spi2 { + spi2-pinmux { + pinmux = , /* CK2 */ + , /* MOSI2 */ + , /* MISO2 */ + ; /* SSL20 */ + }; + }; + /omit-if-no-ref/ xspi0_default: xspi0_default { xspi0-pinmux { pinmux = , /* XSPI0_CKP */ diff --git a/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts b/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts index 265c2f092d7a2..c08c80df0903f 100644 --- a/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts +++ b/boards/renesas/rzn2l_rsk/rzn2l_rsk.dts @@ -125,6 +125,12 @@ status = "okay"; }; +&spi2 { + pinctrl-0 = <&spi2_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &wdt0 { status = "okay"; }; diff --git a/boards/renesas/rzn2l_rsk/rzn2l_rsk.yaml b/boards/renesas/rzn2l_rsk/rzn2l_rsk.yaml index 86a27b0da0985..22e2fc3213b6f 100644 --- a/boards/renesas/rzn2l_rsk/rzn2l_rsk.yaml +++ b/boards/renesas/rzn2l_rsk/rzn2l_rsk.yaml @@ -11,5 +11,6 @@ supported: - adc - i2c - counter + - spi - watchdog vendor: renesas diff --git a/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi b/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi index 079e524948559..63a971e8989d7 100644 --- a/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi +++ b/boards/renesas/rzt2m_rsk/rzt2m_rsk-pinctrl.dtsi @@ -41,6 +41,15 @@ }; }; + /omit-if-no-ref/ spi2_pins: spi2 { + spi2-pinmux { + pinmux = , /* CK2 */ + , /* MOSI2 */ + , /* MISO2 */ + ; /* SSL20 */ + }; + }; + /omit-if-no-ref/ xspi0_default: xspi0_default { xspi0-pinmux { pinmux = , /* XSPI0_CKP */ diff --git a/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts b/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts index 3ec08a9689834..6606eb1995083 100644 --- a/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts +++ b/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.dts @@ -122,6 +122,12 @@ status = "okay"; }; +&spi2 { + pinctrl-0 = <&spi2_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + &wdt0 { status = "okay"; }; diff --git a/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.yaml b/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.yaml index 8f5ff3ea5a9fb..9ad2cc1ba7cff 100644 --- a/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.yaml +++ b/boards/renesas/rzt2m_rsk/rzt2m_rsk_r9a07g075m24gbg_cr520.yaml @@ -16,5 +16,6 @@ supported: - adc - i2c - counter + - spi - watchdog vendor: renesas From de283a3736f0b6262efe1a4881b1d48f564bf338 Mon Sep 17 00:00:00 2001 From: Quang Le Date: Wed, 8 Oct 2025 15:35:45 +0700 Subject: [PATCH 273/397] tests: drivers: spi: Add support for RZN2L, T2M Enable SPI driver tests for RZN2L, T2M Signed-off-by: Quang Le Signed-off-by: Tien Nguyen --- .../boards/rzn2l_rsk.conf | 2 + .../boards/rzn2l_rsk.overlay | 52 ++++++++++++++++++ .../rzt2m_rsk_r9a07g075m24gbg_cr520.conf | 2 + .../rzt2m_rsk_r9a07g075m24gbg_cr520.overlay | 53 +++++++++++++++++++ .../spi/spi_loopback/boards/rzn2l_rsk.conf | 5 ++ .../spi/spi_loopback/boards/rzn2l_rsk.overlay | 19 +++++++ .../rzt2m_rsk_r9a07g075m24gbg_cr520.conf | 5 ++ .../rzt2m_rsk_r9a07g075m24gbg_cr520.overlay | 19 +++++++ 8 files changed, 157 insertions(+) create mode 100644 tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.conf create mode 100644 tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.overlay create mode 100644 tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf create mode 100644 tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.conf b/tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.conf new file mode 100644 index 0000000000000..a491c30deaf54 --- /dev/null +++ b/tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.conf @@ -0,0 +1,2 @@ +CONFIG_SPI_RENESAS_RZ_INTERRUPT=y +CONFIG_TESTED_SPI_MODE=1 diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.overlay new file mode 100644 index 0000000000000..2ebcc12027a4b --- /dev/null +++ b/tests/drivers/spi/spi_controller_peripheral/boards/rzn2l_rsk.overlay @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + /omit-if-no-ref/ spi2_pins: spi2 { + spi2-pinmux { + pinmux = , /* CK2 */ + , /* MOSI2 */ + ; /* MISO2 */ + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + + /omit-if-no-ref/ spi3_pins: spi3 { + spi3-pinmux { + pinmux = , /* CK3 */ + , /* MOSI3 */ + , /* MISO3 */ + ; /* SSL3_0 */ + drive-strength = "high"; + slew-rate = "fast"; + }; + }; +}; + +&gpio3 { + status = "okay"; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_pins>; + pinctrl-names = "default"; + cs-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>; + + dut_spi_dt: test-spi-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cs-setup-delay-ns = <180000>; + spi-cs-hold-delay-ns = <180000>; + }; +}; + +dut_spis: &spi3 { + status = "okay"; + pinctrl-0 = <&spi3_pins>; + pinctrl-names = "default"; +}; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf b/tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf new file mode 100644 index 0000000000000..a491c30deaf54 --- /dev/null +++ b/tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf @@ -0,0 +1,2 @@ +CONFIG_SPI_RENESAS_RZ_INTERRUPT=y +CONFIG_TESTED_SPI_MODE=1 diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay new file mode 100644 index 0000000000000..e20522dc95e00 --- /dev/null +++ b/tests/drivers/spi/spi_controller_peripheral/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + + /omit-if-no-ref/ spi2_pins: spi2 { + spi2-pinmux { + pinmux = , /* CK2 */ + , /* MOSI2 */ + ; /* MISO2 */ + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + + /omit-if-no-ref/ spi3_pins: spi3 { + spi3-pinmux { + pinmux = , /* CK3 */ + , /* MOSI3 */ + , /* MISO3 */ + ; /* SSL3 */ + drive-strength = "high"; + slew-rate = "fast"; + }; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_pins>; + pinctrl-names = "default"; + cs-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + + dut_spi_dt: test-spi-dev@0 { + compatible = "vnd,spi-device"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cs-setup-delay-ns = <180000>; + spi-cs-hold-delay-ns = <180000>; + }; +}; + +dut_spis: &spi3 { + status = "okay"; + pinctrl-0 = <&spi3_pins>; + pinctrl-names = "default"; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.conf b/tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.conf new file mode 100644 index 0000000000000..3de8446aac514 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.conf @@ -0,0 +1,5 @@ +CONFIG_SPI_ASYNC=y +CONFIG_SPI_RENESAS_RZ_INTERRUPT=y +CONFIG_SPI_RTIO=n +CONFIG_SPI_LOOPBACK_MODE_LOOP=n +CONFIG_SPI_LARGE_BUFFER_SIZE=2048 diff --git a/tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.overlay b/tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.overlay new file mode 100644 index 0000000000000..7cee6555a3cdf --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rzn2l_rsk.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi2 { + slow@2 { + compatible = "test-spi-loopback-slow"; + reg = <2>; + spi-max-frequency = <500000>; + }; + + fast@2 { + compatible = "test-spi-loopback-fast"; + reg = <2>; + spi-max-frequency = <2500000>; + }; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf b/tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf new file mode 100644 index 0000000000000..3de8446aac514 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf @@ -0,0 +1,5 @@ +CONFIG_SPI_ASYNC=y +CONFIG_SPI_RENESAS_RZ_INTERRUPT=y +CONFIG_SPI_RTIO=n +CONFIG_SPI_LOOPBACK_MODE_LOOP=n +CONFIG_SPI_LARGE_BUFFER_SIZE=2048 diff --git a/tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay b/tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay new file mode 100644 index 0000000000000..7cee6555a3cdf --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi2 { + slow@2 { + compatible = "test-spi-loopback-slow"; + reg = <2>; + spi-max-frequency = <500000>; + }; + + fast@2 { + compatible = "test-spi-loopback-fast"; + reg = <2>; + spi-max-frequency = <2500000>; + }; +}; From d06169f72024a8bb506170ac5708f0d6d9a475b2 Mon Sep 17 00:00:00 2001 From: Quang Le Date: Wed, 8 Oct 2025 16:43:17 +0700 Subject: [PATCH 274/397] samples: drivers: spi: Add support for RZT2M Enable SPI driver sample for RZT2M Signed-off-by: Quang Le Signed-off-by: Tien Nguyen --- .../boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf | 2 ++ .../boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf create mode 100644 samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay diff --git a/samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf b/samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf new file mode 100644 index 0000000000000..bec1bd2a12d91 --- /dev/null +++ b/samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.conf @@ -0,0 +1,2 @@ +CONFIG_GPIO=y +CONFIG_NO_OPTIMIZATIONS=y diff --git a/samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay b/samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay new file mode 100644 index 0000000000000..b48068b7596a5 --- /dev/null +++ b/samples/drivers/spi_bitbang/boards/rzt2m_rsk_r9a07g075m24gbg_cr520.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +spibb0: &spi2 { + cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; From dc84ac0471150da0412d3d513705b163570eab5e Mon Sep 17 00:00:00 2001 From: Bartlomiej Buczek Date: Wed, 8 Oct 2025 09:02:06 +0200 Subject: [PATCH 275/397] boards: nordic: nrf54h20: Add adc to supported features Enable twister tests execution on nrf54h20dk/nrf54h20/cpuppr target. Signed-off-by: Bartlomiej Buczek --- boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuppr_0_9_0.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuppr_0_9_0.yaml b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuppr_0_9_0.yaml index 60f22350504dc..87fe8c68ba91b 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuppr_0_9_0.yaml +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuppr_0_9_0.yaml @@ -11,6 +11,7 @@ sysbuild: true ram: 62 flash: 62 supported: + - adc - counter - gpio - i2c From 8a21df678cfe2af7717c32c58a256fd670873aa8 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Mon, 29 Sep 2025 00:03:45 -0300 Subject: [PATCH 276/397] drivers: udc_dwc2: add Espressif pre-enable and shutdown hooks Ensure the USB clock is enabled before initializing the controller by invoking the pre_enable hook. This avoids initialization failures when the HAL has not yet configured the clock. Adds shutdown hook to allow interrupt and clock deinit. Signed-off-by: Sylvio Alves --- drivers/usb/udc/udc_dwc2_vendor_quirks.h | 42 +++++++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/usb/udc/udc_dwc2_vendor_quirks.h b/drivers/usb/udc/udc_dwc2_vendor_quirks.h index 6766649161ea8..192554e5928e7 100644 --- a/drivers/usb/udc/udc_dwc2_vendor_quirks.h +++ b/drivers/usb/udc/udc_dwc2_vendor_quirks.h @@ -607,30 +607,42 @@ static inline int esp32_usb_otg_init(const struct device *dev, return ret; } -static inline int esp32_usb_otg_enable_phy(struct phy_context_t *phy_ctx, bool enable) +static inline int esp32_usb_otg_enable_clk(struct phy_context_t *phy_ctx) { - LOG_MODULE_DECLARE(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL); + usb_wrap_ll_enable_bus_clock(true); - if (enable) { - usb_wrap_ll_enable_bus_clock(true); - usb_wrap_hal_init(&phy_ctx->wrap_hal); + usb_wrap_ll_reset_register(); + usb_wrap_hal_init(&phy_ctx->wrap_hal); #if USB_WRAP_LL_EXT_PHY_SUPPORTED - usb_wrap_hal_phy_set_external(&phy_ctx->wrap_hal, - (phy_ctx->target == USB_PHY_TARGET_EXT)); + usb_wrap_hal_phy_set_external(&phy_ctx->wrap_hal, (phy_ctx->target == USB_PHY_TARGET_EXT)); #endif + return 0; +} + +static inline int esp32_usb_otg_enable_phy(struct phy_context_t *phy_ctx, bool enable) +{ + LOG_MODULE_DECLARE(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL); + + if (enable) { + usb_wrap_ll_phy_enable_pad(phy_ctx->wrap_hal.dev, true); LOG_DBG("PHY enabled"); } else { - usb_wrap_ll_enable_bus_clock(false); usb_wrap_ll_phy_enable_pad(phy_ctx->wrap_hal.dev, false); - LOG_DBG("PHY disabled"); } return 0; } +static inline int esp32_usb_otg_shutdown(struct phy_context_t *phy_ctx) +{ + usb_wrap_ll_enable_bus_clock(false); + + return 0; +} + #define QUIRK_ESP32_USB_OTG_DEFINE(n) \ \ static struct phy_context_t phy_ctx_##n = { \ @@ -660,6 +672,11 @@ static inline int esp32_usb_otg_enable_phy(struct phy_context_t *phy_ctx, bool e &usb_otg_config_##n, &usb_otg_data_##n); \ } \ \ + static int esp32_usb_otg_enable_clk_##n(const struct device *dev) \ + { \ + return esp32_usb_otg_enable_clk(&phy_ctx_##n); \ + } \ + \ static int esp32_usb_otg_enable_phy_##n(const struct device *dev) \ { \ return esp32_usb_otg_enable_phy(&phy_ctx_##n, true); \ @@ -668,12 +685,19 @@ static inline int esp32_usb_otg_enable_phy(struct phy_context_t *phy_ctx, bool e static int esp32_usb_otg_disable_phy_##n(const struct device *dev) \ { \ return esp32_usb_otg_enable_phy(&phy_ctx_##n, false); \ + } \ + static int esp32_usb_otg_shutdown_##n(const struct device *dev) \ + { \ + esp_intr_free(usb_otg_data_##n.int_handle); \ + return esp32_usb_otg_shutdown(&phy_ctx_##n); \ } \ \ const struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \ .init = esp32_usb_otg_init_##n, \ + .pre_enable = esp32_usb_otg_enable_clk_##n, \ .post_enable = esp32_usb_otg_enable_phy_##n, \ .disable = esp32_usb_otg_disable_phy_##n, \ + .shutdown = esp32_usb_otg_shutdown_##n, \ }; \ #define UDC_DWC2_IRQ_DT_INST_DEFINE(n) \ From 60fbfbd5700aa08f19dd646ecefa21f8c2b066aa Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Tue, 30 Sep 2025 11:20:35 -0300 Subject: [PATCH 277/397] drivers: udc_dwc2: increase stack size for ESP32-S3 Increase default UDC DWS stack size for ESP32-S3 in order to guarantee quirks are executed without issues. Signed-off-by: Sylvio Alves --- drivers/usb/udc/Kconfig.dwc2 | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/udc/Kconfig.dwc2 b/drivers/usb/udc/Kconfig.dwc2 index ff3b169e66a51..43fdf0c96731d 100644 --- a/drivers/usb/udc/Kconfig.dwc2 +++ b/drivers/usb/udc/Kconfig.dwc2 @@ -37,6 +37,7 @@ config UDC_DWC2_PTI config UDC_DWC2_STACK_SIZE int "UDC DWC2 driver internal thread stack size" + default 1024 if SOC_SERIES_ESP32S3 default 512 help DWC2 driver internal thread stack size. From 26e1864a5ff4101438e264b882b49059893de9ab Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Sat, 6 Sep 2025 11:30:14 +0200 Subject: [PATCH 278/397] Bluetooth: BAP: BASE: Split bt_bap_base_get_base_from_ad Split the subgroup validation from bt_bap_base_get_base_from_ad into a new function base_pull_subgroup to make the function simpler and make Sonarcloud happy. The new function, base_pull_subgroup, is also used in the bt_bap_base_foreach_subgroup to reduce code duplication. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_base.c | 158 +++++++++++++++--------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/subsys/bluetooth/audio/bap_base.c b/subsys/bluetooth/audio/bap_base.c index 37d1f72b35e8c..4a7a08acbb7f5 100644 --- a/subsys/bluetooth/audio/bap_base.c +++ b/subsys/bluetooth/audio/bap_base.c @@ -101,6 +101,74 @@ static bool check_pull_ltv(struct net_buf_simple *net_buf) return true; } +static struct bt_bap_base_subgroup *base_pull_subgroup(struct net_buf_simple *net_buf, + uint8_t index) +{ + struct bt_bap_base_subgroup *subgroup = (struct bt_bap_base_subgroup *)net_buf->data; + uint8_t bis_count; + + if (net_buf->len < sizeof(bis_count)) { + LOG_DBG("Invalid BASE length when pulling bis_count: %u", net_buf->size); + + return NULL; + } + + bis_count = base_pull_bis_count(net_buf); + if (!IN_RANGE(bis_count, 1U, BT_ISO_MAX_GROUP_ISO_COUNT)) { + LOG_DBG("Subgroup[%u]: Invalid BIS count: %u", index, bis_count); + + return NULL; + } + + if (net_buf->len < BASE_CODEC_ID_SIZE) { + LOG_DBG("Invalid BASE length when pulling codec: %u", net_buf->size); + + return NULL; + } + + base_pull_codec_id(net_buf, NULL); + + /* Pull CC */ + if (!check_pull_ltv(net_buf)) { + LOG_DBG("Invalid BASE length when pulling CC LTV: %u", net_buf->size); + + return NULL; + } + + /* Pull meta */ + if (!check_pull_ltv(net_buf)) { + LOG_DBG("Invalid BASE length when pulling meta LTV: %u", net_buf->size); + + return NULL; + } + + for (uint8_t i = 0U; i < bis_count; i++) { + uint8_t bis_index; + + if (net_buf->len < sizeof(bis_index)) { + LOG_DBG("Invalid BASE length when pulling bis_index: %u", net_buf->size); + + return NULL; + } + + bis_index = net_buf_simple_pull_u8(net_buf); + if (!IN_RANGE(bis_index, 1U, BT_ISO_BIS_INDEX_MAX)) { + LOG_DBG("Subgroup[%u]: Invalid BIS index: %u", index, bis_index); + + return NULL; + } + + /* Pull BIS CC data */ + if (!check_pull_ltv(net_buf)) { + LOG_DBG("Invalid BASE length when pulling BIS CC LTV: %u", net_buf->size); + + return NULL; + } + } + + return subgroup; +} + const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad) { struct bt_uuid_16 broadcast_uuid; @@ -155,66 +223,13 @@ const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad) } for (uint8_t i = 0U; i < subgroup_count; i++) { - uint8_t bis_count; - - if (net_buf.len < sizeof(bis_count)) { - LOG_DBG("Invalid BASE length: %u", ad->data_len); - - return NULL; - } + const struct bt_bap_base_subgroup *subgroup = base_pull_subgroup(&net_buf, i); - bis_count = base_pull_bis_count(&net_buf); - if (!IN_RANGE(bis_count, 1U, BT_ISO_MAX_GROUP_ISO_COUNT)) { - LOG_DBG("Subgroup[%u]: Invalid BIS count: %u", i, bis_count); + if (subgroup == NULL) { + LOG_DBG("Subgroup[%u] is invalid", i); return NULL; } - - if (net_buf.len < BASE_CODEC_ID_SIZE) { - LOG_DBG("Invalid BASE length: %u", ad->data_len); - - return NULL; - } - - base_pull_codec_id(&net_buf, NULL); - - /* Pull CC */ - if (!check_pull_ltv(&net_buf)) { - LOG_DBG("Invalid BASE length: %u", ad->data_len); - - return NULL; - } - - /* Pull meta */ - if (!check_pull_ltv(&net_buf)) { - LOG_DBG("Invalid BASE length: %u", ad->data_len); - - return NULL; - } - - for (uint8_t j = 0U; j < bis_count; j++) { - uint8_t bis_index; - - if (net_buf.len < sizeof(bis_index)) { - LOG_DBG("Invalid BASE length: %u", ad->data_len); - - return NULL; - } - - bis_index = net_buf_simple_pull_u8(&net_buf); - if (!IN_RANGE(bis_index, 1U, BT_ISO_BIS_INDEX_MAX)) { - LOG_DBG("Subgroup[%u]: Invalid BIS index: %u", i, bis_index); - - return NULL; - } - - /* Pull BIS CC data */ - if (!check_pull_ltv(&net_buf)) { - LOG_DBG("Invalid BASE length: %u", ad->data_len); - - return NULL; - } - } } return base; @@ -312,7 +327,6 @@ int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base, void *user_data), void *user_data) { - struct bt_bap_base_subgroup *subgroup; struct net_buf_simple net_buf; uint8_t subgroup_count; @@ -333,32 +347,18 @@ int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base, subgroup_count = net_buf_simple_pull_u8(&net_buf); for (uint8_t i = 0U; i < subgroup_count; i++) { - subgroup = (struct bt_bap_base_subgroup *)net_buf.data; - if (!func(subgroup, user_data)) { - LOG_DBG("user stopped parsing"); + const struct bt_bap_base_subgroup *subgroup = base_pull_subgroup(&net_buf, i); - return -ECANCELED; - } - - /* Parse subgroup data to get next subgroup pointer */ - if (subgroup_count > 1) { /* Only parse data if it isn't the last one */ - uint8_t bis_count; - - bis_count = base_pull_bis_count(&net_buf); - base_pull_codec_id(&net_buf, NULL); - - /* Codec config */ - base_pull_ltv(&net_buf, NULL); + if (subgroup == NULL) { + LOG_DBG("Subgroup[%u] is invalid", i); - /* meta */ - base_pull_ltv(&net_buf, NULL); + return -EINVAL; + } - for (uint8_t j = 0U; j < bis_count; j++) { - net_buf_simple_pull_u8(&net_buf); /* index */ + if (!func(subgroup, user_data)) { + LOG_DBG("user stopped parsing"); - /* Codec config */ - base_pull_ltv(&net_buf, NULL); - } + return -ECANCELED; } } From 5dd472cbe950db6aa7b81a3e6d9d49f8e1155093 Mon Sep 17 00:00:00 2001 From: Dave Rensberger Date: Wed, 16 Apr 2025 11:14:00 -0400 Subject: [PATCH 279/397] drivers: wifi: infineon: add .iface_status method The .iface_status method of the wifi_mgmt_ops API needs to be added so that the "wifi status" command on the network shell will work. Signed-off-by: Dave Rensberger --- drivers/wifi/infineon/airoc_wifi.c | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/wifi/infineon/airoc_wifi.c b/drivers/wifi/infineon/airoc_wifi.c index fb1846e3d5eb1..7604b82b66ea1 100644 --- a/drivers/wifi/infineon/airoc_wifi.c +++ b/drivers/wifi/infineon/airoc_wifi.c @@ -13,6 +13,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); @@ -811,6 +812,80 @@ static int airoc_mgmt_ap_disable(const struct device *dev) return 0; } +static int airoc_iface_status(const struct device *dev, struct wifi_iface_status *status) +{ + struct airoc_wifi_data *data = dev->data; + whd_result_t result; + wl_bss_info_t bss_info; + whd_security_t security_info = 0; + uint32_t wpa_data_rate_value = 0; + uint32_t join_status; + + if (airoc_if == NULL) { + return -ENOTSUP; + } + + status->iface_mode = + (data->is_ap_up ? WIFI_MODE_AP + : (data->is_sta_connected ? WIFI_MODE_INFRA : WIFI_MODE_UNKNOWN)); + + join_status = whd_wifi_is_ready_to_transceive(airoc_if); + + if (join_status == WHD_SUCCESS) { + status->state = WIFI_STATE_COMPLETED; + } else if (join_status == WHD_JOIN_IN_PROGRESS) { + status->state = WIFI_STATE_ASSOCIATING; + } else if (join_status == WHD_NOT_KEYED) { + status->state = WIFI_STATE_AUTHENTICATING; + } else { + status->state = WIFI_STATE_DISCONNECTED; + } + + result = whd_wifi_get_ap_info(airoc_if, &bss_info, &security_info); + + if (result == WHD_SUCCESS) { + memcpy(&(status->bssid[0]), &(bss_info.BSSID), sizeof(whd_mac_t)); + + whd_wifi_get_channel(airoc_if, (int *)&status->channel); + + status->band = (status->channel <= CH_MAX_2G_CHANNEL) ? WIFI_FREQ_BAND_2_4_GHZ + : WIFI_FREQ_BAND_5_GHZ; + + status->rssi = (int)bss_info.RSSI; + + status->ssid_len = bss_info.SSID_len; + strncpy(status->ssid, bss_info.SSID, status->ssid_len); + + status->security = convert_whd_security_to_zephyr(security_info); + + status->beacon_interval = (unsigned short)bss_info.beacon_period; + status->dtim_period = (unsigned char)bss_info.dtim_period; + + status->twt_capable = false; + } + + whd_wifi_get_ioctl_value(airoc_if, WLC_GET_RATE, &wpa_data_rate_value); + status->current_phy_tx_rate = wpa_data_rate_value; + + /* Unbelievably, this appears to be the only way to determine the phy mode with + * the whd SDK that we're currently using. Note that the logic below is only valid on + * devices that are limited to the 2.4Ghz band. Other versions of the SDK and chip + * evidently allow one to obtain a phy_mode value directly from bss_info + */ + if (wpa_data_rate_value > 54) { + status->link_mode = WIFI_4; + } else if (wpa_data_rate_value == 6 || wpa_data_rate_value == 9 || + wpa_data_rate_value == 12 || wpa_data_rate_value == 18 || + wpa_data_rate_value == 24 || wpa_data_rate_value == 36 || + wpa_data_rate_value == 48 || wpa_data_rate_value == 54) { + status->link_mode = WIFI_3; + } else { + status->link_mode = WIFI_1; + } + + return 0; +} + static int airoc_init(const struct device *dev) { int ret; @@ -864,6 +939,7 @@ static const struct wifi_mgmt_ops airoc_wifi_mgmt = { .disconnect = airoc_mgmt_disconnect, .ap_enable = airoc_mgmt_ap_enable, .ap_disable = airoc_mgmt_ap_disable, + .iface_status = airoc_iface_status, #if defined(CONFIG_NET_STATISTICS_WIFI) .get_stats = airoc_mgmt_wifi_stats, #endif From 43f3d47b552c3b891f9988c5391f7d4077534d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Mon, 20 Oct 2025 09:26:18 +0200 Subject: [PATCH 280/397] Bluetooth: Host: Add BT_APP_PASSKEY Kconfig option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the BT_APP_PASSKEY Kconfig, which allows the application to provide passkeys for pairing using the new `app_passkey()` callback. This is an alternative to BT_FIXED_PASSKEY, which will be deprecated in a later commit. Signed-off-by: Håvard Reierstad --- include/zephyr/bluetooth/conn.h | 31 +++++++++++++ subsys/bluetooth/host/Kconfig | 10 +++++ subsys/bluetooth/host/smp.c | 77 +++++++++++++++++++++++++-------- 3 files changed, 99 insertions(+), 19 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 67c3db64e92a1..0ebfb89bf4bf8 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -2464,6 +2464,13 @@ struct bt_conn_pairing_feat { }; #endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */ +/** + * Special passkey value that can be used to generate a random passkey when using the + * app_passkey callback from @ref bt_conn_auth_cb. + * + */ +#define BT_PASSKEY_RAND 0xffffffff + /** Authenticated pairing callback structure */ struct bt_conn_auth_cb { #if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT) @@ -2663,6 +2670,30 @@ struct bt_conn_auth_cb { */ void (*pincode_entry)(struct bt_conn *conn, bool highsec); #endif + +#if defined(CONFIG_BT_APP_PASSKEY) + /** @brief Allow the application to provide a passkey for pairing. + * + * If implemented, this callback allows the application to provide passkeys for pairing. + * The valid range of passkeys is 0 - 999999. The application shall return the passkey for + * pairing, or BT_PASSKEY_RAND to generate a random passkey. This callback is invoked only + * for the Passkey Entry method as defined in Core Specification Vol. 3, Part H. Which + * device in the pairing is showing the passkey depends on the IO capabilities of the + * device; see Table 2.8 of the Bluetooth Core Specification V6.0, Vol. 3, Part H for more + * details. For the purposes of this table, the device gains the "display" capability when + * this callback is non-NULL. This is irrespective of whether the callback returns a + * specified key or BT_PASSKEY_RAND. + * + * + * @note When using this callback, it is the responsibility of the application to use + * random and unique keys. + * + * @param conn Connection where pairing is currently active. + * @return Passkey for pairing, or BT_PASSKEY_RAND for the Host to generate a random + * passkey. + */ + uint32_t (*app_passkey)(struct bt_conn *conn); +#endif /* CONFIG_BT_APP_PASSKEY */ }; /** Authenticated pairing information callback structure */ diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 0e85437f3def3..fc4bd8a598673 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -731,6 +731,16 @@ config BT_FIXED_PASSKEY bt_passkey_set() API to set a fixed passkey. If set, the pairing_confirm() callback will be called for all incoming pairings. +config BT_APP_PASSKEY + bool "Allow the application to provide passkeys for pairing" + depends on !BT_FIXED_PASSKEY + help + With this option enabled, the application will be able to provide passkeys for pairing + using the app_passkey() callback. If the application does not provide a passkey, a + random passkey will be generated by the Host. + + WARNING: It is the responsibility of the application to use random and unique keys. + config BT_USE_DEBUG_KEYS bool "Security Manager Debug Mode" help diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 702e6fc0d215e..b935c61d2a36a 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -222,10 +222,10 @@ struct bt_smp { atomic_t bondable; }; -static unsigned int fixed_passkey = BT_PASSKEY_INVALID; +static unsigned int fixed_passkey = BT_PASSKEY_RAND; #define DISPLAY_FIXED(smp) (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && \ - fixed_passkey != BT_PASSKEY_INVALID && \ + fixed_passkey != BT_PASSKEY_RAND && \ (smp)->method == PASSKEY_DISPLAY) #if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY) @@ -363,9 +363,21 @@ static uint8_t get_io_capa(struct bt_smp *smp) return BT_SMP_IO_DISPLAY_YESNO; } +#if defined(CONFIG_BT_APP_PASSKEY) + /* Implementation of the app_passkey cb implies that the application can "know" the passkey + * without actually having a display, thus earning the "display" capability. + */ + if (smp_auth_cb->app_passkey) { + if (smp_auth_cb->passkey_entry) { + return BT_SMP_IO_KEYBOARD_DISPLAY; + } + + return BT_SMP_IO_DISPLAY_ONLY; + } +#endif /* CONFIG_BT_APP_PASSKEY */ + if (smp_auth_cb->passkey_entry) { - if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && - fixed_passkey != BT_PASSKEY_INVALID) { + if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && fixed_passkey != BT_PASSKEY_RAND) { return BT_SMP_IO_KEYBOARD_DISPLAY; } else { return BT_SMP_IO_KEYBOARD_ONLY; @@ -377,8 +389,7 @@ static uint8_t get_io_capa(struct bt_smp *smp) } no_callbacks: - if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && - fixed_passkey != BT_PASSKEY_INVALID) { + if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && fixed_passkey != BT_PASSKEY_RAND) { return BT_SMP_IO_DISPLAY_ONLY; } else { return BT_SMP_IO_NO_INPUT_OUTPUT; @@ -2475,7 +2486,6 @@ static uint8_t legacy_request_tk(struct bt_smp *smp) struct bt_conn *conn = smp->chan.chan.conn; const struct bt_conn_auth_cb *smp_auth_cb = latch_auth_cb(smp); struct bt_keys *keys; - uint32_t passkey; /* * Fail if we have keys that are stronger than keys that will be @@ -2503,11 +2513,25 @@ static uint8_t legacy_request_tk(struct bt_smp *smp) } break; - case PASSKEY_DISPLAY: - if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && - fixed_passkey != BT_PASSKEY_INVALID) { + case PASSKEY_DISPLAY: { + uint32_t passkey; + + if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && fixed_passkey != BT_PASSKEY_RAND) { passkey = fixed_passkey; - } else { +#if defined(CONFIG_BT_APP_PASSKEY) + } else if (smp_auth_cb && smp_auth_cb->app_passkey) { + passkey = smp_auth_cb->app_passkey(conn); + + if (passkey != BT_PASSKEY_RAND && passkey > 999999) { + LOG_WRN("App-provided passkey is out of valid range: %u", passkey); + return BT_SMP_ERR_UNSPECIFIED; + } +#endif /* CONFIG_BT_APP_PASSKEY */ + } else { + passkey = BT_PASSKEY_RAND; + } + + if (passkey == BT_PASSKEY_RAND) { if (bt_rand(&passkey, sizeof(passkey))) { return BT_SMP_ERR_UNSPECIFIED; } @@ -2527,6 +2551,7 @@ static uint8_t legacy_request_tk(struct bt_smp *smp) sys_put_le32(passkey, smp->tk); break; + } case PASSKEY_INPUT: atomic_set_bit(smp->flags, SMP_FLAG_USER); smp_auth_cb->passkey_entry(conn); @@ -4429,18 +4454,32 @@ __maybe_unused static uint8_t display_passkey(struct bt_smp *smp) { struct bt_conn *conn = smp->chan.chan.conn; const struct bt_conn_auth_cb *smp_auth_cb = latch_auth_cb(smp); + uint32_t passkey = BT_PASSKEY_RAND; - if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && - fixed_passkey != BT_PASSKEY_INVALID) { - smp->passkey = fixed_passkey; - } else { - if (bt_rand(&smp->passkey, sizeof(smp->passkey))) { + if (IS_ENABLED(CONFIG_BT_FIXED_PASSKEY) && fixed_passkey != BT_PASSKEY_RAND) { + passkey = fixed_passkey; + } + +#if defined(CONFIG_BT_APP_PASSKEY) + if (smp_auth_cb && smp_auth_cb->app_passkey) { + passkey = smp_auth_cb->app_passkey(conn); + + if (passkey != BT_PASSKEY_RAND && passkey > 999999) { + LOG_WRN("App-provided passkey is out of valid range: %u", passkey); + return BT_SMP_ERR_UNSPECIFIED; + } + } +#endif /* CONFIG_BT_APP_PASSKEY */ + + if (passkey == BT_PASSKEY_RAND) { + if (bt_rand(&passkey, sizeof(passkey))) { return BT_SMP_ERR_UNSPECIFIED; } - smp->passkey %= 1000000; + passkey %= 1000000; } + smp->passkey = passkey; smp->passkey_round = 0U; if (smp_auth_cb && smp_auth_cb->passkey_display) { @@ -6172,8 +6211,8 @@ int bt_smp_auth_pairing_confirm(struct bt_conn *conn) #if defined(CONFIG_BT_FIXED_PASSKEY) int bt_passkey_set(unsigned int passkey) { - if (passkey == BT_PASSKEY_INVALID) { - fixed_passkey = BT_PASSKEY_INVALID; + if (passkey == BT_PASSKEY_INVALID || passkey == BT_PASSKEY_RAND) { + fixed_passkey = BT_PASSKEY_RAND; return 0; } From 9d4a82080ed750e3924ac80d8e4b663d4edd5bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Mon, 20 Oct 2025 09:40:15 +0200 Subject: [PATCH 281/397] Bluetooth: Host: Deprecate BT_FIXED_PASSKEY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BT_FIXED_PASSKEY Kconfig option is being deprecated, and is replaced by BT_APP_PASSKEY. The reason for the deprecation is an upcoming errata, ES-24489, which mandates that a new passkey shall be generated for each pairing procedure. Signed-off-by: Håvard Reierstad --- doc/releases/migration-guide-4.3.rst | 9 +++++++++ include/zephyr/bluetooth/conn.h | 9 ++++++--- subsys/bluetooth/host/Kconfig | 4 +++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/doc/releases/migration-guide-4.3.rst b/doc/releases/migration-guide-4.3.rst index b913c41e34757..9cd82fc9c2059 100644 --- a/doc/releases/migration-guide-4.3.rst +++ b/doc/releases/migration-guide-4.3.rst @@ -234,6 +234,15 @@ Bluetooth Mesh been removed. The selection of the PSA Crypto provider is now automatically controlled by Kconfig :kconfig:option:`CONFIG_PSA_CRYPTO`. +Bluetooth Host +============== + +* :kconfig:option:`CONFIG_BT_FIXED_PASSKEY` has been deprecated. Instead, the application can + provide passkeys for pairing using the :c:member:`bt_conn_auth_cb.app_passkey` callback, which is + available when :kconfig:option:`CONFIG_BT_APP_PASSKEY` is enabled. The application can return the + passkey for pairing, or :c:macro:`BT_PASSKEY_RAND` for the Host to generate a random passkey + instead. + Ethernet ======== diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 0ebfb89bf4bf8..881d0894ee118 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -2380,8 +2380,8 @@ int bt_le_oob_get_sc_data(struct bt_conn *conn, const struct bt_le_oob_sc_data **oobd_remote); /** - * Special passkey value that can be used to disable a previously - * set fixed passkey. + * DEPRECATED - use @ref BT_PASSKEY_RAND instead. Special passkey value that can be used to disable + * a previously set fixed passkey. */ #define BT_PASSKEY_INVALID 0xffffffff @@ -2393,12 +2393,15 @@ int bt_le_oob_get_sc_data(struct bt_conn *conn, * Sets a fixed passkey to be used for pairing. If set, the * pairing_confirm() callback will be called for all incoming pairings. * + * @deprecated Use @ref BT_PASSKEY_RAND and the app_passkey callback from @ref bt_conn_auth_cb + * instead. + * * @param passkey A valid passkey (0 - 999999) or BT_PASSKEY_INVALID * to disable a previously set fixed passkey. * * @return 0 on success or a negative error code on failure. */ -int bt_passkey_set(unsigned int passkey); +__deprecated int bt_passkey_set(unsigned int passkey); /** Info Structure for OOB pairing */ struct bt_conn_oob_info { diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index fc4bd8a598673..df800f6a2bfcd 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -725,8 +725,10 @@ config BT_SMP_USB_HCI_CTLR_WORKAROUND if the keys are distributed over an encrypted link. config BT_FIXED_PASSKEY - bool "Use a fixed passkey for pairing" + bool "Use a fixed passkey for pairing [DEPRECATED]" + select DEPRECATED help + This option is deprecated, use BT_APP_PASSKEY instead. With this option enabled, the application will be able to call the bt_passkey_set() API to set a fixed passkey. If set, the pairing_confirm() callback will be called for all incoming pairings. From c1136daeedec07ef210720eaa8a604c0a39c283a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Mon, 20 Oct 2025 09:45:26 +0200 Subject: [PATCH 282/397] Bluetooth: Host: shell: Don't use BT_FIXED_PASSKEY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates the bt shell API to use the new Kconfig option BT_APP_PASSKEY instead of BT_FIXED_PASSKEY as this is being deprecated. Signed-off-by: Håvard Reierstad --- subsys/bluetooth/host/shell/bt.c | 53 ++++++++++++++++++++++---------- tests/bluetooth/shell/audio.conf | 2 +- tests/bluetooth/shell/log.conf | 2 +- tests/bluetooth/shell/prj.conf | 2 +- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/subsys/bluetooth/host/shell/bt.c b/subsys/bluetooth/host/shell/bt.c index a09afe4e3e5cb..816b6549853b0 100644 --- a/subsys/bluetooth/host/shell/bt.c +++ b/subsys/bluetooth/host/shell/bt.c @@ -4421,6 +4421,15 @@ static void br_bond_deleted(const bt_addr_t *peer) } #endif /* CONFIG_BT_CLASSIC */ +#if defined(CONFIG_BT_APP_PASSKEY) +static uint32_t app_passkey = BT_PASSKEY_RAND; + +static uint32_t auth_app_passkey(struct bt_conn *conn) +{ + return app_passkey; +} +#endif /* CONFIG_BT_APP_PASSKEY */ + static struct bt_conn_auth_cb auth_cb_display = { .passkey_display = auth_passkey_display, #if defined(CONFIG_BT_PASSKEY_KEYPRESS) @@ -4437,6 +4446,9 @@ static struct bt_conn_auth_cb auth_cb_display = { #if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT) .pairing_accept = pairing_accept, #endif +#if defined(CONFIG_BT_APP_PASSKEY) + .app_passkey = auth_app_passkey, +#endif }; static struct bt_conn_auth_cb auth_cb_display_yes_no = { @@ -4445,6 +4457,9 @@ static struct bt_conn_auth_cb auth_cb_display_yes_no = { .passkey_confirm = auth_passkey_confirm, #if defined(CONFIG_BT_CLASSIC) .pincode_entry = auth_pincode_entry, +#endif +#if defined(CONFIG_BT_APP_PASSKEY) + .app_passkey = auth_app_passkey, #endif .oob_data_request = NULL, .cancel = auth_cancel, @@ -4460,6 +4475,9 @@ static struct bt_conn_auth_cb auth_cb_input = { .passkey_confirm = NULL, #if defined(CONFIG_BT_CLASSIC) .pincode_entry = auth_pincode_entry, +#endif +#if defined(CONFIG_BT_APP_PASSKEY) + .app_passkey = auth_app_passkey, #endif .oob_data_request = NULL, .cancel = auth_cancel, @@ -4472,6 +4490,9 @@ static struct bt_conn_auth_cb auth_cb_input = { static struct bt_conn_auth_cb auth_cb_confirm = { #if defined(CONFIG_BT_CLASSIC) .pincode_entry = auth_pincode_entry, +#endif +#if defined(CONFIG_BT_APP_PASSKEY) + .app_passkey = auth_app_passkey, #endif .oob_data_request = NULL, .cancel = auth_cancel, @@ -4487,6 +4508,9 @@ static struct bt_conn_auth_cb auth_cb_all = { .passkey_confirm = auth_passkey_confirm, #if defined(CONFIG_BT_CLASSIC) .pincode_entry = auth_pincode_entry, +#endif +#if defined(CONFIG_BT_APP_PASSKEY) + .app_passkey = auth_app_passkey, #endif .oob_data_request = auth_pairing_oob_data_request, .cancel = auth_cancel, @@ -4703,16 +4727,15 @@ static int cmd_fal_connect(const struct shell *sh, size_t argc, char *argv[]) #endif /* CONFIG_BT_CENTRAL */ #endif /* defined(CONFIG_BT_FILTER_ACCEPT_LIST) */ -#if defined(CONFIG_BT_FIXED_PASSKEY) -static int cmd_fixed_passkey(const struct shell *sh, - size_t argc, char *argv[]) +#if defined(CONFIG_BT_APP_PASSKEY) +static int cmd_app_passkey(const struct shell *sh, + size_t argc, char *argv[]) { - unsigned int passkey; - int err; + uint32_t passkey; if (argc < 2) { - bt_passkey_set(BT_PASSKEY_INVALID); - shell_print(sh, "Fixed passkey cleared"); + app_passkey = BT_PASSKEY_RAND; + shell_print(sh, "App passkey cleared"); return 0; } @@ -4722,14 +4745,12 @@ static int cmd_fixed_passkey(const struct shell *sh, return -ENOEXEC; } - err = bt_passkey_set(passkey); - if (err) { - shell_print(sh, "Setting fixed passkey failed (err %d)", err); - } + app_passkey = passkey; + shell_print(sh, "App passkey set to %06u", passkey); - return err; + return 0; } -#endif +#endif /* CONFIG_BT_APP_PASSKEY */ static int cmd_auth_passkey(const struct shell *sh, size_t argc, char *argv[]) @@ -5340,10 +5361,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, cmd_fal_connect, 2, 3), #endif /* CONFIG_BT_CENTRAL */ #endif /* defined(CONFIG_BT_FILTER_ACCEPT_LIST) */ -#if defined(CONFIG_BT_FIXED_PASSKEY) - SHELL_CMD_ARG(fixed-passkey, NULL, "[passkey]", cmd_fixed_passkey, +#if defined(CONFIG_BT_APP_PASSKEY) + SHELL_CMD_ARG(app-passkey, NULL, "[passkey]", cmd_app_passkey, 1, 1), -#endif +#endif /* CONFIG_BT_APP_PASSKEY */ #endif /* CONFIG_BT_SMP || CONFIG_BT_CLASSIC) */ #endif /* CONFIG_BT_CONN */ diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index f4143e31aac3e..dc940c0cc0b5e 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -22,7 +22,7 @@ CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y CONFIG_BT_GATT_AUTO_UPDATE_MTU=y CONFIG_BT_L2CAP_ECRED=y CONFIG_BT_SIGNING=y -CONFIG_BT_FIXED_PASSKEY=y +CONFIG_BT_APP_PASSKEY=y CONFIG_BT_ATT_PREPARE_COUNT=5 CONFIG_BT_SHELL=y CONFIG_BT_DEVICE_NAME="audio test shell" diff --git a/tests/bluetooth/shell/log.conf b/tests/bluetooth/shell/log.conf index 746a3bbe57021..9068129f01aac 100644 --- a/tests/bluetooth/shell/log.conf +++ b/tests/bluetooth/shell/log.conf @@ -9,7 +9,7 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y CONFIG_BT_SMP=y CONFIG_BT_SIGNING=y -CONFIG_BT_FIXED_PASSKEY=y +CONFIG_BT_APP_PASSKEY=y CONFIG_BT_ATT_PREPARE_COUNT=2 CONFIG_BT_GATT_CLIENT=y CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y diff --git a/tests/bluetooth/shell/prj.conf b/tests/bluetooth/shell/prj.conf index 85f9ae0072057..54c904e957a87 100644 --- a/tests/bluetooth/shell/prj.conf +++ b/tests/bluetooth/shell/prj.conf @@ -11,7 +11,7 @@ CONFIG_BT_PRIVACY=y CONFIG_BT_SMP=y CONFIG_BT_PASSKEY_KEYPRESS=y CONFIG_BT_SIGNING=y -CONFIG_BT_FIXED_PASSKEY=y +CONFIG_BT_APP_PASSKEY=y CONFIG_BT_ATT_PREPARE_COUNT=2 CONFIG_BT_GATT_CLIENT=y CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y From 5ed20d0759b6023b4e8d56d27b4720907735457c Mon Sep 17 00:00:00 2001 From: Martin Hoff Date: Thu, 16 Oct 2025 15:41:35 +0200 Subject: [PATCH 283/397] drivers: serial: silabs: Correction of dma/peripheral isr exec order This patch correct a bug where the uart/eusart tx callback might be triggered before the dma complete callback at high baudrate when using async transfer. Signed-off-by: Martin Hoff --- drivers/serial/uart_silabs_eusart.c | 4 +++- drivers/serial/uart_silabs_usart.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_silabs_eusart.c b/drivers/serial/uart_silabs_eusart.c index 5def91e1d3ab8..9424fdb5106f0 100644 --- a/drivers/serial/uart_silabs_eusart.c +++ b/drivers/serial/uart_silabs_eusart.c @@ -470,9 +470,12 @@ __maybe_unused static void eusart_dma_tx_cb(const struct device *dma_dev, void * { const struct device *uart_dev = user_data; struct eusart_data *data = uart_dev->data; + const struct eusart_config *config = uart_dev->config; dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); data->dma_tx.enabled = false; + + EUSART_IntEnable(config->eusart, EUSART_IF_TXC); } static int eusart_async_tx(const struct device *dev, const uint8_t *tx_data, size_t buf_size, @@ -500,7 +503,6 @@ static int eusart_async_tx(const struct device *dev, const uint8_t *tx_data, siz eusart_pm_lock_get(dev, EUSART_PM_LOCK_TX); EUSART_IntClear(config->eusart, EUSART_IF_TXC); - EUSART_IntEnable(config->eusart, EUSART_IF_TXC); ret = dma_config(data->dma_tx.dma_dev, data->dma_tx.dma_channel, &data->dma_tx.dma_cfg); if (ret) { diff --git a/drivers/serial/uart_silabs_usart.c b/drivers/serial/uart_silabs_usart.c index e0482bafe1fa6..4f7095b53e714 100644 --- a/drivers/serial/uart_silabs_usart.c +++ b/drivers/serial/uart_silabs_usart.c @@ -461,9 +461,12 @@ void uart_silabs_dma_tx_cb(const struct device *dma_dev, void *user_data, uint32 { const struct device *uart_dev = user_data; struct uart_silabs_data *data = uart_dev->data; + const struct uart_silabs_config *config = uart_dev->config; dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); data->dma_tx.enabled = false; + + USART_IntEnable(config->base, USART_IF_TXC); } static int uart_silabs_async_tx(const struct device *dev, const uint8_t *tx_data, size_t buf_size, @@ -499,7 +502,6 @@ static int uart_silabs_async_tx(const struct device *dev, const uint8_t *tx_data (void)uart_silabs_pm_lock_get(dev, UART_SILABS_PM_LOCK_TX); USART_IntClear(config->base, USART_IF_TXC | USART_IF_TCMP2); - USART_IntEnable(config->base, USART_IF_TXC); if (timeout >= 0) { USART_IntEnable(config->base, USART_IF_TCMP2); } From 9bee842654750245ee013f007bffb6736a0481ad Mon Sep 17 00:00:00 2001 From: Martin Hoff Date: Thu, 16 Oct 2025 15:46:07 +0200 Subject: [PATCH 284/397] drivers: serial: silabs: Fix uart tx abort at high baudrate At high baudrate when using async api of the uart, the abort function in not giving the right informations since we're stopping the dma after getting the status of it. It makes the uart_async_api test failed on high baudrate. Signed-off-by: Martin Hoff --- drivers/serial/uart_silabs_usart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/serial/uart_silabs_usart.c b/drivers/serial/uart_silabs_usart.c index 4f7095b53e714..bfb5a2362801f 100644 --- a/drivers/serial/uart_silabs_usart.c +++ b/drivers/serial/uart_silabs_usart.c @@ -539,11 +539,12 @@ static int uart_silabs_async_tx_abort(const struct device *dev) USART_IntClear(config->base, USART_IF_TXC | USART_IF_TCMP2); (void)uart_silabs_pm_lock_put(dev, UART_SILABS_PM_LOCK_TX); + dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); + if (!dma_get_status(data->dma_tx.dma_dev, data->dma_tx.dma_channel, &stat)) { data->dma_tx.counter = tx_buffer_length - stat.pending_length; } - dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); data->dma_tx.enabled = false; async_evt_tx_abort(data); From d7b20cfdc44696026f0ab9b3568d2a05f0dd4470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 22 Oct 2025 10:55:41 +0200 Subject: [PATCH 285/397] arch: arc: add sys_write64/sys_read64 functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added sys_read64 and sys_write64 functions for 64-bit memory operations, similar to sys_read32 and sys_write32. Signed-off-by: Benjamin Cabé --- include/zephyr/arch/arc/sys-io-common.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/zephyr/arch/arc/sys-io-common.h b/include/zephyr/arch/arc/sys-io-common.h index 006b1012a61e4..cdd92e3e81d17 100644 --- a/include/zephyr/arch/arc/sys-io-common.h +++ b/include/zephyr/arch/arc/sys-io-common.h @@ -74,6 +74,24 @@ static ALWAYS_INLINE void sys_write32(uint32_t data, mem_addr_t addr) compiler_barrier(); } +static ALWAYS_INLINE uint64_t sys_read64(mem_addr_t addr) +{ + uint64_t value; + + compiler_barrier(); + value = *(volatile uint64_t *)addr; + compiler_barrier(); + + return value; +} + +static ALWAYS_INLINE void sys_write64(uint64_t data, mem_addr_t addr) +{ + compiler_barrier(); + *(volatile uint64_t *)addr = data; + compiler_barrier(); +} + #ifdef __cplusplus } #endif From edb4f591f233c7441848a9302ca136fd98966fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 22 Oct 2025 16:08:21 +0200 Subject: [PATCH 286/397] Revert "arch: arc: add sys_write64/sys_read64 functions" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3462a489f06dc247a422f8e1663a9ab4e665004e that was marked as hotfix and merged despite reservations from ARC maintainer Signed-off-by: Benjamin Cabé --- include/zephyr/arch/arc/sys-io-common.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/include/zephyr/arch/arc/sys-io-common.h b/include/zephyr/arch/arc/sys-io-common.h index cdd92e3e81d17..006b1012a61e4 100644 --- a/include/zephyr/arch/arc/sys-io-common.h +++ b/include/zephyr/arch/arc/sys-io-common.h @@ -74,24 +74,6 @@ static ALWAYS_INLINE void sys_write32(uint32_t data, mem_addr_t addr) compiler_barrier(); } -static ALWAYS_INLINE uint64_t sys_read64(mem_addr_t addr) -{ - uint64_t value; - - compiler_barrier(); - value = *(volatile uint64_t *)addr; - compiler_barrier(); - - return value; -} - -static ALWAYS_INLINE void sys_write64(uint64_t data, mem_addr_t addr) -{ - compiler_barrier(); - *(volatile uint64_t *)addr = data; - compiler_barrier(); -} - #ifdef __cplusplus } #endif From c190f1c874ea1c644614faebd6edd38fadf73e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 22 Oct 2025 16:08:54 +0200 Subject: [PATCH 287/397] Revert "shell: modules: devmem: support 64-bit read & write" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5149463f7934d824bad8cbf1a5fca8c3bc06a95f which causes issue for ARC64 architectures in main Signed-off-by: Benjamin Cabé --- subsys/shell/modules/devmem_service.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/subsys/shell/modules/devmem_service.c b/subsys/shell/modules/devmem_service.c index c5781faf9dd70..559a946d6d677 100644 --- a/subsys/shell/modules/devmem_service.c +++ b/subsys/shell/modules/devmem_service.c @@ -253,7 +253,7 @@ static int cmd_load(const struct shell *sh, size_t argc, char **argv) static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) { - uint64_t value; + uint32_t value; int err = 0; switch (width) { @@ -266,11 +266,6 @@ static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) case 32: value = sys_read32(addr); break; -#ifdef CONFIG_64BIT - case 64: - value = sys_read64(addr); - break; -#endif /* CONFIG_64BIT */ default: shell_fprintf(sh, SHELL_NORMAL, "Incorrect data width\n"); err = -EINVAL; @@ -278,7 +273,7 @@ static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) } if (err == 0) { - shell_fprintf(sh, SHELL_NORMAL, "Read value 0x%llx\n", value); + shell_fprintf(sh, SHELL_NORMAL, "Read value 0x%x\n", value); } return err; @@ -298,11 +293,6 @@ static int memory_write(const struct shell *sh, mem_addr_t addr, uint8_t width, case 32: sys_write32(value, addr); break; -#ifdef CONFIG_64BIT - case 64: - sys_write64(value, addr); - break; -#endif /* CONFIG_64BIT */ default: shell_fprintf(sh, SHELL_NORMAL, "Incorrect data width\n"); err = -EINVAL; @@ -316,7 +306,7 @@ static int memory_write(const struct shell *sh, mem_addr_t addr, uint8_t width, static int cmd_devmem(const struct shell *sh, size_t argc, char **argv) { mem_addr_t phys_addr, addr; - uint64_t value = 0; + uint32_t value = 0; uint8_t width; phys_addr = strtoul(argv[1], NULL, 16); @@ -345,9 +335,9 @@ static int cmd_devmem(const struct shell *sh, size_t argc, char **argv) * this value at the address provided */ - value = (uint64_t)strtoull(argv[3], NULL, 16); + value = strtoul(argv[3], NULL, 16); - shell_fprintf(sh, SHELL_NORMAL, "Writing value 0x%llx\n", value); + shell_fprintf(sh, SHELL_NORMAL, "Writing value 0x%x\n", value); return memory_write(sh, addr, width, value); } From 536542e8cef5288ffaf468818a5e9ed15965ba94 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Wed, 22 Oct 2025 12:41:39 +0200 Subject: [PATCH 288/397] MAINTAINERS: add dts/vendor/arduino/ to Arduino Platforms section Files in that directory relate to Arduino hardware products, so it makes sense to include them in the Arduino Platforms section. Signed-off-by: Luca Burelli --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 06b7c992d6d7e..032994d613dec 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -337,6 +337,7 @@ Arduino Platforms: - boards/arduino/ - boards/shields/arduino_*/ - drivers/*/*modulino* + - dts/vendor/arduino/ Base OS: status: maintained From 79ba94ff5e7687e6a82ef82dafa312858eb3f518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Wed, 22 Oct 2025 11:37:11 +0200 Subject: [PATCH 289/397] mgmt: hawkbit: exclude DIRECT_XIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DIRECT_XIP requires different images based on the slot where there it is saved, in hawkbit we currently have no way of telling the server that or chosing a image to download based on it, so make sure it is not used. Signed-off-by: Fin Maaß --- subsys/mgmt/hawkbit/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/mgmt/hawkbit/Kconfig b/subsys/mgmt/hawkbit/Kconfig index 4111f20ccd261..962cb5262a7d7 100644 --- a/subsys/mgmt/hawkbit/Kconfig +++ b/subsys/mgmt/hawkbit/Kconfig @@ -15,6 +15,8 @@ menuconfig HAWKBIT depends on BOOTLOADER_MCUBOOT depends on SMF depends on SMF_ANCESTOR_SUPPORT + depends on !MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP + depends on !MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT select MPU_ALLOW_FLASH_WRITE select IMG_ENABLE_IMAGE_CHECK select IMG_ERASE_PROGRESSIVELY From 0d36e096a3056e296f8781769ddc8a034494daf4 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:42:01 +0200 Subject: [PATCH 290/397] arch: arm: mpu: move MPU memory configuration header Move the helper file arm_mpu_mem_cfg.h, which translates the values of the Kconfig symbols CONFIG_FLASH_SIZE and CONFIG_SRAM_SIZE to size definitions to be used during MPU setup, from a Cortex-M-specific include directory to the Cortex-agnostic zephyr/arch/arm/mpu directory, as: - the contents of this header file are not dependent on the target being an ARMv7M, only ARMv8M is excluded, but the contents are identical for the ARMv7/8 Cortex-R MPU implementation, - the header file zephyr/arch/arm/mpu/arm_mpu.h, included within arm_mpu_mem_cfg.h, is also compatible with both Cortex-M and Cortex-R, the distinction between the two implementations takes place at an even lower level, - several ARMv7/8 Cortex-R targets now reference this header file in their MPU region setup (Xilinx ZynqMP, TI K3, Renode cortex_r8_virtual) while so far referencing it in an ARMv7 Cortex-M-specific include directory. Signed-off-by: Immo Birnbaum --- include/zephyr/arch/arm/{cortex_m => mpu}/arm_mpu_mem_cfg.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename include/zephyr/arch/arm/{cortex_m => mpu}/arm_mpu_mem_cfg.h (96%) diff --git a/include/zephyr/arch/arm/cortex_m/arm_mpu_mem_cfg.h b/include/zephyr/arch/arm/mpu/arm_mpu_mem_cfg.h similarity index 96% rename from include/zephyr/arch/arm/cortex_m/arm_mpu_mem_cfg.h rename to include/zephyr/arch/arm/mpu/arm_mpu_mem_cfg.h index da958a51e643f..5b52a939d2a77 100644 --- a/include/zephyr/arch/arm/cortex_m/arm_mpu_mem_cfg.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu_mem_cfg.h @@ -4,8 +4,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef _ARM_CORTEX_M_MPU_MEM_CFG_H_ -#define _ARM_CORTEX_M_MPU_MEM_CFG_H_ +#ifndef _INCLUDE_ZEPHYR_ARCH_ARM_MPU_MEM_CFG_H_ +#define _INCLUDE_ZEPHYR_ARCH_ARM_MPU_MEM_CFG_H_ #include @@ -119,4 +119,4 @@ #endif /* !ARMV8_M_BASELINE && !ARMV8_M_MAINLINE */ -#endif /* _ARM_CORTEX_M_MPU_MEM_CFG_H_ */ +#endif /* _INCLUDE_ZEPHYR_ARCH_ARM_MPU_MEM_CFG_H_ */ From a8859b8b2a0d75c8a40154e3f9e6da33bdfebdf5 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:32:07 +0200 Subject: [PATCH 291/397] arch: arm: core: mpu: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- arch/arm/core/mpu/arm_mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/core/mpu/arm_mpu_regions.c b/arch/arm/core/mpu/arm_mpu_regions.c index 0bf7a219c27d7..f5f725a75fb6a 100644 --- a/arch/arm/core/mpu/arm_mpu_regions.c +++ b/arch/arm/core/mpu/arm_mpu_regions.c @@ -7,7 +7,7 @@ #include #include -#include +#include static const struct arm_mpu_region mpu_regions[] = { #ifdef CONFIG_XIP From cd43bebfe18b98ebadcf8c39932809cd3049db39 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:33:44 +0200 Subject: [PATCH 292/397] soc: xlnx: zynqmp: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/xlnx/zynqmp/arm_mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/xlnx/zynqmp/arm_mpu_regions.c b/soc/xlnx/zynqmp/arm_mpu_regions.c index 73fc8bdb073dc..57a3a2f07153b 100644 --- a/soc/xlnx/zynqmp/arm_mpu_regions.c +++ b/soc/xlnx/zynqmp/arm_mpu_regions.c @@ -5,7 +5,7 @@ */ #include -#include +#include extern const uint32_t __rom_region_start; extern const uint32_t __rom_region_mpu_size_bits; From ff551e1ab016f1d69cedbe98988457cbd679e5ab Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:34:40 +0200 Subject: [PATCH 293/397] soc: ti: am6x: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/ti/k3/am6x/r5/arm_mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/ti/k3/am6x/r5/arm_mpu_regions.c b/soc/ti/k3/am6x/r5/arm_mpu_regions.c index 495224a0597b3..7b4357a4f39f6 100644 --- a/soc/ti/k3/am6x/r5/arm_mpu_regions.c +++ b/soc/ti/k3/am6x/r5/arm_mpu_regions.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include #include From dc078ef6b43dec4c1bb5b3cc209462aee60ee3cb Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:35:27 +0200 Subject: [PATCH 294/397] soc: st: stm32h7x: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/st/stm32/stm32h7x/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/st/stm32/stm32h7x/mpu_regions.c b/soc/st/stm32/stm32h7x/mpu_regions.c index f77018d36caed..73eab5f1d7ad8 100644 --- a/soc/st/stm32/stm32h7x/mpu_regions.c +++ b/soc/st/stm32/stm32h7x/mpu_regions.c @@ -5,7 +5,7 @@ */ #include -#include +#include static const struct arm_mpu_region mpu_regions[] = { MPU_REGION_ENTRY("FLASH", CONFIG_FLASH_BASE_ADDRESS, From 425bc34296036f522dd2a9168506859ccfc313c8 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:36:12 +0200 Subject: [PATCH 295/397] soc: renode: cortex_r8_virtual: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/renode/cortex_r8_virtual/arm_mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/renode/cortex_r8_virtual/arm_mpu_regions.c b/soc/renode/cortex_r8_virtual/arm_mpu_regions.c index 6a9ea54ed352c..6325a7957d3c8 100644 --- a/soc/renode/cortex_r8_virtual/arm_mpu_regions.c +++ b/soc/renode/cortex_r8_virtual/arm_mpu_regions.c @@ -6,7 +6,7 @@ */ #include -#include +#include extern const uint32_t __rom_region_start; extern const uint32_t __rom_region_mpu_size_bits; From 22860106b13344ac8928e603954f1c76bb1622f0 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:36:57 +0200 Subject: [PATCH 296/397] soc: nxp: s32k3: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/nxp/s32/s32k3/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/nxp/s32/s32k3/mpu_regions.c b/soc/nxp/s32/s32k3/mpu_regions.c index 948e28bcab7ea..10e9de27b3b0b 100644 --- a/soc/nxp/s32/s32k3/mpu_regions.c +++ b/soc/nxp/s32/s32k3/mpu_regions.c @@ -6,7 +6,7 @@ #include #include -#include +#include #if !defined(CONFIG_XIP) extern char _rom_attr[]; From bb9f7359966c8c29a28b8230244a022bb0ce7bfc Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:37:25 +0200 Subject: [PATCH 297/397] soc: nxp: imxrt: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/nxp/imxrt/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/nxp/imxrt/mpu_regions.c b/soc/nxp/imxrt/mpu_regions.c index 51ce490eff1d8..8a017dadaf174 100644 --- a/soc/nxp/imxrt/mpu_regions.c +++ b/soc/nxp/imxrt/mpu_regions.c @@ -7,7 +7,7 @@ #define SDRAM_BASE_ADDR 0x80000000 #include -#include +#include static const struct arm_mpu_region mpu_regions[] = { /* Region 0 */ From 13d7cf683f92892f4c8dc17e63decb8a9e77fb75 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:37:54 +0200 Subject: [PATCH 298/397] soc: nxp: imx8m: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/nxp/imx/imx8m/m7/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/nxp/imx/imx8m/m7/mpu_regions.c b/soc/nxp/imx/imx8m/m7/mpu_regions.c index ed7deb8575abf..c7ca883882f73 100644 --- a/soc/nxp/imx/imx8m/m7/mpu_regions.c +++ b/soc/nxp/imx/imx8m/m7/mpu_regions.c @@ -5,7 +5,7 @@ */ #include -#include +#include #define REGION_MASK_BASE_ADDRESS 0x00000000U #define REGION_ITCM_BASE_ADDRESS 0x00000000U From 796430e8ce16bf64341276ec314d3fd8f7a03fa4 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:38:28 +0200 Subject: [PATCH 299/397] soc: nuvoton: m55m1x: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/nuvoton/numaker/m55m1x/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/nuvoton/numaker/m55m1x/mpu_regions.c b/soc/nuvoton/numaker/m55m1x/mpu_regions.c index 33e59b71fba18..ecf2a0a4651e8 100644 --- a/soc/nuvoton/numaker/m55m1x/mpu_regions.c +++ b/soc/nuvoton/numaker/m55m1x/mpu_regions.c @@ -5,7 +5,7 @@ */ #include -#include +#include static const struct arm_mpu_region mpu_regions[] = { MPU_REGION_ENTRY("FLASH", From f8c616e9a9d7112b9a5913703071b0800b2978b6 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:38:56 +0200 Subject: [PATCH 300/397] soc: nuvoton: npcx7: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/nuvoton/npcx/npcx7/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/nuvoton/npcx/npcx7/mpu_regions.c b/soc/nuvoton/npcx/npcx7/mpu_regions.c index e9d4c07330588..da8199eceb8db 100644 --- a/soc/nuvoton/npcx/npcx7/mpu_regions.c +++ b/soc/nuvoton/npcx/npcx7/mpu_regions.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include static const struct arm_mpu_region mpu_regions[] = { MPU_REGION_ENTRY("FLASH_0_0", From 829f2e69555404246557e3bd1a397723032acc02 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:39:40 +0200 Subject: [PATCH 301/397] soc: nordic: nrf54hx: nrf92x: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/nordic/common/nrf54hx_nrf92x_mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/nordic/common/nrf54hx_nrf92x_mpu_regions.c b/soc/nordic/common/nrf54hx_nrf92x_mpu_regions.c index a9e8b3de7a912..65814c347d710 100644 --- a/soc/nordic/common/nrf54hx_nrf92x_mpu_regions.c +++ b/soc/nordic/common/nrf54hx_nrf92x_mpu_regions.c @@ -5,7 +5,7 @@ */ #include -#include +#include #define USBHS_BASE DT_REG_ADDR_BY_NAME(DT_NODELABEL(usbhs), core) #define USBHS_SIZE DT_REG_SIZE_BY_NAME(DT_NODELABEL(usbhs), core) From 300d9e05459eeb59504299a469520e4f0fa6dee9 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:40:19 +0200 Subject: [PATCH 302/397] soc: infineon: cyq20829: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/infineon/cat1b/cyw20829/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/infineon/cat1b/cyw20829/mpu_regions.c b/soc/infineon/cat1b/cyw20829/mpu_regions.c index 6ee6078def26f..36313f9481f4b 100644 --- a/soc/infineon/cat1b/cyw20829/mpu_regions.c +++ b/soc/infineon/cat1b/cyw20829/mpu_regions.c @@ -5,7 +5,7 @@ */ #include -#include +#include #define BOOTSTRAP_SAHB_RAM_BASE_ADDRESS DT_REG_ADDR(DT_NODELABEL(sram_bootstrap_sahb)) #define BOOTSTRAP_CBUS_RAM_BASE_ADDRESS DT_REG_ADDR(DT_NODELABEL(sram_bootstrap_cbus)) From 9160f1903d7fcaae034484287ba35e81ca42711c Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:40:55 +0200 Subject: [PATCH 303/397] soc: adi: max32: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/adi/max32/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/adi/max32/mpu_regions.c b/soc/adi/max32/mpu_regions.c index fd5c56a47e3b4..020b5cf19126f 100644 --- a/soc/adi/max32/mpu_regions.c +++ b/soc/adi/max32/mpu_regions.c @@ -6,7 +6,7 @@ #include #include -#include +#include /* * Define noncacheable flash region attributes using noncacheable SRAM memory From 4b7b55efc0386bf1021ae3a55a7043be2b5fe1e7 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 16:41:21 +0200 Subject: [PATCH 304/397] boards: nxp: mimxrt1180_evk: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c b/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c index ac4e838fca30e..cd444ea4ec673 100644 --- a/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c +++ b/boards/nxp/mimxrt1180_evk/cm7/mpu_regions.c @@ -5,7 +5,7 @@ */ #include -#include +#include #define MEMORY_REGION_SIZE_KB(SIZE) (SIZE / 1024) From 1330d7b34252b4bf3ab4641524a80d129a2260d0 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 18:19:34 +0200 Subject: [PATCH 305/397] soc: infineon: pse84: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/infineon/edge/pse84/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/infineon/edge/pse84/mpu_regions.c b/soc/infineon/edge/pse84/mpu_regions.c index 137245c4b30f7..b4d285e4e341b 100644 --- a/soc/infineon/edge/pse84/mpu_regions.c +++ b/soc/infineon/edge/pse84/mpu_regions.c @@ -6,7 +6,7 @@ */ #include -#include +#include /* We are expected to give *CONFIG_SIZE* in KB, but REGION_ATTR * expects bytes, so we multiply by 1024 to convert. From 80e6a9d9c32ecfc6c2f2c90f851f98e992b664eb Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Mon, 20 Oct 2025 18:20:13 +0200 Subject: [PATCH 306/397] soc: st: stm32h7rsx: adjust MPU header include Update include of header file arm_mpu_mem_cfg.h which has been moved to a Cortex-M/-R-agnostic include directory. Signed-off-by: Immo Birnbaum --- soc/st/stm32/stm32h7rsx/mpu_regions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/st/stm32/stm32h7rsx/mpu_regions.c b/soc/st/stm32/stm32h7rsx/mpu_regions.c index 72995b85216e6..35dfce848cded 100644 --- a/soc/st/stm32/stm32h7rsx/mpu_regions.c +++ b/soc/st/stm32/stm32h7rsx/mpu_regions.c @@ -8,7 +8,7 @@ #include #include -#include +#include static const struct arm_mpu_region mpu_regions[] = { /* Use first region to prevent speculative access in entire memory space */ From 1ec03f70a535cd53b0abc671713bc5bc3ab843f0 Mon Sep 17 00:00:00 2001 From: Cristian Bulacu Date: Mon, 20 Oct 2025 16:21:09 +0300 Subject: [PATCH 307/397] modules: openthread: platform: mdns_socket: Update AIL address monitor This commit improves AIL address monitoring; Associated function will be called after OpenThread mDNS module starts platform code by 'otPlatMdnsSetListeningEnabled`. A new flag, `mdns_socket_is_enabled` has been added to support this new logic. Signed-off-by: Cristian Bulacu --- modules/openthread/platform/mdns_socket.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/openthread/platform/mdns_socket.c b/modules/openthread/platform/mdns_socket.c index 59e0c204315fd..71abb3150c3ba 100644 --- a/modules/openthread/platform/mdns_socket.c +++ b/modules/openthread/platform/mdns_socket.c @@ -35,6 +35,7 @@ static int mdns_sock_v4 = -1; #endif /* CONFIG_NET_IPV4 */ static struct otInstance *ot_instance_ptr; static uint32_t ail_iface_index; +static bool mdns_socket_is_enabled; static otError mdns_socket_init_v6(uint32_t ail_iface_idx); #if defined(CONFIG_NET_IPV4) @@ -87,10 +88,13 @@ static otError set_listening_enable(otInstance *instance, bool enable, uint32_t #if defined(CONFIG_NET_IPV4) SuccessOrExit(error = mdns_socket_init_v4(ail_iface_idx)); #endif /* CONFIG_NET_IPV4 */ + mdns_socket_is_enabled = true; + mdns_plat_monitor_interface(net_if_get_by_index(ail_iface_idx)); ExitNow(); } SuccessOrExit(error = mdns_socket_deinit()); + mdns_socket_is_enabled = false; exit: return error; @@ -389,6 +393,10 @@ void mdns_plat_monitor_interface(struct net_if *ail_iface) otIp6Address ip6_addr = {0}; struct net_if_addr *unicast = NULL; + VerifyOrExit(mdns_socket_is_enabled); + + net_if_lock(ail_iface); + otPlatMdnsHandleHostAddressRemoveAll(ot_instance_ptr, ail_iface_index); ipv6 = ail_iface->config.ip.ipv6; @@ -422,4 +430,8 @@ void mdns_plat_monitor_interface(struct net_if *ail_iface) ail_iface_index); } #endif /* CONFIG_NET_IPV4 && CONFIG_NET_IPV4_MAPPING_TO_IPV6 */ + + net_if_unlock(ail_iface); +exit: + return; } From 3073c15460f7d82fd76a679fea916618db579570 Mon Sep 17 00:00:00 2001 From: Cristian Bulacu Date: Mon, 20 Oct 2025 16:24:32 +0300 Subject: [PATCH 308/397] net: l2: openthread: openthread_border_router: Update address events This commit refactored IPV6 and IPV4 address events. Events have been defined independently for each installed callback. Previously, IPV6 address event was not triggered due to a mix of IPV4 and IPV6 flags. Signed-off-by: Cristian Bulacu --- .../l2/openthread/openthread_border_router.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/subsys/net/l2/openthread/openthread_border_router.c b/subsys/net/l2/openthread/openthread_border_router.c index dde38376ac5cd..8a21f0d35ca64 100644 --- a/subsys/net/l2/openthread/openthread_border_router.c +++ b/subsys/net/l2/openthread/openthread_border_router.c @@ -33,9 +33,9 @@ #include static struct net_mgmt_event_callback ail_net_event_connection_cb; -static struct net_mgmt_event_callback ail_net_event_address_cb; +static struct net_mgmt_event_callback ail_net_event_ipv6_addr_cb; #if defined(CONFIG_NET_IPV4) -static struct net_mgmt_event_callback ail_net_event_ipv4_addr_add_cb; +static struct net_mgmt_event_callback ail_net_event_ipv4_addr_cb; #endif /* CONFIG_NET_IPV4 */ static uint32_t ail_iface_index; static struct net_if *ail_iface_ptr; @@ -234,15 +234,14 @@ static void ail_connection_handler(struct net_mgmt_event_callback *cb, uint64_t mdns_plat_monitor_interface(iface); } -static void ail_address_event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, +static void ail_ipv6_address_event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) { return; } - if ((mgmt_event & (NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_ADDR_DEL | - NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IPV4_ADDR_DEL)) != mgmt_event) { + if ((mgmt_event & (NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_ADDR_DEL)) != mgmt_event) { return; } @@ -257,13 +256,15 @@ static void ail_ipv4_address_event_handler(struct net_mgmt_event_callback *cb, u return; } - if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { + if ((mgmt_event & (NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IPV4_ADDR_DEL)) != mgmt_event) { return; } - struct openthread_context *ot_context = openthread_get_default_context(); + if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) { + struct openthread_context *ot_context = openthread_get_default_context(); - openthread_start_border_router_services(ot_context->iface, iface); + openthread_start_border_router_services(ot_context->iface, iface); + } mdns_plat_monitor_interface(iface); } @@ -318,15 +319,14 @@ void openthread_border_router_init(struct openthread_context *ot_ctx) net_mgmt_init_event_callback(&ail_net_event_connection_cb, ail_connection_handler, NET_EVENT_IF_UP | NET_EVENT_IF_DOWN); net_mgmt_add_event_callback(&ail_net_event_connection_cb); - net_mgmt_init_event_callback(&ail_net_event_address_cb, ail_address_event_handler, - NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_ADDR_DEL | - NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IPV4_ADDR_DEL); - net_mgmt_add_event_callback(&ail_net_event_address_cb); + net_mgmt_init_event_callback(&ail_net_event_ipv6_addr_cb, ail_ipv6_address_event_handler, + NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_ADDR_DEL); + net_mgmt_add_event_callback(&ail_net_event_ipv6_addr_cb); #if defined(CONFIG_NET_IPV4) - net_mgmt_init_event_callback(&ail_net_event_ipv4_addr_add_cb, + net_mgmt_init_event_callback(&ail_net_event_ipv4_addr_cb, ail_ipv4_address_event_handler, NET_EVENT_IPV4_ADDR_ADD); - net_mgmt_add_event_callback(&ail_net_event_ipv4_addr_add_cb); + net_mgmt_add_event_callback(&ail_net_event_ipv4_addr_cb); #endif /* CONFIG_NET_IPV4 */ openthread_set_bbr_multicast_listener_cb(ot_bbr_multicast_listener_handler, (void *)ot_ctx); (void)infra_if_start_icmp6_listener(); From 245efb8ae0c3c0f3628411b2d994f21f6f5692bc Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 20 Oct 2025 14:45:03 +0200 Subject: [PATCH 309/397] scripts: west_commands: sign: Replace ToggleAction Replaces the custom ToggleAction with the argparse.BooleanOptionalAction. Signed-off-by: Pieter De Gendt --- scripts/west_commands/sign.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index c6fa273138e5a..c2416f3d4b300 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -101,12 +101,6 @@ [1]: https://www.silabs.com/documents/public/user-guides/ug574-siwx917-soc-manufacturing-utility-user-guide.pdf ''' -class ToggleAction(argparse.Action): - - def __call__(self, parser, args, ignored, option): - setattr(args, self.dest, not option.startswith('--no-')) - - class Sign(Forceable): def __init__(self): super(Sign, self).__init__( @@ -147,8 +141,7 @@ def do_add_parser(self, parser_adder): # bin file options group = parser.add_argument_group('binary (.bin) file options') - group.add_argument('--bin', '--no-bin', dest='gen_bin', nargs=0, - action=ToggleAction, + group.add_argument('--bin', dest='gen_bin', action=argparse.BooleanOptionalAction, help='''produce a signed .bin file? (default: yes, if supported and unsigned bin exists)''') @@ -159,8 +152,7 @@ def do_add_parser(self, parser_adder): # hex file options group = parser.add_argument_group('Intel HEX (.hex) file options') - group.add_argument('--hex', '--no-hex', dest='gen_hex', nargs=0, - action=ToggleAction, + group.add_argument('--hex', dest='gen_hex', action=argparse.BooleanOptionalAction, help='''produce a signed .hex file? (default: yes, if supported and unsigned hex exists)''') From 7aa8356776ba7d7167ba3ee8b30e82dfe51b4a37 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 20 Oct 2025 14:46:16 +0200 Subject: [PATCH 310/397] scripts: west_commands: runners: Replace ToggleAction Replaces the custom ToggleAction with the argparse.BooleanOptionalAction. Signed-off-by: Pieter De Gendt --- scripts/west_commands/runners/canopen_program.py | 9 +-------- scripts/west_commands/runners/core.py | 11 ++--------- scripts/west_commands/runners/jlink.py | 11 ++--------- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/scripts/west_commands/runners/canopen_program.py b/scripts/west_commands/runners/canopen_program.py index e72b1dbbd6655..a53e05a8e5f71 100644 --- a/scripts/west_commands/runners/canopen_program.py +++ b/scripts/west_commands/runners/canopen_program.py @@ -44,11 +44,6 @@ PROGRAM_CTRL_CLEAR = 0x03 PROGRAM_CTRL_ZEPHYR_CONFIRM = 0x80 -class ToggleAction(argparse.Action): - '''Toggle argument parser''' - def __call__(self, parser, namespace, values, option_string=None): - setattr(namespace, self.dest, not option_string.startswith('--no-')) - class CANopenBinaryRunner(ZephyrBinaryRunner): '''Runner front-end for CANopen.''' def __init__(self, cfg, dev_id, can_context=DEFAULT_CAN_CONTEXT, @@ -99,9 +94,7 @@ def do_add_parser(cls, parser): help=f'Python-CAN context to use (default: {DEFAULT_CAN_CONTEXT})') parser.add_argument('--program-number', type=int, default=DEFAULT_PROGRAM_NUMBER, help=f'program number (default: {DEFAULT_PROGRAM_NUMBER})') - parser.add_argument('--confirm', '--no-confirm', - dest='confirm', nargs=0, - action=ToggleAction, + parser.add_argument('--confirm', action=argparse.BooleanOptionalAction, help='confirm after starting? (default: yes)') parser.add_argument('--confirm-only', default=False, action='store_true', help='confirm only, no program download (default: no)') diff --git a/scripts/west_commands/runners/core.py b/scripts/west_commands/runners/core.py index 611848f671cd9..c391788eed3a2 100644 --- a/scripts/west_commands/runners/core.py +++ b/scripts/west_commands/runners/core.py @@ -377,11 +377,6 @@ def __call__(self, parser, namespace, values, option_string=None): namespace.dt_flash = False -class _ToggleAction(argparse.Action): - - def __call__(self, parser, args, ignored, option): - setattr(args, self.dest, not option.startswith('--no-')) - class DeprecatedAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): @@ -610,14 +605,12 @@ def add_parser(cls, parser): help='path to zephyr.mot' if not caps.file else 'Deprecated, use -f/--file instead.') - parser.add_argument('--erase', '--no-erase', nargs=0, - action=_ToggleAction, + parser.add_argument('--erase', action=argparse.BooleanOptionalAction, help=("mass erase flash before loading, or don't. " "Default action depends on each specific runner." if caps.erase else argparse.SUPPRESS)) - parser.add_argument('--reset', '--no-reset', nargs=0, - action=_ToggleAction, + parser.add_argument('--reset', action=argparse.BooleanOptionalAction, help=("reset device after flashing, or don't. " "Default action depends on each specific runner." if caps.reset else argparse.SUPPRESS)) diff --git a/scripts/west_commands/runners/jlink.py b/scripts/west_commands/runners/jlink.py index 5fa13e19873e2..bb9426ceab86b 100644 --- a/scripts/west_commands/runners/jlink.py +++ b/scripts/west_commands/runners/jlink.py @@ -43,11 +43,6 @@ def is_ip(ip): def is_tunnel(tunnel): return tunnel.startswith("tunnel:") if tunnel else False -class ToggleAction(argparse.Action): - - def __call__(self, parser, args, ignored, option): - setattr(args, self.dest, not option.startswith('--no-')) - class JLinkBinaryRunner(ZephyrBinaryRunner): '''Runner front-end for the J-Link GDB server.''' @@ -194,10 +189,8 @@ def do_add_parser(cls, parser): parser.add_argument('--commander', default=DEFAULT_JLINK_EXE, help=f'''J-Link Commander, default is {DEFAULT_JLINK_EXE}''') - parser.add_argument('--reset-after-load', '--no-reset-after-load', - dest='reset', nargs=0, - action=ToggleAction, - help='obsolete synonym for --reset/--no-reset') + parser.add_argument('--reset-after-load', action=argparse.BooleanOptionalAction, + dest='reset', help='obsolete synonym for --reset/--no-reset') parser.add_argument('--rtt-client', default='JLinkRTTClient', help='RTT client, default is JLinkRTTClient') parser.add_argument('--rtt-port', default=DEFAULT_JLINK_RTT_PORT, From aa911607abb374ff1661c5e4751c93fd26b8e8d5 Mon Sep 17 00:00:00 2001 From: Arthur Gay Date: Mon, 18 Aug 2025 17:31:13 +0200 Subject: [PATCH 311/397] drivers: disk: sdmmc_stm32: Add API to retrieve SD card CSD register Introduce a new API function in the sdmmc_stm32 driver that allows applications to access the Card Specific Data (CSD) register of the SD/MMC card. This functionality, already available in the SPI-based SD and MMC subsystems, was previously missing from the STM32 SDMMC driver. This enhancement enables use cases such as verifying the correct SD card during manufacturing, ensuring that OEMs use the specified SD card, and preventing mismatches. Signed-off-by: Arthur Gay --- drivers/disk/sdmmc_stm32.c | 7 +++++++ include/zephyr/drivers/disk/sdmmc_stm32.h | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/disk/sdmmc_stm32.c b/drivers/disk/sdmmc_stm32.c index 38ae227de6117..d76dffad7eb40 100644 --- a/drivers/disk/sdmmc_stm32.c +++ b/drivers/disk/sdmmc_stm32.c @@ -907,6 +907,13 @@ void stm32_sdmmc_get_card_cid(const struct device *dev, uint32_t cid[4]) memcpy(cid, &priv->hsd.CID, sizeof(priv->hsd.CID)); } +void stm32_sdmmc_get_card_csd(const struct device *dev, uint32_t csd[4]) +{ + const struct stm32_sdmmc_priv *priv = dev->data; + + memcpy(csd, &priv->hsd.CSD, sizeof(priv->hsd.CSD)); +} + #if DT_NODE_HAS_STATUS_OKAY(DT_DRV_INST(0)) #if STM32_SDMMC_USE_DMA diff --git a/include/zephyr/drivers/disk/sdmmc_stm32.h b/include/zephyr/drivers/disk/sdmmc_stm32.h index ed132903d605a..2472aaf3aacc8 100644 --- a/include/zephyr/drivers/disk/sdmmc_stm32.h +++ b/include/zephyr/drivers/disk/sdmmc_stm32.h @@ -28,4 +28,22 @@ */ void stm32_sdmmc_get_card_cid(const struct device *dev, uint32_t cid[4]); +/** + * @brief Get the CSD (Card Specific Data) information from the SD/MMC card. + * + * This function copies the Card Specific Data (CSD) from the internal + * HAL SD/MMC struct populated during device initialization. It does not check + * the current presence or status of the card. If the card was removed after + * initialization (or initialization failed), the returned CSD may be stale or + * all zeroes. + * + * It is the caller's responsibility to verify that the card is present and + * initialized (e.g., by calling @ref disk_access_status) before invoking this + * function. + * + * @param dev Pointer to the device structure representing the SD/MMC card. + * @param csd Pointer to an array where the CSD data will be stored. + */ +void stm32_sdmmc_get_card_csd(const struct device *dev, uint32_t csd[4]); + #endif /* ZEPHYR_INCLUDE_DRIVERS_DISK_SDMMC_STM32_H_ */ From aca89cc17df87f4daa55b443b66fbe96b073ca44 Mon Sep 17 00:00:00 2001 From: Allen Zhang Date: Mon, 20 Oct 2025 01:06:35 +0800 Subject: [PATCH 312/397] dts: mcxw23x: add OSTIMER and DMA support in dts add dts support for OSTIMER and DMA Signed-off-by: Allen Zhang --- dts/arm/nxp/nxp_mcxw23x_common.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dts/arm/nxp/nxp_mcxw23x_common.dtsi b/dts/arm/nxp/nxp_mcxw23x_common.dtsi index ad4965464c264..d70b192daa574 100644 --- a/dts/arm/nxp/nxp_mcxw23x_common.dtsi +++ b/dts/arm/nxp/nxp_mcxw23x_common.dtsi @@ -64,6 +64,10 @@ }; }; +&systick { + status = "disabled"; +}; + &peripheral { #address-cells = <1>; #size-cells = <1>; @@ -231,12 +235,21 @@ #pwm-cells = <3>; }; + os_timer: timers@2d000 { + compatible = "nxp,os-timer"; + reg = <0x2d000 0x1000>; + interrupts = <38 1>; + status = "disabled"; + }; + flexcomm0: flexcomm@86000 { compatible = "nxp,lpc-flexcomm"; reg = <0x86000 0x1000>; interrupts = <14 1>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; resets = <&reset NXP_SYSCON_RESET(1, 11)>; + dmas = <&dma0 4 &dma0 5>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -246,6 +259,8 @@ interrupts = <15 1>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; resets = <&reset NXP_SYSCON_RESET(1, 12)>; + dmas = <&dma0 6 &dma0 7>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -255,6 +270,8 @@ interrupts = <16 1>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; resets = <&reset NXP_SYSCON_RESET(1, 13)>; + dmas = <&dma0 8 &dma0 9>; + dma-names = "rx", "tx"; status = "disabled"; }; From 1da217eeaa44f1bfe21577845a9b99fc13bcf159 Mon Sep 17 00:00:00 2001 From: Allen Zhang Date: Mon, 20 Oct 2025 01:09:22 +0800 Subject: [PATCH 313/397] soc: mcxw: enable OSTIMER for MCXW2xx Enable OSTIMER for MCXW2XX Signed-off-by: Allen Zhang --- soc/nxp/mcx/mcxw/mcxw2xx/Kconfig.defconfig | 4 ++++ soc/nxp/mcx/mcxw/mcxw2xx/soc.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/soc/nxp/mcx/mcxw/mcxw2xx/Kconfig.defconfig b/soc/nxp/mcx/mcxw/mcxw2xx/Kconfig.defconfig index ecf76e22c7157..3b260c2abb4fd 100644 --- a/soc/nxp/mcx/mcxw/mcxw2xx/Kconfig.defconfig +++ b/soc/nxp/mcx/mcxw/mcxw2xx/Kconfig.defconfig @@ -4,12 +4,16 @@ if SOC_SERIES_MCXW2XX +config CORTEX_M_SYSTICK + default n if MCUX_OS_TIMER + config NUM_IRQS default 63 DT_SYSCLK_PATH := $(dt_nodelabel_path,sysclk) config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 if MCUX_OS_TIMER default $(dt_node_int_prop_int,$(DT_SYSCLK_PATH),clock-frequency) if CORTEX_M_SYSTICK # Set to the minimal size of data which can be written. diff --git a/soc/nxp/mcx/mcxw/mcxw2xx/soc.c b/soc/nxp/mcx/mcxw/mcxw2xx/soc.c index 8e91dcec8338b..5e57268f2e040 100644 --- a/soc/nxp/mcx/mcxw/mcxw2xx/soc.c +++ b/soc/nxp/mcx/mcxw/mcxw2xx/soc.c @@ -96,6 +96,12 @@ __weak void clock_init(void) DT_FOREACH_STATUS_OKAY(nxp_ctimer_pwm, CTIMER_CLOCK_SETUP) configure_32k_osc(); + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(os_timer), nxp_os_timer, okay) + /*!< OS event timer select FRO 1 MHz clock */ + PMC->OSTIMERr &= ~PMC_OSTIMER_OSTIMERCLKSEL_MASK; + PMC->OSTIMERr |= OSTIMERCLKSEL_FRO_1MHz << PMC_OSTIMER_OSTIMERCLKSEL_SHIFT; +#endif } #ifdef CONFIG_SOC_RESET_HOOK From 0b2e0531d625b8d2be01686a386b15528ac28286 Mon Sep 17 00:00:00 2001 From: Allen Zhang Date: Mon, 20 Oct 2025 01:12:00 +0800 Subject: [PATCH 314/397] boards: mcxw23: Add support for OSTIMER, SPI and DMA Enable board support for OSTIMER, SPI and DMA Signed-off-by: Allen Zhang --- .../nxp/frdm_mcxw23/frdm_mcxw23-pinctrl.dtsi | 10 +++++++ boards/nxp/frdm_mcxw23/frdm_mcxw23.yaml | 2 ++ .../nxp/frdm_mcxw23/frdm_mcxw23_common.dtsi | 26 ++++++++++++++++- boards/nxp/frdm_mcxw23/pre_dt_board.cmake | 5 ++++ boards/nxp/mcxw23_evk/mcxw23_evk-pinctrl.dtsi | 10 +++++++ boards/nxp/mcxw23_evk/mcxw23_evk.yaml | 2 ++ boards/nxp/mcxw23_evk/mcxw23_evk_common.dtsi | 28 +++++++++++++++++-- boards/nxp/mcxw23_evk/pre_dt_board.cmake | 5 ++++ .../mcux/mcux-sdk-ng/drivers/drivers.cmake | 2 +- 9 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 boards/nxp/frdm_mcxw23/pre_dt_board.cmake create mode 100644 boards/nxp/mcxw23_evk/pre_dt_board.cmake diff --git a/boards/nxp/frdm_mcxw23/frdm_mcxw23-pinctrl.dtsi b/boards/nxp/frdm_mcxw23/frdm_mcxw23-pinctrl.dtsi index 4b1467fba11d2..d0a0ecd98c862 100644 --- a/boards/nxp/frdm_mcxw23/frdm_mcxw23-pinctrl.dtsi +++ b/boards/nxp/frdm_mcxw23/frdm_mcxw23-pinctrl.dtsi @@ -26,6 +26,16 @@ }; }; + pinmux_flexcomm2_spi: pinmux_flexcomm2_spi { + group0 { + pinmux = , + , + , + ; + slew-rate = "standard"; + }; + }; + pinmux_sctimer_default: pinmux_sctimer_default { group0 { pinmux = ; diff --git a/boards/nxp/frdm_mcxw23/frdm_mcxw23.yaml b/boards/nxp/frdm_mcxw23/frdm_mcxw23.yaml index c7154b8d88732..b979d8ff8cff9 100644 --- a/boards/nxp/frdm_mcxw23/frdm_mcxw23.yaml +++ b/boards/nxp/frdm_mcxw23/frdm_mcxw23.yaml @@ -22,4 +22,6 @@ supported: - i2c - watchdog - pwm + - spi + - dma vendor: nxp diff --git a/boards/nxp/frdm_mcxw23/frdm_mcxw23_common.dtsi b/boards/nxp/frdm_mcxw23/frdm_mcxw23_common.dtsi index 640a888650207..e7065d363b254 100644 --- a/boards/nxp/frdm_mcxw23/frdm_mcxw23_common.dtsi +++ b/boards/nxp/frdm_mcxw23/frdm_mcxw23_common.dtsi @@ -176,6 +176,15 @@ pinctrl-names = "default"; }; +/* + * MCXW23 FRDM board uses OS timer as the kernel timer + * In case we need to switch to SYSTICK timer, then + * replace &os_timer with &systick + */ +&os_timer { + status = "okay"; +}; + &wwdt0 { status = "okay"; }; @@ -188,6 +197,14 @@ status = "okay"; }; +&dma0 { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; @@ -218,7 +235,14 @@ arduino_i2c: &flexcomm1 {}; -arduino_spi: &flexcomm2 {}; +arduino_spi: &flexcomm2 { + status = "okay"; + compatible = "nxp,lpc-spi"; + pinctrl-0 = <&pinmux_flexcomm2_spi>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; +}; mikrobus_i2c: &flexcomm1 {}; diff --git a/boards/nxp/frdm_mcxw23/pre_dt_board.cmake b/boards/nxp/frdm_mcxw23/pre_dt_board.cmake new file mode 100644 index 0000000000000..29bf157c1b597 --- /dev/null +++ b/boards/nxp/frdm_mcxw23/pre_dt_board.cmake @@ -0,0 +1,5 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "spi_bus_bridge" as flexcomm node can be used as a SPI device. +list(APPEND EXTRA_DTC_FLAGS "-Wno-spi_bus_bridge") diff --git a/boards/nxp/mcxw23_evk/mcxw23_evk-pinctrl.dtsi b/boards/nxp/mcxw23_evk/mcxw23_evk-pinctrl.dtsi index 4b1467fba11d2..d0a0ecd98c862 100644 --- a/boards/nxp/mcxw23_evk/mcxw23_evk-pinctrl.dtsi +++ b/boards/nxp/mcxw23_evk/mcxw23_evk-pinctrl.dtsi @@ -26,6 +26,16 @@ }; }; + pinmux_flexcomm2_spi: pinmux_flexcomm2_spi { + group0 { + pinmux = , + , + , + ; + slew-rate = "standard"; + }; + }; + pinmux_sctimer_default: pinmux_sctimer_default { group0 { pinmux = ; diff --git a/boards/nxp/mcxw23_evk/mcxw23_evk.yaml b/boards/nxp/mcxw23_evk/mcxw23_evk.yaml index a137a9558c7d1..d3c5f6ffac817 100644 --- a/boards/nxp/mcxw23_evk/mcxw23_evk.yaml +++ b/boards/nxp/mcxw23_evk/mcxw23_evk.yaml @@ -22,4 +22,6 @@ supported: - i2c - watchdog - pwm + - spi + - dma vendor: nxp diff --git a/boards/nxp/mcxw23_evk/mcxw23_evk_common.dtsi b/boards/nxp/mcxw23_evk/mcxw23_evk_common.dtsi index 09c1ac9d29e0d..7cdc1103826a0 100644 --- a/boards/nxp/mcxw23_evk/mcxw23_evk_common.dtsi +++ b/boards/nxp/mcxw23_evk/mcxw23_evk_common.dtsi @@ -156,6 +156,15 @@ pinctrl-names = "default"; }; +/* + * MCXW23 EVK board uses OS timer as the kernel timer + * In case we need to switch to SYSTICK timer, then + * replace &os_timer with &systick + */ +&os_timer { + status = "okay"; +}; + &wwdt0 { status = "okay"; }; @@ -168,6 +177,14 @@ status = "okay"; }; +&dma0 { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; @@ -198,8 +215,13 @@ arduino_i2c: &flexcomm0 {}; -arduino_spi: &flexcomm0 {}; - mikrobus_i2c: &flexcomm0 {}; -mikrobus_spi: &flexcomm0 {}; +mikrobus_spi: &flexcomm2 { + status = "okay"; + compatible = "nxp,lpc-spi"; + pinctrl-0 = <&pinmux_flexcomm2_spi>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/boards/nxp/mcxw23_evk/pre_dt_board.cmake b/boards/nxp/mcxw23_evk/pre_dt_board.cmake new file mode 100644 index 0000000000000..29bf157c1b597 --- /dev/null +++ b/boards/nxp/mcxw23_evk/pre_dt_board.cmake @@ -0,0 +1,5 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Suppress "spi_bus_bridge" as flexcomm node can be used as a SPI device. +list(APPEND EXTRA_DTC_FLAGS "-Wno-spi_bus_bridge") diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index 3d6f4879362d6..338326f1b7d82 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -228,7 +228,7 @@ if(CONFIG_SOC_MCXW716C OR CONFIG_SOC_MCXW727C OR CONFIG_SOC_MCXN947 OR CONFIG_SO set_variable_ifdef(CONFIG_SOC_FLASH_MCUX CONFIG_MCUX_COMPONENT_driver.flash_k4) endif() -if(CONFIG_SOC_FAMILY_MCXW OR CONFIG_SOC_MCXN547) +if(CONFIG_SOC_MCXW716C OR CONFIG_SOC_MCXW727C OR CONFIG_SOC_MCXN547) if(CONFIG_DMA) zephyr_include_directories(${MCUX_SDK_NG_DIR}/drivers/trgmux) set_variable_ifdef(CONFIG_MBOX_NXP_IMX_MU CONFIG_MCUX_COMPONENT_driver.mu) From 4573b3b3d828ebc8d5c848482a2cf65d0b0a47aa Mon Sep 17 00:00:00 2001 From: Allen Zhang Date: Mon, 20 Oct 2025 01:13:45 +0800 Subject: [PATCH 315/397] tests: drivers: spi: add overlay and conf file to run test on MCXW23 boards Support spi_loopback example for frdm_mcxw23 and mcxw23_evk boards. Test using tests/drivers/spi/spi_loopback. Signed-off-by: Allen Zhang --- .../spi/spi_loopback/boards/frdm_mcxw23.conf | 4 ++++ .../spi_loopback/boards/frdm_mcxw23.overlay | 19 +++++++++++++++++++ .../spi/spi_loopback/boards/mcxw23_evk.conf | 4 ++++ .../spi_loopback/boards/mcxw23_evk.overlay | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/mcxw23_evk.conf create mode 100644 tests/drivers/spi/spi_loopback/boards/mcxw23_evk.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.conf b/tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.conf new file mode 100644 index 0000000000000..0eabab226f59d --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.conf @@ -0,0 +1,4 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SPI_IDEAL_TRANSFER_DURATION_SCALING=9 diff --git a/tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.overlay b/tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.overlay new file mode 100644 index 0000000000000..8a261240b963d --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/frdm_mcxw23.overlay @@ -0,0 +1,19 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Connect J2 pins 6-7 */ +&flexcomm2 { + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = <500000>; + }; + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = <16000000>; + }; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/mcxw23_evk.conf b/tests/drivers/spi/spi_loopback/boards/mcxw23_evk.conf new file mode 100644 index 0000000000000..0eabab226f59d --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/mcxw23_evk.conf @@ -0,0 +1,4 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SPI_IDEAL_TRANSFER_DURATION_SCALING=9 diff --git a/tests/drivers/spi/spi_loopback/boards/mcxw23_evk.overlay b/tests/drivers/spi/spi_loopback/boards/mcxw23_evk.overlay new file mode 100644 index 0000000000000..6f29649b8fe39 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/mcxw23_evk.overlay @@ -0,0 +1,19 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Connect J21 pins 3-4 */ +&flexcomm2 { + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = <500000>; + }; + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = <16000000>; + }; +}; From d38c51dc308bef8730074345c2556367e8313bbe Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Mon, 20 Oct 2025 19:18:48 +0200 Subject: [PATCH 316/397] net: tc_mapping: Use preprocessor Avoid token pasting and use preprocessor more for additional flexibility. Signed-off-by: Cla Mattia Galliard --- subsys/net/ip/net_tc.c | 4 + subsys/net/ip/net_tc_mapping.h | 174 ++++++++++++++------------------- 2 files changed, 79 insertions(+), 99 deletions(-) diff --git a/subsys/net/ip/net_tc.c b/subsys/net/ip/net_tc.c index c38004532619d..b9536fcdcd115 100644 --- a/subsys/net/ip/net_tc.c +++ b/subsys/net/ip/net_tc.c @@ -120,6 +120,8 @@ enum net_verdict net_tc_submit_to_rx_queue(uint8_t tc, struct net_pkt *pkt) int net_tx_priority2tc(enum net_priority prio) { #if NET_TC_TX_COUNT > 0 + static const uint8_t tx_prio2tc_map[] = PRIORITY2TC_TX; + if (prio > NET_PRIORITY_NC) { /* Use default value suggested in 802.1Q */ prio = NET_PRIORITY_BE; @@ -136,6 +138,8 @@ int net_tx_priority2tc(enum net_priority prio) int net_rx_priority2tc(enum net_priority prio) { #if NET_TC_RX_COUNT > 0 + static const uint8_t rx_prio2tc_map[] = PRIORITY2TC_RX; + if (prio > NET_PRIORITY_NC) { /* Use default value suggested in 802.1Q */ prio = NET_PRIORITY_BE; diff --git a/subsys/net/ip/net_tc_mapping.h b/subsys/net/ip/net_tc_mapping.h index c5ac0febbeed9..343269b2fe242 100644 --- a/subsys/net/ip/net_tc_mapping.h +++ b/subsys/net/ip/net_tc_mapping.h @@ -13,7 +13,7 @@ #ifndef __TC_MAPPING_H #define __TC_MAPPING_H -#include +#include "zephyr/net/net_core.h" /* All the maps below use priorities and indexes, below is the list of them * according to 802.1Q - table I-2. @@ -29,122 +29,98 @@ * 7 (highest) NC Network control */ -/* Helper macros used to generate the map to use */ -#define PRIORITY2TC_GEN_INNER(TYPE, COUNT) priority2tc_ ## TYPE ## _ ## COUNT -#define PRIORITY2TC_GEN(TYPE, COUNT) PRIORITY2TC_GEN_INNER(TYPE, COUNT) - -#if defined(CONFIG_NET_TC_MAPPING_STRICT) && (NET_TC_COUNT > 0) /* This is the recommended priority to traffic class mapping for * implementations that do not support the credit-based shaper transmission * selection algorithm. * Ref: 802.1Q - chapter 8.6.6 - table 8-4 */ +#if defined(CONFIG_NET_TC_MAPPING_STRICT) +#define PRIORITY2TC_1 {0, 0, 0, 0, 0, 0, 0, 0} +#define PRIORITY2TC_2 {0, 0, 0, 0, 1, 1, 1, 1} +#define PRIORITY2TC_3 {0, 0, 0, 0, 1, 1, 2, 2} +#define PRIORITY2TC_4 {0, 0, 1, 1, 2, 2, 3, 3} +#define PRIORITY2TC_5 {0, 0, 1, 1, 2, 2, 3, 4} +#define PRIORITY2TC_6 {1, 0, 2, 2, 3, 3, 4, 5} +#define PRIORITY2TC_7 {1, 0, 2, 3, 4, 4, 5, 6} +#define PRIORITY2TC_8 {1, 0, 2, 3, 4, 5, 6, 7} -#if NET_TC_TX_COUNT == 1 || NET_TC_RX_COUNT == 1 -static const uint8_t priority2tc_strict_1[] = {0, 0, 0, 0, 0, 0, 0, 0}; -#endif -#if NET_TC_TX_COUNT == 2 || NET_TC_RX_COUNT == 2 -static const uint8_t priority2tc_strict_2[] = {0, 0, 0, 0, 1, 1, 1, 1}; -#endif -#if NET_TC_TX_COUNT == 3 || NET_TC_RX_COUNT == 3 -static const uint8_t priority2tc_strict_3[] = {0, 0, 0, 0, 1, 1, 2, 2}; -#endif -#if NET_TC_TX_COUNT == 4 || NET_TC_RX_COUNT == 4 -static const uint8_t priority2tc_strict_4[] = {0, 0, 1, 1, 2, 2, 3, 3}; -#endif -#if NET_TC_TX_COUNT == 5 || NET_TC_RX_COUNT == 5 -static const uint8_t priority2tc_strict_5[] = {0, 0, 1, 1, 2, 2, 3, 4}; -#endif -#if NET_TC_TX_COUNT == 6 || NET_TC_RX_COUNT == 6 -static const uint8_t priority2tc_strict_6[] = {1, 0, 2, 2, 3, 3, 4, 5}; -#endif -#if NET_TC_TX_COUNT == 7 || NET_TC_RX_COUNT == 7 -static const uint8_t priority2tc_strict_7[] = {1, 0, 2, 3, 4, 4, 5, 6}; -#endif -#if NET_TC_TX_COUNT == 8 || NET_TC_RX_COUNT == 8 -static const uint8_t priority2tc_strict_8[] = {1, 0, 2, 3, 4, 5, 6, 7}; -#endif - -#if NET_TC_TX_COUNT > 0 -static const uint8_t *tx_prio2tc_map = PRIORITY2TC_GEN(strict, NET_TC_TX_COUNT); -#endif -#if NET_TC_RX_COUNT > 0 -static const uint8_t *rx_prio2tc_map = PRIORITY2TC_GEN(strict, NET_TC_RX_COUNT); -#endif - -#elif defined(CONFIG_NET_TC_MAPPING_SR_CLASS_A_AND_B) && (NET_TC_COUNT > 0) /* This is the recommended priority to traffic class mapping for a system that * supports SR (Stream Reservation) class A and SR class B. * Ref: 802.1Q - chapter 34.5 - table 34-1 */ +#elif defined(CONFIG_NET_TC_MAPPING_SR_CLASS_A_AND_B) +#define PRIORITY2TC_1 {0, 0, 0, 0, 0, 0, 0, 0} +#define PRIORITY2TC_2 {0, 0, 1, 1, 0, 0, 0, 0} +#define PRIORITY2TC_3 {0, 0, 1, 2, 0, 0, 0, 0} +#define PRIORITY2TC_4 {0, 0, 2, 3, 1, 1, 1, 1} +#define PRIORITY2TC_5 {0, 0, 3, 4, 1, 1, 2, 2} +#define PRIORITY2TC_6 {0, 0, 4, 5, 1, 1, 2, 3} +#define PRIORITY2TC_7 {0, 0, 5, 6, 1, 2, 3, 4} +#define PRIORITY2TC_8 {1, 0, 6, 7, 2, 3, 4, 5} -#if NET_TC_TX_COUNT == 2 || NET_TC_RX_COUNT == 2 -static const uint8_t priority2tc_sr_ab_2[] = {0, 0, 1, 1, 0, 0, 0, 0}; -#endif -#if NET_TC_TX_COUNT == 3 || NET_TC_RX_COUNT == 3 -static const uint8_t priority2tc_sr_ab_3[] = {0, 0, 1, 2, 0, 0, 0, 0}; -#endif -#if NET_TC_TX_COUNT == 4 || NET_TC_RX_COUNT == 4 -static const uint8_t priority2tc_sr_ab_4[] = {0, 0, 2, 3, 1, 1, 1, 1}; -#endif -#if NET_TC_TX_COUNT == 5 || NET_TC_RX_COUNT == 5 -static const uint8_t priority2tc_sr_ab_5[] = {0, 0, 3, 4, 1, 1, 2, 2}; -#endif -#if NET_TC_TX_COUNT == 6 || NET_TC_RX_COUNT == 6 -static const uint8_t priority2tc_sr_ab_6[] = {0, 0, 4, 5, 1, 1, 2, 3}; -#endif -#if NET_TC_TX_COUNT == 7 || NET_TC_RX_COUNT == 7 -static const uint8_t priority2tc_sr_ab_7[] = {0, 0, 5, 6, 1, 2, 3, 4}; -#endif -#if NET_TC_TX_COUNT == 8 || NET_TC_RX_COUNT == 8 -static const uint8_t priority2tc_sr_ab_8[] = {1, 0, 6, 7, 2, 3, 4, 5}; -#endif - -#if NET_TC_TX_COUNT > 0 -static const uint8_t *tx_prio2tc_map = PRIORITY2TC_GEN(sr_ab, NET_TC_TX_COUNT); -#endif -#if NET_TC_RX_COUNT > 0 -static const uint8_t *rx_prio2tc_map = PRIORITY2TC_GEN(sr_ab, NET_TC_RX_COUNT); -#endif - -#elif defined(CONFIG_NET_TC_MAPPING_SR_CLASS_B_ONLY) && (NET_TC_COUNT > 0) /* This is the recommended priority to traffic class mapping for a system that * supports SR (Stream Reservation) class B only. * Ref: 802.1Q - chapter 34.5 - table 34-2 */ - -#if NET_TC_TX_COUNT == 2 || NET_TC_RX_COUNT == 2 -static const uint8_t priority2tc_sr_b_2[] = {0, 0, 1, 0, 0, 0, 0, 0}; -#endif -#if NET_TC_TX_COUNT == 3 || NET_TC_RX_COUNT == 3 -static const uint8_t priority2tc_sr_b_3[] = {0, 0, 2, 0, 1, 1, 1, 1}; -#endif -#if NET_TC_TX_COUNT == 4 || NET_TC_RX_COUNT == 4 -static const uint8_t priority2tc_sr_b_4[] = {0, 0, 3, 0, 1, 1, 2, 2}; -#endif -#if NET_TC_TX_COUNT == 5 || NET_TC_RX_COUNT == 5 -static const uint8_t priority2tc_sr_b_5[] = {0, 0, 4, 1, 2, 2, 3, 3}; -#endif -#if NET_TC_TX_COUNT == 6 || NET_TC_RX_COUNT == 6 -static const uint8_t priority2tc_sr_b_6[] = {0, 0, 5, 1, 2, 2, 3, 4}; -#endif -#if NET_TC_TX_COUNT == 7 || NET_TC_RX_COUNT == 7 -static const uint8_t priority2tc_sr_b_7[] = {1, 0, 6, 2, 3, 3, 4, 5}; -#endif -#if NET_TC_TX_COUNT == 8 || NET_TC_RX_COUNT == 8 -static const uint8_t priority2tc_sr_b_8[] = {1, 0, 7, 2, 3, 4, 5, 6}; -#endif - -#if NET_TC_TX_COUNT > 0 -static const uint8_t *tx_prio2tc_map = PRIORITY2TC_GEN(sr_b, NET_TC_TX_COUNT); -#endif -#if NET_TC_RX_COUNT > 0 -static const uint8_t *rx_prio2tc_map = PRIORITY2TC_GEN(sr_b, NET_TC_RX_COUNT); -#endif - +#elif defined(CONFIG_NET_TC_MAPPING_SR_CLASS_B_ONLY) +#define PRIORITY2TC_1 {0, 0, 0, 0, 0, 0, 0, 0} +#define PRIORITY2TC_2 {0, 0, 1, 0, 0, 0, 0, 0} +#define PRIORITY2TC_3 {0, 0, 2, 0, 1, 1, 1, 1} +#define PRIORITY2TC_4 {0, 0, 3, 0, 1, 1, 2, 2} +#define PRIORITY2TC_5 {0, 0, 4, 1, 2, 2, 3, 3} +#define PRIORITY2TC_6 {0, 0, 5, 1, 2, 2, 3, 4} +#define PRIORITY2TC_7 {1, 0, 6, 2, 3, 3, 4, 5} +#define PRIORITY2TC_8 {1, 0, 7, 2, 3, 4, 5, 6} +#endif + + +#if NET_TC_TX_COUNT == 0 +#elif NET_TC_TX_COUNT == 1 +#define PRIORITY2TC_TX PRIORITY2TC_1 +#elif NET_TC_TX_COUNT == 2 +#define PRIORITY2TC_TX PRIORITY2TC_2 +#elif NET_TC_TX_COUNT == 3 +#define PRIORITY2TC_TX PRIORITY2TC_3 +#elif NET_TC_TX_COUNT == 4 +#define PRIORITY2TC_TX PRIORITY2TC_4 +#elif NET_TC_TX_COUNT == 5 +#define PRIORITY2TC_TX PRIORITY2TC_5 +#elif NET_TC_TX_COUNT == 6 +#define PRIORITY2TC_TX PRIORITY2TC_6 +#elif NET_TC_TX_COUNT == 7 +#define PRIORITY2TC_TX PRIORITY2TC_7 +#elif NET_TC_TX_COUNT == 8 +#define PRIORITY2TC_TX PRIORITY2TC_8 +#else +BUILD_ASSERT(false, "Too many effective tx traffic class queues, either reduce " + "CONFIG_NET_TC_TX_COUNT or disable " + "CONFIG_NET_TC_TX_SKIP_FOR_HIGH_PRIO"); +#endif + +#if NET_TC_RX_COUNT == 0 +#elif NET_TC_RX_COUNT == 1 +#define PRIORITY2TC_RX PRIORITY2TC_1 +#elif NET_TC_RX_COUNT == 2 +#define PRIORITY2TC_RX PRIORITY2TC_2 +#elif NET_TC_RX_COUNT == 3 +#define PRIORITY2TC_RX PRIORITY2TC_3 +#elif NET_TC_RX_COUNT == 4 +#define PRIORITY2TC_RX PRIORITY2TC_4 +#elif NET_TC_RX_COUNT == 5 +#define PRIORITY2TC_RX PRIORITY2TC_5 +#elif NET_TC_RX_COUNT == 6 +#define PRIORITY2TC_RX PRIORITY2TC_6 +#elif NET_TC_RX_COUNT == 7 +#define PRIORITY2TC_RX PRIORITY2TC_7 +#elif NET_TC_RX_COUNT == 8 +#define PRIORITY2TC_RX PRIORITY2TC_8 +#else +BUILD_ASSERT(false, "Too many effective rx traffic class queues, either reduce " + "CONFIG_NET_TC_RX_COUNT or disable " + "CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO"); #endif #endif /* __TC_MAPPING_H */ From 41768689ba3b13257550a9b9e05201efd30e9729 Mon Sep 17 00:00:00 2001 From: Cla Mattia Galliard Date: Sun, 19 Oct 2025 21:03:59 +0200 Subject: [PATCH 317/397] net: tc-mapping: Fix SKIP_FOR_HIGH_PRIO Adjust the way the SKIP option worked. Before this patch, a constant priority offset was considered "high priority" this had the effect, that the threads assigned to work on the priority were effectively usesless. To fix it, consider this immediate handling as a pseudo-queue and compute the tc-thead-mapping based on the effective count (+1 if skipping is enabled). This makes it so that all threads are usefull and the high-priority skip-path is considered as a pseudo tc-thread. Signed-off-by: Cla Mattia Galliard --- include/zephyr/net/net_core.h | 12 +++++++++++ subsys/net/ip/net_private.h | 9 +++++---- subsys/net/ip/net_tc.c | 5 ----- subsys/net/ip/net_tc_mapping.h | 37 +++++++++++++++++----------------- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/include/zephyr/net/net_core.h b/include/zephyr/net/net_core.h index 505683eb139b3..cedc2686ff7ec 100644 --- a/include/zephyr/net/net_core.h +++ b/include/zephyr/net/net_core.h @@ -181,6 +181,18 @@ static inline int net_send_data(struct net_pkt *pkt) #define NET_TC_COUNT 0 #endif /* CONFIG_NET_TC_TX_COUNT && CONFIG_NET_TC_RX_COUNT */ +#if CONFIG_NET_TC_TX_SKIP_FOR_HIGH_PRIO +#define NET_TC_TX_EFFECTIVE_COUNT (NET_TC_TX_COUNT + 1) +#else +#define NET_TC_TX_EFFECTIVE_COUNT NET_TC_TX_COUNT +#endif + +#if CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO +#define NET_TC_RX_EFFECTIVE_COUNT (NET_TC_RX_COUNT + 1) +#else +#define NET_TC_RX_EFFECTIVE_COUNT NET_TC_RX_COUNT +#endif + /** * @brief Registration information for a given L3 handler. Note that * the layer number (L3) just refers to something that is on top diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 7723365a71434..624f61d889349 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_NET_MGMT_EVENT_INFO @@ -212,8 +213,8 @@ extern int net_tc_tx_thread_priority(int tc); extern int net_tc_rx_thread_priority(int tc); static inline bool net_tc_tx_is_immediate(int tc, int prio) { - ARG_UNUSED(tc); - bool high_prio = (prio >= NET_PRIORITY_CA); + ARG_UNUSED(prio); + bool high_prio = (tc == NET_TC_TX_EFFECTIVE_COUNT - 1); bool skipping = IS_ENABLED(CONFIG_NET_TC_TX_SKIP_FOR_HIGH_PRIO); bool no_queues = (0 == NET_TC_TX_COUNT); @@ -221,8 +222,8 @@ static inline bool net_tc_tx_is_immediate(int tc, int prio) } static inline bool net_tc_rx_is_immediate(int tc, int prio) { - ARG_UNUSED(tc); - bool high_prio = (prio >= NET_PRIORITY_CA); + ARG_UNUSED(prio); + bool high_prio = (tc == NET_TC_RX_EFFECTIVE_COUNT - 1); bool skipping = IS_ENABLED(CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO); bool no_queues = (0 == NET_TC_RX_COUNT); diff --git a/subsys/net/ip/net_tc.c b/subsys/net/ip/net_tc.c index b9536fcdcd115..fad0150563aec 100644 --- a/subsys/net/ip/net_tc.c +++ b/subsys/net/ip/net_tc.c @@ -18,9 +18,6 @@ LOG_MODULE_REGISTER(net_tc, CONFIG_NET_TC_LOG_LEVEL); #include "net_stats.h" #include "net_tc_mapping.h" -#define TC_RX_PSEUDO_QUEUE (COND_CODE_1(CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO, (1), (0))) -#define NET_TC_RX_EFFECTIVE_COUNT (NET_TC_RX_COUNT + TC_RX_PSEUDO_QUEUE) - #if NET_TC_RX_EFFECTIVE_COUNT > 1 #define NET_TC_RX_SLOTS (CONFIG_NET_PKT_RX_COUNT / NET_TC_RX_EFFECTIVE_COUNT) BUILD_ASSERT(NET_TC_RX_SLOTS > 0, @@ -29,8 +26,6 @@ BUILD_ASSERT(NET_TC_RX_SLOTS > 0, "CONFIG_NET_TC_RX_COUNT or disable CONFIG_NET_TC_RX_SKIP_FOR_HIGH_PRIO"); #endif -#define TC_TX_PSEUDO_QUEUE (COND_CODE_1(CONFIG_NET_TC_TX_SKIP_FOR_HIGH_PRIO, (1), (0))) -#define NET_TC_TX_EFFECTIVE_COUNT (NET_TC_TX_COUNT + TC_TX_PSEUDO_QUEUE) #if NET_TC_TX_EFFECTIVE_COUNT > 1 #define NET_TC_TX_SLOTS (CONFIG_NET_PKT_TX_COUNT / NET_TC_TX_EFFECTIVE_COUNT) diff --git a/subsys/net/ip/net_tc_mapping.h b/subsys/net/ip/net_tc_mapping.h index 343269b2fe242..7fc53e4d97fdb 100644 --- a/subsys/net/ip/net_tc_mapping.h +++ b/subsys/net/ip/net_tc_mapping.h @@ -77,22 +77,22 @@ #endif -#if NET_TC_TX_COUNT == 0 -#elif NET_TC_TX_COUNT == 1 +#if NET_TC_TX_EFFECTIVE_COUNT == 0 +#elif NET_TC_TX_EFFECTIVE_COUNT == 1 #define PRIORITY2TC_TX PRIORITY2TC_1 -#elif NET_TC_TX_COUNT == 2 +#elif NET_TC_TX_EFFECTIVE_COUNT == 2 #define PRIORITY2TC_TX PRIORITY2TC_2 -#elif NET_TC_TX_COUNT == 3 +#elif NET_TC_TX_EFFECTIVE_COUNT == 3 #define PRIORITY2TC_TX PRIORITY2TC_3 -#elif NET_TC_TX_COUNT == 4 +#elif NET_TC_TX_EFFECTIVE_COUNT == 4 #define PRIORITY2TC_TX PRIORITY2TC_4 -#elif NET_TC_TX_COUNT == 5 +#elif NET_TC_TX_EFFECTIVE_COUNT == 5 #define PRIORITY2TC_TX PRIORITY2TC_5 -#elif NET_TC_TX_COUNT == 6 +#elif NET_TC_TX_EFFECTIVE_COUNT == 6 #define PRIORITY2TC_TX PRIORITY2TC_6 -#elif NET_TC_TX_COUNT == 7 +#elif NET_TC_TX_EFFECTIVE_COUNT == 7 #define PRIORITY2TC_TX PRIORITY2TC_7 -#elif NET_TC_TX_COUNT == 8 +#elif NET_TC_TX_EFFECTIVE_COUNT == 8 #define PRIORITY2TC_TX PRIORITY2TC_8 #else BUILD_ASSERT(false, "Too many effective tx traffic class queues, either reduce " @@ -100,22 +100,23 @@ BUILD_ASSERT(false, "Too many effective tx traffic class queues, either reduce " "CONFIG_NET_TC_TX_SKIP_FOR_HIGH_PRIO"); #endif -#if NET_TC_RX_COUNT == 0 -#elif NET_TC_RX_COUNT == 1 + +#if NET_TC_RX_EFFECTIVE_COUNT == 0 +#elif NET_TC_RX_EFFECTIVE_COUNT == 1 #define PRIORITY2TC_RX PRIORITY2TC_1 -#elif NET_TC_RX_COUNT == 2 +#elif NET_TC_RX_EFFECTIVE_COUNT == 2 #define PRIORITY2TC_RX PRIORITY2TC_2 -#elif NET_TC_RX_COUNT == 3 +#elif NET_TC_RX_EFFECTIVE_COUNT == 3 #define PRIORITY2TC_RX PRIORITY2TC_3 -#elif NET_TC_RX_COUNT == 4 +#elif NET_TC_RX_EFFECTIVE_COUNT == 4 #define PRIORITY2TC_RX PRIORITY2TC_4 -#elif NET_TC_RX_COUNT == 5 +#elif NET_TC_RX_EFFECTIVE_COUNT == 5 #define PRIORITY2TC_RX PRIORITY2TC_5 -#elif NET_TC_RX_COUNT == 6 +#elif NET_TC_RX_EFFECTIVE_COUNT == 6 #define PRIORITY2TC_RX PRIORITY2TC_6 -#elif NET_TC_RX_COUNT == 7 +#elif NET_TC_RX_EFFECTIVE_COUNT == 7 #define PRIORITY2TC_RX PRIORITY2TC_7 -#elif NET_TC_RX_COUNT == 8 +#elif NET_TC_RX_EFFECTIVE_COUNT == 8 #define PRIORITY2TC_RX PRIORITY2TC_8 #else BUILD_ASSERT(false, "Too many effective rx traffic class queues, either reduce " From 85794ff6b0156a3c3cb77a0ed65b1bcac4d651b8 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 22 Oct 2025 09:46:31 +0200 Subject: [PATCH 318/397] dts: arm: st: l5: add missing #address-cells in exti node Add missing #address-cells property in exti interrupt controller node. This change prevents build warning messages when using DTC v1.6.1. With former or later DTC versions, missing #address-cells property is ignored but it remains requires as per DT schemas, e.g. [1] Link: https://github.com/devicetree-org/dt-schema/blob/v2025.08/dtschema/schemas/interrupt-controller.yaml#L18 [1] Signed-off-by: Etienne Carriere --- dts/arm/st/l5/stm32l5.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index 778227d908fbc..e5dd9c38dbac1 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -171,6 +171,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; + #address-cells = <0>; reg = <0x4000f400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 0)>; num-lines = <64>; From 16930a51dcb114ad536eca2e77dbb688c5da553c Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 22 Oct 2025 09:46:47 +0200 Subject: [PATCH 319/397] dts: arm: st: wba: add missing #address-cells in exti node Add missing #address-cells property in exti interrupt controller node. This change prevents build warning messages when using DTC v1.6.1. With former or later DTC versions, missing #address-cells property is ignored but it remains requires as per DT schemas, e.g. [1] Link: https://github.com/devicetree-org/dt-schema/blob/v2025.08/dtschema/schemas/interrupt-controller.yaml#L18 [1] Signed-off-by: Etienne Carriere --- dts/arm/st/wba/stm32wba.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 2f04f92e671a5..f73f73c418788 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -226,6 +226,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; + #address-cells = <0>; reg = <0x46022000 0x400>; clocks = <&rcc STM32_CLOCK(APB7, 1)>; num-lines = <32>; From 8078d8067ecdf68141a62cf1d1c95f488c6e47ce Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 22 Oct 2025 10:08:06 +0200 Subject: [PATCH 320/397] dts: arm: st: correct exti #address-cells value Correct #address-cells property in exti interrupt controller nodes for STM32 SoCs that defined it to 1 whereas value 0 is more applicable as that interrupt does not expect sub-node nor interrupt mapping. No functional changes as the value is ignored. This change rather targets STM32 SoCs DTSI files consistency. Signed-off-by: Etienne Carriere --- dts/arm/st/c0/stm32c0.dtsi | 2 +- dts/arm/st/f0/stm32f0.dtsi | 2 +- dts/arm/st/f1/stm32f1.dtsi | 2 +- dts/arm/st/f2/stm32f2.dtsi | 2 +- dts/arm/st/f3/stm32f3.dtsi | 2 +- dts/arm/st/f4/stm32f4.dtsi | 2 +- dts/arm/st/f7/stm32f7.dtsi | 2 +- dts/arm/st/g0/stm32g0.dtsi | 2 +- dts/arm/st/g4/stm32g4.dtsi | 2 +- dts/arm/st/h5/stm32h5.dtsi | 2 +- dts/arm/st/h7/stm32h7.dtsi | 2 +- dts/arm/st/h7rs/stm32h7rs.dtsi | 2 +- dts/arm/st/l0/stm32l0.dtsi | 2 +- dts/arm/st/l1/stm32l1.dtsi | 2 +- dts/arm/st/l4/stm32l4.dtsi | 2 +- dts/arm/st/mp1/stm32mp157.dtsi | 2 +- dts/arm/st/mp13/stm32mp13.dtsi | 2 +- dts/arm/st/mp2/stm32mp2_m33.dtsi | 2 +- dts/arm/st/n6/stm32n6.dtsi | 2 +- dts/arm/st/u0/stm32u0.dtsi | 2 +- dts/arm/st/u3/stm32u3.dtsi | 2 +- dts/arm/st/u5/stm32u5.dtsi | 2 +- dts/arm/st/wb/stm32wb.dtsi | 2 +- dts/arm/st/wl/stm32wl.dtsi | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/dts/arm/st/c0/stm32c0.dtsi b/dts/arm/st/c0/stm32c0.dtsi index b60869063aca4..5941dace1b751 100644 --- a/dts/arm/st/c0/stm32c0.dtsi +++ b/dts/arm/st/c0/stm32c0.dtsi @@ -187,7 +187,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40021800 0x400>; clocks = <&rcc STM32_CLOCK(APB1_2, 0)>; num-lines = <32>; diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index 3df708cb32239..bc855c7a4581a 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -117,7 +117,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40010400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 0)>; num-lines = <32>; diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index 9c80be9ca8bc2..8f562d2f20277 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -137,7 +137,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40010400 0x400>; num-lines = <32>; interrupts = <6 0>, <7 0>, <8 0>, <9 0>, diff --git a/dts/arm/st/f2/stm32f2.dtsi b/dts/arm/st/f2/stm32f2.dtsi index 1c645d5a9d106..1cdf6ad01b41e 100644 --- a/dts/arm/st/f2/stm32f2.dtsi +++ b/dts/arm/st/f2/stm32f2.dtsi @@ -110,7 +110,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40013c00 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 14)>; num-lines = <32>; diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index 5c9fbd208354f..025db8459434d 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -111,7 +111,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40010400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 0)>; num-lines = <32>; diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index d341a521bcab3..1018c1eb74c71 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -141,7 +141,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40013c00 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 14)>; num-lines = <32>; diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index d2f8153068c3e..b203b93271127 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -155,7 +155,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40013c00 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 14)>; num-lines = <32>; diff --git a/dts/arm/st/g0/stm32g0.dtsi b/dts/arm/st/g0/stm32g0.dtsi index f3198a12335f3..28aec6252811b 100644 --- a/dts/arm/st/g0/stm32g0.dtsi +++ b/dts/arm/st/g0/stm32g0.dtsi @@ -145,7 +145,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40021800 0x400>; clocks = <&rcc STM32_CLOCK(APB1_2, 0)>; num-lines = <32>; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index acdbec7bf00ee..f8301c5283019 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -197,7 +197,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40010400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 0)>; num-lines = <64>; diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index a5ad1fb67a86b..25f1db85e8a31 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -163,7 +163,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x44022000 0x400>; clocks = <&rcc STM32_CLOCK(APB3, 1)>; num-lines = <64>; diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 6028d38755dd0..a4549f6ba024f 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -168,7 +168,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x58000000 0x400>; clocks = <&rcc STM32_CLOCK(APB4, 1)>; num-lines = <96>; diff --git a/dts/arm/st/h7rs/stm32h7rs.dtsi b/dts/arm/st/h7rs/stm32h7rs.dtsi index 94694138f1e98..8da85ea625c36 100644 --- a/dts/arm/st/h7rs/stm32h7rs.dtsi +++ b/dts/arm/st/h7rs/stm32h7rs.dtsi @@ -210,7 +210,7 @@ compatible = "st,stm32h7rs-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x58000000 0x400>; clocks = <&rcc STM32_CLOCK(APB4, 1)>; /* SBS for interrupt */ diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index 930c2548f9112..985de6324e0b0 100644 --- a/dts/arm/st/l0/stm32l0.dtsi +++ b/dts/arm/st/l0/stm32l0.dtsi @@ -145,7 +145,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40010400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 0)>; num-lines = <32>; diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index fd8ba55e993fd..92a32695fae5b 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -291,7 +291,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40010400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 0)>; num-lines = <32>; diff --git a/dts/arm/st/l4/stm32l4.dtsi b/dts/arm/st/l4/stm32l4.dtsi index 5dfd821112dcf..f1a87034f1817 100644 --- a/dts/arm/st/l4/stm32l4.dtsi +++ b/dts/arm/st/l4/stm32l4.dtsi @@ -159,7 +159,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40010400 0x400>; clocks = <&rcc STM32_CLOCK(APB2, 0)>; num-lines = <64>; diff --git a/dts/arm/st/mp1/stm32mp157.dtsi b/dts/arm/st/mp1/stm32mp157.dtsi index 76d506ddbc5b6..8ccd29f28a95a 100644 --- a/dts/arm/st/mp1/stm32mp157.dtsi +++ b/dts/arm/st/mp1/stm32mp157.dtsi @@ -70,7 +70,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x5000d000 0x400>; clocks = <&rcc STM32_CLOCK(APB3, 11)>; num-lines = <96>; diff --git a/dts/arm/st/mp13/stm32mp13.dtsi b/dts/arm/st/mp13/stm32mp13.dtsi index 60f69adb126fe..d9a4a8be9552c 100644 --- a/dts/arm/st/mp13/stm32mp13.dtsi +++ b/dts/arm/st/mp13/stm32mp13.dtsi @@ -152,7 +152,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x5000D000 0x400>; clocks = <&rcc STM32_CLOCK(APB3_S, 0)>; num-lines = <96>; diff --git a/dts/arm/st/mp2/stm32mp2_m33.dtsi b/dts/arm/st/mp2/stm32mp2_m33.dtsi index 9bf80bf93e4ac..711e62706f722 100644 --- a/dts/arm/st/mp2/stm32mp2_m33.dtsi +++ b/dts/arm/st/mp2/stm32mp2_m33.dtsi @@ -51,7 +51,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x46230000 DT_SIZE_K(1)>; num-lines = <77>; interrupts = <17 0>, <18 0>, <19 0>, <20 0>, diff --git a/dts/arm/st/n6/stm32n6.dtsi b/dts/arm/st/n6/stm32n6.dtsi index 537800433f05f..e3df2576ccfc8 100644 --- a/dts/arm/st/n6/stm32n6.dtsi +++ b/dts/arm/st/n6/stm32n6.dtsi @@ -312,7 +312,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x56025000 0x400>; clocks = <&rcc STM32_CLOCK(APB4_2, 0)>; num-lines = <96>; diff --git a/dts/arm/st/u0/stm32u0.dtsi b/dts/arm/st/u0/stm32u0.dtsi index ec036136807e8..54783cec47c0d 100644 --- a/dts/arm/st/u0/stm32u0.dtsi +++ b/dts/arm/st/u0/stm32u0.dtsi @@ -149,7 +149,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40021800 0x400>; clocks = <&rcc STM32_CLOCK(APB1_2, 0)>; num-lines = <32>; diff --git a/dts/arm/st/u3/stm32u3.dtsi b/dts/arm/st/u3/stm32u3.dtsi index 4439a20b35b3e..8318ac221d1e8 100644 --- a/dts/arm/st/u3/stm32u3.dtsi +++ b/dts/arm/st/u3/stm32u3.dtsi @@ -124,7 +124,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x40032000 0x400>; clocks = <&rcc STM32_CLOCK(APB3, 1)>; num-lines = <22>; diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 2b6e76e61cd26..5d6911698cd92 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -195,7 +195,7 @@ compatible = "st,stm32g0-exti", "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x46022000 0x400>; clocks = <&rcc STM32_CLOCK(APB3, 1)>; num-lines = <32>; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index d467cdcc332bb..a049374f7035a 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -179,7 +179,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x58000800 0x400>; num-lines = <64>; interrupts = <6 0>, <7 0>, <8 0>, <9 0>, diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index 1544e96369944..a81aa26db4492 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -151,7 +151,7 @@ compatible = "st,stm32-exti"; interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; + #address-cells = <0>; reg = <0x58000800 0x400>; clocks = <&rcc STM32_CLOCK(APB0, 8)>; num-lines = <64>; From 8c3ea2afe329336b1fe159a60b720d68af8c87fe Mon Sep 17 00:00:00 2001 From: Lei Xu Date: Mon, 7 Jul 2025 18:22:36 -0700 Subject: [PATCH 321/397] dts: arm64: imx9131: add USDHC device nodes Add device nodes for SDHC. Signed-off-by: Lei Xu Signed-off-by: Jiafei Pan --- dts/arm64/nxp/nxp_mimx9131.dtsi | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/dts/arm64/nxp/nxp_mimx9131.dtsi b/dts/arm64/nxp/nxp_mimx9131.dtsi index 5bb1e158401b5..37a0850b489e5 100644 --- a/dts/arm64/nxp/nxp_mimx9131.dtsi +++ b/dts/arm64/nxp/nxp_mimx9131.dtsi @@ -240,6 +240,32 @@ status = "disabled"; }; + usdhc1: usdhc@42850000 { + compatible = "nxp,imx-usdhc"; + reg = <0x42850000 0x10000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_USDHC1_CLK 0 0>; + max-current-330 = <1020>; + max-current-180 = <1020>; + max-bus-freq = <208000000>; + min-bus-freq = <400000>; + status = "disabled"; + }; + + usdhc2: usdhc@42860000 { + compatible = "nxp,imx-usdhc"; + reg = <0x42860000 0x10000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_USDHC2_CLK 0 0>; + max-current-330 = <1020>; + max-current-180 = <1020>; + max-bus-freq = <208000000>; + min-bus-freq = <400000>; + status = "disabled"; + }; + tpm1: tpm@44310000 { compatible = "nxp,tpm-timer"; reg = <0x44310000 DT_SIZE_K(64)>; From c2992fd5ce0eae9d0b19281375e814ef04de370c Mon Sep 17 00:00:00 2001 From: Lei Xu Date: Tue, 8 Jul 2025 00:29:32 -0700 Subject: [PATCH 322/397] soc: imx91: add empty soc.h Some drivers need header file soc.h, according to Zephyr SoC Porting Guide soc.h must be provided for each SoC, so created an empty one. Signed-off-by: Lei Xu Signed-off-by: Jiafei Pan --- soc/nxp/imx/imx9/imx91/soc.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 soc/nxp/imx/imx9/imx91/soc.h diff --git a/soc/nxp/imx/imx9/imx91/soc.h b/soc/nxp/imx/imx9/imx91/soc.h new file mode 100644 index 0000000000000..c899f64d7d525 --- /dev/null +++ b/soc/nxp/imx/imx9/imx91/soc.h @@ -0,0 +1,16 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC_NXP_IMX_IMX91_SOC_H_ +#define _SOC_NXP_IMX_IMX91_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC_NXP_IMX_IMX91_SOC_H_ */ From 9df3aae1310838184373594bbaa44cd9802a047c Mon Sep 17 00:00:00 2001 From: Lei Xu Date: Mon, 7 Jul 2025 18:26:51 -0700 Subject: [PATCH 323/397] boards: frdm_imx91: enable SDHC on the board Added pinctrl and dts nodes for uSDHC1 and uSDHC2, they are disabled by default, and provided overlay files to enable them if needed. Signed-off-by: Lei Xu Signed-off-by: Jiafei Pan --- boards/nxp/frdm_imx91/Kconfig.defconfig | 9 + boards/nxp/frdm_imx91/doc/index.rst | 31 +++ boards/nxp/frdm_imx91/dts/usdhc1.overlay | 18 ++ boards/nxp/frdm_imx91/dts/usdhc2.overlay | 18 ++ boards/nxp/frdm_imx91/frdm_imx91-pinctrl.dtsi | 195 ++++++++++++++++++ boards/nxp/frdm_imx91/frdm_imx91_mimx9131.dts | 41 ++++ 6 files changed, 312 insertions(+) create mode 100644 boards/nxp/frdm_imx91/Kconfig.defconfig create mode 100644 boards/nxp/frdm_imx91/dts/usdhc1.overlay create mode 100644 boards/nxp/frdm_imx91/dts/usdhc2.overlay diff --git a/boards/nxp/frdm_imx91/Kconfig.defconfig b/boards/nxp/frdm_imx91/Kconfig.defconfig new file mode 100644 index 0000000000000..bc9db5069fcd4 --- /dev/null +++ b/boards/nxp/frdm_imx91/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_FRDM_IMX91 + +config GPIO + default y if IMX_USDHC + +endif # BOARD_FRDM_IMX93 diff --git a/boards/nxp/frdm_imx91/doc/index.rst b/boards/nxp/frdm_imx91/doc/index.rst index 9c2a956951ec8..a4c628cd81ce5 100644 --- a/boards/nxp/frdm_imx91/doc/index.rst +++ b/boards/nxp/frdm_imx91/doc/index.rst @@ -70,6 +70,37 @@ Serial Port This board configuration uses a single serial communication channel with the CPU's UART1 for A55 core. +uSDHC (SD or eMMC Interface on A55) +----------------------------------- + +i.MX 91 processor has three ultra secured digital host controller (uSDHC) modules +for SD/eMMC interface support. On the FRDM-IMX91 board, the uSDHC2 interface of +the processor connects to the MicroSD card slot (P13), and uSDHC1 interface connects +to the eMMC memory (located at the SOM board). DTS overlay file "usdhc1.overlay" and +"usdhc2.overlay" are provided to enable specified the uSDHC controller. + +Currently it rely on U-boot or Linux to boot Zephyr, so Zephyr need to use different +uSDHC controller from U-boot or Linux to avoid resource conflict. For example, if +FRDM-IMX91 board boots from SD Card which uses uSDHC2, Zephyr can use MMC +which uses uSDHC1 for testing: + +.. zephyr-app-commands:: + :zephyr-app: tests/subsys/sd/mmc + :host-os: unix + :board: frdm_imx91/mimx9131 + :goals: build + :gen-args: -DEXTRA_DTC_OVERLAY_FILE=usdhc1.overlay + +And if FRDM-IMX91 board boots from MMC which uses uSDHC1, Zephyr can use SD Card which uses +uSDHC2 for testing: + +.. zephyr-app-commands:: + :zephyr-app: tests/subsys/sd/sdmmc + :host-os: unix + :board: frdm_imx91/mimx9131 + :goals: build + :gen-args: -DEXTRA_DTC_OVERLAY_FILE=usdhc2.overlay + Programming and Debugging ************************* diff --git a/boards/nxp/frdm_imx91/dts/usdhc1.overlay b/boards/nxp/frdm_imx91/dts/usdhc1.overlay new file mode 100644 index 0000000000000..d020f5e31e5f4 --- /dev/null +++ b/boards/nxp/frdm_imx91/dts/usdhc1.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + sdhc0 = &usdhc1; + }; +}; + +&usdhc1 { + status = "okay"; + sdmmc { + status = "okay"; + }; +}; diff --git a/boards/nxp/frdm_imx91/dts/usdhc2.overlay b/boards/nxp/frdm_imx91/dts/usdhc2.overlay new file mode 100644 index 0000000000000..8e32620412de5 --- /dev/null +++ b/boards/nxp/frdm_imx91/dts/usdhc2.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + sdhc0 = &usdhc2; + }; +}; + +&usdhc2 { + status = "okay"; + sdmmc { + status = "okay"; + }; +}; diff --git a/boards/nxp/frdm_imx91/frdm_imx91-pinctrl.dtsi b/boards/nxp/frdm_imx91/frdm_imx91-pinctrl.dtsi index c5b02e6771a0e..b17f345ad53d5 100644 --- a/boards/nxp/frdm_imx91/frdm_imx91-pinctrl.dtsi +++ b/boards/nxp/frdm_imx91/frdm_imx91-pinctrl.dtsi @@ -26,4 +26,199 @@ drive-strength = "x5"; }; }; + + pinmux_usdhc1: pinmux_usdhc1 { + group0 { + pinmux = <&iomuxc1_sd1_clk_usdhc_clk_usdhc1_clk>, + <&iomuxc1_sd1_strobe_usdhc_strobe_usdhc1_strobe>; + drive-strength = "x1"; + bias-pull-down; + slew-rate = "fast"; + input-schmitt-enable; + }; + + group1 { + pinmux = <&iomuxc1_sd1_cmd_usdhc_cmd_usdhc1_cmd>, + <&iomuxc1_sd1_data0_usdhc_data_usdhc1_data0>, + <&iomuxc1_sd1_data1_usdhc_data_usdhc1_data1>, + <&iomuxc1_sd1_data2_usdhc_data_usdhc1_data2>, + <&iomuxc1_sd1_data3_usdhc_data_usdhc1_data3>, + <&iomuxc1_sd1_data4_usdhc_data_usdhc1_data4>, + <&iomuxc1_sd1_data5_usdhc_data_usdhc1_data5>, + <&iomuxc1_sd1_data6_usdhc_data_usdhc1_data6>, + <&iomuxc1_sd1_data7_usdhc_data_usdhc1_data7>; + drive-strength = "x1"; + slew-rate = "fast"; + input-schmitt-enable; + bias-pull-up; + input-enable; + }; + }; + + pinmux_usdhc1_100mhz: pinmux_usdhc1_100mhz { + group0 { + pinmux = <&iomuxc1_sd1_clk_usdhc_clk_usdhc1_clk>, + <&iomuxc1_sd1_strobe_usdhc_strobe_usdhc1_strobe>; + drive-strength = "x3"; + bias-pull-down; + slew-rate = "fast"; + input-schmitt-enable; + }; + + group1 { + pinmux = <&iomuxc1_sd1_cmd_usdhc_cmd_usdhc1_cmd>, + <&iomuxc1_sd1_data0_usdhc_data_usdhc1_data0>, + <&iomuxc1_sd1_data1_usdhc_data_usdhc1_data1>, + <&iomuxc1_sd1_data2_usdhc_data_usdhc1_data2>, + <&iomuxc1_sd1_data3_usdhc_data_usdhc1_data3>, + <&iomuxc1_sd1_data4_usdhc_data_usdhc1_data4>, + <&iomuxc1_sd1_data5_usdhc_data_usdhc1_data5>, + <&iomuxc1_sd1_data6_usdhc_data_usdhc1_data6>, + <&iomuxc1_sd1_data7_usdhc_data_usdhc1_data7>; + drive-strength = "x3"; + slew-rate = "fast"; + input-schmitt-enable; + bias-pull-up; + input-enable; + }; + }; + + pinmux_usdhc1_200mhz: pinmux_usdhc1_200mhz { + group0 { + pinmux = <&iomuxc1_sd1_clk_usdhc_clk_usdhc1_clk>, + <&iomuxc1_sd1_strobe_usdhc_strobe_usdhc1_strobe>; + drive-strength = "x6"; + bias-pull-down; + slew-rate = "fast"; + input-schmitt-enable; + }; + + group1 { + pinmux = <&iomuxc1_sd1_cmd_usdhc_cmd_usdhc1_cmd>, + <&iomuxc1_sd1_data0_usdhc_data_usdhc1_data0>, + <&iomuxc1_sd1_data1_usdhc_data_usdhc1_data1>, + <&iomuxc1_sd1_data2_usdhc_data_usdhc1_data2>, + <&iomuxc1_sd1_data3_usdhc_data_usdhc1_data3>, + <&iomuxc1_sd1_data4_usdhc_data_usdhc1_data4>, + <&iomuxc1_sd1_data5_usdhc_data_usdhc1_data5>, + <&iomuxc1_sd1_data6_usdhc_data_usdhc1_data6>, + <&iomuxc1_sd1_data7_usdhc_data_usdhc1_data7>; + drive-strength = "x6"; + slew-rate = "fast"; + input-schmitt-enable; + bias-pull-up; + input-enable; + }; + }; + + pinmux_usdhc2: pinmux_usdhc2 { + group0 { + pinmux = <&iomuxc1_sd2_clk_usdhc_clk_usdhc2_clk>; + drive-strength = "x1"; + bias-pull-down; + slew-rate = "fast"; + input-schmitt-enable; + }; + + group1 { + pinmux = <&iomuxc1_sd2_cmd_usdhc_cmd_usdhc2_cmd>, + <&iomuxc1_sd2_data0_usdhc_data_usdhc2_data0>, + <&iomuxc1_sd2_data1_usdhc_data_usdhc2_data1>, + <&iomuxc1_sd2_data2_usdhc_data_usdhc2_data2>, + <&iomuxc1_sd2_data3_usdhc_data_usdhc2_data3>; + drive-strength = "x1"; + slew-rate = "fast"; + input-schmitt-enable; + bias-pull-up; + input-enable; + }; + + group2 { + pinmux = <&iomuxc1_sd2_vselect_usdhc_vselect_usdhc2_vselect>; + drive-strength = "x4"; + slew-rate = "slightly_fast"; + }; + + group3 { + pinmux = <&iomuxc1_sd2_cd_b_gpio_io_gpio3_io0>, + <&iomuxc1_sd2_reset_b_gpio_io_gpio3_io7>; + drive-strength = "x4"; + slew-rate = "slightly_fast"; + bias-pull-up; + }; + }; + + pinmux_usdhc2_100mhz: pinmux_usdhc2_100mhz { + group0 { + pinmux = <&iomuxc1_sd2_clk_usdhc_clk_usdhc2_clk>; + drive-strength = "x3"; + bias-pull-down; + slew-rate = "fast"; + input-schmitt-enable; + }; + + group1 { + pinmux = <&iomuxc1_sd2_cmd_usdhc_cmd_usdhc2_cmd>, + <&iomuxc1_sd2_data0_usdhc_data_usdhc2_data0>, + <&iomuxc1_sd2_data1_usdhc_data_usdhc2_data1>, + <&iomuxc1_sd2_data2_usdhc_data_usdhc2_data2>, + <&iomuxc1_sd2_data3_usdhc_data_usdhc2_data3>; + drive-strength = "x3"; + slew-rate = "fast"; + input-schmitt-enable; + bias-pull-up; + input-enable; + }; + + group2 { + pinmux = <&iomuxc1_sd2_vselect_usdhc_vselect_usdhc2_vselect>; + drive-strength = "x4"; + slew-rate = "slightly_fast"; + }; + + group3 { + pinmux = <&iomuxc1_sd2_cd_b_gpio_io_gpio3_io0>, + <&iomuxc1_sd2_reset_b_gpio_io_gpio3_io7>; + drive-strength = "x4"; + slew-rate = "slightly_fast"; + bias-pull-up; + }; + }; + + pinmux_usdhc2_200mhz: pinmux_usdhc2_200mhz { + group0 { + pinmux = <&iomuxc1_sd2_clk_usdhc_clk_usdhc2_clk>; + drive-strength = "x6"; + bias-pull-down; + slew-rate = "fast"; + input-schmitt-enable; + }; + + group1 { + pinmux = <&iomuxc1_sd2_cmd_usdhc_cmd_usdhc2_cmd>, + <&iomuxc1_sd2_data0_usdhc_data_usdhc2_data0>, + <&iomuxc1_sd2_data1_usdhc_data_usdhc2_data1>, + <&iomuxc1_sd2_data2_usdhc_data_usdhc2_data2>, + <&iomuxc1_sd2_data3_usdhc_data_usdhc2_data3>; + drive-strength = "x6"; + slew-rate = "fast"; + input-schmitt-enable; + bias-pull-up; + input-enable; + }; + + group2 { + pinmux = <&iomuxc1_sd2_vselect_usdhc_vselect_usdhc2_vselect>; + drive-strength = "x4"; + slew-rate = "slightly_fast"; + }; + + group3 { + pinmux = <&iomuxc1_sd2_cd_b_gpio_io_gpio3_io0>, + <&iomuxc1_sd2_reset_b_gpio_io_gpio3_io7>; + drive-strength = "x4"; + slew-rate = "slightly_fast"; + bias-pull-up; + }; + }; }; diff --git a/boards/nxp/frdm_imx91/frdm_imx91_mimx9131.dts b/boards/nxp/frdm_imx91/frdm_imx91_mimx9131.dts index 329ba3e83b73c..b36f451daf8f6 100644 --- a/boards/nxp/frdm_imx91/frdm_imx91_mimx9131.dts +++ b/boards/nxp/frdm_imx91/frdm_imx91_mimx9131.dts @@ -25,6 +25,10 @@ }; +&gpio3{ + status = "okay"; +}; + &lpuart1 { status = "okay"; current-speed = <115200>; @@ -35,3 +39,40 @@ &tpm2 { status = "okay"; }; + +&usdhc1 { + pinctrl-0 = <&pinmux_usdhc1>; + pinctrl-1 = <&pinmux_usdhc1_100mhz>; + pinctrl-2 = <&pinmux_usdhc1_200mhz>; + pinctrl-names = "default", "med", "fast"; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + read-watermark = <0x10>; + write-watermark = <0x80>; + status = "disabled"; + mmc { + compatible = "zephyr,mmc-disk"; + disk-name = "SD2"; + status = "disabled"; + }; +}; + +&usdhc2 { + pinctrl-0 = <&pinmux_usdhc2>; + pinctrl-1 = <&pinmux_usdhc2_100mhz>; + pinctrl-2 = <&pinmux_usdhc2_200mhz>; + pinctrl-names = "default", "med", "fast"; + pwr-gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>; + cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>; + power-delay-ms = <20>; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + read-watermark = <0x10>; + write-watermark = <0x80>; + status = "disabled"; + sdmmc { + compatible = "zephyr,sdmmc-disk"; + disk-name = "SD"; + status = "disabled"; + }; +}; From 6f197c567b9f0a74ec607b41b64c18b0c3aaef9b Mon Sep 17 00:00:00 2001 From: Lei Xu Date: Thu, 26 Dec 2024 20:08:59 -0800 Subject: [PATCH 324/397] samples: fs: fs_sample: Increase CONFIG_MAIN_STACK_SIZE for imx91 Increase CONFIG_MAIN_STACK_SIZE to 8192 to avoid possible crash. Signed-off-by: Lei Xu Signed-off-by: Jiafei Pan --- samples/subsys/fs/fs_sample/boards/frdm_imx91_mimx9131.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 samples/subsys/fs/fs_sample/boards/frdm_imx91_mimx9131.conf diff --git a/samples/subsys/fs/fs_sample/boards/frdm_imx91_mimx9131.conf b/samples/subsys/fs/fs_sample/boards/frdm_imx91_mimx9131.conf new file mode 100644 index 0000000000000..dd98d3df475c9 --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/frdm_imx91_mimx9131.conf @@ -0,0 +1 @@ +CONFIG_MAIN_STACK_SIZE=8192 From f381729b334d0145edd354d6e6011572f5c2047d Mon Sep 17 00:00:00 2001 From: Zhaoxiang Jin Date: Wed, 22 Oct 2025 10:06:36 +0800 Subject: [PATCH 325/397] drivers: mcux_syscon: enable MICFIL clock control Enable MICFIL clock control for NXP MCUX SoCs. Signed-off-by: Zhaoxiang Jin --- drivers/clock_control/clock_control_mcux_syscon.c | 10 ++++++++++ .../zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/clock_control/clock_control_mcux_syscon.c b/drivers/clock_control/clock_control_mcux_syscon.c index 62eb489394562..f14aedf6c029a 100644 --- a/drivers/clock_control/clock_control_mcux_syscon.c +++ b/drivers/clock_control/clock_control_mcux_syscon.c @@ -185,6 +185,10 @@ static int mcux_lpc_syscon_clock_control_on(const struct device *dev, #endif #endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(micfil)) + CLOCK_EnableClock(kCLOCK_Micfil); +#endif + return 0; } @@ -620,6 +624,12 @@ static int mcux_lpc_syscon_clock_control_get_subsys_rate(const struct device *de *rate = CLOCK_GetLpspiClkFreq(1); break; #endif /* defined(CONFIG_SPI_NXP_LPSPI) */ + +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(micfil)) + case MCUX_MICFIL_CLK: + *rate = CLOCK_GetMicfilClkFreq(); + break; +#endif } return 0; diff --git a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h index 285c63703a23c..d9c4217357d9c 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -136,4 +136,6 @@ #define MCUX_ELS_CLK MCUX_LPC_CLK_ID(0x19, 0x0) +#define MCUX_MICFIL_CLK MCUX_LPC_CLK_ID(0x20, 0x00) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ From f57851478f09691a92394b3766e222d852578b5d Mon Sep 17 00:00:00 2001 From: Zhaoxiang Jin Date: Wed, 22 Oct 2025 10:05:35 +0800 Subject: [PATCH 326/397] drivers: audio: Add NXP MICFIL driver Add NXP MICFIL driver base DMIC device driver model. MICFIL reference manual:https://www.nxp.com/products/MCX-N23X#documentation chapter 58. Signed-off-by: Zhaoxiang Jin --- drivers/audio/CMakeLists.txt | 1 + drivers/audio/Kconfig | 1 + drivers/audio/Kconfig.dmic_nxp_micfil | 22 + drivers/audio/dmic_nxp_micfil.c | 666 ++++++++++++++++++++++++++ dts/bindings/audio/nxp,pdm.yaml | 87 ++++ 5 files changed, 777 insertions(+) create mode 100644 drivers/audio/Kconfig.dmic_nxp_micfil create mode 100644 drivers/audio/dmic_nxp_micfil.c create mode 100644 dts/bindings/audio/nxp,pdm.yaml diff --git a/drivers/audio/CMakeLists.txt b/drivers/audio/CMakeLists.txt index 2c98e885468a0..f70c78cbfc114 100644 --- a/drivers/audio/CMakeLists.txt +++ b/drivers/audio/CMakeLists.txt @@ -17,3 +17,4 @@ zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_PCM1681 pcm1681.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_MAX98091 max98091.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_AMBIQ_PDM dmic_ambiq_pdm.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_DA7212 da7212.c) +zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_NXP_MICFIL dmic_nxp_micfil.c) diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index 0f9c5f0fae1fb..396aa2c3e59c6 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -68,6 +68,7 @@ source "drivers/audio/Kconfig.mpxxdtyy" source "drivers/audio/Kconfig.dmic_pdm_nrfx" source "drivers/audio/Kconfig.dmic_mcux" source "drivers/audio/Kconfig.dmic_ambiq_pdm" +source "drivers/audio/Kconfig.dmic_nxp_micfil" endif # AUDIO_DMIC diff --git a/drivers/audio/Kconfig.dmic_nxp_micfil b/drivers/audio/Kconfig.dmic_nxp_micfil new file mode 100644 index 0000000000000..35f56b312e30b --- /dev/null +++ b/drivers/audio/Kconfig.dmic_nxp_micfil @@ -0,0 +1,22 @@ +# Copyright 2025 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +config AUDIO_DMIC_NXP_MICFIL + bool "NXP MICFIL driver" + default y + depends on DT_HAS_NXP_MICFIL_ENABLED + select CLOCK_CONTROL + select PINCTRL + help + Enable NXP MICFIL driver. + +if AUDIO_DMIC_NXP_MICFIL + +config DMIC_NXP_MICFIL_QUEUE_SIZE + int "Message queue depth" + default 4 + help + Depth of the message queue used to pass filled buffers to the app. + +endif # AUDIO_DMIC_NXP_MICFIL diff --git a/drivers/audio/dmic_nxp_micfil.c b/drivers/audio/dmic_nxp_micfil.c new file mode 100644 index 0000000000000..cecef93c9794f --- /dev/null +++ b/drivers/audio/dmic_nxp_micfil.c @@ -0,0 +1,666 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(dmic_nxp_micfil, CONFIG_AUDIO_DMIC_LOG_LEVEL); + +#define DT_DRV_COMPAT nxp_micfil + +struct nxp_micfil_cfg { + PDM_Type *base; + uint8_t quality_mode; + uint8_t fifo_watermark; + uint8_t cic_decimation_rate; + uint8_t chan_dc_cutoff[4]; /* dc remover cutoff frequency. */ + uint8_t chan_gain[4]; /* decimation filter gain. */ + uint8_t ch_enabled_mask; + uint32_t sample_rate; /* MICFIL sample rate */ + const struct device *clock_dev; + clock_control_subsys_t clock_name; + void (*irq_config_func)(const struct device *dev); + const struct pinctrl_dev_config *pcfg; +}; + +struct nxp_micfil_drv_data { + const struct device *dev; + PDM_Type *base; + struct k_msgq *rx_msg_queue; + volatile enum dmic_state state; + uint8_t hw_chan[4]; /* Requested hardware channel order, maximun 4 channels. */ + uint8_t channels; /* Current active channels count */ + uint8_t sample_bytes; /* bytes per sample (4 for 32bits). */ + uint16_t block_size; + struct k_mem_slab *mem_slab; + void *active_buf; /* Current active buffer */ + uint16_t write_off; /* Bytes written into active_buf */ + uint8_t fifo_wm; /* FIFO watermark */ +}; + +static int nxp_micfil_configure(const struct device *dev, struct dmic_cfg *cfg_in) +{ + struct nxp_micfil_drv_data *data = dev->data; + const struct nxp_micfil_cfg *cfg = dev->config; + struct pdm_chan_cfg *chan = &cfg_in->channel; + struct pcm_stream_cfg *stream = &cfg_in->streams[0]; + uint8_t act = 0U; + uint8_t micfil_idx; + enum pdm_lr lr; + + if (data->state == DMIC_STATE_ACTIVE) { + return -EBUSY; + } + + if (stream->pcm_rate == 0U || stream->pcm_width == 0U || + stream->mem_slab == NULL || stream->block_size == 0U) { + return -EINVAL; + } + + /* NXP MICFIL FIFO data width is 32-bit, only the 24 more significant bits + * have information, and the other bits are always 0. We output 32-bit PCM + * to keep alignment and simplify processing. + */ + if (stream->pcm_width != 32U) { + LOG_ERR("Unsupported pcm width %u", stream->pcm_width); + return -EINVAL; + } + + if (chan->req_num_streams != 1U) { + LOG_ERR("Only 1 stream supported"); + return -EINVAL; + } + + /* Basic channel count sanity and support limit */ + if ((chan->req_num_chan == 0U) || (chan->req_num_chan > ARRAY_SIZE(data->hw_chan))) { + LOG_ERR("Unsupported number of channels: %u", chan->req_num_chan); + return -ENOTSUP; + } + + /* Parse the requested logical channels and build HW channel list. */ + for (uint8_t index = 0U; index < chan->req_num_chan; index++) { + dmic_parse_channel_map(chan->req_chan_map_lo, chan->req_chan_map_hi, + index, &micfil_idx, &lr); + + /* New mapping model: + * - The micfil number in the map is used directly as the DMIC channel number, + * which corresponds to the hardware DATACH index. + * - The lr value selects which side (Left/Right) that DMIC channel represents + * within its stereo pair; adjacency/consecutiveness is validated later. + */ + uint8_t hw_chan = micfil_idx; + + if (hw_chan >= ARRAY_SIZE(data->hw_chan)) { + LOG_ERR("Requested hw channel index %u exceeds supported %u", + hw_chan, (uint32_t)ARRAY_SIZE(data->hw_chan)); + return -EINVAL; + } + + if ((cfg->ch_enabled_mask & BIT(hw_chan)) == 0U) { + LOG_ERR("Requested hw channel %u not enabled in DT", hw_chan); + return -EINVAL; + } + + /* Avoid duplicates */ + for (uint8_t i = 0U; i < act; i++) { + if (data->hw_chan[i] == hw_chan) { + LOG_ERR("Duplicate channel request for hw channel %u", hw_chan); + return -EINVAL; + } + } + + data->hw_chan[act++] = hw_chan; + } + + /* Ensure no extra mappings beyond req_num_chan are set */ + for (uint8_t index = chan->req_num_chan; index < 16U; index++) { + uint32_t chan_map; + + if (index < 8U) { + chan_map = (chan->req_chan_map_lo >> (index * 4U)) & 0xFU; + } else { + chan_map = (chan->req_chan_map_hi >> ((index - 8U) * 4U)) & 0xFU; + } + if (chan_map != 0U) { + LOG_ERR("Extra mapping present for logical channel %u", index); + return -EINVAL; + } + } + + /* Validate adjacency for each stereo pair (L/R in any order) + * New model requires paired dmics to use consecutive DMIC channel numbers + * (e.g., 0/1, 2/3, ...), not the same micfil number. This preserves the API + * constraint that L and R are adjacent while allowing explicit control + * over which channel number is Left/Right. + */ + for (uint8_t index = 0U; index + 1U < chan->req_num_chan; index += 2U) { + uint8_t micfil0, micfil1; + enum pdm_lr lr0, lr1; + + dmic_parse_channel_map(chan->req_chan_map_lo, chan->req_chan_map_hi, + index, &micfil0, &lr0); + dmic_parse_channel_map(chan->req_chan_map_lo, chan->req_chan_map_hi, + index + 1U, &micfil1, &lr1); + + if (lr0 == lr1) { + LOG_ERR("Pair %u/%u has same L/R selection", index, index + 1U); + return -EINVAL; + } + /* Require consecutive DMIC channel numbers within a pair (e.g., 0/1, 2/3). + * Enforce that the smaller of the two is even to avoid crossing pairs (e.g., 1/2). + */ + uint8_t minp = MIN(micfil0, micfil1); + uint8_t maxp = MAX(micfil0, micfil1); + + if (!((maxp == (uint8_t)(minp + 1U)) && ((minp & 0x1U) == 0U))) { + LOG_ERR("Pair %u/%u must map to consecutive DMIC channels.", + index, index + 1U); + return -EINVAL; + } + } + + if (act == 0U) { + LOG_ERR("No channels requested"); + return -EINVAL; + } + + data->channels = act; + data->sample_bytes = stream->pcm_width / 8U; + data->block_size = stream->block_size; + data->mem_slab = stream->mem_slab; + + /* Validate block_size alignment to complete frames */ + uint32_t frame_bytes = (uint32_t)data->channels * (uint32_t)data->sample_bytes; + + if ((data->block_size % frame_bytes) != 0U) { + LOG_ERR("block_size %u not aligned to frame size %u (channels=%u)", + data->block_size, (uint32_t)frame_bytes, data->channels); + return -EINVAL; + } + + /* Populate act_* fields according to accepted configuration */ + chan->act_num_streams = 1U; + chan->act_num_chan = chan->req_num_chan; + chan->act_chan_map_lo = chan->req_chan_map_lo; + chan->act_chan_map_hi = chan->req_chan_map_hi; + + data->state = DMIC_STATE_CONFIGURED; + + return 0; +} + +/** + * @brief Start MICFIL capture: + * 1. Allocate first buffer + * 2. Clear pending status + * 3. Configure FIFO interrupt + * 4. Enable requested channels + * 5. Enable MICFIL interface. + */ +static int nxp_micfil_start_capture(struct nxp_micfil_drv_data *data) +{ + void *buf = NULL; + + if (k_mem_slab_alloc(data->mem_slab, &buf, K_NO_WAIT) != 0) { + return -ENOMEM; + } + data->active_buf = buf; + data->write_off = 0; + + /* Clear any pending status before enabling data interrupts */ + uint32_t st = data->base->FIFO_STAT; + + if (st) { + data->base->FIFO_STAT = st; + } + st = data->base->STAT; + if (st) { + data->base->STAT = st; + } + + /* Enable data FIFO watermark interrupts only (DISEL=2). */ + data->base->CTRL_1 = ((data->base->CTRL_1 & ~PDM_CTRL_1_DISEL_MASK) | + PDM_CTRL_1_DISEL(2U)); + + /* Enable the requested channels */ + for (uint8_t index = 0; index < data->channels; index++) { + data->base->CTRL_1 |= BIT(data->hw_chan[index]); + } + + /* Enable MICFIL. */ + data->base->CTRL_1 |= PDM_CTRL_1_PDMIEN_MASK; + + data->state = DMIC_STATE_ACTIVE; + + return 0; +} + +/** + * @brief Stop/Pause/Reset MICFIL capture and clean up buffers/queues. + */ +static void nxp_micfil_stop_or_reset(struct nxp_micfil_drv_data *data, enum dmic_trigger cmd) +{ + /* Check if we are in a state that can be stopped/paused/reset */ + if (data->state == DMIC_STATE_ACTIVE || data->state == DMIC_STATE_PAUSED || + data->state == DMIC_STATE_ERROR) { + /* Disable MICFIL */ + data->base->CTRL_1 &= ~PDM_CTRL_1_PDMIEN_MASK; + + /* Disable the requested channels */ + for (uint8_t index = 0; index < data->channels; index++) { + data->base->CTRL_1 &= ~(BIT(data->hw_chan[index])); + } + + /* Disable fifo interrupts. */ + data->base->CTRL_1 &= ~PDM_CTRL_1_DISEL_MASK; + + /* Set state early so any in-flight ISR bails out */ + data->state = (cmd == DMIC_TRIGGER_RESET) ? DMIC_STATE_UNINIT : + DMIC_STATE_CONFIGURED; + + /* Clear any pending status flags */ + uint32_t st = data->base->FIFO_STAT; + + if (st) { + data->base->FIFO_STAT = st; + } + + st = data->base->STAT; + + if (st) { + data->base->STAT = st; + } + } + + /* Free active buffer if any */ + if (data->active_buf) { + void *tmp = data->active_buf; + + data->active_buf = NULL; + k_mem_slab_free(data->mem_slab, tmp); + } + + /* Drain and free any queued buffers that were filled + * but not yet read to avoid leaks. + */ + if (data->rx_msg_queue) { + void *queued; + + while (k_msgq_get(data->rx_msg_queue, &queued, K_NO_WAIT) == 0) { + k_mem_slab_free(data->mem_slab, queued); + } + } +} + +static int nxp_micfil_trigger(const struct device *dev, enum dmic_trigger cmd) +{ + struct nxp_micfil_drv_data *data = dev->data; + + switch (cmd) { + case DMIC_TRIGGER_START: + case DMIC_TRIGGER_RELEASE: { + /* Check if we are in a state that can be started/released */ + if (data->state != DMIC_STATE_CONFIGURED && + data->state != DMIC_STATE_PAUSED) { + return -EIO; + } + + int ret = nxp_micfil_start_capture(data); + + if (ret) { + LOG_ERR("Failed to start capture: %d", ret); + return ret; + } + + break; + } + + case DMIC_TRIGGER_PAUSE: + case DMIC_TRIGGER_STOP: + case DMIC_TRIGGER_RESET: { + nxp_micfil_stop_or_reset(data, cmd); + + break; + } + + default: + return -EINVAL; + } + + return 0; +} + +static int nxp_micfil_read(const struct device *dev, uint8_t stream, + void **buffer, size_t *size, int32_t timeout) +{ + struct nxp_micfil_drv_data *data = dev->data; + + ARG_UNUSED(stream); + + /* Check if we are in a state that can read */ + if (data->state != DMIC_STATE_ACTIVE && data->state != DMIC_STATE_PAUSED) { + return -EIO; + } + + /* Get the filled buffer from the queue */ + int ret = k_msgq_get(data->rx_msg_queue, buffer, SYS_TIMEOUT_MS(timeout)); + + if (ret == 0) { + *size = data->block_size; + return 0; + } + + /* Fallback: if active but no IRQ-produced data arrived within timeout, + * return a zero-filled block so API semantics (non-timeout) are satisfied. + */ + if (data->state == DMIC_STATE_ACTIVE) { + void *buf = NULL; + static uint32_t last_warn_ms; + + if (k_mem_slab_alloc(data->mem_slab, &buf, K_NO_WAIT) != 0) { + return ret; /* original error */ + } + /* Provide silence */ + (void)memset(buf, 0, data->block_size); + + uint32_t now = k_uptime_get_32(); + + if ((now - last_warn_ms) > 1000U) { + LOG_ERR("DMIC fallback: no IRQ data yet, returning silence\n"); + last_warn_ms = now; + } + + *buffer = buf; + *size = data->block_size; + + return 0; + } + + return ret; +} + +static void nxp_micfil_isr(const void *arg) +{ + const struct device *dev = (const struct device *)arg; + struct nxp_micfil_drv_data *data = dev->data; + uint32_t state = data->base->FIFO_STAT; + + /* Clear status flags */ + if (state) { + data->base->FIFO_STAT = state; + } + + state = data->base->STAT; + + if (state) { + data->base->STAT = state; + } + + /* Check if we are in a state that can read */ + if (!data->active_buf || data->state != DMIC_STATE_ACTIVE) { + return; + } + + /* Read data from all enabled channels */ + uint8_t *dst = (uint8_t *)data->active_buf; + /* Each frame is channels * sample_bytes. Hardware returns 32-bit samples in DATACH[]. + * We output little-endian 32-bit PCM: LSB first, 4 bytes per sample. + */ + uint16_t frame_bytes = (uint16_t)(data->channels * data->sample_bytes); + /* Calculate how many complete frames are left in the current block that can be + * written. This limits the maximum number of frames that this ISR can take from + * the hardware FIFO to avoid write overflow and maintain frame alignment. + */ + uint16_t frames_remaining = (uint16_t)((data->block_size - data->write_off) / frame_bytes); + /* Read up to fifo_wm frames. */ + uint16_t frames_to_read = (uint16_t)data->fifo_wm; + + /* Adjust if more frames than remaining in buffer */ + if (frames_to_read > frames_remaining) { + frames_to_read = frames_remaining; + } + + /* Read frames from all active channels' FIFO. */ + for (uint16_t frame = 0; frame < frames_to_read; frame++) { + for (uint8_t chan = 0; chan < data->channels; chan++) { + /* Read one 32-bit sample from the selected hardware channel FIFO. */ + uint8_t hw = data->hw_chan[chan]; + volatile uint32_t raw_data = data->base->DATACH[hw]; + + dst[data->write_off + 0] = (uint8_t)(raw_data & 0xFFU); + dst[data->write_off + 1] = (uint8_t)((raw_data >> 8U) & 0xFFU); + dst[data->write_off + 2] = (uint8_t)((raw_data >> 16U) & 0xFFU); + dst[data->write_off + 3] = (uint8_t)((raw_data >> 24U) & 0xFFU); + + data->write_off += 4; + } + } + + /* Check if active buffer is full. Hand off to queue and rotate buffers safely. */ + if (data->write_off >= data->block_size) { + void *completed = data->active_buf; + void *new_buf = NULL; + + /* Allocate next buffer first to avoid using a freed buffer */ + if (k_mem_slab_alloc(data->mem_slab, &new_buf, K_NO_WAIT) != 0) { + /* No memory available: enter error state and stop capturing */ + data->active_buf = NULL; + data->state = DMIC_STATE_ERROR; + + /* Disable MICFIL */ + data->base->CTRL_1 &= ~PDM_CTRL_1_PDMIEN_MASK; + + /* Disable the requested channels */ + for (uint8_t index = 0; index < data->channels; index++) { + data->base->CTRL_1 &= ~(BIT(data->hw_chan[index])); + } + + /* Disable fifo interrupts. */ + data->base->CTRL_1 &= ~PDM_CTRL_1_DISEL_MASK; + return; + } + + /* Try to enqueue the completed buffer. If queue is full, free it. */ + if (k_msgq_put(data->rx_msg_queue, &completed, K_NO_WAIT) != 0) { + k_mem_slab_free(data->mem_slab, completed); + } + + /* Switch to the new active buffer */ + data->active_buf = new_buf; + data->write_off = 0; + } +} + +static int nxp_micfil_init(const struct device *dev) +{ + const struct nxp_micfil_cfg *cfg = dev->config; + struct nxp_micfil_drv_data *data = dev->data; + uint32_t clk_rate = 0U; + int ret; + + data->dev = dev; + data->base = cfg->base; + + if (cfg->clock_dev != NULL) { + ret = clock_control_on(cfg->clock_dev, cfg->clock_name); + if (ret) { + LOG_ERR("Device clock turn on failed"); + return ret; + } + + ret = clock_control_get_rate(cfg->clock_dev, cfg->clock_name, &clk_rate); + if (ret < 0) { + LOG_WRN("Device clock rate not available (%d)", ret); + } + } + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to configure pins (%d)", ret); + return ret; + } + + if (cfg->irq_config_func) { + cfg->irq_config_func(dev); + } + + /* MICFIL initialization. */ + /* Ensure module is enabled and interface/interrupts/channels + * are disabled before config. + */ + data->base->CTRL_1 &= ~(PDM_CTRL_1_MDIS_MASK | PDM_CTRL_1_PDMIEN_MASK | + PDM_CTRL_1_ERREN_MASK); + /* TODO: Use DT property instead of hardcoding channel numbers. */ + for (uint8_t ch = 0U; ch < 4U; ch++) { + data->base->CTRL_1 &= ~BIT(ch); + } + + /* Wait until all filters stopped if supported. */ + while ((data->base->STAT & PDM_STAT_BSY_FIL_MASK) != 0U) { + } + + /* Do a software reset pulse before configuration. */ + data->base->CTRL_1 |= PDM_CTRL_1_SRES_MASK; + + /* Configure quality mode, CIC decimation rate. */ + data->base->CTRL_2 &= ~(PDM_CTRL_2_QSEL_MASK | PDM_CTRL_2_CICOSR_MASK); + data->base->CTRL_2 |= PDM_CTRL_2_QSEL(cfg->quality_mode) | + PDM_CTRL_2_CICOSR(cfg->cic_decimation_rate); + + /* Configure FIFO watermark. */ + data->base->FIFO_CTRL = (data->base->FIFO_CTRL & ~PDM_FIFO_CTRL_FIFOWMK_MASK) | + PDM_FIFO_CTRL_FIFOWMK(cfg->fifo_watermark); + + /* Cache FIFO watermark for ISR. */ + data->fifo_wm = cfg->fifo_watermark; + + /* MICFIL channels initialization. */ + /* Configure DC remover cutoff per hardware channel. */ + for (uint8_t ch = 0U; ch < ARRAY_SIZE(cfg->chan_dc_cutoff); ch++) { + uint32_t mask = PDM_DC_CTRL_DCCONFIG0_MASK << (ch * 2U); + uint32_t val = (cfg->chan_dc_cutoff[ch] & PDM_DC_CTRL_DCCONFIG0_MASK) << (ch * 2U); + + data->base->DC_OUT_CTRL = ((data->base->DC_OUT_CTRL & ~mask) | val); + } + + /* Configure decimation-filter-gain per hardware channel. */ + for (uint8_t ch = 0U; ch < ARRAY_SIZE(cfg->chan_gain); ch++) { + uint32_t mask = PDM_RANGE_CTRL_RANGEADJ0_MASK << (ch * 4U); + uint32_t val = (cfg->chan_gain[ch] & PDM_RANGE_CTRL_RANGEADJ0_MASK) << (ch * 4U); + + data->base->RANGE_CTRL = ((data->base->RANGE_CTRL & ~mask) | val); + } + + /* Configure clock divider if clock rate and sample rate are known. */ + if (clk_rate != 0U && cfg->sample_rate != 0U) { + uint32_t osr_reg_max = (PDM_CTRL_2_CICOSR_MASK >> PDM_CTRL_2_CICOSR_SHIFT); + + if (cfg->cic_decimation_rate > osr_reg_max) { + LOG_ERR("CIC decimation rate %u exceeds max %u", + cfg->cic_decimation_rate, (uint32_t)osr_reg_max); + return -EINVAL; + } + + /* Real OSR per MCUX SDK: (max + 1 - programmed). */ + uint32_t real_osr = osr_reg_max + 1U - (uint32_t)cfg->cic_decimation_rate; + uint32_t micfil_clock_rate = cfg->sample_rate * real_osr * 8U; + + if (clk_rate < micfil_clock_rate) { + LOG_ERR("Clock rate %u too low for sample rate %u (OSR=%u)", + clk_rate, cfg->sample_rate, real_osr); + return -EINVAL; + } + + uint32_t reg_div = clk_rate / micfil_clock_rate; + + if (reg_div == 0U) { + reg_div = 1U; + } + + uint32_t clkdiv_max = (PDM_CTRL_2_CLKDIV_MASK >> PDM_CTRL_2_CLKDIV_SHIFT); + + if (reg_div > clkdiv_max) { + LOG_WRN("CLKDIV %u exceeds max %u, clamping", reg_div, clkdiv_max); + reg_div = clkdiv_max; + } + + data->base->CTRL_2 = (data->base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | + PDM_CTRL_2_CLKDIV(reg_div); + + LOG_INF("MICFIL clk=%uHz sample=%u OSR=%u div=%u wm=%u", + clk_rate, cfg->sample_rate, real_osr, reg_div, cfg->fifo_watermark); + } else { + LOG_WRN("Clock rate or sample rate is zero, cannot set clock divider"); + } + + data->state = DMIC_STATE_INITIALIZED; + + return 0; +} + +static const struct _dmic_ops dmic_ops = { + .configure = nxp_micfil_configure, + .trigger = nxp_micfil_trigger, + .read = nxp_micfil_read, +}; + +#define NXP_MICFIL_IRQ_CONFIG(inst) \ + static void _CONCAT(irq_config, inst)(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \ + nxp_micfil_isr, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } + +/* Build per-hardware-channel DC cutoff array from DT child nodes. */ +#define DC_CUTOFF_ITEM(node_id) [DT_REG_ADDR(node_id)] = \ + DT_PROP(node_id, dc_remover_cutoff_freq), +/* Build per-hardware-channel OUT gain array from DT child nodes. */ +#define OUT_GAIN_ITEM(node_id) [DT_REG_ADDR(node_id)] = \ + DT_PROP_OR(node_id, decimation_filter_gain, 0), +/* Build bitmask of enabled channels by OR-ing BIT(reg) per child. */ +#define CH_BIT(node_id) | BIT(DT_REG_ADDR(node_id)) + +#define NXP_MICFIL_DEFINE(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + K_MSGQ_DEFINE(nxp_micfil_msgq##inst, sizeof(void *), \ + CONFIG_DMIC_NXP_MICFIL_QUEUE_SIZE, 4); \ + \ + NXP_MICFIL_IRQ_CONFIG(inst) \ + \ + static struct nxp_micfil_drv_data _CONCAT(data, inst) = { \ + .rx_msg_queue = &nxp_micfil_msgq##inst, \ + .state = DMIC_STATE_UNINIT, \ + }; \ + \ + static const struct nxp_micfil_cfg _CONCAT(cfg, inst) = { \ + .base = (PDM_Type *)DT_INST_REG_ADDR(inst), \ + .quality_mode = DT_INST_PROP(inst, quality_mode), \ + .fifo_watermark = DT_INST_PROP(inst, fifo_watermark), \ + .cic_decimation_rate = DT_INST_PROP(inst, cic_decimation_rate), \ + .chan_dc_cutoff = { DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, \ + DC_CUTOFF_ITEM) }, \ + .chan_gain = { DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, OUT_GAIN_ITEM) },\ + .ch_enabled_mask = (0 DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, CH_BIT)), \ + .sample_rate = DT_INST_PROP(inst, sample_rate), \ + .clock_dev = DEVICE_DT_GET_OR_NULL(DT_INST_CLOCKS_CTLR(inst)), \ + .clock_name = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, name), \ + .irq_config_func = _CONCAT(irq_config, inst), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, nxp_micfil_init, NULL, \ + &_CONCAT(data, inst), &_CONCAT(cfg, inst), \ + POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, &dmic_ops); + +DT_INST_FOREACH_STATUS_OKAY(NXP_MICFIL_DEFINE) diff --git a/dts/bindings/audio/nxp,pdm.yaml b/dts/bindings/audio/nxp,pdm.yaml new file mode 100644 index 0000000000000..715665bfb49e2 --- /dev/null +++ b/dts/bindings/audio/nxp,pdm.yaml @@ -0,0 +1,87 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP PDM Microphone Interface (MICFIL) + +compatible: "nxp,micfil" + +include: + - base.yaml + - pinctrl-device.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true + + quality-mode: + type: int + enum: [0, 1, 4, 5, 6, 7] + default: 0 + description: | + Decimation filter quality mode. + 0 = Medium, default value, PoR reset value of register + 1 = High + 4 = VeryLow2 + 5 = VeryLow1 + 6 = VeryLow0 + 7 = Low + + cic-decimation-rate: + type: int + description: | + CIC filter decimation rate setting, + range is SoC specific, may [0, 15] or [8, 31] + The final OSR = (16 - cic-decimation-rate) + CIC decimation rate = 2 * OSR; If HQ, VLQ0 mode. + CIC decimation rate = OSR; If other modes. + 0: CIC oversampling rate = 0, default value, PoR reset value + 1: CIC oversampling rate = 1 + ... + 15: CIC oversampling rate = 15 + + fifo-watermark: + type: int + description: | + FIFO watermark level (implementation defined, typically 7), + range is SoC specific, may [0, 7] or [0, 15]. + Default is PoR reset value of register. + + sample-rate: + type: int + enum: [8000, 12000, 16000, 24000, 32000, 48000, 96000] + description: | + Sample rate in Hz. + +child-binding: + description: | + NXP MICFIL channel. Can be used to configure DC remover cutoff frequency and gain + include: + - name: base.yaml + property-allowlist: + - reg + properties: + reg: + required: true + dc-remover-cutoff-freq: + type: int + enum: [0, 1, 2, 3] + default: 0 + description: | + DC remover cutoff frequency in Hz + 0: 20Hz (FS=48KHz), default value, PoR reset value + 1: 13.3Hz (FS=48KHz) + 2: 40Hz (FS=48KHz) + 3: DC remover is bypassed + + decimation-filter-gain: + type: int + default: 0 + description: | + Decimation filter gain setting, range: [0, 15]. + Default is PoR reset value of register. From 6a544a93f5a826db7100a23fd7bc205dcfbecb66 Mon Sep 17 00:00:00 2001 From: Zhaoxiang Jin Date: Wed, 22 Oct 2025 10:07:19 +0800 Subject: [PATCH 327/397] board: frdm_mcxn236: Enable MICFIL on frdm_mcxn236 1. Enable MICFIL on frdm_mcxn236 board. 2. MICFIL CLOCK and DATA Pins are conflict with flexcomm0_lpuart pins, so change flexcomm0_lpuart pins to 'FC0_P2_PIO0_6' and 'FC0_P3_PIO0_7'. Signed-off-by: Zhaoxiang Jin --- boards/nxp/frdm_mcxn236/board.c | 19 ++++++--- .../frdm_mcxn236/frdm_mcxn236-pinctrl.dtsi | 14 ++++++- boards/nxp/frdm_mcxn236/frdm_mcxn236.dts | 6 +++ dts/arm/nxp/nxp_mcxn23x_common.dtsi | 42 +++++++++++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/boards/nxp/frdm_mcxn236/board.c b/boards/nxp/frdm_mcxn236/board.c index 53d2052a78331..f4034aebbc3c2 100644 --- a/boards/nxp/frdm_mcxn236/board.c +++ b/boards/nxp/frdm_mcxn236/board.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * SPDX-License-Identifier: Apache-2.0 */ #include @@ -103,7 +103,9 @@ void board_early_init_hook(void) CLOCK_SetupExtClocking(BOARD_XTAL0_CLK_HZ); -#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai0)) || DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai1)) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai0)) || \ + DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sai1)) || \ + DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(micfil)) /* < Set up PLL1 */ const pll_setup_t pll1_Setup = { .pllctrl = SCG_SPLLCTRL_SOURCE(1U) | SCG_SPLLCTRL_SELI(3U) | @@ -111,12 +113,13 @@ void board_early_init_hook(void) .pllndiv = SCG_SPLLNDIV_NDIV(25U), .pllpdiv = SCG_SPLLPDIV_PDIV(10U), .pllmdiv = SCG_SPLLMDIV_MDIV(256U), - .pllRate = 24576000U}; + .pllRate = 24576000U + }; /* Configure PLL1 to the desired values */ CLOCK_SetPLL1Freq(&pll1_Setup); - /* Set PLL1 CLK0 divider to value 1 */ - CLOCK_SetClkDiv(kCLOCK_DivPLL1Clk0, 1U); + /* Set PLL1 CLK0 divider to value 2, then the clock is 12288000Hz. */ + CLOCK_SetClkDiv(kCLOCK_DivPLL1Clk0, 2U); #endif #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexcomm0)) @@ -339,6 +342,12 @@ void board_early_init_hook(void) CLOCK_EnableClock(kCLOCK_Sai1); #endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(micfil)) + CLOCK_SetClkDiv(kCLOCK_DivMicfilFClk, 1U); + CLOCK_AttachClk(kPLL1_CLK0_to_MICFILF); + CLOCK_EnableClock(kCLOCK_Micfil); +#endif + /* Set SystemCoreClock variable. */ SystemCoreClock = CLOCK_INIT_CORE_CLOCK; } diff --git a/boards/nxp/frdm_mcxn236/frdm_mcxn236-pinctrl.dtsi b/boards/nxp/frdm_mcxn236/frdm_mcxn236-pinctrl.dtsi index d03950c097718..5b8aaf77b9831 100644 --- a/boards/nxp/frdm_mcxn236/frdm_mcxn236-pinctrl.dtsi +++ b/boards/nxp/frdm_mcxn236/frdm_mcxn236-pinctrl.dtsi @@ -8,8 +8,8 @@ &pinctrl { pinmux_flexcomm0_lpuart: pinmux_flexcomm0_lpuart { group0 { - pinmux = , - ; + pinmux = , + ; slew-rate = "fast"; drive-strength = "low"; input-enable; @@ -248,4 +248,14 @@ drive-open-drain; }; }; + + pinmux_micfil: pinmux_micfil { + group0 { + pinmux = , + ; + drive-strength = "high"; + slew-rate = "fast"; + input-enable; + }; + }; }; diff --git a/boards/nxp/frdm_mcxn236/frdm_mcxn236.dts b/boards/nxp/frdm_mcxn236/frdm_mcxn236.dts index 35bb46e9ee7bd..a22cac77b6aaf 100644 --- a/boards/nxp/frdm_mcxn236/frdm_mcxn236.dts +++ b/boards/nxp/frdm_mcxn236/frdm_mcxn236.dts @@ -443,3 +443,9 @@ dvp_20pin_interface: &video_sdma {}; pinctrl-0 = <&pinmux_sai1>; pinctrl-names = "default"; }; + +&micfil { + status = "okay"; + pinctrl-0 = <&pinmux_micfil>; + pinctrl-names = "default"; +}; diff --git a/dts/arm/nxp/nxp_mcxn23x_common.dtsi b/dts/arm/nxp/nxp_mcxn23x_common.dtsi index e95c01fc1840a..4b88cae0ced77 100644 --- a/dts/arm/nxp/nxp_mcxn23x_common.dtsi +++ b/dts/arm/nxp/nxp_mcxn23x_common.dtsi @@ -983,6 +983,48 @@ nxp,rx-dma-channel = <3>; status = "disabled"; }; + + micfil: micfil@10c000 { + compatible = "nxp,micfil"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <48 0>; + reg = <0x10c000 0x1000>; + clocks = <&syscon MCUX_MICFIL_CLK>; + status = "disabled"; + quality-mode = <1>; + cic-decimation-rate = <0>; + fifo-watermark = <15>; + sample-rate = <16000>; + + channel0: micfil-channel@0 { + reg = <0>; + status = "disabled"; + dc-remover-cutoff-freq = <2>; + decimation-filter-gain = <4>; + }; + + channel1: micfil-channel@1 { + reg = <1>; + status = "disabled"; + dc-remover-cutoff-freq = <2>; + decimation-filter-gain = <4>; + }; + + channel2: micfil-channel@2 { + reg = <2>; + status = "disabled"; + dc-remover-cutoff-freq = <2>; + decimation-filter-gain = <4>; + }; + + channel3: micfil-channel@3 { + reg = <3>; + status = "disabled"; + dc-remover-cutoff-freq = <2>; + decimation-filter-gain = <4>; + }; + }; }; &systick { From ceabe7c19e0e989c1605bbece92d13eca7fca41d Mon Sep 17 00:00:00 2001 From: Zhaoxiang Jin Date: Wed, 22 Oct 2025 10:07:48 +0800 Subject: [PATCH 328/397] samples: i2s_codec: Enable nxp micfil sample Enable nxp micfil sample with 'CONFIG_USE_DMIC=y', you can hear the voice played from the on-board micphone. Signed-off-by: Zhaoxiang Jin --- samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.conf | 3 +++ .../drivers/i2s/i2s_codec/boards/frdm_mcxn236.overlay | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.conf b/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.conf index fa7f7f5603d7e..444b842b8f930 100644 --- a/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.conf +++ b/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.conf @@ -8,5 +8,8 @@ CONFIG_SAMPLE_FREQ=16000 CONFIG_I2S_INIT_BUFFERS=1 CONFIG_USE_CODEC_CLOCK=y CONFIG_USE_DMIC=n +CONFIG_USE_DMIC=y CONFIG_DMIC_CHANNELS=1 CONFIG_EXTRA_BLOCKS=10 +CONFIG_SAMPLE_WIDTH=32 +CONFIG_BYTES_PER_SAMPLE=4 diff --git a/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.overlay b/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.overlay index ce71fb5ed380c..e6f4e0e140cbf 100644 --- a/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.overlay +++ b/samples/drivers/i2s/i2s_codec/boards/frdm_mcxn236.overlay @@ -18,3 +18,13 @@ &sai1 { mclk-output; }; + +dmic_dev: &micfil { + channel0: micfil-channel@0 { + status = "okay"; + }; + + channel1: micfil-channel@1 { + status = "okay"; + }; +}; From 45faa27f011e60c6a230d6946c97cf952691adf3 Mon Sep 17 00:00:00 2001 From: Kai Cheng Date: Tue, 21 Oct 2025 23:15:59 +0800 Subject: [PATCH 329/397] Bluetooth: Classic: add power mode control for sniff mode Implement BR/EDR power mode control with sniff mode functionality. Adds APIs bt_conn_br_enter_sniff_mode() and bt_conn_br_exit_sniff_mode() to manage power saving modes. Includes parameter validation and HCI command handling for sniff mode configuration with min/max intervals, attempt count, and timeout parameters. Signed-off-by: Kai Cheng --- include/zephyr/bluetooth/conn.h | 24 +++++++++ include/zephyr/bluetooth/hci_types.h | 27 ++++++++++ subsys/bluetooth/host/classic/Kconfig | 7 +++ subsys/bluetooth/host/conn.c | 74 +++++++++++++++++++++++++++ subsys/bluetooth/host/conn_internal.h | 5 ++ 5 files changed, 137 insertions(+) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 881d0894ee118..24c9680b17391 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -2961,6 +2961,30 @@ int bt_conn_br_switch_role(const struct bt_conn *conn, uint8_t role); */ int bt_conn_br_set_role_switch_enable(const struct bt_conn *conn, bool enable); +#if defined(CONFIG_BT_POWER_MODE_CONTROL) +/** @brief bluetooth conn check and enter sniff mode + * + * This function is used to identify which ACL link connection is to + * be placed in Sniff mode + * + * @param conn bt_conn conn + * @param min_interval Minimum sniff interval. + * @param max_interval Maxmum sniff interval. + * @param attempt Number of Baseband receive slots for sniff attempt. + * @param timeout Number of Baseband receive slots for sniff timeout. + */ +int bt_conn_br_enter_sniff_mode(struct bt_conn *conn, uint16_t min_interval, + uint16_t max_interval, uint16_t attempt, uint16_t timeout); + +/** @brief bluetooth conn check and exit sniff mode + * + * @param conn bt_conn conn + * + * @return Zero for success, non-zero otherwise. + */ +int bt_conn_br_exit_sniff_mode(struct bt_conn *conn); +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 92f51b69a4551..dc238e6fb645e 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -602,6 +602,20 @@ struct bt_hci_cp_write_default_link_policy_settings { uint16_t default_link_policy_settings; } __packed; +#define BT_HCI_OP_SNIFF_MODE BT_OP(BT_OGF_LINK_POLICY, 0x0003) /* 0x0803 */ +struct bt_hci_cp_sniff_mode { + uint16_t handle; + uint16_t max_interval; + uint16_t min_interval; + uint16_t attempt; + uint16_t timeout; +} __packed; + +#define BT_HCI_OP_EXIT_SNIFF_MODE BT_OP(BT_OGF_LINK_POLICY, 0x0004) /* 0x0804 */ +struct bt_hci_cp_exit_sniff_mode { + uint16_t handle; +} __packed; + #define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) /* 0x0c01 */ struct bt_hci_cp_set_event_mask { uint8_t events[8]; @@ -2964,6 +2978,19 @@ struct bt_hci_evt_num_completed_packets { struct bt_hci_handle_count h[0]; } __packed; +/* Current mode */ +#define BT_ACTIVE_MODE 0x00 +#define BT_HOLD_MODE 0x01 +#define BT_SNIFF_MODE 0x02 + +#define BT_HCI_EVT_MODE_CHANGE 0x14 +struct bt_hci_evt_mode_change { + uint8_t status; + uint16_t handle; + uint8_t mode; + uint16_t interval; +} __packed; + #define BT_HCI_EVT_PIN_CODE_REQ 0x16 struct bt_hci_evt_pin_code_req { bt_addr_t bdaddr; diff --git a/subsys/bluetooth/host/classic/Kconfig b/subsys/bluetooth/host/classic/Kconfig index 60252cbcecc84..c771cfdcd043e 100644 --- a/subsys/bluetooth/host/classic/Kconfig +++ b/subsys/bluetooth/host/classic/Kconfig @@ -567,6 +567,13 @@ config BT_DEFAULT_ROLE_SWITCH_ENABLE This option sets the controller's default link policy to enable/disable the role switch. +config BT_POWER_MODE_CONTROL + bool "Bluetooth Power Mode Control(Active/Sniff)" + help + This option enables the power mode control feature. This feature + allows the application to control the power mode of the Bluetooth + controller. + config BT_GOEP bool "Bluetooth GOEP Profile [EXPERIMENTAL]" select BT_RFCOMM diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 220095a895aac..f865f8b848a34 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2462,6 +2462,10 @@ struct bt_conn *bt_conn_add_br(const bt_addr_t *peer) conn->get_and_clear_cb = acl_get_and_clear_cb; conn->has_data = acl_has_data; +#if defined(CONFIG_BT_POWER_MODE_CONTROL) + conn->br.mode = BT_ACTIVE_MODE; +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ + return conn; } #endif /* CONFIG_BT_CLASSIC */ @@ -4360,6 +4364,76 @@ void bt_hci_le_df_cte_req_failed(struct net_buf *buf) } #endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ +#if defined(CONFIG_BT_POWER_MODE_CONTROL) +int bt_conn_br_enter_sniff_mode(struct bt_conn *conn, uint16_t min_interval, uint16_t max_interval, + uint16_t attempt, uint16_t timeout) +{ + struct bt_hci_cp_sniff_mode *cp; + struct net_buf *buf; + + if (!bt_conn_is_type(conn, BT_CONN_TYPE_BR)) { + return -EINVAL; + } + + if (conn->state != BT_CONN_CONNECTED) { + return -ENOTCONN; + } + + if (conn->br.mode == BT_SNIFF_MODE) { + return -EBUSY; + } + + /* Check if the parameters are valid */ + if (min_interval < 0x0006 || min_interval > 0x0540 || max_interval < 0x0006 || + max_interval > 0x0540 || min_interval > max_interval || attempt == 0 || + attempt > 0x01F3 || timeout > 0x0028) { + return -EINVAL; + } + + buf = bt_hci_cmd_alloc(K_FOREVER); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->max_interval = sys_cpu_to_le16(max_interval); + cp->min_interval = sys_cpu_to_le16(min_interval); + cp->attempt = sys_cpu_to_le16(attempt); + cp->timeout = sys_cpu_to_le16(timeout); + + return bt_hci_cmd_send_sync(BT_HCI_OP_SNIFF_MODE, buf, NULL); +} + +int bt_conn_br_exit_sniff_mode(struct bt_conn *conn) +{ + struct bt_hci_cp_exit_sniff_mode *cp; + struct net_buf *buf; + + if (!bt_conn_is_type(conn, BT_CONN_TYPE_BR)) { + return -EINVAL; + } + + if (conn->state != BT_CONN_CONNECTED) { + return -ENOTCONN; + } + + if (conn->br.mode == BT_ACTIVE_MODE) { + return -EBUSY; + } + + buf = bt_hci_cmd_alloc(K_FOREVER); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + + return bt_hci_cmd_send_sync(BT_HCI_OP_EXIT_SNIFF_MODE, buf, NULL); +} + +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CONN_TX_NOTIFY_WQ) diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 87393922a93b6..14fd922b620d8 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -155,6 +155,11 @@ struct bt_conn_br { uint8_t features[LMP_MAX_PAGES][8]; struct bt_keys_link_key *link_key; + +#if defined(CONFIG_BT_POWER_MODE_CONTROL) + /* For power mode */ + uint8_t mode; +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ }; struct bt_conn_sco { From 29864901398debfd35ec408ca9687fca98c7342b Mon Sep 17 00:00:00 2001 From: Kai Cheng Date: Tue, 21 Oct 2025 23:19:16 +0800 Subject: [PATCH 330/397] Bluetooth: Classic: add mode change notification for sniff mode Implement mode change event handling and callback notification for BR/EDR power mode transitions. Adds br_mode_changed callback to notify applications when connection switches between active and sniff modes. Handles HCI mode change events and propagates mode and interval information to registered callbacks. Signed-off-by: Kai Cheng --- include/zephyr/bluetooth/conn.h | 12 ++++++++++ subsys/bluetooth/host/classic/br.c | 34 +++++++++++++++++++++++++++ subsys/bluetooth/host/conn.c | 17 ++++++++++++++ subsys/bluetooth/host/conn_internal.h | 5 ++++ subsys/bluetooth/host/hci_core.c | 4 ++++ subsys/bluetooth/host/hci_core.h | 3 +++ 6 files changed, 75 insertions(+) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 24c9680b17391..f07e35e315595 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -1970,6 +1970,18 @@ struct bt_conn_cb { struct bt_conn_remote_info *remote_info); #endif /* defined(CONFIG_BT_REMOTE_INFO) */ +#if defined(CONFIG_BT_POWER_MODE_CONTROL) + /** @brief The connection mode change + * + * This callback notifies the application that the sniff mode has changed + * + * @param conn Connection object. + * @param mode Active/Sniff mode. + * @param interval Sniff interval. + */ + void (*br_mode_changed)(struct bt_conn *conn, uint8_t mode, uint16_t interval); +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ + #if defined(CONFIG_BT_USER_PHY_UPDATE) /** @brief The PHY of the connection has changed. * diff --git a/subsys/bluetooth/host/classic/br.c b/subsys/bluetooth/host/classic/br.c index 4e9902747381a..cf58fae021048 100644 --- a/subsys/bluetooth/host/classic/br.c +++ b/subsys/bluetooth/host/classic/br.c @@ -710,6 +710,40 @@ void bt_hci_role_change(struct net_buf *buf) bt_conn_unref(conn); } +#if defined(CONFIG_BT_POWER_MODE_CONTROL) +void bt_hci_link_mode_change(struct net_buf *buf) +{ + struct bt_hci_evt_mode_change *evt = (void *)buf->data; + uint16_t handle = sys_le16_to_cpu(evt->handle); + uint16_t interval = sys_le16_to_cpu(evt->interval); + struct bt_conn *conn; + + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_BR); + if (!conn) { + LOG_ERR("Can't find conn for handle 0x%x", handle); + return; + } + + if (conn->state != BT_CONN_CONNECTED) { + LOG_ERR("Invalid state %d", conn->state); + bt_conn_unref(conn); + return; + } + + if (evt->status) { + LOG_ERR("Error %d, type %d", evt->status, conn->type); + bt_conn_unref(conn); + return; + } + + LOG_DBG("hdl 0x%x mode %d intervel %d", handle, evt->mode, interval); + + conn->br.mode = evt->mode; + bt_conn_notify_mode_changed(conn, evt->mode, interval); + bt_conn_unref(conn); +} +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ + static int read_ext_features(void) { int i; diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index f865f8b848a34..8d9e12c5463e3 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -4433,6 +4433,23 @@ int bt_conn_br_exit_sniff_mode(struct bt_conn *conn) return bt_hci_cmd_send_sync(BT_HCI_OP_EXIT_SNIFF_MODE, buf, NULL); } +void bt_conn_notify_mode_changed(struct bt_conn *conn, uint8_t mode, uint16_t interval) +{ + struct bt_conn_cb *callback; + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) { + if (callback->br_mode_changed) { + callback->br_mode_changed(conn, mode, interval); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->br_mode_changed) { + cb->br_mode_changed(conn, mode, interval); + } + } +} + #endif /* CONFIG_BT_POWER_MODE_CONTROL */ #endif /* CONFIG_BT_CONN */ diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 14fd922b620d8..dad6ea9bd5f06 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -545,6 +545,11 @@ void bt_conn_identity_resolved(struct bt_conn *conn); void bt_conn_security_changed(struct bt_conn *conn, uint8_t hci_err, enum bt_security_err err); +#if defined(CONFIG_BT_POWER_MODE_CONTROL) +/* Notify higher layers that connection sniff mode changed */ +void bt_conn_notify_mode_changed(struct bt_conn *conn, uint8_t mode, uint16_t interval); +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ + /* Prepare a PDU to be sent over a connection */ #if defined(CONFIG_NET_BUF_LOG) struct net_buf *bt_conn_create_pdu_timeout_debug(struct net_buf_pool *pool, diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 11db5a820c29e..d1c6c44d932d9 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -3083,6 +3083,10 @@ static const struct event_handler normal_events[] = { sizeof(struct bt_hci_evt_remote_ext_features)), EVENT_HANDLER(BT_HCI_EVT_ROLE_CHANGE, bt_hci_role_change, sizeof(struct bt_hci_evt_role_change)), +#if defined(CONFIG_BT_POWER_MODE_CONTROL) + EVENT_HANDLER(BT_HCI_EVT_MODE_CHANGE, bt_hci_link_mode_change, + sizeof(struct bt_hci_evt_mode_change)), +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ EVENT_HANDLER(BT_HCI_EVT_SYNC_CONN_COMPLETE, bt_hci_synchronous_conn_complete, sizeof(struct bt_hci_evt_sync_conn_complete)), #endif /* CONFIG_BT_CLASSIC */ diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index e4a390af20aaf..b9434e88c12a0 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -563,6 +563,9 @@ void bt_hci_remote_name_request_complete(struct net_buf *buf); void bt_hci_read_remote_features_complete(struct net_buf *buf); void bt_hci_read_remote_ext_features_complete(struct net_buf *buf); void bt_hci_role_change(struct net_buf *buf); +#if defined(CONFIG_BT_POWER_MODE_CONTROL) +void bt_hci_link_mode_change(struct net_buf *buf); +#endif /* CONFIG_BT_POWER_MODE_CONTROL */ void bt_hci_synchronous_conn_complete(struct net_buf *buf); void bt_hci_le_df_connection_iq_report(struct net_buf *buf); From a0b97c95912138ea307073fc8aef6686edf75242 Mon Sep 17 00:00:00 2001 From: Kai Cheng Date: Tue, 21 Oct 2025 23:20:52 +0800 Subject: [PATCH 331/397] Bluetooth: shell: add sniff mode control command Add shell command for testing BR/EDR power mode control. Supports entering sniff mode with configurable parameters (min/max interval, attempt, timeout) and exiting back to active mode. Provides real-time feedback on mode change requests and status. Signed-off-by: Kai Cheng --- subsys/bluetooth/host/classic/shell/bredr.c | 53 +++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/subsys/bluetooth/host/classic/shell/bredr.c b/subsys/bluetooth/host/classic/shell/bredr.c index e21f64f2de381..dcb268749f371 100644 --- a/subsys/bluetooth/host/classic/shell/bredr.c +++ b/subsys/bluetooth/host/classic/shell/bredr.c @@ -1469,6 +1469,54 @@ static int cmd_set_role_switchable(const struct shell *sh, size_t argc, char *ar return 0; } +#if defined(CONFIG_BT_POWER_MODE_CONTROL) +static int cmd_set_sniff_mode(const struct shell *sh, size_t argc, char *argv[]) +{ + const char *action; + int err = 0; + + action = argv[1]; + if (!default_conn) { + shell_print(sh, "Not connected"); + return -ENOEXEC; + } + + if (!strcmp(action, "on")) { + uint16_t min_interval; + uint16_t max_interval; + uint16_t attempt; + uint16_t timeout; + + min_interval = atoi(argv[2]); + max_interval = atoi(argv[3]); + attempt = atoi(argv[4]); + timeout = atoi(argv[5]); + err = bt_conn_br_enter_sniff_mode(default_conn, min_interval, max_interval, attempt, + timeout); + if (err) { + shell_print(sh, "request enter sniff mode, err:%d", err); + } else { + shell_print(sh, + "request enter sniff mode, min_interval:%d, max_interval:%d, " + "attempt:%d, timeout:%d", + min_interval, max_interval, attempt, timeout); + } + } else if (!strcmp(action, "off")) { + err = bt_conn_br_exit_sniff_mode(default_conn); + if (err) { + shell_print(sh, "request enter active mode, err:%d", err); + } else { + shell_print(sh, "request enter active mode success"); + } + } else { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + return 0; +} +#endif + #if defined(CONFIG_BT_L2CAP_CONNLESS) static void connless_recv(struct bt_conn *conn, uint16_t psm, struct net_buf *buf) { @@ -1639,6 +1687,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(br_cmds, SHELL_CMD_ARG(switch-role, NULL, "", cmd_switch_role, 2, 0), SHELL_CMD_ARG(set-role-switchable, NULL, "", cmd_set_role_switchable, 2, 0), +#if defined(CONFIG_BT_POWER_MODE_CONTROL) + SHELL_CMD_ARG(set_sniff_mode, NULL, + " [min_interval] [max_interval] [attempt] [timeout]", + cmd_set_sniff_mode, 2, 4), +#endif SHELL_SUBCMD_SET_END ); From 0fa225e449ebe9635b85cfee4ee0bc62cfc53cb1 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 15:58:29 +0200 Subject: [PATCH 332/397] kconfiglib: node: add 'loc' attribute Replace 'filename' and 'linenr' usages with a single 'loc' attribute, which is a (filename, linenr) tuple. This simplifies code dealing with locations, and makes it explicitly constant. The original attributes are now provided via properties for compatibility. Signed-off-by: Luca Burelli --- scripts/kconfig/kconfiglib.py | 57 ++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index a2e0755048d51..071e6ecab3a61 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -503,9 +503,9 @@ def my_other_fn(kconf, name, arg_1, arg_2, ...): is None, there is no upper limit to the number of arguments. Passing an invalid number of arguments will generate a KconfigError exception. -Functions can access the current parsing location as kconf.filename/linenr. -Accessing other fields of the Kconfig object is not safe. See the warning -below. +Functions can access the current parsing location as kconf.loc, or individually +as kconf.filename/linenr. Accessing other fields of the Kconfig object is not +safe. See the warning below. Keep in mind that for a variable defined like 'foo = $(fn)', 'fn' will be called only when 'foo' is expanded. If 'fn' uses the parsing location and the @@ -1050,8 +1050,7 @@ def _init(self, filename, warn, warn_to_stderr, encoding): self.top_node.prompt = ("Main menu", self.y) self.top_node.parent = None self.top_node.dep = self.y - self.top_node.filename = filename - self.top_node.linenr = 1 + self.top_node.loc = (filename, 1) self.top_node.include_path = () # Parse the Kconfig files @@ -2935,8 +2934,7 @@ def _parse_block(self, end_token, parent, prev): node.is_configdefault = t0 is _T_CONFIGDEFAULT node.prompt = node.help = node.list = None node.parent = parent - node.filename = self.filename - node.linenr = self.linenr + node.loc = self.loc node.include_path = self._include_path sym.nodes.append(node) @@ -3031,8 +3029,7 @@ def _parse_block(self, end_token, parent, prev): node.prompt = (self._expect_str_and_eol(), self.y) node.visibility = self.y node.parent = parent - node.filename = self.filename - node.linenr = self.linenr + node.loc = self.loc node.include_path = self._include_path self.menus.append(node) @@ -3051,8 +3048,7 @@ def _parse_block(self, end_token, parent, prev): node.prompt = (self._expect_str_and_eol(), self.y) node.list = None node.parent = parent - node.filename = self.filename - node.linenr = self.linenr + node.loc = self.loc node.include_path = self._include_path self.comments.append(node) @@ -3083,8 +3079,7 @@ def _parse_block(self, end_token, parent, prev): node.is_menuconfig = True node.prompt = node.help = None node.parent = parent - node.filename = self.filename - node.linenr = self.linenr + node.loc = self.loc node.include_path = self._include_path choice.nodes.append(node) @@ -4001,7 +3996,7 @@ def is_num(s): for node in self.node_iter(): if sym in node.referenced: msg += "\n\n- Referenced at {}:{}:\n\n{}" \ - .format(node.filename, node.linenr, node) + .format(node.loc[0], node.loc[1], node) self._warn(msg) def _warn(self, msg, filename=None, linenr=None): @@ -4774,7 +4769,7 @@ def __repr__(self): if self.nodes: for node in self.nodes: - add("{}:{}".format(node.filename, node.linenr)) + add("{}:{}".format(*node.loc)) else: add("constant" if self.is_constant else "undefined") @@ -5380,7 +5375,7 @@ def __repr__(self): add("optional") for node in self.nodes: - add("{}:{}".format(node.filename, node.linenr)) + add("{}:{}".format(*node.loc)) return "<{}>".format(", ".join(fields)) @@ -5630,10 +5625,11 @@ class MenuNode(object): 'is_menuconfig' is just a hint on how to display the menu node. It's ignored internally by Kconfiglib, except when printing symbols. - filename/linenr: - The location where the menu node appears. The filename is relative to - $srctree (or to the current directory if $srctree isn't set), except - absolute paths are used for paths outside $srctree. + loc/filename/linenr: + The location where the menu node appears, as a (filename, linenr) tuple + or as individual properties. The filename is relative to $srctree (or to + the current directory if $srctree isn't set), except absolute paths are + used for paths outside $srctree. include_path: A tuple of (filename, linenr) tuples, giving the locations of the @@ -5649,15 +5645,14 @@ class MenuNode(object): """ __slots__ = ( "dep", - "filename", "help", "include_path", "is_menuconfig", "is_configdefault", "item", "kconfig", - "linenr", "list", + "loc", "next", "parent", "prompt", @@ -5679,6 +5674,20 @@ def __init__(self): self.implies = [] self.ranges = [] + @property + def filename(self): + """ + See the class documentation. + """ + return self.loc[0] + + @property + def linenr(self): + """ + See the class documentation. + """ + return self.loc[1] + @property def orig_prompt(self): """ @@ -5798,7 +5807,7 @@ def __repr__(self): if self.next: add("has next") - add("{}:{}".format(self.filename, self.linenr)) + add("{}:{}".format(*self.loc)) return "<{}>".format(", ".join(fields)) @@ -6477,7 +6486,7 @@ def _locs(sc): if sc.nodes: return "(defined at {})".format( - ", ".join("{0.filename}:{0.linenr}".format(node) + ", ".join("{}:{}".format(*node.loc) for node in sc.nodes)) return "(undefined)" From 6cd13dc310cd73fdbfb65e6893d4dfd1a8c09d91 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 15:59:07 +0200 Subject: [PATCH 333/397] kconfiglib: refactor Kconfig._warn() to use 'loc' Replace filename and linenr parameters to _warn() with a single loc element, which is a constant (filename, linenr) tuple that can be more efficiently passed and stored. Signed-off-by: Luca Burelli --- scripts/kconfig/kconfiglib.py | 55 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index 071e6ecab3a61..c30424f14ef97 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -851,6 +851,7 @@ class Kconfig(object): "_readline", "filename", "linenr", + "loc", "_include_path", "_filestack", "_line", @@ -1269,13 +1270,14 @@ def _load_config(self, filename, replace): for linenr, line in enumerate(f, 1): # The C tools ignore trailing whitespace line = line.rstrip() + loc = (filename, linenr) match = set_match(line) if match: name, val = match.groups() sym = get_sym(name) if not sym or not sym.nodes: - self._undef_assign(name, val, filename, linenr) + self._undef_assign(name, val, loc) continue if sym.orig_type in _BOOL_TRISTATE: @@ -1288,8 +1290,7 @@ def _load_config(self, filename, replace): self._warn("'{}' is not a valid value for the {} " "symbol {}. Assignment ignored." .format(val, TYPE_TO_STR[sym.orig_type], - sym.name_and_loc), - filename, linenr) + sym.name_and_loc), loc) continue val = val[0] @@ -1304,8 +1305,7 @@ def _load_config(self, filename, replace): TRI_TO_STR[prev_mode] != val: self._warn("both m and y assigned to symbols " - "within the same choice", - filename, linenr) + "within the same choice", loc) # Set the choice's mode sym.choice.set_value(val) @@ -1315,8 +1315,7 @@ def _load_config(self, filename, replace): if not match: self._warn("malformed string literal in " "assignment to {}. Assignment ignored." - .format(sym.name_and_loc), - filename, linenr) + .format(sym.name_and_loc), loc) continue val = unescape(match.group(1)) @@ -1330,15 +1329,14 @@ def _load_config(self, filename, replace): # rstrip()'d, so blank lines show up as "" here. if line and not line.lstrip().startswith("#"): self._warn("ignoring malformed line '{}'" - .format(line), - filename, linenr) + .format(line), loc) continue name = match.group(1) sym = get_sym(name) if not sym or not sym.nodes: - self._undef_assign(name, "n", filename, linenr) + self._undef_assign(name, "n", loc) continue if sym.orig_type not in _BOOL_TRISTATE: @@ -1349,7 +1347,7 @@ def _load_config(self, filename, replace): # Done parsing the assignment. Set the value. if sym._was_set: - self._assigned_twice(sym, val, filename, linenr) + self._assigned_twice(sym, val, loc) sym.set_value(val) @@ -1365,16 +1363,16 @@ def _load_config(self, filename, replace): if not choice._was_set: choice.unset_value() - def _undef_assign(self, name, val, filename, linenr): + def _undef_assign(self, name, val, loc): # Called for assignments to undefined symbols during .config loading self.missing_syms.append((name, val)) if self.warn_assign_undef: self._warn( "attempt to assign the value '{}' to the undefined symbol {}" - .format(val, name), filename, linenr) + .format(val, name), loc) - def _assigned_twice(self, sym, new_val, filename, linenr): + def _assigned_twice(self, sym, new_val, loc): # Called when a symbol is assigned more than once in a .config file # Use strings for bool/tristate user values in the warning @@ -1388,9 +1386,9 @@ def _assigned_twice(self, sym, new_val, filename, linenr): if user_val == new_val: if self.warn_assign_redun: - self._warn(msg, filename, linenr) + self._warn(msg, loc) elif self.warn_assign_override: - self._warn(msg, filename, linenr) + self._warn(msg, loc) def load_allconfig(self, filename): """ @@ -2232,6 +2230,8 @@ def _next_line(self): line = line[:-2] + self._readline() self.linenr += 1 + self.loc = (self.filename, self.linenr) + self._tokens = self._tokenize(line) # Initialize to 1 instead of 0 to factor out code from _parse_block() # and _parse_props(). They immediately fetch self._tokens[0]. @@ -2253,6 +2253,7 @@ def _line_after_help(self, line): line = line[:-2] + self._readline() self.linenr += 1 + self.loc = (self.filename, self.linenr) self._tokens = self._tokenize(line) self._reuse_tokens = True @@ -2425,8 +2426,7 @@ def _tokenize(self, s): if token is not _T_CHOICE: self._warn("style: quotes recommended around '{}' in '{}'" - .format(name, self._line.strip()), - self.filename, self.linenr) + .format(name, self._line.strip()), self.loc) token = name i = match.end() @@ -3222,7 +3222,7 @@ def _parse_props(self, node): self._warn("{1} has 'option env=\"{0}\"', " "but the environment variable {0} is not " "set".format(node.item.name, env_var), - self.filename, self.linenr) + self.loc) if env_var != node.item.name: self._warn("Kconfiglib expands environment variables " @@ -3232,7 +3232,7 @@ def _parse_props(self, node): "rename {} to {} (so that the symbol name " "matches the environment variable name)." .format(node.item.name, env_var), - self.filename, self.linenr) + self.loc) elif self._check_token(_T_DEFCONFIG_LIST): if not self.defconfig_list: @@ -3242,7 +3242,7 @@ def _parse_props(self, node): "symbols ({0} and {1}). Only {0} will be " "used.".format(self.defconfig_list.name, node.item.name), - self.filename, self.linenr) + self.loc) elif self._check_token(_T_MODULES): # To reduce warning spam, only warn if 'option modules' is @@ -3258,8 +3258,7 @@ def _parse_props(self, node): "Kconfiglib just assumes the symbol name " "MODULES, like older versions of the C " "implementation did when 'option modules' " - "wasn't used.", - self.filename, self.linenr) + "wasn't used.", self.loc) elif self._check_token(_T_ALLNOCONFIG_Y): if node.item.__class__ is not Symbol: @@ -3999,15 +3998,15 @@ def is_num(s): .format(node.loc[0], node.loc[1], node) self._warn(msg) - def _warn(self, msg, filename=None, linenr=None): + def _warn(self, msg, loc=None): # For printing general warnings if not self.warn: return msg = "warning: " + msg - if filename is not None: - msg = "{}:{}: {}".format(filename, linenr, msg) + if loc is not None: + msg = "{}:{}: {}".format(loc[0], loc[1], msg) self.warnings.append(msg) if self.warn_to_stderr: @@ -6824,7 +6823,7 @@ def _info_fn(kconf, _, msg): def _warning_if_fn(kconf, _, cond, msg): if cond == "y": - kconf._warn(msg, kconf.filename, kconf.linenr) + kconf._warn(msg, kconf.loc) return "" @@ -6854,7 +6853,7 @@ def _shell_fn(kconf, _, command): if stderr: kconf._warn("'{}' wrote to stderr: {}".format( command, "\n".join(stderr.splitlines())), - kconf.filename, kconf.linenr) + kconf.loc) # Universal newlines with splitlines() (to prevent e.g. stray \r's in # command output on Windows), trailing newline removal, and From b4a221bfef2612bd6344f772f2783c5f4c49a8a6 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 15:59:43 +0200 Subject: [PATCH 334/397] kconfiglib: add 'user_loc' to Symbol and Choice classes The 'user_loc' stores the location (filename and line number) where a symbol or choice was last set via a direct user selection. Signed-off-by: Luca Burelli --- scripts/kconfig/kconfiglib.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index c30424f14ef97..b97b6d35a0145 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -1308,7 +1308,7 @@ def _load_config(self, filename, replace): "within the same choice", loc) # Set the choice's mode - sym.choice.set_value(val) + sym.choice.set_value(val, loc) elif sym.orig_type is STRING: match = _conf_string_match(val) @@ -1349,7 +1349,7 @@ def _load_config(self, filename, replace): if sym._was_set: self._assigned_twice(sym, val, loc) - sym.set_value(val) + sym.set_value(val, loc) if replace: # If we're replacing the configuration, unset the symbols that @@ -4154,6 +4154,10 @@ class Symbol(object): most symbols. Undefined and constant symbols have an empty nodes list. Symbols defined in multiple locations get one node for each location. + user_loc: + A (filename, linenr) tuple indicating where the user value was set, or + None if the user hasn't set a value. + choice: Holds the parent Choice for choice symbols, and None for non-choice symbols. Doubles as a flag for whether a symbol is a choice symbol. @@ -4295,6 +4299,7 @@ class Symbol(object): "ranges", "rev_dep", "selects", + "user_loc", "user_value", "weak_rev_dep", ) @@ -4588,7 +4593,7 @@ def name_and_loc(self): """ return self.name + " " + _locs(self) - def set_value(self, value): + def set_value(self, value, loc=None): """ Sets the user value of the symbol. @@ -4621,6 +4626,9 @@ def set_value(self, value): Symbol.user_value. Kconfiglib will print a warning by default for invalid assignments, and set_value() will return False. + loc: + A (filename, linenr) tuple indicating where the value was set. + Returns True if the value is valid for the type of the symbol, and False otherwise. This only looks at the form of the value. For BOOL and TRISTATE symbols, check the Symbol.assignable attribute to see what @@ -4661,6 +4669,7 @@ def set_value(self, value): return False + self.user_loc = loc self.user_value = value self._was_set = True @@ -4683,6 +4692,7 @@ def unset_value(self): gotten a user value via Kconfig.load_config() or Symbol.set_value(). """ if self.user_value is not None: + self.user_loc = None self.user_value = None self._rec_invalidate_if_has_prompt() @@ -4827,6 +4837,7 @@ def __init__(self): self.implies = [] self.ranges = [] + self.user_loc = \ self.user_value = \ self.choice = \ self.env_var = \ @@ -5125,6 +5136,10 @@ class Choice(object): WARNING: Do not assign directly to this. It will break things. Call sym.set_value(2) on the choice symbol to be selected instead. + user_loc: + A (filename, linenr) tuple indicating where the user value was set, or + None if the user hasn't set a value. + visibility: See the Symbol class documentation. Acts on the value (mode). @@ -5195,6 +5210,7 @@ class Choice(object): "nodes", "orig_type", "syms", + "user_loc", "user_selection", "user_value", ) @@ -5274,7 +5290,7 @@ def selection(self): self._cached_selection = self._selection() return self._cached_selection - def set_value(self, value): + def set_value(self, value, loc=None): """ Sets the user value (mode) of the choice. Like for Symbol.set_value(), the visibility might truncate the value. Choices without the 'optional' @@ -5309,6 +5325,7 @@ def set_value(self, value): return False + self.user_loc = loc self.user_value = value self._was_set = True self._rec_invalidate() @@ -5321,6 +5338,7 @@ def unset_value(self): the user had never touched the mode or any of the choice symbols. """ if self.user_value is not None or self.user_selection: + self.user_loc = None self.user_value = self.user_selection = None self._rec_invalidate() From 6778602caa16cd3c520b87cbb60551de95dae8ff Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 16:00:07 +0200 Subject: [PATCH 335/397] kconfiglib: add 'loc' to reverse dependencies Store the location (filename and line number) where a 'select', 'imply', 'range' or 'default' was added to a Symbol or Choice. Signed-off-by: Luca Burelli --- scripts/kconfig/kconfiglib.py | 101 +++++++++++++++++----------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index b97b6d35a0145..970eed9e775e6 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -1137,7 +1137,7 @@ def defconfig_filename(self): See the class documentation. """ if self.defconfig_list: - for filename, cond in self.defconfig_list.defaults: + for filename, cond, _ in self.defconfig_list.defaults: if expr_value(cond): try: with self._open_config(filename.str_value) as f: @@ -3170,7 +3170,7 @@ def _parse_props(self, node): self._parse_error("only symbols can select") node.selects.append((self._expect_nonconst_sym(), - self._parse_cond())) + self._parse_cond(), self.loc)) elif t0 is None: # Blank line @@ -3178,26 +3178,26 @@ def _parse_props(self, node): elif t0 is _T_DEFAULT: node.defaults.append((self._parse_expr(False), - self._parse_cond())) + self._parse_cond(), self.loc)) elif t0 in _DEF_TOKEN_TO_TYPE: self._set_type(node.item, _DEF_TOKEN_TO_TYPE[t0]) node.defaults.append((self._parse_expr(False), - self._parse_cond())) + self._parse_cond(), self.loc)) elif t0 is _T_PROMPT: self._parse_prompt(node) elif t0 is _T_RANGE: node.ranges.append((self._expect_sym(), self._expect_sym(), - self._parse_cond())) + self._parse_cond(), self.loc)) elif t0 is _T_IMPLY: if node.item.__class__ is not Symbol: self._parse_error("only symbols can imply") node.implies.append((self._expect_nonconst_sym(), - self._parse_cond())) + self._parse_cond(), self.loc)) elif t0 is _T_VISIBLE: if not self._check_token(_T_IF): @@ -3217,7 +3217,7 @@ def _parse_props(self, node): if env_var in os.environ: node.defaults.append( (self._lookup_const_sym(os.environ[env_var]), - self.y)) + self.y, "env[{}]".format(env_var))) else: self._warn("{1} has 'option env=\"{0}\"', " "but the environment variable {0} is not " @@ -3493,7 +3493,7 @@ def _build_dep(self): depend_on(sym, node.prompt[1]) # The default values and their conditions - for value, cond in sym.defaults: + for value, cond, _ in sym.defaults: depend_on(sym, value) depend_on(sym, cond) @@ -3502,7 +3502,7 @@ def _build_dep(self): depend_on(sym, sym.weak_rev_dep) # The ranges along with their conditions - for low, high, cond in sym.ranges: + for low, high, cond, _ in sym.ranges: depend_on(sym, low) depend_on(sym, high) depend_on(sym, cond) @@ -3528,7 +3528,7 @@ def _build_dep(self): depend_on(choice, node.prompt[1]) # The default symbol conditions - for _, cond in choice.defaults: + for _, cond, _ in choice.defaults: depend_on(choice, cond) def _add_choice_deps(self): @@ -3573,7 +3573,7 @@ def _finalize_sym(self, sym): # Add the defaults to the node, with the requirement that # direct dependencies are respected. The original order # of the default statements between nodes is preserved. - default = (d[0], self._make_and(sym.direct_dep, d[1])) + default = (d[0], self._make_and(sym.direct_dep, d[1]), d[2]) sym.defaults.insert(inserted + idx, default) inserted += 1 @@ -3684,23 +3684,23 @@ def _propagate_deps(self, node, visible_if): # Propagate dependencies to defaults if cur.defaults: - cur.defaults = [(default, self._make_and(cond, dep)) - for default, cond in cur.defaults] + cur.defaults = [(default, self._make_and(cond, dep), loc) + for default, cond, loc in cur.defaults] # Propagate dependencies to ranges if cur.ranges: - cur.ranges = [(low, high, self._make_and(cond, dep)) - for low, high, cond in cur.ranges] + cur.ranges = [(low, high, self._make_and(cond, dep), loc) + for low, high, cond, loc in cur.ranges] # Propagate dependencies to selects if cur.selects: - cur.selects = [(target, self._make_and(cond, dep)) - for target, cond in cur.selects] + cur.selects = [(target, self._make_and(cond, dep), loc) + for target, cond, loc in cur.selects] # Propagate dependencies to implies if cur.implies: - cur.implies = [(target, self._make_and(cond, dep)) - for target, cond in cur.implies] + cur.implies = [(target, self._make_and(cond, dep), loc) + for target, cond, loc in cur.implies] elif cur.prompt: # Not a symbol/choice # Propagate dependencies to the prompt. 'visible if' is only @@ -3739,14 +3739,14 @@ def _add_props_to_sym(self, node): sym.implies += node.implies # Modify the reverse dependencies of the selected symbol - for target, cond in node.selects: + for target, cond, _ in node.selects: target.rev_dep = self._make_or( target.rev_dep, self._make_and(sym, cond)) # Modify the weak reverse dependencies of the implied # symbol - for target, cond in node.implies: + for target, cond, _ in node.implies: target.weak_rev_dep = self._make_or( target.weak_rev_dep, self._make_and(sym, cond)) @@ -3775,7 +3775,7 @@ def num_ok(sym, type_): # A helper function could be factored out here, but keep it # speedy/straightforward - for target_sym, _ in sym.selects: + for target_sym, _, _ in sym.selects: if target_sym.orig_type not in _BOOL_TRISTATE_UNKNOWN: self._warn("{} selects the {} symbol {}, which is not " "bool or tristate" @@ -3783,7 +3783,7 @@ def num_ok(sym, type_): TYPE_TO_STR[target_sym.orig_type], target_sym.name_and_loc)) - for target_sym, _ in sym.implies: + for target_sym, _, _ in sym.implies: if target_sym.orig_type not in _BOOL_TRISTATE_UNKNOWN: self._warn("{} implies the {} symbol {}, which is not " "bool or tristate" @@ -3792,7 +3792,7 @@ def num_ok(sym, type_): target_sym.name_and_loc)) elif sym.orig_type: # STRING/INT/HEX - for default, _ in sym.defaults: + for default, _, _ in sym.defaults: if default.__class__ is not Symbol: raise KconfigError( "the {} symbol {} has a malformed default {} -- " @@ -3834,7 +3834,7 @@ def num_ok(sym, type_): .format(TYPE_TO_STR[sym.orig_type], sym.name_and_loc)) else: - for low, high, _ in sym.ranges: + for low, high, _, _ in sym.ranges: if not num_ok(low, sym.orig_type) or \ not num_ok(high, sym.orig_type): @@ -3872,7 +3872,7 @@ def warn_select_imply(sym, expr, expr_type): else: self._warn(choice.name_and_loc + " defined without a prompt") - for default, _ in choice.defaults: + for default, _, _ in choice.defaults: if default.__class__ is not Symbol: raise KconfigError( "{} has a malformed default {}" @@ -4163,8 +4163,8 @@ class Symbol(object): symbols. Doubles as a flag for whether a symbol is a choice symbol. defaults: - List of (default, cond) tuples for the symbol's 'default' properties. For - example, 'default A && B if C || D' is represented as + List of (default, cond, loc) tuples for the symbol's 'default' + properties. For example, 'default A && B if C || D' is represented as ((AND, A, B), (OR, C, D)). If no condition was given, 'cond' is self.kconfig.y. @@ -4172,9 +4172,9 @@ class Symbol(object): 'default' conditions. selects: - List of (symbol, cond) tuples for the symbol's 'select' properties. For - example, 'select A if B && C' is represented as (A, (AND, B, C)). If no - condition was given, 'cond' is self.kconfig.y. + List of (symbol, cond, loc) tuples for the symbol's 'select' properties. + For example, 'select A if B && C' is represented as (A, (AND, B, C)). If + no condition was given, 'cond' is self.kconfig.y. Note that 'depends on' and parent dependencies are propagated to 'select' conditions. @@ -4183,9 +4183,9 @@ class Symbol(object): Like 'selects', for imply. ranges: - List of (low, high, cond) tuples for the symbol's 'range' properties. For - example, 'range 1 2 if A' is represented as (1, 2, A). If there is no - condition, 'cond' is self.kconfig.y. + List of (low, high, cond, loc) tuples for the symbol's 'range' + properties. For example, 'range 1 2 if A' is represented as (1, 2, A). If + there is no condition, 'cond' is self.kconfig.y. Note that 'depends on' and parent dependencies are propagated to 'range' conditions. @@ -4357,7 +4357,7 @@ def str_value(self): base = _TYPE_TO_BASE[self.orig_type] # Check if a range is in effect - for low_expr, high_expr, cond in self.ranges: + for low_expr, high_expr, cond, _ in self.ranges: if expr_value(cond): has_active_range = True @@ -4400,7 +4400,7 @@ def str_value(self): # Used to implement the warning below has_default = False - for sym, cond in self.defaults: + for sym, cond, _ in self.defaults: if expr_value(cond): has_default = self._write_to_conf = True @@ -4445,7 +4445,7 @@ def str_value(self): val = self.user_value else: # Otherwise, look at defaults - for sym, cond in self.defaults: + for sym, cond, _ in self.defaults: if expr_value(cond): val = sym.str_value self._write_to_conf = True @@ -4499,7 +4499,7 @@ def tri_value(self): # Otherwise, look at defaults and weak reverse dependencies # (implies) - for default, cond in self.defaults: + for default, cond, _ in self.defaults: dep_val = expr_value(cond) if dep_val: val = min(expr_value(default), dep_val) @@ -4970,7 +4970,7 @@ def _str_default(self): # Defaults, selects, and implies do not affect choice symbols if not self.choice: - for default, cond in self.defaults: + for default, cond, _ in self.defaults: cond_val = expr_value(cond) if cond_val: val = min(expr_value(default), cond_val) @@ -4988,7 +4988,7 @@ def _str_default(self): return TRI_TO_STR[val] if self.orig_type: # STRING/INT/HEX - for default, cond in self.defaults: + for default, cond, _ in self.defaults: if expr_value(cond): return default.str_value @@ -5490,7 +5490,7 @@ def _selection(self): def _selection_from_defaults(self): # Check if we have a default - for sym, cond in self.defaults: + for sym, cond, _ in self.defaults: # The default symbol must be visible too if expr_value(cond) and sym.visibility: return sym @@ -5587,7 +5587,8 @@ class MenuNode(object): orig_ranges: These work the like the corresponding attributes without orig_*, but omit any dependencies propagated from 'depends on' and surrounding 'if's (the - direct dependencies, stored in MenuNode.dep). + direct dependencies, stored in MenuNode.dep). These also strip any + location information. One use for this is generating less cluttered documentation, by only showing the direct dependencies in one place. @@ -5720,7 +5721,7 @@ def orig_defaults(self): See the class documentation. """ return [(default, self._strip_dep(cond)) - for default, cond in self.defaults] + for default, cond, _ in self.defaults] @property def orig_selects(self): @@ -5728,7 +5729,7 @@ def orig_selects(self): See the class documentation. """ return [(select, self._strip_dep(cond)) - for select, cond in self.selects] + for select, cond, _ in self.selects] @property def orig_implies(self): @@ -5736,7 +5737,7 @@ def orig_implies(self): See the class documentation. """ return [(imply, self._strip_dep(cond)) - for imply, cond in self.implies] + for imply, cond, _ in self.implies] @property def orig_ranges(self): @@ -5744,7 +5745,7 @@ def orig_ranges(self): See the class documentation. """ return [(low, high, self._strip_dep(cond)) - for low, high, cond in self.ranges] + for low, high, cond, _ in self.ranges] @property def referenced(self): @@ -5761,19 +5762,19 @@ def referenced(self): if self.item is MENU: res |= expr_items(self.visibility) - for value, cond in self.defaults: + for value, cond, _ in self.defaults: res |= expr_items(value) res |= expr_items(cond) - for value, cond in self.selects: + for value, cond, _ in self.selects: res.add(value) res |= expr_items(cond) - for value, cond in self.implies: + for value, cond, _ in self.implies: res.add(value) res |= expr_items(cond) - for low, high, cond in self.ranges: + for low, high, cond, _ in self.ranges: res.add(low) res.add(high) res |= expr_items(cond) From d7d3994ecea105c5d40c3e5bb31205571a9e366a Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 16:00:38 +0200 Subject: [PATCH 336/397] kconfiglib: track origin for symbol values Track information about what caused a value to be set in the 'origin' property of Symbol. 'imply' and 'select' dependencies do not have a location associated with them, so in those cases the location is a string representation of the dependency expression. For defaults and user values, the location in the Kconfig file is stored. Signed-off-by: Luca Burelli --- scripts/kconfig/kconfiglib.py | 87 +++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 4 deletions(-) diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index 970eed9e775e6..316a4c4e40f4f 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -4113,6 +4113,24 @@ class Symbol(object): The visibility of the symbol. One of 0, 1, 2, representing n, m, y. See the module documentation for an overview of symbol values and visibility. + origin: + A (kind, loc) tuple containing information about how and where a symbol's + final value is derived, or None if the symbol is hidden from the + configuration and can't be given a value. + + There can be 5 kinds of origins of a symbol's value: + - "assign", when it was set by the user (via CONFIG_xx=y) + - "default", when it was set by a 'default' property + - "select", when it was set by a 'select' statement on another symbol + - "imply", when it was set by an 'imply' statement on another symbol + - "unset", when none of the above applied + The location can be either: + - None, if the value is unset, has an implicit default, or no location + was provided in set_value(); + - a (filename, linenr) tuple, if the value was set by a single line; + - a list of strings describing the conditions that resulted in the + value being set, in case of reverse dependencies (select and imply). + config_string: The .config assignment string that would get written out for the symbol by Kconfig.write_config(). Returns the empty string if no .config @@ -4281,6 +4299,7 @@ class Symbol(object): "_cached_vis", "_dependents", "_old_val", + "_origin", "_visited", "_was_set", "_write_to_conf", @@ -4342,6 +4361,7 @@ def str_value(self): return self.name val = "" + self._origin = None # Warning: See Symbol._rec_invalidate(), and note that this is a hidden # function call (property magic) vis = self.visibility @@ -4393,6 +4413,7 @@ def str_value(self): # specified in the assignment (with or without "0x", etc.) val = self.user_value use_defaults = False + self._origin = _T_CONFIG, self.user_loc if use_defaults: # No user value or invalid user value. Look at defaults. @@ -4400,11 +4421,12 @@ def str_value(self): # Used to implement the warning below has_default = False - for sym, cond, _ in self.defaults: + for sym, cond, loc in self.defaults: if expr_value(cond): has_default = self._write_to_conf = True val = sym.str_value + self._origin = _T_DEFAULT, loc if _is_base_n(val, base): val_num = int(val, base) @@ -4414,6 +4436,7 @@ def str_value(self): break else: val_num = 0 # strtoll() on empty string + self._origin = _T_DEFAULT, None # This clamping procedure runs even if there's no default if has_active_range: @@ -4443,12 +4466,14 @@ def str_value(self): if vis and self.user_value is not None: # If the symbol is visible and has a user value, use that val = self.user_value + self._origin = _T_CONFIG, self.user_loc else: # Otherwise, look at defaults - for sym, cond, _ in self.defaults: + for sym, cond, loc in self.defaults: if expr_value(cond): val = sym.str_value self._write_to_conf = True + self._origin = _T_DEFAULT, loc break # env_var corresponds to SYMBOL_AUTO in the C implementation, and is @@ -4494,17 +4519,19 @@ def tri_value(self): if vis and self.user_value is not None: # If the symbol is visible and has a user value, use that val = min(self.user_value, vis) + self._origin = _T_CONFIG, self.user_loc else: # Otherwise, look at defaults and weak reverse dependencies # (implies) - for default, cond, _ in self.defaults: + for default, cond, loc in self.defaults: dep_val = expr_value(cond) if dep_val: val = min(expr_value(default), dep_val) if val: self._write_to_conf = True + self._origin = _T_DEFAULT, loc break # Weak reverse dependencies are only considered if our @@ -4513,6 +4540,7 @@ def tri_value(self): if dep_val and expr_value(self.direct_dep): val = max(dep_val, val) self._write_to_conf = True + self._origin = _T_IMPLY, None # expanded later # Reverse (select-related) dependencies take precedence dep_val = expr_value(self.rev_dep) @@ -4522,6 +4550,7 @@ def tri_value(self): val = max(dep_val, val) self._write_to_conf = True + self._origin = _T_SELECT, None # expanded later # m is promoted to y for (1) bool symbols and (2) symbols with a # weak_rev_dep (from imply) of y @@ -4534,6 +4563,8 @@ def tri_value(self): # the visibility of choice symbols, so it's sufficient to just # check the visibility of the choice symbols themselves. val = 2 if self.choice.selection is self else 0 + self._origin = self.choice._origin \ + if self.choice.selection is self else None elif vis and self.user_value: # Visible choice symbol in m-mode choice, with set non-0 user value @@ -4560,6 +4591,38 @@ def visibility(self): self._cached_vis = _visibility(self) return self._cached_vis + @property + def origin(self): + """ + See the class documentation. + """ + # Reading 'str_value' computes _write_to_conf and _origin. + _ = self.str_value + if not self._write_to_conf: + return None + + if not self._origin: + return (KIND_TO_STR[UNKNOWN], None) + + kind, loc = self._origin + + if kind == _T_SELECT: + # calculate subexpressions that contribute to the value + loc = [ expr_str(subexpr) + for subexpr in split_expr(self.rev_dep, OR) + if expr_value(subexpr) ] + elif kind == _T_IMPLY: + # calculate subexpressions that contribute to the value + loc = [ expr_str(subexpr) + for subexpr in split_expr(self.weak_rev_dep, OR) + if expr_value(subexpr) ] + elif isinstance(loc, tuple) and not os.path.isabs(loc[0]): + # convert filename to absolute + fn, ln = loc + loc = os.path.abspath(os.path.join(self.kconfig.srctree, fn)), ln + + return (KIND_TO_STR[kind], loc) + @property def config_string(self): """ @@ -4841,6 +4904,7 @@ def __init__(self): self.user_value = \ self.choice = \ self.env_var = \ + self._origin = \ self._cached_str_val = self._cached_tri_val = self._cached_vis = \ self._cached_assignable = None @@ -5199,6 +5263,7 @@ class Choice(object): "_cached_selection", "_cached_vis", "_dependents", + "_origin", "_visited", "_was_set", "defaults", @@ -5442,6 +5507,7 @@ def __init__(self): self.name = \ self.user_value = self.user_selection = \ + self.user_loc = self._origin = \ self._cached_vis = self._cached_assignable = None self._cached_selection = _NO_CACHED_SELECTION @@ -5483,6 +5549,7 @@ def _selection(self): # Use the user selection if it's visible if self.user_selection and self.user_selection.visibility: + self._origin = _T_CONFIG, self.user_loc return self.user_selection # Otherwise, check if we have a default @@ -5490,20 +5557,23 @@ def _selection(self): def _selection_from_defaults(self): # Check if we have a default - for sym, cond, _ in self.defaults: + for sym, cond, loc in self.defaults: # The default symbol must be visible too if expr_value(cond) and sym.visibility: + self._origin = _T_DEFAULT, loc return sym # Otherwise, pick the first visible symbol, if any for sym in self.syms: if sym.visibility: + self._origin = _T_DEFAULT, None return sym # Couldn't find a selection return None def _invalidate(self): + self.user_loc = self._origin = \ self._cached_vis = self._cached_assignable = None self._cached_selection = _NO_CACHED_SELECTION @@ -7185,6 +7255,15 @@ def _shell_fn(kconf, _, command): GREATER_EQUAL, }) +# Origin kinds map +KIND_TO_STR = { + UNKNOWN: "unset", # value not set + _T_CONFIG: "assign", # explicit assignment + _T_DEFAULT: "default", # 'default' statement + _T_SELECT: "select", # 'select' statement + _T_IMPLY: "imply", # 'imply' statement +} + # Helper functions for getting compiled regular expressions, with the needed # matching function returned directly as a small optimization. # From 947db8e04f0f17d7ccb4ffbefa997e56d583ac06 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 17:01:49 +0200 Subject: [PATCH 337/397] kconfig: collect and save trace data Collect and save trace data for all symbols in the merged configuration. This includes information about where each symbol was defined or assigned, which can be useful for debugging complex Kconfig setups. The trace data includes the following information for each symbol: - Name - Visibility - Type - Value - Kind and location of value origin (as defined in kconfiglib) The trace data is saved for later use in two formats: a binary pickle file and a human-readable JSON file. Signed-off-by: Luca Burelli --- scripts/kconfig/kconfig.py | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/scripts/kconfig/kconfig.py b/scripts/kconfig/kconfig.py index 4e4e08631798e..ddc98e7bd9a93 100755 --- a/scripts/kconfig/kconfig.py +++ b/scripts/kconfig/kconfig.py @@ -16,7 +16,9 @@ # Also does various checks (most via Kconfiglib warnings). import argparse +import json import os +import pickle import re import sys import textwrap @@ -29,7 +31,9 @@ OR, TRI_TO_STR, TRISTATE, + TYPE_TO_STR, Kconfig, + Symbol, expr_str, expr_value, split_expr, @@ -132,6 +136,13 @@ def main(): print(kconf.write_config(args.config_out)) print(kconf.write_autoconf(args.header_out)) + # Write value origin information for the merged configuration + trace_data = collect_trace_data(kconf) + with open(args.config_out + '-trace.pickle', 'wb') as f: + pickle.dump(trace_data, f) + with open(args.config_out + '-trace.json', 'w') as f: + json.dump(trace_data, f, indent=2) + # Write the list of parsed Kconfig files to a file write_kconfig_filenames(kconf, args.kconfig_list_out) @@ -286,6 +297,44 @@ def promptless(sym): return not any(node.prompt for node in sym.nodes) +def collect_trace_data(kconf): + """ + Collects trace data for all symbols in 'kconf'. The output is currently a + list of 6-tuples with one entry per symbol definition, with the following + layout: + + (name, visibility, type, value, kind, location) + + where the first 4 entries are the string representation of the symbol's + properties, and 'kind' and 'location' are taken from its 'origin' + attribute. + """ + + # NOTE: this data is used by scripts/kconfig/traceconfig.py and the tests + # under tests/kconfig/tracing. Make sure to keep them aligned if the + # format changes in any way. + + trace_data = [] + for node in kconf.node_iter(True): + item = node.item + if not isinstance(item, Symbol): + continue + + origin = item.origin + if origin is None: + continue + + name = kconf.config_prefix + item.name + kind, loc = origin + value = None if kind == "unset" else item.str_value + + trace_entry = (name, TRI_TO_STR[item.visibility], + TYPE_TO_STR[item.type], value, kind, loc) + trace_data.append(trace_entry) + + return trace_data + + def write_kconfig_filenames(kconf, kconfig_list_path): # Writes a sorted list with the absolute paths of all parsed Kconfig files # to 'kconfig_list_path'. The paths are realpath()'d, and duplicates are From 2cece5080e6870eb7797aaa77811a5f2134e233e Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 17:07:12 +0200 Subject: [PATCH 338/397] traceconfig: add target to export value origin traces to Markdown The new 'traceconfig' target generates a Markdown file listing all configuration symbols, their values, and where those values originated (user assignment, default, selection, implication, or unset). Signed-off-by: Luca Burelli --- cmake/modules/kconfig.cmake | 8 ++- doc/build/kconfig/index.rst | 1 + doc/build/kconfig/tips.rst | 2 + doc/build/kconfig/tracing.rst | 59 +++++++++++++++++ scripts/kconfig/traceconfig.py | 118 +++++++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 doc/build/kconfig/tracing.rst create mode 100755 scripts/kconfig/traceconfig.py diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index 60667eb6444bd..1a6332298ba64 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -191,7 +191,13 @@ set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_hardenconfig ${ZEPHYR_BASE}/scripts/kconfig/hardenconfig.py ) -set_ifndef(KCONFIG_TARGETS menuconfig guiconfig hardenconfig) +set(EXTRA_KCONFIG_TARGET_COMMAND_FOR_traceconfig + ${ZEPHYR_BASE}/scripts/kconfig/traceconfig.py + ${DOTCONFIG} + ${PROJECT_BINARY_DIR}/kconfig-trace.md + ) + +set_ifndef(KCONFIG_TARGETS menuconfig guiconfig hardenconfig traceconfig) foreach(kconfig_target ${KCONFIG_TARGETS} diff --git a/doc/build/kconfig/index.rst b/doc/build/kconfig/index.rst index b59213ded02a8..5c09cf7ea9872 100644 --- a/doc/build/kconfig/index.rst +++ b/doc/build/kconfig/index.rst @@ -25,6 +25,7 @@ tips and best practices for writing :file:`Kconfig` files. :maxdepth: 1 menuconfig.rst + tracing.rst setting.rst tips.rst preprocessor-functions.rst diff --git a/doc/build/kconfig/tips.rst b/doc/build/kconfig/tips.rst index 0f4dfe4671212..ab1653424bce1 100644 --- a/doc/build/kconfig/tips.rst +++ b/doc/build/kconfig/tips.rst @@ -375,6 +375,8 @@ error-prone, since it can be hard to spot that the same dependency is added twice. +.. _stuck_symbols: + "Stuck" symbols in menuconfig and guiconfig ******************************************* diff --git a/doc/build/kconfig/tracing.rst b/doc/build/kconfig/tracing.rst new file mode 100644 index 0000000000000..b1b11640818ac --- /dev/null +++ b/doc/build/kconfig/tracing.rst @@ -0,0 +1,59 @@ +Tracing values to their source +############################## + +The merged configuration saved to :file:`zephyr/.config` contains the result of +applying the user configuration file to the whole tree of Kconfig files. This +process can be hard to follow, especially when invisible symbols are being +implicitly selected from anywhere in the tree. To help with this, the +``traceconfig`` target can be used to generate a file in the build directory +that details how each symbol got its final value. + +After building the Zephyr project as usual, the Kconfig trace can be generated +with either of these commands: + + .. code-block:: bash + + west build -t traceconfig + + .. code-block:: bash + + ninja traceconfig + +.. note:: + The generated information is only useful on a clean build, because otherwise + the ``.config`` file "pins" all settings to a specific value (as described + in :ref:`Stuck symbols `). Therefore, it is recommended to + run a :ref:`pristine build ` before generating the + trace. + +The output will be in the :file:`zephyr/kconfig-trace.md` file in the build +directory. This file is best viewed within IDEs to take advantage of Markdown +elements (tables, highlighting, clickable links), but can easily be understood +even when opened directly with any text editor. + +The report is divided in three sections: + +#. Visible symbols +#. Invisible symbols +#. Unset symbols + +For sections 1 and 2, a table is presented where each symbol is shown with its +type, name, and current value. The fourth column details the kind of statement +that resulted in the value being applied, and can be one of the following: + + - *assigned*, when an explicit assignment, of the form ``CONFIG_xxx=y``, is + read from a config file; + + - *default*, when there was no user assignment, but an applicable default + value was read from Kconfig tree; + + - *selected* or *implied*, when a ``select`` or ``imply`` statement from a + separate symbol caused the symbol to be set. + +The fifth column details the location for the source statement. For the first +two kinds of statements, the exact location (file name and line number) is +provided; in the latter cases, it contains the expressions that resulted in the +symbol being set. + +Finally, section 3 simply lists all undefined symbols. These have no additional +information since they never received a value by any of the above means. diff --git a/scripts/kconfig/traceconfig.py b/scripts/kconfig/traceconfig.py new file mode 100755 index 0000000000000..ca22fb093ea5c --- /dev/null +++ b/scripts/kconfig/traceconfig.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import os +import pickle + +from tabulate import tabulate + +KIND_TO_COL = { + "unset": "not set", + "default": "default", + "assign": "assigned", + "select": "selected", + "imply": "implied", +} + + +def source_link(refpath, fn, ln): + if refpath: + fn = os.path.relpath(fn, refpath) + + link_fn = fn + disp_fn = os.path.normpath(fn).replace("../", "").replace("_", "\\_") + + return f"[{disp_fn}:{ln}](<{link_fn}#L{ln}>)" + + +def write_markdown(trace_data, output): + sections = {"user": [], "hidden": [], "unset": []} + + if os.name == "nt": + # relative paths on Windows can't span drives, so don't use them + # generated links will be absolute + refpath = None + else: + refpath = os.path.dirname(os.path.abspath(output)) + + for sym in trace_data: + sym_name, sym_vis, sym_type, sym_value, sym_src, sym_loc = sym + if sym_vis == "n": + section = "hidden" + elif sym_src == "unset": + section = "unset" + else: + section = "user" + + if section == "user": + sym_name = f"`{sym_name}`" + elif section == "hidden": + sym_name = f"`{sym_name}` (h)" + + if sym_type == "string" and sym_value is not None: + sym_value = f'"{sym_value}"'.replace("_", "\\_") + + if isinstance(sym_loc, tuple): + sym_loc = source_link(refpath, *sym_loc) + elif isinstance(sym_loc, list): + sym_loc = " ||
".join(f"`{loc}`" for loc in sym_loc) + sym_loc = sym_loc.replace("|", "\\|") + elif sym_loc is None and sym_src == "default": + sym_loc = "_(implicit)_" + + sym_src = KIND_TO_COL[sym_src] + + sections[section].append((sym_type, sym_name, sym_value, sym_src, sym_loc)) + + lines = [] + add = lines.append + + headers = ["Type", "Name", "Value", "Source", "Location"] + colaligns = ["right", "left", "right", "center", "left"] + + add("\n## Visible symbols\n\n") + add( + tabulate( + sorted(sections["user"], key=lambda x: x[1]), + headers=headers, + tablefmt='pipe', + colalign=colaligns, + ) + ) + + add("\n\n## Invisible symbols\n\n") + add( + tabulate( + sorted(sections["hidden"], key=lambda x: x[1]), + headers=headers, + tablefmt='pipe', + colalign=colaligns, + ) + ) + + add("\n\n## Unset symbols\n\n") + for sym_name in sorted(x[1] for x in sections["unset"]): + add(f" # {sym_name} is not set\n") + + with open(output, "w") as f: + f.writelines(lines) + + +def main(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("dotconfig_file", help="Input merged .config file") + parser.add_argument("output_file", help="Output Markdown file") + parser.add_argument("kconfig_file", help="Top-level Kconfig file", nargs="?") + + args = parser.parse_args() + + with open(args.dotconfig_file + '-trace.pickle', 'rb') as f: + trace_data = pickle.load(f) + write_markdown(trace_data, args.output_file) + + +if __name__ == '__main__': + main() From 2b71067aab91cd5be928b2ec758d93c8577ed10f Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 19 Sep 2025 18:38:18 +0200 Subject: [PATCH 339/397] tests/kconfig: add Kconfig origin tracing test Add a test case that verifies Kconfig value origin traces are correctly generated in both JSON and pickle formats. The test includes a sample Kconfig configuration with dependencies, selections, and choices to cover various scenarios. A validation script checks the generated source origin data against expected values. In addition, the 'traceconfig' target is called to test the generation of the Markdown file with the Kconfig trace report. Signed-off-by: Luca Burelli --- tests/kconfig/tracing/CMakeLists.txt | 25 ++++ tests/kconfig/tracing/Kconfig | 34 ++++++ tests/kconfig/tracing/prj.conf | 7 ++ tests/kconfig/tracing/src/main.c | 10 ++ tests/kconfig/tracing/testcase.yaml | 11 ++ tests/kconfig/tracing/validate_tracing.py | 142 ++++++++++++++++++++++ 6 files changed, 229 insertions(+) create mode 100644 tests/kconfig/tracing/CMakeLists.txt create mode 100644 tests/kconfig/tracing/Kconfig create mode 100644 tests/kconfig/tracing/prj.conf create mode 100644 tests/kconfig/tracing/src/main.c create mode 100644 tests/kconfig/tracing/testcase.yaml create mode 100644 tests/kconfig/tracing/validate_tracing.py diff --git a/tests/kconfig/tracing/CMakeLists.txt b/tests/kconfig/tracing/CMakeLists.txt new file mode 100644 index 0000000000000..1a2b1845e5601 --- /dev/null +++ b/tests/kconfig/tracing/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +# will never be created so the check runs every time +set(output_file ${PROJECT_BINARY_DIR}/validate_tracing_output.txt) + +add_custom_command( + COMMENT "Testing Kconfig value origin traces" + OUTPUT ${output_file} + DEPENDS + ${logical_target_for_zephyr_elf} + $<$:native_runner_executable> + COMMAND ${PYTHON_EXECUTABLE} ${APPLICATION_SOURCE_DIR}/validate_tracing.py ${DOTCONFIG} + COMMAND ${WEST} build -t traceconfig +) + +add_custom_target(validate_traces ALL DEPENDS ${output_file}) + +project(check_tracing) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/kconfig/tracing/Kconfig b/tests/kconfig/tracing/Kconfig new file mode 100644 index 0000000000000..86d66a0841bb6 --- /dev/null +++ b/tests/kconfig/tracing/Kconfig @@ -0,0 +1,34 @@ +# Copyright 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +# Note that line numbers in this file are important for test scripts. Ensure +# these match the expectations in validate_srcrefs.py. + +source "Kconfig.zephyr" + +config MAIN_FLAG + bool + +config MAIN_FLAG_DEPENDENCY + bool "Main Feature Dependency" + default y + depends on MAIN_FLAG + +config MAIN_FLAG_SELECT + bool "Main Feature Dependent" + select MAIN_FLAG + +choice MULTIPLE_CHOICES + prompt "Multiple Choice Option" + +config FIRST_CHOICE + bool "First Choice Option" + depends on !MAIN_FLAG + +config SECOND_CHOICE + bool "Second Choice Option" + +endchoice + +config UNSET_FLAG + bool "Disabled Feature" diff --git a/tests/kconfig/tracing/prj.conf b/tests/kconfig/tracing/prj.conf new file mode 100644 index 0000000000000..adfdd05102d91 --- /dev/null +++ b/tests/kconfig/tracing/prj.conf @@ -0,0 +1,7 @@ +# Copyright 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +# Note that line numbers in this file are important for test scripts. Ensure +# these match the expectations in validate_srcrefs.py. + +CONFIG_MAIN_FLAG_SELECT=y diff --git a/tests/kconfig/tracing/src/main.c b/tests/kconfig/tracing/src/main.c new file mode 100644 index 0000000000000..fa3a81d3a960f --- /dev/null +++ b/tests/kconfig/tracing/src/main.c @@ -0,0 +1,10 @@ +/* + * Copyright 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +int main(void) +{ + return 0; +} diff --git a/tests/kconfig/tracing/testcase.yaml b/tests/kconfig/tracing/testcase.yaml new file mode 100644 index 0000000000000..8694d4e3f8fed --- /dev/null +++ b/tests/kconfig/tracing/testcase.yaml @@ -0,0 +1,11 @@ +# Copyright 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +tests: + kconfig.tracing: + build_only: true + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim diff --git a/tests/kconfig/tracing/validate_tracing.py b/tests/kconfig/tracing/validate_tracing.py new file mode 100644 index 0000000000000..0de12a12323fe --- /dev/null +++ b/tests/kconfig/tracing/validate_tracing.py @@ -0,0 +1,142 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +import json +import os +import pickle +import sys + +# fmt: off + +# Indices for the fields in the trace entries +# Keep these in sync with the generation code in scripts/kconfig/kconfig.py! +( + SYM_NAME, + SYM_VIS, + SYM_TYPE, + SYM_VALUE, + SYM_KIND, + SYM_LOC +) = range(6) + +EXPECTED_TRACES = [ + [ + "CONFIG_BOARD", + "n", + "string", + "native_sim", + "default", + [ "zephyr/boards/Kconfig", None ] # only test the file name + ], + [ + "CONFIG_MAIN_FLAG", + "n", + "bool", + "y", + "select", + [ "MAIN_FLAG_SELECT" ] + ], + [ + "CONFIG_MAIN_FLAG_DEPENDENCY", + "y", + "bool", + "y", + "default", + [ "tests/kconfig/tracing/Kconfig", 14 ] + ], + [ + "CONFIG_MAIN_FLAG_SELECT", + "y", + "bool", + "y", + "assign", + [ "tests/kconfig/tracing/prj.conf", 7 ] + ], + [ + "CONFIG_SECOND_CHOICE", + "y", + "bool", + "y", + "default", + None + ], + [ + "CONFIG_UNSET_FLAG", + "y", + "bool", + None, + "unset", + None + ], +] + +# fmt: on + + +def compare_entry(actual, expected): + for field in SYM_NAME, SYM_VIS, SYM_TYPE, SYM_VALUE, SYM_KIND: + if actual[field] != expected[field]: + return False + + if expected[SYM_KIND] in ("imply", "select") or expected[SYM_LOC] is None: + # list of strings or None, compare directly + if actual[SYM_LOC] != expected[SYM_LOC]: + return False + else: + # file reference, trim input path + if not isinstance(actual[SYM_LOC], list | tuple) or len(actual[SYM_LOC]) != 2: + return False + + expected_path, expected_line = expected[SYM_LOC] + actual_path, actual_line = actual[SYM_LOC] + + if not os.path.normpath(actual_path).endswith(expected_path): + return False + + if expected_line is not None and expected_line != actual_line: + return False + + return True + + +def compare_traces(source, actual_list, expected_list): + result = True + for expected in expected_list: + actual = next((sr for sr in actual_list if sr[0] == expected[0]), None) + if not actual: + print(f"Missing value traces for {expected[0]}") + result = False + continue + + if not compare_entry(actual, expected): + print(f"{source}: ERROR: value traces mismatch for {expected[0]}:") + print(" expected:", expected) + print(" actual:", actual) + result = False + continue + + if result: + print(f"{source}: value traces match expected values.") + else: + print(f"{source}: ERROR: Validation failed.") + sys.exit(1) + + +def main(): + if len(sys.argv) != 2: + print("Usage: validate_traces.py ") + sys.exit(1) + + dotconfig = sys.argv[1] + + with open(dotconfig + "-trace.json") as f: + traces = json.load(f) + compare_traces("json", traces, EXPECTED_TRACES) + + with open(dotconfig + "-trace.pickle", 'rb') as f: + traces = pickle.load(f) + compare_traces("pickle", traces, EXPECTED_TRACES) + + +if __name__ == "__main__": + main() From ecc5e1a97385b13b54c76a423aec04fe0a51c69f Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Wed, 27 Aug 2025 09:49:03 +0800 Subject: [PATCH 340/397] drivers: clock_control: add nxp_mc_cgm clock driver - add clock_init function to initialize clock sources according devicetree settings - finish basic clock api function Signed-off-by: Lucien Zhao --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.nxp_mc_cgm | 9 + .../clock_control/clock_control_nxp_mc_cgm.c | 315 ++++++++++++++++++ dts/bindings/clock/nxp,firc.yaml | 18 + dts/bindings/clock/nxp,fxosc.yaml | 33 ++ dts/bindings/clock/nxp,mc-cgm.yaml | 65 ++++ dts/bindings/clock/nxp,plldig.yaml | 61 ++++ .../nxp_clock_controller_sources.h | 36 ++ include/zephyr/dt-bindings/clock/nxp_mc_cgm.h | 113 +++++++ 10 files changed, 653 insertions(+) create mode 100644 drivers/clock_control/Kconfig.nxp_mc_cgm create mode 100644 drivers/clock_control/clock_control_nxp_mc_cgm.c create mode 100644 dts/bindings/clock/nxp,firc.yaml create mode 100644 dts/bindings/clock/nxp,fxosc.yaml create mode 100644 dts/bindings/clock/nxp,mc-cgm.yaml create mode 100644 dts/bindings/clock/nxp,plldig.yaml create mode 100644 include/zephyr/drivers/clock_control/nxp_clock_controller_sources.h create mode 100644 include/zephyr/dt-bindings/clock/nxp_mc_cgm.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 13100d651592d..b4ebce89ee00a 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -40,6 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SI32_AHB clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SI32_APB clock_control_si32_apb.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_control_smartbond.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_control_numaker_scc.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_MC_CGM clock_control_nxp_mc_cgm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_control_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA_CGC clock_control_renesas_ra_cgc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA_SUBCLK clock_control_renesas_ra_cgc_subclk.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index e2c4a071ab09a..2d5ed6198b840 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -86,6 +86,8 @@ source "drivers/clock_control/Kconfig.smartbond" source "drivers/clock_control/Kconfig.numaker" +source "drivers/clock_control/Kconfig.nxp_mc_cgm" + source "drivers/clock_control/Kconfig.nxp_s32" source "drivers/clock_control/Kconfig.agilex5" diff --git a/drivers/clock_control/Kconfig.nxp_mc_cgm b/drivers/clock_control/Kconfig.nxp_mc_cgm new file mode 100644 index 0000000000000..aba3c9b54d9a3 --- /dev/null +++ b/drivers/clock_control/Kconfig.nxp_mc_cgm @@ -0,0 +1,9 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_NXP_MC_CGM + bool "NXP MC_CGM clock driver" + default y + depends on DT_HAS_NXP_MC_CGM_ENABLED + help + Enable support for NXP MC_CGM clock driver. diff --git a/drivers/clock_control/clock_control_nxp_mc_cgm.c b/drivers/clock_control/clock_control_nxp_mc_cgm.c new file mode 100644 index 0000000000000..6eca1da92c4ce --- /dev/null +++ b/drivers/clock_control/clock_control_nxp_mc_cgm.c @@ -0,0 +1,315 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_mc_cgm + +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_REGISTER(clock_control); + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(fxosc), nxp_fxosc, okay) +const fxosc_config_t fxosc_config = {.freqHz = NXP_FXOSC_FREQ, + .workMode = NXP_FXOSC_WORKMODE, + .startupDelay = NXP_FXOSC_DELAY, + .overdriveProtect = NXP_FXOSC_OVERDRIVE}; +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), nxp_plldig, okay) +const pll_config_t pll_config = {.workMode = NXP_PLL_WORKMODE, + .preDiv = NXP_PLL_PREDIV, /* PLL input clock predivider: 2 */ + .postDiv = NXP_PLL_POSTDIV, + .multiplier = NXP_PLL_MULTIPLIER, + .fracLoopDiv = NXP_PLL_FRACLOOPDIV, + .stepSize = NXP_PLL_STEPSIZE, + .stepNum = NXP_PLL_STEPNUM, + .accuracy = NXP_PLL_ACCURACY, + .outDiv = NXP_PLL_OUTDIV_POINTER}; +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(mc_cgm), nxp_mc_cgm, okay) +const clock_pcfs_config_t pcfs_config = {.maxAllowableIDDchange = NXP_PLL_MAXIDOCHANGE, + .stepDuration = NXP_PLL_STEPDURATION, + .clkSrcFreq = NXP_PLL_CLKSRCFREQ}; +#endif + +static int mc_cgm_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system) +{ +#if defined(CONFIG_CAN_MCUX_FLEXCAN) + switch ((uint32_t)sub_system) { + case MCUX_FLEXCAN0_CLK: + CLOCK_EnableClock(kCLOCK_Flexcan0); + break; + case MCUX_FLEXCAN1_CLK: + CLOCK_EnableClock(kCLOCK_Flexcan1); + break; + case MCUX_FLEXCAN2_CLK: + CLOCK_EnableClock(kCLOCK_Flexcan2); + break; + case MCUX_FLEXCAN3_CLK: + CLOCK_EnableClock(kCLOCK_Flexcan3); + break; + case MCUX_FLEXCAN4_CLK: + CLOCK_EnableClock(kCLOCK_Flexcan4); + break; + case MCUX_FLEXCAN5_CLK: + CLOCK_EnableClock(kCLOCK_Flexcan5); + break; + default: + break; + } +#endif /* defined(CONFIG_CAN_MCUX_MCAN) */ + +#if defined(CONFIG_UART_MCUX_LPUART) + switch ((uint32_t)sub_system) { + case MCUX_LPUART0_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart0); + break; + case MCUX_LPUART1_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart1); + break; + case MCUX_LPUART2_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart2); + break; + case MCUX_LPUART3_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart3); + break; + case MCUX_LPUART4_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart4); + break; + case MCUX_LPUART5_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart5); + break; + case MCUX_LPUART6_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart6); + break; + case MCUX_LPUART7_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart7); + break; + case MCUX_LPUART8_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart8); + break; + case MCUX_LPUART9_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart9); + break; + case MCUX_LPUART10_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart10); + break; + case MCUX_LPUART11_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart11); + break; + case MCUX_LPUART12_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart12); + break; + case MCUX_LPUART13_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart13); + break; + case MCUX_LPUART14_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart14); + break; + case MCUX_LPUART15_CLK: + CLOCK_EnableClock(kCLOCK_Lpuart15); + break; + default: + break; + } +#endif /* defined(CONFIG_UART_MCUX_LPUART) */ + +#if defined(CONFIG_SPI_NXP_LPSPI) + switch ((uint32_t)sub_system) { + case MCUX_LPSPI0_CLK: + CLOCK_EnableClock(kCLOCK_Lpspi0); + break; + case MCUX_LPSPI1_CLK: + CLOCK_EnableClock(kCLOCK_Lpspi1); + break; + case MCUX_LPSPI2_CLK: + CLOCK_EnableClock(kCLOCK_Lpspi2); + break; + case MCUX_LPSPI3_CLK: + CLOCK_EnableClock(kCLOCK_Lpspi3); + break; + case MCUX_LPSPI4_CLK: + CLOCK_EnableClock(kCLOCK_Lpspi4); + break; + case MCUX_LPSPI5_CLK: + CLOCK_EnableClock(kCLOCK_Lpspi5); + break; + default: + break; + } +#endif /* defined(CONFIG_SPI_NXP_LPSPI) */ + +#if defined(CONFIG_I2C_MCUX_LPI2C) + switch ((uint32_t)sub_system) { + case MCUX_LPI2C0_CLK: + CLOCK_EnableClock(kCLOCK_Lpi2c0); + break; + case MCUX_LPI2C1_CLK: + CLOCK_EnableClock(kCLOCK_Lpi2c1); + break; + default: + break; + } +#endif /* defined(CONFIG_I2C_MCUX_LPI2C) */ + + return 0; +} + +static int mc_cgm_clock_control_off(const struct device *dev, clock_control_subsys_t sub_system) +{ + return 0; +} + +static int mc_cgm_get_subsys_rate(const struct device *dev, clock_control_subsys_t sub_system, + uint32_t *rate) +{ + uint32_t clock_name = (uint32_t)sub_system; + + switch (clock_name) { +#if defined(CONFIG_UART_MCUX_LPUART) + case MCUX_LPUART0_CLK: + case MCUX_LPUART8_CLK: + *rate = CLOCK_GetAipsPlatClkFreq(); + break; + case MCUX_LPUART1_CLK: + case MCUX_LPUART2_CLK: + case MCUX_LPUART3_CLK: + case MCUX_LPUART4_CLK: + case MCUX_LPUART5_CLK: + case MCUX_LPUART6_CLK: + case MCUX_LPUART7_CLK: + case MCUX_LPUART9_CLK: + case MCUX_LPUART10_CLK: + case MCUX_LPUART11_CLK: + case MCUX_LPUART12_CLK: + case MCUX_LPUART13_CLK: + case MCUX_LPUART14_CLK: + case MCUX_LPUART15_CLK: + *rate = CLOCK_GetAipsSlowClkFreq(); + break; +#endif /* defined(CONFIG_UART_MCUX_LPUART) */ + +#if defined(CONFIG_SPI_NXP_LPSPI) + case MCUX_LPSPI0_CLK: + *rate = CLOCK_GetAipsPlatClkFreq(); + break; + case MCUX_LPSPI1_CLK: + case MCUX_LPSPI2_CLK: + case MCUX_LPSPI3_CLK: + case MCUX_LPSPI4_CLK: + case MCUX_LPSPI5_CLK: + *rate = CLOCK_GetAipsSlowClkFreq(); + break; +#endif /* defined(CONFIG_SPI_NXP_LPSPI) */ + +#if defined(CONFIG_I2C_MCUX_LPI2C) + case MCUX_LPI2C0_CLK: + case MCUX_LPI2C1_CLK: + *rate = CLOCK_GetAipsSlowClkFreq(); + break; +#endif /* defined(CONFIG_I2C_MCUX_LPI2C) */ + +#if defined(CONFIG_CAN_MCUX_FLEXCAN) + case MCUX_FLEXCAN0_CLK: + *rate = CLOCK_GetFlexcanPeClkFreq(0); + break; + case MCUX_FLEXCAN1_CLK: + *rate = CLOCK_GetFlexcanPeClkFreq(1); + break; + case MCUX_FLEXCAN2_CLK: + *rate = CLOCK_GetFlexcanPeClkFreq(2); + break; + case MCUX_FLEXCAN3_CLK: + *rate = CLOCK_GetFlexcanPeClkFreq(3); + break; + case MCUX_FLEXCAN4_CLK: + *rate = CLOCK_GetFlexcanPeClkFreq(4); + break; + case MCUX_FLEXCAN5_CLK: + *rate = CLOCK_GetFlexcanPeClkFreq(5); + break; +#endif /* defined(CONFIG_CAN_MCUX_FLEXCAN) */ + } + return 0; +} + +static int mc_cgm_init(const struct device *dev) +{ +#if defined(FSL_FEATURE_PMC_HAS_LAST_MILE_REGULATOR) && (FSL_FEATURE_PMC_HAS_LAST_MILE_REGULATOR) + /* Enables PMC last mile regulator before enable PLL. */ + if ((PMC->LVSC & PMC_LVSC_LVD15S_MASK) != 0U) { + /* External bipolar junction transistor is connected between external voltage and + * V15 input pin. + */ + PMC->CONFIG |= PMC_CONFIG_LMBCTLEN_MASK; + } + while ((PMC->LVSC & PMC_LVSC_LVD15S_MASK) != 0U) { + } + PMC->CONFIG |= PMC_CONFIG_LMEN_MASK; + while ((PMC->CONFIG & PMC_CONFIG_LMSTAT_MASK) == 0u) { + } +#endif /* FSL_FEATURE_PMC_HAS_LAST_MILE_REGULATOR */ + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(firc), nxp_firc, okay) + /* Switch the FIRC_DIV_SEL to the desired diveder. */ + CLOCK_SetFircDiv(NXP_FIRC_DIV); + /* Disable FIRC in standby mode. */ + CLOCK_DisableFircInStandbyMode(); +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(sirc), nxp_sirc, okay) + /* Disable SIRC in standby mode. */ + CLOCK_DisableSircInStandbyMode(); +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(fxosc), nxp_fxosc, okay) + /* Enable FXOSC. */ + CLOCK_InitFxosc(&fxosc_config); +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), nxp_plldig, okay) + /* Enable PLL. */ + CLOCK_InitPll(&pll_config); +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(mc_cgm), nxp_mc_cgm, okay) + CLOCK_SelectSafeClock(kFIRC_CLK_to_MUX0); + /* Configure MUX_0_CSC dividers */ + CLOCK_SetClkMux0DivTriggerType(KCLOCK_CommonTriggerUpdate); + CLOCK_SetClkDiv(kCLOCK_DivCoreClk, NXP_PLL_MUX_0_DC_0_DIV); + CLOCK_SetClkDiv(kCLOCK_DivAipsPlatClk, NXP_PLL_MUX_0_DC_1_DIV); + CLOCK_SetClkDiv(kCLOCK_DivAipsSlowClk, NXP_PLL_MUX_0_DC_2_DIV); + CLOCK_SetClkDiv(kCLOCK_DivHseClk, NXP_PLL_MUX_0_DC_3_DIV); + CLOCK_SetClkDiv(kCLOCK_DivDcmClk, NXP_PLL_MUX_0_DC_4_DIV); +#ifdef MC_CGM_MUX_0_DC_5_DIV_MASK + CLOCK_SetClkDiv(kCLOCK_DivLbistClk, NXP_PLL_MUX_0_DC_5_DIV); +#endif +#ifdef MC_CGM_MUX_0_DC_6_DIV_MASK + CLOCK_SetClkDiv(kCLOCK_DivQspiClk, NXP_PLL_MUX_0_DC_6_DIV); +#endif + CLOCK_CommonTriggerClkMux0DivUpdate(); + CLOCK_ProgressiveClockFrequencySwitch(kPLL_PHI0_CLK_to_MUX0, &pcfs_config); +#endif + + /* Set SystemCoreClock variable. */ + SystemCoreClockUpdate(); + + return 0; +} + +static DEVICE_API(clock_control, mcux_mcxe31x_clock_api) = { + .on = mc_cgm_clock_control_on, + .off = mc_cgm_clock_control_off, + .get_rate = mc_cgm_get_subsys_rate, +}; + +DEVICE_DT_INST_DEFINE(0, mc_cgm_init, NULL, NULL, NULL, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &mcux_mcxe31x_clock_api); diff --git a/dts/bindings/clock/nxp,firc.yaml b/dts/bindings/clock/nxp,firc.yaml new file mode 100644 index 0000000000000..ca57df3a55238 --- /dev/null +++ b/dts/bindings/clock/nxp,firc.yaml @@ -0,0 +1,18 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Fast internal RC oscillator + +compatible: "nxp,firc" + +include: [base.yaml] + +properties: + reg: + required: true + + firc-div: + required: true + type: string + description: FIRC_DIV_SEL + enum: ["NULL", "DivBy2", "DivBy16", "UnDiv"] diff --git a/dts/bindings/clock/nxp,fxosc.yaml b/dts/bindings/clock/nxp,fxosc.yaml new file mode 100644 index 0000000000000..9362d431bf197 --- /dev/null +++ b/dts/bindings/clock/nxp,fxosc.yaml @@ -0,0 +1,33 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Fast external crystal oscillator + +compatible: "nxp,fxosc" + +include: [base.yaml] + +properties: + reg: + required: true + + freq: + required: true + type: int + description: FXOSC output clock frequency in Hz + + workmode: + required: true + type: string + description: FXOSC work mode setting + enum: ["crystal", "bypass"] + + delay: + required: true + type: int + description: FXOSC startup delay in counts + + overdrive: + required: true + type: int + description: FXOSC overdrive protection setting diff --git a/dts/bindings/clock/nxp,mc-cgm.yaml b/dts/bindings/clock/nxp,mc-cgm.yaml new file mode 100644 index 0000000000000..0a53a94d82a59 --- /dev/null +++ b/dts/bindings/clock/nxp,mc-cgm.yaml @@ -0,0 +1,65 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Glitchless clock switching Clock Generation module + +compatible: "nxp,mc-cgm" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + max-ido-change: + required: true + type: int + description: | + Maximum variation of current per time (mA/microsec) - max allowable + IDD change is determined by the user's power supply design. + + step-duration: + required: true + type: int + description: Step duration of each PCFS step (time per step in us). + + clk-src-freq: + required: true + type: int + description: | + Frequency of the clock source from which ramp-down and to which ramp-up are processed. + + mux-0-dc-0-div: + type: int + description: MUX_0_DC_0 divider setting + + mux-0-dc-1-div: + type: int + description: MUX_0_DC_1 divider setting + + mux-0-dc-2-div: + type: int + description: MUX_0_DC_2 divider setting + + mux-0-dc-3-div: + type: int + description: MUX_0_DC_3 divider setting + + mux-0-dc-4-div: + type: int + description: MUX_0_DC_4 divider setting + + mux-0-dc-5-div: + type: int + description: MUX_0_DC_5 divider setting + + mux-0-dc-6-div: + type: int + description: MUX_0_DC_6 divider setting + + "#clock-cells": + type: int + const: 1 + +clock-cells: + - name diff --git a/dts/bindings/clock/nxp,plldig.yaml b/dts/bindings/clock/nxp,plldig.yaml new file mode 100644 index 0000000000000..23d17e87050d8 --- /dev/null +++ b/dts/bindings/clock/nxp,plldig.yaml @@ -0,0 +1,61 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Phase-locked loop + +compatible: "nxp,plldig" + +include: [base.yaml] + +properties: + reg: + required: true + + workmode: + required: true + type: string + description: PLL work mode setting + enum: ["Integer", "Fractional", "SSCG"] + + prediv: + required: true + type: int + description: Input Clock Predivider + + postdiv: + required: true + type: int + description: VCO clock post divider for driving the PHI output clock. + + multiplier: + required: true + type: int + description: Multiplication factor applied to the reference frequency + + fracloopdiv: + required: true + type: int + description: Numerator Of Fractional Loop Division Factor. + Value should less than 18432. + + stepsize: + required: true + type: int + description: For SSCG mode. Frequency Modulation Step Size + + stepnum: + required: true + type: int + description: | + For SSCG mode. Number Of Steps Of Modulation Period Or Frequency Modulation + + accuracy: + required: true + type: string + description: PLL unlock accuracy + enum: ["Accuracy9", "Accuracy17", "Accuracy33", "Accuracy5"] + + outdiv: + required: true + type: array + description: PLL Output Divider diff --git a/include/zephyr/drivers/clock_control/nxp_clock_controller_sources.h b/include/zephyr/drivers/clock_control/nxp_clock_controller_sources.h new file mode 100644 index 0000000000000..e3e4f08927ef5 --- /dev/null +++ b/include/zephyr/drivers/clock_control/nxp_clock_controller_sources.h @@ -0,0 +1,36 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NXP_CLOCK_CONTROLLER_SOURCES_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NXP_CLOCK_CONTROLLER_SOURCES_H_ + +#include + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(firc), nxp_firc, okay) +#define NXP_FIRC_DIV DT_ENUM_IDX(DT_NODELABEL(firc), firc_div) +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(fxosc), nxp_fxosc, okay) +#define NXP_FXOSC_FREQ DT_PROP(DT_NODELABEL(fxosc), freq) +#define NXP_FXOSC_WORKMODE \ + (DT_ENUM_IDX(DT_NODELABEL(fxosc), workmode) == 0 ? kFXOSC_ModeCrystal : kFXOSC_ModeBypass) +#define NXP_FXOSC_DELAY DT_PROP(DT_NODELABEL(fxosc), delay) +#define NXP_FXOSC_OVERDRIVE DT_PROP(DT_NODELABEL(fxosc), overdrive) +#endif + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), nxp_plldig, okay) +#define NXP_PLL_WORKMODE DT_ENUM_IDX(DT_NODELABEL(pll), workmode) +#define NXP_PLL_PREDIV DT_PROP(DT_NODELABEL(pll), prediv) +#define NXP_PLL_POSTDIV DT_PROP(DT_NODELABEL(pll), postdiv) +#define NXP_PLL_MULTIPLIER DT_PROP(DT_NODELABEL(pll), multiplier) +#define NXP_PLL_FRACLOOPDIV DT_PROP(DT_NODELABEL(pll), fracloopdiv) +#define NXP_PLL_STEPSIZE DT_PROP(DT_NODELABEL(pll), stepsize) +#define NXP_PLL_STEPNUM DT_PROP(DT_NODELABEL(pll), stepnum) +#define NXP_PLL_ACCURACY DT_ENUM_IDX(DT_NODELABEL(pll), accuracy) +#define NXP_PLL_OUTDIV_POINTER DT_PROP(DT_NODELABEL(pll), outdiv) +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NXP_CLOCK_CONTROLLER_SOURCES_H_ */ diff --git a/include/zephyr/dt-bindings/clock/nxp_mc_cgm.h b/include/zephyr/dt-bindings/clock/nxp_mc_cgm.h new file mode 100644 index 0000000000000..6debb6a21bc8c --- /dev/null +++ b/include/zephyr/dt-bindings/clock/nxp_mc_cgm.h @@ -0,0 +1,113 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_MC_CGM_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_MC_CGM_H_ + +/* Define a set of macros related to NXP mc_cgm IP configuration parameter */ +#define NXP_PLL_MAXIDOCHANGE DT_PROP(DT_NODELABEL(mc_cgm), max_ido_change) +#define NXP_PLL_STEPDURATION DT_PROP(DT_NODELABEL(mc_cgm), step_duration) +#define NXP_PLL_CLKSRCFREQ DT_PROP(DT_NODELABEL(mc_cgm), clk_src_freq) +#define NXP_PLL_MUX_0_DC_0_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_0_div) +#define NXP_PLL_MUX_0_DC_1_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_1_div) +#define NXP_PLL_MUX_0_DC_2_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_2_div) +#define NXP_PLL_MUX_0_DC_3_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_3_div) +#define NXP_PLL_MUX_0_DC_4_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_4_div) +#define NXP_PLL_MUX_0_DC_5_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_5_div) +#define NXP_PLL_MUX_0_DC_6_DIV DT_PROP(DT_NODELABEL(mc_cgm), mux_0_dc_6_div) + +/* Note- clock identifiers in this file must be unique, + * as the driver uses them in a switch case + */ + +#define MCUX_MC_CGM_CLK_ID(high, low) ((high << 8) | (low)) + +/* These IDs are used within SOC macros, and thus cannot be defined + * using the standard MCUX_MC_CGM_CLK_ID form + */ +/* --------------------- System layer clock --------------------- */ +#define MCUX_CORESYS_CLK MCUX_MC_CGM_CLK_ID(0x00, 0x00) +#define MCUX_AIPSPLAT_CLK MCUX_MC_CGM_CLK_ID(0x01, 0x00) +#define MCUX_AIPSSLOW_CLK MCUX_MC_CGM_CLK_ID(0x02, 0x00) +#define MCUX_HSE_CLK MCUX_MC_CGM_CLK_ID(0x03, 0x00) +#define MCUX_DCM_CLK MCUX_MC_CGM_CLK_ID(0x04, 0x00) +#define MCUX_LBIST_CLK MCUX_MC_CGM_CLK_ID(0x05, 0x00) +#define MCUX_QSPI_CLK MCUX_MC_CGM_CLK_ID(0x06, 0x00) + +/* --------------------- MC_CGM clock --------------------- */ +#define MCUX_FIRC_CLK MCUX_MC_CGM_CLK_ID(0x10, 0x00) +#define MCUX_SIRC_CLK MCUX_MC_CGM_CLK_ID(0x11, 0x00) +#define MCUX_FXOSC_CLK MCUX_MC_CGM_CLK_ID(0x12, 0x00) +#define MCUX_SXOSC_CLK MCUX_MC_CGM_CLK_ID(0x13, 0x00) +#define MCUX_PLLPHI0_CLK MCUX_MC_CGM_CLK_ID(0x14, 0x00) +#define MCUX_PLLPHI1_CLK MCUX_MC_CGM_CLK_ID(0x14, 0x01) + +/* --------------------- Peripheral clock --------------------- */ +#define MCUX_ADC0_CLK MCUX_MC_CGM_CLK_ID(0x20, 0x00) +#define MCUX_ADC1_CLK MCUX_MC_CGM_CLK_ID(0x20, 0x01) +#define MCUX_ADC2_CLK MCUX_MC_CGM_CLK_ID(0x20, 0x02) + +#define MCUX_BCTU_CLK MCUX_MC_CGM_CLK_ID(0x21, 0x00) + +#define MCUX_CMP0_CLK MCUX_MC_CGM_CLK_ID(0x22, 0x00) +#define MCUX_CMP1_CLK MCUX_MC_CGM_CLK_ID(0x22, 0x01) +#define MCUX_CMP2_CLK MCUX_MC_CGM_CLK_ID(0x22, 0x02) + +#define MCUX_EMIOS_CLK MCUX_MC_CGM_CLK_ID(0x23, 0x00) + +#define MCUX_FLEXCAN0_CLK MCUX_MC_CGM_CLK_ID(0x24, 0x00) +#define MCUX_FLEXCAN1_CLK MCUX_MC_CGM_CLK_ID(0x24, 0x01) +#define MCUX_FLEXCAN2_CLK MCUX_MC_CGM_CLK_ID(0x24, 0x02) +#define MCUX_FLEXCAN3_CLK MCUX_MC_CGM_CLK_ID(0x24, 0x03) +#define MCUX_FLEXCAN4_CLK MCUX_MC_CGM_CLK_ID(0x24, 0x04) +#define MCUX_FLEXCAN5_CLK MCUX_MC_CGM_CLK_ID(0x24, 0x05) + +#define MCUX_FLEXIO_CLK MCUX_MC_CGM_CLK_ID(0x25, 0x00) + +#define MCUX_LPI2C0_CLK MCUX_MC_CGM_CLK_ID(0x26, 0x00) +#define MCUX_LPI2C1_CLK MCUX_MC_CGM_CLK_ID(0x26, 0x01) + +#define MCUX_LPSPI0_CLK MCUX_MC_CGM_CLK_ID(0x27, 0x00) +#define MCUX_LPSPI1_CLK MCUX_MC_CGM_CLK_ID(0x27, 0x01) +#define MCUX_LPSPI2_CLK MCUX_MC_CGM_CLK_ID(0x27, 0x02) +#define MCUX_LPSPI3_CLK MCUX_MC_CGM_CLK_ID(0x27, 0x03) +#define MCUX_LPSPI4_CLK MCUX_MC_CGM_CLK_ID(0x27, 0x04) +#define MCUX_LPSPI5_CLK MCUX_MC_CGM_CLK_ID(0x27, 0x05) + +#define MCUX_LPUART0_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x00) +#define MCUX_LPUART1_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x01) +#define MCUX_LPUART2_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x02) +#define MCUX_LPUART3_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x03) +#define MCUX_LPUART4_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x04) +#define MCUX_LPUART5_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x05) +#define MCUX_LPUART6_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x06) +#define MCUX_LPUART7_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x07) +#define MCUX_LPUART8_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x08) +#define MCUX_LPUART9_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x09) +#define MCUX_LPUART10_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x0A) +#define MCUX_LPUART11_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x0B) +#define MCUX_LPUART12_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x0C) +#define MCUX_LPUART13_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x0D) +#define MCUX_LPUART14_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x0E) +#define MCUX_LPUART15_CLK MCUX_MC_CGM_CLK_ID(0x28, 0x0F) + +#define MCUX_PIT0_CLK MCUX_MC_CGM_CLK_ID(0x29, 0x00) +#define MCUX_PIT1_CLK MCUX_MC_CGM_CLK_ID(0x29, 0x01) +#define MCUX_PIT2_CLK MCUX_MC_CGM_CLK_ID(0x29, 0x02) + +#define MCUX_SAI0_CLK MCUX_MC_CGM_CLK_ID(0x2A, 0x00) +#define MCUX_SAI1_CLK MCUX_MC_CGM_CLK_ID(0x2A, 0x01) + +#define MCUX_STM0_CLK MCUX_MC_CGM_CLK_ID(0x2B, 0x00) +#define MCUX_STM1_CLK MCUX_MC_CGM_CLK_ID(0x2B, 0x01) + +/* --------------------- Partition 2 clock --------------------- */ +#define MCUX_QSPISF_CLK MCUX_MC_CGM_CLK_ID(0x2C, 0x00) +#define MCUX_EMACRX_CLK MCUX_MC_CGM_CLK_ID(0x2C, 0x01) +#define MCUX_EMACTX_CLK MCUX_MC_CGM_CLK_ID(0x2C, 0x02) +#define MCUX_EMACTS_CLK MCUX_MC_CGM_CLK_ID(0x2C, 0x03) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_MC_CGM_H_ */ From c89a11cc60de7b5389b9e48ca1f28db9ba87d78d Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Fri, 5 Sep 2025 23:31:28 +0800 Subject: [PATCH 341/397] drivers: interrupt_controller: adapt for mcxe31x series - adapt for mcxe31x series - due to some bit defined in header files add some conditional macro to separate Signed-off-by: Lucien Zhao --- drivers/interrupt_controller/Kconfig.nxp_siul2 | 2 +- drivers/interrupt_controller/intc_nxp_siul2_eirq.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/interrupt_controller/Kconfig.nxp_siul2 b/drivers/interrupt_controller/Kconfig.nxp_siul2 index ba439cd5d60cf..ae2c64f261c51 100644 --- a/drivers/interrupt_controller/Kconfig.nxp_siul2 +++ b/drivers/interrupt_controller/Kconfig.nxp_siul2 @@ -15,7 +15,7 @@ if NXP_SIUL2_EIRQ config NXP_SIUL2_EIRQ_EXT_INTERRUPTS_MAX int default 8 if SOC_SERIES_S32ZE - default 32 if SOC_SERIES_S32K3 + default 32 if SOC_SERIES_S32K3 || SOC_SERIES_MCXE31X help Number of SIUL2 external interrupts per controller. This is a SoC integration option. diff --git a/drivers/interrupt_controller/intc_nxp_siul2_eirq.c b/drivers/interrupt_controller/intc_nxp_siul2_eirq.c index 27cc145e877b0..8668925d9beef 100644 --- a/drivers/interrupt_controller/intc_nxp_siul2_eirq.c +++ b/drivers/interrupt_controller/intc_nxp_siul2_eirq.c @@ -28,13 +28,20 @@ #define SIUL2_IFER0 0x28 /* SIUL2 Interrupt Filter Maximum Counter Register */ #define SIUL2_IFMCR(n) (0x30 + 0x4 * (n)) +#ifndef SIUL2_IFMCR_MAXCNT_MASK #define SIUL2_IFMCR_MAXCNT_MASK GENMASK(3, 0) +#endif +#ifndef SIUL2_IFMCR_MAXCNT #define SIUL2_IFMCR_MAXCNT(v) FIELD_PREP(SIUL2_IFMCR_MAXCNT_MASK, (v)) +#endif /* SIUL2 Interrupt Filter Clock Prescaler Register */ #define SIUL2_IFCPR 0xb0 +#ifndef SIUL2_IFCPR_IFCP_MASK #define SIUL2_IFCPR_IFCP_MASK GENMASK(3, 0) +#endif +#ifndef SIUL2_IFCPR_IFCP #define SIUL2_IFCPR_IFCP(v) FIELD_PREP(SIUL2_IFCPR_IFCP_MASK, (v)) - +#endif /* Handy accessors */ #define REG_READ(r) sys_read32(config->base + (r)) #define REG_WRITE(r, v) sys_write32((v), config->base + (r)) From a3e617e736d0c0a4547c486f53b8db3d9de92bf4 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Thu, 18 Sep 2025 13:19:17 +0800 Subject: [PATCH 342/397] driver: pinctrl: adapt for mcxe31x series - add binding files: nxp,mcxe31x-siul2-pinctrl.yaml - Enable PINCTRL_NXP_SIUL2 when nxp,mcxe31x-siul2-pinctrl is ok Signed-off-by: Lucien Zhao --- drivers/pinctrl/Kconfig.nxp_siul2 | 3 +- .../pinctrl/nxp,mcxe31x-siul2-pinctrl.yaml | 115 ++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/pinctrl/nxp,mcxe31x-siul2-pinctrl.yaml diff --git a/drivers/pinctrl/Kconfig.nxp_siul2 b/drivers/pinctrl/Kconfig.nxp_siul2 index e60391fa8445a..1650f9d386853 100644 --- a/drivers/pinctrl/Kconfig.nxp_siul2 +++ b/drivers/pinctrl/Kconfig.nxp_siul2 @@ -4,6 +4,7 @@ config PINCTRL_NXP_SIUL2 bool "Pin controller driver for NXP SIUL2" default y - depends on DT_HAS_NXP_S32ZE_SIUL2_PINCTRL_ENABLED || DT_HAS_NXP_S32K3_SIUL2_PINCTRL_ENABLED + depends on DT_HAS_NXP_S32ZE_SIUL2_PINCTRL_ENABLED || DT_HAS_NXP_S32K3_SIUL2_PINCTRL_ENABLED || \ + DT_HAS_NXP_MCXE31X_SIUL2_PINCTRL_ENABLED help Enable pin controller driver for NXP SIUL2. diff --git a/dts/bindings/pinctrl/nxp,mcxe31x-siul2-pinctrl.yaml b/dts/bindings/pinctrl/nxp,mcxe31x-siul2-pinctrl.yaml new file mode 100644 index 0000000000000..43b24d7b3c780 --- /dev/null +++ b/dts/bindings/pinctrl/nxp,mcxe31x-siul2-pinctrl.yaml @@ -0,0 +1,115 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP SIUL2 Pin Controller for MCXE31X SoCs + + The NXP SIUL2 pin controller is a singleton node responsible for controlling + the pin function selection and pin properties. This node, labeled 'pinctrl' in + the SoC's devicetree, will define pin configurations in pin groups. Each group + within the pin configuration defines the pin configuration for a peripheral, + and each numbered subgroup in the pin group defines all the pins for that + peripheral with the same configuration properties. The 'pinmux' property in + a group selects the pins to be configured, and the remaining properties set + configuration values for those pins. + + For example, to configure the pinmux for UART0, modify the 'pinctrl' from your + board or application devicetree overlay as follows: + + /* Include the SoC package header containing the predefined pins definitions */ + #include + + &pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + }; + + The 'uart0_default' node contains the pin configurations for a particular state + of a device. The 'default' state is the active state. Other states for the same + device can be specified in separate child nodes of 'pinctrl'. + + In addition to 'pinmux' property, each group can contain other properties such as + 'bias-pull-up' or 'slew-rate' that will be applied to all the pins defined in + 'pinmux' array. To enable the input buffer use 'input-enable' and to enable the + output buffer use 'output-enable'. + + To link the pin configurations with UART0 device, use pinctrl-N property in the + device node, where 'N' is the zero-based state index (0 is the default state). + Following previous example: + + &uart0 { + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + status = "okay"; + }; + + If only the required properties are supplied, the pin configuration register + will be assigned the following values: + - input and output buffers disabled + - internal pull not enabled + - slew rate "fastest" + - invert disabled + - drive strength disabled. + + Additionally, following settings are currently not supported and default to + the values indicated below: + - Safe Mode Control (disabled) + - Pad Keeping (disabled) + - Input Filter (disabled). + +compatible: "nxp,mcxe31x-siul2-pinctrl" + +include: base.yaml + +child-binding: + description: NXP SIUL2 pin controller pin group. + child-binding: + description: NXP SIUL2 pin controller pin configuration node. + + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-disable + - bias-pull-down + - bias-pull-up + - input-enable + - output-enable + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. The pins must be + defined using the macros from the SoC package header. These macros + encode all the pin muxing information in a 32-bit value. + + slew-rate: + type: string + enum: + - "fastest" + - "slowest" + default: "fastest" + description: | + Slew rate control. Can be either slowest or fastest setting. + See the SoC reference manual for applicability of this setting. + + nxp,invert: + type: boolean + description: | + Invert the signal selected by Source Signal Selection (SSS) before + transmitting it to the associated destination (chip pin or module port). + + nxp,drive-strength: + type: boolean + description: | + Drive strength enable. + See the SoC reference manual for applicability of this setting. From e6a5e5ddeaae9b3d76566cdc6f064991cead9e7c Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Fri, 5 Sep 2025 23:19:54 +0800 Subject: [PATCH 343/397] soc: nxp: mcx: add mcxe31 series soc - create 'mcxe' as family and 'mcxe31x' as series - add pinctrl_soc.h - add soc.c/.h to do some soc level initialization - add ecc initialization in mcxe31x_soc_initialization.S Signed-off-by: Lucien Zhao --- soc/nxp/mcx/mcxe/Kconfig | 2 +- soc/nxp/mcx/mcxe/mcxe31x/CMakeLists.txt | 16 +++ soc/nxp/mcx/mcxe/mcxe31x/Kconfig | 56 +++++++++ soc/nxp/mcx/mcxe/mcxe31x/Kconfig.defconfig | 18 +++ soc/nxp/mcx/mcxe/mcxe31x/Kconfig.soc | 68 +++++++++++ soc/nxp/mcx/mcxe/mcxe31x/boot_header.ld | 8 ++ soc/nxp/mcx/mcxe/mcxe31x/itcm.ld | 13 ++ .../mcxe/mcxe31x/mcxe31x_soc_initialization.S | 115 ++++++++++++++++++ soc/nxp/mcx/mcxe/mcxe31x/pinctrl_soc.h | 32 +++++ soc/nxp/mcx/mcxe/mcxe31x/soc.c | 40 ++++++ soc/nxp/mcx/mcxe/mcxe31x/soc.h | 27 ++++ soc/nxp/mcx/mcxe/mcxe31x/sram_config.c | 24 ++++ soc/nxp/mcx/soc.yml | 8 ++ 13 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/CMakeLists.txt create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/Kconfig create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/Kconfig.defconfig create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/Kconfig.soc create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/boot_header.ld create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/itcm.ld create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/mcxe31x_soc_initialization.S create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/pinctrl_soc.h create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/soc.c create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/soc.h create mode 100644 soc/nxp/mcx/mcxe/mcxe31x/sram_config.c diff --git a/soc/nxp/mcx/mcxe/Kconfig b/soc/nxp/mcx/mcxe/Kconfig index 2a1d867fd5876..d3f147cb36f12 100644 --- a/soc/nxp/mcx/mcxe/Kconfig +++ b/soc/nxp/mcx/mcxe/Kconfig @@ -5,4 +5,4 @@ if SOC_FAMILY_MCXE rsource "*/Kconfig" -endif #SOC_FAMILY_MCXE +endif # SOC_FAMILY_MCXE diff --git a/soc/nxp/mcx/mcxe/mcxe31x/CMakeLists.txt b/soc/nxp/mcx/mcxe/mcxe31x/CMakeLists.txt new file mode 100644 index 0000000000000..a3943a2491824 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c) +zephyr_sources(sram_config.c) +zephyr_include_directories(.) + +zephyr_library_sources_ifdef(CONFIG_SOC_RESET_HOOK mcxe31x_soc_initialization.S) + +zephyr_linker_sources_ifdef(CONFIG_BOARD_NXP_MCXE31X_BOOT_HEADER + ROM_START SORT_KEY 0 boot_header.ld) + +zephyr_linker_sources(SECTIONS itcm.ld) +zephyr_code_relocate(FILES sram_config.c LOCATION ${CONFIG_SRAM_CONFIG_RELOCATE_MEM}_TEXT) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/nxp/mcx/mcxe/mcxe31x/Kconfig b/soc/nxp/mcx/mcxe/mcxe31x/Kconfig new file mode 100644 index 0000000000000..d5e653105f7e2 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/Kconfig @@ -0,0 +1,56 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MCXE31X + select CPU_CORTEX_M7 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select ARM + select CLOCK_CONTROL + select HAS_MCUX + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE + select SOC_RESET_HOOK + select SOC_EARLY_INIT_HOOK + select CODE_DATA_RELOCATION + +if SOC_SERIES_MCXE31X + +if CODE_DATA_RELOCATION + +config SRAM_CONFIG_RELOCATE_MEM + string + default "ITCM" + help + Select memory to relocate sram_config.c code + +endif # CODE_DATA_RELOCATION + +config SOC_NXP_MCXE31X_BOOT_HEADER + bool + help + Enable boot header configuration for NXP MCXE31X SoC. + This should be selected by boards that need boot header support. + +if SOC_NXP_MCXE31X_BOOT_HEADER + +config BOOT_HEADER_OFFSET + hex "Flash config data offset" + default 0x0 + help + The flash config offset provides the boot ROM with the on-board + flash type and parameters. The boot ROM requires a fixed flash config + offset for FlexSPI device. + +config IMAGE_VECTOR_TABLE_OFFSET + hex "Image vector table offset" + default 0x1000 + help + The Image Vector Table (IVT) provides the boot ROM with pointers to + the application entry point and device configuration data. The boot + ROM requires a fixed IVT offset for each type of boot device. + +endif # SOC_NXP_MCXE31X_BOOT_HEADER + +endif # SOC_SERIES_MCXE31X diff --git a/soc/nxp/mcx/mcxe/mcxe31x/Kconfig.defconfig b/soc/nxp/mcx/mcxe/mcxe31x/Kconfig.defconfig new file mode 100644 index 0000000000000..2e00f0115b1a8 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_MCXE31X + +config NUM_IRQS + default 240 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if CORTEX_M_SYSTICK + +config CORTEX_M_SYSTICK + default n if (MCUX_LPTMR_TIMER || MCUX_OS_TIMER) + +config ROM_START_OFFSET + default 0x1000 + +endif # SOC_SERIES_MCXE31X diff --git a/soc/nxp/mcx/mcxe/mcxe31x/Kconfig.soc b/soc/nxp/mcx/mcxe/mcxe31x/Kconfig.soc new file mode 100644 index 0000000000000..8e6caff06622f --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/Kconfig.soc @@ -0,0 +1,68 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MCXE31X + bool + select SOC_FAMILY_MCXE + +config SOC_SERIES + default "mcxe31x" if SOC_SERIES_MCXE31X + +config SOC_MCXE315 + bool + select SOC_SERIES_MCXE31X + +config SOC_MCXE316 + bool + select SOC_SERIES_MCXE31X + +config SOC_MCXE317 + bool + select SOC_SERIES_MCXE31X + +config SOC_MCXE31B + bool + select SOC_SERIES_MCXE31X + +config SOC + default "mcxe315" if SOC_MCXE315 + default "mcxe316" if SOC_MCXE316 + default "mcxe317" if SOC_MCXE317 + default "mcxe31b" if SOC_MCXE31B + +config SOC_PART_NUMBER_MCXE315MLF + bool + select SOC_MCXE315 + +config SOC_PART_NUMBER_MCXE315MPA + bool + select SOC_MCXE315 + +config SOC_PART_NUMBER_MCXE316MLF + bool + select SOC_MCXE316 + +config SOC_PART_NUMBER_MCXE316MPA + bool + select SOC_MCXE316 + +config SOC_PART_NUMBER_MCXE317MPA + bool + select SOC_MCXE317 + +config SOC_PART_NUMBER_MCXE317MPB + bool + select SOC_MCXE317 + +config SOC_PART_NUMBER_MCXE31BMPB + bool + select SOC_MCXE31B + +config SOC_PART_NUMBER + default "MCXE315MLF" if SOC_PART_NUMBER_MCXE315MLF + default "MCXE315MPA" if SOC_PART_NUMBER_MCXE315MPA + default "MCXE316MLF" if SOC_PART_NUMBER_MCXE316MLF + default "MCXE316MPA" if SOC_PART_NUMBER_MCXE316MPA + default "MCXE317MPA" if SOC_PART_NUMBER_MCXE317MPA + default "MCXE317MPB" if SOC_PART_NUMBER_MCXE317MPB + default "MCXE31BMPB" if SOC_PART_NUMBER_MCXE31BMPB diff --git a/soc/nxp/mcx/mcxe/mcxe31x/boot_header.ld b/soc/nxp/mcx/mcxe/mcxe31x/boot_header.ld new file mode 100644 index 0000000000000..129d7db81af3c --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/boot_header.ld @@ -0,0 +1,8 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +. += CONFIG_BOOT_HEADER_OFFSET - (. - __rom_start_address); +KEEP(*(.boot_header)) diff --git a/soc/nxp/mcx/mcxe/mcxe31x/itcm.ld b/soc/nxp/mcx/mcxe/mcxe31x/itcm.ld new file mode 100644 index 0000000000000..a3bc678710315 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/itcm.ld @@ -0,0 +1,13 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +SECTION_PROLOGUE(.itcm_text,,) +{ + . = ALIGN(4); + _itcm_text_start = .; + KEEP(*(.itcm_text)) + _itcm_text_end = .; +} GROUP_LINK_IN(ITCM) diff --git a/soc/nxp/mcx/mcxe/mcxe31x/mcxe31x_soc_initialization.S b/soc/nxp/mcx/mcxe/mcxe31x/mcxe31x_soc_initialization.S new file mode 100644 index 0000000000000..44f3617569de8 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/mcxe31x_soc_initialization.S @@ -0,0 +1,115 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define MC_RGM_BASE DT_REG_ADDR(DT_NODELABEL(mc_rgm)) +#define MC_RGM_DES 0x0 +#define MC_RGM_FES 0x8 + +_ASM_FILE_PROLOGUE + +GTEXT(soc_reset_hook) + +SECTION_FUNC(TEXT, soc_reset_hook) + + /* + * On destructive reset, SRAM and TCM memories must be initialized to a known value using a + * 64-bit master before 32-bit masters can read or write to them. Note that SRAM retains + * content during functional reset through a hardware mechanism, therefore accesses do not + * cause any content corruption errors. + * + * This is implemented directly in ASM, to ensure no stack access is performed. + */ + + /* If we come from a destructive reset, then ignore functional reset flags */ + ldr r1, =MC_RGM_BASE + ldr r2, [r1, MC_RGM_DES] + cmp r2, 0x0 + bne ECC_INIT + ldr r2, [r1, MC_RGM_FES] + cmp r2, 0x0 + bne ECC_END + +ECC_INIT: + ldr r1, = DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) + ldr r2, = DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) + + subs r2, #1 + + ble SRAM_LOOP_END + + movs r0, 0 + movs r3, 0 + +SRAM_LOOP: + stm r1!, {r0,r3} + subs r2, 8 + bge SRAM_LOOP + +SRAM_LOOP_END: + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) + + ldr r1, = DT_REG_ADDR(DT_CHOSEN(zephyr_itcm)) + ldr r2, = DT_REG_SIZE(DT_CHOSEN(zephyr_itcm)) + + subs r2, #1 + +ITCM_LOOP: + stm r1!, {r0,r3} + subs r2, 8 + bge ITCM_LOOP +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) + + ldr r1, = DT_REG_ADDR(DT_CHOSEN(zephyr_dtcm)) + ldr r2, = DT_REG_SIZE(DT_CHOSEN(zephyr_dtcm)) + + subs r2, #1 + +DTCM_LOOP: + stm r1!, {r0,r3} + subs r2, 8 + bge DTCM_LOOP +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(itcm1), okay) + + ldr r1, = DT_REG_ADDR(DT_NODELABEL(itcm1)) + ldr r2, = DT_REG_SIZE(DT_NODELABEL(itcm1)) + + subs r2, #1 + +ITCM1_LOOP: + stm r1!, {r0,r3} + subs r2, 8 + bge ITCM1_LOOP +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(dtcm1), okay) + + ldr r1, = DT_REG_ADDR(DT_NODELABEL(dtcm1)) + ldr r2, = DT_REG_SIZE(DT_NODELABEL(dtcm1)) + + subs r2, #1 + +DTCM1_LOOP: + stm r1!, {r0,r3} + subs r2, 8 + bge DTCM1_LOOP +#endif + +ECC_END: + /* save lr value to r4 */ + mov r4, lr + /* Jump to SystemInit function*/ + bl SystemInit + mov lr, r4 + bx lr diff --git a/soc/nxp/mcx/mcxe/mcxe31x/pinctrl_soc.h b/soc/nxp/mcx/mcxe/mcxe31x/pinctrl_soc.h new file mode 100644 index 0000000000000..9f1b56c5d9d68 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/pinctrl_soc.h @@ -0,0 +1,32 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_NXP_MCXE31X_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_NXP_MCXE31X_PINCTRL_SOC_H_ + +#include +#include +#include + +#define NXP_SIUL2_PINMUX_INIT(group, value) \ + .mscr = {.inst = NXP_SIUL2_PINMUX_GET_MSCR_SIUL2_IDX(value), \ + .idx = NXP_SIUL2_PINMUX_GET_MSCR_IDX(value), \ + .val = SIUL2_MSCR_SSS(NXP_SIUL2_PINMUX_GET_MSCR_SSS(value)) | \ + SIUL2_MSCR_OBE(DT_PROP(group, output_enable)) | \ + SIUL2_MSCR_IBE(DT_PROP(group, input_enable)) | \ + SIUL2_MSCR_PUE(DT_PROP(group, bias_pull_up) || \ + DT_PROP(group, bias_pull_down)) | \ + SIUL2_MSCR_PUS(DT_PROP(group, bias_pull_up)) | \ + SIUL2_MSCR_SRC(DT_ENUM_IDX(group, slew_rate)) | \ + SIUL2_MSCR_DSE(DT_PROP(group, nxp_drive_strength)) | \ + SIUL2_MSCR_INV(DT_PROP(group, nxp_invert))}, \ + .imcr = { \ + .inst = NXP_SIUL2_PINMUX_GET_IMCR_SIUL2_IDX(value), \ + .idx = NXP_SIUL2_PINMUX_GET_IMCR_IDX(value), \ + .val = SIUL2_IMCR_SSS(NXP_SIUL2_PINMUX_GET_IMCR_SSS(value)), \ + } + +#endif /* ZEPHYR_SOC_NXP_MCXE31X_PINCTRL_SOC_H_ */ diff --git a/soc/nxp/mcx/mcxe/mcxe31x/soc.c b/soc/nxp/mcx/mcxe/mcxe31x/soc.c new file mode 100644 index 0000000000000..c7a2ebeddbd22 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/soc.c @@ -0,0 +1,40 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for nxp_mcxe platform + * + * This module provides routines to initialize and support board-level + * hardware for the nxp_mcxe platform. + */ + +#include +#include +#include +#include +#include "soc.h" + +/** + * + * @brief Perform basic hardware initialization + * + * Initialize the interrupt controller device drivers. + * Also initialize the counter device driver, if required. + * + * @return 0 + */ +void soc_early_init_hook(void) +{ +#ifdef CONFIG_SOC_MCXE31B + enable_sram_extra_latency(true); +#else + enable_sram_extra_latency(false); +#endif + /* Enable I/DCache */ + sys_cache_instr_enable(); + sys_cache_data_enable(); +} diff --git a/soc/nxp/mcx/mcxe/mcxe31x/soc.h b/soc/nxp/mcx/mcxe/mcxe31x/soc.h new file mode 100644 index 0000000000000..b8f35cb7aa46e --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/soc.h @@ -0,0 +1,27 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +#ifndef _ASMLANGUAGE + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void enable_sram_extra_latency(bool en); + +#ifdef __cplusplus +} +#endif + +#endif /* !_ASMLANGUAGE */ + +#endif /* _SOC__H_ */ diff --git a/soc/nxp/mcx/mcxe/mcxe31x/sram_config.c b/soc/nxp/mcx/mcxe/mcxe31x/sram_config.c new file mode 100644 index 0000000000000..c3f01a48911a3 --- /dev/null +++ b/soc/nxp/mcx/mcxe/mcxe31x/sram_config.c @@ -0,0 +1,24 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "fsl_common.h" + +/* Don't access system RAM when configuring PRAM FT_DIS. */ +void enable_sram_extra_latency(bool en) +{ + if (en) { + /* Configure SRAM read wait states. */ + PRAMC_0->PRCR1 |= PRAMC_PRCR1_FT_DIS_MASK; +#if defined(PRAMC_1) + PRAMC_1->PRCR1 |= PRAMC_PRCR1_FT_DIS_MASK; +#endif + } else { + PRAMC_0->PRCR1 &= ~PRAMC_PRCR1_FT_DIS_MASK; +#if defined(PRAMC_1) + PRAMC_1->PRCR1 &= ~PRAMC_PRCR1_FT_DIS_MASK; +#endif + } +} diff --git a/soc/nxp/mcx/soc.yml b/soc/nxp/mcx/soc.yml index 6917d7821542d..de513776a4c8e 100644 --- a/soc/nxp/mcx/soc.yml +++ b/soc/nxp/mcx/soc.yml @@ -23,6 +23,14 @@ family: - name: mcxe245 - name: mcxe246 - name: mcxe247 +- name: mcxe + series: + - name: mcxe31x + socs: + - name: mcxe315 + - name: mcxe316 + - name: mcxe317 + - name: mcxe31b - name: mcxa socs: - name: mcxa153 From 954dd84f8d0fcf5296fef5b2731480789adc2fdc Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Fri, 5 Sep 2025 23:23:31 +0800 Subject: [PATCH 344/397] dts: arm: nxp: add mcxe31x device tree - Generate a full devices device tree file - Use specific_part.dtsi + full_devices.dtsi way to desribe all devices Signed-off-by: Lucien Zhao --- dts/arm/nxp/nxp_mcxe31b.dtsi | 54 ++ dts/arm/nxp/nxp_mcxe31x_common.dtsi | 1062 +++++++++++++++++++++++++++ 2 files changed, 1116 insertions(+) create mode 100644 dts/arm/nxp/nxp_mcxe31b.dtsi create mode 100644 dts/arm/nxp/nxp_mcxe31x_common.dtsi diff --git a/dts/arm/nxp/nxp_mcxe31b.dtsi b/dts/arm/nxp/nxp_mcxe31b.dtsi new file mode 100644 index 0000000000000..ba7fec4f3b4d0 --- /dev/null +++ b/dts/arm/nxp/nxp_mcxe31b.dtsi @@ -0,0 +1,54 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + itcm: memory@0 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x0 DT_SIZE_K(32)>; + zephyr,memory-region = "ITCM"; + }; + + itcm1: memory@11400000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x11400000 DT_SIZE_K(32)>; + zephyr,memory-region = "ITCM1"; + }; + + dtcm: memory@20000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(64)>; + zephyr,memory-region = "DTCM"; + }; + + /* stdby_ram memory supports content retention in Standby mode */ + stdby_ram: memory@20400000 { + compatible = "mmio-sram"; + reg = <0x20400000 DT_SIZE_K(32)>; + }; + + /* sram memory is available only in Run mode */ + sram: memory@20408000 { + compatible = "mmio-sram"; + reg = <0x20408000 DT_SIZE_K(288)>; + }; + + dtcm1: memory@21400000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x21400000 DT_SIZE_K(64)>; + zephyr,memory-region = "DTCM1"; + }; + + peripheral: peripheral@40000000 { + ranges = <0x0 0x40000000 0x10000000>; + }; + }; +}; + +#include diff --git a/dts/arm/nxp/nxp_mcxe31x_common.dtsi b/dts/arm/nxp/nxp_mcxe31x_common.dtsi new file mode 100644 index 0000000000000..9dfd5ef039a31 --- /dev/null +++ b/dts/arm/nxp/nxp_mcxe31x_common.dtsi @@ -0,0 +1,1062 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + cpus { + #address-cells = <0x1>; + #size-cells = <0>; + + core0: cpu@0 { + reg = <0>; + device_type = "cpu"; + compatible = "arm,cortex-m7"; + }; + }; + + /* Dummy pinctrl node, filled with pin mux options at board level */ + pinctrl: pinctrl { + compatible = "nxp,mcxe31x-siul2-pinctrl"; + status = "okay"; + }; +}; + +&peripheral { + #address-cells = <1>; + #size-cells = <1>; + + adc_0: adc@a0000 { + compatible = "nxp,adc"; + reg = <0xa0000 0x3d4>; + interrupts = <180 0>; + status = "disabled"; + }; + + adc_1: adc@a4000 { + compatible = "nxp,adc"; + reg = <0xa4000 0x3d4>; + interrupts = <181 0>; + status = "disabled"; + }; + + adc_2: adc@a8000 { + compatible = "nxp,adc"; + reg = <0xa8000 0x3d4>; + interrupts = <182 0>; + status = "disabled"; + }; + + axbs_lite: axbs@200000 { + compatible = "nxp,axbs"; + reg = <0x200000 0x630>; + status = "disabled"; + }; + + bctu: bctu@84000 { + compatible = "nxp,bctu"; + reg = <0x84000 0x490>; + status = "disabled"; + }; + + cmu_0: cmu-fc@2bc000 { + compatible = "nxp,cmu-fc"; + reg = <0x2bc000 0x34>; + status = "disabled"; + }; + + cmu_1: cmu-fm@2bc020 { + compatible = "nxp,cmu-fm"; + reg = <0x2bc020 0x2c>; + status = "disabled"; + }; + + cmu_2: cmu-fm@2bc040 { + compatible = "nxp,cmu-fm"; + reg = <0x2bc040 0x2c>; + status = "disabled"; + }; + + cmu_3: cmu-fc@2bc060 { + compatible = "nxp,cmu-fc"; + reg = <0x2bc060 0x34>; + status = "disabled"; + }; + + cmu_4: cmu-fc@2bc080 { + compatible = "nxp,cmu-fc"; + reg = <0x2bc080 0x34>; + status = "disabled"; + }; + + cmu_5: cmu-fc@2bc0a0 { + compatible = "nxp,cmu-fc"; + reg = <0x2bc0a0 0x34>; + status = "disabled"; + }; + + configuration: configuration@39c000 { + compatible = "nxp,configuration"; + reg = <0x39c000 0x84>; + status = "disabled"; + }; + + crc: crc@380000 { + compatible = "nxp,crc"; + reg = <0x380000 0x28>; + }; + + dcm: dcm@2ac000 { + compatible = "nxp,dcm"; + reg = <0x2ac000 0xa0>; + status = "disabled"; + }; + + dcm_gpr: dcm-gpr@2ac200 { + compatible = "nxp,dcm-gpr"; + reg = <0x2ac200 0x510>; + status = "disabled"; + }; + + dmamux_0: dmamux@280000 { + compatible = "nxp,dmamux"; + reg = <0x280000 0x17>; + status = "disabled"; + }; + + dmamux_1: dmamux@284000 { + compatible = "nxp,dmamux"; + reg = <0x284000 0x17>; + status = "disabled"; + }; + + edma: edma@20c000 { + #dma-cells = <2>; + compatible = "nxp,mcux-edma"; + reg = <0x20c000 0x19c>; + dma-channels = <32>; + dma-requests = <128>; + interrupts = <4 0>, <5 0>, <6 0>, <7 0>, + <8 0>, <9 0>, <10 0>, <11 0>, + <12 0>, <13 0>, <14 0>, <15 0>, + <16 0>, <17 0>, <18 0>, <19 0>, + <20 0>, <21 0>, <22 0>, <23 0>, + <24 0>, <25 0>, <26 0>, <27 0>, + <28 0>, <29 0>, <30 0>, <31 0>, + <32 0>, <33 0>, <34 0>, <35 0>; + status = "disabled"; + }; + + eim: eim@258000 { + compatible = "nxp,eim"; + reg = <0x258000 0x8a4>; + status = "disabled"; + }; + + emac: emac@480000 { + compatible = "nxp,emac"; + reg = <0x480000 0x120c>; + interrupts = <105 0>; + status = "disabled"; + }; + + emios_0: emios@88000 { + compatible = "nxp,emios"; + reg = <0x88000 0x338>; + interrupts = <61 0>, <62 0>, <63 0>, <64 0>, + <65 0>, <66 0>; + interrupt-names = "emios0-2", "emios0-3", "emios0-4", + "emios0-5", "emios0-6", "emios0-7"; + status = "disabled"; + }; + + emios_1: emios@8c000 { + compatible = "nxp,emios"; + reg = <0x8c000 0x338>; + status = "disabled"; + }; + + emios_2: emios@90000 { + compatible = "nxp,emios"; + reg = <0x90000 0x338>; + status = "disabled"; + }; + + erm: erm@25c000 { + compatible = "nxp,erm"; + reg = <0x25c000 0x258>; + interrupts = <36 0>, <37 0>; + interrupt-names = "erm-0", "erm-1"; + status = "disabled"; + }; + + fccu: fccu@384000 { + compatible = "nxp,fccu"; + reg = <0x384000 0x158>; + status = "disabled"; + }; + + firc: firc@2d0000 { + compatible = "nxp,firc"; + reg = <0x2d0000 0x28>; + status = "disabled"; + }; + + flash: flash-c40@2ec000 { + compatible = "nxp,pflash"; + reg = <0x2ec000 0x19c>; + interrupts = <48 0>, <49 0>, <50 0>; + interrupt-names = "flash-0", "flash-1", "flash-2"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + program_flash: memory@400000 { + compatible = "soc-nv-flash"; + reg = <0x400000 DT_SIZE_K(4096)>; + }; + }; + + flexcan_0: flexcan@304000 { + compatible = "nxp,flexcan"; + reg = <0x304000 0x321c>; + interrupts = <109 0>, <110 0>, <111 0>, <112 0>; + interrupt-names = "flexcan0-0", "flexcan0-1", "flexcan0-2", "flexcan0-3"; + clocks = <&mc_cgm MCUX_FLEXCAN0_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexcan_1: flexcan@308000 { + compatible = "nxp,flexcan"; + reg = <0x308000 0xd4c>; + interrupts = <113 0>, <114 0>, <115 0>; + interrupt-names = "flexcan1-0", "flexcan1-1", "flexcan1-2"; + clocks = <&mc_cgm MCUX_FLEXCAN1_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexcan_2: flexcan@30c000 { + compatible = "nxp,flexcan"; + reg = <0x30c000 0xd4c>; + interrupts = <116 0>, <117 0>, <118 0>; + interrupt-names = "flexcan2-0", "flexcan2-1", "flexcan2-2"; + clocks = <&mc_cgm MCUX_FLEXCAN2_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexcan_3: flexcan@310000 { + compatible = "nxp,flexcan"; + reg = <0x310000 0xccc>; + interrupts = <119 0>, <120 0>; + interrupt-names = "flexcan3-0", "flexcan3-1"; + clocks = <&mc_cgm MCUX_FLEXCAN3_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexcan_4: flexcan@314000 { + compatible = "nxp,flexcan"; + reg = <0x314000 0xccc>; + interrupts = <121 0>, <122 0>; + interrupt-names = "flexcan4-0", "flexcan4-1"; + clocks = <&mc_cgm MCUX_FLEXCAN4_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexcan_5: flexcan@318000 { + compatible = "nxp,flexcan"; + reg = <0x318000 0xccc>; + interrupts = <123 0>, <124 0>; + interrupt-names = "flexcan5-0", "flexcan5-1"; + clocks = <&mc_cgm MCUX_FLEXCAN5_CLK>; + clk-source = <0>; + status = "disabled"; + }; + + flexio: flexio@324000 { + compatible = "nxp,flexio"; + reg = <0x324000 0x93c>; + interrupts = <139 0>; + clocks = <&mc_cgm MCUX_FLEXIO_CLK>; + status = "disabled"; + }; + + fxosc: fxosc@2d4000 { + compatible = "nxp,fxosc"; + reg = <0x2d4000 0x24>; + status = "disabled"; + }; + + intm: intm@27c000 { + compatible = "nxp,intm"; + reg = <0x27c000 0x64>; + status = "disabled"; + }; + + jdc: jdc@394000 { + compatible = "nxp,jdc"; + reg = <0x394000 0x2c>; + status = "disabled"; + }; + + lcu_0: lcu@98000 { + compatible = "nxp,lcu"; + reg = <0x98000 0x2c8>; + interrupts = <92 0>; + status = "disabled"; + }; + + lcu_1: lcu@9c000 { + compatible = "nxp,lcu"; + reg = <0x9c000 0x2c8>; + interrupts = <93 0>; + status = "disabled"; + }; + + lpcmp_0: lpcmp@370000 { + compatible = "nxp,lpcmp"; + reg = <0x370000 0x50>; + interrupts = <183 0>; + status = "disabled"; + }; + + lpcmp_1: lpcmp@374000 { + compatible = "nxp,lpcmp"; + reg = <0x374000 0x50>; + interrupts = <184 0>; + status = "disabled"; + }; + + lpcmp_2: lpcmp@4e8000 { + compatible = "nxp,lpcmp"; + reg = <0x4e8000 0x50>; + interrupts = <185 0>; + status = "disabled"; + }; + + lpi2c_0: lpi2c@350000 { + compatible = "nxp,lpi2c"; + reg = <0x350000 0x190>; + interrupts = <161 0>; + clocks = <&mc_cgm MCUX_LPI2C0_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpi2c_1: lpi2c@354000 { + compatible = "nxp,lpi2c"; + reg = <0x354000 0x190>; + interrupts = <162 0>; + clocks = <&mc_cgm MCUX_LPI2C1_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi_0: lpspi@358000 { + compatible = "nxp,lpspi"; + reg = <0x358000 0x81c>; + interrupts = <165 0>; + clocks = <&mc_cgm MCUX_LPSPI0_CLK>; + rx-fifo-size = <4>; + tx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi_1: lpspi@35c000 { + compatible = "nxp,lpspi"; + reg = <0x35c000 0x81c>; + interrupts = <166 0>; + clocks = <&mc_cgm MCUX_LPSPI1_CLK>; + rx-fifo-size = <4>; + tx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi_2: lpspi@360000 { + compatible = "nxp,lpspi"; + reg = <0x360000 0x81c>; + interrupts = <167 0>; + clocks = <&mc_cgm MCUX_LPSPI2_CLK>; + rx-fifo-size = <4>; + tx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi_3: lpspi@364000 { + compatible = "nxp,lpspi"; + reg = <0x364000 0x81c>; + interrupts = <168 0>; + clocks = <&mc_cgm MCUX_LPSPI3_CLK>; + rx-fifo-size = <4>; + tx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi_4: lpspi@4bc000 { + compatible = "nxp,lpspi"; + reg = <0x4bc000 0x81c>; + interrupts = <169 0>; + clocks = <&mc_cgm MCUX_LPSPI4_CLK>; + rx-fifo-size = <4>; + tx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi_5: lpspi@4c0000 { + compatible = "nxp,lpspi"; + reg = <0x4c0000 0x81c>; + interrupts = <170 0>; + clocks = <&mc_cgm MCUX_LPSPI5_CLK>; + rx-fifo-size = <4>; + tx-fifo-size = <4>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpuart_0: lpuart@328000 { + compatible = "nxp,lpuart"; + reg = <0x328000 0x50>; + interrupts = <141 0>; + clocks = <&mc_cgm MCUX_LPUART0_CLK>; + status = "disabled"; + }; + + lpuart_1: lpuart@32c000 { + compatible = "nxp,lpuart"; + reg = <0x32c000 0x50>; + interrupts = <142 0>; + clocks = <&mc_cgm MCUX_LPUART1_CLK>; + status = "disabled"; + }; + + lpuart_2: lpuart@330000 { + compatible = "nxp,lpuart"; + reg = <0x330000 0x50>; + interrupts = <143 0>; + clocks = <&mc_cgm MCUX_LPUART2_CLK>; + status = "disabled"; + }; + + lpuart_3: lpuart@334000 { + compatible = "nxp,lpuart"; + reg = <0x334000 0x50>; + interrupts = <144 0>; + clocks = <&mc_cgm MCUX_LPUART3_CLK>; + status = "disabled"; + }; + + lpuart_4: lpuart@338000 { + compatible = "nxp,lpuart"; + reg = <0x338000 0x50>; + interrupts = <145 0>; + clocks = <&mc_cgm MCUX_LPUART4_CLK>; + status = "disabled"; + }; + + lpuart_5: lpuart@33c000 { + compatible = "nxp,lpuart"; + reg = <0x33c000 0x50>; + interrupts = <146 0>; + clocks = <&mc_cgm MCUX_LPUART5_CLK>; + status = "disabled"; + }; + + lpuart_6: lpuart@340000 { + compatible = "nxp,lpuart"; + reg = <0x340000 0x50>; + interrupts = <147 0>; + clocks = <&mc_cgm MCUX_LPUART6_CLK>; + status = "disabled"; + }; + + lpuart_7: lpuart@344000 { + compatible = "nxp,lpuart"; + reg = <0x344000 0x50>; + interrupts = <148 0>; + clocks = <&mc_cgm MCUX_LPUART7_CLK>; + status = "disabled"; + }; + + lpuart_8: lpuart@48c000 { + compatible = "nxp,lpuart"; + reg = <0x48c000 0x50>; + interrupts = <149 0>; + clocks = <&mc_cgm MCUX_LPUART8_CLK>; + status = "disabled"; + }; + + lpuart_9: lpuart@490000 { + compatible = "nxp,lpuart"; + reg = <0x490000 0x50>; + interrupts = <150 0>; + clocks = <&mc_cgm MCUX_LPUART9_CLK>; + status = "disabled"; + }; + + lpuart_10: lpuart@494000 { + compatible = "nxp,lpuart"; + reg = <0x494000 0x50>; + interrupts = <151 0>; + clocks = <&mc_cgm MCUX_LPUART10_CLK>; + status = "disabled"; + }; + + lpuart_11: lpuart@498000 { + compatible = "nxp,lpuart"; + reg = <0x498000 0x50>; + interrupts = <152 0>; + clocks = <&mc_cgm MCUX_LPUART11_CLK>; + status = "disabled"; + }; + + lpuart_12: lpuart@49c000 { + compatible = "nxp,lpuart"; + reg = <0x49c000 0x50>; + interrupts = <153 0>; + clocks = <&mc_cgm MCUX_LPUART12_CLK>; + status = "disabled"; + }; + + lpuart_13: lpuart@4a0000 { + compatible = "nxp,lpuart"; + reg = <0x4a0000 0x50>; + interrupts = <154 0>; + clocks = <&mc_cgm MCUX_LPUART13_CLK>; + status = "disabled"; + }; + + lpuart_14: lpuart@4a4000 { + compatible = "nxp,lpuart"; + reg = <0x4a4000 0x50>; + interrupts = <155 0>; + clocks = <&mc_cgm MCUX_LPUART14_CLK>; + status = "disabled"; + }; + + lpuart_15: lpuart@4a8000 { + compatible = "nxp,lpuart"; + reg = <0x4a8000 0x50>; + interrupts = <156 0>; + clocks = <&mc_cgm MCUX_LPUART15_CLK>; + status = "disabled"; + }; + + mc_cgm: mc_cgm@2d8000 { + compatible = "nxp,mc-cgm"; + reg = <0x2d8000 0x61c>; + #clock-cells = <1>; + status = "disabled"; + }; + + mc_me: mc-me@2dc000 { + compatible = "nxp,mc-me"; + reg = <0x2dc000 0x554>; + status = "disabled"; + }; + + mc_rgm: mc-rgm@28c000 { + compatible = "nxp,mc-rgm"; + reg = <0x28c000 0x4c>; + status = "disabled"; + }; + + mcm_0: mcm@e0080000 { + compatible = "nxp,mcm"; + reg = <0xe0080000 0x430>; + status = "disabled"; + }; + + mdm_ap: mdm-ap@250600 { + compatible = "nxp,mdm-ap"; + reg = <0x250600 0x11c>; + status = "disabled"; + }; + + mscm: mscm@260000 { + compatible = "nxp,mscm"; + reg = <0x260000 0xa6e>; + status = "disabled"; + }; + + mu0_b: mu@38c000 { + compatible = "nxp,mu"; + reg = <0x38c000 0x2ac>; + status = "disabled"; + }; + + mu1_b: mu@4ec000 { + compatible = "nxp,mu"; + reg = <0x4ec000 0x2ac>; + }; + + pflash: pflash@268000 { + compatible = "nxp,pflash"; + reg = <0x268000 0x4dc>; + status = "disabled"; + }; + + pit_0: pit@b0000 { + compatible = "nxp,pit"; + reg = <0xb0000 0x15c>; + interrupts = <96 0>; + clocks = <&mc_cgm MCUX_PIT0_CLK>; + max-load-value = <0xffffffff>; + status = "disabled"; + }; + + pit_1: pit@b4000 { + compatible = "nxp,pit"; + reg = <0xb4000 0x15c>; + interrupts = <97 0>; + clocks = <&mc_cgm MCUX_PIT1_CLK>; + max-load-value = <0xffffffff>; + status = "disabled"; + }; + + pit_2: pit@2fc000 { + compatible = "nxp,pit"; + reg = <0x2fc000 0x15c>; + interrupts = <98 0>; + clocks = <&mc_cgm MCUX_PIT2_CLK>; + max-load-value = <0xffffffff>; + status = "disabled"; + }; + + pll: plldig@402e0000 { + compatible = "nxp,plldig"; + reg = <0x402e0000 0xa4>; + status = "disabled"; + }; + + pmc: pmc@2e8000 { + compatible = "nxp,pmc"; + reg = <0x2e8000 0x2c>; + interrupts = <52 0>; + status = "disabled"; + }; + + pramc_0: pramc@264000 { + compatible = "nxp,pramc"; + reg = <0x264000 0x20>; + status = "disabled"; + }; + + pramc_1: pramc@464000 { + compatible = "nxp,pramc"; + reg = <0x464000 0x20>; + status = "disabled"; + }; + + quadspi: qspi@4cc000 { + compatible = "nxp,qspi"; + reg = <0x4cc000 0x37c>; + interrupts = <173 0>; + status = "disabled"; + }; + + quadspi_ardb: @68000000 { + compatible = "nxp,"; + reg = <0x68000000 0x21c>; + status = "disabled"; + }; + + rtc: rtc@288000 { + compatible = "nxp,rtc"; + reg = <0x288000 0x34>; + interrupts = <102 0>; + status = "disabled"; + }; + + sai_0: sai@36c000 { + compatible = "nxp,sai"; + reg = <0x36c000 0x100>; + interrupts = <174 0>; + status = "disabled"; + }; + + sai_1: sai@4dc000 { + compatible = "nxp,sai"; + reg = <0x4dc000 0x100>; + interrupts = <175 0>; + status = "disabled"; + }; + + sda_ap: sda-ap@254700 { + compatible = "nxp,sda-ap"; + reg = <0x254700 0x11c>; + status = "disabled"; + }; + + selftest: selftest-gpr@3b0000 { + compatible = "nxp,selftest-gpr"; + reg = <0x3b0000 0x34>; + status = "disabled"; + }; + + sema42: sema42@460000 { + compatible = "nxp,sema42"; + reg = <0x460000 0x52>; + status = "disabled"; + }; + + sirc: sirc@402c8000 { + compatible = "nxp,sirc"; + reg = <0x402c8000 0x2c>; + status = "disabled"; + }; + + siul2_0: siul2@290000 { + reg = <0x290000 0x17d4>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x290000 0x17d4>; + + eirq0: eirq@10 { + compatible = "nxp,siul2-eirq"; + reg = <0x10 0xb4>; + #address-cells = <0>; + interrupts = <53 0>, <54 0>, <55 0>, <56 0>; + interrupt-controller; + #interrupt-cells = <2>; + status = "disabled"; + }; + + gpioa_l: gpio@1702 { + compatible = "nxp,siul2-gpio"; + reg = <0x1702 0x02>, <0x240 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 0>, <1 1>, <2 2>, <3 3>, <4 4>, + <5 5>, <6 6>, <7 7>, <8 16>, <9 17>, + <10 18>, <11 19>, <12 20>, <13 21>, + <14 22>, <15 23>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <1 9>, <2 4>, <6 19>, + <8 27>, <9 25>, <13 8>, <15 24>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpioa_h: gpio@1700 { + compatible = "nxp,siul2-gpio"; + reg = <0x1700 0x02>, <0x280 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 4>, <2 0>, <3 1>, <4 2>, + <5 3>, <9 5>, <12 6>, <14 7>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <0 35>, <4 63>, <9 38>, + <10 39>, <14 41>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpiob_l: gpio@1706 { + compatible = "nxp,siul2-gpio"; + reg = <0x1706 0x02>, <0x2c0 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 8>, <1 9>, <2 10>, <3 11>, <4 12>, + <5 13>, <8 14>, <9 15>, <10 24>, <11 25>, + <12 26>, <13 27>, <14 28>, <15 29>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <0 11>, <2 12>, <8 29>, + <9 21>, <11 20>, <12 16>, <13 15>, <15 37>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + gpio-reserved-ranges = <6 2>; + status = "disabled"; + }; + + gpiob_h: gpio@1704 { + compatible = "nxp,siul2-gpio"; + reg = <0x1704 0x02>, <0x300 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 30>, <1 31>, <5 8>, <6 9>, <7 10>, + <8 11>, <9 12>, <10 13>, <12 14>, <15 15>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <0 17>, <1 18>, <3 42>, + <5 43>, <7 44>, <10 45>, <12 46>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpioc_l: gpio@170a { + compatible = "nxp,siul2-gpio"; + reg = <0x170a 0x02>, <0x340 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 1>, <1 1>, <2 2>, <3 3>, <4 4>, + <5 5>, <6 6>, <7 7>, <8 16>, <9 17>, + <10 18>, <11 19>, <12 20>, <13 21>, + <14 22>, <15 23>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <6 7>, <7 6>, <9 14>, <11 22>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpioc_h: gpio@1708 { + compatible = "nxp,siul2-gpio"; + reg = <0x1708 0x02>, <0x380 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <4 16>, <5 17>, <7 18>, <8 19>, + <9 20>, <10 21>, <11 22>, <13 23>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <2 40>, <4 47>, <7 48>, + <8 50>, <9 49>, <10 52>, <13 51>, <15 53>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpiod_l: gpio@170e { + compatible = "nxp,siul2-gpio"; + reg = <0x170e 0x02>, <0x3c0 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 8>, <1 9>, <2 10>, <3 11>, <4 12>, + <5 13>, <6 14>, <7 15>, <8 24>, + <9 25>, <10 26>, <11 27>, <12 28>, + <13 29>, <14 30>, <15 31>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <0 10>, <2 13>, <3 5>, + <4 26>, <13 28>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpiod_h: gpio@170c { + compatible = "nxp,siul2-gpio"; + reg = <0x170c 0x02>, <0x400 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <1 24>, <4 25>, <5 26>, <6 27>, + <7 28>, <8 29>, <11 30>, <12 31>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <4 58>, <7 54>, <11 55>, + <13 56>, <15 57>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpioe_l: gpio@1712 { + compatible = "nxp,siul2-gpio"; + reg = <0x1712 0x02>, <0x440 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 0>, <1 1>, <2 2>, <3 3>, + <4 4>, <5 5>, <6 6>, <8 7>, + <9 8>, <10 9>, <11 10>, <12 11>, + <13 12>, <14 13>, <15 14>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <0 30>, <2 31>, <5 36>, + <6 33>, <11 32>, <14 34>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpioe_h: gpio@1710 { + compatible = "nxp,siul2-gpio"; + reg = <0x1710 0x02>, <0x480 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 15>; + nxp,wkpu = <&wkpu>; + nxp,wkpu-interrupts = <0 23>, <2 59>, <5 60>, + <7 61>, <9 62>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpiof_l: gpio@1716 { + compatible = "nxp,siul2-gpio"; + reg = <0x1716 0x02>, <0x4c0 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 0>, <1 1>, <2 2>, <3 3>, + <4 4>, <5 5>, <6 6>, <7 7>, + <8 16>, <9 17>, <10 18>, <11 19>, + <12 20>, <13 21>, <14 22>, <15 23>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpiof_h: gpio@1714 { + compatible = "nxp,siul2-gpio"; + reg = <0x1714 0x02>, <0x500 0x40>; + reg-names = "pgpdo", "mscr"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpiog_l: gpio@171a { + compatible = "nxp,siul2-gpio"; + reg = <0x171a 0x02>, <0x540 0x40>; + reg-names = "pgpdo", "mscr"; + interrupt-parent = <&eirq0>; + interrupts = <0 8>, <1 9>, <2 10>, <3 11>, + <4 12>, <5 13>, <6 14>, <7 15>, + <8 24>, <9 25>, <10 26>, <11 27>, + <12 28>, <13 29>, <14 30>, <15 31>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + + gpiog_h: gpio@1718 { + compatible = "nxp,siul2-gpio"; + reg = <0x1718 0x02>, <0x580 0x40>; + reg-names = "pgpdo", "mscr"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + }; + }; + + stcu: stcu@3a0000 { + compatible = "nxp,stcu"; + reg = <0x3a0000 0x2260>; + status = "disabled"; + }; + + stm_0: stm@274000 { + compatible = "nxp,stm"; + reg = <0x274000 0x68>; + interrupts = <39 0>; + status = "disabled"; + }; + + stm_1: stm@474000 { + compatible = "nxp,stm"; + reg = <0x474000 0x68>; + interrupts = <40 0>; + status = "disabled"; + }; + + swt_0: swt@270000 { + compatible = "nxp,swt"; + reg = <0x270000 0x3c>; + interrupts = <42 0>; + status = "disabled"; + }; + + sxosc: sxosc@402cc000 { + compatible = "nxp,sxosc"; + reg = <0x402cc000 0x24>; + status = "disabled"; + }; + + tempsense: tempsense@37c000 { + compatible = "nxp,tempsense"; + reg = <0x37c000 0x30>; + status = "disabled"; + }; + + trgmux: trgmux@80000 { + compatible = "nxp,trgmux"; + reg = <0x80000 0xbc>; + status = "disabled"; + }; + + tspc: tspc@2c4000 { + compatible = "nxp,tspc"; + reg = <0x2c4000 0xc4>; + status = "disabled"; + }; + + virt_wrapper: virt-wrapper@2a8000 { + compatible = "nxp,virt-wrapper"; + reg = <0x2a8000 0x124>; + status = "disabled"; + }; + + wkpu: wkpu@2b4000 { + compatible = "nxp,wkpu"; + reg = <0x2b4000 0x90>; + interrupts = <83 0>; + status = "disabled"; + }; + + xbic_axbs: xbic@204000 { + compatible = "nxp,xbic"; + reg = <0x204000 0x2c>; + status = "disabled"; + }; + + xbic_axbs_edma: xbic@404000 { + compatible = "nxp,xbic"; + reg = <0x404000 0x2c>; + status = "disabled"; + }; + + xbic_axbs_peri: xbic@208000 { + compatible = "nxp,xbic"; + reg = <0x208000 0x2c>; + status = "disabled"; + }; + + xbic_axbs_tcm: xbic@400000 { + compatible = "nxp,xbic"; + reg = <0x400000 0x2c>; + status = "disabled"; + }; + + xrdc: xrdc@278000 { + compatible = "nxp,xrdc"; + reg = <0x278000 0x248c>; + status = "disabled"; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; From 4a759a65bb2b42efa3e5b5aa529954fd0ce63179 Mon Sep 17 00:00:00 2001 From: Lucien Zhao Date: Sat, 20 Sep 2025 13:07:20 +0800 Subject: [PATCH 345/397] boards: nxp: add frdm_mcxe31b board support - support XIP way to boot - add board doc and picture - enable cases below: hello_world/blinky/button/ philosophers/synchronization/ gpio_basic_api Signed-off-by: Lucien Zhao --- boards/nxp/frdm_mcxe31b/CMakeLists.txt | 7 + boards/nxp/frdm_mcxe31b/Kconfig | 12 ++ boards/nxp/frdm_mcxe31b/Kconfig.frdm_mcxe31b | 5 + boards/nxp/frdm_mcxe31b/board.cmake | 8 + boards/nxp/frdm_mcxe31b/board.yml | 6 + .../frdm_mcxe31b/boot_header/boot_header.c | 91 +++++++++ .../frdm_mcxe31b/boot_header/boot_header.h | 19 ++ boards/nxp/frdm_mcxe31b/doc/frdm_mcxe31b.webp | Bin 0 -> 42758 bytes boards/nxp/frdm_mcxe31b/doc/index.rst | 174 ++++++++++++++++++ .../frdm_mcxe31b/frdm_mcxe31b-pinctrl.dtsi | 28 +++ boards/nxp/frdm_mcxe31b/frdm_mcxe31b.dts | 167 +++++++++++++++++ boards/nxp/frdm_mcxe31b/frdm_mcxe31b.yaml | 16 ++ .../nxp/frdm_mcxe31b/frdm_mcxe31b_defconfig | 7 + .../boards/frdm_mcxe31b.overlay | 29 +++ .../drivers/gpio/gpio_basic_api/testcase.yaml | 2 + 15 files changed, 571 insertions(+) create mode 100644 boards/nxp/frdm_mcxe31b/CMakeLists.txt create mode 100644 boards/nxp/frdm_mcxe31b/Kconfig create mode 100644 boards/nxp/frdm_mcxe31b/Kconfig.frdm_mcxe31b create mode 100644 boards/nxp/frdm_mcxe31b/board.cmake create mode 100644 boards/nxp/frdm_mcxe31b/board.yml create mode 100644 boards/nxp/frdm_mcxe31b/boot_header/boot_header.c create mode 100644 boards/nxp/frdm_mcxe31b/boot_header/boot_header.h create mode 100644 boards/nxp/frdm_mcxe31b/doc/frdm_mcxe31b.webp create mode 100644 boards/nxp/frdm_mcxe31b/doc/index.rst create mode 100644 boards/nxp/frdm_mcxe31b/frdm_mcxe31b-pinctrl.dtsi create mode 100644 boards/nxp/frdm_mcxe31b/frdm_mcxe31b.dts create mode 100644 boards/nxp/frdm_mcxe31b/frdm_mcxe31b.yaml create mode 100644 boards/nxp/frdm_mcxe31b/frdm_mcxe31b_defconfig create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/frdm_mcxe31b.overlay diff --git a/boards/nxp/frdm_mcxe31b/CMakeLists.txt b/boards/nxp/frdm_mcxe31b/CMakeLists.txt new file mode 100644 index 0000000000000..161914f1a01bb --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_NXP_MCXE31X_BOOT_HEADER) + zephyr_library_sources(boot_header/boot_header.c) + zephyr_library_include_directories(boot_header) +endif() diff --git a/boards/nxp/frdm_mcxe31b/Kconfig b/boards/nxp/frdm_mcxe31b/Kconfig new file mode 100644 index 0000000000000..5373c9c7f9f3b --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/Kconfig @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NXP_MCXE31X_BOOT_HEADER + bool "MCXE31x boot header support" + select SOC_NXP_MCXE31X_BOOT_HEADER + default y + help + Enable this option to include the MCXE31x boot header in the final + image. The boot header is required for proper operation of the + on-chip bootloader. + See the MCXE31x reference manual for more details. diff --git a/boards/nxp/frdm_mcxe31b/Kconfig.frdm_mcxe31b b/boards/nxp/frdm_mcxe31b/Kconfig.frdm_mcxe31b new file mode 100644 index 0000000000000..0a5bb955a9b88 --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/Kconfig.frdm_mcxe31b @@ -0,0 +1,5 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FRDM_MCXE31B + select SOC_PART_NUMBER_MCXE31BMPB diff --git a/boards/nxp/frdm_mcxe31b/board.cmake b/boards/nxp/frdm_mcxe31b/board.cmake new file mode 100644 index 0000000000000..7c3a7470cf770 --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/board.cmake @@ -0,0 +1,8 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=MCXE31B") +board_runner_args(linkserver "--device=MCXE31B:FRDM-MCXE31B") + +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/nxp/frdm_mcxe31b/board.yml b/boards/nxp/frdm_mcxe31b/board.yml new file mode 100644 index 0000000000000..f4030712e3c2b --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/board.yml @@ -0,0 +1,6 @@ +board: + name: frdm_mcxe31b + full_name: FRDM-MCXE31B + vendor: nxp + socs: + - name: mcxe31b diff --git a/boards/nxp/frdm_mcxe31b/boot_header/boot_header.c b/boards/nxp/frdm_mcxe31b/boot_header/boot_header.c new file mode 100644 index 0000000000000..da11b11e521c0 --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/boot_header/boot_header.c @@ -0,0 +1,91 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "boot_header.h" +#include "fsl_common.h" + +/****************************************************************************** + * External references + ******************************************************************************/ +#if defined(CONFIG_BOARD_NXP_MCXE31X_BOOT_HEADER) && (CONFIG_BOARD_NXP_MCXE31X_BOOT_HEADER != 0U) + +extern void *const _vector_start; + +/****************************************************************************** + * Boot Header + ******************************************************************************/ +typedef struct image_vector_table { + uint32_t header; /* header */ + uint32_t boot_config; /* Boot configuration Word */ + const uint32_t reserved1; /* Reserved */ + const uint32_t *cm7_0_start_address; /* Start address of CM7_0 Core */ + const uint32_t reserved2; /* Reserved */ + const uint32_t *reserved3; /* Reserved */ + const uint32_t reserved4; /* Reserved */ + const uint32_t *reserved5; /* Reserved */ + const uint32_t *reserved6; /* Reserved */ + const uint32_t *lcc_config; /* Address of LC config */ + uint8_t reserved7[216]; /* Reserved for future use */ +} ivt_t; + +/****************************************************************************** + * SBAF definitions + ******************************************************************************/ +/* CM7_0_ENABLE: */ +/* 0- Cortex-M7_0 application core clock gated after boot */ +/* 1- Cortex-M7_0 application core clock un-gated after boot */ +#define CM7_0_ENABLE_MASK 1U + +/* Control the boot flow of the application: */ +/* 0- Non-Secure Boot- Application image is started by SBAF without any */ +/* authentication in parallel to HSE firmware. */ +/* 1- Secure Boot- Application image is executed by HSE firmware after the */ +/* authentication. SBAF only starts the HSE firmware after successful */ +/* authentication. */ +#define BOOT_SEQ_MASK 8U + +/* APP_SWT_INIT: Control SWT0 before starting application core(s): */ +/* 0- Disable. */ +/* 1- Enable. SBAF initializes SWT0 before enabling application cores. */ +/* SBAF scans this bit only when BOOT_SEQ bit is 0. */ +#define APP_SWT_INIT_MASK 32U + +/*! + * @brief Sets register field in peripheral configuration structure. + * @details This macro sets register field mask in the peripheral + * configuration structure. + * @param mask Register field to be set. + * @note Implemented as a macro. + */ +#define SET(mask) (mask) + +/*! + * @brief Clears register field in peripheral configuration structure. + * @details This macro clears register field mask in the peripheral + * configuration structure. + * @param mask Register field to be cleared. + * @note Implemented as a macro. + */ +#define CLR(mask) 0 + +const ivt_t _boot_header __attribute__((used, section(".boot_header"))) = { + .header = 0x5AA55AA5, + .boot_config = SET(CM7_0_ENABLE_MASK) | /* booting core is core0 */ + CLR(BOOT_SEQ_MASK) | /* unsecure boot is only supported */ + CLR(APP_SWT_INIT_MASK), /* SWT0 is not setup by BAF */ + .cm7_0_start_address = (const uint32_t *)&_vector_start, + .lcc_config = (const uint32_t *)&lc_config}; + +/****************************************************************************** + * Default configurations that can be overridden by strong definitions + ******************************************************************************/ + +__WEAK const boot_lc_config_t lc_config = 0xffffffff; + +#endif /* CONFIG_BOARD_NXP_MCXE31X_BOOT_HEADER */ +/****************************************************************************** + * End of module + ******************************************************************************/ diff --git a/boards/nxp/frdm_mcxe31b/boot_header/boot_header.h b/boards/nxp/frdm_mcxe31b/boot_header/boot_header.h new file mode 100644 index 0000000000000..5cd390d196a1c --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/boot_header/boot_header.h @@ -0,0 +1,19 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BOOT_HEADER_H_ +#define ZEPHYR_INCLUDE_BOOT_HEADER_H_ + +#include "fsl_common.h" + +/****************************************************************************** + * Configuration structure definition * + ******************************************************************************/ + +typedef uint32_t boot_lc_config_t; +extern const boot_lc_config_t lc_config; + +#endif /* ZEPHYR_INCLUDE_BOOT_HEADER_H_ */ diff --git a/boards/nxp/frdm_mcxe31b/doc/frdm_mcxe31b.webp b/boards/nxp/frdm_mcxe31b/doc/frdm_mcxe31b.webp new file mode 100644 index 0000000000000000000000000000000000000000..e95771fcd0ec35e78566d879be2e5eb366571933 GIT binary patch literal 42758 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 literal 0 HcmV?d00001 diff --git a/boards/nxp/frdm_mcxe31b/doc/index.rst b/boards/nxp/frdm_mcxe31b/doc/index.rst new file mode 100644 index 0000000000000..983390bbea5f5 --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/doc/index.rst @@ -0,0 +1,174 @@ +.. zephyr:board:: frdm_mcxe31b + +Overview +******** +The FRDM-MCXE31B board is a design and evaluation platform based on the NXP MCXE31B +microcontroller (MCU). NXP MCXE31B MCU based on an Arm Cortex-M7 core, running at +speeds of up to 160 MHz with a 2.97 to 5.5V supply. + +Hardware +******** + +- MCXE31B Arm Cortex-M7 microcontroller running up to 160 MHz +- 4MB dual-bank on chip Flash +- 320KB SRAM + 192KB TCM +- 2x I2C +- 6x SPI +- 16x UART +- On-board MCU-Link debugger with CMSIS-DAP +- Arduino Header, mikroBUS + +For more information about the MCXE31B SoC and FRDM-MCXE31B board, see: + +- `MCXE31X Datasheet`_ +- `MCXE31X Reference Manual`_ +- `FRDM-MCXE31B Board User Manual`_ + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Connections and IOs +=================== + +Each GPIO port is divided into two banks: low bank, from pin 0 to 15, and high +bank, from pin 16 to 31. For example, ``PTA2`` is the pin 2 of ``gpioa_l`` (low +bank), and ``PTA20`` is the pin 4 of ``gpioa_h`` (high bank). + +The GPIO controller provides the option to route external input pad interrupts +to either the SIUL2 EIRQ or WKPU interrupt controllers, as supported by the SoC. +By default, GPIO interrupts are routed to SIUL2 EIRQ interrupt controller, +unless they are explicity configured to be directed to the WKPU interrupt +controller, as outlined in :zephyr_file:`dts/bindings/gpio/nxp,siul2-gpio.yaml`. + +To find information about which GPIOs are compatible with each interrupt +controller, refer to the device reference manual. + ++-------+-------------+---------------------------+ +| Name | Function | Usage | ++=======+=============+===========================+ +| PTC16 | GPIO | Red LED | ++-------+-------------+---------------------------+ +| PTB22 | GPIO | Green LED | ++-------+-------------+---------------------------+ +| PTC14 | GPIO | Blue LED | ++-------+-------------+---------------------------+ +| PTE3 | LPUART5_RX | UART Console | ++-------+-------------+---------------------------+ +| PTE14 | LPUART5_TX | UART Console | ++-------+-------------+---------------------------+ + +System Clock +============ + +The MCXE31B SoC is configured to use PLL running at 160MHz as a source for +the system clock. + +Serial Port +=========== + +The MCXE31B LPUART5 is used for the console. + +Programming and Debugging +************************* + +.. zephyr:board-supported-runners:: + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Configuring a Debug Probe +========================= + +A debug probe is used for both flashing and debugging the board. This board is +configured by default to use the MCU-Link CMSIS-DAP Onboard Debug Probe. + +Using LinkServer +---------------- + +Linkserver is the default runner for this board, and supports the factory +default MCU-Link firmware. Follow the instructions in +:ref:`mcu-link-cmsis-onboard-debug-probe` to reprogram the default MCU-Link +firmware. This only needs to be done if the default onboard debug circuit +firmware was changed. To put the board in ``ISP mode`` to program the firmware, +short jumper JP3. + +Using J-Link +------------ + +There are two options. The onboard debug circuit can be updated with Segger +J-Link firmware by following the instructions in +:ref:`mcu-link-jlink-onboard-debug-probe`. +To be able to program the firmware, you need to put the board in ``ISP mode`` +by shorting the jumper JP3. +The second option is to attach a :ref:`jlink-external-debug-probe` to the +10-pin SWD connector (J14) of the board. +For both options use the ``-r jlink`` option with west to use the jlink runner. + +.. code-block:: console + + west flash -r jlink + +Configuring a Console +===================== + +Connect a USB cable from your PC to J13, and use the serial terminal of your choice +(minicom, putty, etc.) with the following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flashing +======== + +Here is an example for the :zephyr:code-sample:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_mcxe31b + :goals: flash + +Open a serial terminal, reset the board (press the RESET button), and you should +see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v4.2.0-2092-g17e93a718422 *** + Hello World! frdm_mcxe31b/mcxe31b + +Debugging +========= + +Here is an example for the :zephyr:code-sample:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_mcxe31b + :goals: debug + +Open a serial terminal, step through the application in your debugger, and you +should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v4.2.0-2092-g17e93a718422 *** + Hello World! frdm_mcxe31b/mcxe31b + +Troubleshooting +=============== + +.. include:: ../../common/segger-ecc-systemview.rst.inc + +.. include:: ../../common/board-footer.rst.inc + +.. _MCXE31X Datasheet: + https://www.nxp.com/docs/en/data-sheet/MCXEP172M160FB0.pdf + +.. _MCXE31X Reference Manual: + https://www.nxp.com/webapp/Download?colCode=MCXE31XRM&location=null + +.. _FRDM-MCXE31B Board User Manual: + https://www.nxp.com/webapp/Download?colCode=UM12330&location=null&isHTMLorPDF=HTML diff --git a/boards/nxp/frdm_mcxe31b/frdm_mcxe31b-pinctrl.dtsi b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b-pinctrl.dtsi new file mode 100644 index 0000000000000..965205033ec69 --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b-pinctrl.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright 2025 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include + +&pinctrl { + eirq0_default: eirq0_default { + group1 { + pinmux = ; + input-enable; + }; + }; + + pinmux_lpuart_5: pinmux_lpuart_5 { + group1 { + pinmux = ; + output-enable; + }; + + group2 { + pinmux = ; + input-enable; + }; + }; +}; diff --git a/boards/nxp/frdm_mcxe31b/frdm_mcxe31b.dts b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b.dts new file mode 100644 index 0000000000000..d56bd97263b72 --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b.dts @@ -0,0 +1,167 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "frdm_mcxe31b-pinctrl.dtsi" +#include +#include +#include + +/ { + model = "NXP FRDM_MCXE31B board"; + compatible = "nxp,mcxe31b"; + + aliases { + led0 = &red_led; + led1 = &green_led; + led2 = &blue_led; + sw0 = &user_button; + }; + + chosen { + zephyr,sram = &sram; + zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; + zephyr,flash = &program_flash; + zephyr,flash-controller = &flash; + zephyr,console = &lpuart_5; + }; + + leds { + compatible = "gpio-leds"; + + red_led: led_0 { + gpios = <&gpioc_h 0 GPIO_ACTIVE_LOW>; + label = "Red LED"; + }; + + green_led: led_1 { + gpios = <&gpiob_h 6 GPIO_ACTIVE_LOW>; + label = "Green LED"; + }; + + blue_led: led_2 { + gpios = <&gpioc_l 14 GPIO_ACTIVE_LOW>; + label = "Blue LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button: button_0 { + label = "User SW3"; + gpios = <&gpiod_l 5 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; + +&core0 { + clock-frequency = ; +}; + +&gpiob_h { + status = "okay"; +}; + +&lpuart_5 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart_5>; + pinctrl-names = "default"; + dmas = <&edma 1 44>, <&edma 2 45>; + dma-names = "tx", "rx"; +}; + +&gpioc_l { + status = "okay"; +}; + +&gpioc_h { + status = "okay"; +}; + +&gpiod_l { + status = "okay"; +}; + +&eirq0 { + pinctrl-0 = <&eirq0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&firc { + status = "okay"; + firc-div = "UnDiv"; +}; + +&fxosc { + status = "okay"; + freq = <16000000>; + workmode = "crystal"; + delay = <49>; + overdrive = <12>; +}; + +&pll { + status = "okay"; + workmode = "Integer"; + prediv = <2>; + postdiv = <2>; + multiplier = <120>; + fracloopdiv = <0>; + stepsize = <0>; + stepnum = <0>; + accuracy = "Accuracy9"; + outdiv = <3 3>; +}; + +&mc_cgm { + status = "okay"; + max-ido-change = <50>; + step-duration = <1>; + clk-src-freq = <160000000>; + mux-0-dc-0-div = <1>; + mux-0-dc-1-div = <2>; + mux-0-dc-2-div = <4>; + mux-0-dc-3-div = <2>; + mux-0-dc-4-div = <4>; + mux-0-dc-5-div = <4>; + mux-0-dc-6-div = <1>; +}; diff --git a/boards/nxp/frdm_mcxe31b/frdm_mcxe31b.yaml b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b.yaml new file mode 100644 index 0000000000000..7a1dafbd58828 --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b.yaml @@ -0,0 +1,16 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +identifier: frdm_mcxe31b +name: NXP FRDM MCXE31B +type: mcu +arch: arm +ram: 288 +flash: 4096 +toolchain: + - zephyr + - gnuarmemb +supported: + - arduino_gpio + - gpio +vendor: nxp diff --git a/boards/nxp/frdm_mcxe31b/frdm_mcxe31b_defconfig b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b_defconfig new file mode 100644 index 0000000000000..7c9b1108f66aa --- /dev/null +++ b/boards/nxp/frdm_mcxe31b/frdm_mcxe31b_defconfig @@ -0,0 +1,7 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/tests/drivers/gpio/gpio_basic_api/boards/frdm_mcxe31b.overlay b/tests/drivers/gpio/gpio_basic_api/boards/frdm_mcxe31b.overlay new file mode 100644 index 0000000000000..f84a3a74f4304 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/frdm_mcxe31b.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + status = "okay"; + out-gpios = <&arduino_header 0 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL | GPIO_PULL_UP)>; + in-gpios = <&arduino_header 1 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL | GPIO_PULL_UP)>; + }; +}; + +&gpioe_l { + status = "okay"; +}; + +&gpioe_h { + status = "okay"; +}; + +&eirq0_default { + group2 { + pinmux = ; + input-enable; + }; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/testcase.yaml b/tests/drivers/gpio/gpio_basic_api/testcase.yaml index 3dc1580e6f773..3c927e71213ac 100644 --- a/tests/drivers/gpio/gpio_basic_api/testcase.yaml +++ b/tests/drivers/gpio/gpio_basic_api/testcase.yaml @@ -59,6 +59,7 @@ tests: platform_exclude: # below boards are customized - frdm_mcxe247 + - frdm_mcxe31b - mimxrt595_evk/mimxrt595s/cm33 - mimxrt1020_evk - mimxrt1040_evk @@ -76,6 +77,7 @@ tests: - arduino_gpio filter: dt_compat_enabled("test-gpio-basic-api") and dt_compat_enabled("arduino-header-r3") platform_allow: + - frdm_mcxe31b - mimxrt595_evk/mimxrt595s/cm33 - mimxrt1020_evk - mimxrt1040_evk From cdf616a51fc6bbcc91681808acb244cfc52f2dd1 Mon Sep 17 00:00:00 2001 From: Daniel Kampert Date: Thu, 24 Jul 2025 13:52:32 +0000 Subject: [PATCH 346/397] drivers: sensor: Add driver for MAX32664C - Add DTS for MAX32664C - Add driver for MAX32664C - Add example for MAX32664C Heart rate measurement with Bluetooth - Add private attributes and channels for health measurement Closes: #93473 Signed-off-by: Daniel Kampert --- drivers/sensor/adi/CMakeLists.txt | 1 + drivers/sensor/adi/Kconfig | 1 + drivers/sensor/adi/max32664c/CMakeLists.txt | 13 + drivers/sensor/adi/max32664c/Kconfig | 45 + drivers/sensor/adi/max32664c/max32664c.c | 1101 +++++++++++++++++ drivers/sensor/adi/max32664c/max32664c.h | 294 +++++ drivers/sensor/adi/max32664c/max32664c_acc.c | 58 + drivers/sensor/adi/max32664c/max32664c_bl.c | 383 ++++++ drivers/sensor/adi/max32664c/max32664c_init.c | 246 ++++ .../adi/max32664c/max32664c_interrupt.c | 80 ++ .../sensor/adi/max32664c/max32664c_worker.c | 369 ++++++ dts/bindings/sensor/maxim,max32664c.yml | 159 +++ include/zephyr/drivers/sensor/max32664c.h | 186 +++ samples/sensor/max32664c/CMakeLists.txt | 7 + samples/sensor/max32664c/README.rst | 49 + .../boards/nrf54l15dk_nrf54l15_cpuapp.overlay | 79 ++ samples/sensor/max32664c/prj.conf | 7 + samples/sensor/max32664c/sample.yaml | 15 + samples/sensor/max32664c/src/main.c | 77 ++ 19 files changed, 3170 insertions(+) create mode 100644 drivers/sensor/adi/max32664c/CMakeLists.txt create mode 100644 drivers/sensor/adi/max32664c/Kconfig create mode 100644 drivers/sensor/adi/max32664c/max32664c.c create mode 100644 drivers/sensor/adi/max32664c/max32664c.h create mode 100644 drivers/sensor/adi/max32664c/max32664c_acc.c create mode 100644 drivers/sensor/adi/max32664c/max32664c_bl.c create mode 100644 drivers/sensor/adi/max32664c/max32664c_init.c create mode 100644 drivers/sensor/adi/max32664c/max32664c_interrupt.c create mode 100644 drivers/sensor/adi/max32664c/max32664c_worker.c create mode 100644 dts/bindings/sensor/maxim,max32664c.yml create mode 100644 include/zephyr/drivers/sensor/max32664c.h create mode 100644 samples/sensor/max32664c/CMakeLists.txt create mode 100644 samples/sensor/max32664c/README.rst create mode 100644 samples/sensor/max32664c/boards/nrf54l15dk_nrf54l15_cpuapp.overlay create mode 100644 samples/sensor/max32664c/prj.conf create mode 100644 samples/sensor/max32664c/sample.yaml create mode 100644 samples/sensor/max32664c/src/main.c diff --git a/drivers/sensor/adi/CMakeLists.txt b/drivers/sensor/adi/CMakeLists.txt index f0bb5910cf972..e524f38dc5e68 100644 --- a/drivers/sensor/adi/CMakeLists.txt +++ b/drivers/sensor/adi/CMakeLists.txt @@ -10,4 +10,5 @@ add_subdirectory_ifdef(CONFIG_ADXL345 adxl345) add_subdirectory_ifdef(CONFIG_ADXL362 adxl362) add_subdirectory_ifdef(CONFIG_ADXL367 adxl367) add_subdirectory_ifdef(CONFIG_ADXL372 adxl372) +add_subdirectory_ifdef(CONFIG_SENSOR_MAX32664C max32664c) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/adi/Kconfig b/drivers/sensor/adi/Kconfig index dea030c68034d..d0812de2dcee4 100644 --- a/drivers/sensor/adi/Kconfig +++ b/drivers/sensor/adi/Kconfig @@ -10,4 +10,5 @@ source "drivers/sensor/adi/adxl345/Kconfig" source "drivers/sensor/adi/adxl362/Kconfig" source "drivers/sensor/adi/adxl367/Kconfig" source "drivers/sensor/adi/adxl372/Kconfig" +source "drivers/sensor/adi/max32664c/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/adi/max32664c/CMakeLists.txt b/drivers/sensor/adi/max32664c/CMakeLists.txt new file mode 100644 index 0000000000000..b36663c699fa7 --- /dev/null +++ b/drivers/sensor/adi/max32664c/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_sources_ifdef(CONFIG_MAX32664C_USE_FIRMWARE_LOADER max32664c_bl.c) + +zephyr_sources_ifdef(CONFIG_MAX32664C_USE_INTERRUPT max32664c_interrupt.c) + +zephyr_sources_ifdef(CONFIG_SENSOR_MAX32664C max32664c.c + max32664c_worker.c + max32664c_init.c + max32664c_acc.c + ) diff --git a/drivers/sensor/adi/max32664c/Kconfig b/drivers/sensor/adi/max32664c/Kconfig new file mode 100644 index 0000000000000..5b939fa826ba3 --- /dev/null +++ b/drivers/sensor/adi/max32664c/Kconfig @@ -0,0 +1,45 @@ +# Copyright(c) 2025, Daniel Kampert +# SPDX-License-Identifier: Apache-2.0 + +config SENSOR_MAX32664C + bool "MAX32664C Driver" + default y + depends on DT_HAS_MAXIM_MAX32664C_ENABLED + select I2C + help + Enable the driver for the MAX32664C biometric sensor hub. + +if SENSOR_MAX32664C +config MAX32664C_USE_FIRMWARE_LOADER + bool "Use this option if you want to flash the sensor hub over the I2C firmware loader" + +config MAX32664C_USE_EXTERNAL_ACC + bool "Use this option if you want to use an external accelerometer" + +config MAX32664C_USE_EXTENDED_REPORTS + bool "Use this option if you want to use extended reports instead of the default reports" + +config MAX32664C_USE_STATIC_MEMORY + bool "Disable this option if the driver should use dynamic memory" + default y + +config MAX32664C_QUEUE_SIZE + int "Length of the message queue" + default 32 + +config MAX32664C_SAMPLE_BUFFER_SIZE + depends on MAX32664C_USE_STATIC_MEMORY + int "Length of the sample buffer for the I2C reading thread" + default 64 + help + This is the number of samples that will be read from the sensor hub in one go. + The maximum value is 64, but you can set it lower if you want to reduce memory usage. + +config MAX32664C_THREAD_STACK_SIZE + int "MAX32664C sample thread stack size" + default 4096 + +config MAX32664C_USE_INTERRUPT + bool "Use this option if you want to use the MFIO interrupt support" + depends on GPIO +endif diff --git a/drivers/sensor/adi/max32664c/max32664c.c b/drivers/sensor/adi/max32664c/max32664c.c new file mode 100644 index 0000000000000..99d89cc655b88 --- /dev/null +++ b/drivers/sensor/adi/max32664c/max32664c.c @@ -0,0 +1,1101 @@ +/* + * Copyright (c) 2025, Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "max32664c.h" + +#define DT_DRV_COMPAT maxim_max32664c + +#if (DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0) +#warning "max32664c driver enabled without any devices" +#endif + +LOG_MODULE_REGISTER(maxim_max32664c, CONFIG_SENSOR_LOG_LEVEL); + +int max32664c_i2c_transmit(const struct device *dev, uint8_t *tx_buf, uint8_t tx_len, + uint8_t *rx_buf, uint32_t rx_len, uint16_t delay_ms) +{ + const struct max32664c_config *config = dev->config; + + /* Wake up the sensor hub before the transmission starts (min. 300 us) */ + gpio_pin_set_dt(&config->mfio_gpio, false); + k_usleep(500); + + if (i2c_write_dt(&config->i2c, tx_buf, tx_len)) { + LOG_ERR("I2C transmission error!"); + return -EBUSY; + } + + k_msleep(delay_ms); + + if (i2c_read_dt(&config->i2c, rx_buf, rx_len)) { + LOG_ERR("I2C read error!"); + return -EBUSY; + } + + k_msleep(MAX32664C_DEFAULT_CMD_DELAY); + + /* The sensor hub can enter sleep mode again now */ + gpio_pin_set_dt(&config->mfio_gpio, true); + k_usleep(300); + + /* Check the status byte for a valid transaction */ + if (rx_buf[0] != 0) { + return -EINVAL; + } + + return 0; +} + +/** @brief Check the accelerometer and AFE WHOAMI registers. + * This function is called during device initialization. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_check_sensors(const struct device *dev) +{ + uint8_t afe_id; + uint8_t tx[3]; + uint8_t rx[2]; + struct max32664c_data *data = dev->data; + const struct max32664c_config *config = dev->config; + + LOG_DBG("Checking sensors..."); + + /* Read MAX86141 WHOAMI */ + tx[0] = 0x41; + tx[1] = 0x00; + tx[2] = 0xFF; + if (max32664c_i2c_transmit(dev, tx, 3, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + if (config->use_max86141) { + LOG_DBG("\tUsing MAX86141 as AFE"); + afe_id = 0x25; + } else if (config->use_max86161) { + LOG_DBG("\tUsing MAX86161 as AFE"); + afe_id = 0x36; + } else { + LOG_ERR("\tNo AFE defined!"); + return -ENODEV; + } + + data->afe_id = rx[1]; + if (data->afe_id != afe_id) { + LOG_ERR("\tAFE WHOAMI failed: 0x%X", data->afe_id); + return -ENODEV; + } + + LOG_DBG("\tAFE WHOAMI OK: 0x%X", data->afe_id); + + /* Read Accelerometer WHOAMI */ + tx[0] = 0x41; + tx[1] = 0x04; + tx[2] = 0x0F; + if (max32664c_i2c_transmit(dev, tx, 3, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + data->accel_id = rx[1]; + /* The sensor hub firmware supports only two accelerometers and one is set to */ + /* EoL. The remaining one is the ST LIS2DS12. */ + if (data->accel_id != 0x43) { + LOG_ERR("\tAccelerometer WHOAMI failed: 0x%X", data->accel_id); + return -ENODEV; + } + + LOG_DBG("\tAccelerometer WHOAMI OK: 0x%X", data->accel_id); + + return 0; +} + +/** @brief Stop the current algorithm. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_stop_algo(const struct device *dev) +{ + uint8_t rx; + uint8_t tx[3]; + struct max32664c_data *data = dev->data; + + if (data->op_mode == MAX32664C_OP_MODE_IDLE) { + LOG_DBG("No algorithm running, nothing to stop."); + return 0; + } + + LOG_DBG("Stop the current algorithm..."); + + /* Stop the algorithm */ + tx[0] = 0x52; + tx[1] = 0x07; + tx[2] = 0x00; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, 120)) { + return -EINVAL; + } + + switch (data->op_mode) { + case MAX32664C_OP_MODE_RAW: { +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + k_msgq_cleanup(&data->raw_report_queue); +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + break; + } +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + case MAX32664C_OP_MODE_ALGO_AEC_EXT: + case MAX32664C_OP_MODE_ALGO_AGC_EXT: { +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + k_msgq_cleanup(&data->ext_report_queue); +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + break; + } +#else + case MAX32664C_OP_MODE_ALGO_AEC: + case MAX32664C_OP_MODE_ALGO_AGC: { +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + k_msgq_cleanup(&data->report_queue); +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + break; + } +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + case MAX32664C_OP_MODE_SCD: { +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + k_msgq_cleanup(&data->scd_report_queue); +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + break; + } + default: { + LOG_ERR("Unknown algorithm mode: %d", data->op_mode); + return -EINVAL; + } + }; + + data->op_mode = MAX32664C_OP_MODE_IDLE; + + k_thread_suspend(data->thread_id); + + return 0; +} + +/** @brief Put the device into raw measurement mode. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_set_mode_raw(const struct device *dev) +{ + uint8_t rx; + uint8_t tx[4]; + struct max32664c_data *data = dev->data; + + /* Stop the current algorithm mode */ + if (max32664c_stop_algo(dev)) { + LOG_ERR("Failed to stop the algorithm!"); + return -EINVAL; + } + + LOG_INF("Entering RAW mode..."); + + /* Set the output format to sensor data only */ + tx[0] = 0x10; + tx[1] = 0x00; + tx[2] = MAX32664C_OUT_SENSOR_ONLY; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Enable the AFE */ + tx[0] = 0x44; + tx[1] = 0x00; + tx[2] = 0x01; + tx[3] = 0x00; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, 250)) { + return -EINVAL; + } + + /* Enable the accelerometer */ + if (max32664c_acc_enable(dev, true)) { + return -EINVAL; + } + + /* Set AFE sample rate to 100 Hz */ + tx[0] = 0x40; + tx[1] = 0x00; + tx[2] = 0x12; + tx[3] = 0x18; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Set the LED current */ + for (uint8_t i = 0; i < sizeof(data->led_current); i++) { + tx[0] = 0x40; + tx[1] = 0x00; + tx[2] = 0x23 + i; + tx[3] = data->led_current[i]; + LOG_INF("Set LED%d current: %u", i + 1, data->led_current[i]); + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set LED%d current", i + 1); + return -EINVAL; + } + } + +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + if (k_msgq_alloc_init(&data->raw_report_queue, sizeof(struct max32664c_raw_report_t), + CONFIG_MAX32664C_QUEUE_SIZE)) { + LOG_ERR("Failed to allocate RAW report queue!"); + return -ENOMEM; + } +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + + data->op_mode = MAX32664C_OP_MODE_RAW; + + k_thread_resume(data->thread_id); + + return 0; +} + +/** @brief Put the sensor hub into algorithm mode. + * @param dev Pointer to device + * @param device_mode Target device mode + * @param algo_mode Target algorithm mode + * @param extended Set to #true when the extended mode should be used + * @return 0 when successful + */ +static int max32664c_set_mode_algo(const struct device *dev, enum max32664c_device_mode device_mode, + enum max32664c_algo_mode algo_mode, bool extended) +{ + uint8_t rx; + uint8_t tx[5]; + struct max32664c_data *data = dev->data; + + /* Stop the current algorithm mode */ + if (max32664c_stop_algo(dev)) { + LOG_ERR("Failed to stop the algorithm!"); + return -EINVAL; + } + + LOG_DBG("Entering algorithm mode..."); + +#ifndef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + if (extended) { + LOG_ERR("No support for extended reports enabled!"); + return -EINVAL; + } +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + + /* Set the output mode to sensor and algorithm data */ + tx[0] = 0x10; + tx[1] = 0x00; + tx[2] = MAX32664C_OUT_ALGO_AND_SENSOR; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Set the algorithm mode */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x0A; + tx[3] = algo_mode; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + if (device_mode == MAX32664C_OP_MODE_ALGO_AEC) { + LOG_DBG("Entering AEC mode..."); + + /* Enable AEC */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x0B; + tx[3] = 0x01; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Enable Auto PD */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x12; + tx[3] = 0x01; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Enable SCD */ + LOG_DBG("Enabling SCD..."); + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x0C; + tx[3] = 0x01; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + data->op_mode = MAX32664C_OP_MODE_ALGO_AEC; + + if (extended) { + data->op_mode = MAX32664C_OP_MODE_ALGO_AEC_EXT; + } + } else if (device_mode == MAX32664C_OP_MODE_ALGO_AGC) { + LOG_DBG("Entering AGC mode..."); + + /* TODO: Test if this works */ + /* Set the LED current */ + for (uint8_t i = 0; i < sizeof(data->led_current); i++) { + tx[0] = 0x40; + tx[1] = 0x00; + tx[2] = 0x23 + i; + tx[3] = data->led_current[i]; + LOG_INF("Set LED%d current: %u", i + 1, data->led_current[i]); + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, + MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set LED%d current", i + 1); + return -EINVAL; + } + } + + /* Enable AEC */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x0B; + tx[3] = 0x01; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Disable PD auto current calculation */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x12; + tx[3] = 0x00; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Disable SCD */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x0C; + tx[3] = 0x00; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Set AGC target PD current to 10 uA */ + /* TODO: Add setting of PD current via API or DT? */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x11; + tx[3] = 0x00; + tx[4] = 0x64; + if (max32664c_i2c_transmit(dev, tx, 5, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + data->op_mode = MAX32664C_OP_MODE_ALGO_AGC; + + if (extended) { + data->op_mode = MAX32664C_OP_MODE_ALGO_AGC_EXT; + } + } else { + LOG_ERR("Invalid mode!"); + return -EINVAL; + } + + /* Enable HR and SpO2 algorithm */ + tx[2] = 0x01; + if (extended) { + tx[2] = 0x02; + } + + tx[0] = 0x52; + tx[1] = 0x07; + + /* Use the maximum time to cover all modes (see Table 6 and 12 in the User Guide) */ + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, 500)) { + return -EINVAL; + } + +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + if (k_msgq_alloc_init(&data->raw_report_queue, sizeof(struct max32664c_raw_report_t), + CONFIG_MAX32664C_QUEUE_SIZE)) { + LOG_ERR("Failed to allocate RAW report queue!"); + return -ENOMEM; + } + + if (!extended && k_msgq_alloc_init(&data->report_queue, sizeof(struct max32664c_report_t), + CONFIG_MAX32664C_QUEUE_SIZE)) { + LOG_ERR("Failed to allocate report queue!"); + return -ENOMEM; + } + +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + if (extended && + k_msgq_alloc_init(&data->ext_report_queue, sizeof(struct max32664c_ext_report_t), + CONFIG_MAX32664C_QUEUE_SIZE)) { + LOG_ERR("Failed to allocate extended report queue!"); + return -ENOMEM; + } +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + + k_thread_resume(data->thread_id); + + return 0; +} + +/** @brief Enable the skin contact detection only mode. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_set_mode_scd(const struct device *dev) +{ + uint8_t rx; + uint8_t tx[4]; + struct max32664c_data *data = dev->data; + + /* Stop the current algorithm mode */ + if (max32664c_stop_algo(dev)) { + LOG_ERR("Failed to stop the algorithm!"); + return -EINVAL; + } + + LOG_DBG("MAX32664C entering SCD mode..."); + + /* Use LED2 for SCD */ + tx[0] = 0xE5; + tx[1] = 0x02; + if (max32664c_i2c_transmit(dev, tx, 2, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Set the output mode to algorithm data */ + tx[0] = 0x10; + tx[1] = 0x00; + tx[2] = MAX32664C_OUT_ALGORITHM_ONLY; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Enable SCD only algorithm */ + tx[0] = 0x52; + tx[1] = 0x07; + tx[2] = 0x03; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, 500)) { + return -EINVAL; + } + +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + if (k_msgq_alloc_init(&data->scd_report_queue, sizeof(struct max32664c_scd_report_t), + CONFIG_MAX32664C_QUEUE_SIZE)) { + LOG_ERR("Failed to allocate SCD report queue!"); + return -ENOMEM; + } +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + + data->op_mode = MAX32664C_OP_MODE_SCD; + + k_thread_resume(data->thread_id); + + return 0; +} + +static int max32664c_set_mode_wake_on_motion(const struct device *dev) +{ + uint8_t rx; + uint8_t tx[6]; + struct max32664c_data *data = dev->data; + + LOG_DBG("MAX32664C entering wake on motion mode..."); + + /* Stop the current algorithm */ + tx[0] = 0x52; + tx[1] = 0x07; + tx[2] = 0x00; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Set the motion detection threshold (see Table 12 in the SpO2 and Heart Rate Using Guide) + */ + tx[0] = 0x46; + tx[1] = 0x04; + tx[2] = 0x00; + tx[3] = 0x01; + tx[4] = MAX32664C_MOTION_TIME(data->motion_time); + tx[5] = MAX32664C_MOTION_THRESHOLD(data->motion_threshold); + if (max32664c_i2c_transmit(dev, tx, 6, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Set the output mode to sensor data */ + tx[0] = 0x10; + tx[1] = 0x00; + tx[2] = MAX32664C_OUT_SENSOR_ONLY; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Enable the accelerometer */ + if (max32664c_acc_enable(dev, true)) { + return -EINVAL; + } + + data->op_mode = MAX32664C_OP_MODE_WAKE_ON_MOTION; + + return 0; +} + +static int max32664c_exit_mode_wake_on_motion(const struct device *dev) +{ + uint8_t rx; + uint8_t tx[6]; + struct max32664c_data *data = dev->data; + + LOG_DBG("MAX32664C exiting wake on motion mode..."); + + /* Exit wake on motion mode */ + tx[0] = 0x46; + tx[1] = 0x04; + tx[2] = 0x00; + tx[3] = 0x00; + tx[4] = 0xFF; + tx[5] = 0xFF; + if (max32664c_i2c_transmit(dev, tx, 6, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + /* Disable the accelerometer */ + if (max32664c_acc_enable(dev, false)) { + return -EINVAL; + } + + data->op_mode = MAX32664C_OP_MODE_IDLE; + + return 0; +} + +static int max32664c_disable_sensors(const struct device *dev) +{ + uint8_t rx; + uint8_t tx[4]; + struct max32664c_data *data = dev->data; + + if (max32664c_stop_algo(dev)) { + LOG_ERR("Failed to stop the algorithm!"); + return -EINVAL; + } + + /* Leave wake on motion first because we disable the accelerometer */ + if (max32664c_exit_mode_wake_on_motion(dev)) { + LOG_ERR("Failed to exit wake on motion mode!"); + return -EINVAL; + } + + LOG_DBG("Disable the sensors..."); + + /* Disable the AFE */ + tx[0] = 0x44; + tx[1] = 0x00; + tx[2] = 0x00; + tx[3] = 0x00; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, 250)) { + return -EINVAL; + } + + /* Disable the accelerometer */ + if (max32664c_acc_enable(dev, false)) { + return -EINVAL; + } + + data->op_mode = MAX32664C_OP_MODE_IDLE; + + return 0; +} + +static int max32664c_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct max32664c_data *data = dev->data; + + switch (data->op_mode) { + case MAX32664C_OP_MODE_STOP_ALGO: + case MAX32664C_OP_MODE_IDLE: + LOG_DBG("Device is idle, no data to fetch!"); + return -EAGAIN; + case MAX32664C_OP_MODE_SCD: + k_msgq_get(&data->scd_report_queue, &data->scd, K_NO_WAIT); + return 0; +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + case MAX32664C_OP_MODE_ALGO_AEC_EXT: + case MAX32664C_OP_MODE_ALGO_AGC_EXT: + k_msgq_get(&data->ext_report_queue, &data->ext, K_NO_WAIT); + return 0; +#else + case MAX32664C_OP_MODE_ALGO_AEC: + case MAX32664C_OP_MODE_ALGO_AGC: + k_msgq_get(&data->report_queue, &data->report, K_NO_WAIT); + return 0; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + /* Raw data are reported with normal and extended algorithms so we need to fetch them too */ + case MAX32664C_OP_MODE_RAW: + k_msgq_get(&data->raw_report_queue, &data->raw, K_NO_WAIT); + return 0; + default: + return -ENOTSUP; + } +} + +static int max32664c_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct max32664c_data *data = dev->data; + + switch ((int)chan) { + case SENSOR_CHAN_ACCEL_X: { + val->val1 = data->raw.acc.x; + break; + } + case SENSOR_CHAN_ACCEL_Y: { + val->val1 = data->raw.acc.y; + break; + } + case SENSOR_CHAN_ACCEL_Z: { + val->val1 = data->raw.acc.z; + break; + } + case SENSOR_CHAN_GREEN: { + val->val1 = data->raw.PPG1; + break; + } + case SENSOR_CHAN_IR: { + val->val1 = data->raw.PPG2; + break; + } + case SENSOR_CHAN_RED: { + val->val1 = data->raw.PPG3; + break; + } + case SENSOR_CHAN_MAX32664C_HEARTRATE: { +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + val->val1 = data->ext.hr; + val->val2 = data->ext.hr_confidence; +#else + val->val1 = data->report.hr; + val->val2 = data->report.hr_confidence; +#endif + break; + } + case SENSOR_CHAN_MAX32664C_RESPIRATION_RATE: { +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + val->val1 = data->ext.rr; + val->val2 = data->ext.rr_confidence; +#else + val->val1 = data->report.rr; + val->val2 = data->report.rr_confidence; +#endif + break; + } + case SENSOR_CHAN_MAX32664C_BLOOD_OXYGEN_SATURATION: { +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + val->val1 = data->ext.spo2_meas.value; + val->val2 = data->ext.spo2_meas.confidence; +#else + val->val1 = data->report.spo2_meas.value; + val->val2 = data->report.spo2_meas.confidence; +#endif + break; + } + case SENSOR_CHAN_MAX32664C_SKIN_CONTACT: { + val->val1 = data->report.scd_state; + break; + } + default: { + LOG_ERR("Channel %u not supported!", chan); + return -ENOTSUP; + } + } + + return 0; +} + +static int max32664c_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + int err; + uint8_t tx[5]; + uint8_t rx; + struct max32664c_data *data = dev->data; + + err = 0; + + switch ((int)attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: { + break; + } + case SENSOR_ATTR_MAX32664C_HEIGHT: { + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x06; + tx[3] = (val->val1 & 0xFF00) >> 8; + tx[4] = val->val1 & 0x00FF; + if (max32664c_i2c_transmit(dev, tx, 5, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set height!"); + return -EINVAL; + } + + break; + } + case SENSOR_ATTR_MAX32664C_WEIGHT: { + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x07; + tx[3] = (val->val1 & 0xFF00) >> 8; + tx[4] = val->val1 & 0x00FF; + if (max32664c_i2c_transmit(dev, tx, 5, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set weight!"); + return -EINVAL; + } + + break; + } + case SENSOR_ATTR_MAX32664C_AGE: { + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x08; + tx[3] = val->val1 & 0x00FF; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set age!"); + return -EINVAL; + } + + break; + } + case SENSOR_ATTR_MAX32664C_GENDER: { + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x08; + tx[3] = val->val1 & 0x00FF; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set gender!"); + return -EINVAL; + } + + break; + } + case SENSOR_ATTR_SLOPE_DUR: { + data->motion_time = val->val1; + break; + } + case SENSOR_ATTR_SLOPE_TH: { + data->motion_threshold = val->val1; + break; + } + case SENSOR_ATTR_CONFIGURATION: { + switch ((int)chan) { + case SENSOR_CHAN_GREEN: { + data->led_current[0] = val->val1 & 0xFF; + break; + } + case SENSOR_CHAN_IR: { + data->led_current[1] = val->val1 & 0xFF; + break; + } + case SENSOR_CHAN_RED: { + data->led_current[2] = val->val1 & 0xFF; + break; + } + default: { + LOG_ERR("Channel %u not supported for setting attribute!", (int)chan); + return -ENOTSUP; + } + } + break; + } + case SENSOR_ATTR_MAX32664C_OP_MODE: { + switch (val->val1) { + case MAX32664C_OP_MODE_ALGO_AEC: { +#ifndef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + err = max32664c_set_mode_algo(dev, MAX32664C_OP_MODE_ALGO_AEC, val->val2, + false); +#else + return -EINVAL; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + break; + } + case MAX32664C_OP_MODE_ALGO_AEC_EXT: { +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + err = max32664c_set_mode_algo(dev, MAX32664C_OP_MODE_ALGO_AEC, val->val2, + true); +#else + return -EINVAL; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + break; + } + case MAX32664C_OP_MODE_ALGO_AGC: { +#ifndef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + err = max32664c_set_mode_algo(dev, MAX32664C_OP_MODE_ALGO_AGC, val->val2, + false); +#else + return -EINVAL; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + break; + } + case MAX32664C_OP_MODE_ALGO_AGC_EXT: { +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + err = max32664c_set_mode_algo(dev, MAX32664C_OP_MODE_ALGO_AGC, val->val2, + true); +#else + return -EINVAL; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + break; + } + case MAX32664C_OP_MODE_RAW: { + err = max32664c_set_mode_raw(dev); + break; + } + case MAX32664C_OP_MODE_SCD: { + err = max32664c_set_mode_scd(dev); + break; + } + case MAX32664C_OP_MODE_WAKE_ON_MOTION: { + err = max32664c_set_mode_wake_on_motion(dev); + break; + } + case MAX32664C_OP_MODE_EXIT_WAKE_ON_MOTION: { + err = max32664c_exit_mode_wake_on_motion(dev); + break; + } + case MAX32664C_OP_MODE_STOP_ALGO: { + err = max32664c_stop_algo(dev); + break; + } + case MAX32664C_OP_MODE_IDLE: { + err = max32664c_disable_sensors(dev); + break; + } + default: { + LOG_ERR("Unsupported sensor operation mode"); + return -ENOTSUP; + } + } + + break; + } + default: { + LOG_ERR("Unsupported sensor attribute!"); + return -ENOTSUP; + } + } + + return err; +} + +static int max32664c_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + struct max32664c_data *data = dev->data; + + switch ((int)attr) { + case SENSOR_ATTR_MAX32664C_OP_MODE: { + val->val1 = data->op_mode; + val->val2 = 0; + break; + } + case SENSOR_ATTR_CONFIGURATION: { + switch ((int)chan) { + case SENSOR_CHAN_GREEN: { + val->val1 = data->led_current[0]; + break; + } + case SENSOR_CHAN_IR: { + val->val1 = data->led_current[1]; + break; + } + case SENSOR_CHAN_RED: { + val->val1 = data->led_current[2]; + break; + } + default: { + LOG_ERR("Channel %u not supported for getting attribute!", (int)chan); + return -ENOTSUP; + } + } + break; + } + default: { + LOG_ERR("Unsupported sensor attribute!"); + return -ENOTSUP; + } + } + + return 0; +} + +static DEVICE_API(sensor, max32664c_driver_api) = { + .attr_set = max32664c_attr_set, + .attr_get = max32664c_attr_get, + .sample_fetch = max32664c_sample_fetch, + .channel_get = max32664c_channel_get, +}; + +static int max32664c_init(const struct device *dev) +{ + uint8_t tx[2]; + uint8_t rx[4]; + const struct max32664c_config *config = dev->config; + struct max32664c_data *data = dev->data; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C not ready"); + return -ENODEV; + } + + gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT); + gpio_pin_configure_dt(&config->mfio_gpio, GPIO_OUTPUT); + + /* Put the hub into application mode */ + LOG_DBG("Set app mode"); + gpio_pin_set_dt(&config->reset_gpio, false); + k_msleep(20); + + gpio_pin_set_dt(&config->mfio_gpio, true); + k_msleep(20); + + /* Wait for 50 ms (switch into app mode) + 1500 ms (initialization) */ + /* (see page 17 of the User Guide) */ + gpio_pin_set_dt(&config->reset_gpio, true); + k_msleep(1600); + + /* Read the device mode */ + tx[0] = 0x02; + tx[1] = 0x00; + if (max32664c_i2c_transmit(dev, tx, 2, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + data->op_mode = rx[1]; + LOG_DBG("Mode: %x ", data->op_mode); + if (data->op_mode != 0) { + return -EINVAL; + } + + /* Read the firmware version */ + tx[0] = 0xFF; + tx[1] = 0x03; + if (max32664c_i2c_transmit(dev, tx, 2, rx, 4, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + memcpy(data->hub_ver, &rx[1], 3); + + LOG_DBG("Version: %d.%d.%d", data->hub_ver[0], data->hub_ver[1], data->hub_ver[2]); + + if (max32664c_check_sensors(dev)) { + return -EINVAL; + } + + if (max32664c_init_hub(dev)) { + return -EINVAL; + } + +#ifdef CONFIG_MAX32664C_USE_STATIC_MEMORY + k_msgq_init(&data->raw_report_queue, data->raw_report_queue_buffer, + sizeof(struct max32664c_raw_report_t), + sizeof(data->raw_report_queue_buffer) / sizeof(struct max32664c_raw_report_t)); + + k_msgq_init(&data->scd_report_queue, data->scd_report_queue_buffer, + sizeof(struct max32664c_scd_report_t), + sizeof(data->scd_report_queue_buffer) / sizeof(struct max32664c_scd_report_t)); + +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + k_msgq_init(&data->ext_report_queue, data->ext_report_queue_buffer, + sizeof(struct max32664c_ext_report_t), + sizeof(data->ext_report_queue_buffer) / sizeof(struct max32664c_ext_report_t)); +#else + k_msgq_init(&data->report_queue, data->report_queue_buffer, + sizeof(struct max32664c_report_t), + sizeof(data->report_queue_buffer) / sizeof(struct max32664c_report_t)); +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int max32664c_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_RESUME: { + break; + } + case PM_DEVICE_ACTION_SUSPEND: { + const struct max32664c_config *config = dev->config; + + /* Pulling MFIO high will cause the hub to enter sleep mode */ + gpio_pin_set_dt(&config->mfio_gpio, true); + k_msleep(20); + break; + } + case PM_DEVICE_ACTION_TURN_OFF: { + uint8_t rx; + uint8_t tx[3]; + + /* Send a shut down command */ + /* NOTE: Toggling RSTN is needed to wake the device */ + tx[0] = 0x01; + tx[1] = 0x00; + tx[2] = 0x01; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + break; + } + case PM_DEVICE_ACTION_TURN_ON: { + /* Toggling RSTN is needed to turn the device on */ + max32664c_init(dev); + break; + } + default: { + return -ENOTSUP; + } + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ + +#define MAX32664C_INIT(inst) \ + static struct max32664c_data max32664c_data_##inst; \ + \ + static const struct max32664c_config max32664c_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \ + .mfio_gpio = GPIO_DT_SPEC_INST_GET(inst, mfio_gpios), \ + .spo2_calib = DT_INST_PROP(inst, spo2_calib), \ + .hr_config = DT_INST_PROP(inst, hr_config), \ + .spo2_config = DT_INST_PROP(inst, spo2_config), \ + .use_max86141 = DT_INST_PROP(inst, use_max86141), \ + .use_max86161 = DT_INST_PROP(inst, use_max86161), \ + .motion_time = DT_INST_PROP(inst, motion_time), \ + .motion_threshold = DT_INST_PROP(inst, motion_threshold), \ + .min_integration_time_idx = DT_INST_ENUM_IDX(inst, min_integration_time), \ + .min_sampling_rate_idx = DT_INST_ENUM_IDX(inst, min_sampling_rate), \ + .max_integration_time_idx = DT_INST_ENUM_IDX(inst, max_integration_time), \ + .max_sampling_rate_idx = DT_INST_ENUM_IDX(inst, max_sampling_rate), \ + .report_period = DT_INST_PROP(inst, report_period), \ + .led_current = DT_INST_PROP(inst, led_current), \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, max32664c_pm_action); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, max32664c_init, PM_DEVICE_DT_INST_GET(inst), \ + &max32664c_data_##inst, &max32664c_config_##inst, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &max32664c_driver_api) + +DT_INST_FOREACH_STATUS_OKAY(MAX32664C_INIT) diff --git a/drivers/sensor/adi/max32664c/max32664c.h b/drivers/sensor/adi/max32664c/max32664c.h new file mode 100644 index 0000000000000..facca74416dec --- /dev/null +++ b/drivers/sensor/adi/max32664c/max32664c.h @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2025, Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include + +#define MAX32664C_BIT_STATUS_NO_ERR 1 +#define MAX32664C_BIT_STATUS_DATA_RDY 3 +#define MAX32664C_BIT_STATUS_OUT_OVFL 4 +#define MAX32664C_BIT_STATUS_IN_OVFL 5 +#define MAX32664C_BIT_STATUS_BUSY 6 + +#define MAX32664C_DEFAULT_CMD_DELAY 10 + +/** @brief Output formats of the sensor hub. + */ +enum max32664c_output_format { + MAX32664C_OUT_PAUSE, + MAX32664C_OUT_SENSOR_ONLY, + MAX32664C_OUT_ALGORITHM_ONLY, + MAX32664C_OUT_ALGO_AND_SENSOR, +}; + +/** @brief Skin contact detection states. + * @note The SCD states are only available when the SCD only mode is enabled. + */ +enum max32664c_scd_states { + MAX32664C_SCD_STATE_UNKNOWN, + MAX32664C_SCD_STATE_OFF_SKIN, + MAX32664C_SCD_STATE_ON_OBJECT, + MAX32664C_SCD_STATE_ON_SKIN, +}; + +/** @brief LED current structure. + */ +struct max32664c_led_current_t { + uint8_t adj_flag; + uint16_t adj_val; +} __packed; + +/** @brief SpO2 measurement result structure. + */ +struct max32664c_spo2_meas_t { + uint8_t confidence; + uint16_t value; + uint8_t complete; + uint8_t low_signal_quality; + uint8_t motion; + uint8_t low_pi; + uint8_t unreliable_r; + uint8_t state; +} __packed; + +/** @brief Extended SpO2 measurement result structure. + */ +struct max32664c_ext_spo2_meas_t { + uint8_t confidence; + uint16_t value; + uint8_t valid_percent; + uint8_t low_signal_flag; + uint8_t motion_flag; + uint8_t low_pi_flag; + uint8_t unreliable_r_flag; + uint8_t state; +} __packed; + +/** @brief Raw data structure, reported by the sensor hub. + */ +struct max32664c_raw_report_t { + uint32_t PPG1: 24; + uint32_t PPG2: 24; + uint32_t PPG3: 24; + uint32_t PPG4: 24; + uint32_t PPG5: 24; + uint32_t PPG6: 24; + struct max32664c_acc_data_t acc; +} __packed; + +/** @brief SCD only data structure, reported by the sensor hub. + */ +struct max32664c_scd_report_t { + uint8_t scd_classifier; +} __packed; + +/** @brief Algorithm data structure, reported by the sensor hub. + */ +struct max32664c_report_t { + uint8_t op_mode; + uint16_t hr; + uint8_t hr_confidence; + uint16_t rr; + uint8_t rr_confidence; + uint8_t activity_class; + uint16_t r; + struct max32664c_spo2_meas_t spo2_meas; + uint8_t scd_state; +} __packed; + +/** @brief Extended algorithm data structure, reported by the sensor hub. + */ +struct max32664c_ext_report_t { + uint8_t op_mode; + uint16_t hr; + uint8_t hr_confidence; + uint16_t rr; + uint8_t rr_confidence; + uint8_t activity_class; + + uint32_t total_walk_steps; + uint32_t total_run_steps; + uint32_t total_energy_kcal; + uint32_t total_amr_kcal; + + struct max32664c_led_current_t led_current_adj1; + struct max32664c_led_current_t led_current_adj2; + struct max32664c_led_current_t led_current_adj3; + + uint8_t integration_time_adj_flag; + uint8_t requested_integration_time; + + uint8_t sampling_rate_adj_flag; + uint8_t requested_sampling_rate; + uint8_t requested_sampling_average; + + uint8_t hrm_afe_ctrl_state; + uint8_t is_high_motion_for_hrm; + + uint8_t scd_state; + + uint16_t r_value; + struct max32664c_ext_spo2_meas_t spo2_meas; + + uint8_t ibi_offset; + uint8_t unreliable_orientation_flag; + + uint8_t reserved[2]; +} __packed; + +/** @brief Device configuration structure. + */ +struct max32664c_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec reset_gpio; + +#ifdef CONFIG_MAX32664C_USE_INTERRUPT + const struct device *dev; + struct gpio_callback gpio_cb; + struct k_work interrupt_work; +#endif /* CONFIG_MAX32664C_USE_INTERRUPT */ + + struct gpio_dt_spec mfio_gpio; + + int32_t spo2_calib[3]; + uint16_t motion_time; + uint16_t motion_threshold; + + uint8_t hr_config[2]; + uint8_t spo2_config[2]; + uint8_t led_current[3]; /**< Initial LED current in mA */ + uint8_t min_integration_time_idx; + uint8_t min_sampling_rate_idx; + uint8_t max_integration_time_idx; + uint8_t max_sampling_rate_idx; + uint8_t report_period; /*< Samples report period */ + + bool use_max86141; + bool use_max86161; +}; + +/** @brief Device runtime data structure. + */ +struct max32664c_data { + struct max32664c_raw_report_t raw; + struct max32664c_scd_report_t scd; + struct max32664c_report_t report; + struct max32664c_ext_report_t ext; + + enum max32664c_device_mode op_mode; /**< Current device mode */ + + uint8_t motion_time; /**< Motion time in milliseconds */ + uint8_t motion_threshold; /**< Motion threshold in milli-g */ + uint8_t led_current[3]; /**< LED current in mA */ + uint8_t min_integration_time_idx; + uint8_t min_sampling_rate_idx; + uint8_t max_integration_time_idx; + uint8_t max_sampling_rate_idx; + uint8_t report_period; /*< Samples report period */ + uint8_t afe_id; + uint8_t accel_id; + uint8_t hub_ver[3]; + + /* Internal */ + struct k_thread thread; + k_tid_t thread_id; + bool is_thread_running; + +#ifdef CONFIG_MAX32664C_USE_STATIC_MEMORY + /** @brief This buffer is used to read all available messages from the sensor hub plus the + * status byte. The buffer size is defined by the CONFIG_MAX32664C_SAMPLE_BUFFER_SIZE + * Kconfig and the largest possible message. The buffer must contain enough space to store + * all available messages at every time because it is not possible to read a single message + * from the sensor hub. + */ +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + uint8_t max32664_i2c_buffer[(CONFIG_MAX32664C_SAMPLE_BUFFER_SIZE * + (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_ext_report_t))) + + 1]; +#else + uint8_t max32664_i2c_buffer[(CONFIG_MAX32664C_SAMPLE_BUFFER_SIZE * + (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_report_t))) + + 1]; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ +#else + uint8_t *max32664_i2c_buffer; +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_MAX32664C_THREAD_STACK_SIZE); + + struct k_msgq raw_report_queue; + struct k_msgq scd_report_queue; + +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + struct k_msgq ext_report_queue; +#else + struct k_msgq report_queue; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + +#ifdef CONFIG_MAX32664C_USE_STATIC_MEMORY + uint8_t raw_report_queue_buffer[CONFIG_MAX32664C_QUEUE_SIZE * + sizeof(struct max32664c_raw_report_t)]; + uint8_t scd_report_queue_buffer[CONFIG_MAX32664C_QUEUE_SIZE * + sizeof(struct max32664c_scd_report_t)]; + +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + uint8_t ext_report_queue_buffer[CONFIG_MAX32664C_QUEUE_SIZE * + (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_ext_report_t))]; +#else + uint8_t report_queue_buffer[CONFIG_MAX32664C_QUEUE_SIZE * + (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_report_t))]; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY*/ +}; + +/** @brief Enable / Disable the accelerometer. + * NOTE: This code is untested and may not work as expected. + * @param dev Pointer to device + * @param enable Enable / Disable + * @return 0 when successful + */ +int max32664c_acc_enable(const struct device *dev, bool enable); + +/** @brief Background worker for reading the sensor hub. + * @param dev Pointer to device + */ +void max32664c_worker(const struct device *dev); + +/** @brief Read / write data from / to the sensor hub. + * @param dev Pointer to device + * @param tx_buf Pointer to transmit buffer + * @param tx_len Length of transmit buffer + * @param rx_buf Pointer to receive buffer + * NOTE: The buffer must be large enough to store the response and the status byte! + * @param rx_len Length of the receive buffer + * @param delay Command delay (milliseconds) + * @return 0 when successful + */ +int max32664c_i2c_transmit(const struct device *dev, uint8_t *tx_buf, uint8_t tx_len, + uint8_t *rx_buf, uint32_t rx_len, uint16_t delay); + +/** @brief Run a basic initialization on the sensor hub. + * @param dev Pointer to device + * @return 0 when successful + */ +int max32664c_init_hub(const struct device *dev); + +#if CONFIG_MAX32664C_USE_INTERRUPT +/** @brief Initialize the interrupt support for the sensor hub. + * @param dev Pointer to device + * @return 0 when successful + */ +int max32664c_init_interrupt(const struct device *dev); +#endif /* CONFIG_MAX32664C_USE_INTERRUPT */ diff --git a/drivers/sensor/adi/max32664c/max32664c_acc.c b/drivers/sensor/adi/max32664c/max32664c_acc.c new file mode 100644 index 0000000000000..1b8dfc1b07d1c --- /dev/null +++ b/drivers/sensor/adi/max32664c/max32664c_acc.c @@ -0,0 +1,58 @@ +/* + * External accelerometer driver for the MAX32664C biometric sensor hub. + * + * Copyright (c) 2025, Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "max32664c.h" + +LOG_MODULE_REGISTER(maxim_max32664c_acc, CONFIG_SENSOR_LOG_LEVEL); + +int max32664c_acc_enable(const struct device *dev, bool enable) +{ + uint8_t tx[4]; + uint8_t rx; + + tx[0] = 0x44; + tx[1] = 0x04; + tx[2] = enable; + +#if CONFIG_MAX32664C_USE_EXTERNAL_ACC + tx[3] = 1; +#else + tx[3] = 0; +#endif /* CONFIG_MAX32664C_USE_EXTERNAL_ACC */ + + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, 20)) { + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_MAX32664C_USE_EXTERNAL_ACC +int max32664c_acc_fill_fifo(const struct device *dev, struct max32664c_acc_data_t *data, + uint8_t length) +{ + uint8_t tx[2 + 16 * sizeof(struct max32664c_acc_data_t)]; + uint8_t rx; + + if (length > 16) { + LOG_ERR("Length exceeds maximum of 16 samples!"); + return -EINVAL; + } + + tx[0] = 0x14; + tx[1] = 0x00; + memcpy(&tx[2], data, length * sizeof(struct max32664c_acc_data_t)); + + if (max32664c_i2c_transmit(dev, tx, 2 + (length * sizeof(struct max32664c_acc_data_t)), &rx, + 1, 20)) { + return -EINVAL; + } + + return 0; +} +#endif /* CONFIG_MAX32664C_USE_EXTERNAL_ACC */ diff --git a/drivers/sensor/adi/max32664c/max32664c_bl.c b/drivers/sensor/adi/max32664c/max32664c_bl.c new file mode 100644 index 0000000000000..147c9aefe3bdf --- /dev/null +++ b/drivers/sensor/adi/max32664c/max32664c_bl.c @@ -0,0 +1,383 @@ +/* + * I2C firmware loader for the MAX32664C biometric sensor hub. + * + * Copyright (c) 2025, Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "max32664c.h" + +#define MAX32664C_FW_PAGE_SIZE 8192 +#define MAX32664C_FW_UPDATE_CRC_SIZE 16 +#define MAX32664C_FW_UPDATE_WRITE_SIZE (MAX32664C_FW_PAGE_SIZE + MAX32664C_FW_UPDATE_CRC_SIZE) +#define MAX32664C_DEFAULT_CMD_DELAY_MS 10 +#define MAX32664C_PAGE_WRITE_DELAY_MS 680 + +static uint8_t max32664c_fw_init_vector[11]; +static uint8_t max32664c_fw_auth_vector[16]; + +LOG_MODULE_REGISTER(max32664_loader, CONFIG_SENSOR_LOG_LEVEL); + +/** @brief Read / write bootloader data from / to the sensor hub. + * @param dev Pointer to device + * @param tx_buf Pointer to transmit buffer + * @param tx_len Length of transmit buffer + * @param rx_buf Pointer to receive buffer + * NOTE: The buffer must be large enough to store the response and the status byte! + * @param rx_len Length of the receive buffer + * @return 0 when successful + */ +static int max32664c_bl_i2c_transmit(const struct device *dev, uint8_t *tx_buf, uint8_t tx_len, + uint8_t *rx_buf, uint8_t rx_len) +{ + int err; + const struct max32664c_config *config = dev->config; + + err = i2c_write_dt(&config->i2c, tx_buf, tx_len); + if (err) { + LOG_ERR("I2C transmission error %d!", err); + return err; + } + k_msleep(MAX32664C_DEFAULT_CMD_DELAY_MS); + err = i2c_read_dt(&config->i2c, rx_buf, rx_len); + if (err) { + LOG_ERR("I2C transmission error %d!", err); + return err; + } + k_msleep(MAX32664C_DEFAULT_CMD_DELAY_MS); + + /* Check the status byte for a valid transaction */ + LOG_DBG("Status: %u", rx_buf[0]); + if (rx_buf[0] != 0) { + return -EINVAL; + } + + return 0; +} + +/** @brief Read application data from the sensor hub. + * @param dev Pointer to device + * @param family Family byte + * @param index Index byte + * @param rx_buf Pointer to receive buffer + * NOTE: The buffer must be large enough to store the response and the status byte! + * @param rx_len Length of receive buffer + * @return 0 when successful + */ +static int max32664c_app_i2c_read(const struct device *dev, uint8_t family, uint8_t index, + uint8_t *rx_buf, uint8_t rx_len) +{ + uint8_t tx_buf[] = {family, index}; + const struct max32664c_config *config = dev->config; + + /* Wake the sensor hub before starting an I2C read (see page 17 of the user Guide) */ + gpio_pin_set_dt(&config->mfio_gpio, false); + k_usleep(300); + + i2c_write_dt(&config->i2c, tx_buf, sizeof(tx_buf)); + k_msleep(MAX32664C_DEFAULT_CMD_DELAY_MS); + i2c_read_dt(&config->i2c, rx_buf, rx_len); + k_msleep(MAX32664C_DEFAULT_CMD_DELAY_MS); + + gpio_pin_set_dt(&config->mfio_gpio, true); + + /* Check the status byte for a valid transaction */ + if (rx_buf[0] != 0) { + return -EINVAL; + } + + return 0; +} + +/** @brief Write a page of data into the sensor hub. + * @param dev Pointer to device + * @param data Pointer to firmware data + * @param offset Start address in the firmware data + * @return 0 when successful + */ +static int max32664c_bl_write_page(const struct device *dev, const uint8_t *data, uint32_t offset) +{ + int err; + uint8_t rx_buf; + uint8_t *tx_buf; + const struct max32664c_config *config = dev->config; + + /* Alloc memory for one page plus two command bytes */ + tx_buf = (uint8_t *)k_malloc(MAX32664C_FW_UPDATE_WRITE_SIZE + 2); + if (tx_buf == NULL) { + return -ENOMEM; + } + + /* Copy the data for one page into the buffer but leave space for the two command bytes */ + memcpy(&tx_buf[2], &data[offset], MAX32664C_FW_UPDATE_WRITE_SIZE); + + /* Set the two command bytes */ + tx_buf[0] = 0x80; + tx_buf[1] = 0x04; + + if (i2c_write_dt(&config->i2c, tx_buf, MAX32664C_FW_UPDATE_WRITE_SIZE + 2)) { + err = -EINVAL; + goto max32664c_bl_write_page_exit; + }; + k_msleep(MAX32664C_PAGE_WRITE_DELAY_MS); + err = i2c_read_dt(&config->i2c, &rx_buf, 1); + if (err) { + LOG_ERR("I2C read error %d!", err); + err = -EINVAL; + goto max32664c_bl_write_page_exit; + }; + k_msleep(MAX32664C_DEFAULT_CMD_DELAY_MS); + + err = rx_buf; + + LOG_DBG("Write page status: %u", err); + +max32664c_bl_write_page_exit: + k_free(tx_buf); + return err; +} + +/** @brief Erase the application from the sensor hub. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_bl_erase_app(const struct device *dev) +{ + uint8_t tx_buf[2] = {0x80, 0x03}; + uint8_t rx_buf; + const struct max32664c_config *config = dev->config; + + if (i2c_write_dt(&config->i2c, tx_buf, sizeof(tx_buf))) { + return -EINVAL; + }; + + k_msleep(1500); + + if (i2c_read_dt(&config->i2c, &rx_buf, sizeof(rx_buf))) { + return -EINVAL; + }; + + k_msleep(MAX32664C_DEFAULT_CMD_DELAY_MS); + + /* Check the status byte for a valid transaction */ + if (rx_buf != 0) { + return -EINVAL; + } + + return 0; +} + +/** @brief Load the firmware into the hub. + * NOTE: See User Guide, Table 9 for the required steps. + * @param dev Pointer to device + * @param firmware Pointer to firmware data + * @param size Firmware size + * @return 0 when successful + */ +static int max32664c_bl_load_fw(const struct device *dev, const uint8_t *firmware, uint32_t size) +{ + uint8_t rx_buf; + uint8_t tx_buf[18] = {0}; + uint32_t page_offset; + + /* Get the number of pages from the firmware file (see User Guide page 53) */ + uint8_t num_pages = firmware[0x44]; + + LOG_INF("Loading firmware..."); + LOG_INF("\tSize: %u", size); + LOG_INF("\tPages: %u", num_pages); + + /* Set the number of pages */ + tx_buf[0] = 0x80; + tx_buf[1] = 0x02; + tx_buf[2] = 0x00; + tx_buf[3] = num_pages; + if (max32664c_bl_i2c_transmit(dev, tx_buf, 4, &rx_buf, 1)) { + return -EINVAL; + } + + if (rx_buf != 0) { + LOG_ERR("Failed to set number of pages: %d", rx_buf); + return -EINVAL; + } + + /* Get the initialization and authentication vectors from the firmware */ + /* (see User Guide page 53) */ + memcpy(max32664c_fw_init_vector, &firmware[0x28], sizeof(max32664c_fw_init_vector)); + memcpy(max32664c_fw_auth_vector, &firmware[0x34], sizeof(max32664c_fw_auth_vector)); + + /* Write the initialization vector */ + LOG_INF("\tWriting init vector..."); + tx_buf[0] = 0x80; + tx_buf[1] = 0x00; + memcpy(&tx_buf[2], max32664c_fw_init_vector, sizeof(max32664c_fw_init_vector)); + if (max32664c_bl_i2c_transmit(dev, tx_buf, 13, &rx_buf, 1)) { + return -EINVAL; + } + if (rx_buf != 0) { + LOG_ERR("Failed to set init vector: %d", rx_buf); + return -EINVAL; + } + + /* Write the authentication vector */ + LOG_INF("\tWriting auth vector..."); + tx_buf[0] = 0x80; + tx_buf[1] = 0x01; + memcpy(&tx_buf[2], max32664c_fw_auth_vector, sizeof(max32664c_fw_auth_vector)); + if (max32664c_bl_i2c_transmit(dev, tx_buf, 18, &rx_buf, 1)) { + return -EINVAL; + } + if (rx_buf != 0) { + LOG_ERR("Failed to set auth vector: %d", rx_buf); + return -EINVAL; + } + + /* Remove the old app from the hub */ + LOG_INF("\tRemove old app..."); + if (max32664c_bl_erase_app(dev)) { + return -EINVAL; + } + + /* Write the new firmware */ + LOG_INF("\tWriting new firmware..."); + page_offset = 0x4C; + for (uint8_t i = 0; i < num_pages; i++) { + uint8_t status; + + LOG_INF("\t\tPage: %d of %d", (i + 1), num_pages); + LOG_INF("\t\tOffset: 0x%x", page_offset); + status = max32664c_bl_write_page(dev, firmware, page_offset); + LOG_INF("\t\tStatus: %u", status); + if (status != 0) { + return -EINVAL; + } + + page_offset += MAX32664C_FW_UPDATE_WRITE_SIZE; + } + + LOG_INF("\tSuccessful!"); + + return max32664c_bl_leave(dev); +} + +int max32664c_bl_enter(const struct device *dev, const uint8_t *firmware, uint32_t size) +{ + uint8_t rx_buf[4] = {0}; + uint8_t tx_buf[3]; + const struct max32664c_config *config = dev->config; + + gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT); + gpio_pin_configure_dt(&config->mfio_gpio, GPIO_OUTPUT); + + /* Put the processor into bootloader mode */ + LOG_INF("Entering bootloader mode"); + gpio_pin_set_dt(&config->reset_gpio, false); + k_msleep(20); + + gpio_pin_set_dt(&config->mfio_gpio, false); + k_msleep(20); + + gpio_pin_set_dt(&config->reset_gpio, true); + k_msleep(200); + + /* Set bootloader mode */ + tx_buf[0] = 0x01; + tx_buf[1] = 0x00; + tx_buf[2] = 0x08; + if (max32664c_bl_i2c_transmit(dev, tx_buf, 3, rx_buf, 1)) { + return -EINVAL; + } + + /* Read the device mode */ + tx_buf[0] = 0x02; + tx_buf[1] = 0x00; + if (max32664c_bl_i2c_transmit(dev, tx_buf, 2, rx_buf, 2)) { + return -EINVAL; + } + + LOG_DBG("Mode: %x ", rx_buf[1]); + if (rx_buf[1] != 8) { + LOG_ERR("Device not in bootloader mode!"); + return -EINVAL; + } + + /* Read the bootloader information */ + tx_buf[0] = 0x81; + tx_buf[1] = 0x00; + if (max32664c_bl_i2c_transmit(dev, tx_buf, 2, rx_buf, 4)) { + return -EINVAL; + } + + LOG_INF("Version: %d.%d.%d", rx_buf[1], rx_buf[2], rx_buf[3]); + + /* Read the bootloader page size */ + tx_buf[0] = 0x81; + tx_buf[1] = 0x01; + if (max32664c_bl_i2c_transmit(dev, tx_buf, 2, rx_buf, 3)) { + return -EINVAL; + } + + LOG_INF("Page size: %u", (uint16_t)(rx_buf[1] << 8) | rx_buf[2]); + + return max32664c_bl_load_fw(dev, firmware, size); +} + +int max32664c_bl_leave(const struct device *dev) +{ + uint8_t hub_ver[3]; + uint8_t rx_buf[4] = {0}; + const struct max32664c_config *config = dev->config; + + gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT); + gpio_pin_configure_dt(&config->mfio_gpio, GPIO_OUTPUT); + + LOG_INF("Entering app mode"); + gpio_pin_set_dt(&config->reset_gpio, true); + gpio_pin_set_dt(&config->mfio_gpio, false); + k_msleep(2000); + + gpio_pin_set_dt(&config->reset_gpio, false); + k_msleep(5); + + gpio_pin_set_dt(&config->mfio_gpio, true); + k_msleep(15); + + gpio_pin_set_dt(&config->reset_gpio, true); + k_msleep(1700); + + /* Read the device mode */ + if (max32664c_app_i2c_read(dev, 0x02, 0x00, rx_buf, 2)) { + return -EINVAL; + } + + LOG_DBG("Mode: %x ", rx_buf[1]); + if (rx_buf[1] != 0) { + LOG_ERR("Device not in application mode!"); + return -EINVAL; + } + + /* Read the MCU type */ + if (max32664c_app_i2c_read(dev, 0xFF, 0x00, rx_buf, 2)) { + return -EINVAL; + } + + LOG_INF("MCU type: %u", rx_buf[1]); + + /* Read the firmware version */ + if (max32664c_app_i2c_read(dev, 0xFF, 0x03, rx_buf, 4)) { + return -EINVAL; + } + + memcpy(hub_ver, &rx_buf[1], 3); + + LOG_INF("Version: %d.%d.%d", hub_ver[0], hub_ver[1], hub_ver[2]); + + return 0; +} diff --git a/drivers/sensor/adi/max32664c/max32664c_init.c b/drivers/sensor/adi/max32664c/max32664c_init.c new file mode 100644 index 0000000000000..e65d2ec6af3c4 --- /dev/null +++ b/drivers/sensor/adi/max32664c/max32664c_init.c @@ -0,0 +1,246 @@ +/* + * Initialization code for the MAX32664C biometric sensor hub. + * + * Copyright (c) 2025, Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "max32664c.h" + +LOG_MODULE_REGISTER(maxim_max32664c_init, CONFIG_SENSOR_LOG_LEVEL); + +/** @brief Set the SpO2 calibration coefficients. + * NOTE: See page 10 of the SpO2 and Heart Rate User Guide for additional information. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_set_spo2_coeffs(const struct device *dev) +{ + const struct max32664c_config *config = dev->config; + + uint8_t tx[15]; + uint8_t rx; + + /* Write the calibration coefficients */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x00; + + /* Copy the A value (index 0) into the transmission buffer */ + memcpy(&tx[3], &config->spo2_calib[0], sizeof(int32_t)); + + /* Copy the B value (index 1) into the transmission buffer */ + memcpy(&tx[7], &config->spo2_calib[1], sizeof(int32_t)); + + /* Copy the C value (index 2) into the transmission buffer */ + memcpy(&tx[11], &config->spo2_calib[2], sizeof(int32_t)); + + return max32664c_i2c_transmit(dev, tx, sizeof(tx), &rx, sizeof(rx), + MAX32664C_DEFAULT_CMD_DELAY); +} + +/** @brief Write the default configuration to the sensor hub. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_write_config(const struct device *dev) +{ + uint8_t rx; + uint8_t tx[5]; + const struct max32664c_config *config = dev->config; + struct max32664c_data *data = dev->data; + + /* Write the default settings */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x13; + tx[3] = config->min_integration_time_idx; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not write minimum integration time!"); + return -EINVAL; + } + + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x14; + tx[3] = config->min_sampling_rate_idx; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not write minimum sampling rate!"); + return -EINVAL; + } + + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x15; + tx[3] = config->max_integration_time_idx; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not write maximum integration time!"); + return -EINVAL; + } + + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x16; + tx[3] = config->max_sampling_rate_idx; + if (max32664c_i2c_transmit(dev, tx, 4, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not write maximum sampling rate!"); + return -EINVAL; + } + + tx[0] = 0x10; + tx[1] = 0x02; + tx[2] = config->report_period; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set report period!"); + return -EINVAL; + } + + /* Configure WHRM */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x17; + tx[3] = config->hr_config[0]; + tx[4] = config->hr_config[1]; + LOG_DBG("Configuring WHRM: 0x%02X%02X", tx[3], tx[4]); + if (max32664c_i2c_transmit(dev, tx, 5, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not configure WHRM!"); + return -EINVAL; + } + + /* Configure SpO2 */ + tx[0] = 0x50; + tx[1] = 0x07; + tx[2] = 0x18; + tx[3] = config->spo2_config[0]; + tx[4] = config->spo2_config[1]; + LOG_DBG("Configuring SpO2: 0x%02X%02X", tx[3], tx[4]); + if (max32664c_i2c_transmit(dev, tx, 5, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not configure SpO2!"); + return -EINVAL; + } + + /* Set the interrupt threshold */ + tx[0] = 0x10; + tx[1] = 0x01; + tx[2] = 0x01; + if (max32664c_i2c_transmit(dev, tx, 3, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not set interrupt threshold!"); + return -EINVAL; + } + + if (max32664c_set_spo2_coeffs(dev)) { + LOG_ERR("Can not set SpO2 calibration coefficients!"); + return -EINVAL; + } + + data->motion_time = config->motion_time; + data->motion_threshold = config->motion_threshold; + memcpy(data->led_current, config->led_current, sizeof(data->led_current)); + + return 0; +} + +/** @brief Read the configuration from the sensor hub. + * @param dev Pointer to device + * @return 0 when successful + */ +static int max32664c_read_config(const struct device *dev) +{ + uint8_t tx[3]; + uint8_t rx[2]; + struct max32664c_data *data = dev->data; + + tx[0] = 0x11; + tx[1] = 0x02; + if (max32664c_i2c_transmit(dev, tx, 2, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not read report period!"); + return -EINVAL; + } + data->report_period = rx[1]; + + tx[0] = 0x51; + tx[1] = 0x07; + tx[2] = 0x13; + if (max32664c_i2c_transmit(dev, tx, 3, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not read minimum integration time!"); + return -EINVAL; + } + data->min_integration_time_idx = rx[1]; + + tx[0] = 0x51; + tx[1] = 0x07; + tx[2] = 0x14; + if (max32664c_i2c_transmit(dev, tx, 3, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not read minimum sampling rate!"); + return -EINVAL; + } + data->min_sampling_rate_idx = rx[1]; + + tx[0] = 0x51; + tx[1] = 0x07; + tx[2] = 0x15; + if (max32664c_i2c_transmit(dev, tx, 3, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not read maximum integration time!"); + return -EINVAL; + } + data->max_integration_time_idx = rx[1]; + + tx[0] = 0x51; + tx[1] = 0x07; + tx[2] = 0x16; + if (max32664c_i2c_transmit(dev, tx, 3, rx, 2, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not read maximum sampling rate!"); + return -EINVAL; + } + data->max_sampling_rate_idx = rx[1]; + + return 0; +} + +int max32664c_init_hub(const struct device *dev) +{ + struct max32664c_data *data = dev->data; + + LOG_DBG("Initialize sensor hub"); + + if (max32664c_write_config(dev)) { + LOG_ERR("Can not write default configuration!"); + return -EINVAL; + } + + if (max32664c_read_config(dev)) { + LOG_ERR("Can not read configuration!"); + return -EINVAL; + } + + data->is_thread_running = true; + data->thread_id = k_thread_create(&data->thread, data->thread_stack, + K_THREAD_STACK_SIZEOF(data->thread_stack), + (k_thread_entry_t)max32664c_worker, (void *)dev, NULL, + NULL, K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT); + k_thread_suspend(data->thread_id); + k_thread_name_set(data->thread_id, "max32664c_worker"); + + LOG_DBG("Initial configuration:"); + +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + LOG_DBG("\tUsing dynamic memory for queues and buffers"); +#else + LOG_DBG("\tUsing static memory for queues and buffers"); +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + LOG_DBG("\tUsing extended reports"); +#else + LOG_DBG("\tUsing normal reports"); +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS*/ + + LOG_DBG("\tReport period: %u", data->report_period); + LOG_DBG("\tMinimum integration time: %u", data->min_integration_time_idx); + LOG_DBG("\tMinimum sampling rate: %u", data->min_sampling_rate_idx); + LOG_DBG("\tMaximum integration time: %u", data->max_integration_time_idx); + LOG_DBG("\tMaximum sampling rate: %u", data->max_sampling_rate_idx); + + return 0; +} diff --git a/drivers/sensor/adi/max32664c/max32664c_interrupt.c b/drivers/sensor/adi/max32664c/max32664c_interrupt.c new file mode 100644 index 0000000000000..492cdf3e639db --- /dev/null +++ b/drivers/sensor/adi/max32664c/max32664c_interrupt.c @@ -0,0 +1,80 @@ +/* + * Trigger code for the MAX32664C biometric sensor hub. + * + * Copyright (c) 2025, Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "max32664c.h" + +LOG_MODULE_REGISTER(maxim_max32664c_interrupt, CONFIG_SENSOR_LOG_LEVEL); + +#ifdef CONFIG_MAX32664C_USE_INTERRUPT +static void max32664c_interrupt_worker(struct k_work *p_work) +{ + struct max32664c_data *data = CONTAINER_OF(p_work, struct max32664c_data, interrupt_work); + + /* TODO */ +} + +static void max32664c_gpio_callback_handler(const struct device *p_port, struct gpio_callback *p_cb, + gpio_port_pins_t pins) +{ + ARG_UNUSED(pins); + ARG_UNUSED(p_port); + + struct max32664c_data *data = CONTAINER_OF(p_cb, struct max32664c_data, gpio_cb); + + k_work_submit(&data->interrupt_work); +} + +int max32664c_init_interrupt(const struct device *dev) +{ + LOG_DBG("\tUsing MFIO interrupt mode"); + + int err; + uint8_t tx[2]; + uint8_t rx; + struct max32664c_data *data = dev->data; + const struct max32664c_config *config = dev->config; + + LOG_DBG("Configure interrupt pin"); + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("GPIO not ready!"); + return -ENODEV; + } + + err = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (err < 0) { + LOG_ERR("Failed to configure GPIO! Error: %u", err); + return err; + } + + err = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_FALLING); + if (err < 0) { + LOG_ERR("Failed to configure interrupt! Error: %u", err); + return err; + } + + gpio_init_callback(&data->gpio_cb, max32664c_gpio_callback_handler, + BIT(config->int_gpio.pin)); + + err = gpio_add_callback_dt(&config->int_gpio, &data->gpio_cb); + if (err < 0) { + LOG_ERR("Failed to add GPIO callback! Error: %u", err); + return err; + } + + data->interrupt_work.handler = max32664c_interrupt_worker; + + tx[0] = 0xB8; + tx[1] = 0x01; + if (max32664c_i2c_transmit(dev, tx, 2, &rx, 1, MAX32664C_DEFAULT_CMD_DELAY)) { + LOG_ERR("Can not enable interrupt mode!"); + return -EINVAL; + } + + return 0; +} +#endif /* CONFIG_MAX32664C_USE_INTERRUPT */ diff --git a/drivers/sensor/adi/max32664c/max32664c_worker.c b/drivers/sensor/adi/max32664c/max32664c_worker.c new file mode 100644 index 0000000000000..4943c62191909 --- /dev/null +++ b/drivers/sensor/adi/max32664c/max32664c_worker.c @@ -0,0 +1,369 @@ +/* + * Background worker for the MAX32664C biometric sensor hub. + * + * Copyright (c) 2025, Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "max32664c.h" + +LOG_MODULE_REGISTER(maxim_max32664c_worker, CONFIG_SENSOR_LOG_LEVEL); + +/** @brief Read the status from the sensor hub. + * NOTE: Table 7 Sensor Hub Status Byte + * @param dev Pointer to device + * @param status Pointer to status byte + * @param i2c_error Pointer to I2C error byte + * @return 0 when successful, otherwise an error code + */ +static int max32664c_get_hub_status(const struct device *dev, uint8_t *status, uint8_t *i2c_error) +{ + uint8_t tx[2] = {0x00, 0x00}; + uint8_t rx[2]; + + if (max32664c_i2c_transmit(dev, tx, sizeof(tx), rx, sizeof(rx), + MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + *i2c_error = rx[0]; + *status = rx[1]; + + return 0; +} + +/** @brief Read the FIFO sample count. + * @param dev Pointer to device + * @param fifo Pointer to FIFO count + */ +static int max32664c_get_fifo_count(const struct device *dev, uint8_t *fifo) +{ + uint8_t tx[2] = {0x12, 0x00}; + uint8_t rx[2]; + + if (max32664c_i2c_transmit(dev, tx, sizeof(tx), rx, sizeof(rx), + MAX32664C_DEFAULT_CMD_DELAY)) { + return -EINVAL; + } + + *fifo = rx[1]; + + return rx[0]; +} + +/** @brief Push a item into the message queue. + * @param msgq Pointer to message queue + * @param data Pointer to data to push + */ +static void max32664c_push_to_queue(struct k_msgq *msgq, const void *data) +{ + while (k_msgq_put(msgq, data, K_NO_WAIT) != 0) { + k_msgq_purge(msgq); + } +} + +/** @brief Process the buffer to get the raw data from the sensor hub. + * @param dev Pointer to device + */ +static void max32664c_parse_and_push_raw(const struct device *dev) +{ + struct max32664c_data *data = dev->data; + struct max32664c_raw_report_t report; + + report.PPG1 = ((uint32_t)(data->max32664_i2c_buffer[1]) << 16) | + ((uint32_t)(data->max32664_i2c_buffer[2]) << 8) | + data->max32664_i2c_buffer[3]; + report.PPG2 = ((uint32_t)(data->max32664_i2c_buffer[4]) << 16) | + ((uint32_t)(data->max32664_i2c_buffer[5]) << 8) | + data->max32664_i2c_buffer[6]; + report.PPG3 = ((uint32_t)(data->max32664_i2c_buffer[7]) << 16) | + ((uint32_t)(data->max32664_i2c_buffer[8]) << 8) | + data->max32664_i2c_buffer[9]; + + /* PPG4 to 6 are used for PD2 */ + report.PPG4 = 0; + report.PPG5 = 0; + report.PPG6 = 0; + + report.acc.x = + ((int16_t)(data->max32664_i2c_buffer[19]) << 8) | data->max32664_i2c_buffer[20]; + report.acc.y = + ((int16_t)(data->max32664_i2c_buffer[21]) << 8) | data->max32664_i2c_buffer[22]; + report.acc.z = + ((int16_t)(data->max32664_i2c_buffer[23]) << 8) | data->max32664_i2c_buffer[24]; + + max32664c_push_to_queue(&data->raw_report_queue, &report); +} + +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS +/** @brief Process the buffer to get the extended report data from the sensor hub. + * @param dev Pointer to device + */ +static void max32664c_parse_and_push_ext_report(const struct device *dev) +{ + struct max32664c_data *data = dev->data; + struct max32664c_ext_report_t report; + + report.op_mode = data->max32664_i2c_buffer[25]; + report.hr = + (((uint16_t)(data->max32664_i2c_buffer[26]) << 8) | data->max32664_i2c_buffer[27]) / + 10; + report.hr_confidence = data->max32664_i2c_buffer[28]; + report.rr = + (((uint16_t)(data->max32664_i2c_buffer[29]) << 8) | data->max32664_i2c_buffer[30]) / + 10; + report.rr_confidence = data->max32664_i2c_buffer[31]; + report.activity_class = data->max32664_i2c_buffer[32]; + report.total_walk_steps = data->max32664_i2c_buffer[33] | + ((uint32_t)(data->max32664_i2c_buffer[34]) << 8) | + ((uint32_t)(data->max32664_i2c_buffer[35]) << 16) | + ((uint32_t)(data->max32664_i2c_buffer[36]) << 24); + report.total_run_steps = data->max32664_i2c_buffer[37] | + ((uint32_t)(data->max32664_i2c_buffer[38]) << 8) | + ((uint32_t)(data->max32664_i2c_buffer[39]) << 16) | + ((uint32_t)(data->max32664_i2c_buffer[40]) << 24); + report.total_energy_kcal = data->max32664_i2c_buffer[41] | + ((uint32_t)(data->max32664_i2c_buffer[42]) << 8) | + ((uint32_t)(data->max32664_i2c_buffer[43]) << 16) | + ((uint32_t)(data->max32664_i2c_buffer[44]) << 24); + report.total_amr_kcal = data->max32664_i2c_buffer[45] | + ((uint32_t)(data->max32664_i2c_buffer[46]) << 8) | + ((uint32_t)(data->max32664_i2c_buffer[47]) << 16) | + ((uint32_t)(data->max32664_i2c_buffer[48]) << 24); + report.led_current_adj1.adj_flag = data->max32664_i2c_buffer[49]; + report.led_current_adj1.adj_val = + (((uint16_t)(data->max32664_i2c_buffer[50]) << 8) | data->max32664_i2c_buffer[51]) / + 10; + report.led_current_adj2.adj_flag = data->max32664_i2c_buffer[52]; + report.led_current_adj2.adj_val = + (((uint16_t)(data->max32664_i2c_buffer[53]) << 8) | data->max32664_i2c_buffer[54]) / + 10; + report.led_current_adj3.adj_flag = data->max32664_i2c_buffer[55]; + report.led_current_adj3.adj_val = + (((uint16_t)(data->max32664_i2c_buffer[56]) << 8) | data->max32664_i2c_buffer[57]) / + 10; + report.integration_time_adj_flag = data->max32664_i2c_buffer[58]; + report.requested_integration_time = data->max32664_i2c_buffer[59]; + report.sampling_rate_adj_flag = data->max32664_i2c_buffer[60]; + report.requested_sampling_rate = data->max32664_i2c_buffer[61]; + report.requested_sampling_average = data->max32664_i2c_buffer[62]; + report.hrm_afe_ctrl_state = data->max32664_i2c_buffer[63]; + report.is_high_motion_for_hrm = data->max32664_i2c_buffer[64]; + report.scd_state = data->max32664_i2c_buffer[65]; + report.r_value = + (((uint16_t)(data->max32664_i2c_buffer[66]) << 8) | data->max32664_i2c_buffer[67]) / + 1000; + report.spo2_meas.confidence = data->max32664_i2c_buffer[68]; + report.spo2_meas.value = + (((uint16_t)(data->max32664_i2c_buffer[69]) << 8) | data->max32664_i2c_buffer[70]) / + 10; + report.spo2_meas.valid_percent = data->max32664_i2c_buffer[71]; + report.spo2_meas.low_signal_flag = data->max32664_i2c_buffer[72]; + report.spo2_meas.motion_flag = data->max32664_i2c_buffer[73]; + report.spo2_meas.low_pi_flag = data->max32664_i2c_buffer[74]; + report.spo2_meas.unreliable_r_flag = data->max32664_i2c_buffer[75]; + report.spo2_meas.state = data->max32664_i2c_buffer[76]; + report.ibi_offset = data->max32664_i2c_buffer[77]; + report.unreliable_orientation_flag = data->max32664_i2c_buffer[78]; + report.reserved[0] = data->max32664_i2c_buffer[79]; + report.reserved[1] = data->max32664_i2c_buffer[80]; + + max32664c_push_to_queue(&data->ext_report_queue, &report); +} +#else +/** @brief Process the buffer to get the report data from the sensor hub. + * @param dev Pointer to device + */ +static void max32664c_parse_and_push_report(const struct device *dev) +{ + struct max32664c_data *data = dev->data; + struct max32664c_report_t report; + + report.op_mode = data->max32664_i2c_buffer[25]; + report.hr = + (((uint16_t)(data->max32664_i2c_buffer[26]) << 8) | data->max32664_i2c_buffer[27]) / + 10; + report.hr_confidence = data->max32664_i2c_buffer[28]; + report.rr = + (((uint16_t)(data->max32664_i2c_buffer[29]) << 8) | data->max32664_i2c_buffer[30]) / + 10; + report.rr_confidence = data->max32664_i2c_buffer[31]; + report.activity_class = data->max32664_i2c_buffer[32]; + report.r = + (((uint16_t)(data->max32664_i2c_buffer[33]) << 8) | data->max32664_i2c_buffer[34]) / + 1000; + report.spo2_meas.confidence = data->max32664_i2c_buffer[35]; + report.spo2_meas.value = + (((uint16_t)(data->max32664_i2c_buffer[36]) << 8) | data->max32664_i2c_buffer[37]) / + 10; + report.spo2_meas.complete = data->max32664_i2c_buffer[38]; + report.spo2_meas.low_signal_quality = data->max32664_i2c_buffer[39]; + report.spo2_meas.motion = data->max32664_i2c_buffer[40]; + report.spo2_meas.low_pi = data->max32664_i2c_buffer[41]; + report.spo2_meas.unreliable_r = data->max32664_i2c_buffer[42]; + report.spo2_meas.state = data->max32664_i2c_buffer[43]; + report.scd_state = data->max32664_i2c_buffer[44]; + + max32664c_push_to_queue(&data->report_queue, &report); +} +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + +/** @brief Worker thread to read the sensor hub. + * This thread does the following: + * - It polls the sensor hub periodically for new results + * - If new messages are available it reads the number of samples + * - Then it reads all the samples to clear the FIFO. + * It's necessary to clear the complete FIFO because the sensor hub + * doesn´t support the reading of a single message and not clearing + * the FIFO can cause a FIFO overrun. + * - Extract the message data from the FIRST item from the FIFO and + * copy them into the right message structure + * - Put the message into a message queue + * @param dev Pointer to device + */ +void max32664c_worker(const struct device *dev) +{ + int err; + uint8_t fifo = 0; + uint8_t status = 0; + uint8_t i2c_error = 0; + struct max32664c_data *data = dev->data; + + LOG_DBG("Starting worker thread for device: %s", dev->name); + + while (data->is_thread_running) { + err = max32664c_get_hub_status(dev, &status, &i2c_error); + if (err) { + LOG_ERR("Failed to get hub status! Error: %d", err); + continue; + } + + if (!(status & (1 << MAX32664C_BIT_STATUS_DATA_RDY))) { + LOG_WRN("No data ready! Status: 0x%X", status); + k_msleep(100); + continue; + } + + err = max32664c_get_fifo_count(dev, &fifo); + if (err) { + LOG_ERR("Failed to get FIFO count! Error: %d", err); + continue; + } + + if (fifo == 0) { + LOG_DBG("No data available in the FIFO."); + continue; + } +#ifdef CONFIG_MAX32664C_USE_STATIC_MEMORY + else if (fifo > CONFIG_MAX32664C_SAMPLE_BUFFER_SIZE) { + LOG_ERR("FIFO count %u exceeds maximum buffer size %u!", + fifo, CONFIG_MAX32664C_SAMPLE_BUFFER_SIZE); + + /* TODO: Find a good way to clear the FIFO */ + continue; + } +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + size_t buffer_size = fifo * (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_ext_report_t)) + + 1; +#else + size_t buffer_size = fifo * (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_report_t)) + + 1; +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + + LOG_DBG("Allocating memory %u samples", fifo); + LOG_DBG("Allocating memory for the I2C buffer with size: %u", buffer_size); + data->max32664_i2c_buffer = (uint8_t *)k_malloc(buffer_size); + + if (data->max32664_i2c_buffer == NULL) { + LOG_ERR("Can not allocate memory for the I2C buffer!"); + continue; + } +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + + uint8_t tx[2] = {0x12, 0x01}; + + switch (data->op_mode) { + case MAX32664C_OP_MODE_RAW: { + /* Get all samples to clear the FIFO */ + max32664c_i2c_transmit( + dev, tx, 2, data->max32664_i2c_buffer, + (fifo * (sizeof(struct max32664c_raw_report_t))) + + 1, + MAX32664C_DEFAULT_CMD_DELAY); + + if (data->max32664_i2c_buffer[0] != 0) { + break; + } + + max32664c_parse_and_push_raw(dev); + + break; + } +#ifdef CONFIG_MAX32664C_USE_EXTENDED_REPORTS + case MAX32664C_OP_MODE_ALGO_AEC_EXT: + case MAX32664C_OP_MODE_ALGO_AGC_EXT: { + + /* Get all samples to clear the FIFO */ + max32664c_i2c_transmit( + dev, tx, 2, data->max32664_i2c_buffer, + (fifo * (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_ext_report_t))) + + 1, + MAX32664C_DEFAULT_CMD_DELAY); + + if (data->max32664_i2c_buffer[0] != 0) { + break; + } + + max32664c_parse_and_push_raw(dev); + max32664c_parse_and_push_ext_report(dev); + + break; + } +#else + case MAX32664C_OP_MODE_ALGO_AEC: + case MAX32664C_OP_MODE_ALGO_AGC: { + + /* Get all samples to clear the FIFO */ + max32664c_i2c_transmit( + dev, tx, 2, data->max32664_i2c_buffer, + (fifo * (sizeof(struct max32664c_raw_report_t) + + sizeof(struct max32664c_report_t))) + + 1, + MAX32664C_DEFAULT_CMD_DELAY); + + if (data->max32664_i2c_buffer[0] != 0) { + break; + } + + max32664c_parse_and_push_raw(dev); + max32664c_parse_and_push_report(dev); + + break; + } +#endif /* CONFIG_MAX32664C_USE_EXTENDED_REPORTS */ + default: { + break; + } + } + + if (data->max32664_i2c_buffer[0] != 0) { + LOG_ERR("Can not read report! Status: 0x%X", + data->max32664_i2c_buffer[0]); + } + +#ifndef CONFIG_MAX32664C_USE_STATIC_MEMORY + k_free(data->max32664_i2c_buffer); +#endif /* CONFIG_MAX32664C_USE_STATIC_MEMORY */ + + k_msleep(100); + } +} diff --git a/dts/bindings/sensor/maxim,max32664c.yml b/dts/bindings/sensor/maxim,max32664c.yml new file mode 100644 index 0000000000000..3f8c36c77499f --- /dev/null +++ b/dts/bindings/sensor/maxim,max32664c.yml @@ -0,0 +1,159 @@ +title: | + MAX32664 biometric sensor hub + +description: | + The MAX32664 is a ultra-low power biometric sensor hub. + + NOTES: + This driver is primarily written to work with a MAX86141. Other sensors can be + used but they are untested! The driver supports up to two photodetectors (PDs) + and three LEDs fix. It requires a specific LED + configuration for the MAX86141. + LED1 -> Green + LED2 -> IR + LED3 -> Red + The LEDs can be changed manually but this may require changes in the driver. + + This driver is tested with Sensor Hub firmware 30.13.31 and an external + Accelerometer (e.g. LIS2DH12). + + See more info at: + https://www.analog.com/media/en/technical-documentation/data-sheets/MAX32664.pdf + +compatible: "maxim,max32664c" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + reset-gpios: + type: phandle-array + required: true + description: + External System Reset (Active-Low) Input. + + mfio-gpios: + type: phandle-array + required: true + description: + MFIO asserts low as an output when the sensor hub needs to + communication with the host; MFIO acts as an input and when held + low during a reset, the sensor hub enters bootloader mode. + + use-max86141: + type: boolean + description: + Use the MAX86141 as the AFE for the MAX32664C. This is the + default and recommended configuration. The driver is optimized for + this sensor. + + use-max86161: + type: boolean + description: + Use the MAX86161 as the AFE for the MAX32664C. + + motion-time: + type: int + default: 200 + description: + Sensor Hub configuration - Motion activation time in milliseconds. + The default corresponds to Table 12 in the HR and SpO2 User guide. + + motion-threshold: + type: int + default: 500 + description: + Sensor Hub configuration - Motion activation time in milli-g. + The default corresponds to Table 12 in the HR and SpO2 User guide. + + report-period: + type: int + default: 1 + description: + Sensor Hub configuration - Set the samples report period (e.g., a value + of 25 means a samples report is generated once every 25 samples). + The default corresponds to Table 16 in the HR and SpO2 User guide. + + spo2-calib: + type: array + default: [0xFFE69196, 0x000CB735, 0x00989680] + description: + Algorithm configuration - SpO2 calibration coefficients. + The default corresponds to Table 12 in the HR and SpO2 User guide. + + min-integration-time: + type: int + default: 14 + enum: + - 14 + - 29 + - 58 + - 117 + description: + Algorithm configuration - Minimum integration time in microseconds. + The default corresponds to Table 11 in the HR and SpO2 User guide. + + min-sampling-rate: + type: int + default: 50 + enum: + - 25 + - 50 + - 100 + - 200 + - 400 + description: + Algorithm configuration - Minimum sampling rate (samples per second) + and averaging (samples). + The default corresponds to Table 11 in the HR and SpO2 User guide. + + max-integration-time: + type: int + default: 117 + enum: + - 14 + - 29 + - 58 + - 117 + description: + Algorithm configuration - Maximum integration time in microseconds. + The default corresponds to Table 11 in the HR and SpO2 User guide. + + max-sampling-rate: + type: int + default: 100 + enum: + - 25 + - 50 + - 100 + - 200 + - 400 + description: + Algorithm configuration - Maximum sampling rate (samples per second) + and averaging (samples). + The default corresponds to Table 11 in the HR and SpO2 User guide. + + led-current: + type: uint8-array + default: [0x7F, 0x7F, 0x7F] + description: + Initial LED current configuration in bits. Please check the datasheet + of the attached AFE to determine the appropriate values. + The current can also be changed later by the firmware. + Index 0 corresponds to LED1, index 1 to LED2, and index 2 to LED3. + The default corresponds to Table 5 in the HR and SpO2 User guide. + + hr-config: + type: uint8-array + default: [0x00, 0x01] + description: + Algorithm configuration - LED and PD configuration for the heartrate measurement. + The first entry configures channel 1, the second channel 2. + The default corresponds to Table 15 in the HR and SpO2 User guide. + + spo2-config: + type: uint8-array + default: [0x10, 0x20] + description: + Algorithm configuration - LED and PD configuration for the SpO2 measurement. + The first entry configures the IR channel, the second the red channel. + The default corresponds to Table 15 in the HR and SpO2 User guide. diff --git a/include/zephyr/drivers/sensor/max32664c.h b/include/zephyr/drivers/sensor/max32664c.h new file mode 100644 index 0000000000000..128f15ead201a --- /dev/null +++ b/include/zephyr/drivers/sensor/max32664c.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2025 Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_MAX32664C_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_MAX32664C_H_ + +#include + +/** @brief Converts a motion time in milli-seconds to the corresponding value for the MAX32664C + * sensor. This macro should be used when configuring the motion based wake up settings for the + * sensor. + */ +#define MAX32664C_MOTION_TIME(ms) ((uint8_t)((ms * 25UL) / 1000)) + +/** @brief Converts a motion threshold in milli-g (Acceleration) to the corresponding value for the + * MAX32664C sensor. This macro should be used when configuring the motion based wake up settings + * for the sensor. + */ +#define MAX32664C_MOTION_THRESHOLD(mg) ((uint8_t)((mg * 16UL) / 1000)) + +/* MAX32664C specific channels */ +enum sensor_channel_max32664c { + /** Heart rate value (bpm) */ + SENSOR_CHAN_MAX32664C_HEARTRATE = SENSOR_CHAN_PRIV_START, + /** SpO2 value (%) */ + SENSOR_CHAN_MAX32664C_BLOOD_OXYGEN_SATURATION, + /** Respiration rate (breaths per minute) */ + SENSOR_CHAN_MAX32664C_RESPIRATION_RATE, + /** Skin contact (1 -> Skin contact, 0, no contact) */ + SENSOR_CHAN_MAX32664C_SKIN_CONTACT, + /** Activity class (index). The reported index is vendor specific. */ + SENSOR_CHAN_MAX32664C_ACTIVITY, + /** Step counter */ + SENSOR_CHAN_MAX32664C_STEP_COUNTER, +}; + +/* MAX32664C specific attributes */ +enum sensor_attribute_max32664c { + /** Gender of the subject being monitored */ + SENSOR_ATTR_MAX32664C_GENDER = SENSOR_ATTR_PRIV_START, + /** Age of the subject being monitored */ + SENSOR_ATTR_MAX32664C_AGE, + /** Weight of the subject being monitored */ + SENSOR_ATTR_MAX32664C_WEIGHT, + /** Height of the subject being monitored */ + SENSOR_ATTR_MAX32664C_HEIGHT, + /** Get / Set the operation mode of a sensor. This can be used to + * switch between different measurement modes when a sensor supports them. + */ + SENSOR_ATTR_MAX32664C_OP_MODE, +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Device operating modes for the MAX32664C sensor. + * + * This enum defines the various operating modes that the MAX32664C sensor + * can be configured to. These modes control the sensor's behavior and + * functionality, such as calibration, idle state, raw data output, and + * algorithm-based operations. + */ +enum max32664c_device_mode { + MAX32664C_OP_MODE_IDLE, /**< Idle mode, no algorithm, */ + /**< sensors or wake on motion running */ + MAX32664C_OP_MODE_RAW, /**< Raw output mode */ + /* For hardware testing purposes, the user may choose to start the sensor hub to collect + * raw PPG samples. In this case, the host configures the sensor hub to work in Raw Data + * mode (no algorithm) by enabling the accelerometer and the AFE. + */ + MAX32664C_OP_MODE_ALGO_AEC, /**< Algorithm AEC mode */ + /* Automatic Exposure Control (AEC) is Maxim’s gain control algorithm that is superior to + * AGC. The AEC algorithm optimally maintains the best SNR range and power optimization. The + * targeted SNR range is maintained regardless of skin color or ambient temperature within + * the limits of the LED currents configurations; The AEC dynamically manages the + * appropriate register settings for sampling rate, LED current, pulse width and integration + * time. + */ + MAX32664C_OP_MODE_ALGO_AEC_EXT, /**< Algorithm with extended reports */ + MAX32664C_OP_MODE_ALGO_AGC, /**< Algorithm AGC mode */ + /* In this mode, the wearable algorithm suite (SpO2 and WHRM) is enabled and the R value, + * SpO2, SpO2 confidence level, heart rate, heart rate confidence level, RR value, and + * activity class are reported. Furthermore, automatic gain control (AGC) is enabled. + * Because AGC is a subset of AEC functionality, to enable AGC, AEC still needs to be + * enabled. However, automatic calculation of target PD should be turned off, and the + * desired level of AGC target PD current is set by the user. The user may change the + * algorithm to the desired configuration mode. If signal quality is poor, the user may need + * to adjust the AGC settings to maintain optimal performance. If signal quality is low, a + * LowSNR flag will be set. Excessive motion is also reported with a flag. + */ + MAX32664C_OP_MODE_ALGO_AGC_EXT, /**< Algorithm AGC with extended reports */ + MAX32664C_OP_MODE_SCD, /**< SCD only mode */ + MAX32664C_OP_MODE_WAKE_ON_MOTION, /**< Wake on motion mode */ + MAX32664C_OP_MODE_EXIT_WAKE_ON_MOTION, /**< Exit wake on motion mode */ + MAX32664C_OP_MODE_STOP_ALGO, /**< Stop the current algorithm */ +}; + +/** @brief Algorithm modes for the MAX32664C sensor. + * + * This enum defines the various algorithm modes supported by the MAX32664C sensor. + * These modes determine the type of data processing performed by the sensor, + * such as continuous heart rate monitoring, SpO2 calculation, or activity tracking. + */ +enum max32664c_algo_mode { + MAX32664C_ALGO_MODE_CONT_HR_CONT_SPO2, + MAX32664C_ALGO_MODE_CONT_HR_SHOT_SPO2, + MAX32664C_ALGO_MODE_CONT_HRM, + /* NOTE: These algorithm modes are untested */ + /*MAX32664C_ALGO_MODE_SAMPLED_HRM,*/ + /*MAX32664C_ALGO_MODE_SAMPLED_HRM_SHOT_SPO2,*/ + /*MAX32664C_ALGO_MODE_ACTIVITY_TRACK,*/ + /*MAX32664C_ALGO_MODE_SAMPLED_HRM_FAST_SPO2 = 7,*/ +}; + +/** @brief Gender settings for the MAX32664C sensor. + * + * This enum defines the supported gender settings for the MAX32664C sensor. + */ +enum max32664c_algo_gender { + MAX32664_ALGO_GENDER_MALE, + MAX32664_ALGO_GENDER_FEMALE, +}; + +/** @brief Activity classes for the MAX32664C sensor. + * + * This enum defines the supported activity classes for the MAX32664C sensor. + */ +enum max32664c_algo_activity { + MAX32664C_ALGO_ACTIVITY_REST, + MAX32664C_ALGO_ACTIVITY_OTHER, + MAX32664C_ALGO_ACTIVITY_WALK, + MAX32664C_ALGO_ACTIVITY_RUN, + MAX32664C_ALGO_ACTIVITY_BIKE, +}; + +/** @brief Data structure for external accelerometer data. + * + * This structure is used to represent the accelerometer data that can be + * collected from an external accelerometer and then fed into the MAX32664C + * sensor hub. It contains the x, y, and z acceleration values. + * This structure is only used when the external accelerometer is enabled. + */ +struct max32664c_acc_data_t { + int16_t x; + int16_t y; + int16_t z; +} __packed; + +#ifdef CONFIG_MAX32664C_USE_FIRMWARE_LOADER +/** @brief Enter the bootloader mode and run a firmware update. + * @param dev Pointer to device + * @param firmware Pointer to firmware data + * @param size Size of the firmware + * @return 0 when successful + */ +int max32664c_bl_enter(const struct device *dev, const uint8_t *firmware, uint32_t size); + +/** @brief Leave the bootloader and enter the application mode. + * @param dev Pointer to device + * @return 0 when successful + */ +int max32664c_bl_leave(const struct device *dev); +#endif /* CONFIG_MAX32664C_USE_FIRMWARE_LOADER */ + +#ifdef CONFIG_MAX32664C_USE_EXTERNAL_ACC +/** @brief Fill the FIFO buffer with accelerometer data + * NOTE: This function supports up to 16 samples and it must be called + * periodically to provide accelerometer data to the MAX32664C! + * @param dev Pointer to device + * @param data Pointer to the accelerometer data structure + * @param length Number of samples to fill + * @return 0 when successful + */ +int max32664c_acc_fill_fifo(const struct device *dev, struct max32664c_acc_data_t *data, + uint8_t length); +#endif /* CONFIG_MAX32664C_USE_EXTERNAL_ACC*/ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_MAX32664C_H_ */ diff --git a/samples/sensor/max32664c/CMakeLists.txt b/samples/sensor/max32664c/CMakeLists.txt new file mode 100644 index 0000000000000..4992762f91cdf --- /dev/null +++ b/samples/sensor/max32664c/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(max32664c) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/sensor/max32664c/README.rst b/samples/sensor/max32664c/README.rst new file mode 100644 index 0000000000000..0c25e003f3928 --- /dev/null +++ b/samples/sensor/max32664c/README.rst @@ -0,0 +1,49 @@ +.. zephyr:code-sample:: max32664c + :name: MAX32664C + MAX86141 Sensor Hub + :relevant-api: sensor_interface + +Get health data from a MAX32664C and a MAX86141 sensor (polling mode). + +NOTE: This example requires sensor hub firmware 30.13.31! + +Overview +******** + +This sample measures the heart rate and the blood oxygen saturation on a wrist. +It uses the MAX32664C sensor to control the MAX86141 sensor. + +Requirements +************ + +This sample uses the MAX32664 sensor controlled using the I2C30 interface at +the nRF54L15-DK board. + +References +********** + +- MAX32664C: https://www.analog.com/en/products/max32664.html + +Building and Running +******************** + +This project outputs sensor data to the console. It requires a MAX32664C +sensor to be connected to the desired board. An additional MAX86141 sensor +must be connected to the MAX32664C to provide the sensor data for the algorithms. + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/max32664c/ + :goals: build flash + +Sample Output +============= + +.. code-block:: console + + [00:00:00.000,000] sensor: MAX32664C: Initializing... + [00:00:01.600,000] sensor: MAX32664C: Initialization complete. + [00:00:01.600,000] sensor: MAX32664C: HR: 75 bpm + [00:00:01.600,100] sensor: MAX32664C: HR Confidence: 98 + [00:00:02.600,000] sensor: MAX32664C: HR: 76 bpm + [00:00:02.600,100] sensor: MAX32664C: HR Confidence: 97 + [00:00:03.600,000] sensor: MAX32664C: HR: 74 bpm + [00:00:03.600,100] sensor: MAX32664C: HR Confidence: 98 diff --git a/samples/sensor/max32664c/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/samples/sensor/max32664c/boards/nrf54l15dk_nrf54l15_cpuapp.overlay new file mode 100644 index 0000000000000..92d64ae965303 --- /dev/null +++ b/samples/sensor/max32664c/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + i2c30_default: i2c30_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; + + i2c30_sleep: i2c30_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +/ { + aliases { + sensor = &biometric_hub; + }; +}; + +&i2c30 { + compatible = "nordic,nrf-twim"; + status = "okay"; + clock-frequency = ; + + // Flash buffer size is needed for the I2C bootloader to flash the firmware + zephyr,flash-buf-max-size = <8250>; + + pinctrl-0 = <&i2c30_default>; + pinctrl-1 = <&i2c30_sleep>; + pinctrl-names = "default", "sleep"; + + biometric_hub: max32664c@55 { + compatible = "maxim,max32664c"; + reg = <0x55>; + status = "okay"; + reset-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>; + mfio-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; + use-max86141; + }; +}; + +&dppic10 { + status = "okay"; +}; + +&ppib11 { + status = "okay"; +}; + +&ppib21 { + status = "okay"; +}; + +&dppic20 { + status = "okay"; +}; + +&ppib22 { + status = "okay"; +}; + +&ppib30 { + status = "okay"; +}; + +&dppic30 { + status = "okay"; +}; diff --git a/samples/sensor/max32664c/prj.conf b/samples/sensor/max32664c/prj.conf new file mode 100644 index 0000000000000..653e8d1b0cf5a --- /dev/null +++ b/samples/sensor/max32664c/prj.conf @@ -0,0 +1,7 @@ +CONFIG_I2C=y +CONFIG_SENSOR=y + +CONFIG_LOG=y +CONFIG_LOG_PRINTK=y + +CONFIG_HEAP_MEM_POOL_SIZE=16384 diff --git a/samples/sensor/max32664c/sample.yaml b/samples/sensor/max32664c/sample.yaml new file mode 100644 index 0000000000000..e515826752305 --- /dev/null +++ b/samples/sensor/max32664c/sample.yaml @@ -0,0 +1,15 @@ +sample: + name: MAX32664C heart rate monitor sample +tests: + sample.sensor.max32664c: + harness: sensor + platform_allow: + - nrf54l15dk/nrf54l15/cpuapp + integration_platforms: + - nrf54l15dk/nrf54l15/cpuapp + tags: + - sensors + - heart rate + filter: dt_compat_enabled("maxim,max32664c") + depends_on: + - i2c diff --git a/samples/sensor/max32664c/src/main.c b/samples/sensor/max32664c/src/main.c new file mode 100644 index 0000000000000..96a32cb7b7a9a --- /dev/null +++ b/samples/sensor/max32664c/src/main.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Daniel Kampert + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +static const struct device *const sensor_hub = DEVICE_DT_GET(DT_ALIAS(sensor)); + +LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); + +static void update(void) +{ + struct sensor_value value; + + sensor_sample_fetch(sensor_hub); + sensor_attr_get(sensor_hub, SENSOR_CHAN_MAX32664C_HEARTRATE, SENSOR_ATTR_MAX32664C_OP_MODE, + &value); + if (value.val1 == MAX32664C_OP_MODE_RAW) { + struct sensor_value x; + struct sensor_value y; + struct sensor_value z; + + if (sensor_channel_get(sensor_hub, SENSOR_CHAN_ACCEL_X, &x) || + sensor_channel_get(sensor_hub, SENSOR_CHAN_ACCEL_Y, &y) || + sensor_channel_get(sensor_hub, SENSOR_CHAN_ACCEL_Z, &z)) { + LOG_ERR("Failed to get accelerometer data"); + return; + } + + LOG_INF("\tx: %i", x.val1); + LOG_INF("\ty: %i", y.val1); + LOG_INF("\tz: %i", z.val1); + } else if (value.val1 == MAX32664C_OP_MODE_ALGO_AEC) { + struct sensor_value hr; + + if (sensor_channel_get(sensor_hub, SENSOR_CHAN_MAX32664C_HEARTRATE, &hr)) { + LOG_ERR("Failed to get heart rate data"); + return; + } + + LOG_INF("HR: %u bpm", hr.val1); + LOG_INF("HR Confidence: %u", hr.val2); + } else { + LOG_WRN("Operation mode not implemented: %u", value.val1); + } +} + +int main(void) +{ + struct sensor_value value; + + if (!device_is_ready(sensor_hub)) { + LOG_ERR("Sensor hub not ready!"); + return -1; + } + + LOG_INF("Sensor hub ready"); + + value.val1 = MAX32664C_OP_MODE_ALGO_AEC; + value.val2 = MAX32664C_ALGO_MODE_CONT_HRM; + sensor_attr_set(sensor_hub, SENSOR_CHAN_MAX32664C_HEARTRATE, SENSOR_ATTR_MAX32664C_OP_MODE, + &value); + + while (1) { + update(); + k_msleep(1000); + } + + return 0; +} From ecfc23e64574a2f1a99aaba8276428287b184162 Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Sun, 20 Jul 2025 21:29:39 +0000 Subject: [PATCH 347/397] boards: nucleo_n657x0_q: add DCMIPP and CSI connector support Add an instance for DCMIPP as well as devicetree definitions to allow plugging Raspberry Pi 22 pins or 15 pins shields via the csi_* devicetree labels. Signed-off-by: Josuah Demangeon Signed-off-by: Alain Volmat --- .../nucleo_n657x0_q_common.dtsi | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index 0660ce0463c08..988e5dd8f9c71 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "arduino_r3_connector.dtsi" @@ -54,6 +55,15 @@ led2 = &red_led; sw0 = &user_button; }; + + csi_connector: connector_csi { + compatible = "raspberrypi,csi-connector"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = , + ; + }; }; &clk_hse { @@ -109,6 +119,19 @@ status = "okay"; }; +&ic17 { + pll-src = <1>; + ic-div = <4>; + status = "okay"; +}; + +/* IC18 must be enabled for the 27MHz CSIPHY */ +&ic18 { + pll-src = <1>; + ic-div = <60>; + status = "okay"; +}; + &perck { clocks = <&rcc STM32_SRC_HSI PER_SEL(0)>; status = "okay"; @@ -154,6 +177,15 @@ status = "okay"; }; +csi_i2c: &i2c2 { + clocks = <&rcc STM32_CLOCK(APB1, 22)>, + <&rcc STM32_SRC_CKPER I2C2_SEL(1)>; + pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; +}; + &i2c4 { clocks = <&rcc STM32_CLOCK(APB4, 7)>, <&rcc STM32_SRC_CKPER I2C4_SEL(1)>; @@ -257,3 +289,9 @@ zephyr_udc0: &usbotg_hs1 { }; }; }; + +csi_interface: &dcmipp { + port { + csi_ep_in: endpoint {}; + }; +}; From 90b277c63381fbbd150ee0d683c386ad48fd67e2 Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Sun, 20 Jul 2025 23:29:31 +0000 Subject: [PATCH 348/397] shields: st_b_cams_imx_mb1854: introduce csi_gpio1_hogs The "gpio-hog;" devicetree property configuring the "power enable" pin at boot was not working, due to being placed on a gpio-nexus. This is not supported and lead the gpio-hog inactive. Instead, let the board specify their CSI_IO0 and CSI_IO1 pin as GPIO hogs with status = "disabled", letting shields enable them and set the direction as needed. Signed-off-by: Josuah Demangeon --- .../st_b_cams_imx_mb1854/Kconfig.defconfig | 3 +++ .../st_b_cams_imx_mb1854.overlay | 11 ++++------- .../nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi | 16 ++++++++++++++++ .../st/stm32n6570_dk/stm32n6570_dk_common.dtsi | 16 ++++++++++++++++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/boards/shields/st_b_cams_imx_mb1854/Kconfig.defconfig b/boards/shields/st_b_cams_imx_mb1854/Kconfig.defconfig index ce0297675d285..db13e996f1f41 100644 --- a/boards/shields/st_b_cams_imx_mb1854/Kconfig.defconfig +++ b/boards/shields/st_b_cams_imx_mb1854/Kconfig.defconfig @@ -14,4 +14,7 @@ config VIDEO_STM32_DCMIPP_SENSOR_WIDTH config VIDEO_STM32_DCMIPP_SENSOR_HEIGHT default 1944 +config GPIO_HOGS + default y + endif # VIDEO_STM32_DCMIPP diff --git a/boards/shields/st_b_cams_imx_mb1854/st_b_cams_imx_mb1854.overlay b/boards/shields/st_b_cams_imx_mb1854/st_b_cams_imx_mb1854.overlay index 5399867bfc737..0ee986db6af58 100644 --- a/boards/shields/st_b_cams_imx_mb1854/st_b_cams_imx_mb1854.overlay +++ b/boards/shields/st_b_cams_imx_mb1854/st_b_cams_imx_mb1854.overlay @@ -47,11 +47,8 @@ }; }; -&csi_connector { - /* Power the camera module */ - en-module-gpios { - gpio-hog; - gpios = ; - output-high; - }; +/* Power the camera module */ +&csi_gpio1_hog { + status = "okay"; + output-high; }; diff --git a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi index 988e5dd8f9c71..7bbb69b776935 100644 --- a/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi +++ b/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi @@ -66,6 +66,22 @@ }; }; +&gpioo { + csi_gpio0_hog: csi-gpio0-hog { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + +&gpioa { + csi_gpio1_hog: csi-gpio1-hog { + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + &clk_hse { hse-div2; clock-frequency = ; diff --git a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi index 0f1096116a1bd..e93f6ffa86f14 100644 --- a/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi +++ b/boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi @@ -86,6 +86,22 @@ }; }; +&gpioc { + csi_gpio0_hog: csi-gpio0-hog { + gpio-hog; + gpios = <8 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + +&gpiod { + csi_gpio1_hog: csi-gpio1-hog { + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + &i2c2 { status = "okay"; clocks = <&rcc STM32_CLOCK(APB1, 22)>, From b0c5f3d45f9242e9d152e36d46fbf1b29d8df7f1 Mon Sep 17 00:00:00 2001 From: Nathan Winslow Date: Thu, 31 Jul 2025 11:54:50 -0400 Subject: [PATCH 349/397] drivers: fuelgauge: Added properties to prop_type. Adds properties to fuel gauge api to support ADI LTC2959. Signed-off-by: Nathan Winslow --- drivers/fuel_gauge/CMakeLists.txt | 1 + drivers/fuel_gauge/Kconfig | 1 + drivers/fuel_gauge/ltc2959/CMakeLists.txt | 4 + drivers/fuel_gauge/ltc2959/Kconfig | 20 + drivers/fuel_gauge/ltc2959/emul_ltc2959.c | 255 ++++++++ drivers/fuel_gauge/ltc2959/ltc2959.c | 683 ++++++++++++++++++++++ drivers/fuel_gauge/ltc2959/ltc2959.h | 76 +++ dts/bindings/fuel-gauge/adi,ltc2959.yaml | 20 + include/zephyr/drivers/fuel_gauge.h | 40 ++ 9 files changed, 1100 insertions(+) create mode 100644 drivers/fuel_gauge/ltc2959/CMakeLists.txt create mode 100644 drivers/fuel_gauge/ltc2959/Kconfig create mode 100644 drivers/fuel_gauge/ltc2959/emul_ltc2959.c create mode 100644 drivers/fuel_gauge/ltc2959/ltc2959.c create mode 100644 drivers/fuel_gauge/ltc2959/ltc2959.h create mode 100644 dts/bindings/fuel-gauge/adi,ltc2959.yaml diff --git a/drivers/fuel_gauge/CMakeLists.txt b/drivers/fuel_gauge/CMakeLists.txt index afd417040cf89..fa1a0f12bcbfe 100644 --- a/drivers/fuel_gauge/CMakeLists.txt +++ b/drivers/fuel_gauge/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_AXP2101 axp2101) add_subdirectory_ifdef(CONFIG_LC709203F lc709203f) add_subdirectory_ifdef(CONFIG_SY24561 sy24561) add_subdirectory_ifdef(CONFIG_BQ40Z50 bq40z50) +add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_LTC2959 ltc2959) zephyr_library_sources_ifdef(CONFIG_USERSPACE fuel_gauge_syscall_handlers.c) diff --git a/drivers/fuel_gauge/Kconfig b/drivers/fuel_gauge/Kconfig index c7168036e3eac..cb4ca429c863f 100644 --- a/drivers/fuel_gauge/Kconfig +++ b/drivers/fuel_gauge/Kconfig @@ -27,5 +27,6 @@ source "drivers/fuel_gauge/composite/Kconfig" source "drivers/fuel_gauge/axp2101/Kconfig" source "drivers/fuel_gauge/lc709203f/Kconfig" source "drivers/fuel_gauge/sy24561/Kconfig" +source "drivers/fuel_gauge/ltc2959/Kconfig" endif # FUEL_GAUGE diff --git a/drivers/fuel_gauge/ltc2959/CMakeLists.txt b/drivers/fuel_gauge/ltc2959/CMakeLists.txt new file mode 100644 index 0000000000000..3c072d684ab17 --- /dev/null +++ b/drivers/fuel_gauge/ltc2959/CMakeLists.txt @@ -0,0 +1,4 @@ +zephyr_library_sources(ltc2959.c) + +zephyr_include_directories_ifdef(CONFIG_EMUL_LTC2959 .) +zephyr_library_sources_ifdef(CONFIG_EMUL_LTC2959 ./emul_ltc2959.c) diff --git a/drivers/fuel_gauge/ltc2959/Kconfig b/drivers/fuel_gauge/ltc2959/Kconfig new file mode 100644 index 0000000000000..070b809c85cca --- /dev/null +++ b/drivers/fuel_gauge/ltc2959/Kconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Nathan Winslow +# +# SPDX-License-Identifier: Apache-2.0 + +config FUEL_GAUGE_LTC2959 + depends on DT_HAS_ADI_LTC2959_ENABLED + bool "LTC2959 Fuel Gauge" + default y + select I2C + help + Enable the LTC2959 fuel gauge driver from Analog Devices. + +config EMUL_LTC2959 + bool "Emulate an LTC2959 fuel gauge" + default y + depends on EMUL + depends on FUEL_GAUGE_LTC2959 + help + It provides readings which follow a simple sequence, thus allowing + test code to check that things are working as expected. diff --git a/drivers/fuel_gauge/ltc2959/emul_ltc2959.c b/drivers/fuel_gauge/ltc2959/emul_ltc2959.c new file mode 100644 index 0000000000000..fe40019cc8142 --- /dev/null +++ b/drivers/fuel_gauge/ltc2959/emul_ltc2959.c @@ -0,0 +1,255 @@ +/** + * Copyright (c) 2025 Nathan Winslow + * SPDX-License-Identifier: Apache-2.0 + * + * Emulator for ltc2959 fuel gauge + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT adi_ltc2959 + +LOG_MODULE_REGISTER(EMUL_LTC2959); + +#include "ltc2959.h" + +struct ltc2959_emul_data { + uint8_t regs[LTC2959_REG_GPIO_THRESH_LOW_LSB + 1]; /* enough for all regs */ +}; + +struct ltc2959_emul_cfg { + /* I2C Address of emulator */ + uint16_t addr; +}; + +static int ltc2959_emul_reset(const struct emul *target) +{ + struct ltc2959_emul_data *data = (struct ltc2959_emul_data *)target->data; + + memset(data->regs, 0, sizeof(data->regs)); + + /* Values according to pgs 10-11 of the LTC2959 datasheet */ + data->regs[LTC2959_REG_STATUS] = 0x01; + data->regs[LTC2959_REG_ADC_CONTROL] = 0x18; + data->regs[LTC2959_REG_CC_CONTROL] = 0x50; + data->regs[LTC2959_REG_ACC_CHARGE_3] = 0x80; + data->regs[LTC2959_REG_CHG_THRESH_HIGH_3] = 0xFF; + data->regs[LTC2959_REG_CHG_THRESH_HIGH_2] = 0xFF; + data->regs[LTC2959_REG_CHG_THRESH_HIGH_1] = 0xFF; + data->regs[LTC2959_REG_CHG_THRESH_HIGH_0] = 0xFF; + data->regs[LTC2959_REG_VOLT_THRESH_HIGH_MSB] = 0xFF; + data->regs[LTC2959_REG_VOLT_THRESH_HIGH_LSB] = 0xFF; + data->regs[LTC2959_REG_CURR_THRESH_HIGH_MSB] = 0x7F; + data->regs[LTC2959_REG_CURR_THRESH_HIGH_LSB] = 0xFF; + data->regs[LTC2959_REG_CURR_THRESH_LOW_MSB] = 0x80; + data->regs[LTC2959_REG_MAX_CURRENT_MSB] = 0x80; + data->regs[LTC2959_REG_MIN_CURRENT_MSB] = 0x7F; + data->regs[LTC2959_REG_MIN_CURRENT_LSB] = 0xFF; + data->regs[LTC2959_REG_TEMP_THRESH_HIGH_MSB] = 0xFF; + data->regs[LTC2959_REG_TEMP_THRESH_HIGH_LSB] = 0xFF; + data->regs[LTC2959_REG_GPIO_THRESH_HIGH_MSB] = 0x7F; + data->regs[LTC2959_REG_GPIO_THRESH_HIGH_LSB] = 0xFF; + data->regs[LTC2959_REG_GPIO_THRESH_LOW_MSB] = 0x80; + + return 0; +} + +static int emul_ltc2959_reg_write(const struct emul *target, int reg, int val) +{ + struct ltc2959_emul_data *data = target->data; + + switch (reg) { + case LTC2959_REG_ADC_CONTROL: + case LTC2959_REG_CC_CONTROL: + case LTC2959_REG_ACC_CHARGE_3: + case LTC2959_REG_ACC_CHARGE_2: + case LTC2959_REG_ACC_CHARGE_1: + case LTC2959_REG_ACC_CHARGE_0: + case LTC2959_REG_CHG_THRESH_LOW_3: + case LTC2959_REG_CHG_THRESH_LOW_2: + case LTC2959_REG_CHG_THRESH_LOW_1: + case LTC2959_REG_CHG_THRESH_LOW_0: + case LTC2959_REG_CHG_THRESH_HIGH_3: + case LTC2959_REG_CHG_THRESH_HIGH_2: + case LTC2959_REG_CHG_THRESH_HIGH_1: + case LTC2959_REG_CHG_THRESH_HIGH_0: + case LTC2959_REG_VOLT_THRESH_HIGH_MSB: + case LTC2959_REG_VOLT_THRESH_HIGH_LSB: + case LTC2959_REG_VOLT_THRESH_LOW_MSB: + case LTC2959_REG_VOLT_THRESH_LOW_LSB: + case LTC2959_REG_MAX_VOLTAGE_MSB: + case LTC2959_REG_MAX_VOLTAGE_LSB: + case LTC2959_REG_MIN_VOLTAGE_MSB: + case LTC2959_REG_MIN_VOLTAGE_LSB: + case LTC2959_REG_CURR_THRESH_HIGH_MSB: + case LTC2959_REG_CURR_THRESH_HIGH_LSB: + case LTC2959_REG_CURR_THRESH_LOW_MSB: + case LTC2959_REG_CURR_THRESH_LOW_LSB: + case LTC2959_REG_MAX_CURRENT_MSB: + case LTC2959_REG_MAX_CURRENT_LSB: + case LTC2959_REG_MIN_CURRENT_MSB: + case LTC2959_REG_MIN_CURRENT_LSB: + case LTC2959_REG_TEMP_THRESH_HIGH_MSB: + case LTC2959_REG_TEMP_THRESH_HIGH_LSB: + case LTC2959_REG_TEMP_THRESH_LOW_MSB: + case LTC2959_REG_TEMP_THRESH_LOW_LSB: + case LTC2959_REG_GPIO_THRESH_HIGH_MSB: + case LTC2959_REG_GPIO_THRESH_HIGH_LSB: + case LTC2959_REG_GPIO_THRESH_LOW_MSB: + case LTC2959_REG_GPIO_THRESH_LOW_LSB: + data->regs[reg] = val; + break; + + case LTC2959_REG_STATUS: + case LTC2959_REG_VOLTAGE_MSB: + case LTC2959_REG_VOLTAGE_LSB: + case LTC2959_REG_CURRENT_MSB: + case LTC2959_REG_CURRENT_LSB: + case LTC2959_REG_TEMP_MSB: + case LTC2959_REG_TEMP_LSB: + case LTC2959_REG_GPIO_VOLTAGE_MSB: + case LTC2959_REG_GPIO_VOLTAGE_LSB: + default: + LOG_ERR("Unknown or Read Only Register: 0x%x", reg); + return -EIO; + } + return 0; +} + +static int emul_ltc2959_reg_read(const struct emul *target, int reg, int *val) +{ + if (reg < LTC2959_REG_STATUS || reg > LTC2959_REG_GPIO_THRESH_LOW_LSB) { + LOG_ERR("Unknown Register: 0x%x", reg); + return -EIO; + } + + struct ltc2959_emul_data *data = target->data; + *val = data->regs[reg]; + + return 0; +} + +static int ltc2959_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, int num_msgs, + int addr) +{ + __ASSERT_NO_MSG(msgs && num_msgs); + i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false); + + switch (num_msgs) { + case 1: { + /* Single write: [reg, data0, data1, ...] */ + struct i2c_msg *m = &msgs[0]; + + if (m->flags & I2C_MSG_READ) { + LOG_ERR("Unexpected single-message read"); + return -EIO; + } + if (m->len < 2) { + LOG_ERR("Single-message write must be reg+data (len=%d)", m->len); + return -EIO; + } + uint8_t reg = m->buf[0]; + + for (size_t i = 1; i < m->len; i++, reg++) { + int ret = emul_ltc2959_reg_write(target, reg, m->buf[i]); + + if (ret < 0) { + return ret; + } + } + return 0; + } + + case 2: { + /* Two-message: [reg], then [read N] OR [write N] */ + struct i2c_msg *m0 = &msgs[0]; + struct i2c_msg *m1 = &msgs[1]; + + if ((m0->flags & I2C_MSG_READ) || m0->len != 1) { + LOG_ERR("Invalid first msg (flags=0x%x len=%d)", m0->flags, m0->len); + return -EIO; + } + + uint8_t reg = m0->buf[0]; + + if (m1->flags & I2C_MSG_READ) { + /* Burst READ: stream N bytes starting at reg */ + for (size_t i = 0; i < m1->len; i++) { + int val; + int ret = emul_ltc2959_reg_read(target, reg + i, &val); + + if (ret < 0) { + return ret; + } + + m1->buf[i] = (uint8_t)val; + } + return 0; + } + /* Burst WRITE: stream N bytes into reg..reg+N-1 */ + if (!m1->len) { + LOG_ERR("Empty write"); + return -EIO; + } + for (size_t i = 0; i < m1->len; i++) { + int ret = emul_ltc2959_reg_write(target, reg + i, m1->buf[i]); + + if (ret < 0) { + return ret; + } + } + return 0; + } + + default: + LOG_ERR("Unsupported number of I2C messages: %d", num_msgs); + return -EIO; + } +} + +/* The I2C emulator API required by Zephyr. */ +static const struct i2c_emul_api ltc2959_emul_api_i2c = { + .transfer = ltc2959_emul_transfer_i2c, +}; + +#ifdef CONFIG_ZTEST +#include + +/* Add test reset handlers in when using emulators with tests */ +#define LTC2959_EMUL_RESET_RULE_BEFORE(inst) ltc2959_emul_reset(EMUL_DT_GET(DT_DRV_INST(inst))); + +static void ltc2959_gauge_reset_rule_after(const struct ztest_unit_test *test, void *data) +{ + ARG_UNUSED(test); + ARG_UNUSED(data); + + DT_INST_FOREACH_STATUS_OKAY(LTC2959_EMUL_RESET_RULE_BEFORE) +} +ZTEST_RULE(ltc2959_gauge_reset, NULL, ltc2959_gauge_reset_rule_after); +#endif /* CONFIG_ZTEST */ + +static int ltc2959_emul_init(const struct emul *target, const struct device *parent) +{ + ARG_UNUSED(parent); + ltc2959_emul_reset(target); + return 0; +} + +/* + * Main instantiation macro. + */ +#define DEFINE_LTC2959_EMUL(n) \ + static struct ltc2959_emul_data ltc2959_emul_data_##n; \ + static const struct ltc2959_emul_cfg ltc2959_emul_cfg_##n = { \ + .addr = DT_INST_REG_ADDR(n), \ + }; \ + EMUL_DT_INST_DEFINE(n, ltc2959_emul_init, <c2959_emul_data_##n, <c2959_emul_cfg_##n, \ + <c2959_emul_api_i2c, NULL) + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_LTC2959_EMUL); diff --git a/drivers/fuel_gauge/ltc2959/ltc2959.c b/drivers/fuel_gauge/ltc2959/ltc2959.c new file mode 100644 index 0000000000000..6632c930e0225 --- /dev/null +++ b/drivers/fuel_gauge/ltc2959/ltc2959.c @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2025, Nathan Winslow + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ltc2959.h" + +#define DT_DRV_COMPAT adi_ltc2959 + +LOG_MODULE_REGISTER(LTC2959, CONFIG_FUEL_GAUGE_LOG_LEVEL); + +#define LTC2959_TEMP_K_SF (8250) +#define LTC2959_VOLT_UV_SF (955) /* µV per full-scale (16-bit) */ +#define LTC2959_GPIO_BIPOLAR_UV_SF (97500) +#define LTC2959_GPIO_UNIPOLAR_UV_SF (1560000) +#define LTC2959_VOLT_THRESH_UV_SCALAR (62600000) + +/* CONTROL Register Bit Masks */ +#define LTC2959_CTRL_ADC_MODE_MASK GENMASK(7, 5) +#define LTC2959_CTRL_GPIO_MODE_MASK GENMASK(4, 3) +#define LTC2959_CTRL_VIN_SEL_BIT BIT(2) +#define LTC2959_CTRL_RESERVED_MASK GENMASK(1, 0) + +#define LTC2959_CC_WRITABLE_MASK (BIT(7) | BIT(6) | BIT(3)) /* 0xC8 */ +#define LTC2959_CC_RESERVED_FIXED BIT(4) + +/* Used when ACR is controlled via firmware */ +#define LTC2959_ACR_CLR (0xFFFFFFFF) +/* ACR base (50 mΩ) LSB: 533 nAh = 0.533 µAh */ +#define LTC2959_ACR_UAH_NUM (533u) /* numerator (µAh) */ +#define LTC2959_ACR_UAH_DEN (1000u) /* denominator (—) */ +#define LTC2959_ACR_RSENSE_REF_MOHM (50u) + +/* Voltage source selection (bit 2 of Control Register) */ +#define LTC2959_VIN_VDD (0x0 << 2) +#define LTC2959_VIN_SENSEN (0x1 << 2) + +/* STATUS Register Bit Definitions (0x00) */ +enum ltc2959_status_flags { + LTC2959_STATUS_GPIO_ALERT = BIT(7), /* Default: 0 */ + LTC2959_STATUS_CURRENT_ALERT = BIT(6), /* Default: 0 */ + LTC2959_STATUS_CHARGE_OVER_UNDER = BIT(5), /* Default: 0 */ + LTC2959_STATUS_TEMP_ALERT = BIT(4), /* Default: 0 */ + LTC2959_STATUS_CHARGE_HIGH = BIT(3), /* Default: 0 */ + LTC2959_STATUS_CHARGE_LOW = BIT(2), /* Default: 0 */ + LTC2959_STATUS_VOLTAGE_ALERT = BIT(1), /* Default: 0 */ + LTC2959_STATUS_UVLO = BIT(0) /* Default: 1 */ +}; + +/* ADC mode values (bits 7:5 of CONTROL register 0x01) */ +enum ltc2959_adc_modes { + LTC2959_ADC_MODE_SLEEP = 0x00, + LTC2959_ADC_MODE_SMART_SLEEP = 0x20, + LTC2959_ADC_MODE_CONT_V = 0x40, + LTC2959_ADC_MODE_CONT_I = 0x60, + LTC2959_ADC_MODE_CONT_VI = 0x80, + LTC2959_ADC_MODE_SINGLE_SHOT = 0xA0, + LTC2959_ADC_MODE_CONT_VIT = 0xC0 /* recommended for full telemetry */ +}; + +/* GPIO mode bits (bits 4:3 of CONTROL register 0x01) */ +enum ltc2959_gpio_modes { + LTC2959_GPIO_MODE_ALERT = 0x00, + LTC2959_GPIO_MODE_CHGCOMP = 0x08, + LTC2959_GPIO_MODE_BIPOLAR = 0x10, + LTC2959_GPIO_MODE_UNIPOLAR = 0x18, +}; + +/* CC Control bits (CC register 0x02)*/ +enum ltc2959_cc_options { + LTC2959_CC_DEADBAND_0UV = (0b00 << 6), + LTC2959_CC_DEADBAND_20UV = (0b01 << 6), + LTC2959_CC_DEADBAND_40UV = (0b10 << 6), + LTC2959_CC_DEADBAND_80UV = (0b11 << 6), + LTC2959_CC_DO_NOT_COUNT = BIT(3), +}; + +struct ltc2959_config { + struct i2c_dt_spec i2c; + int32_t current_lsb_ua; + uint32_t rsense_milliohms; +}; + +static int ltc2959_read16(const struct device *dev, uint8_t reg, uint16_t *value) +{ + uint8_t buf[2]; + const struct ltc2959_config *cfg = dev->config; + int ret = i2c_burst_read_dt(&cfg->i2c, reg, buf, sizeof(buf)); + + if (ret < 0) { + LOG_ERR("Failed to read 16-bit register 0x%02X", reg); + return ret; + } + + *value = sys_get_be16(buf); + return 0; +} + +static int ltc2959_read32(const struct device *dev, uint8_t reg, uint32_t *value) +{ + uint8_t buf[4]; + const struct ltc2959_config *cfg = dev->config; + int ret = i2c_burst_read_dt(&cfg->i2c, reg, buf, sizeof(buf)); + + if (ret < 0) { + LOG_ERR("Failed to read 32-bit register 0x%02X", reg); + return ret; + } + + *value = sys_get_be32(buf); + return 0; +} + +static int ltc2959_get_adc_mode(const struct device *dev, uint8_t *mode) +{ + const struct ltc2959_config *cfg = dev->config; + + return i2c_reg_read_byte_dt(&cfg->i2c, LTC2959_REG_ADC_CONTROL, mode); +} + +static int ltc2959_set_adc_mode(const struct device *dev, uint8_t mode) +{ + const struct ltc2959_config *cfg = dev->config; + uint8_t ctrl; + int ret; + + if ((mode & ~(LTC2959_CTRL_ADC_MODE_MASK | LTC2959_CTRL_GPIO_MODE_MASK | + LTC2959_CTRL_VIN_SEL_BIT)) != 0U) { + return -EINVAL; + } + + ret = i2c_reg_read_byte_dt(&cfg->i2c, LTC2959_REG_ADC_CONTROL, &ctrl); + + if (ret < 0) { + return ret; + } + + ctrl &= ~(LTC2959_CTRL_ADC_MODE_MASK | LTC2959_CTRL_GPIO_MODE_MASK | + LTC2959_CTRL_VIN_SEL_BIT); + ctrl |= mode; + + ret = i2c_reg_write_byte_dt(&cfg->i2c, LTC2959_REG_ADC_CONTROL, ctrl); + + if (ret < 0) { + LOG_ERR("Failed to set ADC mode: 0x%02x (ctrl=0x%02x)", mode, ctrl); + return ret; + } + + return 0; +} + +static int ltc2959_get_cc_config(const struct device *dev, uint8_t *value) +{ + const struct ltc2959_config *cfg = dev->config; + + return i2c_reg_read_byte_dt(&cfg->i2c, LTC2959_REG_CC_CONTROL, value); +} + +static int ltc2959_set_cc_config(const struct device *dev, uint8_t value) +{ + const struct ltc2959_config *cfg = dev->config; + uint8_t mask = (value & LTC2959_CC_WRITABLE_MASK) | LTC2959_CC_RESERVED_FIXED; + + LOG_DBG("setting cc to: 0x%02X", mask); + return i2c_reg_write_byte_dt(&cfg->i2c, LTC2959_REG_CC_CONTROL, mask); +} + +static inline uint32_t u64_div_round_closest_u32_sat(uint64_t n, uint32_t d) +{ + /* round-to-nearest: (n + d/2) / d, with saturation to u32 */ + uint64_t q = (n + (uint64_t)(d / 2u)) / d; + + return (q > UINT32_MAX) ? UINT32_MAX : (uint32_t)q; +} + +static inline uint32_t ltc2959_counts_to_uah(uint32_t counts, const struct ltc2959_config *cfg) +{ + /* µAh = counts * 0.533µAh * (50 mΩ / r_sense) */ + uint64_t prod = (uint64_t)counts * (uint64_t)LTC2959_ACR_UAH_NUM * + (uint64_t)LTC2959_ACR_RSENSE_REF_MOHM; + uint32_t den = LTC2959_ACR_UAH_DEN * cfg->rsense_milliohms; + + return u64_div_round_closest_u32_sat(prod, den); +} + +static inline uint32_t ltc2959_uah_to_counts(uint32_t uah, const struct ltc2959_config *cfg) +{ + /* counts = µAh * (r_sense / 50 mΩ) * 1000 / 533 */ + uint64_t prod = + (uint64_t)uah * (uint64_t)LTC2959_ACR_UAH_DEN * (uint64_t)cfg->rsense_milliohms; + uint32_t den = LTC2959_ACR_UAH_NUM * LTC2959_ACR_RSENSE_REF_MOHM; + + return u64_div_round_closest_u32_sat(prod, den); +} + +static int ltc2959_read_acr(const struct device *dev, uint32_t *value) +{ + return ltc2959_read32(dev, LTC2959_REG_ACC_CHARGE_3, value); +} + +static int ltc2959_write_acr(const struct device *dev, uint32_t value) +{ + const struct ltc2959_config *cfg = dev->config; + uint8_t buf[4]; + + sys_put_be32(value, buf); + return i2c_burst_write_dt(&cfg->i2c, LTC2959_REG_ACC_CHARGE_3, buf, sizeof(buf)); +} + +static int ltc2959_get_gpio_voltage_uv(const struct device *dev, int32_t *value_uv) +{ + uint8_t ctrl; + uint16_t raw; + + int ret = ltc2959_get_adc_mode(dev, &ctrl); + + if (ret < 0) { + return ret; + } + + ret = ltc2959_read16(dev, LTC2959_REG_GPIO_VOLTAGE_MSB, &raw); + + if (ret < 0) { + return ret; + } + + int16_t raw_signed = (int16_t)raw; + uint8_t gpio_mode = ctrl & LTC2959_CTRL_GPIO_MODE_MASK; + + switch (gpio_mode) { + case LTC2959_GPIO_MODE_BIPOLAR: + *value_uv = ((int64_t)raw_signed * LTC2959_GPIO_BIPOLAR_UV_SF) >> 15; + break; + + case LTC2959_GPIO_MODE_UNIPOLAR: + *value_uv = + (int32_t)(((uint64_t)raw * (uint64_t)LTC2959_GPIO_UNIPOLAR_UV_SF) >> 15); + break; + + default: + LOG_ERR("Unsupported GPIO analog mode: 0x%x", gpio_mode); + return -EINVAL; + } + + return 0; +} + +static int ltc2959_get_gpio_threshold_uv(const struct device *dev, bool high, int32_t *value_uv) +{ + uint8_t reg = high ? LTC2959_REG_GPIO_THRESH_HIGH_MSB : LTC2959_REG_GPIO_THRESH_LOW_MSB; + const struct ltc2959_config *cfg = dev->config; + uint8_t ctrl; + + int ret = i2c_reg_read_byte_dt(&cfg->i2c, LTC2959_REG_ADC_CONTROL, &ctrl); + + if (ret < 0) { + LOG_ERR("NO CTRL: %i", ret); + return ret; + } + + uint16_t raw_th; + + ret = ltc2959_read16(dev, reg, &raw_th); + + if (ret < 0) { + return ret; + } + + int16_t raw_signed = (int16_t)raw_th; + uint8_t gpio_mode = ctrl & LTC2959_CTRL_GPIO_MODE_MASK; + + switch (gpio_mode) { + case LTC2959_GPIO_MODE_BIPOLAR: + *value_uv = ((int64_t)raw_signed * LTC2959_GPIO_BIPOLAR_UV_SF) >> 15; + break; + + case LTC2959_GPIO_MODE_UNIPOLAR: + *value_uv = + (int32_t)(((uint64_t)raw_th * (uint64_t)LTC2959_GPIO_UNIPOLAR_UV_SF) >> 15); + break; + + default: + LOG_ERR("Unsupported GPIO mode: 0x%x", gpio_mode); + return -ENOTSUP; + } + return 0; +} + +static int ltc2959_set_gpio_threshold_uv(const struct device *dev, bool high, int32_t value_uv) +{ + uint8_t reg = high ? LTC2959_REG_GPIO_THRESH_HIGH_MSB : LTC2959_REG_GPIO_THRESH_LOW_MSB; + + const struct ltc2959_config *cfg = dev->config; + + uint8_t ctrl; + int ret = i2c_reg_read_byte_dt(&cfg->i2c, LTC2959_REG_ADC_CONTROL, &ctrl); + + if (ret < 0) { + return ret; + } + + uint8_t gpio_mode = ctrl & LTC2959_CTRL_GPIO_MODE_MASK; + + switch (gpio_mode) { + case LTC2959_GPIO_MODE_BIPOLAR: { + int64_t raw_bp64 = ((int64_t)value_uv * 32768) / LTC2959_GPIO_BIPOLAR_UV_SF; + + if ((raw_bp64 < INT16_MIN) || (raw_bp64 > INT16_MAX)) { + return -ERANGE; + } + + uint16_t raw_bp = (uint16_t)((int16_t)raw_bp64); + uint8_t buf[2]; + + sys_put_be16(raw_bp, buf); + return i2c_burst_write_dt(&cfg->i2c, reg, buf, sizeof(buf)); + } + case LTC2959_GPIO_MODE_UNIPOLAR: { + + if (value_uv < 0) { + return -ERANGE; + } + + int64_t raw_up64 = ((int64_t)value_uv * 32768) / LTC2959_GPIO_UNIPOLAR_UV_SF; + + if ((raw_up64 < 0) || (raw_up64 > UINT16_MAX)) { + return -ERANGE; + } + + uint16_t raw_up = (uint16_t)raw_up64; + uint8_t buf[2]; + + sys_put_be16(raw_up, buf); + return i2c_burst_write_dt(&cfg->i2c, reg, buf, sizeof(buf)); + } + default: + break; + } + + LOG_ERR("Unsupported GPIO mode: 0x%02x", gpio_mode); + return -ENOTSUP; +} + +static int ltc2959_get_voltage_threshold_uv(const struct device *dev, bool high, uint32_t *value) +{ + uint8_t reg = high ? LTC2959_REG_VOLT_THRESH_HIGH_MSB : LTC2959_REG_VOLT_THRESH_LOW_MSB; + uint16_t raw; + int ret = ltc2959_read16(dev, reg, &raw); + + if (ret < 0) { + LOG_ERR("Failed to get voltage threshold: %i", ret); + return ret; + } + + *value = ((uint64_t)raw * LTC2959_VOLT_THRESH_UV_SCALAR) >> 15; + + return 0; +} + +static int ltc2959_set_voltage_threshold_uv(const struct device *dev, bool high, uint32_t value) +{ + uint8_t reg = high ? LTC2959_REG_VOLT_THRESH_HIGH_MSB : LTC2959_REG_VOLT_THRESH_LOW_MSB; + uint64_t raw64 = ((uint64_t)value << 15) / LTC2959_VOLT_THRESH_UV_SCALAR; + + if (raw64 > UINT16_MAX) { + return -ERANGE; + } + + uint16_t raw = (uint16_t)raw64; + + uint8_t buf[2]; + + sys_put_be16(raw, buf); + const struct ltc2959_config *cfg = dev->config; + + return i2c_burst_write_dt(&cfg->i2c, reg, buf, sizeof(buf)); +} + +static int ltc2959_get_current_threshold_ua(const struct device *dev, bool high, int32_t *value_ua) +{ + uint8_t reg = high ? LTC2959_REG_CURR_THRESH_HIGH_MSB : LTC2959_REG_CURR_THRESH_LOW_MSB; + + uint16_t raw_cth; + int ret = ltc2959_read16(dev, reg, &raw_cth); + + if (ret < 0) { + return ret; + } + + const struct ltc2959_config *cfg = dev->config; + int16_t signed_raw = (int16_t)raw_cth; + *value_ua = signed_raw * cfg->current_lsb_ua; + + return 0; +} + +static int ltc2959_set_current_threshold_ua(const struct device *dev, bool high, int32_t value_ua) +{ + uint8_t reg = high ? LTC2959_REG_CURR_THRESH_HIGH_MSB : LTC2959_REG_CURR_THRESH_LOW_MSB; + const struct ltc2959_config *cfg = dev->config; + + if (!cfg->current_lsb_ua) { + return -ERANGE; + } + + int32_t raw32 = value_ua / cfg->current_lsb_ua; + + /* To account for cases where current thresholds are +-2A */ + int16_t raw16 = CLAMP(raw32, INT16_MIN, INT16_MAX); + uint8_t buf[2]; + + sys_put_be16(raw16, buf); + return i2c_burst_write_dt(&cfg->i2c, reg, buf, sizeof(buf)); +} + +static int ltc2959_get_temp_threshold_dK(const struct device *dev, bool high, uint16_t *value_dK) +{ + uint8_t reg = high ? LTC2959_REG_TEMP_THRESH_HIGH_MSB : LTC2959_REG_TEMP_THRESH_LOW_MSB; + uint16_t raw_tth; + int ret = ltc2959_read16(dev, reg, &raw_tth); + + if (ret < 0) { + return ret; + } + + *value_dK = ((uint32_t)raw_tth * LTC2959_TEMP_K_SF) >> 16; + + return 0; +} + +static int ltc2959_set_temp_threshold_dK(const struct device *dev, bool high, uint16_t value_dK) +{ + uint8_t reg = high ? LTC2959_REG_TEMP_THRESH_HIGH_MSB : LTC2959_REG_TEMP_THRESH_LOW_MSB; + uint64_t raw64 = ((uint64_t)value_dK << 16) / LTC2959_TEMP_K_SF; + + if (raw64 > UINT16_MAX) { + return -ERANGE; + } + + uint16_t raw = (uint16_t)raw64; + uint8_t buf[2]; + + sys_put_be16(raw, buf); + const struct ltc2959_config *cfg = dev->config; + + return i2c_burst_write_dt(&cfg->i2c, reg, buf, sizeof(buf)); +} + +static int ltc2959_get_prop(const struct device *dev, fuel_gauge_prop_t prop, + union fuel_gauge_prop_val *val) +{ + const struct ltc2959_config *cfg = dev->config; + int ret; + + switch (prop) { + case FUEL_GAUGE_STATUS: + uint8_t raw_st; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, LTC2959_REG_STATUS, &raw_st); + + if (ret < 0) { + return ret; + } + + val->fg_status = raw_st; + + break; + + case FUEL_GAUGE_VOLTAGE: + uint16_t raw_voltage; + + ret = ltc2959_read16(dev, LTC2959_REG_VOLTAGE_MSB, &raw_voltage); + + if (ret < 0) { + return ret; + } + /** + * NOTE: LSB = 62.6V / 65536 = ~955 µV + * Zephyr's API expects this value in microvolts + * https://docs.zephyrproject.org/latest/doxygen/html/group__fuel__gauge__interface.html + */ + val->voltage = raw_voltage * LTC2959_VOLT_UV_SF; + + return 0; + + case FUEL_GAUGE_CURRENT: + uint16_t raw_current; + + ret = ltc2959_read16(dev, LTC2959_REG_CURRENT_MSB, &raw_current); + + if (ret < 0) { + return ret; + } + + /* Signed 16-bit value from ADC */ + int16_t current_raw = (int16_t)raw_current; + + val->current = current_raw * cfg->current_lsb_ua; + + break; + + case FUEL_GAUGE_TEMPERATURE: + uint16_t raw_temp; + + ret = ltc2959_read16(dev, LTC2959_REG_TEMP_MSB, &raw_temp); + + if (ret < 0) { + return ret; + } + /** + * NOTE: + * Temp is in deciKelvin as per API requirements. + * from the datasheet: + * T(°C) = 825 * (raw / 65536) - 273.15 + * T(dK) = 8250 * (raw / 65536) + * 65536 = 2 ^ 16, so we can avoid division altogether. + */ + val->temperature = ((uint32_t)raw_temp * LTC2959_TEMP_K_SF) >> 16; + break; + + case FUEL_GAUGE_REMAINING_CAPACITY: + uint32_t acr; + + ret = ltc2959_read_acr(dev, &acr); + + if (ret < 0) { + return ret; + } + + val->remaining_capacity = ltc2959_counts_to_uah(acr, cfg); + break; + + case FUEL_GAUGE_ADC_MODE: + ret = ltc2959_get_adc_mode(dev, &val->adc_mode); + break; + + case FUEL_GAUGE_HIGH_VOLTAGE_ALARM: + ret = ltc2959_get_voltage_threshold_uv(dev, true, &val->high_voltage_alarm); + break; + + case FUEL_GAUGE_LOW_VOLTAGE_ALARM: + ret = ltc2959_get_voltage_threshold_uv(dev, false, &val->low_voltage_alarm); + break; + + case FUEL_GAUGE_HIGH_CURRENT_ALARM: + ret = ltc2959_get_current_threshold_ua(dev, true, &val->high_current_alarm); + break; + + case FUEL_GAUGE_LOW_CURRENT_ALARM: + ret = ltc2959_get_current_threshold_ua(dev, false, &val->low_current_alarm); + break; + + case FUEL_GAUGE_HIGH_TEMPERATURE_ALARM: + ret = ltc2959_get_temp_threshold_dK(dev, true, &val->high_temperature_alarm); + break; + + case FUEL_GAUGE_LOW_TEMPERATURE_ALARM: + ret = ltc2959_get_temp_threshold_dK(dev, false, &val->low_temperature_alarm); + break; + + case FUEL_GAUGE_GPIO_VOLTAGE: + ret = ltc2959_get_gpio_voltage_uv(dev, &val->gpio_voltage); + break; + + case FUEL_GAUGE_HIGH_GPIO_ALARM: + ret = ltc2959_get_gpio_threshold_uv(dev, true, &val->high_gpio_alarm); + break; + + case FUEL_GAUGE_LOW_GPIO_ALARM: + ret = ltc2959_get_gpio_threshold_uv(dev, false, &val->low_gpio_alarm); + break; + + case FUEL_GAUGE_CC_CONFIG: + ret = ltc2959_get_cc_config(dev, &val->cc_config); + break; + + default: + return -ENOTSUP; + } + return ret; +} + +static int ltc2959_set_prop(const struct device *dev, fuel_gauge_prop_t prop, + union fuel_gauge_prop_val val) +{ + int ret = 0; + const struct ltc2959_config *cfg = dev->config; + + switch (prop) { + case FUEL_GAUGE_ADC_MODE: + ret = ltc2959_set_adc_mode(dev, val.adc_mode); + break; + + case FUEL_GAUGE_LOW_VOLTAGE_ALARM: + ret = ltc2959_set_voltage_threshold_uv(dev, false, val.low_voltage_alarm); + break; + + case FUEL_GAUGE_HIGH_VOLTAGE_ALARM: + ret = ltc2959_set_voltage_threshold_uv(dev, true, val.high_voltage_alarm); + break; + + case FUEL_GAUGE_LOW_CURRENT_ALARM: + ret = ltc2959_set_current_threshold_ua(dev, false, val.low_current_alarm); + break; + + case FUEL_GAUGE_HIGH_CURRENT_ALARM: + ret = ltc2959_set_current_threshold_ua(dev, true, val.high_current_alarm); + break; + + case FUEL_GAUGE_LOW_TEMPERATURE_ALARM: + ret = ltc2959_set_temp_threshold_dK(dev, false, val.low_temperature_alarm); + break; + + case FUEL_GAUGE_HIGH_TEMPERATURE_ALARM: + ret = ltc2959_set_temp_threshold_dK(dev, true, val.high_temperature_alarm); + break; + + case FUEL_GAUGE_LOW_GPIO_ALARM: + ret = ltc2959_set_gpio_threshold_uv(dev, false, val.low_gpio_alarm); + break; + + case FUEL_GAUGE_HIGH_GPIO_ALARM: + ret = ltc2959_set_gpio_threshold_uv(dev, true, val.high_gpio_alarm); + break; + + case FUEL_GAUGE_CC_CONFIG: + LOG_DBG("config stats: 0x%02X", val.cc_config); + ret = ltc2959_set_cc_config(dev, val.cc_config); + break; + + case FUEL_GAUGE_REMAINING_CAPACITY: + uint32_t counts = ltc2959_uah_to_counts(val.remaining_capacity, cfg); + + if (counts == LTC2959_ACR_CLR) { + counts = LTC2959_ACR_CLR - 1; + } + ret = ltc2959_write_acr(dev, counts); + break; + + default: + ret = -ENOTSUP; + break; + } + return ret; +} + +static int ltc2959_init(const struct device *dev) +{ + const struct ltc2959_config *cfg = dev->config; + + if (!device_is_ready(cfg->i2c.bus)) { + LOG_ERR("I2C bus not ready"); + return -ENODEV; + } + + return 0; +} + +static DEVICE_API(fuel_gauge, ltc2959_driver_api) = { + .get_property = <c2959_get_prop, + .set_property = <c2959_set_prop, +}; + +#define LTC2959_DEFINE(inst) \ + BUILD_ASSERT(DT_NODE_HAS_PROP(DT_DRV_INST(inst), rsense_milliohms)); \ + BUILD_ASSERT(DT_INST_PROP(inst, rsense_milliohms) > 0); \ + static const struct ltc2959_config ltc2959_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .current_lsb_ua = (97500000 / (DT_INST_PROP(inst, rsense_milliohms) * 32768)), \ + .rsense_milliohms = DT_INST_PROP(inst, rsense_milliohms), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, ltc2959_init, NULL, NULL, <c2959_config_##inst, POST_KERNEL, \ + CONFIG_FUEL_GAUGE_INIT_PRIORITY, <c2959_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(LTC2959_DEFINE) diff --git a/drivers/fuel_gauge/ltc2959/ltc2959.h b/drivers/fuel_gauge/ltc2959/ltc2959.h new file mode 100644 index 0000000000000..09b78159d2e90 --- /dev/null +++ b/drivers/fuel_gauge/ltc2959/ltc2959.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025, Nathan Winslow + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_FUELGAUGE_LTC2959_GAUGE_H_ +#define ZEPHYR_DRIVERS_FUELGAUGE_LTC2959_GAUGE_H_ + +#include +#include + +enum ltc2959_regs { + /* Status and Control */ + LTC2959_REG_STATUS = 0x00, + LTC2959_REG_ADC_CONTROL = 0x01, + LTC2959_REG_CC_CONTROL = 0x02, + + /* Accumulated Charge (uint32_t) */ + LTC2959_REG_ACC_CHARGE_3 = 0x03, + LTC2959_REG_ACC_CHARGE_2 = 0x04, + LTC2959_REG_ACC_CHARGE_1 = 0x05, + LTC2959_REG_ACC_CHARGE_0 = 0x06, + + /* Charge Thresholds (Low and High, uint32_t each) */ + LTC2959_REG_CHG_THRESH_LOW_3 = 0x07, + LTC2959_REG_CHG_THRESH_LOW_2 = 0x08, + LTC2959_REG_CHG_THRESH_LOW_1 = 0x09, + LTC2959_REG_CHG_THRESH_LOW_0 = 0x0A, + LTC2959_REG_CHG_THRESH_HIGH_3 = 0x0B, + LTC2959_REG_CHG_THRESH_HIGH_2 = 0x0C, + LTC2959_REG_CHG_THRESH_HIGH_1 = 0x0D, + LTC2959_REG_CHG_THRESH_HIGH_0 = 0x0E, + + /* Voltage (uint16_t) */ + LTC2959_REG_VOLTAGE_MSB = 0x0F, + LTC2959_REG_VOLTAGE_LSB = 0x10, + LTC2959_REG_VOLT_THRESH_HIGH_MSB = 0x11, + LTC2959_REG_VOLT_THRESH_HIGH_LSB = 0x12, + LTC2959_REG_VOLT_THRESH_LOW_MSB = 0x13, + LTC2959_REG_VOLT_THRESH_LOW_LSB = 0x14, + LTC2959_REG_MAX_VOLTAGE_MSB = 0x15, + LTC2959_REG_MAX_VOLTAGE_LSB = 0x16, + LTC2959_REG_MIN_VOLTAGE_MSB = 0x17, + LTC2959_REG_MIN_VOLTAGE_LSB = 0x18, + + /* Current (int16_t) */ + LTC2959_REG_CURRENT_MSB = 0x19, + LTC2959_REG_CURRENT_LSB = 0x1A, + LTC2959_REG_CURR_THRESH_HIGH_MSB = 0x1B, + LTC2959_REG_CURR_THRESH_HIGH_LSB = 0x1C, + LTC2959_REG_CURR_THRESH_LOW_MSB = 0x1D, + LTC2959_REG_CURR_THRESH_LOW_LSB = 0x1E, + LTC2959_REG_MAX_CURRENT_MSB = 0x1F, + LTC2959_REG_MAX_CURRENT_LSB = 0x20, + LTC2959_REG_MIN_CURRENT_MSB = 0x21, + LTC2959_REG_MIN_CURRENT_LSB = 0x22, + + /* Temperature (uint16_t) */ + LTC2959_REG_TEMP_MSB = 0x23, + LTC2959_REG_TEMP_LSB = 0x24, + LTC2959_REG_TEMP_THRESH_HIGH_MSB = 0x25, + LTC2959_REG_TEMP_THRESH_HIGH_LSB = 0x26, + LTC2959_REG_TEMP_THRESH_LOW_MSB = 0x27, + LTC2959_REG_TEMP_THRESH_LOW_LSB = 0x28, + + /* GPIO */ + LTC2959_REG_GPIO_VOLTAGE_MSB = 0x29, + LTC2959_REG_GPIO_VOLTAGE_LSB = 0x2A, + LTC2959_REG_GPIO_THRESH_HIGH_MSB = 0x2B, + LTC2959_REG_GPIO_THRESH_HIGH_LSB = 0x2C, + LTC2959_REG_GPIO_THRESH_LOW_MSB = 0x2D, + LTC2959_REG_GPIO_THRESH_LOW_LSB = 0x2E, +}; + +#endif /* END ZEPHYR_DRIVERS_FUELGAUGE_LTC2959_GAUGE_H_ */ diff --git a/dts/bindings/fuel-gauge/adi,ltc2959.yaml b/dts/bindings/fuel-gauge/adi,ltc2959.yaml new file mode 100644 index 0000000000000..61f3e3cc80848 --- /dev/null +++ b/dts/bindings/fuel-gauge/adi,ltc2959.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Nathan Winslow +# SPDX-License-Identifier: Apache-2.0 + +description: | + Analog Devices LTC2959 ultra-low-power battery fuel gauge. + +compatible: "adi,ltc2959" + +include: [base.yaml, i2c-device.yaml, fuel-gauge.yaml] + +properties: + reg: + required: true + + rsense-milliohms: + type: int + required: true + description: | + Sensor resistor value in milliohms. Connected to SENSEP or SENSEN on the IC. + NOTE: The datasheet uses a default value of 50 milliOhm diff --git a/include/zephyr/drivers/fuel_gauge.h b/include/zephyr/drivers/fuel_gauge.h index 9dee971c4df06..fb95d2a116b10 100644 --- a/include/zephyr/drivers/fuel_gauge.h +++ b/include/zephyr/drivers/fuel_gauge.h @@ -111,6 +111,26 @@ enum fuel_gauge_prop_type { FUEL_GAUGE_STATE_OF_CHARGE_ALARM, /** Low Cell Voltage Alarm (uV)*/ FUEL_GAUGE_LOW_VOLTAGE_ALARM, + /** High Cell Voltage Alarm (uV)*/ + FUEL_GAUGE_HIGH_VOLTAGE_ALARM, + /** Low Cell Current Alarm (uA)*/ + FUEL_GAUGE_LOW_CURRENT_ALARM, + /** High Cell Current Alarm (uA)*/ + FUEL_GAUGE_HIGH_CURRENT_ALARM, + /** Low Cell Temperature Alarm (dK)*/ + FUEL_GAUGE_LOW_TEMPERATURE_ALARM, + /** High Cell Temperature Alarm (dK)*/ + FUEL_GAUGE_HIGH_TEMPERATURE_ALARM, + /** Low GPIO Voltage Alarm (uV)*/ + FUEL_GAUGE_LOW_GPIO_ALARM, + /** High GPIO Voltage Alarm (uV)*/ + FUEL_GAUGE_HIGH_GPIO_ALARM, + /** GPIO Voltage (uV)*/ + FUEL_GAUGE_GPIO_VOLTAGE, + /** ADC Mode (flags) */ + FUEL_GAUGE_ADC_MODE, + /** Coulomb Counter Config (flags)*/ + FUEL_GAUGE_CC_CONFIG, /** Reserved to demark end of common fuel gauge properties */ FUEL_GAUGE_COMMON_COUNT, @@ -195,6 +215,26 @@ union fuel_gauge_prop_val { uint8_t state_of_charge_alarm; /** FUEL_GAUGE_LOW_VOLTAGE_ALARM */ uint32_t low_voltage_alarm; + /** FUEL_GAUGE_HIGH_VOLTAGE_ALARM */ + uint32_t high_voltage_alarm; + /** FUEL_GAUGE_LOW_CURRENT_ALARM */ + int32_t low_current_alarm; + /** FUEL_GAUGE_HIGH_CURRENT_ALARM */ + int32_t high_current_alarm; + /** FUEL_GAUGE_LOW_TEMPERATURE_ALARM */ + uint16_t low_temperature_alarm; + /** FUEL_GAUGE_HIGH_TEMPERATURE_ALARM */ + uint16_t high_temperature_alarm; + /** FUEL_GAUGE_GPIO_VOLTAGE*/ + int32_t gpio_voltage; + /** FUEL_GAUGE_LOW_GPIO_ALARM */ + int32_t low_gpio_alarm; + /** FUEL_GAUGE_HIGH_GPIO_ALARM */ + int32_t high_gpio_alarm; + /** FUEL_GAUGE_ADC_MODE */ + uint8_t adc_mode; + /** FUEL_GAUGE_CC_CONFIG */ + uint8_t cc_config; }; /** From 81e16c0974c14c2707a0bd17cfb39527016582b4 Mon Sep 17 00:00:00 2001 From: Nathan Winslow Date: Thu, 31 Jul 2025 12:01:38 -0400 Subject: [PATCH 350/397] drivers: fuelgauge: Added test for ADI LTC2959 Adds test and native sim support for ADI LTC2959 fuel gauge. Signed-off-by: Nathan Winslow --- .../drivers/fuel_gauge/ltc2959/CMakeLists.txt | 8 + .../fuel_gauge/ltc2959/boards/native_sim.conf | 3 + .../ltc2959/boards/native_sim.overlay | 13 + tests/drivers/fuel_gauge/ltc2959/prj.conf | 7 + .../fuel_gauge/ltc2959/src/test_ltc2959.c | 287 ++++++++++++++++++ .../drivers/fuel_gauge/ltc2959/testcase.yaml | 7 + 6 files changed, 325 insertions(+) create mode 100644 tests/drivers/fuel_gauge/ltc2959/CMakeLists.txt create mode 100644 tests/drivers/fuel_gauge/ltc2959/boards/native_sim.conf create mode 100644 tests/drivers/fuel_gauge/ltc2959/boards/native_sim.overlay create mode 100644 tests/drivers/fuel_gauge/ltc2959/prj.conf create mode 100644 tests/drivers/fuel_gauge/ltc2959/src/test_ltc2959.c create mode 100644 tests/drivers/fuel_gauge/ltc2959/testcase.yaml diff --git a/tests/drivers/fuel_gauge/ltc2959/CMakeLists.txt b/tests/drivers/fuel_gauge/ltc2959/CMakeLists.txt new file mode 100644 index 0000000000000..afc875718de71 --- /dev/null +++ b/tests/drivers/fuel_gauge/ltc2959/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(device) + +target_sources(app PRIVATE src/test_ltc2959.c) diff --git a/tests/drivers/fuel_gauge/ltc2959/boards/native_sim.conf b/tests/drivers/fuel_gauge/ltc2959/boards/native_sim.conf new file mode 100644 index 0000000000000..022a71dd0f0a6 --- /dev/null +++ b/tests/drivers/fuel_gauge/ltc2959/boards/native_sim.conf @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_EMUL=y diff --git a/tests/drivers/fuel_gauge/ltc2959/boards/native_sim.overlay b/tests/drivers/fuel_gauge/ltc2959/boards/native_sim.overlay new file mode 100644 index 0000000000000..3a3511ee5bc74 --- /dev/null +++ b/tests/drivers/fuel_gauge/ltc2959/boards/native_sim.overlay @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors + */ + +&i2c0 { + ltc2959: ltc2959@63 { + compatible = "adi,ltc2959"; + reg = <0x63>; + rsense-milliohms = <50>; + status = "okay"; + }; +}; diff --git a/tests/drivers/fuel_gauge/ltc2959/prj.conf b/tests/drivers/fuel_gauge/ltc2959/prj.conf new file mode 100644 index 0000000000000..824ffaf7142a3 --- /dev/null +++ b/tests/drivers/fuel_gauge/ltc2959/prj.conf @@ -0,0 +1,7 @@ +CONFIG_ZTEST=y +CONFIG_I2C=y +CONFIG_TEST_USERSPACE=y +CONFIG_LOG=y + +CONFIG_FUEL_GAUGE=y +CONFIG_FUEL_GAUGE_LTC2959=y diff --git a/tests/drivers/fuel_gauge/ltc2959/src/test_ltc2959.c b/tests/drivers/fuel_gauge/ltc2959/src/test_ltc2959.c new file mode 100644 index 0000000000000..49f9aed79169b --- /dev/null +++ b/tests/drivers/fuel_gauge/ltc2959/src/test_ltc2959.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2025 Nathan Winslow + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define LTC_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(adi_ltc2959) +BUILD_ASSERT(DT_NODE_EXISTS(LTC_NODE), "No adi,ltc2959 node in DT for tests"); + +#define RSENSE_MOHMS DT_PROP(LTC_NODE, rsense_milliohms) + +/* Integer LSB sizes (keep tests stable) */ +#define CURRENT_LSB_UA (97500000ULL / ((uint64_t)RSENSE_MOHMS * 32768ULL)) +#define VOLTAGE_MAX_UV (UINT16_MAX * 955U) /* ~955 = 62.6V full scale / 65536 */ + +struct ltc2959_fixture { + const struct device *dev; + const struct fuel_gauge_driver_api *api; +}; + +static void *ltc2959_setup(void) +{ + static ZTEST_DMEM struct ltc2959_fixture fixture; + + fixture.dev = DEVICE_DT_GET_ANY(adi_ltc2959); + k_object_access_all_grant(fixture.dev); + + zassume_true(device_is_ready(fixture.dev), "Fuel Gauge not found"); + + return &fixture; +} + +LOG_MODULE_REGISTER(test_ltc2959, LOG_LEVEL_INF); + +ZTEST_F(ltc2959, test_get_props__returns_ok) +{ + fuel_gauge_prop_t props[] = { + FUEL_GAUGE_STATUS, + FUEL_GAUGE_VOLTAGE, + FUEL_GAUGE_CURRENT, + FUEL_GAUGE_TEMPERATURE, + }; + + union fuel_gauge_prop_val vals[ARRAY_SIZE(props)]; + int ret = fuel_gauge_get_props(fixture->dev, props, vals, ARRAY_SIZE(props)); + +#if CONFIG_EMUL + zassert_equal(vals[0].fg_status, 0x01); + zassert_equal(vals[1].voltage, 0x00); + zassert_equal(vals[2].current, 0x00); + zassert_equal(vals[3].temperature, 0x00); +#else + zassert_between_inclusive(vals[0].fg_status, 0, 0xFF); + zassert_between_inclusive(vals[1].voltage, 0, VOLTAGE_MAX_UV); +#endif + zassert_equal(ret, 0, "Getting bad property has a good status."); +} + +ZTEST_F(ltc2959, test_set_get_single_prop) +{ + int ret; + union fuel_gauge_prop_val in = {.low_voltage_alarm = 1200000}; /* 1.2V */ + + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_LOW_VOLTAGE_ALARM, in); + zassert_equal(ret, 0, "set low voltage threshold failed"); + + union fuel_gauge_prop_val out; + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_LOW_VOLTAGE_ALARM, &out); + zassert_equal(ret, 0, "get low voltage threshold failed"); + + /* Allow for register quantization: one LSB ≈ 1.91 mV */ + const int32_t lsb_uv = 62600000 / 32768; /* integer ≈ 1910 */ + int32_t diff = (int32_t)out.low_voltage_alarm - (int32_t)in.low_voltage_alarm; + + zassert_true(diff <= lsb_uv && diff >= -lsb_uv, + "Set/get mismatch: in=%d, out=%d, diff=%d > LSB=%d", (int)in.low_voltage_alarm, + (int)out.low_voltage_alarm, (int)(diff), (int)lsb_uv); + + LOG_INF("in=%d, out=%d, diff=%d > LSB=%d", (int)in.low_voltage_alarm, + (int)out.low_voltage_alarm, (int)(diff), (int)lsb_uv); +} + +ZTEST_F(ltc2959, test_current_threshold_roundtrip) +{ + int ret; + union fuel_gauge_prop_val in, out; + int32_t tol = CURRENT_LSB_UA ? (int32_t)CURRENT_LSB_UA : 100; + + in.high_current_alarm = 123456; /* µA */ + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_HIGH_CURRENT_ALARM, in); + zassert_equal(ret, 0, "set current high threshold failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_HIGH_CURRENT_ALARM, &out); + zassert_equal(ret, 0, "get current high threshold failed (%d)", ret); + + int32_t diff = out.high_current_alarm - in.high_current_alarm; + + if (diff < 0) { + diff = -diff; + } + + zassert_true(diff <= tol, "current high threshold mismatch: in=%d out=%d diff=%d tol=%d", + (int)in.high_current_alarm, (int)out.high_current_alarm, (int)diff, (int)tol); + + in.low_current_alarm = -78901; /* µA */ + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_LOW_CURRENT_ALARM, in); + zassert_equal(ret, 0, "set current low threshold failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_LOW_CURRENT_ALARM, &out); + zassert_equal(ret, 0, "get current low threshold failed (%d)", ret); + + diff = out.low_current_alarm - in.low_current_alarm; + + if (diff < 0) { + diff = -diff; + } + + zassert_true(diff <= tol, "current low threshold mismatch: in=%d out=%d diff=%d tol=%d", + (int)in.low_current_alarm, (int)out.low_current_alarm, (int)diff, (int)tol); +} + +ZTEST_F(ltc2959, test_temperature_threshold_roundtrip) +{ + int ret; + union fuel_gauge_prop_val in; + union fuel_gauge_prop_val out; + + in.low_temperature_alarm = 3000; + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_LOW_TEMPERATURE_ALARM, in); + zassert_equal(ret, 0, "set temp low threshold failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_LOW_TEMPERATURE_ALARM, &out); + zassert_equal(ret, 0, "get temp low threshold failed (%d)", ret); + int32_t diff = (int32_t)out.low_temperature_alarm - (int32_t)in.low_temperature_alarm; + + if (diff < 0) { + diff = -diff; + } + + zassert_true(diff <= 1, "temp low threshold mismatch: in=%u out=%u diff=%d", + in.low_temperature_alarm, out.low_temperature_alarm, (int)diff); + + in.high_temperature_alarm = 3500; + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_HIGH_TEMPERATURE_ALARM, in); + zassert_equal(ret, 0, "set temp high threshold failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_HIGH_TEMPERATURE_ALARM, &out); + zassert_equal(ret, 0, "get temp high threshold failed (%d)", ret); + diff = (int32_t)out.high_temperature_alarm - (int32_t)in.high_temperature_alarm; + + if (diff < 0) { + diff = -diff; + } + + zassert_true(diff <= 1, "temp high threshold mismatch: in=%u out=%u diff=%d", + in.high_temperature_alarm, out.high_temperature_alarm, (int)diff); +} + +ZTEST_F(ltc2959, test_adc_mode_roundtrip) +{ + int ret; + union fuel_gauge_prop_val in, out; + + in.adc_mode = 0xC0 | 0x10; /* CONT_VIT + GPIO BIPOLAR */ + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_ADC_MODE, in); + zassert_equal(ret, 0, "set ADC_MODE failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_ADC_MODE, &out); + zassert_equal(ret, 0, "get ADC_MODE failed (%d)", ret); + zassert_equal(out.adc_mode, in.adc_mode, "ADC_MODE mismatch (got 0x%02x)", out.adc_mode); +} + +ZTEST_F(ltc2959, test_remaining_capacity_roundtrip) +{ + int ret; + union fuel_gauge_prop_val in, out; + + in.remaining_capacity = 1234567; /* µAh */ + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_REMAINING_CAPACITY, in); + zassert_equal(ret, 0, "set ACR failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_REMAINING_CAPACITY, &out); + zassert_equal(ret, 0, "get ACR failed (%d)", ret); + + int32_t diff = (int32_t)out.remaining_capacity - (int32_t)in.remaining_capacity; + + if (diff < 0) { + diff = -diff; + } + + zassert_true(diff <= 1, "ACR mismatch: in=%d out=%d diff=%d tol=1", + (int)in.remaining_capacity, (int)out.remaining_capacity, (int)diff); +} + +ZTEST_F(ltc2959, test_remaining_capacity_reserved_guard) +{ + int ret; + union fuel_gauge_prop_val in, out; + + /* 0xFFFFFFFF counts ≈ 2,289,000,000 µAh (533 nAh/LSB) */ + in.remaining_capacity = 2289000000U; + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_REMAINING_CAPACITY, in); + zassert_equal(ret, 0, "set ACR near fullscale failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_REMAINING_CAPACITY, &out); + zassert_equal(ret, 0, "get ACR near fullscale failed (%d)", ret); + + /* We expect the driver to write 0xFFFFFFFE instead, so out <= in and close */ + zassert_true(out.remaining_capacity <= in.remaining_capacity, + "ACR guard failed: got larger than requested"); + int32_t diff = (int32_t)in.remaining_capacity - (int32_t)out.remaining_capacity; + + if (diff < 0) { + diff = -diff; + } + + zassert_true(diff <= 1, "ACR guard too lossy: in=%d out=%d |diff|=%d", + (int)in.remaining_capacity, (int)out.remaining_capacity, (int)diff); +} + +ZTEST_F(ltc2959, test_cc_config_sanitized) +{ + int ret; + union fuel_gauge_prop_val in, out; + + in.cc_config = 0xFF; /* try to set everything */ + ret = fuel_gauge_set_prop(fixture->dev, FUEL_GAUGE_CC_CONFIG, in); + zassert_equal(ret, 0, "set cc_config failed (%d)", ret); + + ret = fuel_gauge_get_prop(fixture->dev, FUEL_GAUGE_CC_CONFIG, &out); + zassert_equal(ret, 0, "get cc_config failed (%d)", ret); + + /* Expect bits 7,6,3 kept; bit 4 forced; others cleared => 0xD8 */ + zassert_equal(out.cc_config, 0xD8, "cc_config not sanitized (got 0x%02X)", out.cc_config); +} + +ZTEST_USER_F(ltc2959, test_get_some_props_failed__returns_bad_status) +{ + fuel_gauge_prop_t props[] = { + /* First invalid property */ + FUEL_GAUGE_PROP_MAX, + /* Second invalid property */ + FUEL_GAUGE_PROP_MAX, + /* Valid property */ + FUEL_GAUGE_VOLTAGE, + }; + union fuel_gauge_prop_val vals[ARRAY_SIZE(props)]; + + int ret = fuel_gauge_get_props(fixture->dev, props, vals, ARRAY_SIZE(props)); + + zassert_equal(ret, -ENOTSUP, "Getting bad property has a good status."); +} + +ZTEST_F(ltc2959, test_set_some_props_failed__returns_err) +{ + fuel_gauge_prop_t prop_types[] = { + /* First invalid property */ + FUEL_GAUGE_PROP_MAX, + /* Second invalid property */ + FUEL_GAUGE_PROP_MAX, + /* Valid property */ + FUEL_GAUGE_LOW_VOLTAGE_ALARM, + }; + + union fuel_gauge_prop_val props[] = { + /* First invalid property */ + {0}, + /* Second invalid property */ + {0}, + /* Valid property */ + {.voltage = 0}, + }; + + int ret = fuel_gauge_set_props(fixture->dev, prop_types, props, ARRAY_SIZE(props)); + + zassert_equal(ret, -ENOTSUP); +} + +ZTEST_SUITE(ltc2959, NULL, ltc2959_setup, NULL, NULL, NULL); diff --git a/tests/drivers/fuel_gauge/ltc2959/testcase.yaml b/tests/drivers/fuel_gauge/ltc2959/testcase.yaml new file mode 100644 index 0000000000000..1f359bb1e893c --- /dev/null +++ b/tests/drivers/fuel_gauge/ltc2959/testcase.yaml @@ -0,0 +1,7 @@ +tests: + drivers.fuel_gauge.ltc2959: + tags: + - fuel_gauge + filter: dt_compat_enabled("adi,ltc2959") + platform_allow: + - native_sim From 19d95bcbd8bb7a01b7351b74f2e54f10938b9c23 Mon Sep 17 00:00:00 2001 From: S Mohamed Fiaz Date: Tue, 12 Aug 2025 18:01:13 +0530 Subject: [PATCH 351/397] driver: dma: dma_silabs_siwx91x: Add pm policy state support for dma driver This commit enables the pm policy state lock support for the dma_silabs_siwx91x driver. Signed-off-by: S Mohamed Fiaz --- drivers/dma/dma_silabs_siwx91x.c | 88 ++++++++++++++++++++++++++------ dts/arm/silabs/siwg917.dtsi | 4 ++ 2 files changed, 75 insertions(+), 17 deletions(-) diff --git a/drivers/dma/dma_silabs_siwx91x.c b/drivers/dma/dma_silabs_siwx91x.c index 7cd1290d336c0..21b06bc598158 100644 --- a/drivers/dma/dma_silabs_siwx91x.c +++ b/drivers/dma/dma_silabs_siwx91x.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include "rsi_rom_udma.h" #include "rsi_rom_udma_wrapper.h" @@ -39,6 +41,7 @@ struct dma_siwx91x_channel_info { void *cb_data; /* User callback data */ RSI_UDMA_DESC_T *sg_desc_addr_info; /* Scatter-Gather table start address */ enum dma_xfer_dir xfer_direction; /* mem<->mem ot per<->mem */ + bool channel_active; /* Channel active flag */ }; struct dma_siwx91x_config { @@ -60,6 +63,16 @@ struct dma_siwx91x_data { */ }; +static void siwx91x_dma_pm_policy_state_lock_get(void) +{ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); +} + +static void siwx91x_dma_pm_policy_state_lock_put(void) +{ + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); +} + static enum dma_xfer_dir siwx91x_transfer_direction(uint32_t dir) { if (dir == MEMORY_TO_MEMORY) { @@ -482,7 +495,17 @@ static int siwx91x_dma_start(const struct device *dev, uint32_t channel) return -EINVAL; } + /* Get the power management policy state lock */ + if (!data->zephyr_channel_info[channel].channel_active) { + siwx91x_dma_pm_policy_state_lock_get(); + data->zephyr_channel_info[channel].channel_active = true; + } + if (RSI_UDMA_ChannelEnable(udma_handle, channel) != 0) { + if (data->zephyr_channel_info[channel].channel_active) { + siwx91x_dma_pm_policy_state_lock_put(); + data->zephyr_channel_info[channel].channel_active = false; + } return -EINVAL; } @@ -510,6 +533,11 @@ static int siwx91x_dma_stop(const struct device *dev, uint32_t channel) return -EIO; } + if (data->zephyr_channel_info[channel].channel_active) { + siwx91x_dma_pm_policy_state_lock_put(); + data->zephyr_channel_info[channel].channel_active = false; + } + return 0; } @@ -560,8 +588,7 @@ bool siwx91x_dma_chan_filter(const struct device *dev, int channel, void *filter } } -/* Function to initialize DMA peripheral */ -static int siwx91x_dma_init(const struct device *dev) +static int dma_siwx91x_pm_action(const struct device *dev, enum pm_device_action action) { const struct dma_siwx91x_config *cfg = dev->config; struct dma_siwx91x_data *data = dev->data; @@ -573,25 +600,45 @@ static int siwx91x_dma_init(const struct device *dev) }; int ret; - ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys); - if (ret) { - return ret; - } + switch (action) { + case PM_DEVICE_ACTION_RESUME: + break; + case PM_DEVICE_ACTION_SUSPEND: + break; + case PM_DEVICE_ACTION_TURN_ON: + ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys); + if (ret < 0 && ret != -EALREADY) { + return ret; + } - udma_handle = UDMAx_Initialize(&udma_resources, udma_resources.desc, NULL, - (uint32_t *)&data->udma_handle); - if (udma_handle != &data->udma_handle) { - return -EINVAL; + udma_handle = UDMAx_Initialize(&udma_resources, udma_resources.desc, NULL, + (uint32_t *)&data->udma_handle); + if (udma_handle != &data->udma_handle) { + return -EINVAL; + } + + if (UDMAx_DMAEnable(&udma_resources, udma_handle) != 0) { + return -EBUSY; + } + break; + case PM_DEVICE_ACTION_TURN_OFF: + break; + default: + return -ENOTSUP; } + return 0; +} + +/* Function to initialize DMA peripheral */ +static int siwx91x_dma_init(const struct device *dev) +{ + const struct dma_siwx91x_config *cfg = dev->config; + /* Connect the DMA interrupt */ cfg->irq_configure(); - if (UDMAx_DMAEnable(&udma_resources, udma_handle) != 0) { - return -EBUSY; - } - - return 0; + return pm_device_driver_init(dev, dma_siwx91x_pm_action); } static void siwx91x_dma_isr(const struct device *dev) @@ -639,6 +686,10 @@ static void siwx91x_dma_isr(const struct device *dev) dev, data->zephyr_channel_info[channel].cb_data, channel, 0); } sys_write32(BIT(channel), (mem_addr_t)&cfg->reg->UDMA_DONE_STATUS_REG); + if (data->zephyr_channel_info[channel].channel_active) { + siwx91x_dma_pm_policy_state_lock_put(); + data->zephyr_channel_info[channel].channel_active = false; + } } else { /* Call UDMA ROM IRQ handler. */ ROMAPI_UDMA_WRAPPER_API->uDMAx_IRQHandler(&udma_resources, udma_resources.desc, @@ -701,7 +752,10 @@ static DEVICE_API(dma, siwx91x_dma_api) = { (siwx91x_dma_chan_desc##inst)), \ .irq_configure = siwx91x_dma_irq_configure_##inst, \ }; \ - DEVICE_DT_INST_DEFINE(inst, siwx91x_dma_init, NULL, &dma_data_##inst, &dma_cfg_##inst, \ - POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, &siwx91x_dma_api); + PM_DEVICE_DT_INST_DEFINE(inst, dma_siwx91x_pm_action); \ + DEVICE_DT_INST_DEFINE(inst, siwx91x_dma_init, PM_DEVICE_DT_INST_GET(inst), \ + &dma_data_##inst, &dma_cfg_##inst, POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, \ + &siwx91x_dma_api); DT_INST_FOREACH_STATUS_OKAY(SIWX91X_DMA_INIT) diff --git a/dts/arm/silabs/siwg917.dtsi b/dts/arm/silabs/siwg917.dtsi index 1db4c3f8d1619..218fbe89c1268 100644 --- a/dts/arm/silabs/siwg917.dtsi +++ b/dts/arm/silabs/siwg917.dtsi @@ -309,6 +309,8 @@ clocks = <&clock0 SIWX91X_CLK_DMA0>; #dma-cells = <1>; dma-channels = <32>; + power-domains = <&siwx91x_soc_pd>; + zephyr,pm-device-runtime-auto; status = "disabled"; }; @@ -323,6 +325,8 @@ silabs,sram-region = <&sram_dma1>; #dma-cells = <1>; dma-channels = <12>; + power-domains = <&siwx91x_soc_pd>; + zephyr,pm-device-runtime-auto; status = "disabled"; }; From f14796a56d7c93a4f08bb6357908afa0a85dbb2f Mon Sep 17 00:00:00 2001 From: Steve Boylan Date: Wed, 15 Oct 2025 14:39:39 -0400 Subject: [PATCH 352/397] dts: bindings: vendor-prefixes: Add canis prefix Add Canis Automotive Labs vendor prefix. Signed-off-by: Steve Boylan --- dts/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index f9b987895f8c0..b8d71c51eef6f 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -122,6 +122,7 @@ calaosystems CALAO Systems SAS calxeda Calxeda canaan Canaan, Inc. caninos Caninos Loucos Program +canis Canis Automotive Labs capella Capella Microsystems, Inc cascoda Cascoda, Ltd. catalyst Catalyst Semiconductor, Inc. From f3ce54f729519ae1625d29d428bb2577bec422dd Mon Sep 17 00:00:00 2001 From: Steve Boylan Date: Wed, 15 Oct 2025 14:37:07 -0400 Subject: [PATCH 353/397] boards: shields: Add support for Canis Labs CANPico Shield Add support for shields based on the Microchip MCP251xFD CAN Bus controllers, along with the Canis Automotive Labs CANPico shield for the Raspberry Pi Pico. Updated to focus on only the CANPico shield. Use alternate image for shield. Corrected image file extension. Signed-off-by: Steve Boylan --- boards/shields/canis_canpico/Kconfig.shield | 5 + .../canis_canpico/canis_canpico.overlay | 44 +++++ .../canis_canpico/doc/canis_canpico.webp | Bin 0 -> 32104 bytes boards/shields/canis_canpico/doc/index.rst | 165 ++++++++++++++++++ boards/shields/canis_canpico/shield.yml | 6 + 5 files changed, 220 insertions(+) create mode 100644 boards/shields/canis_canpico/Kconfig.shield create mode 100644 boards/shields/canis_canpico/canis_canpico.overlay create mode 100644 boards/shields/canis_canpico/doc/canis_canpico.webp create mode 100644 boards/shields/canis_canpico/doc/index.rst create mode 100644 boards/shields/canis_canpico/shield.yml diff --git a/boards/shields/canis_canpico/Kconfig.shield b/boards/shields/canis_canpico/Kconfig.shield new file mode 100644 index 0000000000000..45f2cd41f29e2 --- /dev/null +++ b/boards/shields/canis_canpico/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Steve Boylan +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_CANIS_CANPICO + def_bool $(shields_list_contains,canis_canpico) diff --git a/boards/shields/canis_canpico/canis_canpico.overlay b/boards/shields/canis_canpico/canis_canpico.overlay new file mode 100644 index 0000000000000..8a5d069f3255b --- /dev/null +++ b/boards/shields/canis_canpico/canis_canpico.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Steve Boylan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pico_spi { + status = "okay"; + cs-gpios = <&pico_header 6 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi1_canpico>; + pinctrl-names = "default"; + + mcp251xfd_canis_canpico: can@0 { + compatible = "microchip,mcp251xfd"; + spi-max-frequency = <1000000>; + int-gpios = <&pico_header 5 GPIO_ACTIVE_LOW>; + status = "okay"; + reg = <0x0>; + osc-freq = <16000000>; + + can-transceiver { + max-bitrate = <1000000>; + }; + }; +}; + +&pinctrl { + spi1_canpico: spi1_canpico { + group1 { + pinmux = , ; + }; + + group2 { + pinmux = ; + input-enable; + }; + }; +}; + +/ { + chosen { + zephyr,canbus = &mcp251xfd_canis_canpico; + }; +}; diff --git a/boards/shields/canis_canpico/doc/canis_canpico.webp b/boards/shields/canis_canpico/doc/canis_canpico.webp new file mode 100644 index 0000000000000000000000000000000000000000..f3fb8e0408f59ee52f7365c03ed42a8e26f82622 GIT binary patch literal 32104 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⁣rdW)Oa0&HIEJEIB%; z{ylz!-!!zNz9n%3VjG@y(WSDHft1asIhqx}e!k*>vDPKlOtm}cv9B6fN~3!=1xXG< zgKtT4T%c5FU{$=@Bf-x%d@<0eJC5!@I_x^#>hYvTqn>IpUghzu@_*B_SMWpqev&}9 zP4`^Fnp}^OIHH-LXCHqxP^vTXAhJevaS0_QE18i%V(s4yLw4x!zW^WbeJYqkoJ-Yr zF|kJtn8Ug^ma+FffU?~sKRtIrkH8<6#}w!}un<6`NBD5q|AW6gKNg@Xb2d|?eSMr< zfy};l7_Rc;$KJ#}KlBOOXRHNtG%5Wb@eK@GoMK$d_=xyiG^ zv!}--f37Gtv^nw8qbmnNBy7bWD}vXrPA2*=ox!m(L5#PW?0J;(b7MvKbF3(c9)(G` zfG><~u`kkX4qK}6E%_~Ep2JrVf;nTh1oCvtXH0l=W9_Yn5;rFc-ZuCM$twZ*=GPy3!Ag#eh4co!!V@|q;yRp+upmrHmD5eJ0=6Tyah)PcS zcQ=>T)VGo-hAd}rqg)v$KviHma7Z$R`%m)sl`B7a!&42n~d3rT&SkYRKR z3%%K#%XDzNa&s>GImHj0RQur_B4^oTH+5F3uELq$A>~p|H6tg028N>1yN%7lBD8St zI-m7T$oNMR0W*I)zLAaicYNr;yyg``uwUHJn45H&C7y{WPEgHatE2jh=OxGX>RsGD z%b2Ojr7jkH^-3AtRHae4-UtJ%`>^IxqZ2MOH(7yuzU!giPfYHXRE?N(c512Wp||C( zw6PUB_xSROkMhPm{Wwve#mK;fidHT1U?dnecJNs_D%!8WNRX^$L6w(eNCIz?rdmXL z65~WNnF0&ROf&@F=-_V9>x2uu~| z2+`KhoFeB<4$Ub0gukli8pPaTihxdM5*HpsNgf-W(ciI`k^W-HMR8D;{54)u9oem+ zx6j5Pi0Pys@?dRd;(hclgTp8Ck|0=$DF$xYYC$N>1YQ>}3_^TrOJkDm zZASznnBN)PAsA-Ng?92gR~=wnWEu#EG%Gs43>c?k-D5X?cZIK;tux%COy<3N=g+%z zAfU|0;8~;G>c#(!3z8ouPCwko&u zzTS5Wl=A><)oJU6Vf5!*1B>YB98}^EX&5x%RaH1XsFYmLK!dw6!M(`nQ4(d;FxLp` zW}z|!quV@C>(`ApE5xJay#T&n%59*R67rm#$uu8T?~Vg7bd4KX^(HwBlFFE2q$3*W z8`Oa>CpKTzgFeyOl0T(AyDm)#`Td`y{k_6c89)&L9`@A!e{h)o%DQa%*6#S{KW#B* z6egqH)!ho)cc<&C+@!}bRp}}BwYwPe+~Y7vv+?qbldi$|l2#6um_ zt&&XyO3GszTk*klr(W>Z)j8Ns(&kEbDqhNE@KTU%yoc6Rt4Mx&T*VvoDgVVIXc;Cd z^2y(-G`+YWfG=5qYV478K4`COeH1AK(bQ%8ca_m8M9Xs{b5TSn@~LRKWaMp#&~w{@ z;_gKn2BSy&|A$Ub0D?&oZj{1i^U?+}z-4QZ*u2sjDp>s?YMj4tR$O0A&#ru9M_{xL z=9t#mxt0+9@=N(PR{&tdB#tt;BN{W~XffiBBuKrfeATGlRyb#dt|3eHr`MgqGwrBO z;rQ>tCgWb#so}i()FUPJTA8VmPClsJ9@bpisTREujlpc={ww6cg8|XARC`bB{KqnE zK!5SA#2N%}XhvI5-3<{eHROqb4x7-N=@@^hs-AJJy@^d%6!@-$dpUs}Kza@8q;rUK z?t_PxNtJ59yxbd4zAopgyq6adC_42}r4KhI)S7wQ64C^L@lU4!O4D?<_>E0!nN#`6 z=^*UHq&+Pcu&|h4Wq}%rh#CKPyg!!C{xts1>Myb%TYcDRJBqmR^ifR=tVeovHiBNA zUA6g)AdSxm=cp|>)cco0^@6#YSq!THKB6x*V)G%zshifsitGj-79O|H@72A3-T@v* z!gOcM4Vdc8+#>DlMbA%wcnEgMua&lc+5PVHcZ_xSu2blfaDWAzcrm00dvc=gknkqn z-bE8s) z3yO@>G&2K%AKzEV^yMb0;iHwPWt9OQkw+k*{LPCm zeiP7VBR6D?Zn~V@xBu9_%y?S4r(JYlt}&mHbJb08?cyig;?-WY15di;=8q+)+)G5F zNW=v|+ipQ}EFGMsQ znu}C#q<1kfHmDd3Fjg5J&dw%KLunsVjusxG$On$hXmooB>TJh)>;vCIZMfHmL!_;Z z;I-&LW#(b#mZp*lO)9JkMX`N_Uf7N3Mc)QmYBMln5uah!vixg5cuTrjS+`~;Db#Bd zyW5Qu>6c$dnNcXBq)qbqcl4*Gyy#*|_#2Wwp@PX44j-NM;oRLnU@Z6$yr~{+d;sG5 zx*_~PZebjg@jvgkJWEZAHi#G`iueq4A8PyBQd)hOQ&;CvK%Q)?2i={IEq4xJpDZD<9m&Ox;Eaqt;PWMdO)#G7cgaQofwcf}A?A&pg+RcK z!z!f#LPXkC%DLt7_9ZxJMqqW_@!3nObzO;8+`WbRJwUY zUnyct+RESI1_t1@mND=t#y|{f&k-5wnZg(@M-X0nHp0x2BYm6!9h2cI131g|G#V=o zbuWNrVDkjz|F7z%jk1FB_j5gKx(^3GXK~EPGgu+ zjlx$ccwU68M+-9B`{EPJTHlrj7p!RZ>y)VJ94X+UsrhVLmzNY~m|j!Ug+sL?f6IDF zE`PC{jWVQN{H9DNPx|DP;#nJ`fwrwl8~*xS@{%&lB?xP6S_XAJUeq<_tai9$YJhaa&P z#OCA7F-!86!>RL~vrge`^j^yY0?0x5Ydw^g+EJ`6q;xqifGf?(FCX^ve<>}{k?|7| zCc!uml%K-Nr7PvvScfcD(8gH_pAPH+~R_2lFX~nt z>UQ))R2D9zc|?M@Fa9Ug#<*^XU?@4I$V%Dm=BU2>Nke^z@jUUr1(?(lthtHbErAI0 zmyYfuh|W1|h1}*6Jn+ooKF@G_iEk=wnP;VC8Nmz2VDAhD^&PL3Brs{ynKN=fA}Yj4 z`NBuGt3z>>C7GZq872-`Wy|h^j~z3Kjao+o;Jeq<4qK5-#Jotc7S)8`mPt(uTEP<) z(lz!bJ!%N`ydK)IK{;eT7v9?=r&*d&0p?uL(E~6eTsdyk&=S$>>KoUpclAp4+02t~ ztO&L|Y2oV!!7hFJvsuogX&(^SZ6+l&H|WMV9Q%8-28el^xJ=f{-ZxxKP6Ijl-$O>5 zU|v9o)Zgr6G<|F^K8Z$n9C7^AgjViIG+AI4cA!xPuH_7f$p&*ZwDd@EAWZh0^ookr zqEe!*b&wzix;;O{+zv94jBylGn?k{MM;oJmf#SnR(#q%dF_`h71YN`S~ zEL0I}73zCPK*wa@@FteIy(c;q7zG0qj^7_Y4o;!U2^X@t6c|XHhH+;!&AKq5Jy0RH z(v(@gRN~UVb^vk$aryX;j`f){qF>WwNn4t64Jw?L@&pc}b-(EL$)#7U(d|0iUVlMk zN72{L3A4(_Jyani4gE0G^`$TH4=O811p)KYE#(Rn*}t_w|x47P%KQzErMF$ z8HZX(M6U;MnLQuYt466N8_Rh@yL1i#H{=QNTuq~`aLzcxVD*%8n(e_zB}8*vb00Eser_6v1s&*-iiBVIgd9!P12iLtB4# zeLg{zb!|2tr3FY9LPEp@egZsX!(|~C!n^+TICK$51XP4H02mYIK&RjcW?$ACP#+Gd z5(h#yM7u4}v=)p}s>%t%G=d$uN|yOlwYg}>m@Zq4!ZP%Gk9t5q z1fFWY?~YVSob`YHS!t?e0|p1hqC=*uPq=4kav=+0@L*Mx0o|HCEISUHs%xr5K%2F| z3Fnx*xbHHnCQCMaU~;ysrMuh^!3M$%=^3*+ple#h#0tV-5bZQtbt#y{Nva06-YszBNPr6oT?KnL+WnbyvC1JOtEDvoL(g99G^uV^F`)@|I0=V(a zinF7q?3RasfvXKQxiC35M998z4H*62LZ_CK2D`nj!VJn`3e}Y@a*x6VPb@Fy8WTl^ zEVdH6+2eahBBP6{<2wia&jm$EcC=v~9b}mSK>zhWK%pqqapkZjGsR0uHADs6_@t15 z%mH8$vAQ*^i45A|14&q~U!hq|ZiBers!P)%)azag#0vYBk!jN>QL~7YvY)N>wcjd? z?Ts_=o*e6wHI2+UpUofQwmQH+<*^}0A)+-r@;DWCzd@&ES{6nXz6oe5Hd0$4TIgql zLcu|ADRAmTfK)ssAkVB*U8#-I_kdBZ-z5v*c8U{rog)6JT3q--*4ZgaiKTsxMq!J- z0{O@g^1cLSA@NLz^~?hDdJTJ;eI#!S^)nuD0`P>19w3H%H&sED#|${Y<*L$kCY)8V9B!V|RmEk%QL4_jm(rC_mu~Q=Ynf^sPZqc@wyJ*OSkvM2A z(dpOm1>+AjmFmY}|H6pEWq)=HR^z{Ij?H+8DSz-)X^H1_+N)5^)cbpW)NYBvl}IlD z#PSQ`*Gohy#HCVvo`fcKQDvKVWi(2WzrX5c-o1-)*pBn%D$v8Rh%&k}4m3YK+dqK*V#eenBH-jS!|1l7$J=aQDw-RgStKgWGi8;%kWF(!`k`NJ1s9)~=9~No16eJUlI6KZlfr7h!V@ZGv{iRZ*pT ztig6;m%u^$rD0EzJ@=j=lVp9-rQBTs>H5yyUA1%lT>o0VArF;2ISeb0QRgHyJ7#0&(zSdzb3Lw-ARk zYKcb8Z#OoZIj)STscs7Jq2nt8EMncTBE&ZZvo8o>zsG*3X&U` zhL~c>+H$bUg;^z!i?7TycSwFjpF{6MX8zyS;kSau6tS)GwpSXN;H6bfu0tFXK--o{ zBy>UcdW5Gk_;2!{BD-<*Rnol@{OCWw`C5}>;81q+?JI~ebZh~(cgp#l*|(!9PIGt z$YLNvW-bIGHH8s2h8o35dFZzLlj%qPT!59bUFfvMfCpsiI}|Vv%<*6R)tb=|0=0OI zezy2P%esl^5W{Ih;Jt;xK;`9BOfB6{5ho>sNwuHqLfrs5E8d_8X&CxHiq$ftVF}*%(YZJG0Vn{IUj7g&F+;ZvgHY1hUuMOaqqHYEQjSh2urK{pIj{8@hvSq{Xmx^nZ*%&4G}RZL=6X+*LVS&> z?oa?Y7+#0b^r4LI9ZE1c;m<9zYmWqW21e`MoMRS!&yROsAVq1CS?eVHH9u@q#I9sISX9q z5qk@$^)3QO%}|t%3O|MCuBz5ZKhLC&YkISS=%C(_{H)QR zGmPifMXRww=I(Y{8*pB^%U6>A;bJyrB$#sf2oc|7zSw)y^?pWE07HzKa2|+tg9(3e#@nWrd#uylxw4?$l=Q=_DxQ7Q&|Uix~YO= z%IIt^CA8)cYiGGO|PPGdA%QgMlQbjG`Y7@Z!kLKI( zQ+(G3=wSbel-?`wlgnY+eEc0l>})l~6RBhE)QwZpm*XlJ{UOGo9&mYNzi(Wxnh|L^ z&Yu?Y)vcT#eFRU@-hcF(O^MiPi3Sw#y>Ud>=@tDwC&G@=7$|#~3IQBkkTRTUsK+|+ zSp-A_fyBR1|44Y9gD*7>Z>t*=sffGaG5nq}S`<^}`8{kFY0-a%w2fik3Z^n6^#X4z z7wEad83RY|p)v!D+{D^cv|WOQBm&47=g`qi04VftKrh>7J9G#>?!3qbc5Ry*UXxvF zZ?sARh=ZM+gfU?YrTgI5>^R8ci7_ZfufLXi|Xm>FaSdg$;zOlk7;bwHnXn* z)LI*T%!`G*G8!tBx-bttDaNy9_TzO8BkNLmPTMj`qZequiAx2%2?TX1=jcB z3{t@K;IDS{y4w%GZmpWPipd=?G!lF4XOwR+@dfH=e+FgSQXoSez~U_x+9nJTfc}sg zG2U5}@~{y!xSAtDT7{HLdm=Hhb`ei74TVfn12(vVSd0xwu zw_sFKzuIH$Jqw#C?iDFcq_41BAse68vi?e4h;JMHT0%T#z`Qki2J{vc|N0w>D=+kX zteUv{3$Qz>?W5q~n^Ke9Y)!xT){v@1;RrwExTgPH1mCA@G6t?tES;A z37xa^`sNvD@G)xX;FvEYd!gs-=ojMW6+q?;vA7cWRVHNyZ&f{tNyRdkhKV+we>Nz} z{$KS;?j%LWtaNS(S)bcJzX6ftd=$G0v)u+r%d1TNg%guP9+#Cx-!E-y5+%7~a$5x2 zQLkdXmt3uK??aMvhzz_5SiC${E=hrJA8#*wL6m!KG!cXGSJ%fgcih6aZx;H0ZnJj9 zQ)@tQ0ot#?hcgw!>u;GwuGxVesJ>4gfb!GIQ{KvHN)qY~7O|c4y)cS(IK`>%J;lrI z6d?p{7DqFj5sB!fU{#u$Zfx?^(gKYoNv+}}=X%ZZ=eG!4LYm`iuCy7#{}M>OK4uS;bFKRbXCjNM>? z^f2ntME*H9f+J-*wGiki@sHwA*#s*g01p*zgu02PglTe|1>-o7Q>@2x#m%Z+rp~Vaa z>VQ-!F*BtMdyVdU>MO=zQ|(clD+#d}+3;+r@UaB7!rpKLEQd>8U@TQ{ zay6s);>I3szBVyWHL=OQz!A}6{Q-vU8F0Ql*UQhzkj(^6TZqkB**Vew$4+SOSGNB* zq##->1rp9ly$4_8F$5p??HFPMlaYgx9X!o9?qq$+iB37H+1D z*l#RNudv)w$x|uxE(<2L>656-3U3-~HGRgcof7GhW&qAe@F=pG1E4Bj2a^W-u78E3 zEyYu^$KOI2Qx6RCQJOss_~*va8A=1QCn3_SPG#)O9?5H5b06W(w-c@@wdXPb1b${z z?W0Hm82?{)LpH0swi!aoLj5`FlW1Nul>l+O06kNAPm6BY&yL@o`JhVH)E-Vhk7u-G zPRT^+NAC!?eF>B7>FTRhPimjaJN6aCdr;zh%XWv+v-{m*Ynj~64o)-FV)2pL9}2c5 z(1rzPMO-%}dqi;qya>@0Mrdm$ql?jb6&S5!D6lBBoRSR5}kw7zQcI9v*!# z!iegLklQGRB;0Ek@O}-sOPCDG&o`RV(&i+DSrQQaHH-rXQj8GR^_1=AS>6m)ARp|&=z&2Fm>#x)&(YII)gu!mmTI%pGc zq`SRnFB?O@>JxsmSN>$_AO62@nV~^up`iWgpu<^&YK|&~vGFMMG8T`WrbX4C5ouY6 zzl}e(cTAi9SaICdnyS)^d>e8C0@^89#)?iFzWF+PukW|s`3&g$q zi=0#q>Yz@a8P(}WBeb(VzRS{045$|ZM=z$EvUX!5SB(cR(w@?Q2u`!|+TuB&;uez|_XVWsEy-e1v!45OT2F>}@ZKj5&D>9YQoYCWAx z(}uIjuj#6r8Q&cu7##%TXq*(?Al`Cf<=WZ`E0DV|B(qi%e9D8o+-^G>I z%jaKiLM}3pfc(WY2;rbW0|Cov)2Arl-fhBgl?Tb1Y4m}qZ`1aw6^9#?+ng7mD&yyO zn9enPfMW1r9+iM>Qc0~YA18!<3E+w5mmng;z;5lhLiM0)+W{eT4x}MJAlh)PO+}wI zd8flo8Ib!OSdtF%N})%=E8nt)!}4S7Zb5S5#!^~lIKbOcm~=6$s77)E?XJA>XJw6`~* z98AcsvPBr(oZW^ttH8qt#`oAf%GM8JdGO%$ZobdggjdoCr+Bm_^ulXB^~!&2ylT8W zM>aM%rwTcI4d%W0ia)i!C`CLIA|k^aPZ-74e){9>_AVld!&gm^R@SA#FVQVBx`duv zhyAbHV9-uCVqN~dEd|g~@TGf|0ixiNp)W}sVl&adipR2w>!4OHiG%w|c-V3az9^PH zfcODzpE{Dhi)e5zidRsm2@Ip5f|L^$*C=t(mc*jmzLZGoXny4%3a z^yASgBv3=a=H(=3q}o&+i$p5Y6!s*%nD=1&aD=ugZ-qC9aGZY=xR$Ze*b+v!Uq&kD z7x7EHe*~m-wXR`*$A`e?-=4}B1BNicpDMdAa;~pev6=lmx3xUp-H&{a{A1#|k*m_* zf2CD@B1e2?I-LvUws7%min}`XQx@H5qbO7& Date: Wed, 12 Mar 2025 09:52:29 +0300 Subject: [PATCH 354/397] tests: subsys: pm: Enable testing on MAX78002EVKIT Enable SoC power management tests on MAX78002EVKIT board. Signed-off-by: Tahsin Mutlugun --- tests/subsys/pm/power_mgmt_soc/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/pm/power_mgmt_soc/testcase.yaml b/tests/subsys/pm/power_mgmt_soc/testcase.yaml index 147b4f813e42c..8c4e71804fe11 100644 --- a/tests/subsys/pm/power_mgmt_soc/testcase.yaml +++ b/tests/subsys/pm/power_mgmt_soc/testcase.yaml @@ -20,6 +20,7 @@ tests: - max32655fthr/max32655/m4 - max32657evkit/max32657 - max32657evkit/max32657/ns + - max78002evkit/max78002/m4 - imx95_evk/mimx9596/m7 - ek_ra8m1 - ek_ra8d1 From d0c8956c3125db9a0229475ae4a78f11521b8ebf Mon Sep 17 00:00:00 2001 From: Tahsin Mutlugun Date: Wed, 22 Oct 2025 23:10:07 +0300 Subject: [PATCH 355/397] drivers: fuel_gauge: ltc2959: Fix build warnings from declarations C standards prior to C23 do not allow variable declarations immediately after labels. Wrap such declarations in blocks to eliminate build warnings. Signed-off-by: Tahsin Mutlugun --- drivers/fuel_gauge/ltc2959/ltc2959.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/fuel_gauge/ltc2959/ltc2959.c b/drivers/fuel_gauge/ltc2959/ltc2959.c index 6632c930e0225..32f2cec1eed85 100644 --- a/drivers/fuel_gauge/ltc2959/ltc2959.c +++ b/drivers/fuel_gauge/ltc2959/ltc2959.c @@ -461,7 +461,7 @@ static int ltc2959_get_prop(const struct device *dev, fuel_gauge_prop_t prop, int ret; switch (prop) { - case FUEL_GAUGE_STATUS: + case FUEL_GAUGE_STATUS: { uint8_t raw_st; ret = i2c_reg_read_byte_dt(&cfg->i2c, LTC2959_REG_STATUS, &raw_st); @@ -473,8 +473,8 @@ static int ltc2959_get_prop(const struct device *dev, fuel_gauge_prop_t prop, val->fg_status = raw_st; break; - - case FUEL_GAUGE_VOLTAGE: + } + case FUEL_GAUGE_VOLTAGE: { uint16_t raw_voltage; ret = ltc2959_read16(dev, LTC2959_REG_VOLTAGE_MSB, &raw_voltage); @@ -490,8 +490,8 @@ static int ltc2959_get_prop(const struct device *dev, fuel_gauge_prop_t prop, val->voltage = raw_voltage * LTC2959_VOLT_UV_SF; return 0; - - case FUEL_GAUGE_CURRENT: + } + case FUEL_GAUGE_CURRENT: { uint16_t raw_current; ret = ltc2959_read16(dev, LTC2959_REG_CURRENT_MSB, &raw_current); @@ -506,8 +506,8 @@ static int ltc2959_get_prop(const struct device *dev, fuel_gauge_prop_t prop, val->current = current_raw * cfg->current_lsb_ua; break; - - case FUEL_GAUGE_TEMPERATURE: + } + case FUEL_GAUGE_TEMPERATURE: { uint16_t raw_temp; ret = ltc2959_read16(dev, LTC2959_REG_TEMP_MSB, &raw_temp); @@ -525,8 +525,8 @@ static int ltc2959_get_prop(const struct device *dev, fuel_gauge_prop_t prop, */ val->temperature = ((uint32_t)raw_temp * LTC2959_TEMP_K_SF) >> 16; break; - - case FUEL_GAUGE_REMAINING_CAPACITY: + } + case FUEL_GAUGE_REMAINING_CAPACITY: { uint32_t acr; ret = ltc2959_read_acr(dev, &acr); @@ -537,7 +537,7 @@ static int ltc2959_get_prop(const struct device *dev, fuel_gauge_prop_t prop, val->remaining_capacity = ltc2959_counts_to_uah(acr, cfg); break; - + } case FUEL_GAUGE_ADC_MODE: ret = ltc2959_get_adc_mode(dev, &val->adc_mode); break; @@ -636,7 +636,7 @@ static int ltc2959_set_prop(const struct device *dev, fuel_gauge_prop_t prop, ret = ltc2959_set_cc_config(dev, val.cc_config); break; - case FUEL_GAUGE_REMAINING_CAPACITY: + case FUEL_GAUGE_REMAINING_CAPACITY: { uint32_t counts = ltc2959_uah_to_counts(val.remaining_capacity, cfg); if (counts == LTC2959_ACR_CLR) { @@ -644,7 +644,7 @@ static int ltc2959_set_prop(const struct device *dev, fuel_gauge_prop_t prop, } ret = ltc2959_write_acr(dev, counts); break; - + } default: ret = -ENOTSUP; break; From 9b7e8b71b2044fa6aa57e43578d81fa8933b4ca2 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 22 Oct 2025 16:30:17 +0000 Subject: [PATCH 356/397] MAINTAINERS: add the newly added CANPico shield to the CAN area Add the newly added Canis Labs CANPico shield to the CAN area, similar to other CAN shields. Signed-off-by: Henrik Brix Andersen --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 032994d613dec..0beea159b462a 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1274,6 +1274,7 @@ Documentation Infrastructure: - martinjaeger - str4t0m files: + - boards/shields/canis_canpico/ - boards/shields/mcp2515/ - boards/shields/tcan4550evm/ - doc/connectivity/canbus/ From 5b34e14c248813d9a2c232dc25ada07032969fbe Mon Sep 17 00:00:00 2001 From: Rodrigo Peixoto Date: Wed, 22 Oct 2025 12:05:48 -0300 Subject: [PATCH 357/397] doc: zbus: fix benchmark sample execution command error Fixes #98070 Signed-off-by: Rodrigo Peixoto --- samples/subsys/zbus/benchmark/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/subsys/zbus/benchmark/README.rst b/samples/subsys/zbus/benchmark/README.rst index 2db3e7d23ff3c..5fb9c52feeaba 100644 --- a/samples/subsys/zbus/benchmark/README.rst +++ b/samples/subsys/zbus/benchmark/README.rst @@ -11,7 +11,7 @@ Building and Running ******************** .. zephyr-app-commands:: - :zephyr-app: samples/subsys/zbus/dyn_channel + :zephyr-app: samples/subsys/zbus/benchmark :host-os: unix :board: qemu_cortex_m3 :gen-args: -DCONFIG_BM_MESSAGE_SIZE=512 -DCONFIG_BM_ONE_TO=1 -DCONFIG_BM_LISTENERS=y From e48cf953f10195b4089f3c3cbe11c402cd30d71f Mon Sep 17 00:00:00 2001 From: Yasushi SHOJI Date: Fri, 17 Oct 2025 15:33:35 +0900 Subject: [PATCH 358/397] doc: kernel: services: interrupts: Add markup for generated files Apply `:file:` markup to file names in the "Files generated by the script" section under "Implementation Details" to improve clarity and readability. Signed-off-by: Yasushi SHOJI --- doc/kernel/services/interrupts.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index 621e843895001..25de0ab3e30be 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -689,16 +689,16 @@ Files generated by the script ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The interrupt tables generator script creates 3 files: -isr_tables.c, isr_tables_swi.ld, and isr_tables_vt.ld. +:file:`isr_tables.c`, :file:`isr_tables_swi.ld`, and :file:`isr_tables_vt.ld`. -The isr_tables.c will contain all the structures for interrupts, direct interrupts and +The :file:`isr_tables.c` will contain all the structures for interrupts, direct interrupts and shared interrupts (if enabled). This file implements only all the structures that are not implemented by the application, leaving a comment where the interrupt not implemented here can be found. -Then two linker files are used. The isr_tables_vt.ld file is included in place +Then two linker files are used. The :file:`isr_tables_vt.ld` file is included in place where the interrupt vectors are required to be placed in the selected architecture. -The isr_tables_swi.ld file describes the placement of the software interrupt table +The :file:`isr_tables_swi.ld` file describes the placement of the software interrupt table elements. The separated file is required as it might be placed in writable on nonwritable section, depending on the current configuration. From 1d7779bfe7067555d0bffa1c4d39f3ba52b44184 Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Fri, 17 Oct 2025 20:52:13 +0200 Subject: [PATCH 359/397] net: mqtt_sn: fix returning address from zsock_recvfrom The fix in 1264a923f37bce88146674a3c7f93d3886a50669 was incomplete, because it doesn't initialize the variable. To quote from opengroup [1]: address_len Either a null pointer, if address is a null pointer, or a pointer to a socklen_t object which on input specifies the length of the supplied sockaddr structure, and on output specifies the length of the stored address. This caused the returned address to be incomplete, because it got truncated depending on what addrlen_local got initialized with implicitly. This broke talking to discovered MQTT-SN gateways. I intend to implement integration tests for the MQTT-SN UDP transport to prevent such issues in future, but that will be done in a separate PR. [1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html Signed-off-by: Michael Zimmermann --- subsys/net/lib/mqtt_sn/mqtt_sn_transport_udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/mqtt_sn/mqtt_sn_transport_udp.c b/subsys/net/lib/mqtt_sn/mqtt_sn_transport_udp.c index cca6788fafb10..630aa24f03354 100644 --- a/subsys/net/lib/mqtt_sn/mqtt_sn_transport_udp.c +++ b/subsys/net/lib/mqtt_sn/mqtt_sn_transport_udp.c @@ -213,7 +213,7 @@ static ssize_t tp_udp_recvfrom(struct mqtt_sn_client *client, void *buffer, size struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport); int rc; struct sockaddr *srcaddr = src_addr; - socklen_t addrlen_local; + socklen_t addrlen_local = *addrlen; rc = zsock_recvfrom(udp->sock, buffer, length, 0, src_addr, &addrlen_local); LOG_DBG("recv %d", rc); From a1da734e6b0c203aab305e17e6b11c6e51e8de7b Mon Sep 17 00:00:00 2001 From: John Batch Date: Mon, 20 Oct 2025 10:57:50 -0700 Subject: [PATCH 360/397] soc: infineon: PSOC Edge: Remove board references from soc cmake Removes references to the kit_pse84_eval board from the soc cmake file. Signed-off-by: John Batch --- soc/infineon/edge/pse84/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soc/infineon/edge/pse84/CMakeLists.txt b/soc/infineon/edge/pse84/CMakeLists.txt index 53d390c49b263..527b42bbdb20a 100644 --- a/soc/infineon/edge/pse84/CMakeLists.txt +++ b/soc/infineon/edge/pse84/CMakeLists.txt @@ -40,7 +40,7 @@ endif() zephyr_include_directories(security_config) zephyr_sources(security_config/pse84_boot.c) -if(CONFIG_BOARD_KIT_PSE84_EVAL_PSE846GPS2DBZC4A_M55 AND CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS) +if(CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS) zephyr_sources_ifdef(CONFIG_CPU_CORTEX_M55 mpu_regions.c) endif() @@ -51,7 +51,7 @@ if(${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "armclang") endif() # Add sections -if(CONFIG_BOARD_KIT_PSE84_EVAL_PSE846GPS2DBZC4A_M33) +if(CONFIG_CPU_CORTEX_M33) zephyr_linker_sources(SECTIONS shared_mem_sec.ld) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") else() From 2a3180d509b024789d8e9d3f735cbcba8c70a8d7 Mon Sep 17 00:00:00 2001 From: John Batch Date: Mon, 20 Oct 2025 11:53:01 -0700 Subject: [PATCH 361/397] modules: hal_infineon: Remove board reference from module cmake *Removes a reference to kit_pse84_eval from modules cmake file. These includes aren't board specific. *Removes reference to non-secure M33, which aren't currently supported. Signed-off-by: John Batch --- .../mtb-template-cat1/CMakeLists.txt | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/modules/hal_infineon/mtb-template-cat1/CMakeLists.txt b/modules/hal_infineon/mtb-template-cat1/CMakeLists.txt index 08f203f053db3..0807e415d78f3 100644 --- a/modules/hal_infineon/mtb-template-cat1/CMakeLists.txt +++ b/modules/hal_infineon/mtb-template-cat1/CMakeLists.txt @@ -47,14 +47,10 @@ if(CONFIG_SOC_FAMILY_INFINEON_EDGE) zephyr_include_directories(${edge_dir}/devices/include) zephyr_library_sources(${edge_dir}/system_edge.c) - if(CONFIG_BOARD_KIT_PSE84_EVAL_PSE846GPS2DBZC4A_M33) - zephyr_library_sources_ifdef(CONFIG_CPU_CORTEX_M33 - ${edge_dir}/COMPONENT_CM33/COMPONENT_SECURE_DEVICE/s_system_pse84.c) - zephyr_include_directories(${edge_dir}/COMPONENT_CM33/COMPONENT_SECURE_DEVICE) - else() - zephyr_library_sources_ifdef(CONFIG_CPU_CORTEX_M33 - ${edge_dir}/COMPONENT_CM33/COMPONENT_NON_SECURE_DEVICE/ns_system_pse84.c) - endif() - zephyr_library_sources_ifdef(CONFIG_CPU_CORTEX_M55 - ${edge_dir}/COMPONENT_CM55/COMPONENT_NON_SECURE_DEVICE/ns_system_pse84.c) + zephyr_library_sources_ifdef(CONFIG_CPU_CORTEX_M33 + ${edge_dir}/COMPONENT_CM33/COMPONENT_SECURE_DEVICE/s_system_pse84.c) + zephyr_include_directories_ifdef(CONFIG_CPU_CORTEX_M33 + ${edge_dir}/COMPONENT_CM33/COMPONENT_SECURE_DEVICE) + zephyr_library_sources_ifdef(CONFIG_CPU_CORTEX_M55 + ${edge_dir}/COMPONENT_CM55/COMPONENT_NON_SECURE_DEVICE/ns_system_pse84.c) endif() From 851190c03a0d0b6922b52e77069dbf576c888dff Mon Sep 17 00:00:00 2001 From: Roy Jamil Date: Mon, 20 Oct 2025 18:33:43 +0200 Subject: [PATCH 362/397] scripts: puncover: Fix compatibility with v0.6.0 Signed-off-by: Roy Jamil Puncover v0.6.0 renamed the command-line argument `--gcc_tools_base` to `--gcc-tools-base`. Fixes compatibility error when running `west build -t puncover` with puncover v0.6.0 or newer. --- cmake/reports/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/reports/CMakeLists.txt b/cmake/reports/CMakeLists.txt index a65482ac10ac8..7f282b6029e9c 100644 --- a/cmake/reports/CMakeLists.txt +++ b/cmake/reports/CMakeLists.txt @@ -128,7 +128,7 @@ if(NOT ${PUNCOVER} STREQUAL PUNCOVER-NOTFOUND) puncover ${PUNCOVER} --elf_file ${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} - --gcc_tools_base ${CROSS_COMPILE} + --gcc-tools-base ${CROSS_COMPILE} --src_root ${ZEPHYR_BASE} --build_dir ${CMAKE_BINARY_DIR} ${PUNCOVER_ARGS} From e32489cdeb1c7f796bcd4d509cf21c8266d3da9e Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 20 Oct 2025 11:31:44 +0200 Subject: [PATCH 363/397] drivers: video: stm32_venc: fix return value Avoid mixing encoder library return code and driver return value to fix wrong value returned by enqueue() in nominal case. Signed-off-by: Hugues Fruchet --- drivers/video/video_stm32_venc.c | 63 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/drivers/video/video_stm32_venc.c b/drivers/video/video_stm32_venc.c index abd1608454dfb..a128442742e0a 100644 --- a/drivers/video/video_stm32_venc.c +++ b/drivers/video/video_stm32_venc.c @@ -465,7 +465,7 @@ static int stm32_venc_get_fmt(const struct device *dev, struct video_format *fmt static int encoder_prepare(struct stm32_venc_data *data) { - H264EncRet ret; + H264EncRet h264ret; H264EncConfig cfg = {0}; H264EncPreProcessingCfg preproc_cfg = {0}; H264EncRateCtrl ratectrl_cfg = {0}; @@ -489,42 +489,42 @@ static int encoder_prepare(struct stm32_venc_data *data) cfg.svctLevel = 0; cfg.viewMode = H264ENC_BASE_VIEW_SINGLE_BUFFER; - ret = H264EncInit(&cfg, &data->encoder); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncInit error=%d", ret); + h264ret = H264EncInit(&cfg, &data->encoder); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncInit error=%d", h264ret); return -EIO; } /* set format conversion for preprocessing */ - ret = H264EncGetPreProcessing(data->encoder, &preproc_cfg); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncGetPreProcessing error=%d", ret); + h264ret = H264EncGetPreProcessing(data->encoder, &preproc_cfg); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncGetPreProcessing error=%d", h264ret); return -EIO; } preproc_cfg.inputType = to_h264pixfmt(data->in_fmt.pixelformat); - ret = H264EncSetPreProcessing(data->encoder, &preproc_cfg); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncSetPreProcessing error=%d", ret); + h264ret = H264EncSetPreProcessing(data->encoder, &preproc_cfg); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncSetPreProcessing error=%d", h264ret); return -EIO; } /* setup coding ctrl */ - ret = H264EncGetCodingCtrl(data->encoder, &codingctrl_cfg); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncGetCodingCtrl error=%d", ret); + h264ret = H264EncGetCodingCtrl(data->encoder, &codingctrl_cfg); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncGetCodingCtrl error=%d", h264ret); return -EIO; } - ret = H264EncSetCodingCtrl(data->encoder, &codingctrl_cfg); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncSetCodingCtrl error=%d", ret); + h264ret = H264EncSetCodingCtrl(data->encoder, &codingctrl_cfg); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncSetCodingCtrl error=%d", h264ret); return -EIO; } /* set bit rate configuration */ - ret = H264EncGetRateCtrl(data->encoder, &ratectrl_cfg); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncGetRateCtrl error=%d", ret); + h264ret = H264EncGetRateCtrl(data->encoder, &ratectrl_cfg); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncGetRateCtrl error=%d", h264ret); return -EIO; } @@ -537,9 +537,9 @@ static int encoder_prepare(struct stm32_venc_data *data) ratectrl_cfg.qpMin = ratectrl_cfg.qpHdr; ratectrl_cfg.qpMax = ratectrl_cfg.qpHdr; - ret = H264EncSetRateCtrl(data->encoder, &ratectrl_cfg); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncSetRateCtrl error=%d", ret); + h264ret = H264EncSetRateCtrl(data->encoder, &ratectrl_cfg); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncSetRateCtrl error=%d", h264ret); return -EIO; } @@ -548,7 +548,7 @@ static int encoder_prepare(struct stm32_venc_data *data) static int encoder_start(struct stm32_venc_data *data, struct video_buffer *output) { - H264EncRet ret; + H264EncRet h264ret; H264EncIn encIn = {0}; H264EncOut encOut = {0}; @@ -557,9 +557,9 @@ static int encoder_start(struct stm32_venc_data *data, struct video_buffer *outp encIn.outBufSize = output->size; /* create stream */ - ret = H264EncStrmStart(data->encoder, &encIn, &encOut); - if (ret != H264ENC_OK) { - LOG_ERR("H264EncStrmStart error=%d", ret); + h264ret = H264EncStrmStart(data->encoder, &encIn, &encOut); + if (h264ret != H264ENC_OK) { + LOG_ERR("H264EncStrmStart error=%d", h264ret); return -EIO; } @@ -586,7 +586,8 @@ static int encoder_end(struct stm32_venc_data *data) static int encode_frame(struct stm32_venc_data *data) { - int ret = H264ENC_FRAME_READY; + int ret = 0; + H264EncRet h264ret = H264ENC_FRAME_READY; struct video_buffer *input; struct video_buffer *output; H264EncIn encIn = {0}; @@ -637,11 +638,11 @@ static int encode_frame(struct stm32_venc_data *data) encIn.outBufSize = output->size; encOut.streamSize = 0; - ret = H264EncStrmEncode(data->encoder, &encIn, &encOut, NULL, NULL, NULL); + h264ret = H264EncStrmEncode(data->encoder, &encIn, &encOut, NULL, NULL, NULL); output->bytesused = encOut.streamSize; LOG_DBG("output=%p, encOut.streamSize=%d", output, encOut.streamSize); - switch (ret) { + switch (h264ret) { case H264ENC_FRAME_READY: /* save stream */ if (encOut.streamSize == 0) { @@ -652,7 +653,7 @@ static int encode_frame(struct stm32_venc_data *data) output->bytesused = encOut.streamSize; break; case H264ENC_FUSE_ERROR: - LOG_ERR("H264EncStrmEncode error=%d", ret); + LOG_ERR("H264EncStrmEncode error=%d", h264ret); LOG_ERR("DCMIPP and VENC desync at frame %d, restart the video", data->frame_nb); encoder_end(data); @@ -663,7 +664,7 @@ static int encode_frame(struct stm32_venc_data *data) } break; default: - LOG_ERR("H264EncStrmEncode error=%d", ret); + LOG_ERR("H264EncStrmEncode error=%d", h264ret); LOG_ERR("error encoding frame %d", data->frame_nb); encoder_end(data); From 1979291370d2288d6a1db6aa436dac22c2a115c6 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 20 Oct 2025 14:23:25 +0200 Subject: [PATCH 364/397] drivers: video: stm32_venc: log an error in case of hardware timeout Log an error in case of hardware timeout. Signed-off-by: Hugues Fruchet --- drivers/video/video_stm32_venc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/video/video_stm32_venc.c b/drivers/video/video_stm32_venc.c index a128442742e0a..5b585eaee6040 100644 --- a/drivers/video/video_stm32_venc.c +++ b/drivers/video/video_stm32_venc.c @@ -326,7 +326,7 @@ i32 EWLWaitHwRdy(const void *instance, uint32_t *slicesReady) { struct stm32_venc_ewl *inst = (struct stm32_venc_ewl *)instance; const struct stm32_venc_config *config = inst->config; - uint32_t ret = EWL_HW_WAIT_TIMEOUT; + int32_t ret = EWL_HW_WAIT_TIMEOUT; volatile uint32_t irq_stats; uint32_t prevSlicesReady = 0; k_timepoint_t timeout = sys_timepoint_calc(K_MSEC(EWL_TIMEOUT)); @@ -380,13 +380,18 @@ i32 EWLWaitHwRdy(const void *instance, uint32_t *slicesReady) } while (!sys_timepoint_expired(timeout)); + if (ret != EWL_OK) { + LOG_ERR("Timeout"); + return ret; + } + LOG_DBG("encoding = %d ms", k_ticks_to_ms_ceil32(sys_clock_tick_get_32() - start)); if (slicesReady != NULL) { LOG_DBG("slicesReady = %d", *slicesReady); } - return ret; + return EWL_OK; } void EWLassert(bool expr, const char *str_expr, const char *file, unsigned int line) From 0fd2f776eb0f4fbb8eb3cb05078b401e41b7e769 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 20 Oct 2025 14:21:42 +0200 Subject: [PATCH 365/397] drivers: video: stm32_venc: fix coding style Fix coding style issues in venc video driver. Signed-off-by: Hugues Fruchet --- drivers/video/video_stm32_venc.c | 86 ++++++++++++++++---------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/video/video_stm32_venc.c b/drivers/video/video_stm32_venc.c index 5b585eaee6040..082ee0bc01dc0 100644 --- a/drivers/video/video_stm32_venc.c +++ b/drivers/video/video_stm32_venc.c @@ -322,26 +322,26 @@ int EWLmemcmp(const void *s1, const void *s2, uint32_t n) return memcmp(s1, s2, n); } -i32 EWLWaitHwRdy(const void *instance, uint32_t *slicesReady) +i32 EWLWaitHwRdy(const void *instance, uint32_t *slices_ready) { struct stm32_venc_ewl *inst = (struct stm32_venc_ewl *)instance; const struct stm32_venc_config *config = inst->config; int32_t ret = EWL_HW_WAIT_TIMEOUT; volatile uint32_t irq_stats; - uint32_t prevSlicesReady = 0; + uint32_t prev_slices_ready = 0; k_timepoint_t timeout = sys_timepoint_calc(K_MSEC(EWL_TIMEOUT)); uint32_t start = sys_clock_tick_get_32(); __ASSERT_NO_MSG(inst != NULL); /* check how to clear IRQ flags for VENC */ - uint32_t clrByWrite1 = EWLReadReg(inst, BASE_HWFuse2) & HWCFGIrqClearSupport; + uint32_t clr_by_write_1 = EWLReadReg(inst, BASE_HWFuse2) & HWCFGIrqClearSupport; do { irq_stats = sys_read32(config->reg + BASE_HEncIRQ); /* get the number of completed slices from ASIC registers. */ - if (slicesReady != NULL && *slicesReady > prevSlicesReady) { - *slicesReady = FIELD_GET(NUM_SLICES_READY_MASK, + if (slices_ready != NULL && *slices_ready > prev_slices_ready) { + *slices_ready = FIELD_GET(NUM_SLICES_READY_MASK, sys_read32(config->reg + BASE_HEncControl7)); } @@ -362,7 +362,7 @@ i32 EWLWaitHwRdy(const void *instance, uint32_t *slicesReady) irq_stats &= ~(ASIC_STATUS_SLICE_READY | ASIC_IRQ_LINE); - if (clrByWrite1 != 0UL) { + if (clr_by_write_1 != 0UL) { clr_stats = ASIC_STATUS_SLICE_READY | ASIC_IRQ_LINE; } else { clr_stats = irq_stats; @@ -373,7 +373,7 @@ i32 EWLWaitHwRdy(const void *instance, uint32_t *slicesReady) break; } - if (slicesReady != NULL && *slicesReady > prevSlicesReady) { + if (slices_ready != NULL && *slices_ready > prev_slices_ready) { ret = EWL_OK; break; } @@ -387,8 +387,8 @@ i32 EWLWaitHwRdy(const void *instance, uint32_t *slicesReady) LOG_DBG("encoding = %d ms", k_ticks_to_ms_ceil32(sys_clock_tick_get_32() - start)); - if (slicesReady != NULL) { - LOG_DBG("slicesReady = %d", *slicesReady); + if (slices_ready != NULL) { + LOG_DBG("slices_ready = %d", *slices_ready); } return EWL_OK; @@ -554,21 +554,21 @@ static int encoder_prepare(struct stm32_venc_data *data) static int encoder_start(struct stm32_venc_data *data, struct video_buffer *output) { H264EncRet h264ret; - H264EncIn encIn = {0}; - H264EncOut encOut = {0}; + H264EncIn enc_in = {0}; + H264EncOut enc_out = {0}; - encIn.pOutBuf = (uint32_t *)output->buffer; - encIn.busOutBuf = (uint32_t)encIn.pOutBuf; - encIn.outBufSize = output->size; + enc_in.pOutBuf = (uint32_t *)output->buffer; + enc_in.busOutBuf = (uint32_t)enc_in.pOutBuf; + enc_in.outBufSize = output->size; /* create stream */ - h264ret = H264EncStrmStart(data->encoder, &encIn, &encOut); + h264ret = H264EncStrmStart(data->encoder, &enc_in, &enc_out); if (h264ret != H264ENC_OK) { LOG_ERR("H264EncStrmStart error=%d", h264ret); return -EIO; } - output->bytesused = encOut.streamSize; + output->bytesused = enc_out.streamSize; LOG_DBG("SPS/PPS generated, size= %d", output->bytesused); data->resync = true; @@ -578,11 +578,11 @@ static int encoder_start(struct stm32_venc_data *data, struct video_buffer *outp static int encoder_end(struct stm32_venc_data *data) { - H264EncIn encIn = {0}; - H264EncOut encOut = {0}; + H264EncIn enc_in = {0}; + H264EncOut enc_out = {0}; if (data->encoder != NULL) { - H264EncStrmEnd(data->encoder, &encIn, &encOut); + H264EncStrmEnd(data->encoder, &enc_in, &enc_out); data->encoder = NULL; } @@ -595,8 +595,8 @@ static int encode_frame(struct stm32_venc_data *data) H264EncRet h264ret = H264ENC_FRAME_READY; struct video_buffer *input; struct video_buffer *output; - H264EncIn encIn = {0}; - H264EncOut encOut = {0}; + H264EncIn enc_in = {0}; + H264EncOut enc_out = {0}; if (k_fifo_is_empty(&data->in_fifo_in) || k_fifo_is_empty(&data->out_fifo_in)) { /* Encoding deferred to next buffer queueing */ @@ -624,38 +624,38 @@ static int encode_frame(struct stm32_venc_data *data) /* one key frame every seconds */ if ((data->frame_nb % VENC_DEFAULT_FRAMERATE) == 0 || data->resync) { /* if frame is the first or resync needed: set as intra coded */ - encIn.codingType = H264ENC_INTRA_FRAME; + enc_in.codingType = H264ENC_INTRA_FRAME; } else { /* if there was a frame previously, set as predicted */ - encIn.timeIncrement = 1; - encIn.codingType = H264ENC_PREDICTED_FRAME; + enc_in.timeIncrement = 1; + enc_in.codingType = H264ENC_PREDICTED_FRAME; } - encIn.ipf = H264ENC_REFERENCE_AND_REFRESH; - encIn.ltrf = H264ENC_REFERENCE; + enc_in.ipf = H264ENC_REFERENCE_AND_REFRESH; + enc_in.ltrf = H264ENC_REFERENCE; /* set input buffers to structures */ - encIn.busLuma = (ptr_t)input->buffer; - encIn.busChromaU = (ptr_t)encIn.busLuma + data->in_fmt.width * data->in_fmt.height; + enc_in.busLuma = (ptr_t)input->buffer; + enc_in.busChromaU = (ptr_t)enc_in.busLuma + data->in_fmt.width * data->in_fmt.height; - encIn.pOutBuf = (uint32_t *)output->buffer; - encIn.busOutBuf = (uint32_t)encIn.pOutBuf; - encIn.outBufSize = output->size; - encOut.streamSize = 0; + enc_in.pOutBuf = (uint32_t *)output->buffer; + enc_in.busOutBuf = (uint32_t)enc_in.pOutBuf; + enc_in.outBufSize = output->size; + enc_out.streamSize = 0; - h264ret = H264EncStrmEncode(data->encoder, &encIn, &encOut, NULL, NULL, NULL); - output->bytesused = encOut.streamSize; - LOG_DBG("output=%p, encOut.streamSize=%d", output, encOut.streamSize); + h264ret = H264EncStrmEncode(data->encoder, &enc_in, &enc_out, NULL, NULL, NULL); + output->bytesused = enc_out.streamSize; + LOG_DBG("output=%p, enc_out.streamSize=%d", output, enc_out.streamSize); switch (h264ret) { case H264ENC_FRAME_READY: /* save stream */ - if (encOut.streamSize == 0) { + if (enc_out.streamSize == 0) { /* Nothing encoded */ data->resync = true; goto out; } - output->bytesused = encOut.streamSize; + output->bytesused = enc_out.streamSize; break; case H264ENC_FUSE_ERROR: LOG_ERR("H264EncStrmEncode error=%d", h264ret); @@ -841,19 +841,19 @@ static const struct stm32_venc_config stm32_venc_config_0 = { .irq_config = stm32_venc_irq_config_func, }; -static void RISAF_Config(void) +static void risaf_config(void) { /* Define and initialize the master configuration structure */ - RIMC_MasterConfig_t RIMC_master = {0}; + RIMC_MasterConfig_t rimc_master = {0}; /* Enable the clock for the RIFSC (RIF Security Controller) */ __HAL_RCC_RIFSC_CLK_ENABLE(); - RIMC_master.MasterCID = RIF_CID_1; - RIMC_master.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV; + rimc_master.MasterCID = RIF_CID_1; + rimc_master.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV; /* Configure the master attributes for the video encoder peripheral (VENC) */ - HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_VENC, &RIMC_master); + HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_VENC, &rimc_master); /* Set the secure and privileged attributes for the VENC as a slave */ HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_VENC, @@ -890,7 +890,7 @@ static int stm32_venc_init(const struct device *dev) /* Run IRQ init */ config->irq_config(dev); - RISAF_Config(); + risaf_config(); LOG_DBG("CPU frequency : %d", HAL_RCC_GetCpuClockFreq() / 1000000); LOG_DBG("sysclk frequency : %d", HAL_RCC_GetSysClockFreq() / 1000000); From 1a168c1af19808382f443fb401637f8e3e4f598e Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Mon, 20 Oct 2025 11:26:08 +0200 Subject: [PATCH 366/397] dts: arm: silabs: Add rtcc and sysrtc bindings Different Series 2 devices have different RTC IPs, despite sharing a HAL driver. Introduce separate bindings for the different IPs, and use a chosen node to select the node to use for timekeeping. A chosen node was selected over a nodelabel since chosen nodes can be overridden by board-level dts and devicetree overlays, while nodelabels can't. Signed-off-by: Aksel Skauge Mellbye --- .../sparkfun_thing_plus_matter_mgm240p.dts | 2 +- dts/arm/silabs/siwg917.dtsi | 5 +++-- dts/arm/silabs/xg21/xg21.dtsi | 5 +++-- dts/arm/silabs/xg22/xg22.dtsi | 5 +++-- dts/arm/silabs/xg23/xg23.dtsi | 5 +++-- dts/arm/silabs/xg24/xg24.dtsi | 5 +++-- dts/arm/silabs/xg27/xg27.dtsi | 5 +++-- dts/arm/silabs/xg28/xg28.dtsi | 5 +++-- dts/arm/silabs/xg29/xg29.dtsi | 5 +++-- dts/bindings/rtc/silabs,rtcc.yaml | 16 ++++++++++++++++ dts/bindings/rtc/silabs,sysrtc.yaml | 18 ++++++++++++++++++ 11 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 dts/bindings/rtc/silabs,rtcc.yaml create mode 100644 dts/bindings/rtc/silabs,sysrtc.yaml diff --git a/boards/sparkfun/thing_plus_matter_mgm240p/sparkfun_thing_plus_matter_mgm240p.dts b/boards/sparkfun/thing_plus_matter_mgm240p/sparkfun_thing_plus_matter_mgm240p.dts index 2b76d423cafe6..26dcdf0123be9 100644 --- a/boards/sparkfun/thing_plus_matter_mgm240p/sparkfun_thing_plus_matter_mgm240p.dts +++ b/boards/sparkfun/thing_plus_matter_mgm240p/sparkfun_thing_plus_matter_mgm240p.dts @@ -183,7 +183,7 @@ zephyr_i2c: &i2c0 { status = "okay"; }; -&stimer0 { +&sysrtc0 { status = "okay"; }; diff --git a/dts/arm/silabs/siwg917.dtsi b/dts/arm/silabs/siwg917.dtsi index 218fbe89c1268..561e9051c57de 100644 --- a/dts/arm/silabs/siwg917.dtsi +++ b/dts/arm/silabs/siwg917.dtsi @@ -11,6 +11,7 @@ / { chosen { + silabs,sleeptimer = &sysrtc0; zephyr,sram = &sram0; zephyr,entropy = &rng0; zephyr,flash = &flash0; @@ -363,8 +364,8 @@ status = "disabled"; }; - sysrtc0: stimer0: sysrtc@24048c00 { - compatible = "silabs,gecko-stimer"; + sysrtc0: sysrtc@24048c00 { + compatible = "silabs,sysrtc"; reg = <0x24048c00 0x78>; interrupts = <22 0>; interrupt-names = "sysrtc"; diff --git a/dts/arm/silabs/xg21/xg21.dtsi b/dts/arm/silabs/xg21/xg21.dtsi index 8356421e8a780..5bdfed4857cf0 100644 --- a/dts/arm/silabs/xg21/xg21.dtsi +++ b/dts/arm/silabs/xg21/xg21.dtsi @@ -16,6 +16,7 @@ / { chosen { + silabs,sleeptimer = &rtcc0; zephyr,entropy = &se; zephyr,flash-controller = &msc; }; @@ -448,8 +449,8 @@ status = "disabled"; }; - rtcc0: stimer0: rtcc@58000000 { - compatible = "silabs,gecko-stimer"; + rtcc0: rtcc@58000000 { + compatible = "silabs,rtcc"; reg = <0x58000000 0x4000>; clock-frequency = <32768>; clocks = <&cmu CLOCK_AUTO CLOCK_BRANCH_RTCCCLK>; diff --git a/dts/arm/silabs/xg22/xg22.dtsi b/dts/arm/silabs/xg22/xg22.dtsi index 0177e3f85dd54..0b2873ff5ed7b 100644 --- a/dts/arm/silabs/xg22/xg22.dtsi +++ b/dts/arm/silabs/xg22/xg22.dtsi @@ -15,6 +15,7 @@ / { chosen { + silabs,sleeptimer = &rtcc0; zephyr,entropy = &trng; zephyr,flash-controller = &msc; }; @@ -491,8 +492,8 @@ status = "disabled"; }; - rtcc0: stimer0: rtcc@58000000 { - compatible = "silabs,gecko-stimer"; + rtcc0: rtcc@58000000 { + compatible = "silabs,rtcc"; reg = <0x58000000 0x4000>; clock-frequency = <32768>; clocks = <&cmu CLOCK_RTCC CLOCK_BRANCH_RTCCCLK>; diff --git a/dts/arm/silabs/xg23/xg23.dtsi b/dts/arm/silabs/xg23/xg23.dtsi index 93bc1006d6f6b..9d29801be79a9 100644 --- a/dts/arm/silabs/xg23/xg23.dtsi +++ b/dts/arm/silabs/xg23/xg23.dtsi @@ -15,6 +15,7 @@ / { chosen { + silabs,sleeptimer = &sysrtc0; zephyr,entropy = &se; zephyr,flash-controller = &msc; }; @@ -511,8 +512,8 @@ status = "disabled"; }; - sysrtc0: stimer0: sysrtc@500a8000 { - compatible = "silabs,gecko-stimer"; + sysrtc0: sysrtc@500a8000 { + compatible = "silabs,sysrtc"; reg = <0x500a8000 0x4000>; clock-frequency = <32768>; clocks = <&cmu CLOCK_SYSRTC0 CLOCK_BRANCH_SYSRTCCLK>; diff --git a/dts/arm/silabs/xg24/xg24.dtsi b/dts/arm/silabs/xg24/xg24.dtsi index da17df1f25f3b..9b31a8b42c8aa 100644 --- a/dts/arm/silabs/xg24/xg24.dtsi +++ b/dts/arm/silabs/xg24/xg24.dtsi @@ -15,6 +15,7 @@ / { chosen { + silabs,sleeptimer = &sysrtc0; zephyr,entropy = &se; zephyr,flash-controller = &msc; }; @@ -494,8 +495,8 @@ status = "disabled"; }; - sysrtc0: stimer0: sysrtc@500a8000 { - compatible = "silabs,gecko-stimer"; + sysrtc0: sysrtc@500a8000 { + compatible = "silabs,sysrtc"; reg = <0x500a8000 0x4000>; clock-frequency = <32768>; clocks = <&cmu CLOCK_SYSRTC0 CLOCK_BRANCH_SYSRTCCLK>; diff --git a/dts/arm/silabs/xg27/xg27.dtsi b/dts/arm/silabs/xg27/xg27.dtsi index 1f97b67cd50ea..f479fbd8a2521 100644 --- a/dts/arm/silabs/xg27/xg27.dtsi +++ b/dts/arm/silabs/xg27/xg27.dtsi @@ -15,6 +15,7 @@ / { chosen { + silabs,sleeptimer = &rtcc0; zephyr,entropy = &trng; zephyr,flash-controller = &msc; }; @@ -491,8 +492,8 @@ status = "disabled"; }; - rtcc0: stimer0: rtcc@58000000 { - compatible = "silabs,gecko-stimer"; + rtcc0: rtcc@58000000 { + compatible = "silabs,rtcc"; reg = <0x58000000 0x4000>; clock-frequency = <32768>; clocks = <&cmu CLOCK_RTCC CLOCK_BRANCH_RTCCCLK>; diff --git a/dts/arm/silabs/xg28/xg28.dtsi b/dts/arm/silabs/xg28/xg28.dtsi index 92a188f1acbd0..6f9863472bebe 100644 --- a/dts/arm/silabs/xg28/xg28.dtsi +++ b/dts/arm/silabs/xg28/xg28.dtsi @@ -15,6 +15,7 @@ / { chosen { + silabs,sleeptimer = &sysrtc0; zephyr,entropy = &se; zephyr,flash-controller = &msc; }; @@ -511,8 +512,8 @@ status = "disabled"; }; - sysrtc0: stimer0: sysrtc@500a8000 { - compatible = "silabs,gecko-stimer"; + sysrtc0: sysrtc@500a8000 { + compatible = "silabs,sysrtc"; reg = <0x500a8000 0x4000>; clock-frequency = <32768>; clocks = <&cmu CLOCK_SYSRTC0 CLOCK_BRANCH_SYSRTCCLK>; diff --git a/dts/arm/silabs/xg29/xg29.dtsi b/dts/arm/silabs/xg29/xg29.dtsi index 17eb20f2a765a..93a5cb4bb28d3 100644 --- a/dts/arm/silabs/xg29/xg29.dtsi +++ b/dts/arm/silabs/xg29/xg29.dtsi @@ -14,6 +14,7 @@ / { chosen { + silabs,sleeptimer = &rtcc0; zephyr,entropy = &se; zephyr,flash-controller = &msc; }; @@ -505,8 +506,8 @@ status = "disabled"; }; - rtcc0: stimer0: rtcc@58000000 { - compatible = "silabs,gecko-stimer"; + rtcc0: rtcc@58000000 { + compatible = "silabs,rtcc"; reg = <0x58000000 0x4000>; clock-frequency = <32768>; clocks = <&cmu CLOCK_RTCC CLOCK_BRANCH_RTCCCLK>; diff --git a/dts/bindings/rtc/silabs,rtcc.yaml b/dts/bindings/rtc/silabs,rtcc.yaml new file mode 100644 index 0000000000000..a5eb71689fce3 --- /dev/null +++ b/dts/bindings/rtc/silabs,rtcc.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Silicon Labs Series 2 RTCC (Real Time Clock with Capture) + +description: | + The Real Time Clock with Capture (RTCC) is a 32-bit counter kept running down to energy mode EM3. + It can be used as an EM2/3 wakeup source as well as a timekeeping counter during low energy mode. + +compatible: "silabs,rtcc" + +include: rtc.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/rtc/silabs,sysrtc.yaml b/dts/bindings/rtc/silabs,sysrtc.yaml new file mode 100644 index 0000000000000..7391c733d9ea7 --- /dev/null +++ b/dts/bindings/rtc/silabs,sysrtc.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2025 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +title: Silicon Labs Series 2 SYSRTC (System Real Time Clock) + +description: | + The SYSRTC (System Real Time Counter) is a 32-bit counter kept running down to energy mode EM3. + It can be used as a sleep timer / wakeup source as well as a timekeeping counter during low energy + modes. Multiple groups of capture / compare registers are available to different cores in the + system, allowing the peripheral and time base to be shared across cores and save energy. + +compatible: "silabs,sysrtc" + +include: rtc.yaml + +properties: + reg: + required: true From 31f91af9f2d4409f869e27ec6e114056f662c8e6 Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Mon, 20 Oct 2025 11:30:13 +0200 Subject: [PATCH 367/397] drivers: timer: silabs_sleeptimer: Use chosen node Use the `silabs,sleeptimer` chosen node instead of a devicetree compatible to select the devicetree node for the RTC. Signed-off-by: Aksel Skauge Mellbye --- drivers/timer/Kconfig.silabs | 4 +++- drivers/timer/silabs_sleeptimer_timer.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/timer/Kconfig.silabs b/drivers/timer/Kconfig.silabs index f84fa7ec8ccc9..813cae6c19bec 100644 --- a/drivers/timer/Kconfig.silabs +++ b/drivers/timer/Kconfig.silabs @@ -1,10 +1,12 @@ # Copyright (c) 2024 Silicon Laboratories Inc. # SPDX-License-Identifier: Apache-2.0 +DT_CHOSEN_SILABS_SLEEPTIMER := silabs,sleeptimer + config SILABS_SLEEPTIMER_TIMER bool "Silabs Sleeptimer system clock driver" depends on SOC_FAMILY_SILABS_S2 || SOC_FAMILY_SILABS_SIWX91X - depends on DT_HAS_SILABS_GECKO_STIMER_ENABLED + depends on $(dt_chosen_enabled,$(DT_CHOSEN_SILABS_SLEEPTIMER)) select SILABS_SISDK_SLEEPTIMER select TICKLESS_CAPABLE select TIMER_READS_ITS_FREQUENCY_AT_RUNTIME diff --git a/drivers/timer/silabs_sleeptimer_timer.c b/drivers/timer/silabs_sleeptimer_timer.c index d0e643d21bfa2..1313a095687ec 100644 --- a/drivers/timer/silabs_sleeptimer_timer.c +++ b/drivers/timer/silabs_sleeptimer_timer.c @@ -22,7 +22,7 @@ LOG_MODULE_REGISTER(silabs_sleeptimer_timer); /* Maximum time interval between timer interrupts (in hw_cycles) */ #define MAX_TIMEOUT_CYC (UINT32_MAX >> 1) -#define DT_RTC DT_COMPAT_GET_ANY_STATUS_OKAY(silabs_gecko_stimer) +#define DT_RTC DT_CHOSEN(silabs_sleeptimer) /* Ensure interrupt names don't expand to register interface struct pointers */ #undef RTCC From eb243e66f42ab584ea3f8f6134c9d5f0ad70873c Mon Sep 17 00:00:00 2001 From: Aksel Skauge Mellbye Date: Mon, 20 Oct 2025 11:34:09 +0200 Subject: [PATCH 368/397] drivers: counter: gecko_stimer: Use chosen node Use the `silabs,sleeptimer` chosen node instead of a devicetree compatible to select the devicetree node for the counter. Signed-off-by: Aksel Skauge Mellbye --- drivers/counter/Kconfig.gecko | 4 +++- drivers/counter/counter_gecko_stimer.c | 16 +++++++--------- .../counter/counter_basic_api/src/test_counter.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/counter/Kconfig.gecko b/drivers/counter/Kconfig.gecko index 529d2f8b5bf3f..ce2459e1a6c87 100644 --- a/drivers/counter/Kconfig.gecko +++ b/drivers/counter/Kconfig.gecko @@ -3,6 +3,8 @@ # Copyright (c) 2019, Piotr Mienkowski # SPDX-License-Identifier: Apache-2.0 +DT_CHOSEN_SILABS_SLEEPTIMER := silabs,sleeptimer + config COUNTER_GECKO_RTCC bool "Silicon Labs Gecko Counter (RTCC) driver" default y @@ -16,7 +18,7 @@ config COUNTER_GECKO_RTCC config COUNTER_GECKO_STIMER bool "Silicon Labs Gecko Counter Sleep Timer driver" default y - depends on DT_HAS_SILABS_GECKO_STIMER_ENABLED + depends on $(dt_chosen_enabled,$(DT_CHOSEN_SILABS_SLEEPTIMER)) select SILABS_SISDK_SLEEPTIMER help Enable the counter driver for Sleep Timer module for Silicon Labs diff --git a/drivers/counter/counter_gecko_stimer.c b/drivers/counter/counter_gecko_stimer.c index 029ccd2d920e4..63060f4f47f40 100644 --- a/drivers/counter/counter_gecko_stimer.c +++ b/drivers/counter/counter_gecko_stimer.c @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT silabs_gecko_stimer - #include #include #include @@ -21,7 +19,7 @@ LOG_MODULE_REGISTER(counter_gecko, CONFIG_COUNTER_LOG_LEVEL); -#define DT_RTC DT_COMPAT_GET_ANY_STATUS_OKAY(silabs_gecko_stimer) +#define DT_RTC DT_CHOSEN(silabs_sleeptimer) #define STIMER_ALARM_NUM 2 #define STIMER_MAX_VALUE 0xFFFFFFFFUL @@ -273,7 +271,7 @@ static DEVICE_API(counter, counter_gecko_driver_api) = { .get_top_value = counter_gecko_get_top_value, }; -BUILD_ASSERT((DT_INST_PROP(0, prescaler) > 0U) && (DT_INST_PROP(0, prescaler) <= 32768U)); +BUILD_ASSERT((DT_PROP(DT_RTC, prescaler) > 0U) && (DT_PROP(DT_RTC, prescaler) <= 32768U)); static void counter_gecko_0_irq_config(void) { @@ -281,22 +279,22 @@ static void counter_gecko_0_irq_config(void) IRQ_DIRECT_CONNECT(DT_IRQ(DT_RTC, irq), DT_IRQ(DT_RTC, priority), CONCAT(DT_STRING_UPPER_TOKEN_BY_IDX(DT_RTC, interrupt_names, 0), _IRQHandler), 0); - irq_enable(DT_INST_IRQN(0)); + irq_enable(DT_IRQN(DT_RTC)); #endif } static const struct counter_gecko_config counter_gecko_0_config = { .info = { .max_top_value = STIMER_MAX_VALUE, - .freq = DT_INST_PROP(0, clock_frequency) / DT_INST_PROP(0, prescaler), + .freq = DT_PROP(DT_RTC, clock_frequency) / DT_PROP(DT_RTC, prescaler), .flags = COUNTER_CONFIG_INFO_COUNT_UP, .channels = STIMER_ALARM_NUM, }, .irq_config = counter_gecko_0_irq_config, - .prescaler = DT_INST_PROP(0, prescaler), + .prescaler = DT_PROP(DT_RTC, prescaler), }; static struct counter_gecko_data counter_gecko_0_data; -DEVICE_DT_INST_DEFINE(0, counter_gecko_init, NULL, &counter_gecko_0_data, &counter_gecko_0_config, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &counter_gecko_driver_api); +DEVICE_DT_DEFINE(DT_RTC, counter_gecko_init, NULL, &counter_gecko_0_data, &counter_gecko_0_config, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &counter_gecko_driver_api); diff --git a/tests/drivers/counter/counter_basic_api/src/test_counter.c b/tests/drivers/counter/counter_basic_api/src/test_counter.c index 841853d3b7f0f..34406d88a3919 100644 --- a/tests/drivers/counter/counter_basic_api/src/test_counter.c +++ b/tests/drivers/counter/counter_basic_api/src/test_counter.c @@ -94,7 +94,7 @@ static const struct device *const devices[] = { DEVS_FOR_DT_COMPAT(st_stm32_rtc) #endif #ifdef CONFIG_COUNTER_GECKO_STIMER - DEVS_FOR_DT_COMPAT(silabs_gecko_stimer) + DEVICE_DT_GET(DT_CHOSEN(silabs_sleeptimer)), #endif #ifdef CONFIG_COUNTER_NXP_PIT DEVS_FOR_DT_COMPAT(nxp_pit_channel) From 540ce83d6e08afa9455c198816b5b2d9a9e1c146 Mon Sep 17 00:00:00 2001 From: Diego Herranz Date: Sun, 19 Oct 2025 15:42:08 +0200 Subject: [PATCH 369/397] boards: doc: use board-supported-hw directive in imx7-based boards Use the zephyr:board-supported-hw directive for the documentation of every imx7-based which board which didn't use it yet. Bonus: remove redundant image from 96boards/meerkat96. Signed-off-by: Diego Herranz --- boards/96boards/meerkat96/doc/index.rst | 28 ++-------------------- boards/technexion/pico_pi/doc/index.rst | 23 +----------------- boards/toradex/colibri_imx7d/doc/index.rst | 26 +------------------- 3 files changed, 4 insertions(+), 73 deletions(-) diff --git a/boards/96boards/meerkat96/doc/index.rst b/boards/96boards/meerkat96/doc/index.rst index c76229de75b4a..52238cf795f66 100644 --- a/boards/96boards/meerkat96/doc/index.rst +++ b/boards/96boards/meerkat96/doc/index.rst @@ -1,4 +1,4 @@ -.. _96b_meerkat96: +.. zephyr:board:: 96b_meerkat96 96Boards Meerkat96 ################## @@ -35,10 +35,6 @@ Zephyr OS is ported to run on the Cortex®-M4 core. - 1x Blue Bluetooth LED - 1x Yellow WiFi LED -.. image:: img/96b_meerkat96.jpg - :align: center - :alt: 96Boards Meerkat96 - More information about the board can be found at the `96Boards website`_. @@ -91,27 +87,7 @@ More information about the i.MX7 SoC can be found here: Supported Features ================== -The Zephyr 96b_meerkat96 board configuration supports the following hardware -features: - -+-----------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+=====================================+ -| NVIC | on-chip | nested vector interrupt controller | -+-----------+------------+-------------------------------------+ -| SYSTICK | on-chip | systick | -+-----------+------------+-------------------------------------+ -| GPIO | on-chip | gpio | -+-----------+------------+-------------------------------------+ -| UART | on-chip | serial port-polling; | -| | | serial port-interrupt | -+-----------+------------+-------------------------------------+ - -The default configuration can be found in the defconfig file: - - :zephyr_file:`boards/96boards/meerkat96/96b_meerkat96_mcimx7d_m4_defconfig` - -Other hardware features are not currently supported by the port. +.. zephyr:board-supported-hw:: Connections and IOs =================== diff --git a/boards/technexion/pico_pi/doc/index.rst b/boards/technexion/pico_pi/doc/index.rst index 530bc3a86afa1..b0b5f8c11d1f6 100644 --- a/boards/technexion/pico_pi/doc/index.rst +++ b/boards/technexion/pico_pi/doc/index.rst @@ -44,28 +44,7 @@ For more information about the i.MX7 SoC and Pico-Pi i.MX7D, see these reference Supported Features ================== -The Pico-Pi i.MX7D configuration supports the following hardware features on the -Cortex M4 Core: - -+-----------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+=====================================+ -| NVIC | on-chip | nested vector interrupt controller | -+-----------+------------+-------------------------------------+ -| SYSTICK | on-chip | systick | -+-----------+------------+-------------------------------------+ -| GPIO | on-chip | gpio | -+-----------+------------+-------------------------------------+ -| I2C | on-chip | i2c | -+-----------+------------+-------------------------------------+ -| UART | on-chip | serial port-polling; | -| | | serial port-interrupt | -+-----------+------------+-------------------------------------+ - -The default configuration can be found in the defconfig file: -:zephyr_file:`boards/technexion/pico_pi/pico_pi_mcimx7d_m4_defconfig` - -Other hardware features are not currently supported by the port. +.. zephyr:board-supported-hw:: Connections and IOs =================== diff --git a/boards/toradex/colibri_imx7d/doc/index.rst b/boards/toradex/colibri_imx7d/doc/index.rst index c381a39a49657..c05d61e0110e5 100644 --- a/boards/toradex/colibri_imx7d/doc/index.rst +++ b/boards/toradex/colibri_imx7d/doc/index.rst @@ -61,31 +61,7 @@ and Colibri Evaluation Board, see these references: Supported Features ================== -The Colibri iMX7D Computer on Module with Colibri Evaluation Board configuration -supports the following hardware features on the Cortex M4 Core: - -+-----------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+=====================================+ -| NVIC | on-chip | nested vector interrupt controller | -+-----------+------------+-------------------------------------+ -| SYSTICK | on-chip | systick | -+-----------+------------+-------------------------------------+ -| GPIO | on-chip | gpio | -+-----------+------------+-------------------------------------+ -| I2C | on-chip | i2c | -+-----------+------------+-------------------------------------+ -| PWM | on-chip | pwm | -+-----------+------------+-------------------------------------+ -| UART | on-chip | serial port-polling; | -| | | serial port-interrupt | -+-----------+------------+-------------------------------------+ - -The default configuration can be found in the defconfig file: - - :zephyr_file:`boards/toradex/colibri_imx7d/colibri_imx7d_mcimx7d_m4_defconfig` - -Other hardware features are not currently supported by the port. +.. zephyr:board-supported-hw:: Connections and IOs =================== From 339e569881d7d1aad66d62b18e023362d5e8b70c Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Tue, 22 Oct 2024 22:21:42 +0300 Subject: [PATCH 370/397] drivers: pwm: cc23x0: Add power management Add PM support for PWM (LGPT0, LGPT1, LGPT2 and LGPT3) to cc23x0 SoC. Signed-off-by: Stoyan Bogdanov --- drivers/pwm/pwm_cc23x0_timer.c | 61 ++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/pwm_cc23x0_timer.c b/drivers/pwm/pwm_cc23x0_timer.c index b74975d921e2b..d0a3f97caa399 100644 --- a/drivers/pwm/pwm_cc23x0_timer.c +++ b/drivers/pwm/pwm_cc23x0_timer.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include @@ -34,6 +36,22 @@ struct pwm_cc23x0_config { const struct pinctrl_dev_config *pcfg; }; +static inline void pwm_cc23x0_pm_policy_state_lock_get(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +#endif +} + +static inline void pwm_cc23x0_pm_policy_state_lock_put(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); +#endif +} + static int pwm_cc23x0_set_cycles(const struct device *dev, uint32_t channel, uint32_t period, uint32_t pulse, pwm_flags_t flags) { @@ -41,6 +59,10 @@ static int pwm_cc23x0_set_cycles(const struct device *dev, uint32_t channel, uin LOG_DBG("set cycles period[%x] pulse[%x]", period, pulse); + if (pulse == 0) { + pwm_cc23x0_pm_policy_state_lock_get(); + } + if ((config->base != LGPT3_BASE) && (pulse > 0xffff || period > 0xffff || pulse > period)) { /* LGPT0, LGPT1, LGPT2 - 16bit counters */ LOG_ERR("Period of pulse out of range"); @@ -72,6 +94,10 @@ static int pwm_cc23x0_set_cycles(const struct device *dev, uint32_t channel, uin /* Activate LGPT */ HWREG(config->base + LGPT_O_STARTCFG) = 0x1; + if (pulse > 0) { + pwm_cc23x0_pm_policy_state_lock_put(); + } + return 0; } @@ -90,7 +116,7 @@ static const struct pwm_driver_api pwm_cc23x0_driver_api = { .get_cycles_per_sec = pwm_cc23x0_get_cycles_per_sec, }; -static int pwm_cc23x0_activate_clock(const struct device *dev) +static int pwm_cc23x0_clock_action(const struct device *dev, bool activate) { const struct pwm_cc23x0_config *config = dev->config; struct pwm_cc23x0_data *data = dev->data; @@ -113,13 +139,35 @@ static int pwm_cc23x0_activate_clock(const struct device *dev) return -EINVAL; } - CLKCTLEnable(CLKCTL_BASE, lgpt_clk_id); - HWREG(config->base + LGPT_O_PRECFG) = LGPT_CLK_PRESCALE(data->prescale); - HWREG(EVTSVT_BASE + EVTSVT_O_LGPTSYNCSEL) = EVTSVT_LGPTSYNCSEL_PUBID_SYSTIM0; + if (activate) { + CLKCTLEnable(CLKCTL_BASE, lgpt_clk_id); + HWREG(config->base + LGPT_O_PRECFG) = LGPT_CLK_PRESCALE(data->prescale); + HWREG(EVTSVT_BASE + EVTSVT_O_LGPTSYNCSEL) = EVTSVT_LGPTSYNCSEL_PUBID_SYSTIM0; + } else { + CLKCTLDisable(CLKCTL_BASE, lgpt_clk_id); + } return 0; } +#ifdef CONFIG_PM_DEVICE + +static int pwm_cc23x0_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + pwm_cc23x0_clock_action(dev, false); + return 0; + case PM_DEVICE_ACTION_RESUME: + pwm_cc23x0_clock_action(dev, true); + return 0; + default: + return -ENOTSUP; + } +} + +#endif /* CONFIG_PM_DEVICE */ + #define DT_TIMER(idx) DT_INST_PARENT(idx) #define DT_TIMER_BASE_ADDR(idx) (DT_REG_ADDR(DT_TIMER(idx))) @@ -137,12 +185,13 @@ static int pwm_cc23x0_init(const struct device *dev) return ret; } - pwm_cc23x0_activate_clock(dev); + pwm_cc23x0_clock_action(dev, true); return 0; } #define PWM_DEVICE_INIT(idx) \ + PM_DEVICE_DT_INST_DEFINE(idx, pwm_cc23x0_pm_action); \ PINCTRL_DT_INST_DEFINE(idx); \ LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, CONFIG_PWM_LOG_LEVEL); \ \ @@ -156,7 +205,7 @@ static int pwm_cc23x0_init(const struct device *dev) .base_clk = DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency), \ }; \ \ - DEVICE_DT_INST_DEFINE(idx, pwm_cc23x0_init, NULL, &pwm_cc23x0_##idx##_data, \ + DEVICE_DT_INST_DEFINE(idx, pwm_cc23x0_init, NULL, &pwm_cc23x0_##idx##_data, \ &pwm_cc23x0_##idx##_config, POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \ &pwm_cc23x0_driver_api) From adf6dc9b748ca1721740dc85daf6688c632b9ee7 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Tue, 22 Oct 2024 16:00:37 +0300 Subject: [PATCH 371/397] drivers: i2c: cc23x0: Add power management Add PM support to cc23x0 I2C. Signed-off-by: Stoyan Bogdanov --- drivers/i2c/i2c_cc23x0.c | 76 +++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/i2c_cc23x0.c b/drivers/i2c/i2c_cc23x0.c index 50668a9cbfe12..eb2db11ab3a3d 100644 --- a/drivers/i2c/i2c_cc23x0.c +++ b/drivers/i2c/i2c_cc23x0.c @@ -30,6 +30,7 @@ struct i2c_cc23x0_data { struct k_sem lock; struct k_sem complete; volatile uint32_t error; + uint32_t cfg; }; struct i2c_cc23x0_config { @@ -37,6 +38,22 @@ struct i2c_cc23x0_config { const struct pinctrl_dev_config *pcfg; }; +static inline void i2c_cc23x0_pm_policy_state_lock_get(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +#endif +} + +static inline void i2c_cc23x0_pm_policy_state_lock_put(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +#endif +} + static int i2c_cc23x0_transmit(const struct device *dev, const uint8_t *buf, uint32_t len, uint16_t addr) { @@ -53,7 +70,7 @@ static int i2c_cc23x0_transmit(const struct device *dev, const uint8_t *buf, uin /* Single transmission */ if (len == 1) { - I2CControllerPutData(base, *buf); + I2CControllerPutData(base, buf[0]); I2CControllerCommand(base, I2C_CONTROLLER_CMD_SINGLE_SEND); k_sem_take(&data->complete, K_FOREVER); return data->error == I2C_MASTER_ERR_NONE ? 0 : -EIO; @@ -103,18 +120,19 @@ static int i2c_cc23x0_receive(const struct device *dev, uint8_t *buf, uint32_t l if (len == 0) { return -EIO; } - I2CControllerSetTargetAddr(base, addr, true); + I2CControllerSetTargetAddr(base, addr, true); /* Single receive */ if (len == 1) { + buf[0] = I2CControllerGetData(base); I2CControllerCommand(base, I2C_CONTROLLER_CMD_SINGLE_RECEIVE); + k_sem_take(&data->complete, K_FOREVER); if (data->error != I2C_MASTER_ERR_NONE) { return -EIO; } - - *buf = I2CControllerGetData(base); + buf[0] = I2CControllerGetData(base); return 0; } @@ -127,7 +145,6 @@ static int i2c_cc23x0_receive(const struct device *dev, uint8_t *buf, uint32_t l } buf[0] = I2CControllerGetData(base); - for (int i = 1; i < len - 1; i++) { I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_RECEIVE_CONT); k_sem_take(&data->complete, K_FOREVER); @@ -159,6 +176,7 @@ static int i2c_cc23x0_transfer(const struct device *dev, struct i2c_msg *msgs, u uint16_t addr) { struct i2c_cc23x0_data *data = dev->data; + const struct i2c_cc23x0_config *config = dev->config; int ret = 0; if (num_msgs == 0) { @@ -167,6 +185,8 @@ static int i2c_cc23x0_transfer(const struct device *dev, struct i2c_msg *msgs, u k_sem_take(&data->lock, K_FOREVER); + i2c_cc23x0_pm_policy_state_lock_get(); + for (int i = 0; i < num_msgs; i++) { /* Not supported by hardware */ if (msgs[i].flags & I2C_MSG_ADDR_10_BITS) { @@ -184,6 +204,13 @@ static int i2c_cc23x0_transfer(const struct device *dev, struct i2c_msg *msgs, u break; } } + + while (I2CControllerBusy(config->base)) { + ; + } + + i2c_cc23x0_pm_policy_state_lock_put(); + k_sem_give(&data->lock); return ret; @@ -227,6 +254,33 @@ static int i2c_cc23x0_configure(const struct device *dev, uint32_t dev_config) return 0; } +#ifdef CONFIG_PM_DEVICE + +static int i2c_cc23x0_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct i2c_cc23x0_config *config = dev->config; + struct i2c_cc23x0_data *data = dev->data; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + I2CControllerDisable(config->base); + I2CControllerDisableInt(config->base); + CLKCTLDisable(CLKCTL_BASE, CLKCTL_I2C0); + break; + case PM_DEVICE_ACTION_RESUME: + CLKCTLEnable(CLKCTL_BASE, CLKCTL_I2C0); + i2c_cc23x0_configure(dev, data->cfg | I2C_MODE_CONTROLLER); + I2CControllerEnableInt(config->base); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +#endif /* CONFIG_PM_DEVICE */ + static void i2c_cc23x0_isr(const struct device *dev) { const struct i2c_cc23x0_config *config = dev->config; @@ -237,8 +291,12 @@ static void i2c_cc23x0_isr(const struct device *dev) I2CControllerClearInt(base); data->error = I2CControllerError(base); - - k_sem_give(&data->complete); + if (data->error) { + LOG_ERR("Error [%x]", data->error); + } + if (!I2CControllerBusy(config->base)) { + k_sem_give(&data->complete); + } } } @@ -290,8 +348,8 @@ static const struct i2c_driver_api i2c_cc23x0_driver_api = {.configure = i2c_cc2 .complete = Z_SEM_INITIALIZER(i2c_cc23x0_##id##_data.complete, 0, 1), \ .error = I2C_MASTER_ERR_NONE}; \ \ - I2C_DEVICE_DT_INST_DEFINE(id, i2c_cc23x0_init##id, NULL, &i2c_cc23x0_##id##_data, \ - &i2c_cc23x0_##id##_config, POST_KERNEL, \ + I2C_DEVICE_DT_INST_DEFINE(id, i2c_cc23x0_init##id, PM_DEVICE_DT_INST_GET(id), \ + &i2c_cc23x0_##id##_data, &i2c_cc23x0_##id##_config, POST_KERNEL, \ CONFIG_I2C_INIT_PRIORITY, &i2c_cc23x0_driver_api); DT_INST_FOREACH_STATUS_OKAY(CC23X0_I2C); From 2db4fbda66b9b5a19a85b39423f4902f3a400e2e Mon Sep 17 00:00:00 2001 From: Siratul Islam Date: Fri, 17 Oct 2025 05:43:03 +0600 Subject: [PATCH 372/397] boards: arm: Rename WeAct STM32U585 Update board.yml for naming consistency throughout the weact family Signed-off-by: Siratul Islam --- boards/weact/blackpill_u585ci/board.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/weact/blackpill_u585ci/board.yml b/boards/weact/blackpill_u585ci/board.yml index 4abf4758c34bb..47697f740013c 100644 --- a/boards/weact/blackpill_u585ci/board.yml +++ b/boards/weact/blackpill_u585ci/board.yml @@ -1,6 +1,6 @@ board: name: blackpill_u585ci - full_name: WeAct Studio Black Pill STM32U585 Core Board + full_name: Black Pill STM32U585 vendor: weact socs: - name: stm32u585xx From 084edd5785a2b3c755d6b19605297ea3466400c8 Mon Sep 17 00:00:00 2001 From: Fabrice DJIATSA Date: Thu, 16 Oct 2025 15:39:39 +0200 Subject: [PATCH 373/397] drivers: clock_control: stm32: enable clocks for SRAM1 and SRAM2 enables the AHB2 peripheral clocks for SRAM1 and SRAM2 on STM32H7RSX series using LL_AHB2_GRP1_EnableClock. These clocks are required to access the corresponding SRAM regions during runtime. Fixes potential access faults when using SRAM1 and SRAM2. Signed-off-by: Fabrice DJIATSA --- drivers/clock_control/clock_stm32_ll_h7.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index 3b99555d1eead..2f0a581d24bec 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -1040,6 +1040,14 @@ int stm32_clock_control_init(const struct device *dev) #endif z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); +#if defined(CONFIG_SOC_SERIES_STM32H7RSX) +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sram1)) + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_AHBSRAM1); +#endif +#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(sram2)) + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_AHBSRAM2); +#endif +#endif /* Set up individual enabled clocks */ set_up_fixed_clock_sources(); From 9d521730ab77f1513e6d1ba2219e2e84df3f5492 Mon Sep 17 00:00:00 2001 From: Fabrice DJIATSA Date: Fri, 17 Oct 2025 12:09:45 +0200 Subject: [PATCH 374/397] dts: arm: st: h7rs: Add zephyr,memory-attr to SRAM1 and SRAM2 regions adds the `zephyr,memory-attr` property to the SRAM1 and SRAM2 memory nodes to explicitly define their MPU attributes as normal RAM. This ensures proper memory protection and caching behavior when these regions are used by the kernel or application. Resolve a Data Access Violation encountered during test, where the faulting address was 0x30000000. Note: add the zephyr,memory-attr property in the board overlay for SRAM2 to avoid conflict with the support of h7rs ethernet with MPU regions enabled. see link below for more details : https://github.com/zephyrproject-rtos/zephyr/pull/97364/files#r2439668915 Signed-off-by: Fabrice DJIATSA --- dts/arm/st/h7rs/stm32h7rs.dtsi | 6 ++++++ tests/drivers/memc/ram/boards/stm32h7s78_dk.overlay | 10 ++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/drivers/memc/ram/boards/stm32h7s78_dk.overlay diff --git a/dts/arm/st/h7rs/stm32h7rs.dtsi b/dts/arm/st/h7rs/stm32h7rs.dtsi index 8da85ea625c36..313706e57297d 100644 --- a/dts/arm/st/h7rs/stm32h7rs.dtsi +++ b/dts/arm/st/h7rs/stm32h7rs.dtsi @@ -61,6 +61,7 @@ reg = <0x30000000 DT_SIZE_K(16)>; compatible = "zephyr,memory-region", "mmio-sram"; zephyr,memory-region = "SRAM1"; + zephyr,memory-attr = ; }; /* System data RAM accessible over AHB bus: SRAM2 in D2 domain */ @@ -68,6 +69,11 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x30004000 DT_SIZE_K(16)>; zephyr,memory-region = "SRAM2"; + /* Disable SRAM2 by default to avoid unintended access. + * To enable it, explicitly define zephyr,memory-attr + * to configure MPU attributes. + */ + status = "disabled"; }; dtcm: memory@20000000 { diff --git a/tests/drivers/memc/ram/boards/stm32h7s78_dk.overlay b/tests/drivers/memc/ram/boards/stm32h7s78_dk.overlay new file mode 100644 index 0000000000000..9a7568844a39e --- /dev/null +++ b/tests/drivers/memc/ram/boards/stm32h7s78_dk.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&sram2 { + zephyr,memory-attr = ; + status = "okay"; +}; From a6e6a10c095d8ac624c745b8ecae6b20ca8ff0b6 Mon Sep 17 00:00:00 2001 From: Luis Ubieda Date: Thu, 2 Oct 2025 18:19:40 -0400 Subject: [PATCH 375/397] bmi08x: Add support for Read-decode and Streaming Mode One-shot reads through Read-Decode API matches functionality from Fetch-Get API, but asynchronously. Streaming mode supporting FIFO Watermark Interrupts. Works for both Gyro and Accel drivers. These changes are covered under the build-all test for sensor async api. Signed-off-by: Luis Ubieda --- drivers/sensor/bosch/bmi08x/CMakeLists.txt | 9 + drivers/sensor/bosch/bmi08x/Kconfig | 18 +- drivers/sensor/bosch/bmi08x/bmi08x.h | 124 +++++++++- drivers/sensor/bosch/bmi08x/bmi08x_accel.c | 48 +++- .../sensor/bosch/bmi08x/bmi08x_accel_async.c | 91 +++++++ .../sensor/bosch/bmi08x/bmi08x_accel_async.h | 16 ++ .../bosch/bmi08x/bmi08x_accel_decoder.c | 226 +++++++++++++++++ .../bosch/bmi08x/bmi08x_accel_decoder.h | 19 ++ .../sensor/bosch/bmi08x/bmi08x_accel_stream.c | 229 +++++++++++++++++ .../sensor/bosch/bmi08x/bmi08x_accel_stream.h | 17 ++ drivers/sensor/bosch/bmi08x/bmi08x_bus.c | 148 +++++++++++ drivers/sensor/bosch/bmi08x/bmi08x_bus.h | 39 +++ drivers/sensor/bosch/bmi08x/bmi08x_gyro.c | 57 ++++- .../sensor/bosch/bmi08x/bmi08x_gyro_async.c | 91 +++++++ .../sensor/bosch/bmi08x/bmi08x_gyro_async.h | 17 ++ .../sensor/bosch/bmi08x/bmi08x_gyro_decoder.c | 142 +++++++++++ .../sensor/bosch/bmi08x/bmi08x_gyro_decoder.h | 19 ++ .../sensor/bosch/bmi08x/bmi08x_gyro_stream.c | 231 ++++++++++++++++++ .../sensor/bosch/bmi08x/bmi08x_gyro_stream.h | 17 ++ dts/bindings/sensor/bosch,bmi08x-accel.yaml | 5 + dts/bindings/sensor/bosch,bmi08x-gyro.yaml | 5 + tests/drivers/build_all/sensor/i2c.dtsi | 2 + .../build_all/sensor/sensors_async_api.conf | 2 + tests/drivers/build_all/sensor/spi.dtsi | 2 + 24 files changed, 1558 insertions(+), 16 deletions(-) create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_accel_async.c create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_accel_async.h create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.c create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.h create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.c create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.h create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_bus.c create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_bus.h create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.c create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.h create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.c create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.h create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.c create mode 100644 drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.h diff --git a/drivers/sensor/bosch/bmi08x/CMakeLists.txt b/drivers/sensor/bosch/bmi08x/CMakeLists.txt index 0282cc73d2051..5899fedf05971 100644 --- a/drivers/sensor/bosch/bmi08x/CMakeLists.txt +++ b/drivers/sensor/bosch/bmi08x/CMakeLists.txt @@ -7,3 +7,12 @@ zephyr_library_sources(bmi08x_gyro.c) zephyr_library_sources(bmi08x.c) zephyr_library_sources_ifdef(CONFIG_BMI08X_ACCEL_TRIGGER bmi08x_accel_trigger.c) zephyr_library_sources_ifdef(CONFIG_BMI08X_GYRO_TRIGGER bmi08x_gyro_trigger.c) +zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API + bmi08x_bus.c + bmi08x_gyro_async.c + bmi08x_gyro_decoder.c + bmi08x_accel_async.c + bmi08x_accel_decoder.c +) +zephyr_library_sources_ifdef(CONFIG_BMI08X_GYRO_STREAM bmi08x_gyro_stream.c) +zephyr_library_sources_ifdef(CONFIG_BMI08X_ACCEL_STREAM bmi08x_accel_stream.c) diff --git a/drivers/sensor/bosch/bmi08x/Kconfig b/drivers/sensor/bosch/bmi08x/Kconfig index cbe40bf5c26e5..fc0a17baeda34 100644 --- a/drivers/sensor/bosch/bmi08x/Kconfig +++ b/drivers/sensor/bosch/bmi08x/Kconfig @@ -11,6 +11,8 @@ menuconfig BMI08X || $(dt_compat_on_bus,$(DT_COMPAT_BOSCH_BMI08X_GYRO),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_BOSCH_BMI08X_ACCEL),spi) \ || $(dt_compat_on_bus,$(DT_COMPAT_BOSCH_BMI08X_GYRO),spi) + select SPI_RTIO if SPI + select I2C_RTIO if I2C help Enable Bosch BMI08X inertial measurement unit that provides acceleration and angular rate measurements. @@ -19,7 +21,7 @@ if BMI08X choice BMI08X_ACCEL_TRIGGER_MODE prompt "Accelerometer trigger mode" - default BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD + default BMI08X_ACCEL_TRIGGER_NONE help Specify the type of triggering to be used by the driver. @@ -39,6 +41,13 @@ config BMI08X_ACCEL_TRIGGER_OWN_THREAD select BMI08X_ACCEL_TRIGGER endchoice +config BMI08X_ACCEL_STREAM + bool "Accelerometer Streaming Mode (FIFO)" + depends on !BMI08X_ACCEL_TRIGGER + depends on GPIO + depends on $(dt_compat_any_has_prop,$(DT_COMPAT_BOSCH_BMI08X_ACCEL),int-gpios) + + config BMI08X_ACCEL_TRIGGER bool @@ -59,7 +68,6 @@ config BMI08X_ACCEL_THREAD_STACK_SIZE choice BMI08X_GYRO_TRIGGER_MODE prompt "Gyroscope trigger mode" default BMI08X_GYRO_TRIGGER_NONE - default BMI08X_GYRO_TRIGGER_GLOBAL_THREAD help Specify the type of triggering to be used by the driver. @@ -75,6 +83,12 @@ config BMI08X_GYRO_TRIGGER_OWN_THREAD select BMI08X_GYRO_TRIGGER endchoice +config BMI08X_GYRO_STREAM + bool "Gyroscope Streaming Mode (FIFO)" + depends on !BMI08X_GYRO_TRIGGER + depends on GPIO + depends on $(dt_compat_any_has_prop,$(DT_COMPAT_BOSCH_BMI08X_GYRO),int-gpios) + config BMI08X_GYRO_TRIGGER bool diff --git a/drivers/sensor/bosch/bmi08x/bmi08x.h b/drivers/sensor/bosch/bmi08x/bmi08x.h index 83926126e4844..5aa4dd7a5779c 100644 --- a/drivers/sensor/bosch/bmi08x/bmi08x.h +++ b/drivers/sensor/bosch/bmi08x/bmi08x.h @@ -14,6 +14,8 @@ #include #include +#include "bmi08x_bus.h" + /* Accel Chip Id register */ #define BMI08X_REG_ACCEL_CHIP_ID 0x00 @@ -65,6 +67,15 @@ /* Sensor temperature LSB data register */ #define BMI08X_REG_TEMP_LSB 0x23 +/* Accel FIFO Length (low byte) */ +#define BMI08X_REG_ACCEL_FIFO_LEN_0 0x24 + +/* Accel FIFO Length (high byte) */ +#define BMI08X_REG_ACCEL_FIFO_LEN_1 0x25 + +/* Accel FIFO Data register */ +#define BMI08X_REG_ACCEL_FIFO_DATA 0x26 + /* Accel general purpose register 4*/ #define BMI08X_REG_ACCEL_GP_4 0x27 @@ -77,6 +88,18 @@ /* Accel range setting register */ #define BMI08X_REG_ACCEL_RANGE 0x41 +/* Accel FIFO Watermark (low byte) */ +#define BMI08X_REG_ACCEL_FIFO_WTM_0 0x46 + +/* Accel FIFO Watermark (high byte) */ +#define BMI08X_REG_ACCEL_FIFO_WTM_1 0x47 + +/* Accel FIFO Config (FIFO mode) */ +#define BMI08X_REG_ACCEL_FIFO_CONFIG_0 0x48 + +/* Accel FIFO Config (Interrupt enabling) */ +#define BMI08X_REG_ACCEL_FIFO_CONFIG_1 0x49 + /* Accel Interrupt pin 1 configuration register */ #define BMI08X_REG_ACCEL_INT1_IO_CONF 0x53 @@ -262,6 +285,9 @@ /* Gyro Interrupt status register */ #define BMI08X_REG_GYRO_INT_STAT_1 0x0A +/* FIFO Status register (Overrun and Frame counter) */ +#define BMI08X_REG_FIFO_STATUS 0x0E + /* Gyro Range register */ #define BMI08X_REG_GYRO_RANGE 0x0F @@ -283,9 +309,21 @@ /* Gyro Interrupt Map register */ #define BMI08X_REG_GYRO_INT3_INT4_IO_MAP 0x18 +/* FIFO Watermark enable */ +#define BMI08X_REG_GYRO_FIFO_WM_EN 0x1E + /* Gyro Self test register */ #define BMI08X_REG_GYRO_SELF_TEST 0x3C +/* FIFO Config register (FIFO Watermark) */ +#define BMI08X_REG_GYRO_FIFO_CONFIG_0 0x3D + +/* FIFO Config register (FIFO Mode) */ +#define BMI08X_REG_GYRO_FIFO_CONFIG_1 0x3E + +/* FIFO Data register */ +#define BMI08X_REG_GYRO_FIFO_DATA 0x3F + /* Gyro unique chip identifier */ #define BMI08X_GYRO_CHIP_ID 0x0F @@ -469,8 +507,9 @@ struct bmi08x_gyro_bus_io { struct bmi08x_accel_config { union bmi08x_bus bus; const struct bmi08x_accel_bus_io *api; -#if defined(CONFIG_BMI08X_ACCEL_TRIGGER) struct gpio_dt_spec int_gpio; +#if defined(CONFIG_SENSOR_ASYNC_API) + struct bmi08x_rtio_bus rtio_bus; #endif #if defined(CONFIG_BMI08X_ACCEL_TRIGGER) || BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC uint8_t int1_map; @@ -488,8 +527,9 @@ struct bmi08x_accel_config { struct bmi08x_gyro_config { union bmi08x_bus bus; const struct bmi08x_gyro_bus_io *api; -#if defined(CONFIG_BMI08X_GYRO_TRIGGER) struct gpio_dt_spec int_gpio; +#if defined(CONFIG_SENSOR_ASYNC_API) + struct bmi08x_rtio_bus rtio_bus; #endif #if defined(CONFIG_BMI08X_GYRO_TRIGGER) || BMI08X_GYRO_ANY_INST_HAS_DATA_SYNC uint8_t int3_4_map; @@ -500,11 +540,20 @@ struct bmi08x_gyro_config { }; struct bmi08x_accel_data { -#if defined(CONFIG_BMI08X_ACCEL_TRIGGER) + const struct device *dev; +#if defined(CONFIG_BMI08X_ACCEL_TRIGGER) || defined(CONFIG_SENSOR_ASYNC_API) struct gpio_callback gpio_cb; #endif uint16_t acc_sample[3]; uint16_t scale; /* micro m/s^2/lsb */ + uint16_t range; +#if defined(CONFIG_SENSOR_ASYNC_API) + struct { + struct rtio_iodev_sqe *iodev_sqe; + atomic_t state; + uint8_t fifo_wm; + } stream; +#endif #if defined(CONFIG_BMI08X_ACCEL_TRIGGER_OWN_THREAD) K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_BMI08X_ACCEL_THREAD_STACK_SIZE); @@ -512,7 +561,6 @@ struct bmi08x_accel_data { struct k_sem sem; #elif defined(CONFIG_BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD) struct k_work work; - const struct device *dev; #endif #ifdef CONFIG_BMI08X_ACCEL_TRIGGER @@ -523,11 +571,20 @@ struct bmi08x_accel_data { }; struct bmi08x_gyro_data { -#if defined(CONFIG_BMI08X_GYRO_TRIGGER) + const struct device *dev; +#if defined(CONFIG_BMI08X_GYRO_TRIGGER) || defined(CONFIG_SENSOR_ASYNC_API) struct gpio_callback gpio_cb; #endif uint16_t gyr_sample[3]; uint16_t scale; /* micro radians/s/lsb */ + uint16_t range; +#if defined(CONFIG_SENSOR_ASYNC_API) + struct { + struct rtio_iodev_sqe *iodev_sqe; + atomic_t state; + uint8_t fifo_wm; + } stream; +#endif #if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD) K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_BMI08X_GYRO_THREAD_STACK_SIZE); @@ -535,7 +592,6 @@ struct bmi08x_gyro_data { struct k_sem sem; #elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD) struct k_work work; - const struct device *dev; #endif #ifdef CONFIG_BMI08X_GYRO_TRIGGER @@ -544,6 +600,62 @@ struct bmi08x_gyro_data { #endif /* CONFIG_BMI08X_GYRO_TRIGGER */ }; +struct bmi08x_accel_frame { + uint8_t header; + union { + struct { + uint16_t payload[3]; + } accel; + struct { + uint8_t skipped_frames; + } skip; + struct { + uint8_t time[3]; + } sensortime; + struct { + uint8_t change; + } fifo_config; + }; +} __packed; + +struct bmi08x_gyro_frame { + uint16_t payload[3]; +} __packed; + +struct bmi08x_accel_encoded_data { + struct { + uint64_t timestamp; + uint16_t range; + uint8_t chip_id; + bool has_accel; + bool is_streaming; + uint16_t fifo_len; + uint8_t sample_count; + uint16_t buf_len; + } header; + union { + uint16_t payload[3]; + uint8_t fifo[0]; /* Left as bytes since it can contain multiple frames */ + }; +}; + +struct bmi08x_gyro_encoded_data { + struct { + uint64_t timestamp; + uint16_t range; + bool has_gyro; + bool is_streaming; + uint8_t int_status; + uint8_t fifo_status; + uint8_t sample_count; + } header; + union { + struct bmi08x_gyro_frame frame; + struct bmi08x_gyro_frame fifo[0]; + } __packed; +}; + + /* common functions for accel and gyro */ int bmi08x_freq_to_odr_val(uint16_t freq_int, uint16_t freq_milli); int32_t bmi08x_range_to_reg_val(uint16_t range, const struct bmi08x_range *range_map, diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_accel.c b/drivers/sensor/bosch/bmi08x/bmi08x_accel.c index 6053638b0d4c8..e8f0eafa7141e 100644 --- a/drivers/sensor/bosch/bmi08x/bmi08x_accel.c +++ b/drivers/sensor/bosch/bmi08x/bmi08x_accel.c @@ -6,16 +6,21 @@ */ #include +#include #include #include #include #include #include #include +#include #define DT_DRV_COMPAT bosch_bmi08x_accel #include "bmi08x.h" #include "bmi08x_config_file.h" +#include "bmi08x_accel_async.h" +#include "bmi08x_accel_stream.h" +#include "bmi08x_accel_decoder.h" LOG_MODULE_REGISTER(BMI08X_ACCEL, CONFIG_SENSOR_LOG_LEVEL); @@ -320,6 +325,7 @@ static int bmi08x_acc_range_set(const struct device *dev, int32_t range) } data->scale = BMI08X_ACC_SCALE(range); + data->range = reg_val; return ret; } @@ -538,6 +544,10 @@ static DEVICE_API(sensor, bmi08x_api) = { .attr_set = bmi08x_attr_set, #ifdef CONFIG_BMI08X_ACCEL_TRIGGER .trigger_set = bmi08x_trigger_set_acc, +#endif +#ifdef CONFIG_SENSOR_ASYNC_API + .submit = bmi08x_accel_async_submit, + .get_decoder = bmi08x_accel_decoder_get, #endif .sample_fetch = bmi08x_sample_fetch, .channel_get = bmi08x_channel_get, @@ -719,6 +729,14 @@ int bmi08x_accel_init(const struct device *dev) } #endif +#if defined(CONFIG_BMI08X_ACCEL_STREAM) + ret = bmi08x_accel_stream_init(dev); + if (ret < 0) { + LOG_ERR("Failed to init stream: %d", ret); + return ret; + } +#endif + return ret; } @@ -784,22 +802,44 @@ int bmi08x_accel_init(const struct device *dev) #define BMI08X_CREATE_INST(inst) \ \ + RTIO_DEFINE(bmi08x_accel_rtio_ctx_##inst, 16, 16); \ + \ + COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \ + (I2C_DT_IODEV_DEFINE(bmi08x_accel_rtio_bus_##inst, \ + DT_DRV_INST(inst))), \ + (COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (SPI_DT_IODEV_DEFINE(bmi08x_accel_rtio_bus_##inst, \ + DT_DRV_INST(inst), \ + SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB)),\ + ()))); \ + \ IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC(inst);)) \ IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC_ODR(inst);)) \ IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_GYRO_DATA_SYNC_EN(inst);)) \ \ - static struct bmi08x_accel_data bmi08x_drv_##inst; \ + static struct bmi08x_accel_data bmi08x_drv_##inst = { \ + IF_ENABLED(CONFIG_BMI08X_ACCEL_STREAM, \ + (.stream.fifo_wm = DT_INST_PROP_OR(inst, fifo_watermark, 0),)) \ + }; \ + \ \ static const struct bmi08x_accel_config bmi08x_config_##inst = { \ COND_CODE_1(DT_INST_ON_BUS(inst, spi), (BMI08X_CONFIG_SPI(inst)), \ (BMI08X_CONFIG_I2C(inst))) \ .api = COND_CODE_1(DT_INST_ON_BUS(inst, spi), (&bmi08x_spi_api), \ (&bmi08x_i2c_api)), \ - IF_ENABLED(CONFIG_BMI08X_ACCEL_TRIGGER, \ - (.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),)) \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ BMI08X_ACCEL_TRIGGER_PINS(inst) \ .accel_hz = DT_INST_ENUM_IDX(inst, accel_hz) + 5, \ - .accel_fs = DT_INST_PROP(inst, accel_fs), BMI08X_DATA_SYNC_REG(inst)}; \ + .rtio_bus = { \ + .ctx = &bmi08x_accel_rtio_ctx_##inst, \ + .iodev = &bmi08x_accel_rtio_bus_##inst, \ + .type = COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \ + (BMI08X_RTIO_BUS_TYPE_I2C), \ + (BMI08X_RTIO_BUS_TYPE_SPI)), \ + }, \ + .accel_fs = DT_INST_PROP(inst, accel_fs), BMI08X_DATA_SYNC_REG(inst) \ + }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_pm_action); \ SENSOR_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_init, PM_DEVICE_DT_INST_GET(inst), \ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_accel_async.c b/drivers/sensor/bosch/bmi08x/bmi08x_accel_async.c new file mode 100644 index 0000000000000..7eaa9dfdb22a2 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_accel_async.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_accel +#include "bmi08x.h" +#include "bmi08x_bus.h" +#include "bmi08x_accel_stream.h" +#include "bmi08x_accel_decoder.h" + +#include +LOG_MODULE_REGISTER(BMI08X_ACCEL_ASYNC, CONFIG_SENSOR_LOG_LEVEL); + +static void bmi08x_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, int result, + void *arg) +{ + struct rtio_iodev_sqe *iodev_sqe = (struct rtio_iodev_sqe *)arg; + + (void)rtio_flush_completion_queue(ctx); + if (result >= 0) { + rtio_iodev_sqe_ok(iodev_sqe, 0); + } else { + rtio_iodev_sqe_err(iodev_sqe, result); + } +} + +static void bmi08x_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + uint32_t buf_len_req = sizeof(struct bmi08x_accel_encoded_data); + struct bmi08x_accel_encoded_data *edata; + uint32_t buf_len; + int err; + + err = rtio_sqe_rx_buf(iodev_sqe, buf_len_req, buf_len_req, (uint8_t **)&edata, &buf_len); + CHECKIF(err < 0 || buf_len < buf_len_req || !edata) { + LOG_ERR("Failed to get a read-buffer of size %u bytes", buf_len_req); + rtio_iodev_sqe_err(iodev_sqe, err); + return; + } + bmi08x_accel_encode_header(dev, edata, false, 0); + + struct rtio_sqe *out_sqe; + struct rtio_sqe *complete_sqe; + const struct bmi08x_accel_config *config = dev->config; + + err = bmi08x_prep_reg_read_rtio_async(&config->rtio_bus, BMI08X_REG_ACCEL_X_LSB, + (uint8_t *)edata->payload, sizeof(edata->payload), + &out_sqe, true); + if (err < 0) { + LOG_ERR("Failed to perpare async read operation"); + rtio_iodev_sqe_err(iodev_sqe, err); + return; + } + out_sqe->flags |= RTIO_SQE_CHAINED; + + complete_sqe = rtio_sqe_acquire(config->rtio_bus.ctx); + if (!complete_sqe) { + LOG_ERR("Failed to perpare async read operation"); + rtio_sqe_drop_all(config->rtio_bus.ctx); + rtio_iodev_sqe_err(iodev_sqe, err); + return; + } + + rtio_sqe_prep_callback_no_cqe(complete_sqe, bmi08x_complete_result, iodev_sqe, (void *)dev); + rtio_submit(config->rtio_bus.ctx, 0); +} + +void bmi08x_accel_async_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + + if (!cfg->is_streaming) { + bmi08x_submit_one_shot(dev, iodev_sqe); + } else if (IS_ENABLED(CONFIG_BMI08X_ACCEL_STREAM)) { + bmi08x_accel_stream_submit(dev, iodev_sqe); + } else { + LOG_ERR("Streaming not supported"); + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); + } +} diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_accel_async.h b/drivers/sensor/bosch/bmi08x/bmi08x_accel_async.h new file mode 100644 index 0000000000000..241814fa39d2a --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_accel_async.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_ASYNC_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_ASYNC_H_ + +#include +#include + +void bmi08x_accel_async_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_ASYNC_H_ */ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.c b/drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.c new file mode 100644 index 0000000000000..767f2a6aca4c5 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_accel +#include "bmi08x.h" +#include "bmi08x_bus.h" +#include "bmi08x_accel_decoder.h" + +#include +LOG_MODULE_REGISTER(BMI08X_ACCEL_DECODER, CONFIG_SENSOR_LOG_LEVEL); + +enum bmi08x_accel_fifo_header { + BMI08X_ACCEL_FIFO_FRAME_ACCEL = 0x84, + BMI08X_ACCEL_FIFO_FRAME_SKIP = 0x40, + BMI08X_ACCEL_FIFO_FRAME_TIME = 0x44, + BMI08X_ACCEL_FIFO_FRAME_CONFIG = 0x48, + BMI08X_ACCEL_FIFO_FRAME_DROP = 0x50, + BMI08X_ACCEL_FIFO_FRAME_EMPTY = 0x80, +}; + +struct frame_len { + enum bmi08x_accel_fifo_header header; + uint8_t len; +} fifo_frame_len[] = { + {.header = BMI08X_ACCEL_FIFO_FRAME_ACCEL, .len = 7}, + {.header = BMI08X_ACCEL_FIFO_FRAME_SKIP, .len = 2}, + {.header = BMI08X_ACCEL_FIFO_FRAME_TIME, .len = 4}, + {.header = BMI08X_ACCEL_FIFO_FRAME_CONFIG, .len = 2}, + {.header = BMI08X_ACCEL_FIFO_FRAME_DROP, .len = 2}, + {.header = BMI08X_ACCEL_FIFO_FRAME_EMPTY, .len = 2}, +}; + +void bmi08x_accel_encode_header(const struct device *dev, struct bmi08x_accel_encoded_data *edata, + bool is_streaming, uint16_t buf_len) +{ + struct bmi08x_accel_data *data = dev->data; + uint64_t cycles; + + if (sensor_clock_get_cycles(&cycles) == 0) { + edata->header.timestamp = sensor_clock_cycles_to_ns(cycles); + } else { + edata->header.timestamp = 0; + } + edata->header.has_accel = true; + edata->header.range = data->range; + edata->header.chip_id = data->accel_chip_id; + edata->header.is_streaming = is_streaming; + edata->header.sample_count = is_streaming ? data->stream.fifo_wm : 1; + edata->header.buf_len = buf_len; +} + +static int bmi08x_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint16_t *frame_count) +{ + const struct bmi08x_accel_encoded_data *edata = + (const struct bmi08x_accel_encoded_data *)buffer; + + if (!edata->header.has_accel || chan_spec.chan_idx != 0) { + return -ENODATA; + } + + if (chan_spec.chan_type != SENSOR_CHAN_ACCEL_XYZ) { + return -EINVAL; + } + + *frame_count = edata->header.sample_count; + return 0; +} + +static int bmi08x_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size, + size_t *frame_size) +{ + if (chan_spec.chan_idx != 0 || chan_spec.chan_type != SENSOR_CHAN_ACCEL_XYZ) { + return -EINVAL; + } + + *base_size = sizeof(struct sensor_three_axis_data); + *frame_size = sizeof(struct sensor_three_axis_sample_data); + return 0; +} + +static inline void fixed_point_from_encoded_data(const uint16_t encoded_payload[3], uint8_t shift, + uint32_t fsr_value_g, q31_t output[3]) +{ + for (size_t i = 0 ; i < 3 ; i++) { + int64_t raw_value; + + raw_value = sign_extend_64(encoded_payload[i], 15); + raw_value = (raw_value * fsr_value_g << (31 - 5 - 15)) * SENSOR_G / 1000000; + + output[i] = raw_value; + } +} + +static inline int bmi08x_decode_one_shot(const struct bmi08x_accel_encoded_data *edata, + uint32_t *fit, struct sensor_three_axis_data *data_output) +{ + uint32_t fsr_value_g = (edata->header.chip_id == BMI085_ACCEL_CHIP_ID) ? 2 : 3; + + if (*fit != 0) { + return -ENODATA; + } + + /** Bits we need to represent the integer part of FSR in m/s2: + * - 2 - 3 G (19.6 - 29.4 m/s2) = 5 bits. + * - 4 - 6 G (39.2 - 58.8 m/s2) = 6 bits. + * - 8 - 12 G (78.4 - 117.6 m/s2) = 7 bits. + * - 16 - 24 G (156.8 235.2 m/s2) = 8 bits. + */ + data_output->shift = 5 + edata->header.range; + data_output->header.reading_count = 1; + data_output->header.base_timestamp_ns = edata->header.timestamp; + fixed_point_from_encoded_data(edata->payload, data_output->shift, fsr_value_g, + data_output->readings[0].values); + + return ++(*fit); +} + +static inline int fifo_get_frame_len(enum bmi08x_accel_fifo_header header) +{ + for (size_t i = 0 ; i < ARRAY_SIZE(fifo_frame_len) ; i++) { + if (header == fifo_frame_len[i].header) { + return fifo_frame_len[i].len; + } + } + return -EINVAL; +} + +static inline int bmi08x_decode_fifo(const struct bmi08x_accel_encoded_data *edata, uint32_t *fit, + uint16_t max_count, struct sensor_three_axis_data *data_output) +{ + uint8_t reading_count = 0; + uint32_t fsr_value_g = edata->header.chip_id == BMI085_ACCEL_CHIP_ID ? 2 : 3; + + if (*fit >= edata->header.buf_len) { + return -ENODATA; + } + + /** Bits we need to represent the integer part of FSR in m/s2: + * - 2 - 3 G (19.6 - 29.4 m/s2) = 5 bits. + * - 4 - 6 G (39.2 - 58.8 m/s2) = 6 bits. + * - 8 - 12 G (78.4 - 117.6 m/s2) = 7 bits. + * - 16 - 24 G (156.8 235.2 m/s2) = 8 bits. + */ + data_output->shift = 5 + edata->header.range; + data_output->header.reading_count = 0; + data_output->header.base_timestamp_ns = edata->header.timestamp; + + do { + uint8_t header_byte = edata->fifo[*fit] & 0xFC; + int frame_len = fifo_get_frame_len(header_byte); + + if (frame_len < 0) { + LOG_WRN("Invalid frame header: 0x%02X", header_byte); + return frame_len; + } + + if (header_byte == BMI08X_ACCEL_FIFO_FRAME_ACCEL && + *fit + frame_len <= edata->header.buf_len) { + const uint16_t *values = (const uint16_t *)&edata->fifo[*fit + 1]; + + fixed_point_from_encoded_data( + values, data_output->shift, fsr_value_g, + data_output->readings[reading_count].values); + reading_count++; + } + *fit += frame_len; + } while (*fit < edata->header.buf_len && reading_count < max_count); + + data_output->header.reading_count = reading_count; + return reading_count; +} + +static int bmi08x_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + struct sensor_three_axis_data *data_output = (struct sensor_three_axis_data *)data_out; + const struct bmi08x_accel_encoded_data *edata = + (const struct bmi08x_accel_encoded_data *)buffer; + + if (chan_spec.chan_type != SENSOR_CHAN_ACCEL_XYZ || chan_spec.chan_idx != 0 || + max_count == 0 || !edata->header.has_accel) { + return -EINVAL; + } + + if (edata->header.is_streaming) { + return bmi08x_decode_fifo(edata, fit, max_count, data_output); + } else { + return bmi08x_decode_one_shot(edata, fit, data_output); + } +} + +static bool bmi08x_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + const struct bmi08x_accel_encoded_data *edata = + (const struct bmi08x_accel_encoded_data *)buffer; + + return edata->header.is_streaming && edata->header.fifo_len > 0 && + trigger == SENSOR_TRIG_FIFO_WATERMARK; +} + +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = bmi08x_decoder_get_frame_count, + .get_size_info = bmi08x_decoder_get_size_info, + .decode = bmi08x_decoder_decode, + .has_trigger = bmi08x_decoder_has_trigger, +}; + +int bmi08x_accel_decoder_get(const struct device *dev, const struct sensor_decoder_api **decoder) +{ + ARG_UNUSED(dev); + *decoder = &SENSOR_DECODER_NAME(); + return 0; +} diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.h b/drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.h new file mode 100644 index 0000000000000..7bda48059cbd4 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_accel_decoder.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_DECODER_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_DECODER_H_ + +#include +#include +#include "bmi08x.h" + +void bmi08x_accel_encode_header(const struct device *dev, struct bmi08x_accel_encoded_data *edata, + bool is_streaming, uint16_t buf_len); +int bmi08x_accel_decoder_get(const struct device *dev, const struct sensor_decoder_api **decoder); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_DECODER_H_ */ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.c b/drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.c new file mode 100644 index 0000000000000..3141ad2a0d330 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_accel +#include "bmi08x.h" +#include "bmi08x_bus.h" +#include "bmi08x_accel_stream.h" +#include "bmi08x_accel_decoder.h" + +#include +LOG_MODULE_REGISTER(BMI08X_ACCEL_STREAM, CONFIG_SENSOR_LOG_LEVEL); + +enum bmi08x_stream_state { + BMI08X_STREAM_OFF, + BMI08X_STREAM_ON, + BMI08X_STREAM_BUSY, +}; + +static inline void bmi08x_stream_result(const struct device *dev, int result) +{ + struct bmi08x_accel_data *data = dev->data; + const struct bmi08x_accel_config *config = dev->config; + struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; + + data->stream.iodev_sqe = NULL; + (void)rtio_flush_completion_queue(config->rtio_bus.ctx); + if (result >= 0) { + (void)atomic_set(&data->stream.state, BMI08X_STREAM_ON); + if (iodev_sqe) { + rtio_iodev_sqe_ok(iodev_sqe, 0); + } + } else { + (void)atomic_set(&data->stream.state, BMI08X_STREAM_OFF); + if (iodev_sqe) { + rtio_iodev_sqe_err(iodev_sqe, result); + } + } +} + +static void bmi08x_stream_complete_handler(struct rtio *ctx, const struct rtio_sqe *sqe, int err, + void *arg) +{ + const struct device *dev = (const struct device *)arg; + struct bmi08x_accel_data *data = dev->data; + struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; + struct bmi08x_accel_encoded_data *edata; + uint32_t buf_len; + int ret; + + ret = rtio_sqe_rx_buf(iodev_sqe, 0, 0, (uint8_t **)&edata, &buf_len); + if (ret < 0 || buf_len == 0 || edata->header.fifo_len == 0) { + err = -EIO; + } + + bmi08x_stream_result(dev, err); +} + +static inline void bmi08x_accel_stream_evt_handler(const struct device *dev) +{ + struct bmi08x_accel_data *data = dev->data; + const struct bmi08x_accel_config *config = dev->config; + struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; + int ret; + struct bmi08x_accel_encoded_data *edata; + uint32_t buf_len; + size_t readout_len = sizeof(struct bmi08x_accel_frame) * (data->stream.fifo_wm + 1); + size_t required_len = sizeof(struct bmi08x_accel_encoded_data) + readout_len; + struct rtio_sqe *out_sqe; + + CHECKIF(!iodev_sqe || atomic_get(&data->stream.state) == BMI08X_STREAM_OFF) { + LOG_WRN("Event with Stream is Off. Disabling stream"); + bmi08x_stream_result(dev, -EIO); + return; + } + CHECKIF(atomic_cas(&data->stream.state, BMI08X_STREAM_ON, BMI08X_STREAM_BUSY) == false) { + LOG_DBG("Event while Stream is busy. Ignoring"); + return; + } + + ret = rtio_sqe_rx_buf(iodev_sqe, required_len, required_len, (uint8_t **)&edata, &buf_len); + CHECKIF(ret < 0 || buf_len < required_len) { + LOG_ERR("Failed to obtain buffer. Err: %d, Req-len: %d", ret, required_len); + bmi08x_stream_result(dev, -ENOMEM); + return; + } + bmi08x_accel_encode_header(dev, edata, true, readout_len); + + struct reg_val_read { + uint8_t reg; + void *buf; + size_t len; + } streaming_readout[] = { + {.reg = BMI08X_REG_ACCEL_FIFO_LEN_0, .buf = &edata->header.fifo_len, .len = 2}, + {.reg = BMI08X_REG_ACCEL_FIFO_DATA, .buf = edata->fifo, .len = readout_len}, + }; + + for (size_t i = 0 ; i < ARRAY_SIZE(streaming_readout) ; i++) { + ret = bmi08x_prep_reg_read_rtio_async(&config->rtio_bus, streaming_readout[i].reg, + (uint8_t *)streaming_readout[i].buf, + streaming_readout[i].len, &out_sqe, true); + CHECKIF(ret < 0 || !out_sqe) { + bmi08x_stream_result(dev, -EIO); + return; + } + out_sqe->flags |= RTIO_SQE_CHAINED; + } + out_sqe = rtio_sqe_acquire(config->rtio_bus.ctx); + CHECKIF(!out_sqe) { + bmi08x_stream_result(dev, -EIO); + return; + } + rtio_sqe_prep_callback_no_cqe(out_sqe, bmi08x_stream_complete_handler, (void *)dev, NULL); + (void)rtio_submit(config->rtio_bus.ctx, 0); +} + +static void bmi08x_accel_gpio_callback(const struct device *port, struct gpio_callback *cb, + uint32_t pin) +{ + struct bmi08x_accel_data *data = CONTAINER_OF(cb, struct bmi08x_accel_data, gpio_cb); + const struct device *dev = data->dev; + const struct bmi08x_accel_config *cfg = dev->config; + + (void)gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_DISABLE); + (void)gpio_remove_callback(cfg->int_gpio.port, &data->gpio_cb); + bmi08x_accel_stream_evt_handler(dev); +} + +static inline int start_stream(const struct device *dev) +{ + struct bmi08x_accel_data *data = dev->data; + const struct bmi08x_accel_config *cfg = dev->config; + struct rtio_sqe *out_sqe; + int ret; + uint16_t fifo_wm_bytes = data->stream.fifo_wm * sizeof(struct bmi08x_accel_frame); + struct reg_vals { + uint8_t reg; + uint8_t val; + } stream_cfg_reg_writes[] = { + {.reg = BMI08X_REG_ACCEL_FIFO_WTM_0, .val = fifo_wm_bytes & 0xFF}, + {.reg = BMI08X_REG_ACCEL_FIFO_WTM_1, .val = (fifo_wm_bytes >> 8) & 0x1F}, + {.reg = BMI08X_REG_ACCEL_FIFO_CONFIG_0, .val = BIT(1) | BIT(0)}, /* FIFO Mode */ + {.reg = BMI08X_REG_ACCEL_FIFO_CONFIG_1, .val = BIT(6) | BIT(4)}, + {.reg = BMI08X_REG_ACCEL_INT1_INT2_MAP_DATA, .val = BIT(0) | BIT(1)}, /* INT1 */ + {.reg = BMI08X_REG_ACCEL_INT1_IO_CONF, .val = BIT(1) | BIT(3)}, /* Push-pull */ + }; + + for (size_t i = 0 ; i < ARRAY_SIZE(stream_cfg_reg_writes) ; i++) { + ret = bmi08x_prep_reg_write_rtio_async(&cfg->rtio_bus, stream_cfg_reg_writes[i].reg, + &stream_cfg_reg_writes[i].val, 1, &out_sqe); + CHECKIF(ret < 0 || !out_sqe) { + return ret; + } + out_sqe->flags |= RTIO_SQE_CHAINED; + } + out_sqe->flags &= ~RTIO_SQE_CHAINED; + + /** We Synchronously write the stream since we want to do be done before enabling the + * interrupts. In the event that we're recovering from a failure, the interrupt line + * will be de-asserted. + */ + (void)rtio_submit(cfg->rtio_bus.ctx, ret); + return 0; +} + +void bmi08x_accel_stream_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct bmi08x_accel_data *data = dev->data; + const struct bmi08x_accel_config *cfg = dev->config; + const struct sensor_read_config *stream_cfg = iodev_sqe->sqe.iodev->data; + int ret = 0; + + if (stream_cfg->count != 1 || + stream_cfg->triggers->trigger != SENSOR_TRIG_FIFO_WATERMARK || + stream_cfg->triggers->opt != SENSOR_STREAM_DATA_INCLUDE) { + LOG_ERR("Invalid stream configuration"); + rtio_iodev_sqe_err(iodev_sqe, -EINVAL); + return; + } + data->stream.iodev_sqe = iodev_sqe; + + if (atomic_cas(&data->stream.state, BMI08X_STREAM_OFF, BMI08X_STREAM_ON) == true) { + ret = start_stream(dev); + if (ret != 0) { + LOG_ERR("Failed to configure stream"); + bmi08x_stream_result(dev, ret); + return; + } + } + (void)gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb); + (void)gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_LEVEL_HIGH); +} + +int bmi08x_accel_stream_init(const struct device *dev) +{ + struct bmi08x_accel_data *data = dev->data; + const struct bmi08x_accel_config *cfg = dev->config; + int ret; + + if (!gpio_is_ready_dt(&cfg->int_gpio)) { + LOG_ERR("GPIO device not ready: %p - dev: %p", &cfg->int_gpio, dev); + return -ENODEV; + } + ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure GPIO: %d", ret); + return ret; + } + ret = gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("Failed to configure GPIO: %d", ret); + return ret; + } + gpio_init_callback(&data->gpio_cb, bmi08x_accel_gpio_callback, BIT(cfg->int_gpio.pin)); + data->dev = dev; + + return 0; +} diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.h b/drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.h new file mode 100644 index 0000000000000..8caaa1547dc80 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_accel_stream.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_STREAM_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_STREAM_H_ + +#include +#include + +int bmi08x_accel_stream_init(const struct device *dev); +void bmi08x_accel_stream_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_ACCEL_STREAM_H_ */ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_bus.c b/drivers/sensor/bosch/bmi08x/bmi08x_bus.c new file mode 100644 index 0000000000000..92f96f4cd499b --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_bus.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bmi08x_bus.h" + +static uint8_t dummy_byte_val; + +int bmi08x_prep_reg_read_rtio_async(const struct bmi08x_rtio_bus *bus, + uint8_t reg, uint8_t *buf, size_t size, + struct rtio_sqe **out, bool dummy_byte) +{ + struct rtio *ctx = bus->ctx; + struct rtio_iodev *iodev = bus->iodev; + struct rtio_sqe *write_reg_sqe = rtio_sqe_acquire(ctx); + size_t sqe_ct = 2; + + if (!write_reg_sqe) { + rtio_sqe_drop_all(ctx); + return -ENOMEM; + } + reg |= BIT(7); + rtio_sqe_prep_tiny_write(write_reg_sqe, iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_reg_sqe->flags |= RTIO_SQE_TRANSACTION; + + if (dummy_byte) { + struct rtio_sqe *dummy_byte_sqe = rtio_sqe_acquire(ctx); + + if (!dummy_byte_sqe) { + rtio_sqe_drop_all(ctx); + return -ENOMEM; + } + rtio_sqe_prep_read(dummy_byte_sqe, iodev, RTIO_PRIO_NORM, &dummy_byte_val, 1, + NULL); + dummy_byte_sqe->flags |= RTIO_SQE_TRANSACTION; + sqe_ct++; + } + struct rtio_sqe *read_buf_sqe = rtio_sqe_acquire(ctx); + + if (!read_buf_sqe) { + rtio_sqe_drop_all(ctx); + return -ENOMEM; + } + rtio_sqe_prep_read(read_buf_sqe, iodev, RTIO_PRIO_NORM, buf, size, NULL); + if (bus->type == BMI08X_RTIO_BUS_TYPE_I2C) { + read_buf_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART; + } + + /** Send back last SQE so it can be concatenated later. */ + if (out) { + *out = read_buf_sqe; + } + + return sqe_ct; +} + +int bmi08x_prep_reg_write_rtio_async(const struct bmi08x_rtio_bus *bus, + uint8_t reg, const uint8_t *buf, size_t size, + struct rtio_sqe **out) +{ + struct rtio *ctx = bus->ctx; + struct rtio_iodev *iodev = bus->iodev; + struct rtio_sqe *write_reg_sqe = rtio_sqe_acquire(ctx); + struct rtio_sqe *write_buf_sqe = rtio_sqe_acquire(ctx); + + if (!write_reg_sqe || !write_buf_sqe) { + rtio_sqe_drop_all(ctx); + return -ENOMEM; + } + + /** More than 7 won't work with tiny-write */ + if (size > 7) { + return -EINVAL; + } + + rtio_sqe_prep_tiny_write(write_reg_sqe, iodev, RTIO_PRIO_NORM, ®, 1, NULL); + write_reg_sqe->flags |= RTIO_SQE_TRANSACTION; + rtio_sqe_prep_tiny_write(write_buf_sqe, iodev, RTIO_PRIO_NORM, buf, size, NULL); + if (bus->type == BMI08X_RTIO_BUS_TYPE_I2C) { + write_buf_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP; + } + + /** Send back last SQE so it can be concatenated later. */ + if (out) { + *out = write_buf_sqe; + } + + return 2; +} + +int bmi08x_reg_read_rtio(const struct bmi08x_rtio_bus *bus, uint8_t start, uint8_t *buf, int size, + bool dummy_byte) +{ + struct rtio *ctx = bus->ctx; + struct rtio_cqe *cqe; + int ret; + + ret = bmi08x_prep_reg_read_rtio_async(bus, start, buf, size, NULL, dummy_byte); + if (ret < 0) { + return ret; + } + + ret = rtio_submit(ctx, ret); + if (ret) { + return ret; + } + + do { + cqe = rtio_cqe_consume(ctx); + if (cqe != NULL) { + ret = cqe->result; + rtio_cqe_release(ctx, cqe); + } + } while (cqe != NULL); + + return ret; +} + +int bmi08x_reg_write_rtio(const struct bmi08x_rtio_bus *bus, uint8_t reg, const uint8_t *buf, + int size) +{ + struct rtio *ctx = bus->ctx; + struct rtio_cqe *cqe; + int ret; + + ret = bmi08x_prep_reg_write_rtio_async(bus, reg, buf, size, NULL); + if (ret < 0) { + return ret; + } + + ret = rtio_submit(ctx, ret); + if (ret) { + return ret; + } + + do { + cqe = rtio_cqe_consume(ctx); + if (cqe != NULL) { + ret = cqe->result; + rtio_cqe_release(ctx, cqe); + } + } while (cqe != NULL); + + return ret; +} diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_bus.h b/drivers/sensor/bosch/bmi08x/bmi08x_bus.h new file mode 100644 index 0000000000000..f2ef90c0986ff --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_bus.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_RTIO_BUS_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_RTIO_BUS_H_ + +#include +#include + +enum bmi08x_rtio_bus_type { + BMI08X_RTIO_BUS_TYPE_I2C, + BMI08X_RTIO_BUS_TYPE_SPI, +}; + +struct bmi08x_rtio_bus { + struct rtio *ctx; + struct rtio_iodev *iodev; + enum bmi08x_rtio_bus_type type; +}; + +int bmi08x_prep_reg_read_rtio_async(const struct bmi08x_rtio_bus *bus, + uint8_t reg, uint8_t *buf, size_t size, + struct rtio_sqe **out, bool dummy_byte); + +int bmi08x_prep_reg_write_rtio_async(const struct bmi08x_rtio_bus *bus, + uint8_t reg, const uint8_t *buf, size_t size, + struct rtio_sqe **out); + +int bmi08x_reg_read_rtio(const struct bmi08x_rtio_bus *bus, uint8_t start, uint8_t *buf, int size, + bool dummy_byte); + +int bmi08x_reg_write_rtio(const struct bmi08x_rtio_bus *bus, uint8_t reg, const uint8_t *buf, + int size); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_RTIO_BUS_H_ */ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_gyro.c b/drivers/sensor/bosch/bmi08x/bmi08x_gyro.c index 9fec8f71222e9..c9371812d64c9 100644 --- a/drivers/sensor/bosch/bmi08x/bmi08x_gyro.c +++ b/drivers/sensor/bosch/bmi08x/bmi08x_gyro.c @@ -6,15 +6,23 @@ */ #include +#include #include #include #include #include #include #include +#include +#include +#include #define DT_DRV_COMPAT bosch_bmi08x_gyro #include "bmi08x.h" +#include "bmi08x_bus.h" +#include "bmi08x_gyro_async.h" +#include "bmi08x_gyro_stream.h" +#include "bmi08x_gyro_decoder.h" LOG_MODULE_REGISTER(BMI08X_GYRO, CONFIG_SENSOR_LOG_LEVEL); @@ -178,6 +186,7 @@ static int bmi08x_gyr_range_set(const struct device *dev, uint16_t range) } bmi08x->scale = BMI08X_GYR_SCALE(range); + bmi08x->range = reg_val; return ret; } @@ -334,6 +343,10 @@ static DEVICE_API(sensor, bmi08x_api) = { .attr_set = bmi08x_attr_set, #ifdef CONFIG_BMI08X_GYRO_TRIGGER .trigger_set = bmi08x_trigger_set_gyr, +#endif +#ifdef CONFIG_SENSOR_ASYNC_API + .submit = bmi08x_gyro_async_submit, + .get_decoder = bmi08x_gyro_decoder_get, #endif .sample_fetch = bmi08x_sample_fetch, .channel_get = bmi08x_channel_get, @@ -416,6 +429,14 @@ int bmi08x_gyro_init(const struct device *dev) } #endif +#if defined(CONFIG_BMI08X_GYRO_STREAM) + ret = bmi08x_gyro_stream_init(dev); + if (ret < 0) { + LOG_ERR("Failed to init stream: %d", ret); + return ret; + } +#endif + return ret; } @@ -444,17 +465,45 @@ BUILD_ASSERT(CONFIG_BMI08X_GYRO_TRIGGER_NONE, #define BMI08X_CREATE_INST(inst) \ \ - static struct bmi08x_gyro_data bmi08x_drv_##inst; \ + IF_ENABLED(CONFIG_BMI08X_GYRO_STREAM, \ + (BUILD_ASSERT(DT_INST_PROP_OR(inst, fifo_watermark, 0) > 0 && \ + DT_INST_PROP_OR(inst, fifo_watermark, 0) < 100, \ + "FIFO Watermark must be defined for streaming mode, and be " \ + "within 1 and 99. Please define fifo-watermark accordingly or " \ + "disable CONFIG_BMI08X_GYRO_STREAM"))); \ + \ + RTIO_DEFINE(bmi08x_gyro_rtio_ctx_##inst, 16, 16); \ + \ + COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \ + (I2C_DT_IODEV_DEFINE(bmi08x_gyro_rtio_bus_##inst, \ + DT_DRV_INST(inst))), \ + (COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (SPI_DT_IODEV_DEFINE(bmi08x_gyro_rtio_bus_##inst, \ + DT_DRV_INST(inst), \ + SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB)),\ + ()))); \ + \ + static struct bmi08x_gyro_data bmi08x_drv_##inst = { \ + IF_ENABLED(CONFIG_BMI08X_GYRO_STREAM, \ + (.stream.fifo_wm = DT_INST_PROP_OR(inst, fifo_watermark, 0),)) \ + }; \ \ static const struct bmi08x_gyro_config bmi08x_config_##inst = { \ COND_CODE_1(DT_INST_ON_BUS(inst, spi), (BMI08X_CONFIG_SPI(inst)), \ (BMI08X_CONFIG_I2C(inst))) \ .api = COND_CODE_1(DT_INST_ON_BUS(inst, spi), (&bmi08x_spi_api), \ (&bmi08x_i2c_api)), \ - IF_ENABLED(CONFIG_BMI08X_GYRO_TRIGGER, \ - (.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),)) \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ .gyro_hz = DT_INST_ENUM_IDX(inst, gyro_hz), \ - BMI08X_GYRO_TRIGGER_PINS(inst).gyro_fs = DT_INST_PROP(inst, gyro_fs), \ + BMI08X_GYRO_TRIGGER_PINS(inst) \ + .gyro_fs = DT_INST_PROP(inst, gyro_fs), \ + .rtio_bus = { \ + .ctx = &bmi08x_gyro_rtio_ctx_##inst, \ + .iodev = &bmi08x_gyro_rtio_bus_##inst, \ + .type = COND_CODE_1(DT_INST_ON_BUS(inst, i2c), \ + (BMI08X_RTIO_BUS_TYPE_I2C), \ + (BMI08X_RTIO_BUS_TYPE_SPI)), \ + }, \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, bmi08x_gyro_pm_action); \ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.c b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.c new file mode 100644 index 0000000000000..0eae888a36edd --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_gyro +#include "bmi08x.h" +#include "bmi08x_bus.h" +#include "bmi08x_gyro_stream.h" +#include "bmi08x_gyro_decoder.h" + +#include +LOG_MODULE_REGISTER(BMI08X_GYRO_ASYNC, CONFIG_SENSOR_LOG_LEVEL); + +static void bmi08x_complete_result(struct rtio *ctx, const struct rtio_sqe *sqe, int result, + void *arg) +{ + struct rtio_iodev_sqe *iodev_sqe = (struct rtio_iodev_sqe *)arg; + + (void)rtio_flush_completion_queue(ctx); + if (result >= 0) { + rtio_iodev_sqe_ok(iodev_sqe, 0); + } else { + rtio_iodev_sqe_err(iodev_sqe, result); + } +} + +static void bmi08x_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + uint32_t buf_len_req = sizeof(struct bmi08x_gyro_encoded_data); + struct bmi08x_gyro_encoded_data *edata; + uint32_t buf_len; + int err; + + err = rtio_sqe_rx_buf(iodev_sqe, buf_len_req, buf_len_req, (uint8_t **)&edata, &buf_len); + CHECKIF(err < 0 || buf_len < buf_len_req || !edata) { + LOG_ERR("Failed to get a read-buffer of size %u bytes", buf_len_req); + rtio_iodev_sqe_err(iodev_sqe, err); + return; + } + bmi08x_gyro_encode_header(dev, edata, false); + + struct rtio_sqe *out_sqe; + struct rtio_sqe *complete_sqe; + const struct bmi08x_gyro_config *config = dev->config; + + err = bmi08x_prep_reg_read_rtio_async(&config->rtio_bus, BMI08X_REG_GYRO_X_LSB, + (uint8_t *)edata->frame.payload, + sizeof(edata->frame.payload), &out_sqe, false); + if (err < 0) { + LOG_ERR("Failed to perpare async read operation"); + rtio_iodev_sqe_err(iodev_sqe, err); + return; + } + out_sqe->flags |= RTIO_SQE_CHAINED; + + complete_sqe = rtio_sqe_acquire(config->rtio_bus.ctx); + if (!complete_sqe) { + LOG_ERR("Failed to perpare async read operation"); + rtio_sqe_drop_all(config->rtio_bus.ctx); + rtio_iodev_sqe_err(iodev_sqe, err); + return; + } + + rtio_sqe_prep_callback_no_cqe(complete_sqe, bmi08x_complete_result, iodev_sqe, (void *)dev); + rtio_submit(config->rtio_bus.ctx, 0); +} + +void bmi08x_gyro_async_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + + if (!cfg->is_streaming) { + bmi08x_submit_one_shot(dev, iodev_sqe); + } else if (IS_ENABLED(CONFIG_BMI08X_GYRO_STREAM)) { + bmi08x_gyro_stream_submit(dev, iodev_sqe); + } else { + LOG_ERR("Streaming not enabled"); + rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP); + } +} diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.h b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.h new file mode 100644 index 0000000000000..9b2b15f8f16d8 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_async.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_ASYNC_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_ASYNC_H_ + +#include +#include +#include + +void bmi08x_gyro_async_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_ASYNC_H_ */ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.c b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.c new file mode 100644 index 0000000000000..57d7f6d1694d6 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_gyro +#include "bmi08x.h" +#include "bmi08x_bus.h" +#include "bmi08x_gyro_stream.h" +#include "bmi08x_gyro_decoder.h" + +#include +LOG_MODULE_REGISTER(BMI08X_GYRO_DECODER, CONFIG_SENSOR_LOG_LEVEL); + +void bmi08x_gyro_encode_header(const struct device *dev, struct bmi08x_gyro_encoded_data *edata, + bool is_streaming) +{ + struct bmi08x_gyro_data *data = dev->data; + uint64_t cycles; + + if (sensor_clock_get_cycles(&cycles) == 0) { + edata->header.timestamp = sensor_clock_cycles_to_ns(cycles); + } else { + edata->header.timestamp = 0; + } + edata->header.has_gyro = true; + edata->header.range = data->range; + edata->header.is_streaming = is_streaming; + edata->header.sample_count = is_streaming ? data->stream.fifo_wm : 1; +} + +static int bmi08x_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint16_t *frame_count) +{ + const struct bmi08x_gyro_encoded_data *edata = + (const struct bmi08x_gyro_encoded_data *)buffer; + + if (!edata->header.has_gyro || chan_spec.chan_idx != 0) { + return -ENODATA; + } + if (chan_spec.chan_type != SENSOR_CHAN_GYRO_XYZ) { + return -EINVAL; + } + + *frame_count = edata->header.sample_count; + return 0; +} + +static int bmi08x_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size, + size_t *frame_size) +{ + if (chan_spec.chan_idx != 0 || chan_spec.chan_type != SENSOR_CHAN_GYRO_XYZ) { + return -EINVAL; + } + + *base_size = sizeof(struct sensor_three_axis_data); + *frame_size = sizeof(struct sensor_three_axis_sample_data); + return 0; +} + +static int bmi08x_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec, + uint32_t *fit, uint16_t max_count, void *data_out) +{ + const struct bmi08x_gyro_encoded_data *edata = + (const struct bmi08x_gyro_encoded_data *)buffer; + struct sensor_three_axis_data *data_output = (struct sensor_three_axis_data *)data_out; + uint32_t fit0 = *fit; + + if (chan_spec.chan_type != SENSOR_CHAN_GYRO_XYZ || chan_spec.chan_idx != 0 || + max_count == 0) { + return -EINVAL; + } + if (!edata->header.has_gyro || *fit >= edata->header.sample_count) { + return -ENODATA; + } + if (edata->header.is_streaming && + ((edata->header.fifo_status & 0x7F) == 0)) { + return -ENODATA; + } + uint32_t max_samples = MIN(edata->header.sample_count, edata->header.fifo_status & 0x7F); + + /** Bits we need to represent the integer part of FSR in rad/s: + * - 2000 dps (34.91 rad/s) = 6 bits. + * - 1000 dps (17.45 rad/s) = 5 bits. + * - 500 dps (8.73 rad/s) = 4 bits. + * - 250 dps (4.36 rad/s) = 3 bits. + * - 125 dps (2.18 rad/s) = 2 bits. + */ + data_output->shift = 6 - edata->header.range; + data_output->header.base_timestamp_ns = edata->header.timestamp; + + do { + for (size_t i = 0 ; i < 3 ; i++) { + int64_t raw_value; + + raw_value = sign_extend_64(edata->fifo[*fit].payload[i], 15); + raw_value = (raw_value * 2000 << (31 - 6 - 15)) * SENSOR_PI / 1000000 / 180; + + data_output->readings[*fit - fit0].values[i] = raw_value; + } + } while (++(*fit) < MIN(max_samples, fit0 + max_count)); + + data_output->header.reading_count = *fit - fit0; + + return data_output->header.reading_count; +} + +static bool bmi08x_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) +{ + const struct bmi08x_gyro_encoded_data *edata = + (const struct bmi08x_gyro_encoded_data *)buffer; + + return trigger == SENSOR_TRIG_FIFO_WATERMARK && + edata->header.has_gyro && + edata->header.is_streaming && + edata->header.int_status & BIT(4) && + (edata->header.fifo_status & BIT_MASK(7)) > 0; +} + +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = bmi08x_decoder_get_frame_count, + .get_size_info = bmi08x_decoder_get_size_info, + .decode = bmi08x_decoder_decode, + .has_trigger = bmi08x_decoder_has_trigger, +}; + +int bmi08x_gyro_decoder_get(const struct device *dev, const struct sensor_decoder_api **decoder) +{ + ARG_UNUSED(dev); + *decoder = &SENSOR_DECODER_NAME(); + return 0; +} diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.h b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.h new file mode 100644 index 0000000000000..3baa7f6ab5c8a --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_decoder.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_DECODER_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_DECODER_H_ + +#include +#include +#include "bmi08x.h" + +void bmi08x_gyro_encode_header(const struct device *dev, struct bmi08x_gyro_encoded_data *edata, + bool is_streaming); +int bmi08x_gyro_decoder_get(const struct device *dev, const struct sensor_decoder_api **decoder); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_DECODER_H_ */ diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.c b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.c new file mode 100644 index 0000000000000..8dc0af395a386 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_gyro +#include "bmi08x.h" +#include "bmi08x_bus.h" +#include "bmi08x_gyro_stream.h" +#include "bmi08x_gyro_decoder.h" + +#include +LOG_MODULE_REGISTER(BMI08X_GYRO_STREAM, CONFIG_SENSOR_LOG_LEVEL); + +enum bmi08x_stream_state { + BMI08X_STREAM_OFF, + BMI08X_STREAM_ON, + BMI08X_STREAM_BUSY, +}; + +static inline void bmi08x_stream_result(const struct device *dev, int result) +{ + struct bmi08x_gyro_data *data = dev->data; + const struct bmi08x_gyro_config *config = dev->config; + struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; + + data->stream.iodev_sqe = NULL; + (void)rtio_flush_completion_queue(config->rtio_bus.ctx); + if (result >= 0) { + (void)atomic_set(&data->stream.state, BMI08X_STREAM_ON); + if (iodev_sqe) { + rtio_iodev_sqe_ok(iodev_sqe, 0); + } + } else { + (void)atomic_set(&data->stream.state, BMI08X_STREAM_OFF); + if (iodev_sqe) { + rtio_iodev_sqe_err(iodev_sqe, result); + } + } +} + +static void bmi08x_stream_complete_handler(struct rtio *ctx, const struct rtio_sqe *sqe, int err, + void *arg) +{ + const struct device *dev = (const struct device *)arg; + struct bmi08x_gyro_data *data = dev->data; + struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; + struct bmi08x_gyro_encoded_data *edata; + uint32_t buf_len; + int ret; + + ret = rtio_sqe_rx_buf(iodev_sqe, 0, 0, (uint8_t **)&edata, &buf_len); + if (ret < 0 || buf_len == 0 || edata->header.int_status == 0 || + edata->header.fifo_status == 0) { + err = -EIO; + } + + bmi08x_stream_result(dev, err); +} + +static inline void bmi08x_gyro_stream_evt_handler(const struct device *dev) +{ + struct bmi08x_gyro_data *data = dev->data; + const struct bmi08x_gyro_config *config = dev->config; + struct rtio_iodev_sqe *iodev_sqe = data->stream.iodev_sqe; + int ret; + struct bmi08x_gyro_encoded_data *edata; + uint32_t buf_len; + size_t readout_len = sizeof(struct bmi08x_gyro_frame) * data->stream.fifo_wm; + size_t required_len = sizeof(struct bmi08x_gyro_encoded_data) + readout_len; + struct rtio_sqe *out_sqe; + + CHECKIF(!iodev_sqe || atomic_get(&data->stream.state) == BMI08X_STREAM_OFF) { + LOG_WRN("Event with Stream is Off. Disabling stream"); + bmi08x_stream_result(dev, -EIO); + return; + } + CHECKIF(atomic_cas(&data->stream.state, BMI08X_STREAM_ON, BMI08X_STREAM_BUSY) == false) { + LOG_DBG("Event while Stream is busy. Ignoring"); + return; + } + + ret = rtio_sqe_rx_buf(iodev_sqe, required_len, required_len, (uint8_t **)&edata, &buf_len); + CHECKIF(ret < 0 || buf_len < required_len) { + LOG_ERR("Failed to obtain buffer. Err: %d, Req-len: %d", ret, required_len); + bmi08x_stream_result(dev, -ENOMEM); + return; + } + bmi08x_gyro_encode_header(dev, edata, true); + + struct reg_val_read { + uint8_t reg; + void *buf; + size_t len; + } streaming_readout[] = { + {.reg = BMI08X_REG_GYRO_INT_STAT_1, .buf = &edata->header.int_status, .len = 1,}, + {.reg = BMI08X_REG_FIFO_STATUS, .buf = &edata->header.fifo_status, .len = 1}, + {.reg = BMI08X_REG_GYRO_FIFO_DATA, .buf = edata->fifo, .len = readout_len}, + }; + + for (size_t i = 0 ; i < ARRAY_SIZE(streaming_readout) ; i++) { + ret = bmi08x_prep_reg_read_rtio_async(&config->rtio_bus, streaming_readout[i].reg, + (uint8_t *)streaming_readout[i].buf, + streaming_readout[i].len, &out_sqe, false); + CHECKIF(ret < 0 || !out_sqe) { + bmi08x_stream_result(dev, -EIO); + return; + } + out_sqe->flags |= RTIO_SQE_CHAINED; + } + out_sqe = rtio_sqe_acquire(config->rtio_bus.ctx); + CHECKIF(!out_sqe) { + rtio_sqe_drop_all(config->rtio_bus.ctx); + bmi08x_stream_result(dev, -EIO); + return; + } + rtio_sqe_prep_callback_no_cqe(out_sqe, bmi08x_stream_complete_handler, (void *)dev, NULL); + (void)rtio_submit(config->rtio_bus.ctx, 0); +} + +static void bmi08x_gyro_gpio_callback(const struct device *port, struct gpio_callback *cb, + uint32_t pin) +{ + struct bmi08x_gyro_data *data = CONTAINER_OF(cb, struct bmi08x_gyro_data, gpio_cb); + const struct device *dev = data->dev; + const struct bmi08x_accel_config *cfg = dev->config; + + (void)gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_DISABLE); + (void)gpio_remove_callback(cfg->int_gpio.port, &data->gpio_cb); + bmi08x_gyro_stream_evt_handler(dev); +} + +static inline int start_stream(const struct device *dev) +{ + struct bmi08x_gyro_data *data = dev->data; + const struct bmi08x_gyro_config *cfg = dev->config; + struct rtio_sqe *out_sqe; + int ret; + struct reg_vals { + uint8_t reg; + uint8_t val; + } stream_cfg_reg_writes[] = { + {.reg = BMI08X_REG_GYRO_FIFO_CONFIG_1, .val = 0x80}, /* FIFO Stream mode */ + {.reg = BMI08X_REG_GYRO_FIFO_CONFIG_0, .val = data->stream.fifo_wm}, /* WM Level */ + {.reg = BMI08X_REG_GYRO_FIFO_WM_EN, .val = 0x88}, /* Enable FIFO WM */ + {.reg = BMI08X_REG_GYRO_INT3_INT4_IO_MAP, .val = BIT(2)}, /* FIFO INT to INT3 */ + {.reg = BMI08X_REG_GYRO_INT3_INT4_IO_CONF, .val = BIT(0)}, /* Push-pull act-high */ + {.reg = BMI08X_REG_GYRO_INT_CTRL, .val = BIT(6)}, /* Enable FIFO Interrupts */ + }; + + for (size_t i = 0 ; i < ARRAY_SIZE(stream_cfg_reg_writes) ; i++) { + ret = bmi08x_prep_reg_write_rtio_async(&cfg->rtio_bus, stream_cfg_reg_writes[i].reg, + &stream_cfg_reg_writes[i].val, 1, &out_sqe); + CHECKIF(ret < 0 || !out_sqe) { + return ret; + } + out_sqe->flags |= RTIO_SQE_CHAINED; + } + out_sqe->flags &= ~RTIO_SQE_CHAINED; + + /** We Synchronously write the stream since we want to do be done before enabling the + * interrupts. In the event that we're recovering from a failure, the interrupt line + * will be de-asserted. + */ + (void)rtio_submit(cfg->rtio_bus.ctx, ret); + return 0; +} + +void bmi08x_gyro_stream_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct bmi08x_gyro_data *data = dev->data; + const struct bmi08x_gyro_config *cfg = dev->config; + const struct sensor_read_config *stream_cfg = iodev_sqe->sqe.iodev->data; + int ret = 0; + + if (stream_cfg->count != 1 || + stream_cfg->triggers->trigger != SENSOR_TRIG_FIFO_WATERMARK || + stream_cfg->triggers->opt != SENSOR_STREAM_DATA_INCLUDE) { + LOG_ERR("Invalid stream configuration"); + rtio_iodev_sqe_err(iodev_sqe, -EINVAL); + return; + } + data->stream.iodev_sqe = iodev_sqe; + + if (atomic_cas(&data->stream.state, BMI08X_STREAM_OFF, BMI08X_STREAM_ON) == true) { + ret = start_stream(dev); + if (ret != 0) { + LOG_ERR("Failed to configure stream"); + bmi08x_stream_result(dev, ret); + return; + } + } + (void)gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb); + (void)gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_LEVEL_HIGH); +} + +int bmi08x_gyro_stream_init(const struct device *dev) +{ + struct bmi08x_gyro_data *data = dev->data; + const struct bmi08x_gyro_config *cfg = dev->config; + int ret; + + if (!gpio_is_ready_dt(&cfg->int_gpio)) { + LOG_ERR("GPIO device not ready: %p - dev: %p", &cfg->int_gpio, dev); + return -ENODEV; + } + ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure GPIO: %d", ret); + return ret; + } + ret = gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("Failed to configure GPIO: %d", ret); + return ret; + } + gpio_init_callback(&data->gpio_cb, bmi08x_gyro_gpio_callback, BIT(cfg->int_gpio.pin)); + data->dev = dev; + + return 0; +} diff --git a/drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.h b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.h new file mode 100644 index 0000000000000..676e008544966 --- /dev/null +++ b/drivers/sensor/bosch/bmi08x/bmi08x_gyro_stream.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Croxel, Inc. + * Copyright (c) 2025 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_STREAM_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_STREAM_H_ + +#include +#include + +int bmi08x_gyro_stream_init(const struct device *dev); +void bmi08x_gyro_stream_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_BMI08X_GYRO_STREAM_H_ */ diff --git a/dts/bindings/sensor/bosch,bmi08x-accel.yaml b/dts/bindings/sensor/bosch,bmi08x-accel.yaml index 2bd311df0f532..3aa9c85014268 100644 --- a/dts/bindings/sensor/bosch,bmi08x-accel.yaml +++ b/dts/bindings/sensor/bosch,bmi08x-accel.yaml @@ -82,3 +82,8 @@ properties: description: | Enables data sync if defined. This is to point to the bmi08x-gyro definition that is within the same IC as the bmi08x-accel. + + fifo-watermark: + type: int + description: | + FIFO Watermark in number of samples. Ranges between 1 and 99 diff --git a/dts/bindings/sensor/bosch,bmi08x-gyro.yaml b/dts/bindings/sensor/bosch,bmi08x-gyro.yaml index 0a3086d8417c7..7ffb1ecbe23a3 100644 --- a/dts/bindings/sensor/bosch,bmi08x-gyro.yaml +++ b/dts/bindings/sensor/bosch,bmi08x-gyro.yaml @@ -60,3 +60,8 @@ properties: type: boolean description: | Enables data sync if defined. Must be set if bmi08x-accel data-sync is set as well. + + fifo-watermark: + type: int + description: | + FIFO Watermark in number of frames. Ranges between 1 and 99 diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 2feda1d16c37f..3472514935964 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -787,6 +787,7 @@ test_i2c_bmi08x_accel: bmi08x@6d { int2-conf-io = <0x17>; accel-hz = "800"; accel-fs = <4>; + fifo-watermark = <1>; }; test_i2c_bmi08x_gyro: bmi08x@6e { @@ -797,6 +798,7 @@ test_i2c_bmi08x_gyro: bmi08x@6e { int3-4-conf-io = <0x01>; gyro-hz = "1000_116"; gyro-fs = <1000>; + fifo-watermark = <1>; }; test_i2c_ist8310: ist8310@6f { diff --git a/tests/drivers/build_all/sensor/sensors_async_api.conf b/tests/drivers/build_all/sensor/sensors_async_api.conf index 4b98bb3437d0f..e465f9af4a420 100644 --- a/tests/drivers/build_all/sensor/sensors_async_api.conf +++ b/tests/drivers/build_all/sensor/sensors_async_api.conf @@ -12,3 +12,5 @@ CONFIG_IIS3DWB_STREAM=y CONFIG_LSM6DSV16X_STREAM=y CONFIG_ICM45686_STREAM=y CONFIG_ICM4268X_STREAM=y +CONFIG_BMI08X_GYRO_STREAM=y +CONFIG_BMI08X_ACCEL_STREAM=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index 6560c377a0e31..1aa73779cf18c 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -277,6 +277,7 @@ test_spi_bmi08x_accel: bmi08x@23 { int2-conf-io = <0x17>; accel-hz = "800"; accel-fs = <4>; + fifo-watermark = <1>; }; test_spi_bmi08x_gyro: bmi08x@24 { @@ -288,6 +289,7 @@ test_spi_bmi08x_gyro: bmi08x@24 { int3-4-conf-io = <0x01>; gyro-hz = "1000_116"; gyro-fs = <1000>; + fifo-watermark = <1>; }; test_spi_tmag5170: tmag5170@25 { From f1fbc6063905ff8f737b40102eb447a83c7eedf0 Mon Sep 17 00:00:00 2001 From: Martin Koehler Date: Wed, 15 Oct 2025 09:57:23 +0200 Subject: [PATCH 376/397] dts: bindings: sensor: ti,ina226: Added missing enum - Removal of double enum (by me) caused wrong later enum entries - See commit 36abe5efecbc27963189880d7c426c50760bcd58 - Added the second power down state (but with different name) -> This restores the old function but still fixes the double enum issue - The second power down state equals a different valid value in the mode register. Documentation does not state if they are equal but it is likely that they only differ in readback value. -> With this change all possible register values are mapped -> The power down state values are 0b000 and 0b100 Signed-off-by: Martin Koehler --- dts/bindings/sensor/ti,ina226.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/bindings/sensor/ti,ina226.yaml b/dts/bindings/sensor/ti,ina226.yaml index 137dca397013d..2253accb81a8e 100644 --- a/dts/bindings/sensor/ti,ina226.yaml +++ b/dts/bindings/sensor/ti,ina226.yaml @@ -47,6 +47,7 @@ properties: - "Shunt Voltage, Triggered" - "Bus Voltage, Triggered" - "Shunt and Bus, Triggered" + - "Power-Down (or Shutdown)_2" - "Shunt Voltage, Continuous" - "Bus Voltage, Continuous" - "Shunt and Bus, Continuous" From 17f482990ccd44b82d16e71fbdc094423d11f9d1 Mon Sep 17 00:00:00 2001 From: Martin Koehler Date: Tue, 21 Oct 2025 12:01:28 +0200 Subject: [PATCH 377/397] dts: bindings: sensor: ti,ina226: Description indention fix - as the pull request is just running I can also properly indent Signed-off-by: Martin Koehler --- dts/bindings/sensor/ti,ina226.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dts/bindings/sensor/ti,ina226.yaml b/dts/bindings/sensor/ti,ina226.yaml index 2253accb81a8e..81c5d194b058e 100644 --- a/dts/bindings/sensor/ti,ina226.yaml +++ b/dts/bindings/sensor/ti,ina226.yaml @@ -2,10 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 description: | - TI INA226 Bidirectional Current and Power Monitor. - The file should be included in the - DeviceTree as it provides macros that can be used for initializing the - configuration registers. + TI INA226 Bidirectional Current and Power Monitor. + The file should be included in the + DeviceTree as it provides macros that can be used for initializing the + configuration registers. compatible: "ti,ina226" From c31cbe02546f06478916312b8dad22c8532fe4f0 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Tue, 14 Oct 2025 10:28:35 -0300 Subject: [PATCH 378/397] boards: luatos_core: esp32c3: fix board pinout Fix wrong SPI, UART and TWAI pins. Signed-off-by: Sylvio Alves --- .../esp32c3_luatos_core-pinctrl.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core-pinctrl.dtsi b/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core-pinctrl.dtsi index 259b05379f3d7..816168c6011f6 100644 --- a/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core-pinctrl.dtsi +++ b/boards/luatos/esp32c3_luatos_core/esp32c3_luatos_core-pinctrl.dtsi @@ -23,21 +23,21 @@ spim2_default: spim2_default { group1 { - pinmux = , - , - ; + pinmux = , + , + ; }; group2 { - pinmux = ; + pinmux = ; output-low; }; }; i2c0_default: i2c0_default { group1 { - pinmux = , - ; + pinmux = , + ; bias-pull-up; drive-open-drain; output-high; @@ -46,8 +46,8 @@ twai_default: twai_default { group1 { - pinmux = , - ; + pinmux = , + ; }; }; }; From 2347d77427d8aecef0dfea4de126ba958c8097d5 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Tue, 14 Oct 2025 13:36:03 +0200 Subject: [PATCH 379/397] doc: develop: gsg: Update windows installation steps The Python version installed with winget defaults to 3.8, make a more recent version the default. Also add a note on the execution policy for activating the Python virtual environment. Signed-off-by: Pieter De Gendt --- doc/develop/getting_started/index.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/develop/getting_started/index.rst b/doc/develop/getting_started/index.rst index 82588c1c9d67b..9d081061cc04d 100644 --- a/doc/develop/getting_started/index.rst +++ b/doc/develop/getting_started/index.rst @@ -171,7 +171,7 @@ The current minimum required version for the main dependencies are: .. code-block:: bat - winget install Kitware.CMake Ninja-build.Ninja oss-winget.gperf python Git.Git oss-winget.dtc wget 7zip.7zip + winget install Kitware.CMake Ninja-build.Ninja oss-winget.gperf Python.Python.3.12 Git.Git oss-winget.dtc wget 7zip.7zip #. Close the terminal window. @@ -337,6 +337,15 @@ chosen. You'll also install Zephyr's additional Python dependencies in a #. Activate the virtual environment: + .. note:: + + Python's virtual environment activation in PowerShell requires + running a script itself, which needs to be allowed. + + .. code-block:: powershell + + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + .. tabs:: .. code-tab:: bat From f869f41d58df18973b004aaf1210bdad27fd307c Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Fri, 10 Oct 2025 18:18:05 +0200 Subject: [PATCH 380/397] boards: nxp: frdm_rw612: add arduino_spi labels Added arduino_spi label to FRDM-RW612 device tree board definition, allowing compatible shield boards to be used. Also extend the board YAML file with related support tags arduino_gpio, arduino_i2c and arduino_spi. Signed-off-by: Stephan Linz --- boards/nxp/frdm_rw612/frdm_rw612.yaml | 3 +++ boards/nxp/frdm_rw612/frdm_rw612_common.dtsi | 22 ++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/boards/nxp/frdm_rw612/frdm_rw612.yaml b/boards/nxp/frdm_rw612/frdm_rw612.yaml index 659229a89c6f9..7ad0b8d1f93fb 100644 --- a/boards/nxp/frdm_rw612/frdm_rw612.yaml +++ b/boards/nxp/frdm_rw612/frdm_rw612.yaml @@ -16,6 +16,9 @@ flash: 65536 supported: - arduino_gpio - gpio + - arduino_gpio + - arduino_i2c + - arduino_spi - dma - spi - i2c diff --git a/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi b/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi index e649d3d04167b..8391f513b8c93 100644 --- a/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi +++ b/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi @@ -67,8 +67,8 @@ gpio-map = , , , - , - , + , /* GPIO(D11), Not a RX */ + , /* GPIO(D12), Not a TX */ , , , @@ -77,12 +77,12 @@ , , , - , - , - , - , - , - ; + , /* CS */ + , /* MOSI */ + , /* MISO */ + , /* SCK */ + , /* SDA */ + ; /* SCL */ }; }; @@ -299,7 +299,9 @@ zephyr_udc0: &usb_otg { #size-cells = <0>; }; -arduino_i2c: &flexcomm2 { +arduino_spi: &flexcomm1 {}; + +&flexcomm2 { compatible = "nxp,lpc-i2c"; status = "okay"; clock-frequency = ; @@ -315,6 +317,8 @@ arduino_i2c: &flexcomm2 { }; }; +arduino_i2c: &flexcomm2 {}; + zephyr_mipi_dbi_spi: &lcdic { status = "okay"; pinctrl-0 = <&pinmux_lcdic>; From 4115ea9a6b07ebad5ad5f8d800c3d440a6929577 Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Sat, 11 Oct 2025 19:36:14 +0200 Subject: [PATCH 381/397] boards: nxp: frdm_rw612: add mikrobus labels Added mikrobus_serial, mikrobus_i2c, mikrobus_spi and mikrobus_header node labels to FRDM-RW612 device tree board definition, allowing compatible shield boards to be used. Also extend the FlexComm SPI pinmux to support CS0 (Arduino connector) and CS1 (MicroBus connector) as hardware controlled CS pin. Signed-off-by: Stephan Linz --- boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi | 5 ++++ boards/nxp/frdm_rw612/frdm_rw612_common.dtsi | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi b/boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi index 4e1e4af80523a..c960ba7c6f272 100644 --- a/boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi +++ b/boards/nxp/frdm_rw612/frdm_rw612-pinctrl.dtsi @@ -47,11 +47,16 @@ }; }; + /* support CS0 (Arduino connector) and CS1 (MicroBus connector). */ pinmux_flexcomm1_spi: pinmux_flexcomm1_spi { group0 { pinmux = ; slew-rate = "ultra"; }; + group1 { + pinmux = ; + slew-rate = "ultra"; + }; }; pinmux_pwm0: pinmux_pwm0 { diff --git a/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi b/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi index 8391f513b8c93..1d4e20a9ff70b 100644 --- a/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi +++ b/boards/nxp/frdm_rw612/frdm_rw612_common.dtsi @@ -59,6 +59,25 @@ <12 0 &hsgpio0 18 0>; /* Pin 11, LCD touch INT */ }; + mikrobus_header: mikrobus-connector { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &hsgpio1 29 0>, /* AN */ + <1 0 &hsgpio0 19 0>, /* RST */ + <2 0 &hsgpio0 10 0>, /* CS */ + <3 0 &hsgpio0 7 0>, /* SCK */ + <4 0 &hsgpio0 8 0>, /* MISO */ + <5 0 &hsgpio0 9 0>, /* MOSI */ + <6 0 &hsgpio0 1 0>, /* PWM */ + <7 0 &hsgpio1 22 0>, /* INT */ + <8 0 &hsgpio0 2 0>, /* RX */ + <9 0 &hsgpio0 3 0>, /* TX */ + <10 0 &hsgpio0 17 0>, /* SCL */ + <11 0 &hsgpio0 16 0>; /* SDA */ + }; + arduino_header: arduino-connector { compatible = "arduino-header-r3"; #gpio-cells = <2>; @@ -103,6 +122,8 @@ pinctrl-names = "default"; }; +mikrobus_serial: &flexcomm0 {}; + &hsgpio0 { status = "okay"; pinctrl-0 = <&pinmux_hsgpio0>; @@ -301,6 +322,8 @@ zephyr_udc0: &usb_otg { arduino_spi: &flexcomm1 {}; +mikrobus_spi: &flexcomm1 {}; + &flexcomm2 { compatible = "nxp,lpc-i2c"; status = "okay"; @@ -319,6 +342,8 @@ arduino_spi: &flexcomm1 {}; arduino_i2c: &flexcomm2 {}; +mikrobus_i2c: &flexcomm2 {}; + zephyr_mipi_dbi_spi: &lcdic { status = "okay"; pinctrl-0 = <&pinmux_lcdic>; From 9d1ee002c3bcf03ebfb0946e2c63164462f869d1 Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Mon, 13 Oct 2025 01:55:14 +0200 Subject: [PATCH 382/397] samples: frdm_rw612: exclude various tests Disable various samples because they require certain digital or analog signals from the Arduino header, which are not connected and therefore not defined via the connector gpio-map. Signed-off-by: Stephan Linz --- samples/shields/x_nucleo_iks01a1/sample.yaml | 1 + samples/shields/x_nucleo_iks01a2/standard/sample.yaml | 1 + samples/shields/x_nucleo_iks01a3/sensorhub/sample.yaml | 1 + samples/shields/x_nucleo_iks01a3/standard/sample.yaml | 1 + samples/shields/x_nucleo_iks02a1/sensorhub/sample.yaml | 1 + samples/shields/x_nucleo_iks02a1/standard/sample.yaml | 1 + samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml | 1 + samples/shields/x_nucleo_iks4a1/standard/sample.yaml | 1 + 8 files changed, 8 insertions(+) diff --git a/samples/shields/x_nucleo_iks01a1/sample.yaml b/samples/shields/x_nucleo_iks01a1/sample.yaml index 841977cfb643b..d370dfa9a4b5c 100644 --- a/samples/shields/x_nucleo_iks01a1/sample.yaml +++ b/samples/shields/x_nucleo_iks01a1/sample.yaml @@ -4,6 +4,7 @@ tests: sample.shields.x_nucleo_iks01a1: platform_exclude: - disco_l475_iot1 + - frdm_rw612 - pan1781_evb - pan1782_evb harness: shield diff --git a/samples/shields/x_nucleo_iks01a2/standard/sample.yaml b/samples/shields/x_nucleo_iks01a2/standard/sample.yaml index debb544963d43..e0fa2fbafc064 100644 --- a/samples/shields/x_nucleo_iks01a2/standard/sample.yaml +++ b/samples/shields/x_nucleo_iks01a2/standard/sample.yaml @@ -9,6 +9,7 @@ tests: - arduino_gpio platform_exclude: - disco_l475_iot1 + - frdm_rw612 - lpcxpresso55s16 - stm32mp157c_dk2 - mimxrt1010_evk diff --git a/samples/shields/x_nucleo_iks01a3/sensorhub/sample.yaml b/samples/shields/x_nucleo_iks01a3/sensorhub/sample.yaml index 1e86a8c5b49cc..2aef91293cd56 100644 --- a/samples/shields/x_nucleo_iks01a3/sensorhub/sample.yaml +++ b/samples/shields/x_nucleo_iks01a3/sensorhub/sample.yaml @@ -9,5 +9,6 @@ tests: - arduino_gpio platform_exclude: - disco_l475_iot1 + - frdm_rw612 - lpcxpresso55s16 - mimxrt1010_evk diff --git a/samples/shields/x_nucleo_iks01a3/standard/sample.yaml b/samples/shields/x_nucleo_iks01a3/standard/sample.yaml index 296272a8d1ec7..0fef3bce74bbd 100644 --- a/samples/shields/x_nucleo_iks01a3/standard/sample.yaml +++ b/samples/shields/x_nucleo_iks01a3/standard/sample.yaml @@ -11,6 +11,7 @@ tests: - arduino_gpio platform_exclude: - disco_l475_iot1 + - frdm_rw612 - lpcxpresso55s16 - pan1781_evb - pan1782_evb diff --git a/samples/shields/x_nucleo_iks02a1/sensorhub/sample.yaml b/samples/shields/x_nucleo_iks02a1/sensorhub/sample.yaml index c822ccc8772eb..06718166b1131 100644 --- a/samples/shields/x_nucleo_iks02a1/sensorhub/sample.yaml +++ b/samples/shields/x_nucleo_iks02a1/sensorhub/sample.yaml @@ -9,6 +9,7 @@ tests: - arduino_gpio platform_exclude: - disco_l475_iot1 + - frdm_rw612 - lpcxpresso55s16 - stm32mp157c_dk2 - pan1781_evb diff --git a/samples/shields/x_nucleo_iks02a1/standard/sample.yaml b/samples/shields/x_nucleo_iks02a1/standard/sample.yaml index 1f080e2f0d112..3bcef62146c1c 100644 --- a/samples/shields/x_nucleo_iks02a1/standard/sample.yaml +++ b/samples/shields/x_nucleo_iks02a1/standard/sample.yaml @@ -11,6 +11,7 @@ tests: - arduino_gpio platform_exclude: - disco_l475_iot1 + - frdm_rw612 - lpcxpresso55s16 - stm32mp157c_dk2 - pan1781_evb diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml b/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml index b52cd282f7bc6..e4cb9864ea027 100644 --- a/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml @@ -9,6 +9,7 @@ tests: - arduino_gpio platform_exclude: - disco_l475_iot1 + - frdm_rw612 - lpcxpresso55s16 - pan1781_evb - pan1782_evb diff --git a/samples/shields/x_nucleo_iks4a1/standard/sample.yaml b/samples/shields/x_nucleo_iks4a1/standard/sample.yaml index a5cffd34361a7..f13fc9c42c966 100644 --- a/samples/shields/x_nucleo_iks4a1/standard/sample.yaml +++ b/samples/shields/x_nucleo_iks4a1/standard/sample.yaml @@ -11,6 +11,7 @@ tests: - arduino_gpio platform_exclude: - disco_l475_iot1 + - frdm_rw612 - lpcxpresso55s16 - mimxrt1010_evk - pan1781_evb From 07488542a24ab7b35c014ee353cd656bf4c151b6 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 9 Oct 2025 16:39:25 -0500 Subject: [PATCH 383/397] boards: nxp: Remove old LPSPI timing properties The old controller based timing properties being present in boards DTS is making it so that overlays cannot specify timing parameters of spi devices, because the old controller properties take precedence in the driver still. We should remove these anyways, so first step is to remove from board level, luckily there is only these two cases. Signed-off-by: Declan Snyder --- boards/nxp/frdm_mcxw71/frdm_mcxw71.dts | 6 +++--- boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/boards/nxp/frdm_mcxw71/frdm_mcxw71.dts b/boards/nxp/frdm_mcxw71/frdm_mcxw71.dts index d67033c8b5db3..b1cbec74e7e13 100644 --- a/boards/nxp/frdm_mcxw71/frdm_mcxw71.dts +++ b/boards/nxp/frdm_mcxw71/frdm_mcxw71.dts @@ -142,9 +142,6 @@ status = "okay"; pinctrl-0 = <&pinmux_lpspi1>; pinctrl-names = "default"; - pcs-sck-delay = <5>; - sck-pcs-delay = <5>; - transfer-delay = <125>; mx25r6435fm2il0: flash@0 { compatible = "jedec,spi-nor"; @@ -163,6 +160,9 @@ mxicy,mx25r-power-mode = "low-power"; /* 8 MHz for low power mode */ spi-max-frequency = ; + spi-cs-setup-delay-ns = <5>; + spi-cs-hold-delay-ns = <5>; + spi-interframe-delay-ns = <125>; }; }; diff --git a/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts b/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts index e4fd420abd2c5..623ca7c278ba9 100644 --- a/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts +++ b/boards/nxp/vmu_rt1170/vmu_rt1170_mimxrt1176_cm7.dts @@ -255,15 +255,15 @@ &lpspi1 { status = "okay"; - pcs-sck-delay = <50>; - sck-pcs-delay = <50>; - transfer-delay = <50>; icm42686_0: icm42686p0@0 { compatible = "invensense,icm42686", "invensense,icm4268x"; reg = <0>; int-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; spi-max-frequency = ; + spi-cs-setup-delay-ns = <50>; + spi-cs-hold-delay-ns = <50>; + spi-interframe-delay-ns = <50>; accel-pwr-mode = ; accel-odr = ; accel-fs = ; @@ -283,15 +283,15 @@ &lpspi2 { status = "okay"; - pcs-sck-delay = <50>; - sck-pcs-delay = <50>; - transfer-delay = <50>; icm42688_0: icm42688p0@0 { compatible = "invensense,icm42688", "invensense,icm4268x"; reg = <0>; int-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>; spi-max-frequency = ; + spi-cs-setup-delay-ns = <50>; + spi-cs-hold-delay-ns = <50>; + spi-interframe-delay-ns = <50>; accel-pwr-mode = ; accel-odr = ; accel-fs = ; From 08e27f9a672bb2c4baaa8df281369b3db55ecb47 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 9 Oct 2025 16:44:27 -0500 Subject: [PATCH 384/397] tests: spi_loopback: Fix MCXW timing parameters The LPSPI and SOC hardware has some electrical timing characteristics that need to be met in order to pass these test properly, these values should be fine for the purpose. Signed-off-by: Declan Snyder --- tests/drivers/spi/spi_loopback/boards/frdm_mcxw71.overlay | 7 +++++++ .../spi_loopback/boards/mcxw72_evk_mcxw727c_cpu0.overlay | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/tests/drivers/spi/spi_loopback/boards/frdm_mcxw71.overlay b/tests/drivers/spi/spi_loopback/boards/frdm_mcxw71.overlay index fa2b906bbd7c3..72cf56a4a8a32 100644 --- a/tests/drivers/spi/spi_loopback/boards/frdm_mcxw71.overlay +++ b/tests/drivers/spi/spi_loopback/boards/frdm_mcxw71.overlay @@ -9,10 +9,17 @@ compatible = "test-spi-loopback-slow"; reg = <0>; spi-max-frequency = <500000>; + spi-cs-setup-delay-ns = <1000>; + spi-cs-hold-delay-ns = <1000>; + spi-interframe-delay-ns = <1000>; }; fast@0 { compatible = "test-spi-loopback-fast"; reg = <0>; spi-max-frequency = <16000000>; + spi-cs-setup-delay-ns = <200>; + spi-cs-hold-delay-ns = <200>; + spi-interframe-delay-ns = <100>; }; + }; diff --git a/tests/drivers/spi/spi_loopback/boards/mcxw72_evk_mcxw727c_cpu0.overlay b/tests/drivers/spi/spi_loopback/boards/mcxw72_evk_mcxw727c_cpu0.overlay index baa1ce3c6ed86..9ec47673a5beb 100644 --- a/tests/drivers/spi/spi_loopback/boards/mcxw72_evk_mcxw727c_cpu0.overlay +++ b/tests/drivers/spi/spi_loopback/boards/mcxw72_evk_mcxw727c_cpu0.overlay @@ -9,10 +9,16 @@ compatible = "test-spi-loopback-slow"; reg = <0>; spi-max-frequency = <500000>; + spi-cs-setup-delay-ns = <1000>; + spi-cs-hold-delay-ns = <1000>; + spi-interframe-delay-ns = <1000>; }; fast@0 { compatible = "test-spi-loopback-fast"; reg = <0>; spi-max-frequency = <16000000>; + spi-cs-setup-delay-ns = <200>; + spi-cs-hold-delay-ns = <200>; + spi-interframe-delay-ns = <100>; }; }; From 74e566fe0e27260236bf9f080332087805c72ac5 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Mon, 8 Sep 2025 22:23:41 +0200 Subject: [PATCH 385/397] boards: Update all vendors documentation related with Espressif SoCs Update the documentation of ESP32 related boards: * use included sections for common parts * fix the `References` links if applicable. Signed-off-by: Marek Matej --- boards/01space/esp32c3_042_oled/doc/index.rst | 91 +----- boards/adafruit/feather_esp32/doc/index.rst | 71 +++-- .../doc/adafruit_feather_esp32s2.rst | 219 ++------------ .../doc/adafruit_feather_esp32s2_tft.rst | 191 ++---------- .../adafruit_feather_esp32s2_tft_reverse.rst | 180 ++---------- boards/adafruit/feather_esp32s3/doc/index.rst | 248 ++-------------- .../feather_esp32s3_tft/doc/index.rst | 207 ++----------- .../feather_esp32s3_tft_reverse/doc/index.rst | 208 ++------------ boards/adafruit/qt_py_esp32s3/doc/index.rst | 218 +------------- boards/aithinker/esp32_cam/doc/index.rst | 62 ++-- boards/dptechnics/walter/doc/index.rst | 166 ++--------- boards/espressif/common/board-variants.rst | 7 +- boards/espressif/common/building-flashing.rst | 8 +- boards/espressif/common/openocd-debugging.rst | 8 +- .../espressif/common/soc-esp32-features.rst | 43 +++ .../espressif/common/soc-esp32c2-features.rst | 42 +++ .../espressif/common/soc-esp32c3-features.rst | 46 +++ .../espressif/common/soc-esp32c6-features.rst | 93 ++++++ .../espressif/common/soc-esp32h2-features.rst | 68 +++++ .../espressif/common/soc-esp32s2-features.rst | 35 +++ .../espressif/common/soc-esp32s3-features.rst | 76 +++++ .../espressif/common/system-requirements.rst | 17 ++ boards/espressif/esp32_devkitc/doc/index.rst | 89 +----- .../esp32_ethernet_kit/doc/index.rst | 44 +-- .../espressif/esp32c3_devkitc/doc/index.rst | 45 +-- .../espressif/esp32c3_devkitm/doc/index.rst | 45 +-- boards/espressif/esp32c3_rust/doc/index.rst | 43 +-- .../espressif/esp32c6_devkitc/doc/index.rst | 104 +------ .../espressif/esp32h2_devkitm/doc/index.rst | 79 +---- .../espressif/esp32s2_devkitc/doc/index.rst | 44 +-- boards/espressif/esp32s2_saola/doc/index.rst | 44 +-- .../espressif/esp32s3_devkitc/doc/index.rst | 85 +----- .../espressif/esp32s3_devkitm/doc/index.rst | 85 +----- boards/espressif/esp32s3_eye/doc/index.rst | 25 +- .../espressif/esp8684_devkitm/doc/index.rst | 49 +--- boards/espressif/esp_wrover_kit/doc/index.rst | 69 ++--- boards/espressif/index.rst | 2 +- .../esp32s2_franzininho/doc/index.rst | 172 ++--------- boards/hardkernel/odroid_go/doc/index.rst | 193 ++----------- .../heltec_wifi_lora32_v2/doc/index.rst | 181 ++---------- .../doc/index.rst | 177 ++---------- .../kincony/kincony_kc868_a32/doc/index.rst | 62 ++-- boards/lilygo/tdongle_s3/doc/index.rst | 163 ++--------- boards/lilygo/ttgo_lora32/doc/index.rst | 180 ++---------- boards/lilygo/ttgo_t7v1_5/doc/index.rst | 160 ++--------- boards/lilygo/ttgo_t8c3/doc/index.rst | 181 ++---------- boards/lilygo/ttgo_t8s3/doc/index.rst | 161 ++--------- boards/lilygo/ttgo_tbeam/doc/index.rst | 184 ++---------- boards/lilygo/ttgo_toiplus/doc/index.rst | 171 ++--------- boards/lilygo/twatch_s3/doc/index.rst | 157 ++-------- .../luatos/esp32c3_luatos_core/doc/index.rst | 238 ++------------- .../luatos/esp32s3_luatos_core/doc/index.rst | 272 ++---------------- .../m5stack/m5stack_atom_lite/doc/index.rst | 83 ++---- boards/m5stack/m5stack_atoms3/doc/index.rst | 84 ++---- .../m5stack/m5stack_atoms3_lite/doc/index.rst | 81 ++---- boards/m5stack/m5stack_core2/doc/index.rst | 97 ++----- boards/m5stack/m5stack_cores3/doc/index.rst | 239 ++------------- boards/m5stack/m5stack_fire/doc/index.rst | 95 ++---- boards/m5stack/m5stack_stamps3/doc/index.rst | 94 +++--- boards/m5stack/m5stickc_plus/doc/index.rst | 182 ++---------- boards/m5stack/stamp_c3/doc/index.rst | 173 ++--------- boards/olimex/olimex_esp32_evb/doc/index.rst | 188 ++---------- boards/others/esp32c3_supermini/doc/index.rst | 199 ++----------- boards/others/icev_wireless/doc/index.rst | 183 ++---------- boards/seeed/seeeduino_xiao/doc/index.rst | 11 +- boards/seeed/xiao_esp32c3/doc/index.rst | 161 ++--------- boards/seeed/xiao_esp32c6/doc/index.rst | 175 ++--------- boards/seeed/xiao_esp32s3/doc/index.rst | 177 ++---------- boards/vcc-gnd/yd_esp32/doc/index.rst | 240 +++------------- boards/waveshare/esp32s3_matrix/doc/index.rst | 200 ++----------- .../esp32s3_touch_lcd_1_28/doc/index.rst | 83 ++---- boards/we/orthosie1ev/doc/index.rst | 200 +------------ boards/weact/weact_esp32s3_b/doc/index.rst | 84 +----- boards/wemos/esp32s2_lolin_mini/doc/index.rst | 90 ++---- 74 files changed, 1523 insertions(+), 7404 deletions(-) create mode 100644 boards/espressif/common/soc-esp32-features.rst create mode 100644 boards/espressif/common/soc-esp32c2-features.rst create mode 100644 boards/espressif/common/soc-esp32c3-features.rst create mode 100644 boards/espressif/common/soc-esp32c6-features.rst create mode 100644 boards/espressif/common/soc-esp32h2-features.rst create mode 100644 boards/espressif/common/soc-esp32s2-features.rst create mode 100644 boards/espressif/common/soc-esp32s3-features.rst create mode 100644 boards/espressif/common/system-requirements.rst diff --git a/boards/01space/esp32c3_042_oled/doc/index.rst b/boards/01space/esp32c3_042_oled/doc/index.rst index 801e8651cfa67..f51a329b605f1 100644 --- a/boards/01space/esp32c3_042_oled/doc/index.rst +++ b/boards/01space/esp32c3_042_oled/doc/index.rst @@ -3,7 +3,7 @@ Overview ******** -ESP32C3 0.42 OLED is a mini development board based on the `Espressif ESP32-C3`_ +ESP32-C3 0.42 OLED is a mini development board based on the `Espressif ESP32-C3`_ RISC-V WiFi/Bluetooth dual-mode chip. For more details see the `01space ESP32C3 0.42 OLED`_ Github repo. @@ -31,10 +31,8 @@ It features: The ESP32-C3 does not have native USB, it has an on-chip USB-serial converter instead. -Supported Features -================== - -.. zephyr:board-supported-hw:: +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features Connections and IOs =================== @@ -50,87 +48,28 @@ See the following image: It also features a 0.42 inch OLED display, driven by a SSD1306-compatible chip. It is connected over I2C: SDA on GPIO5, SCL on GPIO6. -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs. Run the command below to -retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +System Requirements +******************* - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* .. zephyr:board-supported-runners:: -Standalone application -====================== - -The board can be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - This mode does not provide any security features nor OTA updates. - -Use the following command to build a sample hello_world application: - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_042_oled - :goals: build - -Sysbuild -======== - -:ref:`sysbuild` makes it possible to build and flash all necessary images needed to -bootstrap the board. - -By default, the ESP32 sysbuild configuration creates bootloader (MCUboot) and -application images. - -To build the sample application using sysbuild, use this command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: esp32c3_042_oled - :goals: build - :west-args: --sysbuild - :compact: - -Flashing -======== - -For the :code:`Hello, world!` application, follow the instructions below. -Assuming the board is connected to ``/dev/ttyACM0`` on Linux. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_042_oled - :goals: flash - :flash-args: --esp-device /dev/ttyACM0 - -Since the Zephyr console is by default on the ``usb_serial`` device, we use -the espressif monitor utility to connect to the console. - -.. code-block:: console - - $ west espressif monitor -p /dev/ttyACM0 +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. code-block:: console +Debugging +========= - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32c3_042_oled +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** diff --git a/boards/adafruit/feather_esp32/doc/index.rst b/boards/adafruit/feather_esp32/doc/index.rst index 9c6141ae0d7e9..a9c6928367b3d 100644 --- a/boards/adafruit/feather_esp32/doc/index.rst +++ b/boards/adafruit/feather_esp32/doc/index.rst @@ -6,6 +6,9 @@ Overview The Adafruit ESP32 Feather is an ESP32-based development board using the Feather standard layout. +Hardware +******** + It features the following integrated components: - ESP32-PICO-V3-02 chip (240MHz dual core, Wi-Fi + BLE) @@ -17,51 +20,42 @@ It features the following integrated components: - Reset and user buttons - STEMMA QT I2C connector +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order to work. Run -the commands below to retrieve the files. - -.. code-block:: shell +System Requirements +******************* - west update - west blobs fetch hal_espressif +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Building & flashing -------------------- +Programming and Debugging +************************* -Use the standard build and flash process for this board. See -:ref:`build_an_application` and :ref:`application_run` for more details. +.. zephyr:board-supported-runners:: -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32/esp32/procpu - :goals: build flash +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -After flashing, view the serial monitor with the espressif monitor command. +Debugging +========= -.. code-block:: shell - - west espressif monitor +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging Testing -======= +******* On-board LED ------------- +============ Test the functionality of the user LED connected to pin 13 with the blinky sample program. @@ -72,7 +66,7 @@ sample program. :goals: build flash NeoPixel --------- +======== Test the on-board NeoPixel using the led_strip sample program. @@ -82,7 +76,7 @@ Test the on-board NeoPixel using the led_strip sample program. :goals: build flash User button ------------ +=========== Test the button labeled SW38 using the button input sample program. @@ -92,7 +86,7 @@ Test the button labeled SW38 using the button input sample program. :goals: build flash Wi-Fi ------ +===== Test ESP32 Wi-Fi functionality using the Wi-Fi shell module. @@ -106,8 +100,11 @@ Test ESP32 Wi-Fi functionality using the Wi-Fi shell module. References ********** -- `Adafruit ESP32 Feather V2 `_ -- `Adafruit ESP32 Feather V2 Pinouts `_ -- `Adafruit ESP32 Feather V2 Schematic `_ -- `ESP32-PICO-MINI-02 Datasheet `_ (PDF) -- `STEMMA QT `_ + +.. target-notes:: + +.. _`Adafruit ESP32 Feather V2`: https://www.adafruit.com/product/5400 +.. _`Adafruit ESP32 Feather V2 Pinouts`: https://learn.adafruit.com/adafruit-esp32-feather-v2/pinouts +.. _`Adafruit ESP32 Feather V2 Schematic`: https://learn.adafruit.com/adafruit-esp32-feather-v2/downloads#schematic-and-fab-print-3112284 +.. _`ESP32-PICO-MINI-02 Datasheet`: https://cdn-learn.adafruit.com/assets/assets/000/109/588/original/esp32-pico-mini-02_datasheet_en.pdf?1646852017 +.. _`STEMMA QT`: https://learn.adafruit.com/introducing-adafruit-stemma-qt diff --git a/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2.rst b/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2.rst index 00779bc87e3f0..b8cef7b3d7f98 100644 --- a/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2.rst +++ b/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2.rst @@ -38,14 +38,17 @@ Hardware NeoPixel and I2C QT port on ``rev B`` boards ``GPIO7`` (``i2c_reg``) needs to be set to LOW and on ``rev C`` boards it needs to be set HIGH. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: .. note:: - USB-OTG is until now not supported see `ESP32 development overview`_. To see a serial output - a FTDI-USB-RS232 or similar needs to be connected to the RX/TX pins on the feather connector. + USB-OTG is until now not supported. To see a serial output a FTDI-USB-RS232 or similar + needs to be connected to the RX/TX pins on the feather connector. Connections and IOs =================== @@ -56,211 +59,28 @@ pinouts and the schematic. - `Adafruit ESP32-S2 Feather Pinouts`_ - `Adafruit ESP32-S2 Feather Schematic`_ -Programming and Debugging -************************* - -.. zephyr:board-supported-runners:: - -Prerequisites -============= - -Espressif HAL requires WiFi binary blobs in order work. Run the command below -to retrieve those files. - -.. code-block:: console - - west update - west blobs fetch hal_espressif - -Building & Flashing +System Requirements ******************* -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage -bootloader. It is the default option when building the application without -additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -**Rev B** - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@B - :goals: build - :west-args: --sysbuild - :compact: - -**Rev C** - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@C - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual: - -**Rev B** - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@B - :goals: build - -**Rev C** - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@C - :goals: build - -The usual ``flash`` target will work. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -To enter ROM bootloader mode, hold down ``boot-button`` while clicking reset button. -When in the ROM bootloader, you can upload code and query the chip using ``west flash``. - - -**Rev B** - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@B - :goals: flash - -**Rev C** - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@C - :goals: flash - -After the flashing you will receive most likely this Error: - -.. code-block:: console - - WARNING: ESP32-S2FNR2 (revision v0.0) chip was placed into download mode using GPIO0. - esptool.py can not exit the download mode over USB. To run the app, reset the chip manually. - To suppress this note, set --after option to 'no_reset'. - FATAL ERROR: command exited with status 1: ... - -As stated in the Warning-Message ``esptool`` can't reset the board by itself and this message -can be ignored and the board needs to be reseted via the Reset-Button manually. - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor +Programming and Debugging +************************* -After the board has been manually reseted and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! adafruit_feather_esp32s2 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S2 support on OpenOCD is available at `OpenOCD`_. +========= -ESP32-S2 has a built-in JTAG circuitry and can be debugged without any -additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor -in `JTAG debugging for ESP32-S2`_. - -You can debug an application in the usual way. Here is an example for -the :zephyr:code-sample:`hello_world` application. - -**Rev B** - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@B - :goals: debug - -**Rev C** - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2@C - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging Testing the On-Board-LED ************************ @@ -392,10 +212,7 @@ References .. _`Adafruit ESP32-S2 Feather`: https://www.adafruit.com/product/5000 .. _`Adafruit ESP32-S2 Feather with BME280 Sensor`: https://www.adafruit.com/product/5303 -.. _`OpenOCD`: https://github.com/openocd-org/openocd -.. _`ESP32 development overview`: https://github.com/zephyrproject-rtos/zephyr/issues/29394#issuecomment-2635037831 .. _`Adafruit ESP32-S2 Feather Pinouts`: https://learn.adafruit.com/adafruit-esp32-s2-feather/pinouts .. _`Adafruit ESP32-S2 Feather Schematic`: https://learn.adafruit.com/adafruit-esp32-s2-feather/downloads .. _`SparkFun Qwiic`: https://www.sparkfun.com/qwiic .. _`STEMMA QT`: https://learn.adafruit.com/introducing-adafruit-stemma-qt -.. _`JTAG debugging for ESP32-S2`: https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-guides/jtag-debugging/index.html diff --git a/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft.rst b/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft.rst index 6629b57feee6d..b04a4e19400ea 100644 --- a/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft.rst +++ b/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft.rst @@ -31,14 +31,17 @@ Hardware - For the MAX17048 and LC709203F a driver in zephyr exists and is supported, but needs to be added via a devicetree overlay. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: .. note:: - USB-OTG is until now not supported see `ESP32 development overview`_. To see a serial output - a FTDI-USB-RS232 or similar needs to be connected to the RX/TX pins on the feather connector. + USB-OTG is until now not supported. To see a serial output a FTDI-USB-RS232 or similar + needs to be connected to the RX/TX pins on the feather connector. Connections and IOs =================== @@ -49,183 +52,28 @@ pinouts and the schematic. - `Adafruit ESP32-S2 TFT Feather Pinouts`_ - `Adafruit ESP32-S2 TFT Feather Schematic`_ -Programming and Debugging -************************* - -.. zephyr:board-supported-runners:: - -Prerequisites -============= - -Espressif HAL requires WiFi binary blobs in order work. Run the command below -to retrieve those files. - -.. code-block:: console - - west update - west blobs fetch hal_espressif - -Building & Flashing +System Requirements ******************* -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage -bootloader. It is the default option when building the application without -additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual: - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft - :goals: build - -The usual ``flash`` target will work. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -To enter ROM bootloader mode, hold down ``boot-button`` while clicking reset button. -When in the ROM bootloader, you can upload code and query the chip using ``west flash``. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft - :goals: flash - -After the flashing you will receive most likely this Error: - -.. code-block:: console - - WARNING: ESP32-S2FNR2 (revision v0.0) chip was placed into download mode using GPIO0. - esptool.py can not exit the download mode over USB. To run the app, reset the chip manually. - To suppress this note, set --after option to 'no_reset'. - FATAL ERROR: command exited with status 1: ... - -As stated in the Warning-Message ``esptool`` can't reset the board by itself and this message -can be ignored and the board needs to be reseted via the Reset-Button manually. - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor +Programming and Debugging +************************* -After the board has been manually reseted and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! adafruit_feather_esp32s2_tft +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S2 support on OpenOCD is available at `OpenOCD`_. - -ESP32-S2 has a built-in JTAG circuitry and can be debugged without any -additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor -in `JTAG debugging for ESP32-S2`_. - -You can debug an application in the usual way. Here is an example for -the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft - :goals: debug - -Testing the On-Board-LED -************************ - -There is a sample available to verify that the LEDs on the board are -functioning correctly with Zephyr: - -.. zephyr-app-commands:: - :zephyr-app: samples/basic/blinky - :board: adafruit_feather_esp32s2_tft - :goals: build flash +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging Testing the NeoPixel ******************** @@ -318,10 +166,7 @@ References .. target-notes:: .. _`Adafruit ESP32-S2 TFT Feather`: https://www.adafruit.com/product/5300 -.. _`OpenOCD`: https://github.com/openocd-org/openocd -.. _`ESP32 development overview`: https://github.com/zephyrproject-rtos/zephyr/issues/29394#issuecomment-2635037831 .. _`Adafruit ESP32-S2 TFT Feather Pinouts`: https://learn.adafruit.com/adafruit-esp32-s2-tft-feather/pinouts .. _`Adafruit ESP32-S2 TFT Feather Schematic`: https://learn.adafruit.com/adafruit-esp32-s2-tft-feather/downloads .. _`SparkFun Qwiic`: https://www.sparkfun.com/qwiic .. _`STEMMA QT`: https://learn.adafruit.com/introducing-adafruit-stemma-qt -.. _`JTAG debugging for ESP32-S2`: https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-guides/jtag-debugging/index.html diff --git a/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft_reverse.rst b/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft_reverse.rst index ad90a07858204..3195a242aa6b2 100644 --- a/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft_reverse.rst +++ b/boards/adafruit/feather_esp32s2/doc/adafruit_feather_esp32s2_tft_reverse.rst @@ -27,14 +27,17 @@ Hardware - For the MAX17048 a driver in zephyr exists and is supported, but needs to be added via a devicetree overlay. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: .. note:: - USB-OTG is until now not supported see `ESP32 development overview`_. To see a serial output - a FTDI-USB-RS232 or similar needs to be connected to the RX/TX pins on the feather connector. + USB-OTG is until now not supported. To see a serial output a FTDI-USB-RS232 or similar + needs to be connected to the RX/TX pins on the feather connector. Connections and IOs =================== @@ -45,172 +48,28 @@ including pinouts and the schematic. - `Adafruit ESP32-S2 Reverse TFT Feather Pinouts`_ - `Adafruit ESP32-S2 Reverse TFT Feather Schematic`_ -Programming and Debugging -************************* - -.. zephyr:board-supported-runners:: - -Prerequisites -============= - -Espressif HAL requires WiFi binary blobs in order work. Run the command below -to retrieve those files. - -.. code-block:: console - - west update - west blobs fetch hal_espressif - -Building & Flashing +System Requirements ******************* -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage -bootloader. It is the default option when building the application without -additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft_reverse - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual: - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft_reverse - :goals: build - -The usual ``flash`` target will work. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -To enter ROM bootloader mode, hold down ``boot-button`` while clicking reset button. -When in the ROM bootloader, you can upload code and query the chip using ``west flash``. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft_reverse - :goals: flash - -After the flashing you will receive most likely this Error: - -.. code-block:: console - - WARNING: ESP32-S2FNR2 (revision v0.0) chip was placed into download mode using GPIO0. - esptool.py can not exit the download mode over USB. To run the app, reset the chip manually. - To suppress this note, set --after option to 'no_reset'. - FATAL ERROR: command exited with status 1: ... - -As stated in the Warning-Message ``esptool`` can't reset the board by itself and this message -can be ignored and the board needs to be reseted via the Reset-Button manually. - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor +Programming and Debugging +************************* -After the board has been manually reseted and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! adafruit_feather_esp32s2_tft_reverse +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S2 support on OpenOCD is available at `OpenOCD`_. - -ESP32-S2 has a built-in JTAG circuitry and can be debugged without any -additional chip. Only an USB cable connected to the D+/D- pins is necessary. +========= -Further documentation can be obtained from the SoC vendor -in `JTAG debugging for ESP32-S2`_. - -You can debug an application in the usual way. Here is an example for -the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s2_tft_reverse - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging Testing the On-Board-LED ************************ @@ -280,10 +139,7 @@ References .. target-notes:: .. _`Adafruit ESP32-S2 Reverse TFT Feather`: https://www.adafruit.com/product/5345 -.. _`OpenOCD`: https://github.com/openocd-org/openocd -.. _`ESP32 development overview`: https://github.com/zephyrproject-rtos/zephyr/issues/29394#issuecomment-2635037831 .. _`Adafruit ESP32-S2 Reverse TFT Feather Pinouts`: https://learn.adafruit.com/esp32-s2-reverse-tft-feather/pinouts .. _`Adafruit ESP32-S2 Reverse TFT Feather Schematic`: https://learn.adafruit.com/esp32-s2-reverse-tft-feather/downloads .. _`SparkFun Qwiic`: https://www.sparkfun.com/qwiic .. _`STEMMA QT`: https://learn.adafruit.com/introducing-adafruit-stemma-qt -.. _`JTAG debugging for ESP32-S2`: https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-guides/jtag-debugging/index.html diff --git a/boards/adafruit/feather_esp32s3/doc/index.rst b/boards/adafruit/feather_esp32s3/doc/index.rst index 17332ba68fab6..d4fc4a1d12a76 100644 --- a/boards/adafruit/feather_esp32s3/doc/index.rst +++ b/boards/adafruit/feather_esp32s3/doc/index.rst @@ -23,59 +23,13 @@ Hardware - Built-in NeoPixel indicator RGB LED - STEMMA QT connector for I2C devices, with switchable power for low-power mode -Asymmetric Multiprocessing (AMP) -================================ - -The ESP32-S3 SoC allows 2 different applications to be executed in asymmetric -multiprocessing. Due to its dual-core architecture, each core can be enabled to -execute customized tasks in stand-alone mode and/or exchanging data over OpenAMP -framework. See :zephyr:code-sample-category:`ipc` folder as code reference. - -For more information, check the datasheet at `ESP32-S3 Datasheet`_. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features Supported Features ================== -The current ``adafruit_feather_esp32s3`` board supports the following hardware -features: - -+------------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+============+============+=====================================+ -| UART | on-chip | serial port | -+------------+------------+-------------------------------------+ -| GPIO | on-chip | gpio | -+------------+------------+-------------------------------------+ -| PINMUX | on-chip | pinmux | -+------------+------------+-------------------------------------+ -| USB-JTAG | on-chip | hardware interface | -+------------+------------+-------------------------------------+ -| SPI Master | on-chip | spi | -+------------+------------+-------------------------------------+ -| TWAI/CAN | on-chip | can | -+------------+------------+-------------------------------------+ -| ADC | on-chip | adc | -+------------+------------+-------------------------------------+ -| Timers | on-chip | counter | -+------------+------------+-------------------------------------+ -| Watchdog | on-chip | watchdog | -+------------+------------+-------------------------------------+ -| TRNG | on-chip | entropy | -+------------+------------+-------------------------------------+ -| LEDC | on-chip | pwm | -+------------+------------+-------------------------------------+ -| MCPWM | on-chip | pwm | -+------------+------------+-------------------------------------+ -| PCNT | on-chip | qdec | -+------------+------------+-------------------------------------+ -| GDMA | on-chip | dma | -+------------+------------+-------------------------------------+ -| USB-CDC | on-chip | serial | -+------------+------------+-------------------------------------+ -| Wi-Fi | on-chip | | -+------------+------------+-------------------------------------+ -| Bluetooth | on-chip | | -+------------+------------+-------------------------------------+ +.. zephyr:board-supported-hw:: Connections and IOs =================== @@ -83,199 +37,35 @@ Connections and IOs The `Adafruit Feather ESP32-S3 User Guide`_ has detailed information about the board including `pinouts`_ and the `schematic`_. +System Requirements +******************* + +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements + Programming and Debugging ************************* .. zephyr:board-supported-runners:: -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the -command below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -=================== - -Simple boot ------------ - -The board could be loaded using the single binary image, without 2nd stage -bootloader. It is the default option when building the application without -additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader ------------------- - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be build (and flash) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild --------- - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-S3 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-S3 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` -documentation. - -Manual build ------------- - -During the development cycle, it is intended to build & flash as quickly -possible. For that reason, images can be build one at a time using traditional -build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``adafruit_feather_esp32s3`` board -. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! adafruit_feather_esp32s3 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ========= -ESP32-S3 support on OpenOCD is available upstream as of version 0.12.0. Download -and install OpenOCD from `OpenOCD`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any -additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor in `JTAG debugging -for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3/esp32s3/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the -:zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3/esp32s3/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. _`Adafruit Feather ESP32-S3`: - https://www.adafruit.com/product/5323 - -.. _`OpenOCD`: - https://github.com/openocd-org/openocd - -.. _`JTAG debugging for ESP32-S3`: - https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ - -.. _Adafruit Feather ESP32-S3 User Guide: - https://learn.adafruit.com/adafruit-esp32-s3-feather - -.. _pinouts: - https://learn.adafruit.com/adafruit-esp32-s3-feather/pinouts - -.. _schematic: - https://learn.adafruit.com/adafruit-esp32-s3-feather/downloads - -.. _ESP32-S3 Datasheet: - https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf - -.. _ESP32 Technical Reference Manual: - https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf +.. _`Adafruit Feather ESP32-S3`: https://www.adafruit.com/product/5323 +.. _`Adafruit Feather ESP32-S3 User Guide`: https://learn.adafruit.com/adafruit-esp32-s3-feather +.. _`pinouts`: https://learn.adafruit.com/adafruit-esp32-s3-feather/pinouts +.. _`schematic`: https://learn.adafruit.com/adafruit-esp32-s3-feather/downloads diff --git a/boards/adafruit/feather_esp32s3_tft/doc/index.rst b/boards/adafruit/feather_esp32s3_tft/doc/index.rst index 7324debe849da..af2e61d0a2f68 100644 --- a/boards/adafruit/feather_esp32s3_tft/doc/index.rst +++ b/boards/adafruit/feather_esp32s3_tft/doc/index.rst @@ -25,15 +25,8 @@ Hardware - STEMMA QT connector for I2C devices, with switchable power for low-power mode - 240x135 pixel IPS TFT color display with 1.14" diagonal and ST7789 chipset -Asymmetric Multiprocessing (AMP) -================================ - -The ESP32-S3 SoC allows 2 different applications to be executed in asymmetric -multiprocessing. Due to its dual-core architecture, each core can be enabled to -execute customized tasks in stand-alone mode and/or exchanging data over OpenAMP -framework. See :zephyr:code-sample-category:`ipc` folder as code reference. - -For more information, check the datasheet at `ESP32-S3 Datasheet`_. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features Supported Features ================== @@ -85,199 +78,35 @@ Connections and IOs The `Adafruit Feather ESP32-S3 TFT User Guide`_ has detailed information about the board including `pinouts`_ and the `schematic`_. +System Requirements +******************* + +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements + Programming and Debugging ************************* .. zephyr:board-supported-runners:: -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the -command below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -=================== - -Simple boot ------------ - -The board could be loaded using the single binary image, without 2nd stage -bootloader. It is the default option when building the application without -additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader ------------------- - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be build (and flash) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild --------- - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-S3 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-S3 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` -documentation. - -Manual build ------------- - -During the development cycle, it is intended to build & flash as quickly -possible. For that reason, images can be build one at a time using traditional -build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``adafruit_feather_esp32s3_tft`` -board. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! adafruit_feather_esp32s3_tft +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ========= -ESP32-S3 support on OpenOCD is available upstream as of version 0.12.0. Download -and install OpenOCD from `OpenOCD`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any -additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor in `JTAG debugging -for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft/esp32s3/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the -:zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft/esp32s3/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. _`Adafruit Feather ESP32-S3 TFT`: - https://www.adafruit.com/product/5483 - -.. _`OpenOCD`: - https://github.com/openocd-org/openocd - -.. _`JTAG debugging for ESP32-S3`: - https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ - -.. _Adafruit Feather ESP32-S3 TFT User Guide: - https://learn.adafruit.com/adafruit-esp32-s3-tft-feather - -.. _pinouts: - https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/pinouts - -.. _schematic: - https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/downloads - -.. _ESP32-S3 Datasheet: - https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf - -.. _ESP32 Technical Reference Manual: - https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf +.. _`Adafruit Feather ESP32-S3 TFT`: https://www.adafruit.com/product/5483 +.. _`Adafruit Feather ESP32-S3 TFT User Guide`: https://learn.adafruit.com/adafruit-esp32-s3-tft-feather +.. _`pinouts`: https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/pinouts +.. _`schematic`: https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/downloads diff --git a/boards/adafruit/feather_esp32s3_tft_reverse/doc/index.rst b/boards/adafruit/feather_esp32s3_tft_reverse/doc/index.rst index 98135629d74b2..2df52d4526a48 100644 --- a/boards/adafruit/feather_esp32s3_tft_reverse/doc/index.rst +++ b/boards/adafruit/feather_esp32s3_tft_reverse/doc/index.rst @@ -29,16 +29,8 @@ Hardware - Three User Tactile buttons - D0, D1, and D2. D0/BOOT0 is also used for entering ROM bootloader mode if necessary. - -Asymmetric Multiprocessing (AMP) -================================ - -The ESP32-S3 SoC allows 2 different applications to be executed in asymmetric -multiprocessing. Due to its dual-core architecture, each core can be enabled to -execute customized tasks in stand-alone mode and/or exchanging data over OpenAMP -framework. See :zephyr:code-sample-category:`ipc` folder as code reference. - -For more information, check the datasheet at `ESP32-S3 Datasheet`_. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features Supported Features ================== @@ -51,199 +43,35 @@ Connections and IOs The `Adafruit ESP32-S3 Reverse TFT Feather User Guide`_ has detailed information about the board including `pinouts`_ and the `schematic`_. +System Requirements +******************* + +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements + Programming and Debugging ************************* .. zephyr:board-supported-runners:: -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the -command below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -=================== - -Simple boot ------------ - -The board could be loaded using the single binary image, without 2nd stage -bootloader. It is the default option when building the application without -additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader ------------------- - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be build (and flash) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild --------- - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-S3 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft_reverse/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-S3 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` -documentation. - -Manual build ------------- - -During the development cycle, it is intended to build & flash as quickly -possible. For that reason, images can be build one at a time using traditional -build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: :board: adafruit_feather_esp32s3_tft_reverse/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``adafruit_feather_esp32s3_tft_reverse`` -board. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft_reverse/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! adafruit_feather_esp32s3_tft_reverse/esp32s3/procpu +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ========= -ESP32-S3 support on OpenOCD is available upstream as of version 0.12.0. Download -and install OpenOCD from `OpenOCD`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any -additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor in `JTAG debugging -for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft_reverse/esp32s3/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the -:zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_feather_esp32s3_tft_reverse/esp32s3/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. _`Adafruit ESP32-S3 Reverse TFT Feather`: - https://www.adafruit.com/product/5691 - -.. _`OpenOCD`: - https://github.com/openocd-org/openocd - -.. _`JTAG debugging for ESP32-S3`: - https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ - -.. _Adafruit ESP32-S3 Reverse TFT Feather User Guide: - https://learn.adafruit.com/esp32-s3-reverse-tft-feather - -.. _pinouts: - https://learn.adafruit.com/esp32-s3-reverse-tft-feather/pinouts - -.. _schematic: - https://learn.adafruit.com/esp32-s3-reverse-tft-feather/downloads - -.. _ESP32-S3 Datasheet: - https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf - -.. _ESP32 Technical Reference Manual: - https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf +.. _`Adafruit ESP32-S3 Reverse TFT Feather`: https://www.adafruit.com/product/5691 +.. _`Adafruit ESP32-S3 Reverse TFT Feather User Guide`: https://learn.adafruit.com/esp32-s3-reverse-tft-feather +.. _`pinouts`: https://learn.adafruit.com/esp32-s3-reverse-tft-feather/pinouts +.. _`schematic`: https://learn.adafruit.com/esp32-s3-reverse-tft-feather/downloads diff --git a/boards/adafruit/qt_py_esp32s3/doc/index.rst b/boards/adafruit/qt_py_esp32s3/doc/index.rst index 8ad715a673c0d..57f47442c784e 100644 --- a/boards/adafruit/qt_py_esp32s3/doc/index.rst +++ b/boards/adafruit/qt_py_esp32s3/doc/index.rst @@ -23,222 +23,36 @@ bootloader or user input. Like many other Adafruit boards, it has a `SparkFun Qwiic`_-compatible `STEMMA QT`_ connector for the I2C bus so you don't even need to solder. -ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated -2.4 GHz Wi-Fi and Bluetooth® Low Energy (Bluetooth LE). It consists of -high-performance dual-core microprocessor (Xtensa® 32-bit LX7), a low power -coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, RF module, and -numerous peripherals. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features Supported Features ================== .. zephyr:board-supported-hw:: -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the -command below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage -bootloader. It is the default option when building the application without -additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3 - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. +Programming and Debugging +************************* -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. tabs:: - - .. group-tab:: QT Py ESP32S3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3/esp32s3/procpu - :goals: build - - .. group-tab:: QT Py ESP32S3 with PSRAM - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``adafruit_qt_py_esp32s3`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. tabs:: - - .. group-tab:: QT Py ESP32S3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3/esp32s3/procpu - :goals: flash - - .. group-tab:: QT Py ESP32S3 with PSRAM - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! adafruit_qt_py_esp32s3/esp32s3/procpu +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S3 support on OpenOCD is available at `OpenOCD ESP32`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any -additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor -in `JTAG debugging for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. tabs:: - - .. group-tab:: QT Py ESP32S3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3/esp32s3/procpu - :goals: debug - - .. group-tab:: QT Py ESP32S3 with PSRAM - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu - :goals: debug - -You can debug an application in the usual way. Here is an example for -the :zephyr:code-sample:`hello_world` application. - -.. tabs:: - - .. group-tab:: QT Py ESP32S3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3/esp32s3/procpu - :goals: debug - - .. group-tab:: QT Py ESP32S3 with PSRAM +========= - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -247,7 +61,5 @@ References .. _`Adafruit QT Py ESP32S3`: https://www.adafruit.com/product/5426 .. _`Adafruit QT Py ESP32S3 - PSRAM`: https://www.adafruit.com/product/5700 -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases .. _`SparkFun Qwiic`: https://www.sparkfun.com/qwiic .. _`STEMMA QT`: https://learn.adafruit.com/introducing-adafruit-stemma-qt diff --git a/boards/aithinker/esp32_cam/doc/index.rst b/boards/aithinker/esp32_cam/doc/index.rst index 4e6efe50e34da..605abe9b3aa2a 100644 --- a/boards/aithinker/esp32_cam/doc/index.rst +++ b/boards/aithinker/esp32_cam/doc/index.rst @@ -5,6 +5,9 @@ Overview Ai-Thinker ESP32-CAM is an ESP32-based development board produced by `Ai-Thinker `_. +Hardware +******** + ESP32-CAM features the following components: - ESP32S module @@ -17,27 +20,19 @@ ESP32-CAM features the following components: ESP32's GPIO4 on the ESP32 is shared between the MicroSD data pin and the onboard flash LED. -For more information, check the datasheet at `ESP32 Datasheet`_ or the technical reference -manual at `ESP32 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features Supported Features -****************** +================== .. zephyr:board-supported-hw:: -System requirements +System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -50,23 +45,11 @@ Programming and Debugging .. include:: ../../../espressif/common/board-variants.rst :start-after: espressif-board-variants -Applications for the ``esp32_cam`` board can be built and flashed in the usual way -(see :ref:`build_an_application` and :ref:`application_run` for more details); -however, an external FTDI USB to TTL Serial Adapter is required since the board -does not have any on-board debug IC. - -The following pins of the Serial Adapter must be connected to the header pins: - -* VTref = VCC -* GND = GND -* TXD = U0TXD -* RXD = U0RXD -* Boot = GPIO0 (Must be low at boot) - Debugging ========= -ESP32 support on OpenOCD is available at `OpenOCD ESP32`_. +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging +------------+-----------+ | ESP32 pin | JTAG pin | @@ -84,14 +67,21 @@ ESP32 support on OpenOCD is available at `OpenOCD ESP32`_. | IO15 | TDO | +------------+-----------+ -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32`_. +Sample Applications +******************* + +Applications for the ``esp32_cam`` board can be built and flashed in the usual way +(see :ref:`build_an_application` and :ref:`application_run` for more details); +however, an external FTDI USB to TTL Serial Adapter is required since the board +does not have any on-board debug IC. -Here is an example for building the :zephyr:code-sample:`hello_world` application. +The following pins of the Serial Adapter must be connected to the header pins: -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_cam/esp32/procpu - :goals: build flash +* VTref = VCC +* GND = GND +* TXD = U0TXD +* RXD = U0RXD +* Boot = GPIO0 (Must be low at boot) References ********** @@ -99,7 +89,3 @@ References .. target-notes:: .. _`ESP32-CAM`: https://docs.ai-thinker.com/en/esp32-cam -.. _`ESP32 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf -.. _`ESP32 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/dptechnics/walter/doc/index.rst b/boards/dptechnics/walter/doc/index.rst index eb5dc5e3d50f2..254686992e927 100644 --- a/boards/dptechnics/walter/doc/index.rst +++ b/boards/dptechnics/walter/doc/index.rst @@ -55,168 +55,36 @@ Form factor - Pin and footprint compatible with EOL Pycom GPy - Breadboard friendly +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be build (and flash) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-S3 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :app: samples/hello_world - :board: walter/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. +Programming and Debugging +************************* -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be build one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: walter/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``walter`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: walter/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! walter/esp32s3/procpu +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S3 support on OpenOCD is available at `OpenOCD ESP32`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: walter/esp32s3/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: walter/esp32s3/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -225,5 +93,3 @@ References .. _`QuickSpot Website`: https://www.quickspot.io/ .. _`QuickSpot GitHub page`: https://github.com/QuickSpot -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ -.. _`OpenOCD ESP32`: https://github.com/openocd-org/openocd diff --git a/boards/espressif/common/board-variants.rst b/boards/espressif/common/board-variants.rst index b04cdc57b5f0a..0fffde9c64602 100644 --- a/boards/espressif/common/board-variants.rst +++ b/boards/espressif/common/board-variants.rst @@ -42,4 +42,9 @@ To apply a board variant, use the ``-S`` flag with west build: :snippets: flash-32M,psram-4M :compact: -**Note:** These snippets are applicable to boards with compatible hardware support for the selected flash/PSRAM configuration. +.. note:: + + These snippets are applicable to boards with compatible hardware support for the selected flash/PSRAM configuration. + + - If no FLASH snippet is used, the board default flash size will be used. + - If no PSRAM snippet is used, the board default psram size will be used. diff --git a/boards/espressif/common/building-flashing.rst b/boards/espressif/common/building-flashing.rst index 4cf1df30f8bae..f924043211951 100644 --- a/boards/espressif/common/building-flashing.rst +++ b/boards/espressif/common/building-flashing.rst @@ -2,7 +2,7 @@ .. espressif-building-flashing -Simple boot +Simple Boot =========== The board could be loaded using the single binary image, without 2nd stage bootloader. @@ -12,7 +12,7 @@ It is the default option when building the application without additional config Simple boot does not provide any security features nor OTA updates. -MCUboot bootloader +MCUboot Bootloader ================== User may choose to use MCUboot bootloader instead. In that case the bootloader @@ -74,7 +74,7 @@ Zephyr build. Output is structured by the domain subdirectories: For more information about the system build please read the :ref:`sysbuild` documentation. -Manual build +Manual Build ============ During the development cycle, it is intended to build & flash as quickly possible. @@ -117,3 +117,5 @@ message in the monitor: ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** Hello World! + +.. _`Zephyr Support Status`: https://developer.espressif.com/software/zephyr-support-status/ diff --git a/boards/espressif/common/openocd-debugging.rst b/boards/espressif/common/openocd-debugging.rst index 7e6fccd4d7746..71d75389eb793 100644 --- a/boards/espressif/common/openocd-debugging.rst +++ b/boards/espressif/common/openocd-debugging.rst @@ -7,12 +7,14 @@ OpenOCD As with much custom hardware, the ESP32 modules require patches to OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD for ESP32 `_. +the project. The custom OpenOCD can be obtained at `OpenOCD for ESP32`_. The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the ``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` parameter when building. +Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32`_. + Here is an example for building the :zephyr:code-sample:`hello_world` application. .. zephyr-app-commands:: @@ -27,3 +29,7 @@ You can debug an application in the usual way. Here is an example for the :zephy :zephyr-app: samples/hello_world :board: :goals: debug + + +.. _`OpenOCD for ESP32`: https://github.com/espressif/openocd-esp32/releases +.. _`JTAG debugging for ESP32`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html diff --git a/boards/espressif/common/soc-esp32-features.rst b/boards/espressif/common/soc-esp32-features.rst new file mode 100644 index 0000000000000..f82274e7317b0 --- /dev/null +++ b/boards/espressif/common/soc-esp32-features.rst @@ -0,0 +1,43 @@ +:orphan: + +.. espressif-soc-esp32-features + +ESP32 Features +============== + +- Dual core Xtensa microprocessor (LX6), running at 160 or 240MHz +- 520KB of SRAM +- 802.11b/g/n/e/i +- Bluetooth v4.2 BR/EDR and BLE +- Various peripherals: + + - 12-bit ADC with up to 18 channels + - 2x 8-bit DACs + - 10x touch sensors + - 4x SPI + - 2x I2S + - 2x I2C + - 3x UART + - SD/SDIO/MMC host + - Slave (SDIO/SPI) + - Ethernet MAC + - CAN bus 2.0 + - IR (RX/TX) + - Motor PWM + - LED PWM with up to 16 channels + - Hall effect sensor + - Temperature sensor + +- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) +- 5uA deep sleep current + +Asymmetric Multiprocessing (AMP) +================================ + +ESP32 allows 2 different applications to be executed in ESP32 SoC. Due to its dual-core architecture, each core can be enabled to execute customized tasks in stand-alone mode +and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference. + +For more information, check the `ESP32 Datasheet`_ or the `ESP32 Technical Reference Manual`_. + +.. _`ESP32 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf +.. _`ESP32 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf diff --git a/boards/espressif/common/soc-esp32c2-features.rst b/boards/espressif/common/soc-esp32c2-features.rst new file mode 100644 index 0000000000000..17c713e540586 --- /dev/null +++ b/boards/espressif/common/soc-esp32c2-features.rst @@ -0,0 +1,42 @@ +:orphan: + +.. espressif-soc-esp32c2-features + +ESP32-C2 Features +================= + +ESP32-C2 (ESP8684 core) is a low-cost, Wi-Fi 4 & Bluetooth 5 (LE) chip. Its unique design +makes the chip smaller and yet more powerful than ESP8266. ESP32-C2 is built around a RISC-V +32-bit, single-core processor, with 272 KB of SRAM (16 KB dedicated to cache) and 576 KB of ROM. +ESP32-C2 has been designed to target simple, high-volume, and low-data-rate IoT applications, +such as smart plugs and smart light bulbs. ESP32-C2 offers easy and robust wireless connectivity, +which makes it the go-to solution for developing simple, user-friendly and reliable +smart-home devices. + +Features include the following: + +- 32-bit core RISC-V microcontroller with a maximum clock speed of 120 MHz +- 2 MB or 4 MB in chip (ESP8684) or in package (ESP32-C2) flash +- 272 KB of internal RAM +- 802.11b/g/n +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh +- Various peripherals: + + - General DMA controller (GDMA) + - LED PWM controller, with up to 6 channels + - 14 programmable GPIOs + - 3 SPI + - 2 UART + - 1 I2C Master + - 1 12-bit SAR ADC, up to 5 channels + - 1 temperature sensor + - 1 54-bit general-purpose timer + - 2 watchdog timers + - 1 52-bit system timer + +- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) + +For detailed information check the `ESP8684 Datasheet`_ or the `ESP8684 Technical Reference Manual`_. + +.. _`ESP8684 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp8684_datasheet_en.pdf +.. _`ESP8684 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp8684_technical_reference_manual_en.pdf diff --git a/boards/espressif/common/soc-esp32c3-features.rst b/boards/espressif/common/soc-esp32c3-features.rst new file mode 100644 index 0000000000000..fb48b9319bbe9 --- /dev/null +++ b/boards/espressif/common/soc-esp32c3-features.rst @@ -0,0 +1,46 @@ +:orphan: + +.. espressif-soc-esp32c3-features + +ESP32-C3 Features +================= + +ESP32-C3 is a single-core Wi-Fi and Bluetooth 5 (LE) microcontroller SoC, +based on the open-source RISC-V architecture. It strikes the right balance of power, +I/O capabilities and security, thus offering the optimal cost-effective +solution for connected devices. +The availability of Wi-Fi and Bluetooth 5 (LE) connectivity not only makes the device configuration easy, +but it also facilitates a variety of use-cases based on dual connectivity. + +The features include the following: + +- 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz +- 802.11b/g/n/ +- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh +- 384 KB ROM +- 400 KB SRAM (16 KB for cache) +- 8 KB SRAM in RTC +- 22 x programmable GPIOs +- Various peripherals: + + - Full-speed USB Serial/JTAG controller + - TWAI® compatible with CAN bus 2.0 + - General DMA controller (GDMA) + - 2x 12-bit SAR ADC with up to 6 channels + - 3x SPI + - 2x UART + - 1x I2S + - 1x I2C + - 2 x 54-bit general-purpose timers + - 3 x watchdog timers + - 1 x 52-bit system timer + - Remote Control Peripheral (RMT) + - LED PWM controller (LEDC) with up to 6 channels + - Temperature sensor + +- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) + +For more information, check the `ESP32-C3 Datasheet`_ or the `ESP32-C3 Technical Reference Manual`_. + +.. _`ESP32-C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf +.. _`ESP32-C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf diff --git a/boards/espressif/common/soc-esp32c6-features.rst b/boards/espressif/common/soc-esp32c6-features.rst new file mode 100644 index 0000000000000..886685815c878 --- /dev/null +++ b/boards/espressif/common/soc-esp32c6-features.rst @@ -0,0 +1,93 @@ +:orphan: + +.. espressif-soc-esp32c6-features + +ESP32-C6 Features +================= + +ESP32-C6 is Espressif's first Wi-Fi 6 SoC integrating 2.4 GHz Wi-Fi 6, Bluetooth 5.3 (LE) and the +802.15.4 protocol. ESP32-C6 achieves an industry-leading RF performance, with reliable security +features and multiple memory resources for IoT products. +It consists of a high-performance (HP) 32-bit RISC-V processor, which can be clocked up to 160 MHz, +and a low-power (LP) 32-bit RISC-V processor, which can be clocked up to 20 MHz. +It has a 320KB ROM, a 512KB SRAM, and works with external flash. + +ESP32-C6 includes the following features: + +- 32-bit core RISC-V microcontroller with a clock speed of up to 160 MHz +- 400 KB of internal RAM +- WiFi 802.11 ax 2.4GHz +- Fully compatible with IEEE 802.11b/g/n protocol +- Bluetooth LE: Bluetooth 5.3 certified +- Internal co-existence mechanism between Wi-Fi and Bluetooth to share the same antenna +- IEEE 802.15.4 (Zigbee and Thread) + +Digital interfaces: + +- 30x GPIOs (QFN40), or 22x GPIOs (QFN32) +- 2x UART +- 1x Low-power (LP) UART +- 1x General purpose SPI +- 1x I2C +- 1x Low-power (LP) I2C +- 1x I2S +- 1x Pulse counter +- 1x USB Serial/JTAG controller +- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) +- 1x SDIO 2.0 slave controller +- LED PWM controller, up to 6 channels +- 1x Motor control PWM (MCPWM) +- 1x Remote control peripehral +- 1x Parallel IO interface (PARLIO) +- General DMA controller (GDMA), with 3 transmit channels and 3 receive channels +- Event task matrix (ETM) + +Analog interfaces: + +- 1x 12-bit SAR ADCs, up to 7 channels +- 1x temperature sensor + +Timers: + +- 1x 52-bit system timer +- 1x 54-bit general-purpose timers +- 3x Watchdog timers +- 1x Analog watchdog timer + +Low Power: + +- Four power modes designed for typical scenarios: Active, Modem-sleep, Light-sleep, Deep-sleep + +Security: + +- Secure boot +- Flash encryption +- 4-Kbit OTP, up to 1792 bits for users +- Cryptographic hardware acceleration: (AES-128/256, ECC, HMAC, RSA, SHA, Digital signature, Hash) +- Random number generator (RNG) + +Low-Power CPU (LP CORE) +======================= + +The ESP32-C6 SoC has two RISC-V cores: the High-Performance Core (HP CORE) and the Low-Power Core (LP CORE). +The LP Core features ultra low power consumption, an interrupt controller, a debug module and a system bus +interface for memory and peripheral access. + +The LP Core is in sleep mode by default. It has two application scenarios: + +- Power insensitive scenario: When the High-Performance CPU (HP Core) is active, the LP Core can assist the HP CPU with some speed and efficiency-insensitive controls and computations. +- Power sensitive scenario: When the HP CPU is in the power-down state to save power, the LP Core can be woken up to handle some external wake-up events. + +The LP Core support is fully integrated with :ref:`sysbuild`. The user can enable the LP Core by adding +the following configuration to the project: + +.. code:: cfg + + CONFIG_ULP_COPROC_ENABLED=y + +See :zephyr:code-sample-category:`lp-core` folder as code reference. + +For more information, check the `ESP32-C6 Datasheet`_ or the `ESP32-C6 Technical Reference Manual`_. + +.. _`ESP32-C6 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf +.. _`ESP32-C6 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf diff --git a/boards/espressif/common/soc-esp32h2-features.rst b/boards/espressif/common/soc-esp32h2-features.rst new file mode 100644 index 0000000000000..f237a8ecfbd2f --- /dev/null +++ b/boards/espressif/common/soc-esp32h2-features.rst @@ -0,0 +1,68 @@ +:orphan: + +.. espressif-soc-esp32h2-features + +ESP32-H2 Features +================= + +ESP32-H2 combines IEEE 802.15.4 connectivity with Bluetooth 5 (LE). The SoC is powered by +a single-core, 32-bit RISC-V microcontroller that can be clocked up to 96 MHz. The ESP32-H2 has +been designed to ensure low power consumption and security for connected devices. ESP32-H2 has +320 KB of SRAM with 16 KB of Cache, 128 KB of ROM, 4 KB LP of memory, and a built-in 2 MB or 4 MB +SiP flash. It has 19 programmable GPIOs with support for ADC, SPI, UART, I2C, I2S, RMT, GDMA +and LED PWM. + +ESP32-H2 main features: + +- RISC-V 32-bit single-core microprocessor +- 320 KB of internal RAM +- 4 KB LP Memory +- Bluetooth LE: Bluetooth 5.3 certified +- IEEE 802.15.4 (Zigbee and Thread) +- 19 programmable GPIOs +- Numerous peripherals (details below) + +Digital interfaces: + +- 19x GPIOs +- 2x UART +- 2x I2C +- 1x General-purpose SPI +- 1x I2S +- 1x Pulse counter +- 1x USB Serial/JTAG controller +- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) +- 1x LED PWM controller, up to 6 channels +- 1x Motor Control PWM (MCPWM) +- 1x Remote Control peripheral (RMT), with up to 2 TX and 2 RX channels +- 1x Parallel IO interface (PARLIO) +- General DMA controller (GDMA), with 3 transmit channels and 3 receive channels +- Event Task Matrix (ETM) + +Analog interfaces: + +- 1x 12-bit SAR ADCs, up to 5 channels +- 1x Temperature sensor (die) + +Timers: + +- 1x 52-bit system timer +- 2x 54-bit general-purpose timers +- 3x Watchdog timers + +Low Power: + +- Four power modes designed for typical scenarios: Active, Modem-sleep, Light-sleep, Deep-sleep + +Security: + +- Secure boot +- Flash encryption +- 4-Kbit OTP, up to 1792 bits for users +- Cryptographic hardware acceleration: (AES-128/256, ECC, HMAC, RSA, SHA, Digital signature, Hash) +- Random number generator (RNG) + +For detailed information, check the `ESP32-H2 Datasheet`_ or the `ESP32-H2 Technical Reference Manual`_. + +.. _`ESP32-H2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf +.. _`ESP32-H2 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-h2_technical_reference_manual_en.pdf diff --git a/boards/espressif/common/soc-esp32s2-features.rst b/boards/espressif/common/soc-esp32s2-features.rst new file mode 100644 index 0000000000000..44fa59fb5ed62 --- /dev/null +++ b/boards/espressif/common/soc-esp32s2-features.rst @@ -0,0 +1,35 @@ +:orphan: + +.. espressif-soc-esp32s2-features + +ESP32-S2 Features +================= + +ESP32-S2 is a highly integrated, low-power, single-core Wi-Fi Microcontroller SoC, designed to be secure and +cost-effective, with a high performance and a rich set of IO capabilities. + +The features include the following: + +- RSA-3072-based secure boot +- AES-XTS-256-based flash encryption +- Protected private key and device secrets from software access +- Cryptographic accelerators for enhanced performance +- Protection against physical fault injection attacks +- Various peripherals: + + - 43x programmable GPIOs + - 14x configurable capacitive touch GPIOs + - USB OTG + - LCD interface + - camera interface + - SPI + - I2S + - UART + - ADC + - DAC + - LED PWM with up to 8 channels + +For more information, check the `ESP32-S2 Datasheet`_ or the `ESP32-S2 Technical Reference Manual`_. + +.. _`ESP32-S2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf +.. _`ESP32-S2 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf diff --git a/boards/espressif/common/soc-esp32s3-features.rst b/boards/espressif/common/soc-esp32s3-features.rst new file mode 100644 index 0000000000000..c0a338ec14c15 --- /dev/null +++ b/boards/espressif/common/soc-esp32s3-features.rst @@ -0,0 +1,76 @@ +:orphan: + +.. espressif-soc-esp32s3-features + +ESP32-S3 Features +================= + +ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi +and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor +(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, +RF module, and numerous peripherals. + +ESP32-S3 SoC includes the following features: + +- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz +- Additional vector instructions support for AI acceleration +- 512KB of SRAM +- 384KB of ROM +- Wi-Fi 802.11b/g/n +- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate + +Digital interfaces: + +- 45 programmable GPIOs +- 4x SPI +- 1x LCD interface (8-bit ~16-bit parallel RGB, I8080 and MOTO6800), supporting conversion between RGB565, YUV422, YUV420 and YUV411 +- 1x DVP 8-bit ~16-bit camera interface +- 3x UART +- 2x I2C +- 2x I2S +- 1x RMT (TX/RX) +- 1x pulse counter +- LED PWM controller, up to 8 channels +- 1x full-speed USB OTG +- 1x USB Serial/JTAG controller +- 2x MCPWM +- 1x SDIO host controller with 2 slots +- General DMA controller (GDMA), with 5 transmit channels and 5 receive channels +- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) +- Addressable RGB LED, driven by GPIO38. + +Analog interfaces: + +- 2x 12-bit SAR ADCs, up to 20 channels +- 1x temperature sensor +- 14x touch sensing IOs + +Timers: + +- 4x 54-bit general-purpose timers +- 1x 52-bit system timer +- 3x watchdog timers + +Low Power: + +- Power Management Unit with five power modes +- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM + +Security: + +- Secure boot +- Flash encryption +- 4-Kbit OTP, up to 1792 bits for users +- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) + +Asymmetric Multiprocessing (AMP) +================================ + +Boards featuring the ESP32-S3 SoC allows 2 different applications to be executed. Due to its dual-core +architecture, each core can be enabled to execute customized tasks in stand-alone mode +and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference. + +For more information, check the `ESP32-S3 Datasheet`_ or the `ESP32-S3 Technical Reference Manual`_. + +.. _`ESP32-S3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf +.. _`ESP32-S3 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf diff --git a/boards/espressif/common/system-requirements.rst b/boards/espressif/common/system-requirements.rst new file mode 100644 index 0000000000000..b0fd19d139031 --- /dev/null +++ b/boards/espressif/common/system-requirements.rst @@ -0,0 +1,17 @@ +:orphan: + +.. espressif-system-requirements + +Binary Blobs +============ + +Espressif HAL requires RF binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: console + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. diff --git a/boards/espressif/esp32_devkitc/doc/index.rst b/boards/espressif/esp32_devkitc/doc/index.rst index 48c1a4496a8cc..ddfd1d2041257 100644 --- a/boards/espressif/esp32_devkitc/doc/index.rst +++ b/boards/espressif/esp32_devkitc/doc/index.rst @@ -10,61 +10,22 @@ variations. ESP32 is created and developed by Espressif Systems, a Shanghai-based Chinese company, and is manufactured by TSMC using their 40nm process. For more information, check `ESP32-DevKitC`_. -The features include the following: - -- Dual core Xtensa microprocessor (LX6), running at 160 or 240MHz -- 520KB of SRAM -- 802.11b/g/n/e/i -- Bluetooth v4.2 BR/EDR and BLE -- Various peripherals: - - - 12-bit ADC with up to 18 channels - - 2x 8-bit DACs - - 10x touch sensors - - Temperature sensor - - 4x SPI - - 2x I2S - - 2x I2C - - 3x UART - - SD/SDIO/MMC host - - Slave (SDIO/SPI) - - Ethernet MAC - - CAN bus 2.0 - - IR (RX/TX) - - Motor PWM - - LED PWM with up to 16 channels - - Hall effect sensor - -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) -- 5uA deep sleep current - -For more information, check the datasheet at `ESP32 Datasheet`_ or the technical reference -manual at `ESP32 Technical Reference Manual`_. - -Asymmetric Multiprocessing (AMP) -******************************** - -ESP32-DevKitC-WROVER allows 2 different applications to be executed in ESP32 SoC. Due to its dual-core architecture, each core can be enabled to execute customized tasks in stand-alone mode -and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference. +Hardware +******** + +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features Supported Features -****************** +================== .. zephyr:board-supported-hw:: System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -80,7 +41,8 @@ Programming and Debugging Debugging ========= -ESP32 support on OpenOCD is available at `OpenOCD ESP32`_. +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging On the ESP32-DevKitC board, the JTAG pins are not run to a standard connector (e.g. ARM 20-pin) and need to be manually connected @@ -104,40 +66,9 @@ to the external programmer (e.g. a Flyswatter2): | IO15 | TDO | +------------+-----------+ -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc/esp32/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc/esp32/procpu - :goals: debug - -Note on Debugging with GDB Stub -=============================== - -GDB stub is enabled on ESP32. - -* When adding breakpoints, please use hardware breakpoints with command - ``hbreak``. Command ``break`` uses software breakpoints which requires - modifying memory content to insert break/trap instructions. - This does not work as the code is on flash which cannot be randomly - accessed for modification. - References ********** .. target-notes:: .. _`ESP32-DevKitC`: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-devkitc/index.html -.. _`ESP32 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf -.. _`ESP32 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32_ethernet_kit/doc/index.rst b/boards/espressif/esp32_ethernet_kit/doc/index.rst index 5c58a64e06822..17c5104d54fa5 100644 --- a/boards/espressif/esp32_ethernet_kit/doc/index.rst +++ b/boards/espressif/esp32_ethernet_kit/doc/index.rst @@ -37,13 +37,16 @@ USB interface without a separate JTAG debugger. Hardware ******** +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features -****************** +================== .. zephyr:board-supported-hw:: Functionality Overview -********************** +====================== The block diagram below shows the main components of ESP32-Ethernet-Kit and their interconnections. @@ -55,7 +58,6 @@ and their interconnections. ESP32-Ethernet-Kit block diagram - Functional Description ====================== @@ -64,7 +66,6 @@ and controls of the ESP32-Ethernet-Kit. .. _get-started-esp32-ethernet-kit-a-v1.2-layout: - Ethernet Board (A) ------------------ @@ -187,9 +188,8 @@ PoE. When the Ethernet Board (A) detects 5 V power output from the PoE Board .. _get-started-esp32-ethernet-kit-v1.2-setup-options: - Setup Options -************* +============= This section describes options to configure the ESP32-Ethernet-Kit hardware. @@ -211,7 +211,6 @@ DIP SW GPIO Pin 4 GPIO14 ======= ================ - RMII Clock Selection ==================== @@ -267,14 +266,12 @@ sheet 2, location D2. Please note that if the APLL is already used for other purposes (e.g. I2S peripheral), then you have no choice but use an external RMII clock. - GPIO Allocation -*************** +=============== This section describes allocation of ESP32 GPIOs to specific interfaces or functions of the ESP32-Ethernet-Kit. - IP101GRI (PHY) Interface ======================== @@ -312,7 +309,6 @@ No. ESP32 Pin (MAC) IP101GRI (PHY) be selected from GPIO0, GPIO16 or GPIO17 and it can not be changed through GPIO Matrix. - GPIO Header 1 ============= @@ -330,7 +326,6 @@ No. ESP32 Pin 6 GPIO39 ==== ================ - GPIO Header 2 ============= @@ -413,22 +408,8 @@ GPIO Allocation Summary to use these pins, please solder a module without PSRAM memory inside, e.g. the ESP32-WROOM-32D or ESP32-SOLO-1. -System Requirements -******************* - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - Enabling Ethernet -***************** +================= Enable Ethernet MAC, PHY and MDIO; add these to your device tree overlay: @@ -455,11 +436,17 @@ Enable Ethernet in KConfig: CONFIG_NET_L2_ETHERNET=y Board Init -********** +========== RESET_N (GPIO5) is automatically set high to enable the Ethernet PHY during board initialization (board_init.c) +System Requirements +******************* + +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements + Programming and Debugging ************************* @@ -484,4 +471,3 @@ References .. _`ESP32-Ethernet-Kit V1.2 Ethernet Board (A) Schematic`: https://dl.espressif.com/dl/schematics/SCH_ESP32-Ethernet-Kit_A_V1.2_20200528.pdf .. _`ESP32-WROVER-E Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-wrover-e_esp32-wrover-ie_datasheet_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32c3_devkitc/doc/index.rst b/boards/espressif/esp32c3_devkitc/doc/index.rst index 6ba73a120c847..5c00c7e41bafa 100644 --- a/boards/espressif/esp32c3_devkitc/doc/index.rst +++ b/boards/espressif/esp32c3_devkitc/doc/index.rst @@ -10,34 +10,8 @@ For more information, check `ESP32-C3-DevKitC`_. Hardware ******** -ESP32-C3 is a single-core Wi-Fi and Bluetooth 5 (LE) microcontroller SoC, -based on the open-source RISC-V architecture. It strikes the right balance of power, -I/O capabilities and security, thus offering the optimal cost-effective -solution for connected devices. -The availability of Wi-Fi and Bluetooth 5 (LE) connectivity not only makes the device configuration easy, -but it also facilitates a variety of use-cases based on dual connectivity. - -The features include the following: - -- 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz -- 400 KB of internal RAM -- 802.11b/g/n/e/i -- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh -- Various peripherals: - - - 12-bit ADC with up to 6 channels - - TWAI compatible with CAN bus 2.0 - - Temperature sensor - - 3x SPI - - 1x I2S - - 1x I2C - - 2x UART - - LED PWM with up to 6 channels - -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) - -For more information, check the datasheet at `ESP32-C3 Datasheet`_ or the technical reference -manual at `ESP32-C3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features Supported Features ================== @@ -47,16 +21,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -81,6 +47,3 @@ References .. target-notes:: .. _`ESP32-C3-DevKitC`: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32c3/esp32-c3-devkitc-02/index.html -.. _`ESP32-C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`ESP32-C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32c3_devkitm/doc/index.rst b/boards/espressif/esp32c3_devkitm/doc/index.rst index c1319966e44b8..a46f754694482 100644 --- a/boards/espressif/esp32c3_devkitm/doc/index.rst +++ b/boards/espressif/esp32c3_devkitm/doc/index.rst @@ -10,34 +10,8 @@ For more information, check `ESP32-C3-DevKitM`_. Hardware ******** -ESP32-C3 is a single-core Wi-Fi and Bluetooth 5 (LE) microcontroller SoC, -based on the open-source RISC-V architecture. It strikes the right balance of power, -I/O capabilities and security, thus offering the optimal cost-effective -solution for connected devices. -The availability of Wi-Fi and Bluetooth 5 (LE) connectivity not only makes the device configuration easy, -but it also facilitates a variety of use-cases based on dual connectivity. - -The features include the following: - -- 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz -- 400 KB of internal RAM -- 802.11b/g/n/e/i -- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh -- Various peripherals: - - - 12-bit ADC with up to 6 channels - - TWAI compatible with CAN bus 2.0 - - Temperature sensor - - 3x SPI - - 1x I2S - - 1x I2C - - 2x UART - - LED PWM with up to 6 channels - -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) - -For more information, check the datasheet at `ESP32-C3 Datasheet`_ or the technical reference -manual at `ESP32-C3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features Supported Features ================== @@ -47,16 +21,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -81,6 +47,3 @@ References .. target-notes:: .. _`ESP32-C3-DevKitM`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html -.. _`ESP32-C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`ESP32-C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32c3_rust/doc/index.rst b/boards/espressif/esp32c3_rust/doc/index.rst index 2ab911aab84b0..8412e18952dfd 100644 --- a/boards/espressif/esp32c3_rust/doc/index.rst +++ b/boards/espressif/esp32c3_rust/doc/index.rst @@ -12,32 +12,8 @@ For more information, check `ESP32-C3-DevKit-RUST`_. Hardware ******** -SoC Features: - -- IEEE 802.11 b/g/n-compliant -- Bluetooth 5, Bluetooth mesh -- 32-bit RISC-V single-core processor, up to 160MHz -- 384 KB ROM -- 400 KB SRAM (16 KB for cache) -- 8 KB SRAM in RTC -- 22 x programmable GPIOs -- 3 x SPI -- 2 x UART -- 1 x I2C -- 1 x I2S -- 2 x 54-bit general-purpose timers -- 3 x watchdog timers -- 1 x 52-bit system timer -- Remote Control Peripheral (RMT) -- LED PWM controller (LEDC) -- Full-speed USB Serial/JTAG controller -- General DMA controller (GDMA) -- 1 x TWAI® -- 2 x 12-bit SAR ADCs, up to 6 channels -- 1 x temperature sensor - -For more information, check the datasheet at `ESP32-C3 Datasheet`_ or the technical reference -manual at `ESP32-C3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features Supported Features ================== @@ -92,16 +68,8 @@ Power System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -126,6 +94,3 @@ References .. target-notes:: .. _`ESP32-C3-DevKit-RUST`: https://github.com/esp-rs/esp-rust-board/tree/v1.2 -.. _`ESP32-C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`ESP32-C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32c6_devkitc/doc/index.rst b/boards/espressif/esp32c6_devkitc/doc/index.rst index 3477165463f24..79b4703c07227 100644 --- a/boards/espressif/esp32c6_devkitc/doc/index.rst +++ b/boards/espressif/esp32c6_devkitc/doc/index.rst @@ -10,13 +10,6 @@ Bluetooth LE, Zigbee, and Thread functions. For more information, check `ESP32-C Hardware ******** -ESP32-C6 is Espressif's first Wi-Fi 6 SoC integrating 2.4 GHz Wi-Fi 6, Bluetooth 5.3 (LE) and the -802.15.4 protocol. ESP32-C6 achieves an industry-leading RF performance, with reliable security -features and multiple memory resources for IoT products. -It consists of a high-performance (HP) 32-bit RISC-V processor, which can be clocked up to 160 MHz, -and a low-power (LP) 32-bit RISC-V processor, which can be clocked up to 20 MHz. -It has a 320KB ROM, a 512KB SRAM, and works with external flash. - ESP32-C6-DevKitC is an entry-level development board based on ESP32-C6-WROOM-1(U), a general-purpose module with a 8 MB SPI flash. @@ -24,62 +17,8 @@ Most of the I/O pins are broken out to the pin headers on both sides for easy in Developers can either connect peripherals with jumper wires or mount ESP32-C6-DevKitC on a breadboard. -ESP32-C6 includes the following features: - -- 32-bit core RISC-V microcontroller with a clock speed of up to 160 MHz -- 400 KB of internal RAM -- WiFi 802.11 ax 2.4GHz -- Fully compatible with IEEE 802.11b/g/n protocol -- Bluetooth LE: Bluetooth 5.3 certified -- Internal co-existence mechanism between Wi-Fi and Bluetooth to share the same antenna -- IEEE 802.15.4 (Zigbee and Thread) - -Digital interfaces: - -- 30x GPIOs (QFN40), or 22x GPIOs (QFN32) -- 2x UART -- 1x Low-power (LP) UART -- 1x General purpose SPI -- 1x I2C -- 1x Low-power (LP) I2C -- 1x I2S -- 1x Pulse counter -- 1x USB Serial/JTAG controller -- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) -- 1x SDIO 2.0 slave controller -- LED PWM controller, up to 6 channels -- 1x Motor control PWM (MCPWM) -- 1x Remote control peripehral -- 1x Parallel IO interface (PARLIO) -- General DMA controller (GDMA), with 3 transmit channels and 3 receive channels -- Event task matrix (ETM) - -Analog interfaces: - -- 1x 12-bit SAR ADCs, up to 7 channels -- 1x temperature sensor - -Timers: - -- 1x 52-bit system timer -- 1x 54-bit general-purpose timers -- 3x Watchdog timers -- 1x Analog watchdog timer - -Low Power: - -- Four power modes designed for typical scenarios: Active, Modem-sleep, Light-sleep, Deep-sleep - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, ECC, HMAC, RSA, SHA, Digital signature, Hash) -- Random number generator (RNG) - -For more information, check the datasheet at `ESP32-C6 Datasheet`_ or the technical reference -manual at `ESP32-C6 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32c6-features.rst + :start-after: espressif-soc-esp32c6-features Supported Features ================== @@ -89,16 +28,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -117,36 +48,9 @@ Debugging .. include:: ../../../espressif/common/openocd-debugging.rst :start-after: espressif-openocd-debugging -Low-Power CPU (LP CORE) -*********************** - -The ESP32-C6 SoC has two RISC-V cores: the High-Performance Core (HP CORE) and the Low-Power Core (LP CORE). -The LP Core features ultra low power consumption, an interrupt controller, a debug module and a system bus -interface for memory and peripheral access. - -The LP Core is in sleep mode by default. It has two application scenarios: - -- Power insensitive scenario: When the High-Performance CPU (HP Core) is active, the LP Core can assist the HP CPU with some speed and efficiency-insensitive controls and computations. -- Power sensitive scenario: When the HP CPU is in the power-down state to save power, the LP Core can be woken up to handle some external wake-up events. - -For more information, check the datasheet at `ESP32-C6 Datasheet`_ or the technical reference -manual at `ESP32-C6 Technical Reference Manual`_. - -The LP Core support is fully integrated with :ref:`sysbuild`. The user can enable the LP Core by adding -the following configuration to the project: - -.. code:: cfg - - CONFIG_ULP_COPROC_ENABLED=y - -See :zephyr:code-sample-category:`lp-core` folder as code reference. - References ********** .. target-notes:: .. _`ESP32-C6-DevKitC`: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/user_guide.html -.. _`ESP32-C6 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf -.. _`ESP32-C6 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32h2_devkitm/doc/index.rst b/boards/espressif/esp32h2_devkitm/doc/index.rst index f1f64f7cd2c48..d7b10d72fd9d2 100644 --- a/boards/espressif/esp32h2_devkitm/doc/index.rst +++ b/boards/espressif/esp32h2_devkitm/doc/index.rst @@ -14,69 +14,8 @@ For details on getting started, check `ESP32-H2-DevKitM-1`_. Hardware ******** -ESP32-H2 combines IEEE 802.15.4 connectivity with Bluetooth 5 (LE). The SoC is powered by -a single-core, 32-bit RISC-V microcontroller that can be clocked up to 96 MHz. The ESP32-H2 has -been designed to ensure low power consumption and security for connected devices. ESP32-H2 has -320 KB of SRAM with 16 KB of Cache, 128 KB of ROM, 4 KB LP of memory, and a built-in 2 MB or 4 MB -SiP flash. It has 19 programmable GPIOs with support for ADC, SPI, UART, I2C, I2S, RMT, GDMA -and LED PWM. - -Most of ESP32-H2-DevKitM-1's I/O pins are broken out to the pin headers on both sides for easy -interfacing. Developers can either connect peripherals with jumper wires or mount the board -on a breadboard. - -ESP32-H2 main features: - -- RISC-V 32-bit single-core microprocessor -- 320 KB of internal RAM -- 4 KB LP Memory -- Bluetooth LE: Bluetooth 5.3 certified -- IEEE 802.15.4 (Zigbee and Thread) -- 19 programmable GPIOs -- Numerous peripherals (details below) - -Digital interfaces: - -- 19x GPIOs -- 2x UART -- 2x I2C -- 1x General-purpose SPI -- 1x I2S -- 1x Pulse counter -- 1x USB Serial/JTAG controller -- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) -- 1x LED PWM controller, up to 6 channels -- 1x Motor Control PWM (MCPWM) -- 1x Remote Control peripheral (RMT), with up to 2 TX and 2 RX channels -- 1x Parallel IO interface (PARLIO) -- General DMA controller (GDMA), with 3 transmit channels and 3 receive channels -- Event Task Matrix (ETM) - -Analog interfaces: - -- 1x 12-bit SAR ADCs, up to 5 channels -- 1x Temperature sensor (die) - -Timers: - -- 1x 52-bit system timer -- 2x 54-bit general-purpose timers -- 3x Watchdog timers - -Low Power: - -- Four power modes designed for typical scenarios: Active, Modem-sleep, Light-sleep, Deep-sleep - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, ECC, HMAC, RSA, SHA, Digital signature, Hash) -- Random number generator (RNG) - -For detailed information, check the datasheet at `ESP32-H2 Datasheet`_ or the Technical Reference -Manual at `ESP32-H2 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32h2-features.rst + :start-after: espressif-soc-esp32h2-features Supported Features ================== @@ -86,16 +25,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -120,5 +51,3 @@ References .. target-notes:: .. _`ESP32-H2-DevKitM-1`: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32h2/esp32-h2-devkitm-1/user_guide.html -.. _`ESP32-H2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf -.. _`ESP32-H2 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-h2_technical_reference_manual_en.pdf diff --git a/boards/espressif/esp32s2_devkitc/doc/index.rst b/boards/espressif/esp32s2_devkitc/doc/index.rst index b3bef993a45f7..c269d657691ce 100644 --- a/boards/espressif/esp32s2_devkitc/doc/index.rst +++ b/boards/espressif/esp32s2_devkitc/doc/index.rst @@ -11,32 +11,8 @@ For more information, check `ESP32-S2-DevKitC`_. Hardware ******** -ESP32-S2 is a highly integrated, low-power, single-core Wi-Fi Microcontroller SoC, designed to be secure and -cost-effective, with a high performance and a rich set of IO capabilities. - -The features include the following: - -- RSA-3072-based secure boot -- AES-XTS-256-based flash encryption -- Protected private key and device secrets from software access -- Cryptographic accelerators for enhanced performance -- Protection against physical fault injection attacks -- Various peripherals: - - - 43x programmable GPIOs - - 14x configurable capacitive touch GPIOs - - USB OTG - - LCD interface - - camera interface - - SPI - - I2S - - UART - - ADC - - DAC - - LED PWM with up to 8 channels - -For more information, check the datasheet at `ESP32-S2 Datasheet`_ or the technical reference -manual at `ESP32-S2 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32s2-features.rst + :start-after: espressif-soc-esp32s2-features Supported Features ================== @@ -46,16 +22,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -94,7 +62,3 @@ References .. target-notes:: .. _`ESP32-S2-DevKitC`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html -.. _`ESP32-S2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf -.. _`ESP32-S2 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32-S2`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-guides/jtag-debugging/index.html -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32s2_saola/doc/index.rst b/boards/espressif/esp32s2_saola/doc/index.rst index 418fde8cba778..756ad038e805b 100644 --- a/boards/espressif/esp32s2_saola/doc/index.rst +++ b/boards/espressif/esp32s2_saola/doc/index.rst @@ -11,32 +11,8 @@ For more information, check `ESP32-S3-DevKitC`_. Hardware ******** -ESP32-S2 is a highly integrated, low-power, single-core Wi-Fi Microcontroller SoC, designed to be secure and -cost-effective, with a high performance and a rich set of IO capabilities. - -The features include the following: - -- RSA-3072-based secure boot -- AES-XTS-256-based flash encryption -- Protected private key and device secrets from software access -- Cryptographic accelerators for enhanced performance -- Protection against physical fault injection attacks -- Various peripherals: - - - 43x programmable GPIOs - - 14x configurable capacitive touch GPIOs - - USB OTG - - LCD interface - - camera interface - - SPI - - I2S - - UART - - ADC - - DAC - - LED PWM with up to 8 channels - -For more information, check the datasheet at `ESP32-S2 Datasheet`_ or the technical reference -manual at `ESP32-S2 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32s2-features.rst + :start-after: espressif-soc-esp32s2-features Supported Features ================== @@ -46,16 +22,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -94,7 +62,3 @@ References .. target-notes:: .. _`ESP32-S3-DevKitC`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html -.. _`ESP32-S2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf -.. _`ESP32-S2 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32-S2`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-guides/jtag-debugging/index.html -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32s3_devkitc/doc/index.rst b/boards/espressif/esp32s3_devkitc/doc/index.rst index 6fce1233a6894..a082b9569d42e 100644 --- a/boards/espressif/esp32s3_devkitc/doc/index.rst +++ b/boards/espressif/esp32s3_devkitc/doc/index.rst @@ -10,73 +10,8 @@ and Bluetooth Low Energy functions. For more information, check `ESP32-S3-DevKit Hardware ******** -ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi -and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor -(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, -RF module, and numerous peripherals. - -ESP32-S3-DevKitC includes the following features: - -- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz -- Additional vector instructions support for AI acceleration -- 512KB of SRAM -- 384KB of ROM -- Wi-Fi 802.11b/g/n -- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate - -Digital interfaces: - -- 45 programmable GPIOs -- 4x SPI -- 1x LCD interface (8-bit ~16-bit parallel RGB, I8080 and MOTO6800), supporting conversion between RGB565, YUV422, YUV420 and YUV411 -- 1x DVP 8-bit ~16-bit camera interface -- 3x UART -- 2x I2C -- 2x I2S -- 1x RMT (TX/RX) -- 1x pulse counter -- LED PWM controller, up to 8 channels -- 1x full-speed USB OTG -- 1x USB Serial/JTAG controller -- 2x MCPWM -- 1x SDIO host controller with 2 slots -- General DMA controller (GDMA), with 5 transmit channels and 5 receive channels -- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) -- Addressable RGB LED, driven by GPIO38. - -Analog interfaces: - -- 2x 12-bit SAR ADCs, up to 20 channels -- 1x temperature sensor -- 14x touch sensing IOs - -Timers: - -- 4x 54-bit general-purpose timers -- 1x 52-bit system timer -- 3x watchdog timers - -Low Power: - -- Power Management Unit with five power modes -- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) - -Asymmetric Multiprocessing (AMP) -******************************** - -ESP32S3-DevKitC allows 2 different applications to be executed in ESP32-S3 SoC. Due to its dual-core -architecture, each core can be enabled to execute customized tasks in stand-alone mode -and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference. - -For more information, check the datasheet at `ESP32-S3 Datasheet`_ or the technical reference -manual at `ESP32-S3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features Supported Features ================== @@ -86,16 +21,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -120,7 +47,3 @@ References .. target-notes:: .. _`ESP32-S3-DevKitC`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html -.. _`ESP32-S3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf -.. _`ESP32-S3 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp32s3_devkitm/doc/index.rst b/boards/espressif/esp32s3_devkitm/doc/index.rst index bb403fb5ab0c8..ccd6d363ce296 100644 --- a/boards/espressif/esp32s3_devkitm/doc/index.rst +++ b/boards/espressif/esp32s3_devkitm/doc/index.rst @@ -10,92 +10,19 @@ and Bluetooth Low Energy functions. For more information, check `ESP32-S3-DevKit Hardware ******** -ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi -and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor -(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, -RF module, and numerous peripherals. - -ESP32-S3-DevKitM includes the following features: - -- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz -- Additional vector instructions support for AI acceleration -- 512KB of SRAM -- 384KB of ROM -- Wi-Fi 802.11b/g/n -- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate - -Digital interfaces: - -- 45 programmable GPIOs -- 4x SPI -- 1x LCD interface (8-bit ~16-bit parallel RGB, I8080 and MOTO6800), supporting conversion between RGB565, YUV422, YUV420 and YUV411 -- 1x DVP 8-bit ~16-bit camera interface -- 3x UART -- 2x I2C -- 2x I2S -- 1x RMT (TX/RX) -- 1x pulse counter -- LED PWM controller, up to 8 channels -- 1x full-speed USB OTG -- 1x USB Serial/JTAG controller -- 2x MCPWM -- 1x SDIO host controller with 2 slots -- General DMA controller (GDMA), with 5 transmit channels and 5 receive channels -- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) -- Addressable RGB LED, driven by GPIO48. - -Analog interfaces: - -- 2x 12-bit SAR ADCs, up to 20 channels -- 1x temperature sensor -- 14x touch sensing IOs - -Timers: - -- 4x 54-bit general-purpose timers -- 1x 52-bit system timer -- 3x watchdog timers - -Low Power: - -- Power Management Unit with five power modes -- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features Supported Features ================== .. zephyr:board-supported-hw:: -Asymmetric Multiprocessing (AMP) -******************************** - -ESP32S3-DevKitM allows 2 different applications to be executed in ESP32-S3 SoC. Due to its dual-core -architecture, each core can be enabled to execute customized tasks in stand-alone mode -and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference. - -For more information, check the datasheet at `ESP32-S3 Datasheet`_ or the technical reference -manual at `ESP32-S3 Technical Reference Manual`_. - System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -120,7 +47,3 @@ References .. target-notes:: .. _`ESP32-S3-DevKitM User Guide`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitm-1.html -.. _`ESP32-S3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s3-mini-1_mini-1u_datasheet_en.pdf -.. _`ESP32-S3 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ diff --git a/boards/espressif/esp32s3_eye/doc/index.rst b/boards/espressif/esp32s3_eye/doc/index.rst index 7180ff7d81700..04e1ae7799b8a 100644 --- a/boards/espressif/esp32s3_eye/doc/index.rst +++ b/boards/espressif/esp32s3_eye/doc/index.rst @@ -3,8 +3,8 @@ Overview ******** -The ESP32-S3-EYE is a small-sized AI development board produced by `Espressif`_. -It is based on the `ESP32-S3`_ SoC. +The ESP32-S3-EYE is a small-sized AI development board produced by Espressif and based on the +ESP32-S3 SoC. It features a 2-Megapixel camera, an LCD display, and a microphone, which are used for image recognition and audio processing. ESP32-S3-EYE offers plenty of storage, with an 8 MB Octal PSRAM and a 8 MB flash. @@ -17,6 +17,9 @@ ESP32-S3-WROOM-1 module, camera, SD card slot, digital microphone, USB port, and and the sub board (ESP32-S3-EYE-SUB) that contains an LCD display. The main board and sub board are connected through pin headers. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== @@ -121,16 +124,8 @@ Components on the ESP32-S3-EYE-SUB Sub Board System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -152,8 +147,4 @@ Debugging References ********** -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases - -.. _`Espressif`: https://espressif.com - -.. _`ESP32-S3`: https://www.espressif.com/en/products/socs/esp32-s3 +.. target-notes:: diff --git a/boards/espressif/esp8684_devkitm/doc/index.rst b/boards/espressif/esp8684_devkitm/doc/index.rst index 22b0aef4f4893..a69a65701f891 100644 --- a/boards/espressif/esp8684_devkitm/doc/index.rst +++ b/boards/espressif/esp8684_devkitm/doc/index.rst @@ -10,38 +10,8 @@ For more information, check `ESP8684-DevKitM User Guide`_ Hardware ******** -ESP32-C2 (ESP8684 core) is a low-cost, Wi-Fi 4 & Bluetooth 5 (LE) chip. Its unique design -makes the chip smaller and yet more powerful than ESP8266. ESP32-C2 is built around a RISC-V -32-bit, single-core processor, with 272 KB of SRAM (16 KB dedicated to cache) and 576 KB of ROM. -ESP32-C2 has been designed to target simple, high-volume, and low-data-rate IoT applications, -such as smart plugs and smart light bulbs. ESP32-C2 offers easy and robust wireless connectivity, -which makes it the go-to solution for developing simple, user-friendly and reliable -smart-home devices. For more information, check `ESP8684 Datasheet`_. - -Features include the following: - -- 32-bit core RISC-V microcontroller with a maximum clock speed of 120 MHz -- 2 MB or 4 MB in chip (ESP8684) or in package (ESP32-C2) flash -- 272 KB of internal RAM -- 802.11b/g/n -- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh -- Various peripherals: - - - 14 programmable GPIOs - - 3 SPI - - 2 UART - - 1 I2C Master - - LED PWM controller, with up to 6 channels - - General DMA controller (GDMA) - - 1 12-bit SAR ADC, up to 5 channels - - 1 temperature sensor - - 1 54-bit general-purpose timer - - 2 watchdog timers - - 1 52-bit system timer - -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) - -For detailed information check `ESP8684 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32c2-features.rst + :start-after: espressif-soc-esp32c2-features Supported Features ================== @@ -53,16 +23,8 @@ For a getting started user guide, please check `ESP8684-DevKitM User Guide`_. System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -87,6 +49,3 @@ References .. target-notes:: .. _`ESP8684-DevKitM User Guide`: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp8684/esp8684-devkitm-1/user_guide.html -.. _`ESP8684 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp8684_datasheet_en.pdf -.. _`ESP8684 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp8684_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/espressif/esp_wrover_kit/doc/index.rst b/boards/espressif/esp_wrover_kit/doc/index.rst index 208550ee0ec5c..411f6eadf5b53 100644 --- a/boards/espressif/esp_wrover_kit/doc/index.rst +++ b/boards/espressif/esp_wrover_kit/doc/index.rst @@ -3,8 +3,6 @@ Overview ******** -ESP-WROVER-KIT is an ESP32-based development board produced by `Espressif `_. - ESP-WROVER-KIT features the following integrated components: - ESP32-WROVER-E module @@ -25,12 +23,17 @@ Most of the ESP32 I/O pins are broken out to the board's pin headers for easy ac For more information, check `ESP32-WROVER-E Datasheet`_ and `ESP32 Datasheet`_. +Hardware +******** + +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: - Functionality Overview ====================== @@ -160,7 +163,7 @@ The table below provides description in the following manner: .. _setup options: Setup Options -************* +============= There are three jumper blocks available to set up the board functionality. The most frequently required options are listed in the table below. @@ -190,7 +193,7 @@ required options are listed in the table below. +--------+----------------+-------------------------------------------------------+ Allocation of ESP32 Pins -************************ +======================== Some pins / terminals of ESP32 are allocated for use with the onboard or external hardware. If that hardware is not used, e.g., nothing is plugged into the Camera (JP4) header, then these @@ -211,7 +214,7 @@ For more details on which pins are shared among which peripherals, please refer the next section. Main I/O Connector / JP1 -************************ +======================== The JP1 connector consists of 14x2 male pins whose functions are shown in the middle two “I/O” columns of the table below. The two “Shared With” columns on both sides describe where else on @@ -261,7 +264,7 @@ Legend: - PSRAM - ESP32-WROVER-E's PSRAM 32.768 kHz Oscillator -********************* +===================== +---+-----------+ | . | ESP32 Pin | @@ -279,7 +282,7 @@ Legend: them to positions R12 / R24. SPI Flash / JP2 -*************** +=============== +---+--------------+ | . | ESP32 Pin | @@ -304,7 +307,7 @@ SPI Flash / JP2 module's flash bus from the pin header JP2. JTAG / JP2 -********** +========== +---+---------------+-------------+ | . | ESP32 Pin | JTAG Signal | @@ -321,7 +324,7 @@ JTAG / JP2 +---+---------------+-------------+ Camera / JP4 -************ +============ +----+-----------+-----------------------------+ | . | ESP32 Pin | Camera Signal | @@ -366,7 +369,7 @@ Camera / JP4 - Signals D0 .. D7 denote camera data bus RGB LED -******* +======= +----+-----------+---------+ | . | ESP32 Pin | RGB LED | @@ -379,7 +382,7 @@ RGB LED +----+-----------+---------+ MicroSD Card -************ +============ +---+---------------+----------------+ | . | ESP32 Pin | MicroSD Signal | @@ -400,7 +403,7 @@ MicroSD Card +---+---------------+----------------+ LCD / U5 -******** +======== +---+-----------+------------+ | . | ESP32 Pin | LCD Signal | @@ -420,14 +423,8 @@ LCD / U5 | 7 | GPIO5 | Backlight | +---+-----------+------------+ -Start Application Development -***************************** - -Before powering up your ESP-WROVER-KIT, please make sure that the board is in good -condition with no obvious signs of damage. - Initial Setup -************* +============= Please set only the following jumpers shown in the pictures below: @@ -447,16 +444,8 @@ Turn the Power Switch to ON, the 5V Power On LED should light up. System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -472,7 +461,8 @@ Programming and Debugging Debugging ========= -ESP32 support on OpenOCD is available at `OpenOCD ESP32`_. +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging On the ESP-WROVER-KIT board, the JTAG pins are connected internally to a USB serial port on the same device as the console. These boards @@ -483,27 +473,10 @@ headers are on the right side of the board as viewed from the power switch, next to similar headers for SPI and UART. See `ESP-WROVER-32 V3 Getting Started Guide`_ for details. -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp_wrover_kit/esp32/procpu - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp_wrover_kit/esp32/procpu - :goals: debug - References ********** .. target-notes:: -.. _`ESP32 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf (PDF) .. _`ESP32-WROVER-E Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-wrover-e_esp32-wrover-ie_datasheet_en.pdf (PDF) -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases .. _`ESP-WROVER-32 V3 Getting Started Guide`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-wrover-kit.html diff --git a/boards/espressif/index.rst b/boards/espressif/index.rst index b1b7dfbeede26..d488266df3d1b 100644 --- a/boards/espressif/index.rst +++ b/boards/espressif/index.rst @@ -7,4 +7,4 @@ Espressif :maxdepth: 1 :glob: - **/* + */**/index diff --git a/boards/franzininho/esp32s2_franzininho/doc/index.rst b/boards/franzininho/esp32s2_franzininho/doc/index.rst index bdbc20574ecdb..97de6f586db2c 100644 --- a/boards/franzininho/esp32s2_franzininho/doc/index.rst +++ b/boards/franzininho/esp32s2_franzininho/doc/index.rst @@ -4,172 +4,40 @@ Overview ******** Franzininho is an educational development board based on ESP32-S2 which is a highly integrated, low-power, single-core Wi-Fi Microcontroller SoC, -designed to be secure and cost-effective, with a high performance and a rich set of IO capabilities. [1]_ +designed to be secure and cost-effective, with a high performance and a rich set of IO capabilities. -The features include the following: - -- RSA-3072-based secure boot -- AES-XTS-256-based flash encryption -- Protected private key and device secrets from software access -- Cryptographic accelerators for enhanced performance -- Protection against physical fault injection attacks -- Various peripherals: - - - 43x programmable GPIOs - - 14x configurable capacitive touch GPIOs - - USB OTG - - LCD interface - - camera interface - - SPI - - I2S - - UART - - ADC - - DAC - - LED PWM with up to 8 channels - -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +Hardware +******** - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/soc-esp32s2-features.rst + :start-after: espressif-soc-esp32s2-features -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Sysbuild -======== +Programming and Debugging +************************* -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: esp32s2_franzininho - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s2_franzininho - :goals: build - -The usual ``flash`` target will work with the ``esp32s2_franzininho`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s2_franzininho - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell +.. zephyr:board-supported-runners:: - west espressif monitor +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. code-block:: console +Debugging +========= - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32s2_franzininho +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. [1] https://www.espressif.com/en/products/socs/esp32-s2 -.. _`ESP32S2 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf -.. _`ESP32S2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf +.. _`ESP32-S2 Product page`: https://www.espressif.com/en/products/socs/esp32-s2 diff --git a/boards/hardkernel/odroid_go/doc/index.rst b/boards/hardkernel/odroid_go/doc/index.rst index 3c14c9c23b0f8..23d44955404f7 100644 --- a/boards/hardkernel/odroid_go/doc/index.rst +++ b/boards/hardkernel/odroid_go/doc/index.rst @@ -5,21 +5,27 @@ Overview ODROID-GO Game Kit is a "Do it yourself" ("DIY") portable game console by HardKernel. It features a custom ESP32-WROVER with 16 MB flash and it operates -from 80 MHz - 240 MHz [1]_. +from 80 MHz - 240 MHz. More details can be found in `ODROID-GO pages`_. -The features include the following: +Hardware +******** + +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + +The board peripherals: -- Dual core Xtensa microprocessor (LX6), running at 80 - 240MHz -- 4 MB of PSRAM -- 802.11b/g/n/e/i -- Bluetooth v4.2 BR/EDR and BLE - 2.4 inch 320x240 TFT LCD - Speaker - Micro SD card slot - Micro USB port (battery charging and USB_UART data communication - Input Buttons (Menu, Volume, Select, Start, A, B, Direction Pad) - Expansion port (I2C, GPIO, SPI) -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) + +Supported Features +================== + +.. zephyr:board-supported-hw:: External Connector ================== @@ -48,179 +54,32 @@ External Connector | 10 | VBUS | USB VBUS (5V) | +-------+------------------+-------------------------+ -Supported Features -================== - -.. zephyr:board-supported-hw:: - -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: odroid_go - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: odroid_go/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``odroid_go`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: odroid_go/esp32/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! odroid_go +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: odroid_go/esp32/procpu - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: odroid_go/esp32/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. [1] https://wiki.odroid.com/odroid_go/odroid_go -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases +.. _`ODROID-GO pages`: https://wiki.odroid.com/odroid_go/odroid_go diff --git a/boards/heltec/heltec_wifi_lora32_v2/doc/index.rst b/boards/heltec/heltec_wifi_lora32_v2/doc/index.rst index abe91f4ca90d2..397b1dbc5edac 100644 --- a/boards/heltec/heltec_wifi_lora32_v2/doc/index.rst +++ b/boards/heltec/heltec_wifi_lora32_v2/doc/index.rst @@ -5,7 +5,7 @@ Overview Heltec WiFi LoRa 32 is a classic IoT dev-board designed & produced by Heltec Automation(TM), it's a highly integrated product based on ESP32 + SX127x, it has Wi-Fi, BLE, LoRa functions, also Li-Po battery management -system, 0.96" OLED are also included. [1]_ +system, 0.96" OLED are also included. See the `Heltec WiFi LoRa (V2) pages`_ for more details. The features include the following: @@ -19,169 +19,34 @@ The features include the following: - Onboard 0.96-inch 128*64 dot matrix OLED display - Integrated CP2102 USB to serial port chip -System requirements -******************* - -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +Hardware +******** - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: heltec_wifi_lora32_v2 - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. note:: +Programming and Debugging +************************* - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wifi_lora32_v2/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``heltec_wifi_lora32_v2`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wifi_lora32_v2/esp32/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! heltec_wifi_lora32_v2 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. +========= -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wifi_lora32_v2/esp32/procpu - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wifi_lora32_v2/esp32/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging Utilizing Hardware Features *************************** @@ -202,10 +67,8 @@ connected via I2C. It can therefore be used by enabling the References ********** -- `Heltec WiFi LoRa (v2) Pinout Diagram `_ -- `Heltec WiFi LoRa (v2) Schematic Diagrams `_ -- `ESP32 Toolchain `_ -- `esptool documentation `_ -- `OpenOCD ESP32 `_ +.. target-notes:: -.. [1] https://heltec.org/project/wifi-lora-32/ +.. _`Heltec WiFi LoRa (V2) pages`: https://heltec.org/project/wifi-lora-32/ +.. _`Heltec WiFi LoRa (v2) Pinout Diagram`: https://resource.heltec.cn/download/WiFi_LoRa_32/WIFI_LoRa_32_V2.pdf +.. _`Heltec WiFi LoRa (v2) Schematic Diagrams`: https://resource.heltec.cn/download/WiFi_LoRa_32/V2 diff --git a/boards/heltec/heltec_wireless_stick_lite_v3/doc/index.rst b/boards/heltec/heltec_wireless_stick_lite_v3/doc/index.rst index 431f83d41ebeb..02a846d47fa67 100644 --- a/boards/heltec/heltec_wireless_stick_lite_v3/doc/index.rst +++ b/boards/heltec/heltec_wireless_stick_lite_v3/doc/index.rst @@ -3,7 +3,8 @@ Overview ******** -HelTec Wireless Stick Lite (V3) is a development board with Wi-Fi, Bluetooth and LoRa support. It is designed and produced by HelTec Automation(TM). [1]_ +HelTec Wireless Stick Lite (V3) is a development board with Wi-Fi, Bluetooth and LoRa support. +It is designed and produced by HelTec Automation(TM). See the `Heltec Wireless Stick Lite (v3) pages`_ for more details. Hardware ******** @@ -18,6 +19,9 @@ The main hardware features are: - Integrated CP2102 USB to serial port chip, convenient for program downloading, debugging information printing. - Good RF circuit design and low-power design. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== @@ -120,178 +124,35 @@ Connections and IOs | J3.20 | TWAI_RX | CAN (optional) | +--------+---------+-----------------------------+ - -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the EPS32-S3 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: heltec_wireless_stick_lite_v3 - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32S3 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wireless_stick_lite_v3/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``heltec_wireless_stick_lite_v3`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wireless_stick_lite_v3/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! heltec_wireless_stick_lite_v3 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ========= -As with much custom hardware, the ESP32S3 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wireless_stick_lite_v3/esp32s3/procpu - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: heltec_wireless_stick_lite_v3/esp32s3/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** -- `Heltec Wireless Stick Lite (v3) Pinout Diagram `_ -- `Heltec Wireless Stick Lite (v3) Schematic Diagrams `_ -- `ESP-IDF Programming Guide `_ -- `esptool documentation `_ -- `OpenOCD ESP32 `_ +.. target-notes:: -.. [1] https://heltec.org/project/wireless-stick-lite-v2/ +.. _`Heltec Wireless Stick Lite (v3) pages`: https://heltec.org/project/wireless-stick-lite-v2/ +.. _`Heltec Wireless Stick Lite (v3) Pinout Diagram`: https://resource.heltec.cn/download/Wireless_Stick_Lite_V3/HTIT-WSL_V3.png +.. _`Heltec Wireless Stick Lite (v3) Schematic Diagrams`: https://resource.heltec.cn/download/Wireless_Stick_Lite_V3/HTIT-WSL_V3_Schematic_Diagram.pdf +.. _`ESP-IDF Programming Guide`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/index.html diff --git a/boards/kincony/kincony_kc868_a32/doc/index.rst b/boards/kincony/kincony_kc868_a32/doc/index.rst index 6a001bbfdd8e4..5ebeed6af4c48 100644 --- a/boards/kincony/kincony_kc868_a32/doc/index.rst +++ b/boards/kincony/kincony_kc868_a32/doc/index.rst @@ -4,9 +4,12 @@ Overview ******** Kincony KC868-A32 is a home automation relay module based on the -Espressif ESP-WROOM-32 module with all its inherent capabilities +Espressif ESP32 ESP-WROOM-32 module with all its inherent capabilities (Wi-Fi, Bluetooth, etc.) +Hardware +******** + The features include the following: - 32 digital optoisolated inputs “dry contact” @@ -20,58 +23,25 @@ The features include the following: - RESET and DOWNLOAD buttons - Powered by 12V DC -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features -.. code-block:: console +System Requirements +******************* - west blobs fetch hal_espressif +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -------------------- +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: kincony_kc868_a32/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``kincony_kc868_a32`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: kincony_kc868_a32/esp32/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! kincony_kc868_a32 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Enabling Ethernet ***************** diff --git a/boards/lilygo/tdongle_s3/doc/index.rst b/boards/lilygo/tdongle_s3/doc/index.rst index b90f5a214172c..01d0e17f60073 100644 --- a/boards/lilygo/tdongle_s3/doc/index.rst +++ b/boards/lilygo/tdongle_s3/doc/index.rst @@ -16,165 +16,44 @@ It features the following integrated components: - JST SH 1.0mm 4-pin UART connector - Transparent plastic case -Functional Description -********************** +Hardware +******** + This board is based on the ESP32-S3 with 16MB of flash, WiFi and BLE support. It has an USB-A port for programming and debugging, integrated battery charging and an on-board antenna. The fitted U.FL external antenna connector can be enabled by moving a 0-ohm resistor. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your Lilygo T-Dongle T8-S3, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code-block:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes it possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: tdongle_s3/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flashed at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: tdongle_s3/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``tdongle_s3`` board target. -Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: tdongle_s3/esp32s3/procpu - :goals: flash - -The default baud rate for the Lilygo T-Dongle S3 is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. code-block:: console +Debugging +========= - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! tdongle_s3/esp32s3/procpu +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -183,7 +62,3 @@ References .. _`Lilygo T-Dongle S3 schematic`: https://github.com/Xinyuan-LilyGO/T-Dongle-S3/blob/main/shcematic/T-Dongle-S3.pdf .. _`Lilygo github repo`: https://github.com/Xinyuan-LilyGO/T-Dongle-S3.git -.. _`ESP32-S3 Datasheet`: https://github.com/Xinyuan-LilyGO/T-Dongle-S3/blob/main/doc/esp32-s3_datasheet_en.pdf -.. _`ESP32-S3 Technical Reference Manual`: https://github.com/Xinyuan-LilyGO/T-Dongle-S3/blob/main/doc/esp32-s3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ diff --git a/boards/lilygo/ttgo_lora32/doc/index.rst b/boards/lilygo/ttgo_lora32/doc/index.rst index 1b662bb030c32..dd69751f144dd 100644 --- a/boards/lilygo/ttgo_lora32/doc/index.rst +++ b/boards/lilygo/ttgo_lora32/doc/index.rst @@ -18,161 +18,38 @@ Some of the ESP32 I/O pins are accessible on the board's pin headers. Hardware ******** +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your Lilygo TTGO LoRa32, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order to work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code-block:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes it possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-PICO-D4 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: ttgo_lora32/esp32/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-PICO-D4 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. code-block:: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_lora32/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``ttgo_lora32`` board target. -Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_lora32/esp32/procpu - :goals: flash - -The default baud rate for the Lilygo TTGO LoRa32 is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console +Debugging +========= - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! ttgo_lora32/esp32/procpu +Lilygo TTGO LoRa32 debugging is not supported due to pinout limitations. -Code samples -============ +Sample Applications +******************* The following sample applications will work out of the box with this board: @@ -181,18 +58,15 @@ The following sample applications will work out of the box with this board: * :zephyr:code-sample:`fs` * :zephyr:code-sample:`character-frame-buffer` -Debugging -********* - -Lilygo TTGO LoRa32 debugging is not supported due to pinout limitations. - Related Documents ***************** -- `Lilygo TTGO LoRa32 schematic `_ (PDF) -- `Lilygo TTGO LoRa32 documentation `_ -- `Lilygo github repo `_ -- `ESP32-PICO-D4 Datasheet `_ (PDF) -- `ESP32 Datasheet `_ (PDF) -- `ESP32 Hardware Reference `_ -- `SX127x Datasheet `_ -- `SSD1306 Datasheet `_ (PDF) + +.. target-notes:: + +.. _`Lilygo TTGO LoRa32 schematic`: https://github.com/Xinyuan-LilyGO/LilyGo-LoRa-Series/blob/master/schematic/T3_V1.6.1.pdf +.. _`Lilygo TTGO LoRa32 documentation`: https://www.lilygo.cc/products/lora3 +.. _`Lilygo github repo`: https://github.com/Xinyuan-LilyGo +.. _`ESP32-PICO-D4 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf +.. _`ESP32 Hardware Reference`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/index.html +.. _`SX127x Datasheet`: https://www.semtech.com/products/wireless-rf/lora-connect/sx1276#documentation +.. _`SSD1306 Datasheet`: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf diff --git a/boards/lilygo/ttgo_t7v1_5/doc/index.rst b/boards/lilygo/ttgo_t7v1_5/doc/index.rst index 57d12645c9aed..958f73d418d4a 100644 --- a/boards/lilygo/ttgo_t7v1_5/doc/index.rst +++ b/boards/lilygo/ttgo_t7v1_5/doc/index.rst @@ -20,155 +20,39 @@ This board is based on the ESP32-WROVER-E module with 4MB of flash (there are models 16MB as well), WiFi and BLE support. It has a Micro-USB port for programming and debugging, integrated battery charging and an on-board antenna. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order to work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code-block:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes it possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :app: samples/hello_world - :board: ttgo_t7v1_5/esp32/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. code-block:: +Debugging +========= - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_t7v1_5/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``ttgo_t7v1_5`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_t7v1_5/esp32/procpu - :goals: flash - -The default baud rate for the Lilygo TTGO T7 V1.5 is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! ttgo_t7v1_5 - -Sample applications -=================== +Sample Applications +******************* The following samples will run out of the box on the TTGO T7 V1.5 board. @@ -189,9 +73,11 @@ To build the bluetooth beacon sample: :goals: build -Related Documents -***************** +References +********** + +.. target-notes:: + .. _`Lilygo TTGO T7-V1.5 schematic`: https://github.com/LilyGO/TTGO-T7-Demo/blob/master/t7_v1.5.pdf .. _`Lilygo github repo`: https://github.com/LilyGO/TTGO-T7-Demo/tree/master .. _`Espressif ESP32-WROVER-E datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-wrover-e_esp32-wrover-ie_datasheet_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/lilygo/ttgo_t8c3/doc/index.rst b/boards/lilygo/ttgo_t8c3/doc/index.rst index 33cab6415243e..f7d502b39b03c 100644 --- a/boards/lilygo/ttgo_t8c3/doc/index.rst +++ b/boards/lilygo/ttgo_t8c3/doc/index.rst @@ -22,184 +22,41 @@ has an USB-C port for programming and debugging, integrated battery charging and an on-board antenna. The fitted U.FL external antenna connector can be enabled by moving a 0-ohm resistor. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your Lilygo TTGO T8-C3, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order to work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes it possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-C3 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: ttgo_t8c3 - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-C3 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_t8c3 - :goals: build - -The usual ``flash`` target will work with the ``ttgo_t8c3`` board target. -Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_t8c3 - :goals: flash - -The default baud rate for the Lilygo TTGO T8-C3 is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! ttgo_t8c3 - -Sample applications -=================== - -The following samples will run out of the box on the TTGO T8-C3 board. +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -To build the blinky sample: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/basic/blinky - :board: ttgo_t8c3 - :goals: build +Debugging +========= -To build the bluetooth beacon sample: +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/bluetooth/beacon - :board: ttgo_t8c3 - :goals: build +References +********** +.. target-notes:: -Related Documents -***************** .. _`Lilygo TTGO T8-C3 schematic`: https://github.com/Xinyuan-LilyGO/T8-C3/blob/main/Schematic/T8-C3_V1.1.pdf .. _`Lilygo github repo`: https://github.com/Xinyuan-LilyGo -.. _`Espressif ESP32-C3 datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`Espressif ESP32-C3 technical reference manual`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/lilygo/ttgo_t8s3/doc/index.rst b/boards/lilygo/ttgo_t8s3/doc/index.rst index fb29b2e5f7b60..3cb2384e5cc3f 100644 --- a/boards/lilygo/ttgo_t8s3/doc/index.rst +++ b/boards/lilygo/ttgo_t8s3/doc/index.rst @@ -23,168 +23,45 @@ has an USB-C port for programming and debugging, integrated battery charging and an on-board antenna. The fitted U.FL external antenna connector can be enabled by moving a 0-ohm resistor. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your Lilygo TTGO T8-S3, please make sure that the board is in good -condition with no obvious signs of damage. - System requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order to work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code-block:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes it possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: ttgo_t8s3/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. +Debugging +========= -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_t8s3/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``ttgo_t8s3`` board target -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_t8s3/esp32s3/procpu - :goals: flash - -The default baud rate for the Lilygo TTGO T8-S3 is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! ttgo_t8s3 - -Code samples -============ +Sample Applications +******************* The following code samples will run out of the box on the TTGO T8-S3 board: * :zephyr:code-sample:`wifi-shell` * :zephyr:code-sample:`fs` - References ********** @@ -192,7 +69,3 @@ References .. _`Lilygo TTGO T8-S3 schematic`: https://github.com/Xinyuan-LilyGO/T8-S3/blob/main/schematic/T8_S3_V1.0.pdf .. _`Lilygo github repo`: https://github.com/Xinyuan-LilyGo -.. _`ESP32-S3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s3-mini-1_mini-1u_datasheet_en.pdf -.. _`ESP32-S3 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ diff --git a/boards/lilygo/ttgo_tbeam/doc/index.rst b/boards/lilygo/ttgo_tbeam/doc/index.rst index fa6082abaa29d..64e44c0250c70 100644 --- a/boards/lilygo/ttgo_tbeam/doc/index.rst +++ b/boards/lilygo/ttgo_tbeam/doc/index.rst @@ -20,161 +20,38 @@ Some of the ESP32 I/O pins are accessible on the board's pin headers. Hardware ******** +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your Lilygo TTGO TBeam, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order to work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code-block:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes it possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-PICO-D4 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: ttgo_tbeam/esp32/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-PICO-D4 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. code-block:: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_tbeam/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``ttgo_tbeam`` board target. -Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_tbeam/esp32/procpu - :goals: flash - -The default baud rate for the Lilygo TTGO TBeam is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console +Debugging +========= - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! ttgo_tbeam/esp32/procpu +Lilygo TTGO TBeam debugging is not supported due to pinout limitations. -Code samples -============ +Sample Applications +******************* The following sample applications will work out of the box with this board: @@ -185,20 +62,17 @@ The following sample applications will work out of the box with this board: * :zephyr:code-sample:`character-frame-buffer` * :zephyr:code-sample:`blinky` -Debugging -********* - -Lilygo TTGO TBeam debugging is not supported due to pinout limitations. - Related Documents ***************** -- `Lilygo TTGO TBeam schematic `_ (PDF) -- `Lilygo TTGO TBeam documentation `_ -- `Lilygo github repo `_ -- `ESP32-PICO-D4 Datasheet `_ (PDF) -- `ESP32 Datasheet `_ (PDF) -- `ESP32 Hardware Reference `_ -- `SX127x Datasheet `_ -- `SSD1306 Datasheet `_ (PDF) -- `NEO-6M Datasheet `_ (PDF) -- `NEO-N8M Datasheet `_ (PDF) + +.. target-notes:: + +.. _`Lilygo TTGO TBeam schematic`: https://github.com/Xinyuan-LilyGO/LilyGo-LoRa-Series/blob/master/schematic/LilyGo_TBeam_V1.2.pdf +.. _`Lilygo TTGO TBeam documentation`: https://www.lilygo.cc/products/t-beam-v1-1-esp32-lora-module +.. _`Lilygo github repo`: https://github.com/Xinyuan-LilyGo +.. _`ESP32-PICO-D4 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf +.. _`ESP32 Hardware Reference`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/index.html +.. _`SX127x Datasheet`: https://www.semtech.com/products/wireless-rf/lora-connect/sx1276#documentation +.. _`SSD1306 Datasheet`: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf +.. _`NEO-6M Datasheet`: https://content.u-blox.com/sites/default/files/products/documents/NEO-6_DataSheet_%28GPS.G6-HW-09005%29.pdf +.. _`NEO-N8M Datasheet`: https://content.u-blox.com/sites/default/files/NEO-M8-FW3_DataSheet_UBX-15031086.pdf diff --git a/boards/lilygo/ttgo_toiplus/doc/index.rst b/boards/lilygo/ttgo_toiplus/doc/index.rst index 3ea6b50446fa3..62d560a8f5ac8 100644 --- a/boards/lilygo/ttgo_toiplus/doc/index.rst +++ b/boards/lilygo/ttgo_toiplus/doc/index.rst @@ -14,12 +14,21 @@ It features the following integrated components: - optional 18340 Li-ion battery holder - LED -Functional Description -********************** +Hardware +******** + This board is based on the ESP32-C3 with 4MB of flash, WiFi and BLE support. It has an USB-C port for programming and debugging, integrated battery charging and an Grove connector. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features + +Supported Features +================== + +.. zephyr:board-supported-hw:: + Connections and IOs =================== @@ -27,149 +36,31 @@ Connections and IOs (Note: the above UART interface also supports connecting through USB.) -Start Application Development -***************************** - -Before powering up your Lilygo TTGO T-OI-PLUS, please make sure that the board is in good -condition with no obvious signs of damage. - System requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-C3 SoC. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -To build the sample application using sysbuild use the command: +Programming and Debugging +************************* -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: ttgo_toiplus - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-C3 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml +.. zephyr:board-supported-runners:: -.. note:: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -For more information about the system build please read the :ref:`sysbuild` documentation. +Debugging +========= -Manual build -============ +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_toiplus - :goals: build - -The usual ``flash`` target will work with the ``ttgo_toiplus`` board target. -Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: ttgo_toiplus - :goals: flash - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! ttgo_toiplus - -Sample applications -=================== +Sample Applications +******************* The following samples will run out of the box on the TTGO T-OI-PLUS board. @@ -190,10 +81,10 @@ To build the bluetooth beacon sample: :goals: build -Related Documents -***************** +References +********** + +.. target-notes:: + .. _`Lilygo TTGO T-OI-PLUS schematic`: https://github.com/Xinyuan-LilyGO/LilyGo-T-OI-PLUS/blob/main/schematic/T-OI_PLUS_Schematic.pdf .. _`Lilygo github repo`: https://github.com/Xinyuan-LilyGO -.. _`Espressif ESP32-C3 datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`Espressif ESP32-C3 technical reference manual`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/lilygo/twatch_s3/doc/index.rst b/boards/lilygo/twatch_s3/doc/index.rst index 3dc07e37673ea..215b64add1e7c 100644 --- a/boards/lilygo/twatch_s3/doc/index.rst +++ b/boards/lilygo/twatch_s3/doc/index.rst @@ -3,7 +3,11 @@ Overview ******** -LILYGO T-Watch S3 is an ESP32-S3 based smartwatch with the following features: +LILYGO T-Watch S3 is an ESP32-S3 based smartwatch. + + +Hardware +******** - ESP32-S3-R8 chip @@ -40,149 +44,36 @@ It does not have any GPIO that can easily be connected to something external. There is only 1 physical button which is connected to the PMU and it's used to turn on/off the device. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order to work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Simple boot -=========== - -The board could be loaded using a single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code-block:: cfg +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - CONFIG_BOOTLOADER_MCUBOOT=y +Programming and Debugging +************************* -Sysbuild --------- - -The sysbuild makes it possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild, use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: twatch_s3/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-S3 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-built and re-flashed - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build ------------- - -During the development cycle, it is intended to build & flash as quickly as possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flashed at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: twatch_s3/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``twatch_s3`` board target -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: twatch_s3/esp32s3/procpu - :goals: flash - -The default baud rate is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell +.. zephyr:board-supported-runners:: - west espressif monitor +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. code-block:: console +Debugging +========= - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! twatch_s3/esp32s3/procpu +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -192,7 +83,3 @@ References .. _`Lilygo Twatch S3 schematic`: https://github.com/Xinyuan-LilyGO/TTGO_TWatch_Library/blob/t-watch-s3/schematic/T_WATCH_S3.pdf .. _`Lilygo T-Watch S3 repo`: https://github.com/Xinyuan-LilyGO/TTGO_TWatch_Library/tree/t-watch-s3 .. _`Lilygo T-Watch Deps repo`: https://github.com/Xinyuan-LilyGO/T-Watch-Deps -.. _`ESP32-S3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf -.. _`ESP32-S3 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ diff --git a/boards/luatos/esp32c3_luatos_core/doc/index.rst b/boards/luatos/esp32c3_luatos_core/doc/index.rst index 02df6687cb3c1..547b67b862bc0 100644 --- a/boards/luatos/esp32c3_luatos_core/doc/index.rst +++ b/boards/luatos/esp32c3_luatos_core/doc/index.rst @@ -1,7 +1,4 @@ -.. _esp32c3_luatos_core: - -ESP32C3_LUATOS_CORE -################### +.. zephyr:board:: esp32c3_luatos_core Overview ******** @@ -11,26 +8,14 @@ based on the open-source RISC-V architecture. It strikes the right balance of po I/O capabilities and security, thus offering the optimal cost-effective solution for connected devices. The availability of Wi-Fi and Bluetooth 5 (LE) connectivity not only makes the device configuration easy, -but it also facilitates a variety of use-cases based on dual connectivity. [1]_ - -The features include the following: +but it also facilitates a variety of use-cases based on dual connectivity. +See the `ESP32C3 Luatos Core Website`_ for more details. -- 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz -- 400 KB of internal RAM -- 802.11b/g/n/e/i -- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh -- Various peripherals: - - - 12-bit ADC with up to 6 channels - - TWAI compatible with CAN bus 2.0 - - Temperature sensor - - 3x SPI - - 1x I2S - - 1x I2C - - 2x UART - - LED PWM with up to 6 channels +Hardware +******** -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features There are two version hardware of this board. The difference between them is the ch343 chip. @@ -49,216 +34,41 @@ There are two version hardware of this board. The difference between them is the Supported Features ================== -Current Zephyr's ESP32C3_LUATOS_CORE board supports the following features: +.. zephyr:board-supported-hw:: -+------------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+============+============+=====================================+ -| UART | on-chip | serial port | -+------------+------------+-------------------------------------+ -| GPIO | on-chip | gpio | -+------------+------------+-------------------------------------+ -| PINMUX | on-chip | pinmux | -+------------+------------+-------------------------------------+ -| USB-JTAG | on-chip | hardware interface | -+------------+------------+-------------------------------------+ -| SPI Master | on-chip | spi | -+------------+------------+-------------------------------------+ -| Timers | on-chip | counter | -+------------+------------+-------------------------------------+ -| Watchdog | on-chip | watchdog | -+------------+------------+-------------------------------------+ -| TRNG | on-chip | entropy | -+------------+------------+-------------------------------------+ -| LEDC | on-chip | pwm | -+------------+------------+-------------------------------------+ -| SPI DMA | on-chip | spi | -+------------+------------+-------------------------------------+ -| TWAI | on-chip | can | -+------------+------------+-------------------------------------+ -| USB-CDC | on-chip | serial | -+------------+------------+-------------------------------------+ -| ADC | on-chip | adc | -+------------+------------+-------------------------------------+ -| Wi-Fi | on-chip | | -+------------+------------+-------------------------------------+ -| Bluetooth | on-chip | | -+------------+------------+-------------------------------------+ +Connection and IO +================= .. image:: img/esp32c3_luatos_core_pinfunc.jpg :align: center :alt: esp32c3_luatos_core_pinfunc -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -To build the sample application using sysbuild use the command: +Programming and Debugging +************************* -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: esp32c3_luatos_core - :goals: build - :west-args: --sysbuild - :compact: +.. zephyr:board-supported-runners:: -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_luatos_core - :goals: build - -The usual ``flash`` target will work with the ``esp32c3_luatos_core`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_luatos_core - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32c3_luatos_core +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32-C3 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_luatos_core - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_luatos_core - :goals: debug +========= -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. [1] https://www.espressif.com/en/products/socs/esp32-c3 -.. _ESP32C3 Core Website: https://wiki.luatos.com/chips/esp32c3/board.html -.. _ESP32C3 Technical Reference Manual: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _ESP32C3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf +.. _`ESP32C3 Luatos Core Website`: https://wiki.luatos.com/chips/esp32c3/board.html diff --git a/boards/luatos/esp32s3_luatos_core/doc/index.rst b/boards/luatos/esp32s3_luatos_core/doc/index.rst index c8e3f74375f75..88892e3c2a96c 100644 --- a/boards/luatos/esp32s3_luatos_core/doc/index.rst +++ b/boards/luatos/esp32s3_luatos_core/doc/index.rst @@ -1,7 +1,4 @@ -.. _esp32s3_luatos_core: - -ESP32S3-Luatos-Core -################### +.. zephyr:board:: esp32s3_luatos_core Overview ******** @@ -17,66 +14,8 @@ For more information, check `ESP32S3-Luatos-Core`_ (chinese) Hardware ******** -ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi -and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor -(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, -RF module, and numerous peripherals. - -ESP32S3-Luatos-Core includes the following features: - -- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz -- Additional vector instructions support for AI acceleration -- 512KB of SRAM -- 384KB of ROM -- 8MB of PSRAM -- 16MB of FLASH -- Wi-Fi 802.11b/g/n -- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate - -Digital interfaces: - -- 4x SPI -- 1x LCD interface (8-bit ~16-bit parallel RGB, I8080 and MOTO6800), supporting conversion between RGB565, YUV422, YUV420 and YUV411 -- 1x DVP 8-bit ~16-bit camera interface -- 3x UART -- 2x I2C -- 2x I2S -- 1x RMT (TX/RX) -- 1x pulse counter -- LED PWM controller, up to 8 channels -- 1x USB Port with USB switcher, supporting following modes: - - 1x full-speed USB OTG or 1x USB Serial/JTAG controller - - USB to serial chip CH343 -- 2x MCPWM -- 1x SDIO host controller with 2 slots -- General DMA controller (GDMA), with 5 transmit channels and 5 receive channels -- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) -- 2x Blue LED - -Analog interfaces: - -- 2x 12-bit SAR ADCs, up to 20 channels - -Timers: - -- 4x 54-bit general-purpose timers -- 1x 52-bit system timer -- 3x watchdog timers - -Low Power: - -- Power Management Unit with five power modes -- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) - -For more information, check the datasheet at `ESP32-S3 Datasheet`_ or the technical reference -manual at `ESP32-S3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features .. image:: img/esp32s3_luatos_core_pinout.jpg :align: center @@ -85,203 +24,30 @@ manual at `ESP32-S3 Technical Reference Manual`_. Supported Features ================== -Current Zephyr's ESP32S3-Luatos-Core board supports the following features: - -+------------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+============+============+=====================================+ -| UART | on-chip | serial port | -+------------+------------+-------------------------------------+ -| GPIO | on-chip | gpio | -+------------+------------+-------------------------------------+ -| PINMUX | on-chip | pinmux | -+------------+------------+-------------------------------------+ -| USB-JTAG | on-chip | hardware interface | -+------------+------------+-------------------------------------+ -| SPI Master | on-chip | spi | -+------------+------------+-------------------------------------+ -| TWAI/CAN | on-chip | can | -+------------+------------+-------------------------------------+ -| Timers | on-chip | counter | -+------------+------------+-------------------------------------+ -| Watchdog | on-chip | watchdog | -+------------+------------+-------------------------------------+ -| TRNG | on-chip | entropy | -+------------+------------+-------------------------------------+ -| LEDC | on-chip | pwm | -+------------+------------+-------------------------------------+ -| MCPWM | on-chip | pwm | -+------------+------------+-------------------------------------+ -| PCNT | on-chip | qdec | -+------------+------------+-------------------------------------+ -| GDMA | on-chip | dma | -+------------+------------+-------------------------------------+ -| USB-CDC | on-chip | serial | -+------------+------------+-------------------------------------+ - -Prerequisites -------------- +.. zephyr:board-supported-hw:: -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - CONFIG_BOOTLOADER_MCUBOOT=y +Programming and Debugging +************************* -Sysbuild -======== +.. zephyr:board-supported-runners:: -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: esp32s3_luatos_core - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_luatos_core/esp32s3/procpu - :goals: build - -If CH343 chip is disabled, You need use the following command to build: - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_luatos_core/esp32s3/procpu/usb - :goals: build - -The usual ``flash`` target will work with the ``esp32s3_luatos_core`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_luatos_core/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32s3_luatos_core +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S3 support on OpenOCD is available at `OpenOCD ESP32`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_luatos_core/esp32s3/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_luatos_core/esp32s3/procpu - :goals: debug +========= +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -289,7 +55,3 @@ References .. target-notes:: .. _`ESP32S3-Luatos-Core`: https://wiki.luatos.com/chips/esp32s3/board.html -.. _`ESP32-S3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s3-mini-1_mini-1u_datasheet_en.pdf -.. _`ESP32-S3 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/m5stack/m5stack_atom_lite/doc/index.rst b/boards/m5stack/m5stack_atom_lite/doc/index.rst index 9b84f801fd6f7..121fb55bedbac 100644 --- a/boards/m5stack/m5stack_atom_lite/doc/index.rst +++ b/boards/m5stack/m5stack_atom_lite/doc/index.rst @@ -5,6 +5,9 @@ Overview M5Stack ATOM Lite is an ESP32-based development board from M5Stack. +Hardware +******** + It features the following integrated components: - ESP32-PICO-D4 chip (240MHz dual core, Wi-Fi/BLE 5.0) @@ -13,81 +16,41 @@ It features the following integrated components: - Infrared LED - 1x Grove extension port +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your M5Stack ATOM Lite, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements -=================== - -Prerequisites -------------- +System Requirements +******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. code-block:: shell - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -------------------- +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_atom_lite/esp32/procpu - :goals: build +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -The usual ``flash`` target will work with the ``m5stack_atom_lite`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_atom_lite/esp32/procpu - :goals: flash - -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! m5stack_atom_lite +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ---------- +========= M5Stack ATOM Lite debugging is not supported due to pinout limitations. Related Documents ***************** -- `M5Stack ATOM Lite docs `_ -- `M5Stack ATOM Lite schematic `_ -- `ESP32-PICO-D4 Datasheet `_ (PDF) + +.. target-notes:: + +.. _`M5Stack ATOM Lite docs`: https://docs.m5stack.com/en/core/ATOM%20Lite +.. _`M5Stack ATOM Lite schematic`: https://static-cdn.m5stack.com/resource/docs/products/core/atom_lite/atom_lite_map_01.webp +.. _`ESP32-PICO-D4 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf diff --git a/boards/m5stack/m5stack_atoms3/doc/index.rst b/boards/m5stack/m5stack_atoms3/doc/index.rst index 9cedbfb51805a..fcc0b28f987c5 100644 --- a/boards/m5stack/m5stack_atoms3/doc/index.rst +++ b/boards/m5stack/m5stack_atoms3/doc/index.rst @@ -5,91 +5,49 @@ Overview M5Stack AtomS3 is an ESP32-based development board from M5Stack. -It features the following integrated components: +Hardware +******** + +The board peripherals: -- ESP32-S3FN8 chip (240MHz dual core, Wi-Fi/BLE 5.0) -- 512KB of SRAM -- 384KB of ROM - 8MB of Flash - LCD IPS TFT 0.85", 128x128 px screen (ST7789 compatible) - 6-axis IMU MPU6886 - Infrared emitter +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your M5Stack AtomS3, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: shell - - west blobs fetch hal_espressif - -.. note:: +System Requirements +******************* - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Building & Flashing -------------------- +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_atoms3/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``m5stack_atoms3`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_atoms3/esp32s3/procpu - :goals: flash - -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! m5stack_atoms3 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ---------- +========= M5Stack AtomS3 debugging is not supported due to pinout limitations. Related Documents ***************** -- `M5Stack AtomS3 schematic `_ -- `ESP32S3 Datasheet `_ +.. target-notes:: + +.. _`M5Stack AtomS3 schematic`: https://static-cdn.m5stack.com/resource/docs/products/core/AtomS3/img-b85e925c-adff-445d-994c-45987dc97a44.jpg diff --git a/boards/m5stack/m5stack_atoms3_lite/doc/index.rst b/boards/m5stack/m5stack_atoms3_lite/doc/index.rst index 8403358be1e4f..17a5361f79467 100644 --- a/boards/m5stack/m5stack_atoms3_lite/doc/index.rst +++ b/boards/m5stack/m5stack_atoms3_lite/doc/index.rst @@ -5,6 +5,9 @@ Overview M5Stack AtomS3 Lite is an ESP32-based development board from M5Stack. +Hardware +******** + It features the following integrated components: - ESP32-S3FN8 chip (240MHz dual core, Wi-Fi/BLE 5.0) @@ -13,81 +16,39 @@ It features the following integrated components: - 8MB of Flash - RGB Status-LED +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Start Application Development -***************************** - -Before powering up your M5Stack AtomS3 Lite, please make sure that the board is in good -condition with no obvious signs of damage. - System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: shell - - west blobs fetch hal_espressif - -.. note:: +******************* - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Building & Flashing -------------------- +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_atoms3_lite/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``m5stack_atoms3_lite`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_atoms3_lite/esp32s3/procpu - :goals: flash - -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! m5stack_atoms3_lite +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ---------- +========= M5Stack AtomS3 Lite debugging is not supported due to pinout limitations. -Related Documents -***************** +References +********** + +.. target-notes:: -- `M5Stack AtomS3 Lite schematic `_ -- `ESP32S3 Datasheet `_ +.. _`M5Stack AtomS3 Lite schematic`: https://static-cdn.m5stack.com/resource/docs/products/core/AtomS3%20Lite/img-4061fdd4-6954-4709-a7e7-b0f50e5ba52e.webp diff --git a/boards/m5stack/m5stack_core2/doc/index.rst b/boards/m5stack/m5stack_core2/doc/index.rst index fb21227767c44..e0047a3c6dcd6 100644 --- a/boards/m5stack/m5stack_core2/doc/index.rst +++ b/boards/m5stack/m5stack_core2/doc/index.rst @@ -5,6 +5,9 @@ Overview M5Stack Core2 is an ESP32-based development board from M5Stack. It is the successor for the Core module. +Hardware +******** + M5Stack Core2 features the following integrated components: - ESP32-D0WDQ6-V3 chip (240MHz dual core, 600 DMIPS, 520KB SRAM, Wi-Fi) @@ -23,8 +26,16 @@ M5Stack Core2 features the following integrated components: - MIC SPM1423 - Battery 390mAh 3,7V +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + +Supported Features +================== + +.. zephyr:board-supported-hw:: + Functional Description -********************** +====================== The following table below describes the key components, interfaces, and controls of the M5Stack Core2 board. @@ -82,6 +93,7 @@ of the M5Stack Core2 board. Power supply ============ + M5Stack Core2 module is equipped with the feature-rich power management IC (:dtcompatible:`x-powers,axp192-regulator`). Following regulators are utilized on this module: @@ -98,87 +110,34 @@ Following regulators are utilized on this module: BUS_5V supply for Grove port. Note: This fixed regulator supply is disabled by default. - These voltages can be controlled via regulator api. -Supported Features -================== - -.. zephyr:board-supported-hw:: - -Start Application Development -***************************** - -Before powering up your M5Stack Core2, please make sure that the board is in good -condition with no obvious signs of damage. +System Requirements +******************* -System requirements -=================== +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -------------------- +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_core2/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``m5stack_core2`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_core2/esp32/procpu - :goals: flash - -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! m5stack_core2 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ---------- +========= M5Stack Core2 debugging is not supported due to pinout limitations. Related Documents ***************** -- `M5Stack-Core2 schematic `_ (PDF) -- `ESP32-PICO-D4 Datasheet `_ (PDF) -- `M5Stack-Core2 docs `_ -- `ESP32 Datasheet `_ (PDF) -- `ESP32 Hardware Reference `_ +.. _`M5Stack-Core2 schematic`: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/schematic/Core/CORE2_V1.0_SCH.pdf +.. _`ESP32-PICO-D4 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf +.. _`M5Stack-Core2 docs`: https://docs.m5stack.com/en/core/core2 +.. _`ESP32 Hardware Reference`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/index.html diff --git a/boards/m5stack/m5stack_cores3/doc/index.rst b/boards/m5stack/m5stack_cores3/doc/index.rst index 2fdd042c38e67..e6e6da6136a05 100644 --- a/boards/m5stack/m5stack_cores3/doc/index.rst +++ b/boards/m5stack/m5stack_cores3/doc/index.rst @@ -7,6 +7,9 @@ M5Stack CoreS3 is an ESP32-based development board from M5Stack. It is the third M5Stack CoreS3 SE is the compact version of CoreS3. It has the same form factor as the original M5Stack, and some features were reduced from CoreS3. +Hardware +******** + M5Stack CoreS3/CoreS3 SE features consist of: - ESP32-S3 chip (dual-core Xtensa LX7 processor @240MHz, WIFI, OTG and CDC functions) @@ -26,234 +29,36 @@ M5Stack CoreS3/CoreS3 SE features consist of: - Proximity sensor LTR-553ALS-WA (Not available for CoreS3 SE) - 6-Axis IMU BMI270 (Not available for CoreS3 SE) -Start Application Development -***************************** - -Before powering up your M5Stack CoreS3, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features -Building & Flashing -******************* - -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader +Supported Features ================== -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. tabs:: - - .. group-tab:: M5Stack CoreS3 - - .. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: - - .. group-tab:: M5Stack CoreS3 SE - - .. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu/se - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: +.. zephyr:board-supported-hw:: - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. tabs:: - - .. group-tab:: M5Stack CoreS3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu - :goals: build - - .. group-tab:: M5Stack CoreS3 SE - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu/se - :goals: build - -The usual ``flash`` target will work with the ``m5stack_cores3/esp32s3/procpu`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. tabs:: - - .. group-tab:: M5Stack CoreS3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu - :goals: flash - - .. group-tab:: M5Stack CoreS3 SE - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu/se - :goals: flash - -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: +System Requirements +******************* -.. code-block:: shell +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - west espressif monitor +Programming and Debugging +************************* -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - *** Booting Zephyr OS build vx.x.x-xxx-gxxxxxxxxxxxx *** - Hello World! m5stack_cores3/esp32s3/procpu +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S3 support on OpenOCD is available at `OpenOCD ESP32`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. tabs:: - - .. group-tab:: M5Stack CoreS3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu - :goals: debug - - .. group-tab:: M5Stack CoreS3 SE - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu/se - :goals: debug - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. tabs:: - - .. group-tab:: M5Stack CoreS3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu - :goals: debug - - .. group-tab:: M5Stack CoreS3 SE +========= - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_cores3/esp32s3/procpu/se - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -264,5 +69,3 @@ References .. _`M5Stack CoreS3 Schematic`: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/K128%20CoreS3/Sch_M5_CoreS3_v1.0.pdf .. _`M5Stack CoreS3 SE Documentation`: https://docs.m5stack.com/en/core/M5CoreS3%20SE .. _`M5Stack CoreS3 SE Schematic`: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/products/core/M5CORES3%20SE/M5_CoreS3SE.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ diff --git a/boards/m5stack/m5stack_fire/doc/index.rst b/boards/m5stack/m5stack_fire/doc/index.rst index 0a5f940cc2fe7..f6c19960b3c85 100644 --- a/boards/m5stack/m5stack_fire/doc/index.rst +++ b/boards/m5stack/m5stack_fire/doc/index.rst @@ -5,6 +5,9 @@ Overview M5Stack Fire is an ESP32-based development board from M5Stack. +Hardware +******** + M5Stack Fire features the following integrated components: - ESP32-D0WDQ6 chip (240MHz dual core, 600 DMIPS, 520KB SRAM, Wi-Fi) @@ -22,8 +25,16 @@ M5Stack Fire features the following integrated components: - Three physical buttons - LED strips +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + +Supported Features +================== + +.. zephyr:board-supported-hw:: + Functional Description -********************** +====================== The following table below describes the key components, interfaces, and controls of the M5Stack Core2 board. @@ -69,83 +80,33 @@ of the M5Stack Core2 board. | | possibility to query current battery status. | | +------------------+------------------------------------------------------------------------+-----------+ -Supported Features -================== - -.. zephyr:board-supported-hw:: - -Start Application Development -***************************** - -Before powering up your M5Stack Fire, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements -=================== +System Requirements +******************* -Prerequisites -------------- +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -------------------- +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_fire/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``m5stack_fire`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_fire/esp32/procpu - :goals: flash +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! m5stack_fire +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ---------- +========= M5Stack Fire debugging is not supported due to pinout limitations. Related Documents ***************** -- `M5Stack-Fire schematic `_ (PDF) -- `M5Stack-Fire docs `_ -- `ESP32 Datasheet `_ (PDF) -- `ESP32 Hardware Reference `_ +.. target-notes:: + +.. _`M5Stack-Fire schematic`: https://m5stack-doc.oss-cn-shenzhen.aliyuncs.com/480/M5-Core-Schematic_20171206.pdf +.. _`M5Stack-Fire docs`: https://docs.m5stack.com/en/core/fire_v2.7 +.. _`ESP32 Hardware Reference`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/index.html diff --git a/boards/m5stack/m5stack_stamps3/doc/index.rst b/boards/m5stack/m5stack_stamps3/doc/index.rst index 4e006eca8a397..fd35a04ee41df 100644 --- a/boards/m5stack/m5stack_stamps3/doc/index.rst +++ b/boards/m5stack/m5stack_stamps3/doc/index.rst @@ -4,6 +4,10 @@ Overview ******** M5Stack StampS3 is an ESP32-based development board from M5Stack. + +Hardware +******** + It features the following integrated components: - ESP32-S3FN8 chip (240MHz dual core) @@ -14,8 +18,16 @@ It features the following integrated components: - Bluetooth - User-Button +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + +Supported Features +================== + +.. zephyr:board-supported-hw:: + Functional Description -********************** +====================== The following table below describes the key components, interfaces, and controls of the M5Stack StampS3 module. @@ -108,71 +120,28 @@ supply. If this pin is pulled low this main 3.3V power supply for the MCU will b deactivated. It is internally equipped with a pull-up and can hence be left open if unused. -Start Application Development -***************************** - -Before powering up your M5Stack StampS3, please make sure that the board is in good -condition with no obvious signs of damage. +System Requirements +******************* -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - It is recommended running the command above after :file:`west update`. - -Building & Flashing -------------------- +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_stamps3/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``m5stack_stamps3`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stack_stamps3/esp32s3/procpu - :goals: flash - -The baud rate of 921600bps is set by default. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! m5stack_stamps3 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging ---------- +========= + +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging M5Stack StampS3 exports a JTAG-interface via Pins 19 (MTCK), 21 (MTDO), 23 (MTDI), 25 (MTMS). @@ -185,7 +154,8 @@ M5Stack StampS3 exports a JTAG-interface via Pins 19 (MTCK), 21 (MTDO), 23 Related Documents ***************** -- `M5Stack StampS3 schematic `_ -- `M5Stack StampS3 `_ -- `ESP32 Datasheet `_ (PDF) -- `ESP32 Hardware Reference `_ +.. target-notes:: + +.. _`M5Stack StampS3 schematic`: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/Stamp/S007%20StampS3/Sch_M5StampS3_v0.2.pdf +.. _`M5Stack StampS3`: https://docs.m5stack.com/en/core/StampS3 +.. _`ESP32 Hardware Reference`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/index.html diff --git a/boards/m5stack/m5stickc_plus/doc/index.rst b/boards/m5stack/m5stickc_plus/doc/index.rst index e6e65a3e1d8f1..56eabee9e9452 100644 --- a/boards/m5stack/m5stickc_plus/doc/index.rst +++ b/boards/m5stack/m5stickc_plus/doc/index.rst @@ -5,6 +5,9 @@ Overview M5StickC PLUS, one of the core devices in M5Stacks product series, is an ESP32-based development board. +Hardware +******** + M5StickC PLUS features the following integrated components: - ESP32-PICO-D4 chip (240MHz dual core, 600 DMIPS, 520KB SRAM, Wi-Fi) @@ -17,8 +20,16 @@ M5StickC PLUS features the following integrated components: Some of the ESP32 I/O pins are broken out to the board's pin headers for easy access. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + +Supported Features +================== + +.. zephyr:board-supported-hw:: + Functional Description -********************** +====================== The following table below describes the key components, interfaces, and controls of the M5StickC PLUS board. @@ -57,165 +68,34 @@ of the M5StickC PLUS board. | microphone | | +------------------+-------------------------------------------------------------------------+ - -Start Application Development -***************************** - -Before powering up your M5StickC PLUS, please make sure that the board is in good -condition with no obvious signs of damage. - -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - .. code:: cfg +Programming and Debugging +************************* - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: m5stickc_plus - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stickc_plus/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``m5stickc_plus`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: m5stickc_plus/esp32/procpu - :goals: flash - -The default baud rate for the M5StickC PLUS is set to 1500000bps. If experiencing issues when flashing, -try using different values by using ``--esp-baud-rate `` option during -``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). - -You can also open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! m5stickc_plus +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* +========= M5StickC PLUS debugging is not supported due to pinout limitations. -Related Documents -***************** +References +********** + +.. target-notes:: -- `M5StickC PLUS schematic `_ (WEBP) -- `ESP32-PICO-D4 Datasheet `_ (PDF) -- `M5StickC PLUS docs `_ -- `ESP32 Datasheet `_ (PDF) -- `ESP32 Hardware Reference `_ +.. _`M5StickC PLUS schematic`: https://static-cdn.m5stack.com/resource/docs/products/core/m5stickc_plus/m5stickc_plus_sch_03.webp +.. _`ESP32-PICO-D4 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf +.. _`M5StickC PLUS docs`: https://docs.m5stack.com/en/core/m5stickc_plus +.. _`ESP32 Hardware Reference`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/index.html diff --git a/boards/m5stack/stamp_c3/doc/index.rst b/boards/m5stack/stamp_c3/doc/index.rst index 704bacc6cad90..9b2d729132513 100644 --- a/boards/m5stack/stamp_c3/doc/index.rst +++ b/boards/m5stack/stamp_c3/doc/index.rst @@ -8,171 +8,39 @@ for IoT edge devices such as home appliances and Industrial Automation. For more details see the `M5Stack STAMP-C3`_ page. +Hardware +******** + +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features + Supported Features ================== .. zephyr:board-supported-hw:: -Prerequisites -************* - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: stamp_c3 - :goals: build - :west-args: --sysbuild - :compact: +Programming and Debugging +************************* -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: stamp_c3 - :goals: build - -The usual ``flash`` target will work with the ``stamp_c3`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: stamp_c3 - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! stamp_c3 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: stamp_c3 - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: stamp_c3 - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -180,6 +48,3 @@ References .. target-notes:: .. _`M5Stack STAMP-C3`: https://docs.m5stack.com/en/core/stamp_c3 -.. _`ESP32C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`ESP32C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/olimex/olimex_esp32_evb/doc/index.rst b/boards/olimex/olimex_esp32_evb/doc/index.rst index 1f5ca0033fb30..6bb5e6b810dfc 100644 --- a/boards/olimex/olimex_esp32_evb/doc/index.rst +++ b/boards/olimex/olimex_esp32_evb/doc/index.rst @@ -38,191 +38,43 @@ these reference documents: - `ESP32-EVB GitHub Repository`_ - `ESP32-WROOM32-E/UE Datasheet`_ +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features + Supported Features -****************** +================== .. zephyr:board-supported-hw:: -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: olimex_esp32_evb - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: olimex_esp32_evb/esp32/procpu - :goals: build - -The usual ``flash`` target will work with the ``olimex_esp32_evb`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: olimex_esp32_evb/esp32/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! olimex_esp32_evb +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: olimex_esp32_evb/esp32/procpu - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: olimex_esp32_evb/esp32/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. _ESP32-EVB Website: - https://www.olimex.com/Products/IoT/ESP32/ESP32-EVB/open-source-hardware - -.. _ESP32-EVB Schematic: - https://github.com/OLIMEX/ESP32-EVB/raw/master/HARDWARE/REV-I/ESP32-EVB_Rev_I.pdf - -.. _ESP32-EVB GitHub Repository: - https://github.com/OLIMEX/ESP32-EVB - -.. _ESP32-WROOM32-E/UE Datasheet: - https://www.espressif.com/sites/default/files/documentation/esp32-wroom-32e_esp32-wroom-32ue_datasheet_en.pdf - -.. _OpenOCD ESP32: - https://github.com/espressif/openocd-esp32/releases +.. _`ESP32-EVB Website`: https://www.olimex.com/Products/IoT/ESP32/ESP32-EVB/open-source-hardware +.. _`ESP32-EVB Schematic`: https://github.com/OLIMEX/ESP32-EVB/raw/master/HARDWARE/REV-I/ESP32-EVB_Rev_I.pdf +.. _`ESP32-EVB GitHub Repository`: https://github.com/OLIMEX/ESP32-EVB +.. _`ESP32-WROOM32-E/UE Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-wroom-32e_esp32-wroom-32ue_datasheet_en.pdf diff --git a/boards/others/esp32c3_supermini/doc/index.rst b/boards/others/esp32c3_supermini/doc/index.rst index cf7e1841e05dd..bcd6856c04011 100644 --- a/boards/others/esp32c3_supermini/doc/index.rst +++ b/boards/others/esp32c3_supermini/doc/index.rst @@ -5,206 +5,42 @@ Overview ESP32-C3-SUPERMINI is based on the ESP32-C3, a single-core Wi-Fi and Bluetooth 5 (LE) microcontroller SoC, based on the open-source RISC-V architecture. This board also includes a Type-C USB Serial/JTAG port. -There may be multiple variations depending on the specific vendor. For more information a reasonably well documented version of this board can be found at `ESP32-C3-SUPERMINI`_ +There may be multiple variations depending on the specific vendor. +For more information a reasonably well documented version of this board can be found at `ESP32-C3-SUPERMINI`_ Hardware ******** -SoC Features: - -- IEEE 802.11 b/g/n-compliant -- Bluetooth 5, Bluetooth mesh -- 32-bit RISC-V single-core processor, up to 160MHz -- 384 KB ROM -- 400 KB SRAM (16 KB for cache) -- 8 KB SRAM in RTC -- 22 x programmable GPIOs -- 3 x SPI -- 2 x UART -- 1 x I2C -- 1 x I2S -- 2 x 54-bit general-purpose timers -- 3 x watchdog timers -- 1 x 52-bit system timer -- Remote Control Peripheral (RMT) -- LED PWM controller (LEDC) -- Full-speed USB Serial/JTAG controller -- General DMA controller (GDMA) -- 1 x TWAI® -- 2 x 12-bit SAR ADCs, up to 6 channels -- 1 x soc core temperature sensor - -For more information on the ESP32-C3 SOC, check the datasheet at `ESP32-C3 Datasheet`_ or the technical reference -manual at `ESP32-C3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features Supported Features ================== .. zephyr:board-supported-hw:: -System requirements +System Requirements ******************* -Prerequisites -============= +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: esp32c3_supermini - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_supermini - :goals: build - -The usual ``flash`` target will work with the ``esp32c3_supermini`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_supermini - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32c3_supermini +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32-C3 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_supermini - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32c3_supermini - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -212,6 +48,3 @@ References .. target-notes:: .. _`ESP32-C3-SUPERMINI`: https://www.nologo.tech/product/esp32/esp32c3SuperMini/esp32C3SuperMini.html -.. _`ESP32-C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`ESP32-C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/others/icev_wireless/doc/index.rst b/boards/others/icev_wireless/doc/index.rst index f9168a1489013..e706428d1ca14 100644 --- a/boards/others/icev_wireless/doc/index.rst +++ b/boards/others/icev_wireless/doc/index.rst @@ -3,7 +3,7 @@ Overview ******** -The ICE-V Wireless is a combined ESP32C3 and iCE40 FPGA board. +The ICE-V Wireless is a combined ESP32-C3 and iCE40 FPGA board. See the `ICE-V Wireless Github Project`_ for details. @@ -25,6 +25,9 @@ For details on iCE40 hardware please refer to the following resources: * `iCE40 UltraPlus Family Datasheet`_ +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features + Supported Features ================== @@ -55,179 +58,35 @@ below. :align: center :alt: ICE-V Wireless Pinout +System Requirements +******************* + +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements + Programming and Debugging ************************* .. zephyr:board-supported-runners:: -Programming and debugging for the ICE-V Wireless ESP32-C3 target is -incredibly easy 🎉 following the steps below. - -Building and Flashing -********************* - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: icev_wireless - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -For the :code:`Hello, world!` application, follow the instructions below. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: icev_wireless - :goals: build flash - -Open the serial monitor using the following command: - -.. code-block:: console - - $ west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! icev_wireless +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32C3 modules require patches to -OpenOCD that are not upstreamed. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained by running the following extension: +========= -.. code-block:: console - - west espressif install - -.. note:: - - By default, the OpenOCD will be downloaded and installed under $HOME/.espressif/tools/zephyr directory - (%USERPROFILE%/.espressif/tools/zephyr on Windows). - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: icev_wireless - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the -:zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: icev_wireless - :maybe-skip-config: - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. _ICE-V Wireless Github Project: - https://github.com/ICE-V-Wireless/ICE-V-Wireless - -.. _ESP32-C3-MINI-1 Datasheet: - https://www.espressif.com/sites/default/files/documentation/esp32-c3-mini-1_datasheet_en.pdf - -.. _ESP32-C3 Datasheet: - https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf - -.. _ESP32-C3 Technical Reference Manual: - https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf - -.. _iCE40 UltraPlus Family Datasheet: - https://www.latticesemi.com/-/media/LatticeSemi/Documents/DataSheets/iCE/iCE40-UltraPlus-Family-Data-Sheet.ashx - -.. _PMOD Specification: - https://digilent.com/reference/_media/reference/pmod/pmod-interface-specification-1_2_0.pdf +.. _`ICE-V Wireless Github Project`: https://github.com/ICE-V-Wireless/ICE-V-Wireless +.. _`ESP32-C3-MINI-1 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3-mini-1_datasheet_en.pdf +.. _`iCE40 UltraPlus Family Datasheet`: https://www.latticesemi.com/-/media/LatticeSemi/Documents/DataSheets/iCE/iCE40-UltraPlus-Family-Data-Sheet.ashx +.. _`PMOD Specification`: https://digilent.com/reference/_media/reference/pmod/pmod-interface-specification-1_2_0.pdf diff --git a/boards/seeed/seeeduino_xiao/doc/index.rst b/boards/seeed/seeeduino_xiao/doc/index.rst index 64289cebf1d65..a216a4748af5e 100644 --- a/boards/seeed/seeeduino_xiao/doc/index.rst +++ b/boards/seeed/seeeduino_xiao/doc/index.rst @@ -127,11 +127,6 @@ References .. target-notes:: -.. _Seeeduino XIAO wiki: - https://wiki.seeedstudio.com/Seeeduino-XIAO/ - -.. _pinouts: - https://wiki.seeedstudio.com/Seeeduino-XIAO/#hardware-overview - -.. _schematic: - https://wiki.seeedstudio.com/Seeeduino-XIAO/#resources +.. _`Seeeduino XIAO wiki`: https://wiki.seeedstudio.com/Seeeduino-XIAO/ +.. _`pinouts`: https://wiki.seeedstudio.com/Seeeduino-XIAO/#hardware-overview +.. _`schematic`: https://wiki.seeedstudio.com/Seeeduino-XIAO/#resources diff --git a/boards/seeed/xiao_esp32c3/doc/index.rst b/boards/seeed/xiao_esp32c3/doc/index.rst index ef8bdb5a86e11..84ea2d13a7bb3 100644 --- a/boards/seeed/xiao_esp32c3/doc/index.rst +++ b/boards/seeed/xiao_esp32c3/doc/index.rst @@ -3,7 +3,7 @@ Overview ******** -Seeed Studio XIAO ESP32C3 is an IoT mini development board based on the +Seeed Studio XIAO ESP32-C3 is an IoT mini development board based on the Espressif ESP32-C3 WiFi/Bluetooth dual-mode chip. For more details see the `Seeed Studio XIAO ESP32C3`_ wiki page. @@ -16,6 +16,9 @@ has an USB-C port for programming and debugging, integrated battery charging and an U.FL external antenna connector. It is based on a standard XIAO 14 pin pinout. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features + Supported Features ================== @@ -32,157 +35,28 @@ The board uses a standard XIAO pinout, the default pin mapping is the following: XIAO ESP32C3 Pinout -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: xiao_esp32c3 - :goals: build - :west-args: --sysbuild - :compact: +Programming and Debugging +************************* -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by Sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -For the :code:`Hello, world!` application, follow the instructions below. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32c3 - :goals: build flash - -Since the Zephyr console is by default on the ``usb_serial`` device, we use -the espressif monitor to view. - -.. code-block:: console - - $ west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! xiao_esp32c3 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32c3 - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32c3 - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -190,4 +64,3 @@ References .. target-notes:: .. _`Seeed Studio XIAO ESP32C3`: https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/seeed/xiao_esp32c6/doc/index.rst b/boards/seeed/xiao_esp32c6/doc/index.rst index a1b93cc9c42dc..06aeaf8ed9b45 100644 --- a/boards/seeed/xiao_esp32c6/doc/index.rst +++ b/boards/seeed/xiao_esp32c6/doc/index.rst @@ -18,11 +18,17 @@ Bluetooth 5.3 (LE) and the 802.15.4 protocol. It has an USB-C port for programmi and debugging, integrated battery charging and an U.FL external antenna connector. It is based on a standard XIAO 14 pin pinout. +.. include:: ../../../espressif/common/soc-esp32c6-features.rst + :start-after: espressif-soc-esp32c6-features + Supported Features ================== .. zephyr:board-supported-hw:: +Connections and IOs +=================== + The board uses a standard XIAO pinout, the default pin mapping is the following: .. figure:: img/xiao_esp32c6_pinout.webp @@ -31,170 +37,28 @@ The board uses a standard XIAO pinout, the default pin mapping is the following: XIAO ESP32C6 Pinout -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the EPS32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: xiao_esp32c6/esp32c6/hpcore - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32-C6 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32c6/esp32c6/hpcore - :goals: build - -The usual ``flash`` target will work with the ``xiao_esp32c6`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32c6/esp32c6/hpcore - :goals: flash - -Since the Zephyr console is by default on the ``usb_serial`` device, we use -the espressif monitor to view. - -.. code-block:: console - - $ west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! xiao_esp32c6/esp32c6/hpcore +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32-C6 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32c6/esp32c6/hpcore - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32c6/esp32c6/hpcore - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -202,6 +66,3 @@ References .. target-notes:: .. _`Seeed Studio XIAO ESP32C6`: https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/ -.. _`ESP32-C6 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf -.. _`ESP32-C6 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/seeed/xiao_esp32s3/doc/index.rst b/boards/seeed/xiao_esp32s3/doc/index.rst index 1aacfe17bc44e..8a6976ea7f17f 100644 --- a/boards/seeed/xiao_esp32s3/doc/index.rst +++ b/boards/seeed/xiao_esp32s3/doc/index.rst @@ -35,6 +35,9 @@ RF module, and numerous peripherals. Additionally, Sense variant integrates a OV2640 camera sensor, microphone and sdcard slot. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features + Supported Features ================== @@ -51,173 +54,31 @@ The board uses a standard XIAO pinout, the default pin mapping is the following: XIAO ESP32S3 and XIAO ESP32S3 Sense Pinout -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: xiao_esp32s3 - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). +Programming and Debugging +************************* -.. tabs:: - - .. group-tab:: XIAO ESP32S3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32s3/esp32s3/procpu - :goals: build - - .. group-tab:: XIAO ESP32S3 Sense - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32s3/esp32s3/procpu/sense - :goals: build - -The usual ``flash`` target will work with the ``xiao_esp32s3`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. tabs:: - - .. group-tab:: XIAO ESP32S3 - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32s3/esp32s3/procpu - :goals: flash - - .. group-tab:: XIAO ESP32S3 Sense - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: xiao_esp32s3/esp32s3/procpu/sense - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! xiao_esp32s3 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S3 support on OpenOCD is available at `OpenOCD ESP32`_. +========= -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any additional chip. Only an USB cable connected to the D+/D- pins is necessary. +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. +Sample applications +******************* .. tabs:: @@ -259,5 +120,3 @@ References .. target-notes:: .. _`Seeed Studio XIAO ESP32S3`: https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/ -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/vcc-gnd/yd_esp32/doc/index.rst b/boards/vcc-gnd/yd_esp32/doc/index.rst index af9e54c5a65fd..9885330db4247 100644 --- a/boards/vcc-gnd/yd_esp32/doc/index.rst +++ b/boards/vcc-gnd/yd_esp32/doc/index.rst @@ -6,208 +6,39 @@ Overview The YD-ESP32 development board is one of VCC-GND® Studio's official boards. This board is based on the ESP32-WROOM-32E module, with the ESP32 as the core. -ESP32 -===== - -ESP32 is a series of low cost, low power system on a chip microcontrollers -with integrated Wi-Fi & dual-mode Bluetooth. The ESP32 series employs a -Tensilica Xtensa LX6 microprocessor in both dual-core and single-core -variations. ESP32 is created and developed by Espressif Systems, a -Shanghai-based Chinese company, and is manufactured by TSMC using their 40nm -process. - -The features include the following: - -- Dual core Xtensa microprocessor (LX6), running at 160 or 240MHz -- 520KB of SRAM -- 802.11b/g/n/e/i -- Bluetooth v4.2 BR/EDR and BLE -- Various peripherals: - - - 12-bit ADC with up to 18 channels - - 2x 8-bit DACs - - 10x touch sensors - - Temperature sensor - - 4x SPI - - 2x I2S - - 2x I2C - - 3x UART - - SD/SDIO/MMC host - - Slave (SDIO/SPI) - - Ethernet MAC - - CAN bus 2.0 - - IR (RX/TX) - - Motor PWM - - LED PWM with up to 16 channels - - Hall effect sensor - -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) -- 5uA deep sleep current +Hardware +******** -For more information, check the datasheet at `ESP32 Datasheet`_ or the technical reference -manual at `ESP32 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32-features.rst + :start-after: espressif-soc-esp32-features Supported Features ================== .. zephyr:board-supported-hw:: -System requirements -=================== - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: yd_esp32 - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: yd_esp32/esp32/procpu - :goals: build +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -The usual ``flash`` target will work with the ``yd_esp32`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. +Programming and Debugging +************************* -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: yd_esp32/esp32/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! yd_esp32 - -RGB LED -======= - -The board contains an addressable RGB LED (`XL-5050RGBC-WS2812B`_), driven by GPIO16. -Here is an example of how to test it using the :zephyr:code-sample:`led-strip` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/drivers/led/led_strip - :board: yd_esp32/esp32/procpu - :goals: flash +.. zephyr:board-supported-runners:: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -.. _`XL-5050RGBC-WS2812B`: http://www.xinglight.cn/index.php?c=show&id=947 +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* +========= -ESP32 support on OpenOCD is available at `OpenOCD ESP32`_. +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging On the YD-ESP32 board, the JTAG pins are not run to a standard connector (e.g. ARM 20-pin) and need to be manually connected @@ -231,22 +62,6 @@ to the external programmer (e.g. a Flyswatter2): | IO15 | TDO | +------------+-----------+ -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: yd_esp32/esp32/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: yd_esp32/esp32/procpu - :goals: debug - Note on Debugging with GDB Stub =============================== @@ -258,13 +73,26 @@ GDB stub is enabled on ESP32. This does not work as the code is on flash which cannot be randomly accessed for modification. + +Sample applications +******************* + +RGB LED +======= + +The board contains an addressable RGB LED (`XL-5050RGBC-WS2812B`_), driven by GPIO16. +Here is an example of how to test it using the :zephyr:code-sample:`led-strip` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/led/led_strip + :board: yd_esp32/esp32/procpu + :goals: flash + +.. _`XL-5050RGBC-WS2812B`: http://www.xinglight.cn/index.php?c=show&id=947 + References ********** .. target-notes:: .. _`ESP32-DevKitC-WROVER`: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/hw-reference/esp32/get-started-devkitc.html# -.. _`ESP32 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf -.. _`ESP32 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/waveshare/esp32s3_matrix/doc/index.rst b/boards/waveshare/esp32s3_matrix/doc/index.rst index 4090485a84d66..71d8e7eebf7a1 100644 --- a/boards/waveshare/esp32s3_matrix/doc/index.rst +++ b/boards/waveshare/esp32s3_matrix/doc/index.rst @@ -11,38 +11,13 @@ port. Hardware ******** -ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi -and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor -(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, -RF module, and numerous peripherals. - -ESP32-S3-Matrix includes the following features: - -- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz -- Additional vector instructions support for AI acceleration -- 512KB of SRAM -- 2MB of PSRAM -- 4MB of FLASH -- Wi-Fi 802.11b/g/n -- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate -- 8x8 RGB LED matrix -- Accelerometer/gyroscope - -Digital interfaces: - -- 15 programmable GPIOs +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features -Low Power: +The board included peripherals: -- Power Management Unit with five power modes -- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) +- 8x8 RGB LED matrix +- Accelerometer/gyroscope Asymmetric Multiprocessing (AMP) ******************************** @@ -59,163 +34,28 @@ Supported Features .. zephyr:board-supported-hw:: -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing +System Requirements ******************* -.. zephyr:board-supported-runners:: - -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32-S3 SoC. +Programming and Debugging +************************* -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: esp32s3_matrix/esp32s3/procpu - :goals: build - :west-args: --sysbuild - :compact: - -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │   └── zephyr - │   ├── zephyr.elf - │   └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_matrix/esp32s3/procpu - :goals: build - -The usual ``flash`` target will work with the ``esp32s3_matrix`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_matrix/esp32s3/procpu - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: +.. zephyr:board-supported-runners:: -.. code-block:: console +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32s3_matrix +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -ESP32-S3 support on OpenOCD is available at `OpenOCD ESP32`_. - -ESP32-S3 has a built-in JTAG circuitry and can be debugged without any additional chip. Only an USB cable connected to the D+/D- pins is necessary. - -Further documentation can be obtained from the SoC vendor in `JTAG debugging for ESP32-S3`_. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_matrix/esp32s3/procpu - :goals: build flash - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s3_matrix/esp32s3/procpu - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -223,7 +63,3 @@ References .. target-notes:: .. _ESP32-S3-Matrix Waveshare Wiki: https://www.waveshare.com/wiki/ESP32-S3-Matrix -.. _ESP32-S3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf -.. _ESP32-S3 Technical Reference Manual: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/doc/index.rst b/boards/waveshare/esp32s3_touch_lcd_1_28/doc/index.rst index b9cab2da1d141..1a4ce7dde60e5 100644 --- a/boards/waveshare/esp32s3_touch_lcd_1_28/doc/index.rst +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/doc/index.rst @@ -10,89 +10,40 @@ Low Energy functions, an accelerometer and gyroscope, a battery charger and GPIO Hardware ******** -ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi -and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor -(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, -RF module, and numerous peripherals. - -ESP32-S3-Touch-LCD-1.28 includes the following features: - -- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz -- Additional vector instructions support for AI acceleration -- 2MB of SRAM -- 16MB of FLASH -- Wi-Fi 802.11b/g/n -- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate -- Round 1.28" LCD with touchscreen controller -- Accelerometer/gyroscope -- Battery charger - -Digital interfaces: - -- 6 programmable GPIOs -- 2 open-drain outputs - -Low Power: - -- Power Management Unit with five power modes -- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) - -Asymmetric Multiprocessing (AMP) -******************************** - -ESP32-S3 allows 2 different applications to be executed in ESP32-S3 SoC. Due to its dual-core -architecture, each core can be enabled to execute customized tasks in stand-alone mode -and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference. - -For more information, check the datasheet at `ESP32-S3 Datasheet`_ or the technical reference -manual at `ESP32-S3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features Supported Features ================== .. zephyr:board-supported-hw:: -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: +System Requirements +******************* - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. note:: +Debugging +========= - Simple boot does not provide any security features nor OTA updates. +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. _ESP32-S3-Touch-LCD-1.28 Waveshare Wiki: https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-1.28 -.. _ESP32-S3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s3-mini-1_mini-1u_datasheet_en.pdf -.. _ESP32-S3 Technical Reference Manual: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf +.. _`ESP32-S3-Touch-LCD-1.28 Waveshare Wiki`: https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-1.28 diff --git a/boards/we/orthosie1ev/doc/index.rst b/boards/we/orthosie1ev/doc/index.rst index 55f0afdb168a5..3df31a4a19fbc 100644 --- a/boards/we/orthosie1ev/doc/index.rst +++ b/boards/we/orthosie1ev/doc/index.rst @@ -4,209 +4,42 @@ Overview ******** Orthosie-I-EV is an entry-level development board based on Orthosie-I, -a module named for its small size. This board integrates complete Wi-Fi and Bluetooth® Low Energy functions. +a module named for its small size. This board integrates ESP32-C3 - complete Wi-Fi and Bluetooth® Low Energy functions. For more information, check `Orthosie-I Website`_. Hardware ******** -ESP32-C3 is a single-core Wi-Fi and Bluetooth 5 (LE) microcontroller SoC, -based on the open-source RISC-V architecture. It strikes the right balance of power, -I/O capabilities and security, thus offering the optimal cost-effective -solution for connected devices. -The availability of Wi-Fi and Bluetooth 5 (LE) connectivity not only makes the device configuration easy, -but it also facilitates a variety of use-cases based on dual connectivity. - -The features include the following: - -- 32-bit core RISC-V microcontroller with a maximum clock speed of 160 MHz -- 400 KB of internal RAM -- 802.11b/g/n/e/i -- A Bluetooth LE subsystem that supports features of Bluetooth 5 and Bluetooth Mesh -- Various peripherals: - - - 12-bit ADC with up to 6 channels - - TWAI compatible with CAN bus 2.0 - - Temperature sensor - - 3x SPI - - 1x I2S - - 1x I2C - - 2x UART - - LED PWM with up to 6 channels - -- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) - -For more information, check the datasheet at `ESP32-C3 Datasheet`_ or the technical reference -manual at `ESP32-C3 Technical Reference Manual`_. +.. include:: ../../../espressif/common/soc-esp32c3-features.rst + :start-after: espressif-soc-esp32c3-features Supported Features ================== .. zephyr:board-supported-hw:: -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -******************* +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Simple boot -=========== - -The board could be loaded using the single binary image, without 2nd stage bootloader. -It is the default option when building the application without additional configuration. - -.. note:: - - Simple boot does not provide any security features nor OTA updates. - -MCUboot bootloader -================== - -User may choose to use MCUboot bootloader instead. In that case the bootloader -must be built (and flashed) at least once. - -There are two options to be used when building an application: - -1. Sysbuild -2. Manual build - -.. note:: - - User can select the MCUboot bootloader by adding the following line - to the board default configuration file. - - .. code:: cfg - - CONFIG_BOOTLOADER_MCUBOOT=y - -Sysbuild -======== - -The sysbuild makes possible to build and flash all necessary images needed to -bootstrap the board with the ESP32 SoC. - -To build the sample application using sysbuild use the command: - -.. zephyr-app-commands:: - :tool: west - :zephyr-app: samples/hello_world - :board: we_orthosie1ev - :goals: build - :west-args: --sysbuild - :compact: +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -By default, the ESP32 sysbuild creates bootloader (MCUboot) and application -images. But it can be configured to create other kind of images. - -Build directory structure created by sysbuild is different from traditional -Zephyr build. Output is structured by the domain subdirectories: - -.. code-block:: - - build/ - ├── hello_world - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - ├── mcuboot - │ └── zephyr - │ ├── zephyr.elf - │ └── zephyr.bin - └── domains.yaml - -.. note:: - - With ``--sysbuild`` option the bootloader will be re-build and re-flash - every time the pristine build is used. - -For more information about the system build please read the :ref:`sysbuild` documentation. - -Manual build -============ - -During the development cycle, it is intended to build & flash as quickly possible. -For that reason, images can be built one at a time using traditional build. - -The instructions following are relevant for both manual build and sysbuild. -The only difference is the structure of the build directory. - -.. note:: - - Remember that bootloader (MCUboot) needs to be flash at least once. - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: we_orthosie1ev - :goals: build - -The usual ``flash`` target will work with the ``we_orthosie1ev`` board -configuration. Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: we_orthosie1ev - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! we_orthosie1ev +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants Debugging -********* - -As with much custom hardware, the ESP32-C3 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_. - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :zephyr:code-sample:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: we_orthosie1ev - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :zephyr:code-sample:`hello_world` application. +========= -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: we_orthosie1ev - :goals: debug +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** @@ -214,6 +47,3 @@ References .. target-notes:: .. _`Orthosie-I Website`: https://www.we-online.com/en/components/products/ORTHOSIE-I -.. _`ESP32-C3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _`ESP32-C3 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/weact/weact_esp32s3_b/doc/index.rst b/boards/weact/weact_esp32s3_b/doc/index.rst index a4993ca310e46..9688303d5fb70 100644 --- a/boards/weact/weact_esp32s3_b/doc/index.rst +++ b/boards/weact/weact_esp32s3_b/doc/index.rst @@ -11,78 +11,15 @@ and user button. For more information, check `WeAct Studio ESP32-S3-B`_. Hardware ******** -ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi -and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor -(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, -RF module, and numerous peripherals. +.. include:: ../../../espressif/common/soc-esp32s3-features.rst + :start-after: espressif-soc-esp32s3-features WeAct Studio ESP32-S3-B includes the following features: -- Dual core 32-bit Xtensa Microprocessor (Tensilica LX7), running up to 240MHz -- Additional vector instructions support for AI acceleration -- 16MB external Flash memory (separate chip) -- 8MB integrated PSRAM (ESP32-S3R8 chip) -- 512KB of SRAM -- 384KB of ROM -- Wi-Fi 802.11b/g/n -- Bluetooth LE 5.0 with long-range support and up to 2Mbps data rate - Onboard RGB WS2812 LED (GPIO48) - User button (GPIO45) - BOOT button (GPIO0) -Digital interfaces: - -- 45 programmable GPIOs -- 4x SPI -- 1x LCD interface (8-bit ~16-bit parallel RGB, I8080 and MOTO6800), supporting conversion between RGB565, YUV422, YUV420 and YUV411 -- 1x DVP 8-bit ~16-bit camera interface -- 3x UART -- 2x I2C -- 2x I2S -- 1x RMT (TX/RX) -- 1x pulse counter -- LED PWM controller, up to 8 channels -- 1x full-speed USB OTG -- 1x USB Serial/JTAG controller -- 2x MCPWM -- 1x SDIO host controller with 2 slots -- General DMA controller (GDMA), with 5 transmit channels and 5 receive channels -- 1x TWAI® controller, compatible with ISO 11898-1 (CAN Specification 2.0) - -Analog interfaces: - -- 2x 12-bit SAR ADCs, up to 20 channels -- 1x temperature sensor -- 14x touch sensing IOs - -Timers: - -- 4x 54-bit general-purpose timers -- 1x 52-bit system timer -- 3x watchdog timers - -Low Power: - -- Power Management Unit with five power modes -- Ultra-Low-Power (ULP) coprocessors: ULP-RISC-V and ULP-FSM - -Security: - -- Secure boot -- Flash encryption -- 4-Kbit OTP, up to 1792 bits for users -- Cryptographic hardware acceleration: (AES-128/256, Hash, RSA, RNG, HMAC, Digital signature) - -Asymmetric Multiprocessing (AMP) -******************************** - -WeAct Studio ESP32-S3-B allows 2 different applications to be executed in ESP32-S3 SoC. Due to its dual-core -architecture, each core can be enabled to execute customized tasks in stand-alone mode -and/or exchanging data over OpenAMP framework. See :zephyr:code-sample-category:`ipc` folder as code reference. - -For more information, check the datasheet at `ESP32-S3 Datasheet`_ or the technical reference -manual at `ESP32-S3 Technical Reference Manual`_. - Supported Features ================== @@ -91,16 +28,8 @@ Supported Features System Requirements ******************* -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements Programming and Debugging ************************* @@ -110,6 +39,9 @@ Programming and Debugging .. include:: ../../../espressif/common/building-flashing.rst :start-after: espressif-building-flashing +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants + Debugging ========= @@ -122,5 +54,3 @@ References .. target-notes:: .. _`WeAct Studio ESP32-S3-B`: https://github.com/WeActStudio/WeActStudio.ESP32S3-AorB -.. _`ESP32-S3 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf -.. _`ESP32-S3 Technical Reference Manual`: https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf diff --git a/boards/wemos/esp32s2_lolin_mini/doc/index.rst b/boards/wemos/esp32s2_lolin_mini/doc/index.rst index 9fadc278205e2..eef927b2ca10a 100644 --- a/boards/wemos/esp32s2_lolin_mini/doc/index.rst +++ b/boards/wemos/esp32s2_lolin_mini/doc/index.rst @@ -3,99 +3,45 @@ Overview ******** -ESP32-S2 is a highly integrated, low-power, single-core Wi-Fi Microcontroller SoC, designed to be secure and -cost-effective, with a high performance and a rich set of IO capabilities. [1]_ - -The features include the following: - -- RSA-3072-based secure boot -- AES-XTS-256-based flash encryption -- Protected private key and device secrets from software access -- Cryptographic accelerators for enhanced performance -- Protection against physical fault injection attacks -- Various peripherals: - - - 43x programmable GPIOs - - 14x configurable capacitive touch GPIOs - - USB OTG - - LCD interface - - camera interface - - SPI - - I2S - - UART - - ADC - - DAC - - LED PWM with up to 8 channels +A mini wifi boards based ESP32-S2FN4R2. Hardware ******** +.. include:: ../../../espressif/common/soc-esp32s2-features.rst + :start-after: espressif-soc-esp32s2-features + Supported Features ================== .. zephyr:board-supported-hw:: -System requirements +System Requirements ******************* -Prerequisites -============= - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif +.. include:: ../../../espressif/common/system-requirements.rst + :start-after: espressif-system-requirements -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -=================== +Programming and Debugging +************************* .. zephyr:board-supported-runners:: -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s2_lolin_mini - :goals: build - -The usual ``flash`` target will work with the ``esp32s2_lolin_mini`` board -configuration after putting the board into bootloader mode by holding the '0' -button then pressing 'RST' and releasing the 'RST' button. - -Here is an example for the :zephyr:code-sample:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32s2_lolin_mini - :goals: flash - -Open a serial port using e.g. screen - -.. code-block:: shell - - screen /dev/ttyUSB0 115200 +.. include:: ../../../espressif/common/building-flashing.rst + :start-after: espressif-building-flashing -After the board has been manually reset and booted, you should see the following -message in the monitor: +.. include:: ../../../espressif/common/board-variants.rst + :start-after: espressif-board-variants -.. code-block:: console +Debugging +========= - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32s2_lolin_mini +.. include:: ../../../espressif/common/openocd-debugging.rst + :start-after: espressif-openocd-debugging References ********** .. target-notes:: -.. [1] https://www.espressif.com/en/products/socs/esp32-s2 -.. _`ESP32S2 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf -.. _`ESP32S2 Datasheet`: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf +.. _`ESP32-S2 Product pages`: https://www.espressif.com/en/products/socs/esp32-s2 From 1e600360cc6691616ea224508aed2b636e5d3020 Mon Sep 17 00:00:00 2001 From: S Mohamed Fiaz Date: Tue, 12 Aug 2025 17:27:55 +0530 Subject: [PATCH 386/397] driver: spi: silabs_siwx91x_gspi: Add pm device support for gspi driver This commit enables the pm device driver support for the spi_silabs_siwx91x_gspi driver. Signed-off-by: S Mohamed Fiaz --- drivers/spi/spi_silabs_siwx91x_gspi.c | 72 ++++++++++++++++++++------- dts/arm/silabs/siwg917.dtsi | 2 + 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi_silabs_siwx91x_gspi.c b/drivers/spi/spi_silabs_siwx91x_gspi.c index 2fb7e06dd549f..9ce1e7553145d 100644 --- a/drivers/spi/spi_silabs_siwx91x_gspi.c +++ b/drivers/spi/spi_silabs_siwx91x_gspi.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "clock_update.h" LOG_MODULE_REGISTER(spi_siwx91x_gspi, CONFIG_SPI_LOG_LEVEL); @@ -209,6 +211,7 @@ static void gspi_siwx91x_dma_rx_callback(const struct device *dev, void *user_da spi_context_cs_control(instance_ctx, false); spi_context_complete(instance_ctx, spi_dev, status); + pm_device_runtime_put_async(spi_dev, K_NO_WAIT); } static int gspi_siwx91x_dma_config(const struct device *dev, @@ -533,8 +536,15 @@ static int gspi_siwx91x_transceive(const struct device *dev, const struct spi_co struct gspi_siwx91x_data *data = dev->data; int ret = 0; + ret = pm_device_runtime_get(dev); + if (ret < 0) { + return ret; + } + if (!spi_siwx91x_is_dma_enabled_instance(dev) && asynchronous) { ret = -ENOTSUP; + pm_device_runtime_put(dev); + return ret; } spi_context_lock(&data->ctx, asynchronous, cb, userdata, config); @@ -559,6 +569,7 @@ static int gspi_siwx91x_transceive(const struct device *dev, const struct spi_co /* Perform synchronous polling transceive */ ret = gspi_siwx91x_transceive_polling_sync(dev, &data->ctx); spi_context_unlock_unconditionally(&data->ctx); + pm_device_runtime_put(dev); } return ret; @@ -592,35 +603,57 @@ static int gspi_siwx91x_release(const struct device *dev, const struct spi_confi return 0; } -static int gspi_siwx91x_init(const struct device *dev) +static int gspi_siwx91x_pm_action(const struct device *dev, enum pm_device_action action) { const struct gspi_siwx91x_config *cfg = dev->config; struct gspi_siwx91x_data *data = dev->data; int ret; - ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys); - if (ret) { - return ret; - } + switch (action) { + case PM_DEVICE_ACTION_RESUME: + break; + case PM_DEVICE_ACTION_SUSPEND: + break; + case PM_DEVICE_ACTION_TURN_ON: + ret = clock_control_on(cfg->clock_dev, cfg->clock_subsys); + if (ret < 0 && ret != -EALREADY) { + return ret; + } - ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); - if (ret) { - return ret; - } + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0 && ret != -ENOENT) { + return ret; + } - ret = spi_context_cs_configure_all(&data->ctx); - if (ret) { - return ret; - } + ret = spi_context_cs_configure_all(&data->ctx); + if (ret) { + return ret; + } - spi_context_unlock_unconditionally(&data->ctx); + spi_context_unlock_unconditionally(&data->ctx); - cfg->reg->GSPI_BUS_MODE_b.SPI_HIGH_PERFORMANCE_EN = 1; - cfg->reg->GSPI_CONFIG1_b.GSPI_MANUAL_CSN = 0; + cfg->reg->GSPI_BUS_MODE_b.SPI_HIGH_PERFORMANCE_EN = 1; + cfg->reg->GSPI_CONFIG1_b.GSPI_MANUAL_CSN = 0; + data->ctx.config = NULL; + break; + case PM_DEVICE_ACTION_TURN_OFF: + ret = clock_control_off(cfg->clock_dev, cfg->clock_subsys); + if (ret < 0 && ret != -EALREADY) { + return ret; + } + break; + default: + return -ENOTSUP; + } return 0; } +static int gspi_siwx91x_init(const struct device *dev) +{ + return pm_device_driver_init(dev, gspi_siwx91x_pm_action); +} + static DEVICE_API(spi, gspi_siwx91x_driver_api) = { .transceive = gspi_siwx91x_transceive_sync, #ifdef CONFIG_SPI_ASYNC @@ -662,8 +695,9 @@ static DEVICE_API(spi, gspi_siwx91x_driver_api) = { .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ .mosi_overrun = (uint8_t)SPI_MOSI_OVERRUN_DT(inst), \ }; \ - DEVICE_DT_INST_DEFINE(inst, &gspi_siwx91x_init, NULL, &gspi_data_##inst, \ - &gspi_config_##inst, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ - &gspi_siwx91x_driver_api); + PM_DEVICE_DT_INST_DEFINE(inst, gspi_siwx91x_pm_action); \ + DEVICE_DT_INST_DEFINE(inst, &gspi_siwx91x_init, PM_DEVICE_DT_INST_GET(inst), \ + &gspi_data_##inst, &gspi_config_##inst, POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, &gspi_siwx91x_driver_api); DT_INST_FOREACH_STATUS_OKAY(SIWX91X_GSPI_INIT) diff --git a/dts/arm/silabs/siwg917.dtsi b/dts/arm/silabs/siwg917.dtsi index 561e9051c57de..72ea7f7855ce1 100644 --- a/dts/arm/silabs/siwg917.dtsi +++ b/dts/arm/silabs/siwg917.dtsi @@ -382,6 +382,8 @@ interrupts = <46 0>; interrupt-names = "gspi"; clocks = <&clock0 SIWX91X_CLK_GSPI>; + power-domains = <&siwx91x_soc_pd>; + zephyr,pm-device-runtime-auto; status = "disabled"; }; From ce24f75ce7de2863c4fb0f1b32231b8d7809f9d8 Mon Sep 17 00:00:00 2001 From: Zacck Osiemo Date: Sun, 17 Aug 2025 08:13:01 +0200 Subject: [PATCH 387/397] drivers: spi: Introduce SC18IS606 SPI bridge driver Added the driver implementation and Kconfig choices Signed-off-by: Zacck Osiemo --- drivers/spi/CMakeLists.txt | 1 + drivers/spi/Kconfig | 1 + drivers/spi/Kconfig.sc18is606 | 23 ++ drivers/spi/spi_sc18is606.c | 255 ++++++++++++++++++++++ drivers/spi/spi_sc18is606.h | 64 ++++++ dts/bindings/mfd/nxp,sc18is606.yaml | 33 +++ dts/bindings/spi/nxp,sc18is606-spi.yaml | 32 +++ tests/drivers/build_all/spi/app.overlay | 19 ++ tests/drivers/build_all/spi/testcase.yaml | 4 + 9 files changed, 432 insertions(+) create mode 100644 drivers/spi/Kconfig.sc18is606 create mode 100644 drivers/spi/spi_sc18is606.c create mode 100644 drivers/spi/spi_sc18is606.h create mode 100644 dts/bindings/mfd/nxp,sc18is606.yaml create mode 100644 dts/bindings/spi/nxp,sc18is606-spi.yaml create mode 100644 tests/drivers/build_all/spi/app.overlay diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 7171b93726f01..7425ace593281 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -60,6 +60,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_RPI_PICO_PIO spi_rpi_pico_pio.c) zephyr_library_sources_ifdef(CONFIG_SPI_RV32M1_LPSPI spi_rv32m1_lpspi.c) zephyr_library_sources_ifdef(CONFIG_SPI_SAM spi_sam.c) zephyr_library_sources_ifdef(CONFIG_SPI_SAM0 spi_sam0.c) +zephyr_library_sources_ifdef(CONFIG_SPI_SC18IS606 spi_sc18is606.c) zephyr_library_sources_ifdef(CONFIG_SPI_SEDI spi_sedi.c) zephyr_library_sources_ifdef(CONFIG_SPI_SIFIVE spi_sifive.c) zephyr_library_sources_ifdef(CONFIG_SPI_SILABS_EUSART spi_silabs_eusart.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a083f021c7533..301fdbbcb2ebb 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -122,6 +122,7 @@ source "drivers/spi/Kconfig.mec5" source "drivers/spi/Kconfig.npcx" source "drivers/spi/Kconfig.nrfx" source "drivers/spi/Kconfig.numaker" +source "drivers/spi/Kconfig.sc18is606" source "drivers/spi/Kconfig.nxp_s32" source "drivers/spi/Kconfig.oc_simple" source "drivers/spi/Kconfig.omap" diff --git a/drivers/spi/Kconfig.sc18is606 b/drivers/spi/Kconfig.sc18is606 new file mode 100644 index 0000000000000..09217d9a0b1ef --- /dev/null +++ b/drivers/spi/Kconfig.sc18is606 @@ -0,0 +1,23 @@ +#Copyright (c) 2025, tinyvision.ai +#SPDX-License-Indentifier: Apache 2.0 + +config SPI_SC18IS606 + bool "NXP SC18IS606 SPI controller driver" + default y + select I2C + depends on DT_HAS_NXP_SC18IS606_SPI_ENABLED + help + Enable driver for the NXP SC18IS606 SPI controller driver + +if SPI_SC18IS606 + + +config SPI_SC18IS606_INIT_PRIORITY + int "SC18IS606 SPI init priority" + default 59 + help + SC18IS606 SPI controller initialization priority + + Note: Has to be greater than the I2C initialization priority. + +endif diff --git a/drivers/spi/spi_sc18is606.c b/drivers/spi/spi_sc18is606.c new file mode 100644 index 0000000000000..0c78a8edc9a79 --- /dev/null +++ b/drivers/spi/spi_sc18is606.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2025, tinyvision.ai + * + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT nxp_sc18is606_spi + +#include +LOG_MODULE_REGISTER(spi_sc18is606, CONFIG_SPI_LOG_LEVEL); + + +#include +#include +#include +#include +#include +#include +#include "spi_context.h" + +#define SC18IS606_CONFIG_SPI 0xF0 +#define CLEAR_INTERRUPT 0xF1 +#define IDLE_MODE 0xF2 +#define READ_VERSION 0xFE + +#include "spi_sc18is606.h" + +struct nxp_sc18is606_data { + struct k_mutex bridge_lock; + struct spi_context ctx; + uint32_t spi_clock_freq; + uint8_t spi_mode; +}; + +struct nxp_sc18is606_config { + const struct i2c_dt_spec i2c_controller; +}; + +int nxp_sc18is606_claim(const struct device *dev) +{ + struct nxp_sc18is606_data *data = dev->data; + + return k_mutex_lock(&data->bridge_lock, K_FOREVER); +} + +int nxp_sc18is606_release(const struct device *dev) +{ + struct nxp_sc18is606_data *data = dev->data; + + return k_mutex_unlock(&data->bridge_lock); +} + + +int nxp_sc18is606_transfer(const struct device *dev, + const uint8_t *tx_data, uint8_t tx_len, + uint8_t *rx_data, uint8_t rx_len) +{ + struct nxp_sc18is606_data *data = dev->data; + const struct nxp_sc18is606_config *info = dev->config; + int ret; + + ret = k_mutex_lock(&data->bridge_lock, K_FOREVER); + if(ret < 0){ + return ret; + } + + if(tx_data != NULL) { + ret = i2c_write(info->i2c_controller.bus, tx_data, tx_len, info->i2c_controller.addr); + if (ret) { + LOG_ERR("SPI write failed: %d", ret); + return ret; + } + + } + + if(rx_data != NULL) { + /* What is the time */ + k_timepoint_t end; + + /*Set a deadline in a second*/ + end = sys_timepoint_calc(K_SECONDS(1)); + + do { + ret = i2c_read(info->i2c_controller.bus, rx_data, rx_len, info->i2c_controller.addr); + } while(ret == -1 && !sys_timepoint_expired(end)); /*Keep reading while in the deadline*/ + + /*If the read failed set ret to EAGAIN*/ + ret = ret == -1 ? -EAGAIN : ret; + + if(ret < 0) { + LOG_ERR("Failed to read data (%d)", ret); + } + } + + k_mutex_unlock(&data->bridge_lock); + + return ret; +} + +static int sc18is606_spi_configure(const struct device *dev, const struct spi_config *config) +{ + struct nxp_sc18is606_data *data = dev->data; + + if (config->operation & SPI_OP_MODE_SLAVE) { + LOG_ERR("SC18IS606 does not support Slave mode"); + return -ENOTSUP; + } + + if (config->operation & (SPI_LINES_DUAL | SPI_LINES_QUAD | SPI_LINES_OCTAL)) { + LOG_ERR("Unsupported line configuration"); + return -ENOTSUP; + } + + const int bits = SPI_WORD_SIZE_GET(config->operation); + + if (bits > 8) { + LOG_ERR("Word sizes > 8 bits not supported"); + return -ENOTSUP; + } + + /* Build SC18IS606 configuration byte*/ + uint8_t ret = 0; + + ret |= ((config->operation & SPI_TRANSFER_LSB) >> 4) << 5; + + uint8_t mode = (SPI_MODE_GET(config->operation) >> 1) & 0x3; + + ret |= (mode << 2); + + uint8_t freq; + if(config->frequency >= 1800000) freq = 0b00; + else if(config->frequency >= 400000) freq = 0b01; + else if(config->frequency >= 100000) freq = 0b10; + else freq = 0b11; + + ret |= freq; + + data->ctx.config = config; + + uint8_t buffer[2] = {SC18IS606_CONFIG_SPI, ret}; + + ret = nxp_sc18is606_transfer(dev, buffer, sizeof(buffer), NULL, 0); + + return ret; +} + +static int sc18is606_spi_transceive(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_buffer_set, + const struct spi_buf_set *rx_buffer_set) +{ + int ret = 1; + int reconfig = 1; + + reconfig = sc18is606_spi_configure(dev, spi_cfg); + if (reconfig < 0) { + return reconfig; + } + + if (!tx_buffer_set && !rx_buffer_set) { + LOG_ERR("SC18IS606 at least one buffer_set should be set \n"); + return -EINVAL; + } + + /* CS line to be Used */ + uint8_t ss_idx = spi_cfg->slave; + if (ss_idx > 2) { + LOG_ERR("SC18IS606: Invalid SS Index (%u) must be 0-2", ss_idx); + return -EINVAL; + } + + uint8_t function_id = (1 << ss_idx) & 0x07; + + if (tx_buffer_set && tx_buffer_set->buffers && tx_buffer_set->count > 0) { + for (size_t i = 0; i < tx_buffer_set->count; i++){ + const struct spi_buf *tx_buf = &tx_buffer_set->buffers[i]; + const size_t len = tx_buf->len; + + uint8_t sc18_buf[1 + len]; + sc18_buf[0] = function_id; + memcpy(&sc18_buf[1], tx_buf->buf, len); + + ret = nxp_sc18is606_transfer(dev, sc18_buf, sizeof(sc18_buf), NULL, 0); + } + } + + if (rx_buffer_set && rx_buffer_set->buffers && rx_buffer_set->count > 0) { + for(size_t i = 0; i < rx_buffer_set->count; i++){ + /* Function ID first to select the device */ + uint8_t cmd_buf[1] = {function_id}; + const struct spi_buf *rx_buf = &rx_buffer_set->buffers[i]; + ret = nxp_sc18is606_transfer(dev, cmd_buf, sizeof(cmd_buf), rx_buf->buf, rx_buf->len); + } + } + + return ret; +} + +int sc18is606_spi_release(const struct device *dev, const struct spi_config *config) +{ + struct nxp_sc18is606_data *data = dev->data; + + struct spi_context *ctx = &data->ctx; + + spi_context_unlock_unconditionally(ctx); + + return 0; +} + +static DEVICE_API(spi, sc18is606_api) = { + .transceive = sc18is606_spi_transceive, + .release = sc18is606_spi_release, +}; + +static int sc18is606_init(const struct device *dev) +{ + const struct nxp_sc18is606_config *cfg = dev->config; + struct nxp_sc18is606_data *data = dev->data; + int ret; + + struct spi_config my_config = { + .frequency = data->spi_clock_freq, + .operation = data->spi_mode, + .slave = data->spi_mode, + }; + + + if (!device_is_ready(cfg->i2c_controller.bus)) { + LOG_ERR("I2C controller %s not found", cfg->i2c_controller.bus->name); + return -ENODEV; + } + + LOG_INF("Using I2C controller: %s", cfg->i2c_controller.bus->name); + + ret = sc18is606_spi_configure(dev, &my_config); + if (ret) { + LOG_ERR("Failed to CONFIGURE the SC18IS606: %d", ret); + return ret; + } + + LOG_INF("SC18IS606 initialized"); + return 0; +} + +#define SPI_SC18IS606_DEFINE(inst) \ + static struct nxp_sc18is606_data sc18is606_data_##inst = { \ + .spi_clock_freq = DT_INST_PROP(inst, spi_clock_frequency), \ + .spi_mode = DT_INST_PROP(inst, spi_mode), \ + }; \ + static const struct nxp_sc18is606_config sc18is606_config_##inst = { \ + .i2c_controller = I2C_DT_SPEC_GET(DT_PARENT(DT_DRV_INST(inst))), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, sc18is606_init, NULL, &sc18is606_data_##inst, \ + &sc18is606_config_##inst, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ + &sc18is606_api); + +DT_INST_FOREACH_STATUS_OKAY(SPI_SC18IS606_DEFINE) diff --git a/drivers/spi/spi_sc18is606.h b/drivers/spi/spi_sc18is606.h new file mode 100644 index 0000000000000..877e8ede570fe --- /dev/null +++ b/drivers/spi/spi_sc18is606.h @@ -0,0 +1,64 @@ +/* + * Copyright (c), 2025 tinyvision.ai Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_I2C_SPI_SC18IS606_H_ +#define ZEPHYR_DRIVERS_I2C_SPI_SC18IS606_H_ + + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* @brief Claim the the SC18IS606 bridge + * + * @warning After calling this routine, the device cannot be used by any other thread + * until the calling bridge releases it with the counterpart function of this. + * + * @param dev SC18IS606 device + * @retval 0 Device is claimed + * @retval -EBUSY The device cannnot be claimed + */ +int nxp_sc18is606_claim(const struct device *dev); + +/* @brief Release the SC18IS606 bridge + * + * @warning this routine can only be called once a device has been locked + * + * @param dev SC18IS606 bridge + * + * @retval 0 Device is released + * @retval -EPERM The current thread has not claimed this so cannot release it + * @retval -EINVAL The device has no locks on it. + */ +int nxp_sc18is606_release(const struct device *dev); + +/* @brief Transfer data using I2C to or from the bridge + * + * This routine implements the synchronization between the spi controller and gpio cntroller + * + * @param dev SC18IS606 bridge + * @param tx_data Data to be sent out + * @param tx_len Tx Data length + * @param rx_data Container to recieve data + * @param rx_let size of expected receipt + * @param function_id function id to be used, use NULL if none is needed ( for register writes) + * + * @retval 0 Tranfer success + * @retvak -EAGAIN device did not complete and needs another turn + */ +int nxp_sc18is606_transfer(const struct device *dev, + const uint8_t *tx_data, uint8_t tx_len, + uint8_t *rx_data, uint8_t rx_len); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dts/bindings/mfd/nxp,sc18is606.yaml b/dts/bindings/mfd/nxp,sc18is606.yaml new file mode 100644 index 0000000000000..33ff5a33d5d42 --- /dev/null +++ b/dts/bindings/mfd/nxp,sc18is606.yaml @@ -0,0 +1,33 @@ +description: | + NXP SC18IS606 I2C to SPI/GPIO bridge. + + The SC18IS606 is supports both an external SPI and GPIO controller. + These controllers have to be added to the Device Tree as children, While + the device itself has to be a child of a I2C controller. + + An example configuration: + + &i2c0 { + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; + + sc18is606: sc18is606 { + compatible ="nxp, sc18is606"; + status = "okay"; + + + spi_ext: sc18is606_spi { + compatible = "nxp,sc18is606-spi"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + +compatible: "nxp,sc18is606" +include: i2c-device.yaml + +bus: nxp,sc18is606 diff --git a/dts/bindings/spi/nxp,sc18is606-spi.yaml b/dts/bindings/spi/nxp,sc18is606-spi.yaml new file mode 100644 index 0000000000000..a009db3d9c25f --- /dev/null +++ b/dts/bindings/spi/nxp,sc18is606-spi.yaml @@ -0,0 +1,32 @@ +description: | + SC18IS60S6 I2C to SPI Bridge with Selectable GPIOs + +compatible: "nxp,sc18is606-spi" +include: spi-controller.yaml +properties: + spi-clock-frequency: + type: int + required: false + default: 1875000 + enum: + - 1875000 + - 455000 + - 115000 + - 58000 + + description: SPI Clock frequency in Hz + + spi-mode: + type: int + required: false + default: 0 + enum: + - 0 + - 1 + - 2 + - 3 + + description: SPI mode CPOL and CPHA combination + + +on-bus: nxp,sc18is606 diff --git a/tests/drivers/build_all/spi/app.overlay b/tests/drivers/build_all/spi/app.overlay new file mode 100644 index 0000000000000..df28ac5432ab0 --- /dev/null +++ b/tests/drivers/build_all/spi/app.overlay @@ -0,0 +1,19 @@ +/* +* Copyright (c) 2025 tinyvision.ai +* +* SPDX-License-Identifier: Apache-2.0 +* +*/ + + + &i2c0: { + status = "okay"; + sc18is606: sc18is606@28 { + compatible = "nxp,sc18is606"; + reg = <0x28>; + status = "okay"; + #size-cells = <0>; + #address-cells = <1>; + clock-frequency = <100000>; + }; + }; diff --git a/tests/drivers/build_all/spi/testcase.yaml b/tests/drivers/build_all/spi/testcase.yaml index 5b275c69f1c2a..35f6b89341c35 100644 --- a/tests/drivers/build_all/spi/testcase.yaml +++ b/tests/drivers/build_all/spi/testcase.yaml @@ -5,6 +5,10 @@ common: - spi tests: drivers.spi.build: + # will cover drivers i2c based drivers + platform_allow: native_sim + tags: spi_nxp_sc18is606 + extra_args: "CONFIG_GPIO=y" # will cover drivers without in-tree boards platform_allow: qemu_cortex_m3 tags: spi_cdns From 78b2726971f9f089045f4344d1356d5a9d516b7f Mon Sep 17 00:00:00 2001 From: Zacck Osiemo Date: Sun, 17 Aug 2025 08:13:24 +0200 Subject: [PATCH 388/397] tests: spi: include correct overlay for sc18is606 Apply correct device tree overlay is applied for SC18IS606 Signed-off-by: Zacck Osiemo --- drivers/spi/Kconfig | 2 +- drivers/spi/Kconfig.sc18is606 | 5 +- drivers/spi/spi_sc18is606.c | 244 ++++++++++++++++------ drivers/spi/spi_sc18is606.h | 28 ++- dts/bindings/mfd/nxp,sc18is606.yaml | 24 ++- dts/bindings/spi/nxp,sc18is606-spi.yaml | 18 +- tests/drivers/build_all/mfd/app.overlay | 22 ++ tests/drivers/build_all/spi/app.overlay | 26 ++- tests/drivers/build_all/spi/testcase.yaml | 6 +- 9 files changed, 263 insertions(+), 112 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 301fdbbcb2ebb..d97de01b04f52 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -122,7 +122,6 @@ source "drivers/spi/Kconfig.mec5" source "drivers/spi/Kconfig.npcx" source "drivers/spi/Kconfig.nrfx" source "drivers/spi/Kconfig.numaker" -source "drivers/spi/Kconfig.sc18is606" source "drivers/spi/Kconfig.nxp_s32" source "drivers/spi/Kconfig.oc_simple" source "drivers/spi/Kconfig.omap" @@ -138,6 +137,7 @@ source "drivers/spi/Kconfig.rpi_pico" source "drivers/spi/Kconfig.rv32m1_lpspi" source "drivers/spi/Kconfig.sam" source "drivers/spi/Kconfig.sam0" +source "drivers/spi/Kconfig.sc18is606" source "drivers/spi/Kconfig.sedi" source "drivers/spi/Kconfig.sifive" source "drivers/spi/Kconfig.silabs_eusart" diff --git a/drivers/spi/Kconfig.sc18is606 b/drivers/spi/Kconfig.sc18is606 index 09217d9a0b1ef..acf2790a5afaf 100644 --- a/drivers/spi/Kconfig.sc18is606 +++ b/drivers/spi/Kconfig.sc18is606 @@ -1,5 +1,5 @@ -#Copyright (c) 2025, tinyvision.ai -#SPDX-License-Indentifier: Apache 2.0 +# Copyright (c) 2025, tinyvision.ai +# SPDX-License-Identifier: Apache-2.0 config SPI_SC18IS606 bool "NXP SC18IS606 SPI controller driver" @@ -11,7 +11,6 @@ config SPI_SC18IS606 if SPI_SC18IS606 - config SPI_SC18IS606_INIT_PRIORITY int "SC18IS606 SPI init priority" default 59 diff --git a/drivers/spi/spi_sc18is606.c b/drivers/spi/spi_sc18is606.c index 0c78a8edc9a79..327a222bf4db2 100644 --- a/drivers/spi/spi_sc18is606.c +++ b/drivers/spi/spi_sc18is606.c @@ -3,36 +3,44 @@ * * SPDX-License-Identifier: Apache-2.0 */ + #define DT_DRV_COMPAT nxp_sc18is606_spi #include LOG_MODULE_REGISTER(spi_sc18is606, CONFIG_SPI_LOG_LEVEL); - #include #include #include #include +#include #include #include +#include #include "spi_context.h" #define SC18IS606_CONFIG_SPI 0xF0 #define CLEAR_INTERRUPT 0xF1 #define IDLE_MODE 0xF2 -#define READ_VERSION 0xFE +#define SC18IS606_LSB_MASK GENMASK(5, 5) +#define SC18IS606_MODE_MASK GENMASK(3, 2) +#define SC18IS606_FREQ_MASK GENMASK(1, 0) #include "spi_sc18is606.h" struct nxp_sc18is606_data { struct k_mutex bridge_lock; struct spi_context ctx; - uint32_t spi_clock_freq; + uint8_t frequency_idx; uint8_t spi_mode; + struct gpio_callback int_cb; + struct k_sem int_sem; }; struct nxp_sc18is606_config { const struct i2c_dt_spec i2c_controller; + const struct gpio_dt_spec reset_gpios; + const struct gpio_dt_spec int_gpios; }; int nxp_sc18is606_claim(const struct device *dev) @@ -49,63 +57,98 @@ int nxp_sc18is606_release(const struct device *dev) return k_mutex_unlock(&data->bridge_lock); } - -int nxp_sc18is606_transfer(const struct device *dev, - const uint8_t *tx_data, uint8_t tx_len, - uint8_t *rx_data, uint8_t rx_len) +int nxp_sc18is606_transfer(const struct device *dev, const uint8_t *tx_data, uint8_t tx_len, + uint8_t *rx_data, uint8_t rx_len, uint8_t *id_buf) { struct nxp_sc18is606_data *data = dev->data; const struct nxp_sc18is606_config *info = dev->config; int ret; ret = k_mutex_lock(&data->bridge_lock, K_FOREVER); - if(ret < 0){ + if (ret < 0) { return ret; } - if(tx_data != NULL) { - ret = i2c_write(info->i2c_controller.bus, tx_data, tx_len, info->i2c_controller.addr); - if (ret) { + if (tx_data != NULL) { + if (id_buf != NULL) { + struct i2c_msg tx_msg[2] = { + { + .buf = id_buf, + .len = 1, + .flags = I2C_MSG_WRITE, + }, + { + .buf = (uint8_t *)tx_data, + .len = tx_len, + .flags = I2C_MSG_WRITE, + }, + }; + + ret = i2c_transfer_dt(&info->i2c_controller, tx_msg, 2); + } else { + struct i2c_msg tx_msg[1] = {{ + .buf = (uint8_t *)tx_data, + .len = tx_len, + .flags = I2C_MSG_WRITE, + }}; + + ret = i2c_transfer_dt(&info->i2c_controller, tx_msg, 1); + } + + if (ret != 0) { LOG_ERR("SPI write failed: %d", ret); - return ret; + goto out; } + } + /*If interrupt pin is used wait before next transaction*/ + if (info->int_gpios.port) { + ret = k_sem_take(&data->int_sem, K_MSEC(5)); + if (ret != 0) { + LOG_WRN("Interrupt semaphore timedout, proceeding with read"); + } } - if(rx_data != NULL) { - /* What is the time */ + if (rx_data != NULL) { + /*What is the time*/ k_timepoint_t end; /*Set a deadline in a second*/ - end = sys_timepoint_calc(K_SECONDS(1)); + end = sys_timepoint_calc(K_MSEC(1)); do { - ret = i2c_read(info->i2c_controller.bus, rx_data, rx_len, info->i2c_controller.addr); - } while(ret == -1 && !sys_timepoint_expired(end)); /*Keep reading while in the deadline*/ - - /*If the read failed set ret to EAGAIN*/ - ret = ret == -1 ? -EAGAIN : ret; - - if(ret < 0) { + ret = i2c_read(info->i2c_controller.bus, rx_data, rx_len, + info->i2c_controller.addr); + if (ret >= 0) { + break; + } + } while (!sys_timepoint_expired(end)); /*Keep reading while in the deadline*/ + + if (ret < 0) { LOG_ERR("Failed to read data (%d)", ret); + goto out; } } - k_mutex_unlock(&data->bridge_lock); + ret = 0; +out: + k_mutex_unlock(&data->bridge_lock); return ret; } static int sc18is606_spi_configure(const struct device *dev, const struct spi_config *config) { struct nxp_sc18is606_data *data = dev->data; + uint8_t cfg_byte = 0; + uint8_t buffer[2]; - if (config->operation & SPI_OP_MODE_SLAVE) { + if ((config->operation & SPI_OP_MODE_SLAVE) != 0U) { LOG_ERR("SC18IS606 does not support Slave mode"); return -ENOTSUP; } - if (config->operation & (SPI_LINES_DUAL | SPI_LINES_QUAD | SPI_LINES_OCTAL)) { + if ((config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { LOG_ERR("Unsupported line configuration"); return -ENOTSUP; } @@ -118,50 +161,40 @@ static int sc18is606_spi_configure(const struct device *dev, const struct spi_co } /* Build SC18IS606 configuration byte*/ - uint8_t ret = 0; + cfg_byte |= FIELD_PREP(SC18IS606_LSB_MASK, (config->operation & SPI_TRANSFER_LSB) >> 4); - ret |= ((config->operation & SPI_TRANSFER_LSB) >> 4) << 5; + cfg_byte |= FIELD_PREP(SC18IS606_MODE_MASK, (SPI_MODE_GET(config->operation) >> 1)); - uint8_t mode = (SPI_MODE_GET(config->operation) >> 1) & 0x3; - - ret |= (mode << 2); - - uint8_t freq; - if(config->frequency >= 1800000) freq = 0b00; - else if(config->frequency >= 400000) freq = 0b01; - else if(config->frequency >= 100000) freq = 0b10; - else freq = 0b11; - - ret |= freq; + cfg_byte |= FIELD_PREP(SC18IS606_FREQ_MASK, config->frequency); data->ctx.config = config; - uint8_t buffer[2] = {SC18IS606_CONFIG_SPI, ret}; - - ret = nxp_sc18is606_transfer(dev, buffer, sizeof(buffer), NULL, 0); + buffer[0] = SC18IS606_CONFIG_SPI; + buffer[1] = cfg_byte; + cfg_byte |= ((config->operation & SPI_TRANSFER_LSB) >> 4) << 5; - return ret; + return nxp_sc18is606_transfer(dev, buffer, sizeof(buffer), NULL, 0, NULL); } static int sc18is606_spi_transceive(const struct device *dev, const struct spi_config *spi_cfg, const struct spi_buf_set *tx_buffer_set, const struct spi_buf_set *rx_buffer_set) { - int ret = 1; - int reconfig = 1; + int ret; - reconfig = sc18is606_spi_configure(dev, spi_cfg); - if (reconfig < 0) { - return reconfig; + ret = sc18is606_spi_configure(dev, spi_cfg); + if (ret < 0) { + return ret; } if (!tx_buffer_set && !rx_buffer_set) { - LOG_ERR("SC18IS606 at least one buffer_set should be set \n"); + LOG_ERR("SC18IS606 at least one buffer_set should be set"); return -EINVAL; } /* CS line to be Used */ uint8_t ss_idx = spi_cfg->slave; + if (ss_idx > 2) { LOG_ERR("SC18IS606: Invalid SS Index (%u) must be 0-2", ss_idx); return -EINVAL; @@ -170,24 +203,36 @@ static int sc18is606_spi_transceive(const struct device *dev, const struct spi_c uint8_t function_id = (1 << ss_idx) & 0x07; if (tx_buffer_set && tx_buffer_set->buffers && tx_buffer_set->count > 0) { - for (size_t i = 0; i < tx_buffer_set->count; i++){ + for (size_t i = 0; i < tx_buffer_set->count; i++) { const struct spi_buf *tx_buf = &tx_buffer_set->buffers[i]; - const size_t len = tx_buf->len; - uint8_t sc18_buf[1 + len]; - sc18_buf[0] = function_id; - memcpy(&sc18_buf[1], tx_buf->buf, len); + uint8_t id_buf[1] = {function_id}; - ret = nxp_sc18is606_transfer(dev, sc18_buf, sizeof(sc18_buf), NULL, 0); + ret = nxp_sc18is606_transfer(dev, tx_buf->buf, tx_buf->len, NULL, 0, + id_buf); + if (ret < 0) { + LOG_ERR("SC18IS606: TX of size: %d failed %s", tx_buf->len, + dev->name); + return ret; + } } } if (rx_buffer_set && rx_buffer_set->buffers && rx_buffer_set->count > 0) { - for(size_t i = 0; i < rx_buffer_set->count; i++){ + for (size_t i = 0; i < rx_buffer_set->count; i++) { /* Function ID first to select the device */ uint8_t cmd_buf[1] = {function_id}; + const struct spi_buf *rx_buf = &rx_buffer_set->buffers[i]; - ret = nxp_sc18is606_transfer(dev, cmd_buf, sizeof(cmd_buf), rx_buf->buf, rx_buf->len); + + ret = nxp_sc18is606_transfer(dev, cmd_buf, sizeof(cmd_buf), rx_buf->buf, + rx_buf->len, NULL); + + if (ret < 0) { + LOG_ERR("SC18IS606: RX of size: %d failed on (%s)", rx_buf->len, + dev->name); + return ret; + } } } @@ -210,6 +255,53 @@ static DEVICE_API(spi, sc18is606_api) = { .release = sc18is606_spi_release, }; +static void sc18is606_int_isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + struct nxp_sc18is606_data *data = CONTAINER_OF(cb, struct nxp_sc18is606_data, int_cb); + + k_sem_give(&data->int_sem); +} + +static int int_gpios_setup(const struct device *dev) +{ + struct nxp_sc18is606_data *data = dev->data; + const struct nxp_sc18is606_config *cfg = dev->config; + int ret; + + if (!gpio_is_ready_dt(&cfg->int_gpios)) { + LOG_ERR("SC18IS606 Int GPIO not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&cfg->int_gpios, GPIO_INPUT); + if (ret != 0U) { + LOG_ERR("Failed to configure SC18IS606 int gpio (%d)", ret); + return ret; + } + + ret = k_sem_init(&data->int_sem, 0, 1); + if (ret != 0U) { + LOG_ERR("Failed to Initialize Interrupt Semaphore (%d)", ret); + return ret; + } + + gpio_init_callback(&data->int_cb, sc18is606_int_isr, BIT(cfg->int_gpios.pin)); + + ret = gpio_add_callback(cfg->int_gpios.port, &data->int_cb); + if (ret != 0U) { + LOG_ERR("Failed to assign the Interrupt callback (%d)", ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->int_gpios, GPIO_INT_EDGE_TO_ACTIVE); + if (ret != 0U) { + LOG_ERR("Failed to configure the GPIO interrupt edge (%d)", ret); + return ret; + } + + return ret; +} + static int sc18is606_init(const struct device *dev) { const struct nxp_sc18is606_config *cfg = dev->config; @@ -217,12 +309,11 @@ static int sc18is606_init(const struct device *dev) int ret; struct spi_config my_config = { - .frequency = data->spi_clock_freq, + .frequency = data->frequency_idx, .operation = data->spi_mode, - .slave = data->spi_mode, + .slave = 0, }; - if (!device_is_ready(cfg->i2c_controller.bus)) { LOG_ERR("I2C controller %s not found", cfg->i2c_controller.bus->name); return -ENODEV; @@ -230,24 +321,53 @@ static int sc18is606_init(const struct device *dev) LOG_INF("Using I2C controller: %s", cfg->i2c_controller.bus->name); - ret = sc18is606_spi_configure(dev, &my_config); - if (ret) { + ret = sc18is606_spi_configure(dev, &my_config); + if (ret != 0) { LOG_ERR("Failed to CONFIGURE the SC18IS606: %d", ret); return ret; } + if (cfg->reset_gpios.port) { + if (!gpio_is_ready_dt(&cfg->reset_gpios)) { + LOG_ERR("SC18IS606 Reset GPIO not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&cfg->reset_gpios, GPIO_OUTPUT_ACTIVE); + if (ret != 0U) { + LOG_ERR("Failed to configure SC18IS606 reset GPIO (%d)", ret); + return ret; + } + + ret = gpio_pin_set_dt(&cfg->reset_gpios, 0); + if (ret != 0U) { + LOG_ERR("Failed to reset Bridge via Reset pin (%d)", ret); + return ret; + } + } + + if (cfg->int_gpios.port) { + ret = int_gpios_setup(dev); + if (ret != 0U) { + LOG_ERR("Could not set up device int_gpios (%d)", ret); + return ret; + } + } LOG_INF("SC18IS606 initialized"); return 0; } #define SPI_SC18IS606_DEFINE(inst) \ static struct nxp_sc18is606_data sc18is606_data_##inst = { \ - .spi_clock_freq = DT_INST_PROP(inst, spi_clock_frequency), \ + .frequency_idx = DT_INST_ENUM_IDX(inst, frequency), \ .spi_mode = DT_INST_PROP(inst, spi_mode), \ }; \ static const struct nxp_sc18is606_config sc18is606_config_##inst = { \ .i2c_controller = I2C_DT_SPEC_GET(DT_PARENT(DT_DRV_INST(inst))), \ + .reset_gpios = GPIO_DT_SPEC_GET_OR(DT_INST_PARENT(inst), reset_gpios, {0}), \ + .int_gpios = GPIO_DT_SPEC_GET_OR(DT_INST_PARENT(inst), int_gpios, {0}), \ }; \ + \ DEVICE_DT_INST_DEFINE(inst, sc18is606_init, NULL, &sc18is606_data_##inst, \ &sc18is606_config_##inst, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ &sc18is606_api); diff --git a/drivers/spi/spi_sc18is606.h b/drivers/spi/spi_sc18is606.h index 877e8ede570fe..b3a0302feb7ef 100644 --- a/drivers/spi/spi_sc18is606.h +++ b/drivers/spi/spi_sc18is606.h @@ -7,22 +7,20 @@ #ifndef ZEPHYR_DRIVERS_I2C_SPI_SC18IS606_H_ #define ZEPHYR_DRIVERS_I2C_SPI_SC18IS606_H_ - - #include #ifdef __cplusplus extern "C" { #endif -/* @brief Claim the the SC18IS606 bridge +/* @brief Claim the SC18IS606 bridge * * @warning After calling this routine, the device cannot be used by any other thread * until the calling bridge releases it with the counterpart function of this. * * @param dev SC18IS606 device * @retval 0 Device is claimed - * @retval -EBUSY The device cannnot be claimed + * @retval -EBUSY The device cannot be claimed */ int nxp_sc18is606_claim(const struct device *dev); @@ -33,29 +31,27 @@ int nxp_sc18is606_claim(const struct device *dev); * @param dev SC18IS606 bridge * * @retval 0 Device is released - * @retval -EPERM The current thread has not claimed this so cannot release it * @retval -EINVAL The device has no locks on it. */ -int nxp_sc18is606_release(const struct device *dev); +int nxp_sc18is606_release(const struct device *dev); /* @brief Transfer data using I2C to or from the bridge * - * This routine implements the synchronization between the spi controller and gpio cntroller + * This routine implements the synchronization between the SPI controller and GPIO cntroller * * @param dev SC18IS606 bridge * @param tx_data Data to be sent out * @param tx_len Tx Data length - * @param rx_data Container to recieve data - * @param rx_let size of expected receipt - * @param function_id function id to be used, use NULL if none is needed ( for register writes) + * @param rx_data Container to receive data + * @param rx_len size of expected receipt + * @param id_buf Function id data if used * - * @retval 0 Tranfer success - * @retvak -EAGAIN device did not complete and needs another turn + * @retval 0 Transfer success + * @retval -EAGAIN device lock timed out + * @retval -EBUSY device already locked */ -int nxp_sc18is606_transfer(const struct device *dev, - const uint8_t *tx_data, uint8_t tx_len, - uint8_t *rx_data, uint8_t rx_len); - +int nxp_sc18is606_transfer(const struct device *dev, const uint8_t *tx_data, uint8_t tx_len, + uint8_t *rx_data, uint8_t rx_len, uint8_t *id_buf); #ifdef __cplusplus } diff --git a/dts/bindings/mfd/nxp,sc18is606.yaml b/dts/bindings/mfd/nxp,sc18is606.yaml index 33ff5a33d5d42..5f0e75cd9cbed 100644 --- a/dts/bindings/mfd/nxp,sc18is606.yaml +++ b/dts/bindings/mfd/nxp,sc18is606.yaml @@ -1,9 +1,10 @@ description: | NXP SC18IS606 I2C to SPI/GPIO bridge. - The SC18IS606 is supports both an external SPI and GPIO controller. - These controllers have to be added to the Device Tree as children, While + The SC18IS606 supports both an external SPI and GPIO controller. + These controllers have to be added to the Device Tree as children, while the device itself has to be a child of a I2C controller. + Do note that this device only supports 3 SPI devices on the bus. An example configuration: @@ -13,7 +14,7 @@ description: | pinctrl-names = "default"; sc18is606: sc18is606 { - compatible ="nxp, sc18is606"; + compatible = "nxp,sc18is606"; status = "okay"; @@ -26,8 +27,23 @@ description: | }; }; - compatible: "nxp,sc18is606" include: i2c-device.yaml +properties: + reset-gpios: + type: phandle-array + description: + Driver reset pin of the bridge. + If connected directly to the MCU, this pin should be configured + as active low. + + int-gpios: + type: phandle-array + description: + Driver interrupt pin of the bridge, this allows the driver to ensure + that SPI transactions are done before allowing other transactions. + If connected directly to the MCU, this pin should be configured + as active low. + bus: nxp,sc18is606 diff --git a/dts/bindings/spi/nxp,sc18is606-spi.yaml b/dts/bindings/spi/nxp,sc18is606-spi.yaml index a009db3d9c25f..4c28e17120510 100644 --- a/dts/bindings/spi/nxp,sc18is606-spi.yaml +++ b/dts/bindings/spi/nxp,sc18is606-spi.yaml @@ -1,24 +1,22 @@ description: | - SC18IS60S6 I2C to SPI Bridge with Selectable GPIOs + SPI device through NXP SC18IS606 I2C to SPI Bridge. compatible: "nxp,sc18is606-spi" include: spi-controller.yaml properties: - spi-clock-frequency: + frequency: type: int - required: false - default: 1875000 + default: 1875 enum: - - 1875000 - - 455000 - - 115000 - - 58000 + - 1875 + - 455 + - 115 + - 58 - description: SPI Clock frequency in Hz + description: SPI Clock frequency in KHz spi-mode: type: int - required: false default: 0 enum: - 0 diff --git a/tests/drivers/build_all/mfd/app.overlay b/tests/drivers/build_all/mfd/app.overlay index 92e4cd79c003f..4ac98d6bc661a 100644 --- a/tests/drivers/build_all/mfd/app.overlay +++ b/tests/drivers/build_all/mfd/app.overlay @@ -15,6 +15,28 @@ #address-cells = <1>; #size-cells = <1>; + test_i2c: i2c@33335555{ + status = "okay"; + compatible = "vnd,i2c"; + reg = <0x33335555 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + sc18is606: sc18is606@28 { + compatible ="nxp,sc18is606"; + status = "okay"; + reg = <0x28>; + + spi_ext: sc18is606_spi { + compatible = "nxp,sc18is606-spi"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + frequency = <1875>; + }; + }; + }; + test_uart: uart@55556666 { compatible = "vnd,serial"; reg = <0x55556666 0x1000>; diff --git a/tests/drivers/build_all/spi/app.overlay b/tests/drivers/build_all/spi/app.overlay index df28ac5432ab0..c55ca99a981a7 100644 --- a/tests/drivers/build_all/spi/app.overlay +++ b/tests/drivers/build_all/spi/app.overlay @@ -1,19 +1,23 @@ /* -* Copyright (c) 2025 tinyvision.ai -* -* SPDX-License-Identifier: Apache-2.0 -* -*/ + * Copyright (c) 2025 tinyvision.ai + * + * SPDX-License-Identifier: Apache-2.0 + */ +&i2c0{ + status = "okay"; - &i2c0: { + sc18is606: sc18is606@28 { + compatible ="nxp,sc18is606"; status = "okay"; - sc18is606: sc18is606@28 { - compatible = "nxp,sc18is606"; - reg = <0x28>; + reg = <0x28>; + + spi_ext: sc18is606_spi { + compatible = "nxp,sc18is606-spi"; status = "okay"; - #size-cells = <0>; #address-cells = <1>; - clock-frequency = <100000>; + #size-cells = <0>; + frequency = <0>; }; }; +}; diff --git a/tests/drivers/build_all/spi/testcase.yaml b/tests/drivers/build_all/spi/testcase.yaml index 35f6b89341c35..ce1d8c3a8b5d4 100644 --- a/tests/drivers/build_all/spi/testcase.yaml +++ b/tests/drivers/build_all/spi/testcase.yaml @@ -4,11 +4,7 @@ common: - drivers - spi tests: - drivers.spi.build: - # will cover drivers i2c based drivers - platform_allow: native_sim - tags: spi_nxp_sc18is606 - extra_args: "CONFIG_GPIO=y" + drivers.spi.build.spi_cdns: # will cover drivers without in-tree boards platform_allow: qemu_cortex_m3 tags: spi_cdns From c231eaaf242204f343e6fb95f84dedb0d835e459 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 23 Oct 2024 20:01:39 +0300 Subject: [PATCH 389/397] drivers: counter: cc23x0: Add power management to RTC Add PM support for RTC to cc23x0 SoC. Signed-off-by: Stoyan Bogdanov --- drivers/counter/counter_cc23x0_rtc.c | 51 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/counter/counter_cc23x0_rtc.c b/drivers/counter/counter_cc23x0_rtc.c index 97085359d26bf..bf6c1e9869983 100644 --- a/drivers/counter/counter_cc23x0_rtc.c +++ b/drivers/counter/counter_cc23x0_rtc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -153,6 +154,23 @@ static uint32_t counter_cc23x0_get_pending_int(const struct device *dev) return -ESRCH; } +#ifdef CONFIG_PM_DEVICE + +static int rtc_cc23x0_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + return 0; + case PM_DEVICE_ACTION_RESUME: + counter_cc23x0_get_pending_int(dev); + return 0; + default: + return -ENOTSUP; + } +} + +#endif /* CONFIG_PM_DEVICE */ + static uint32_t counter_cc23x0_get_top_value(const struct device *dev) { ARG_UNUSED(dev); @@ -221,21 +239,22 @@ static DEVICE_API(counter, rtc_cc23x0_api) = { .get_freq = counter_cc23x0_get_freq, }; -#define CC23X0_INIT(inst) \ - static const struct counter_cc23x0_config cc23x0_config_##inst = { \ - .counter_info = \ - { \ - .max_top_value = UINT32_MAX, \ - .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ - .channels = 1, \ - }, \ - .base = DT_INST_REG_ADDR(inst), \ - }; \ - \ - static struct counter_cc23x0_data cc23x0_data_##inst; \ - \ - DEVICE_DT_INST_DEFINE(0, &counter_cc23x0_init, NULL, &cc23x0_data_##inst, \ - &cc23x0_config_##inst, POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ - &rtc_cc23x0_api); +#define CC23X0_INIT(inst) \ + PM_DEVICE_DT_INST_DEFINE(inst, rtc_cc23x0_pm_action); \ + \ + static const struct counter_cc23x0_config cc23x0_config_##inst = { \ + .counter_info = { \ + .max_top_value = UINT32_MAX, \ + .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ + .channels = 1, \ + }, \ + .base = DT_INST_REG_ADDR(inst), \ + }; \ + \ + static struct counter_cc23x0_data cc23x0_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(0, &counter_cc23x0_init, PM_DEVICE_DT_INST_GET(inst), \ + &cc23x0_data_##inst, &cc23x0_config_##inst, POST_KERNEL, \ + CONFIG_COUNTER_INIT_PRIORITY, &rtc_cc23x0_api); DT_INST_FOREACH_STATUS_OKAY(CC23X0_INIT) From dbe2fe9dc9f24a4d54878534796d8d1bef5c8f39 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Tue, 22 Oct 2024 18:00:24 +0300 Subject: [PATCH 390/397] drivers: counter: cc23x0: Add power management to LGPT Add PM support for LGPT0, LGPT1, LGPT2 and LGPT3 to cc23x0 SoC. Signed-off-by: Stoyan Bogdanov --- drivers/counter/counter_cc23x0_lgpt.c | 140 ++++++++++++++++++-------- 1 file changed, 99 insertions(+), 41 deletions(-) diff --git a/drivers/counter/counter_cc23x0_lgpt.c b/drivers/counter/counter_cc23x0_lgpt.c index 1534cc70ea668..3ba0f94349f75 100644 --- a/drivers/counter/counter_cc23x0_lgpt.c +++ b/drivers/counter/counter_cc23x0_lgpt.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -23,11 +25,14 @@ LOG_MODULE_REGISTER(counter_cc23x0_lgpt, CONFIG_COUNTER_LOG_LEVEL); +#define LGPT_CLK_PRESCALE(pres) (((pres) + 1) << 8) + static void counter_cc23x0_lgpt_isr(const struct device *dev); struct counter_cc23x0_lgpt_config { struct counter_config_info counter_info; uint32_t base; + uint32_t clk_idx; uint32_t prescale; }; @@ -36,6 +41,22 @@ struct counter_cc23x0_lgpt_data { struct counter_top_cfg target_cfg; }; +static inline void lgpt_cc23x0_pm_policy_state_lock_get(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +#endif +} + +static inline void lgpt_cc23x0_pm_policy_state_lock_put(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); +#endif +} + static int counter_cc23x0_lgpt_get_value(const struct device *dev, uint32_t *ticks) { const struct counter_cc23x0_lgpt_config *config = dev->config; @@ -221,6 +242,8 @@ static int counter_cc23x0_lgpt_start(const struct device *dev) { const struct counter_cc23x0_lgpt_config *config = dev->config; + lgpt_cc23x0_pm_policy_state_lock_get(); + LOG_DBG("[START] LGPT base[%x]\n", config->base); HWREG(config->base + LGPT_O_CTL) = LGPT_CTL_MODE_UP_PER; @@ -240,9 +263,41 @@ static int counter_cc23x0_lgpt_stop(const struct device *dev) /* Set to 0 to stop timer */ HWREG(config->base + LGPT_O_STARTCFG) = 0x0; + lgpt_cc23x0_pm_policy_state_lock_put(); + return 0; } +static void counter_cc23x0_lgpt_init_common(const struct device *dev) +{ + const struct counter_cc23x0_lgpt_config *config = dev->config; + + HWREG(config->base + LGPT_O_TGT) = config->counter_info.max_top_value; + HWREG(config->base + LGPT_O_PRECFG) = LGPT_CLK_PRESCALE(config->prescale); + HWREG(EVTSVT_BASE + EVTSVT_O_LGPTSYNCSEL) = EVTSVT_LGPTSYNCSEL_PUBID_SYSTIM0; +} + +#ifdef CONFIG_PM_DEVICE + +static int lgpt_cc23x0_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct counter_cc23x0_lgpt_config *config = dev->config; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + CLKCTLDisable(CLKCTL_BASE, config->clk_idx); + return 0; + case PM_DEVICE_ACTION_RESUME: + CLKCTLEnable(CLKCTL_BASE, config->clk_idx); + counter_cc23x0_lgpt_init_common(dev); + return 0; + default: + return -ENOTSUP; + } +} + +#endif /* CONFIG_PM_DEVICE */ + static DEVICE_API(counter, cc23x0_lgpt_api) = { .start = counter_cc23x0_lgpt_start, .stop = counter_cc23x0_lgpt_stop, @@ -255,48 +310,51 @@ static DEVICE_API(counter, cc23x0_lgpt_api) = { .get_freq = counter_cc23x0_lgpt_get_freq, }; -#define LGPT_CLK_PRESCALE(pres) ((pres + 1) << 8) - -#define LGPT_CC23X0_INIT_FUNC(inst) \ - static int counter_cc23x0_lgpt_init##inst(const struct device *dev) \ - { \ - const struct counter_cc23x0_lgpt_config *config = dev->config; \ - \ - CLKCTLEnable(CLKCTL_BASE, CLKCTL_LGPT##inst); \ - \ - IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \ - counter_cc23x0_lgpt_isr, DEVICE_DT_INST_GET(inst), 0); \ - \ - irq_enable(DT_INST_IRQN(inst)); \ - \ - HWREG(config->base + LGPT_O_TGT) = config->counter_info.max_top_value; \ - \ - HWREG(config->base + LGPT_O_PRECFG) = LGPT_CLK_PRESCALE(config->prescale); \ - \ - HWREG(EVTSVT_BASE + EVTSVT_O_LGPTSYNCSEL) = EVTSVT_LGPTSYNCSEL_PUBID_SYSTIM0; \ - \ - return 0; \ +#define LGPT_CC23X0_INIT_FUNC(inst) \ + static int counter_cc23x0_lgpt_init##inst(const struct device *dev) \ + { \ + const struct counter_cc23x0_lgpt_config *config = dev->config; \ + \ + CLKCTLEnable(CLKCTL_BASE, config->clk_idx); \ + \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), \ + counter_cc23x0_lgpt_isr, \ + DEVICE_DT_INST_GET(inst), \ + 0); \ + \ + irq_enable(DT_INST_IRQN(inst)); \ + \ + counter_cc23x0_lgpt_init_common(dev); \ + \ + return 0; \ } -#define CC23X0_LGPT_INIT(inst) \ - \ - LGPT_CC23X0_INIT_FUNC(inst); \ - \ - static const struct counter_cc23x0_lgpt_config cc23x0_lgpt_config_##inst = { \ - .counter_info = \ - { \ - .max_top_value = DT_INST_PROP(inst, max_top_value), \ - .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ - .channels = 3, \ - }, \ - .base = DT_INST_REG_ADDR(inst), \ - .prescale = DT_INST_PROP(inst, clk_prescale), \ - }; \ - \ - static struct counter_cc23x0_lgpt_data cc23x0_lgpt_data_##inst; \ - \ - DEVICE_DT_INST_DEFINE(inst, &counter_cc23x0_lgpt_init##inst, NULL, \ - &cc23x0_lgpt_data_##inst, &cc23x0_lgpt_config_##inst, POST_KERNEL, \ - CONFIG_COUNTER_INIT_PRIORITY, &cc23x0_lgpt_api); +#define CC23X0_LGPT_INIT(inst) \ + \ + LGPT_CC23X0_INIT_FUNC(inst); \ + PM_DEVICE_DT_INST_DEFINE(inst, lgpt_cc23x0_pm_action); \ + \ + static const struct counter_cc23x0_lgpt_config cc23x0_lgpt_config_##inst = { \ + .counter_info = { \ + .max_top_value = DT_INST_PROP(inst, max_top_value), \ + .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ + .channels = 3, \ + }, \ + .base = DT_INST_REG_ADDR(inst), \ + .clk_idx = CLKCTL_LGPT##inst, \ + .prescale = DT_INST_PROP(inst, clk_prescale), \ + }; \ + \ + static struct counter_cc23x0_lgpt_data cc23x0_lgpt_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, \ + &counter_cc23x0_lgpt_init##inst, \ + PM_DEVICE_DT_INST_GET(inst), \ + &cc23x0_lgpt_data_##inst, \ + &cc23x0_lgpt_config_##inst, \ + POST_KERNEL, \ + CONFIG_COUNTER_INIT_PRIORITY, \ + &cc23x0_lgpt_api); DT_INST_FOREACH_STATUS_OKAY(CC23X0_LGPT_INIT); From e971d6c406a9ac905c05224ceaf5834518362a1a Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Fri, 16 May 2025 22:50:14 +0200 Subject: [PATCH 391/397] drivers: sensor: add Vishay veml6046 RGBIR color sensor - add driver for Vishay VEML6046 RGBIR color sensor - add new compatible "vishay,veml6046" - support fetch and get sensor subsystem operations - triggered mode and interrupts are not yet supported Signed-off-by: Andreas Klinger --- drivers/sensor/vishay/CMakeLists.txt | 1 + drivers/sensor/vishay/Kconfig | 1 + drivers/sensor/vishay/veml6046/CMakeLists.txt | 5 + drivers/sensor/vishay/veml6046/Kconfig | 12 + drivers/sensor/vishay/veml6046/veml6046.c | 632 ++++++++++++++++++ dts/bindings/sensor/vishay,veml6046.yaml | 10 + include/zephyr/drivers/sensor/veml6046.h | 194 ++++++ tests/drivers/build_all/sensor/i2c.dtsi | 5 + 8 files changed, 860 insertions(+) create mode 100644 drivers/sensor/vishay/veml6046/CMakeLists.txt create mode 100644 drivers/sensor/vishay/veml6046/Kconfig create mode 100644 drivers/sensor/vishay/veml6046/veml6046.c create mode 100644 dts/bindings/sensor/vishay,veml6046.yaml create mode 100644 include/zephyr/drivers/sensor/veml6046.h diff --git a/drivers/sensor/vishay/CMakeLists.txt b/drivers/sensor/vishay/CMakeLists.txt index c0462dba8620d..56ff0b09bbaac 100644 --- a/drivers/sensor/vishay/CMakeLists.txt +++ b/drivers/sensor/vishay/CMakeLists.txt @@ -5,5 +5,6 @@ add_subdirectory_ifdef(CONFIG_VCNL36825T vcnl36825t) add_subdirectory_ifdef(CONFIG_VCNL4040 vcnl4040) add_subdirectory_ifdef(CONFIG_VEML6031 veml6031) +add_subdirectory_ifdef(CONFIG_VEML6046 veml6046) add_subdirectory_ifdef(CONFIG_VEML7700 veml7700) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/vishay/Kconfig b/drivers/sensor/vishay/Kconfig index 564a9740c9c8e..a203cadd9947b 100644 --- a/drivers/sensor/vishay/Kconfig +++ b/drivers/sensor/vishay/Kconfig @@ -5,5 +5,6 @@ source "drivers/sensor/vishay/vcnl36825t/Kconfig" source "drivers/sensor/vishay/vcnl4040/Kconfig" source "drivers/sensor/vishay/veml6031/Kconfig" +source "drivers/sensor/vishay/veml6046/Kconfig" source "drivers/sensor/vishay/veml7700/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/vishay/veml6046/CMakeLists.txt b/drivers/sensor/vishay/veml6046/CMakeLists.txt new file mode 100644 index 0000000000000..c31cfff011a18 --- /dev/null +++ b/drivers/sensor/vishay/veml6046/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Andreas Klinger +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(veml6046.c) diff --git a/drivers/sensor/vishay/veml6046/Kconfig b/drivers/sensor/vishay/veml6046/Kconfig new file mode 100644 index 0000000000000..06e057e07ec21 --- /dev/null +++ b/drivers/sensor/vishay/veml6046/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Andreas Klinger +# SPDX-License-Identifier: Apache-2.0 + +# Vishay VEML6046 RGBIR color sensor driver options. + +config VEML6046 + bool "Vishay VEML6046 RGBIR color sensor" + default y + depends on DT_HAS_VISHAY_VEML6046_ENABLED + select I2C + help + Enable Vishay VEML6046 RGBIR color sensor driver. diff --git a/drivers/sensor/vishay/veml6046/veml6046.c b/drivers/sensor/vishay/veml6046/veml6046.c new file mode 100644 index 0000000000000..9f0b54e1f27cd --- /dev/null +++ b/drivers/sensor/vishay/veml6046/veml6046.c @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2025 Andreas Klinger + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT vishay_veml6046 + +#include +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(VEML6046, CONFIG_SENSOR_LOG_LEVEL); + +/* + * ID code of device + */ +#define VEML6046_DEFAULT_ID 0x01 + +/* + * Bit mask to check for data ready in single measurement. + */ +#define VEML6046_AF_DATA_READY BIT(3) + +/* + * Maximum value of RGBIR data which also means that the sensor is in + * saturation and that the measured value might be wrong. + * In such a case the user program should reduce one or more of the following + * attributes to get a relyable value: + * gain + * integration time + * effective photodiode size divider + */ +#define VEML6046_DATA_OVERFLOW 0xFFFF + +/* + * 16-bit command register addresses + */ +#define VEML6046_CMDCODE_RGB_CONF_0 0x00 +#define VEML6046_CMDCODE_RGB_CONF_1 0x01 +#define VEML6046_CMDCODE_G_THDH_L 0x04 +#define VEML6046_CMDCODE_G_THDH_H 0x05 +#define VEML6046_CMDCODE_G_THDL_L 0x06 +#define VEML6046_CMDCODE_G_THDL_H 0x07 +#define VEML6046_CMDCODE_R_DATA_L 0x10 +#define VEML6046_CMDCODE_R_DATA_H 0x11 +#define VEML6046_CMDCODE_G_DATA_L 0x12 +#define VEML6046_CMDCODE_G_DATA_H 0x13 +#define VEML6046_CMDCODE_B_DATA_L 0x14 +#define VEML6046_CMDCODE_B_DATA_H 0x15 +#define VEML6046_CMDCODE_IR_DATA_L 0x16 +#define VEML6046_CMDCODE_IR_DATA_H 0x17 +#define VEML6046_CMDCODE_ID_L 0x18 +#define VEML6046_CMDCODE_ID_H 0x19 +#define VEML6046_CMDCODE_INT_L 0x1A +#define VEML6046_CMDCODE_INT_H 0x1B + +/* + * ALS integration time struct. + */ +struct veml6046_it_data { + enum veml6046_it num; + uint8_t val; + int us; +}; + +/* + * ALS integration time setting values. + * + * The enumerators of enum veml6046_it provide indices into this array to get + * the related value for the ALS_IT configuration bits. + */ +static const struct veml6046_it_data veml6046_it_values[VEML6046_IT_COUNT] = { + {VEML6046_IT_3_125, 0x00, 3125}, /* 3.125 - 0b0000 */ + {VEML6046_IT_6_25, 0x01, 6250}, /* 6.25 - 0b0001 */ + {VEML6046_IT_12_5, 0x02, 12500}, /* 12.5 - 0b0010 */ + {VEML6046_IT_25, 0x03, 25000}, /* 25 - 0b0011 */ + {VEML6046_IT_50, 0x04, 50000}, /* 50 - 0b0100 */ + {VEML6046_IT_100, 0x05, 100000}, /* 100 - 0b0101 */ + {VEML6046_IT_200, 0x06, 200000}, /* 200 - 0b0110 */ + {VEML6046_IT_400, 0x07, 400000}, /* 400 - 0b0111 */ +}; + +/* + * Resolution matrix for values to convert between data provided + * by the sensor ("counts") and lux. + * + * These values depend on the current size, gain and integration time settings. + * The enumerators of enum veml6046_pdd, enum veml6046_gain and enum + * veml6046_als_it are used for indices into this matrix. + */ +static const float + veml6046_resolution[VEML6046_PDD_COUNT][VEML6046_GAIN_COUNT][VEML6046_IT_COUNT] = { + /*3.125ms 6.25ms 12.5ms 25ms 50ms 100ms 200ms 400ms IT */ + /* size 2/2 */ + { + {1.3440f, 0.6720f, 0.3360f, 0.1680f, 0.0840f, 0.0420f, 0.0210f, + 0.0105f}, /* Gain 1 */ + {0.6720f, 0.3360f, 0.1680f, 0.0840f, 0.0420f, 0.0210f, 0.0105f, + 0.0053f}, /* Gain 2 */ + {2.0364f, 1.0182f, 0.5091f, 0.2545f, 0.1273f, 0.0636f, 0.0318f, + 0.0159f}, /* Gain 0.66 */ + {2.6880f, 1.3440f, 0.6720f, 0.3360f, 0.1680f, 0.0840f, 0.0420f, + 0.0210f}, /* Gain 0.5 */ + }, + { + /* size 1/2 */ + {2.6880f, 1.3440f, 0.6720f, 0.3360f, 0.1680f, 0.0840f, 0.0420f, + 0.0210f}, /* Gain 1 */ + {1.3440f, 0.6720f, 0.3360f, 0.1680f, 0.0840f, 0.0420f, 0.0210f, + 0.0105f}, /* Gain 2 */ + {4.0727f, 2.0364f, 1.0182f, 0.5091f, 0.2545f, 0.1273f, 0.0636f, + 0.0318f}, /* Gain 0.66 */ + {5.3760f, 2.6880f, 1.3440f, 0.6720f, 0.3360f, 0.1680f, 0.0840f, + 0.0420f}, /* Gain 0.5 */ + }, +}; + +struct veml6046_config { + struct i2c_dt_spec bus; +}; + +struct veml6046_data { + uint8_t sd; /* Band gap and LDO shutdown */ + uint8_t int_en; /* ALS interrupt enable */ + uint8_t trig; /* ALS active force trigger */ + enum veml6046_pdd pdd; /* effective photodiode size divider */ + enum veml6046_gain gain; /* gain selection */ + enum veml6046_it itim; /* ALS integration time */ + enum veml6046_pers pers; /* ALS persistens protect */ + uint16_t thresh_high; + uint16_t thresh_low; + uint16_t red_data; + uint16_t green_data; + uint16_t blue_data; + uint16_t ir_data; + uint32_t red_lux; + uint32_t green_lux; + uint32_t blue_lux; + uint32_t ir_lux; +}; + +static int veml6046_check_gain(const struct sensor_value *val) +{ + return val->val1 >= VEML6046_GAIN_1 && val->val1 <= VEML6046_GAIN_0_5; +} + +static int veml6046_check_it(const struct sensor_value *val) +{ + return val->val1 >= VEML6046_IT_3_125 && val->val1 <= VEML6046_IT_400; +} + +static int veml6046_check_pdd(const struct sensor_value *val) +{ + return val->val1 >= VEML6046_SIZE_2_2 && val->val1 <= VEML6046_SIZE_1_2; +} + +static int veml6046_check_pers(const struct sensor_value *val) +{ + return val->val1 >= VEML6046_PERS_1 && val->val1 <= VEML6046_PERS_8; +} + +static int veml6046_read16(const struct device *dev, uint8_t cmd, uint16_t *data) +{ + const struct veml6046_config *conf = dev->config; + int ret; + + ret = i2c_burst_read_dt(&conf->bus, cmd, (uint8_t *)data, 2); + if (ret < 0) { + return ret; + } + + *data = sys_le16_to_cpu(*data); + + return 0; +} + +/* + * This function excepts an array of uint8_t data[2] with the two corresponding + * values set accordingly to the register map of the sensor. + */ +static int veml6046_write16(const struct device *dev, uint8_t cmd, uint8_t *data) +{ + const struct veml6046_config *conf = dev->config; + + return i2c_burst_write_dt(&conf->bus, cmd, data, 2); +} + +static int veml6046_write_conf(const struct device *dev) +{ + int ret; + struct veml6046_data *data = dev->data; + uint8_t conf[2] = {0, 0}; + + /* Bits 7 -> RGB_ON_1 */ + if (data->sd) { + conf[1] |= BIT(7); + } + /* Bits 6 -> Effective photodiode size */ + conf[1] |= data->pdd << 6; + /* Bit 5 -> reserved */ + /* Bits 4:3 -> Gain selection */ + conf[1] |= data->gain << 3; + /* Bits 2:1 -> ALS persistence protect number */ + conf[1] |= data->pers << 1; + /* Bit 0 -> Calibration should always be 1 when using the sensor */ + conf[1] |= BIT(0); + /* Bit 7 -> reserved, have to be 0 */ + /* Bits 6:4 -> integration time (ALS_IT) */ + conf[0] |= data->itim << 4; + /* Bit 3 -> Active force mode is always enabled + * Auto mode would continuously deliver data which is not what we want + * in this driver + */ + conf[0] |= BIT(3); + /* Bit 2 -> ALS active force trigger */ + if (data->trig) { + conf[0] |= BIT(2); + } + /* Bit 1 -> ALS interrupt enable */ + if (data->int_en) { + conf[0] |= BIT(1); + } + /* Bit 0 -> shut down setting (SD) */ + if (data->sd) { + conf[0] |= BIT(0); + } + + ret = veml6046_write16(dev, VEML6046_CMDCODE_RGB_CONF_0, conf); + if (ret) { + LOG_ERR("Error while writing conf[0] ret: %d", ret); + return ret; + } + + return 0; +} + +static int veml6046_write_thresh_high(const struct device *dev) +{ + int ret; + const struct veml6046_data *data = dev->data; + uint8_t val[2]; + + val[0] = data->thresh_high & 0xFF; + val[1] = data->thresh_high >> 8; + + LOG_DBG("Writing high threshold counts: %d", data->thresh_high); + ret = veml6046_write16(dev, VEML6046_CMDCODE_G_THDH_L, val); + if (ret) { + return ret; + } + + return 0; +} + +static int veml6046_write_thresh_low(const struct device *dev) +{ + int ret; + const struct veml6046_data *data = dev->data; + uint8_t val[2]; + + val[0] = data->thresh_low & 0xFF; + val[1] = data->thresh_low >> 8; + + LOG_DBG("Writing low threshold counts: %d", data->thresh_low); + ret = veml6046_write16(dev, VEML6046_CMDCODE_G_THDL_L, val); + if (ret) { + return ret; + } + + return 0; +} + +static int veml6046_fetch(const struct device *dev) +{ + struct veml6046_data *data = dev->data; + int ret; + + ret = veml6046_read16(dev, VEML6046_CMDCODE_R_DATA_L, &data->red_data); + if (ret) { + return ret; + } + + ret = veml6046_read16(dev, VEML6046_CMDCODE_G_DATA_L, &data->green_data); + if (ret) { + return ret; + } + + ret = veml6046_read16(dev, VEML6046_CMDCODE_B_DATA_L, &data->blue_data); + if (ret) { + return ret; + } + + ret = veml6046_read16(dev, VEML6046_CMDCODE_IR_DATA_L, &data->ir_data); + if (ret) { + return ret; + } + + data->red_lux = data->red_data * veml6046_resolution[data->pdd][data->gain][data->itim]; + data->green_lux = data->green_data * veml6046_resolution[data->pdd][data->gain][data->itim]; + data->blue_lux = data->blue_data * veml6046_resolution[data->pdd][data->gain][data->itim]; + data->ir_lux = data->ir_data * veml6046_resolution[data->pdd][data->gain][data->itim]; + + LOG_DBG("Read (R/G/B/IR): counts=%d/%d/%d/%d, lux=%d/%d/%d/%d", + data->red_data, data->green_data, data->blue_data, data->ir_data, + data->red_lux, data->green_lux, data->blue_lux, data->ir_lux); + + if ((data->red_data == VEML6046_DATA_OVERFLOW) || + (data->green_data == VEML6046_DATA_OVERFLOW) || + (data->blue_data == VEML6046_DATA_OVERFLOW) || + (data->ir_data == VEML6046_DATA_OVERFLOW)) { + return -E2BIG; + } + + return 0; +} + +static int veml6046_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + struct veml6046_data *data = dev->data; + + if (chan != SENSOR_CHAN_LIGHT) { + return -ENOTSUP; + } + + /* SENSOR_ATTR_.*_THRESH are not in enum sensor_attribute_veml6046 */ + switch ((int)attr) { + case SENSOR_ATTR_VEML6046_IT: + if (veml6046_check_it(val)) { + data->itim = (enum veml6046_it)val->val1; + } else { + return -EINVAL; + } + break; + case SENSOR_ATTR_VEML6046_PDD: + if (veml6046_check_pdd(val)) { + data->pdd = (enum veml6046_pdd)val->val1; + } else { + return -EINVAL; + } + break; + case SENSOR_ATTR_VEML6046_GAIN: + if (veml6046_check_gain(val)) { + data->gain = (enum veml6046_gain)val->val1; + } else { + return -EINVAL; + } + break; + case SENSOR_ATTR_VEML6046_PERS: + if (veml6046_check_pers(val)) { + data->pers = (enum veml6046_pers)val->val1; + } else { + return -EINVAL; + } + break; + case SENSOR_ATTR_LOWER_THRESH: + data->thresh_low = + val->val1 / veml6046_resolution[data->pdd][data->gain][data->itim]; + return veml6046_write_thresh_low(dev); + case SENSOR_ATTR_UPPER_THRESH: + data->thresh_high = + val->val1 / veml6046_resolution[data->pdd][data->gain][data->itim]; + return veml6046_write_thresh_high(dev); + default: + return -ENOTSUP; + } + + return 0; +} + +static int veml6046_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + struct veml6046_data *data = dev->data; + + if (chan != SENSOR_CHAN_LIGHT) { + return -ENOTSUP; + } + + /* SENSOR_ATTR_.*_THRESH are not in enum sensor_attribute_veml6046 */ + switch ((int)attr) { + case SENSOR_ATTR_VEML6046_IT: + val->val1 = data->itim; + break; + case SENSOR_ATTR_VEML6046_PDD: + val->val1 = data->pdd; + break; + case SENSOR_ATTR_VEML6046_GAIN: + val->val1 = data->gain; + break; + case SENSOR_ATTR_VEML6046_PERS: + val->val1 = data->pers; + break; + case SENSOR_ATTR_LOWER_THRESH: + val->val1 = data->thresh_low + * veml6046_resolution[data->pdd][data->gain][data->itim]; + break; + case SENSOR_ATTR_UPPER_THRESH: + val->val1 = data->thresh_high + * veml6046_resolution[data->pdd][data->gain][data->itim]; + break; + default: + return -ENOTSUP; + } + + val->val2 = 0; + + return 0; +} + +static int veml6046_perform_single_measurement(const struct device *dev) +{ + struct veml6046_data *data = dev->data; + int ret; + uint16_t val; + int cnt = 0; + + data->trig = 1; + data->int_en = 0; + data->sd = 0; + + ret = veml6046_write_conf(dev); + if (ret) { + return ret; + } + + ret = veml6046_read16(dev, VEML6046_CMDCODE_INT_L, &val); + if (ret) { + return ret; + } + + k_sleep(K_USEC(veml6046_it_values[data->itim].us)); + + while (1) { + ret = veml6046_read16(dev, VEML6046_CMDCODE_INT_L, &val); + if (ret) { + return ret; + } + + if ((val >> 8) & VEML6046_AF_DATA_READY) { + break; + } + + if (cnt > 10) { + return -EAGAIN; + } + + k_sleep(K_USEC(veml6046_it_values[data->itim].us / 10)); + + cnt++; + } + + LOG_DBG("read VEML6046_CMDCODE_INT_H: %02X (%d)", val >> 8, cnt); + + return 0; +} + +static int veml6046_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + int ret; + + /* Start sensor for new measurement */ + if (chan == SENSOR_CHAN_RED || chan == SENSOR_CHAN_GREEN || + chan == SENSOR_CHAN_BLUE || chan == SENSOR_CHAN_IR || + chan == SENSOR_CHAN_ALL) { + ret = veml6046_perform_single_measurement(dev); + if (ret < 0) { + return ret; + } + + return veml6046_fetch(dev); + } else { + return -ENOTSUP; + } + + return 0; +} + +static int veml6046_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct veml6046_data *data = dev->data; + + switch ((int)chan) { + case SENSOR_CHAN_RED: + val->val1 = data->red_lux; + break; + case SENSOR_CHAN_GREEN: + val->val1 = data->green_lux; + break; + case SENSOR_CHAN_BLUE: + val->val1 = data->blue_lux; + break; + case SENSOR_CHAN_IR: + val->val1 = data->ir_lux; + break; + case SENSOR_CHAN_VEML6046_RED_RAW_COUNTS: + val->val1 = data->red_data; + break; + case SENSOR_CHAN_VEML6046_GREEN_RAW_COUNTS: + val->val1 = data->green_data; + break; + case SENSOR_CHAN_VEML6046_BLUE_RAW_COUNTS: + val->val1 = data->blue_data; + break; + case SENSOR_CHAN_VEML6046_IR_RAW_COUNTS: + val->val1 = data->ir_data; + break; + default: + return -ENOTSUP; + } + + val->val2 = 0; + + return 0; +} + +#ifdef CONFIG_PM_DEVICE + +static int veml6046_set_shutdown_flag(const struct device *dev, uint8_t new_val) +{ + struct veml6046_data *data = dev->data; + uint8_t prev_sd; + int ret; + + prev_sd = data->sd; + data->sd = new_val; + + ret = veml6046_write_conf(dev); + if (ret < 0) { + data->sd = prev_sd; + } + return ret; +} + +static int veml6046_pm_action(const struct device *dev, enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + return veml6046_set_shutdown_flag(dev, 1); + + case PM_DEVICE_ACTION_RESUME: + return veml6046_set_shutdown_flag(dev, 0); + + default: + return -ENOTSUP; + } + + return 0; +} + +#endif /* CONFIG_PM_DEVICE */ + +static int veml6046_init(const struct device *dev) +{ + const struct veml6046_config *conf = dev->config; + int ret; + uint16_t val; + + if (!i2c_is_ready_dt(&conf->bus)) { + LOG_ERR("VEML device not ready"); + return -ENODEV; + } + + ret = veml6046_read16(dev, VEML6046_CMDCODE_ID_L, &val); + if (ret) { + LOG_ERR("Error while reading ID. ret: %d", ret); + return ret; + } + if ((val & 0x00FF) != VEML6046_DEFAULT_ID) { + LOG_ERR("Device ID wrong: %d", val & 0x00FF); + return -EIO; + } + + LOG_DBG("veml6046 found package: %02d address: %02X version: %3s", + val >> 14, val >> 12 & 0x03 ? 0x10 : 0x29, + val >> 8 & 0x0F ? "XXX" : "A01"); + + /* Initialize sensor configuration */ + ret = veml6046_write_thresh_low(dev); + if (ret < 0) { + LOG_ERR("Error while writing thresh low. ret: %d", ret); + return ret; + } + + ret = veml6046_write_thresh_high(dev); + if (ret < 0) { + LOG_ERR("Error while writing thresh high. ret: %d", ret); + return ret; + } + + ret = veml6046_write_conf(dev); + if (ret < 0) { + LOG_ERR("Error while writing config. ret: %d", ret); + return ret; + } + + return 0; +} + +static DEVICE_API(sensor, veml6046_api) = { + .sample_fetch = veml6046_sample_fetch, + .channel_get = veml6046_channel_get, + .attr_set = veml6046_attr_set, + .attr_get = veml6046_attr_get, +}; + +#define VEML6046_INIT(n) \ + static struct veml6046_data veml6046_data_##n = {.trig = 0, \ + .pdd = VEML6046_SIZE_2_2, \ + .gain = VEML6046_GAIN_1, \ + .itim = VEML6046_IT_100, \ + .pers = VEML6046_PERS_1, \ + .thresh_high = 0xFFFF}; \ + \ + static const struct veml6046_config veml6046_config_##n = { \ + .bus = I2C_DT_SPEC_INST_GET(n)}; \ + \ + PM_DEVICE_DT_INST_DEFINE(n, veml6046_pm_action); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, veml6046_init, PM_DEVICE_DT_INST_GET(n), \ + &veml6046_data_##n, &veml6046_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &veml6046_api); + +DT_INST_FOREACH_STATUS_OKAY(VEML6046_INIT) diff --git a/dts/bindings/sensor/vishay,veml6046.yaml b/dts/bindings/sensor/vishay,veml6046.yaml new file mode 100644 index 0000000000000..473c131c62792 --- /dev/null +++ b/dts/bindings/sensor/vishay,veml6046.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Andreas Klinger +# SPDX-License-Identifier: Apache-2.0 + +description: | + Vishay VEML6046 RGBIR color sensor with I2C interface. + See: https://www.vishay.com/docs/80173/veml6046x00.pdf + +compatible: "vishay,veml6046" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/include/zephyr/drivers/sensor/veml6046.h b/include/zephyr/drivers/sensor/veml6046.h new file mode 100644 index 0000000000000..c5641dccc791d --- /dev/null +++ b/include/zephyr/drivers/sensor/veml6046.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2025 Andreas Klinger + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Header file for extended sensor API of VEML6046 sensor + * @ingroup veml6046_interface + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEML6046_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEML6046_H_ + +/** + * @defgroup veml6046_interface VEML6046 + * @ingroup sensor_interface_ext + * @brief Vishay VEML6046 RGBIR Sensor + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief VEML6046 integration time options for light measurements. + * + * Possible values for @ref SENSOR_ATTR_VEML6046_IT custom attribute. + */ +enum veml6046_it { + VEML6046_IT_3_125, /**< 3.125 ms */ + VEML6046_IT_6_25, /**< 6.25 ms */ + VEML6046_IT_12_5, /**< 12.5 ms */ + VEML6046_IT_25, /**< 25 ms */ + VEML6046_IT_50, /**< 50 ms */ + VEML6046_IT_100, /**< 100 ms */ + VEML6046_IT_200, /**< 200 ms */ + VEML6046_IT_400, /**< 400 ms */ + /** @cond INTERNAL_HIDDEN */ + VEML6046_IT_COUNT, + /** @endcond */ +}; + +/** + * @brief VEML6046 size options for light measurements. + * + * Possible values for @ref SENSOR_ATTR_VEML6046_PDD custom attribute. + */ +enum veml6046_pdd { + VEML6046_SIZE_2_2 = 0x00, /**< 2/2 photodiode size */ + VEML6046_SIZE_1_2 = 0x01, /**< 1/2 photodiode size */ + /** @cond INTERNAL_HIDDEN */ + VEML6046_PDD_COUNT = 2, + /** @endcond */ +}; + +/** + * @brief VEML6046 gain options for light measurements. + * + * Possible values for @ref SENSOR_ATTR_VEML6046_GAIN custom attribute. + */ +enum veml6046_gain { + VEML6046_GAIN_1 = 0x00, /**< 1x gain */ + VEML6046_GAIN_2 = 0x01, /**< 2x gain */ + VEML6046_GAIN_0_66 = 0x02, /**< 0.66x gain */ + VEML6046_GAIN_0_5 = 0x03, /**< 0.5x gain */ + /** @cond INTERNAL_HIDDEN */ + VEML6046_GAIN_COUNT = 4, + /** @endcond */ +}; + +/** + * @brief VEML6046 interrupt persistence protect number options. + * + * Possible values for @ref SENSOR_ATTR_VEML6046_PERS custom attribute. + */ +enum veml6046_pers { + VEML6046_PERS_1 = 0x00, /**< 1 measurement */ + VEML6046_PERS_2 = 0x01, /**< 2 measurements */ + VEML6046_PERS_4 = 0x02, /**< 4 measurements */ + VEML6046_PERS_8 = 0x03, /**< 8 measurements */ +}; + +/** + * @brief VEML6046 specific sensor attributes. + * + * For high and low threshold window settings (G_THDH_L, G_THDH_H, G_THDL_L and + * G_THDL_H) use the generic attributes @ref SENSOR_ATTR_UPPER_THRESH and + * @ref SENSOR_ATTR_LOWER_THRESH with 16-bit unsigned integer values. Both + * threshold settings are in lux and converted by the driver to a value + * compatible with the sensor. This conversion depends on the current gain, + * integration time and effective photodiode size settings. So a change in + * gain, integration time or effective photodiode size usually requires an + * update of threshold window settings. To get the correct threshold values + * into the sensor update the thresholds -after- a change of gain or + * integration time. + * + * When the sensor goes into saturation @c -E2BIG is returned. This happens + * when the maximum value @c 0xFFFF is returned as raw ALS value. In this case + * it's up to the user to reduce one or more of the following attributes to + * come back into the optimal measurement range of the sensor: + * @ref SENSOR_ATTR_VEML6046_GAIN (gain) + * @ref SENSOR_ATTR_VEML6046_IT (integration time) + * @ref SENSOR_ATTR_VEML6046_PDD (effective photodiode size) + */ +enum sensor_attribute_veml6046 { + /** + * @brief Integration time setting for measurements (IT). + * + * Use enum veml6046_it for attribute values. + */ + SENSOR_ATTR_VEML6046_IT = SENSOR_ATTR_PRIV_START, + /** + * @brief Effective photodiode size (PDD) + * + * Use enum veml6046_pdd for attribute values. + */ + SENSOR_ATTR_VEML6046_PDD, + /** + * @brief Gain setting for measurements (GAIN). + * + * Use enum veml6046_gain for attribute values. + */ + SENSOR_ATTR_VEML6046_GAIN, + /** + * @brief Persistence protect number setting (PERS). + * + * Use enum veml6046_pers for attribute values. + */ + SENSOR_ATTR_VEML6046_PERS, +}; + +/** + * @brief VEML6046 specific sensor channels. + */ +enum sensor_channel_veml6046 { + /** + * @brief Channel for raw red sensor values. + * + * This channel represents the raw measurement counts provided by the + * sensor register. It is useful for estimating good values for + * integration time, effective photodiode size and gain attributes in + * fetch and get mode. + * + * For future implementations with triggers it can also be used to + * estimate the threshold window attributes for the sensor interrupt + * handling. + * + * It cannot be fetched directly. Instead, this channel's value is + * fetched implicitly using @ref SENSOR_CHAN_RED. + * Trying to call sensor_channel_fetch_chan with this enumerator + * as an argument will result in a @c -ENOTSUP. + */ + SENSOR_CHAN_VEML6046_RED_RAW_COUNTS = SENSOR_CHAN_PRIV_START, + + /** + * @brief Channel for green sensor values. + * + * This channel is the raw green channel count output of the sensor. + * About fetching the same as for + * @ref SENSOR_CHAN_VEML6046_RED_RAW_COUNTS applies. + */ + SENSOR_CHAN_VEML6046_GREEN_RAW_COUNTS, + + /** + * @brief Channel for blue sensor values. + * + * This channel is the raw blue channel count output of the sensor. + * About fetching the same as for + * @ref SENSOR_CHAN_VEML6046_RED_RAW_COUNTS applies. + */ + SENSOR_CHAN_VEML6046_BLUE_RAW_COUNTS, + + /** + * @brief Channel for IR sensor values. + * + * This channel is the raw IR channel count output of the sensor. About + * fetching the same as for + * @ref SENSOR_CHAN_VEML6046_RED_RAW_COUNTS applies. + */ + SENSOR_CHAN_VEML6046_IR_RAW_COUNTS, +}; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEML6046_H_ */ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 3472514935964..35849732143d6 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -1433,3 +1433,8 @@ test_i2c_hdc302x: hdc302x@be { reg = <0xbe>; int-gpios = <&test_gpio 0 0>; }; + +test_i2c_veml6046: veml6046@bf { + compatible = "vishay,veml6046"; + reg = <0xbf>; +}; From 95a171559d2e5349185106e2b5bc43c288e3e076 Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Sat, 17 May 2025 09:43:12 +0200 Subject: [PATCH 392/397] samples: sensor: veml6046: add attribution test application - Test all attribute combinations of Vishay RGBIR color sensor VEML6046. - Print OVERFLOW in case of saturation of sensor. - This small program is intended to be helping when finding appropriate attributes for an application of the sensor. Signed-off-by: Andreas Klinger --- samples/sensor/veml6046/CMakeLists.txt | 7 ++ samples/sensor/veml6046/README.rst | 61 ++++++++++ .../veml6046/boards/olimex_stm32_e407.overlay | 29 +++++ samples/sensor/veml6046/prj.conf | 1 + samples/sensor/veml6046/sample.yaml | 10 ++ samples/sensor/veml6046/src/main.c | 111 ++++++++++++++++++ 6 files changed, 219 insertions(+) create mode 100644 samples/sensor/veml6046/CMakeLists.txt create mode 100644 samples/sensor/veml6046/README.rst create mode 100644 samples/sensor/veml6046/boards/olimex_stm32_e407.overlay create mode 100644 samples/sensor/veml6046/prj.conf create mode 100644 samples/sensor/veml6046/sample.yaml create mode 100644 samples/sensor/veml6046/src/main.c diff --git a/samples/sensor/veml6046/CMakeLists.txt b/samples/sensor/veml6046/CMakeLists.txt new file mode 100644 index 0000000000000..4aa3e0a7b7408 --- /dev/null +++ b/samples/sensor/veml6046/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(veml6046) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/sensor/veml6046/README.rst b/samples/sensor/veml6046/README.rst new file mode 100644 index 0000000000000..12f34edfc1759 --- /dev/null +++ b/samples/sensor/veml6046/README.rst @@ -0,0 +1,61 @@ +.. zephyr:code-sample:: veml6046 + :name: VEML6046 RGBIR Color Sensor + :relevant-api: sensor_interface + + Get red, green, blue and IR light data from a VEML6046 sensor (polling + mode). + +Overview +******** + + This sample measures the red, green, blue and IR light for all possible + combinations of sensor attributes. They are: + + - integration time + - effective photodiode size + - gain + + These attributes can be used to put the sensor in an optimal working area. + When the light value reaches the maximum raw value (0xFFFF), an error is + returned to indicate the out of bounds situation to the user program. + With this program the raw value is also printed out together with the + attributes to be able to select good attribute values. + Interrupt and trigger modes are not supported so far, but planned for future + development. + +Requirements +************ + + This sample uses the VEML6046 sensor controlled using the I2C-2 interface of + the Olimex-STM32-E407 board on Feather connector pins PF0 and PF1. + +References +********** + + - VEML6046: https://www.vishay.com/docs/80173/veml6046x00.pdf + - Application note: https://www.vishay.com/docs/80410/designingveml6046x00.pdf + +Building and Running +******************** + + This project outputs sensor data to the console. It requires a VEML6046 + sensor to be connected to the desired board. + + .. zephyr-app-commands:: + :zephyr-app: samples/sensor/veml6046/ + :goals: build flash + :board: olimex_stm32_e407 + + +Sample Output +============= + + .. code-block:: console + + Test all attributes for a good guess of attribute usage away of saturation. + Red: 68 lx ( 51) green: 68 lx ( 84) blue: 68 lx ( 51) IR: 68 lx ( 27) it: 0 pdd: 0 gain: 0 -- + Red: 121 lx ( 181) green: 121 lx ( 347) blue: 121 lx ( 240) IR: 121 lx ( 53) it: 0 pdd: 0 gain: 1 -- + Red: 215 lx ( 106) green: 215 lx ( 226) blue: 215 lx ( 160) IR: 215 lx ( 19) it: 0 pdd: 0 gain: 2 -- + Red: 201 lx ( 75) green: 201 lx ( 156) blue: 201 lx ( 112) IR: 201 lx ( 14) it: 0 pdd: 0 gain: 3 -- + [...] + Test finished. diff --git a/samples/sensor/veml6046/boards/olimex_stm32_e407.overlay b/samples/sensor/veml6046/boards/olimex_stm32_e407.overlay new file mode 100644 index 0000000000000..1960223382389 --- /dev/null +++ b/samples/sensor/veml6046/boards/olimex_stm32_e407.overlay @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Andreas Klinger + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + i2c2_sda_pf0: i2c2_sda_pf0 { + pinmux = < 0xa04 >; + bias-pull-up; + drive-open-drain; + }; + i2c2_scl_pf1: i2c2_scl_pf1 { + pinmux = < 0xa24 >; + bias-pull-up; + drive-open-drain; + }; +}; + +&i2c2 { + pinctrl-0 = < &i2c2_scl_pf1 &i2c2_sda_pf0 >; + pinctrl-names = "default"; + status = "okay"; + + rgbir: rgbir@29 { + compatible = "vishay,veml6046"; + reg = <0x29>; + }; +}; diff --git a/samples/sensor/veml6046/prj.conf b/samples/sensor/veml6046/prj.conf new file mode 100644 index 0000000000000..42fcd3c973bcb --- /dev/null +++ b/samples/sensor/veml6046/prj.conf @@ -0,0 +1 @@ +CONFIG_SENSOR=y diff --git a/samples/sensor/veml6046/sample.yaml b/samples/sensor/veml6046/sample.yaml new file mode 100644 index 0000000000000..fe2704301b11c --- /dev/null +++ b/samples/sensor/veml6046/sample.yaml @@ -0,0 +1,10 @@ +sample: + name: VEML6046 Sensor Sample +tests: + sample.sensor.veml6046: + harness: sensor + platform_allow: olimex_stm32_e407 + integration_platforms: + - olimex_stm32_e407 + tags: sensors + filter: dt_compat_enabled("vishay,veml6046") diff --git a/samples/sensor/veml6046/src/main.c b/samples/sensor/veml6046/src/main.c new file mode 100644 index 0000000000000..aec830e7d5177 --- /dev/null +++ b/samples/sensor/veml6046/src/main.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025 Andreas Klinger + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include +#include + +#include + +static void read_with_attr(const struct device *dev, int it, int pdd, int gain) +{ + int ret; + struct sensor_value red, green, blue, ir; + struct sensor_value red_raw, green_raw, blue_raw, ir_raw; + struct sensor_value sen; + char result[10]; + + sen.val2 = 0; + + sen.val1 = it; + ret = sensor_attr_set(dev, SENSOR_CHAN_LIGHT, + (enum sensor_attribute)SENSOR_ATTR_VEML6046_IT, &sen); + if (ret) { + printf("Failed to set it attribute ret: %d\n", ret); + } + sen.val1 = pdd; + ret = sensor_attr_set(dev, SENSOR_CHAN_LIGHT, + (enum sensor_attribute)SENSOR_ATTR_VEML6046_PDD, &sen); + if (ret) { + printf("Failed to set pdd attribute ret: %d\n", ret); + } + sen.val1 = gain; + ret = sensor_attr_set(dev, SENSOR_CHAN_LIGHT, + (enum sensor_attribute)SENSOR_ATTR_VEML6046_GAIN, &sen); + if (ret) { + printf("Failed to set gain attribute ret: %d\n", ret); + } + + ret = sensor_sample_fetch(dev); + if ((ret < 0) && (ret != -E2BIG)) { + printf("sample update error. ret: %d\n", ret); + } + + sensor_channel_get(dev, SENSOR_CHAN_RED, &red); + sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_RED_RAW_COUNTS, + &red_raw); + + sensor_channel_get(dev, SENSOR_CHAN_GREEN, &green); + sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_GREEN_RAW_COUNTS, + &green_raw); + + sensor_channel_get(dev, SENSOR_CHAN_BLUE, &blue); + sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_BLUE_RAW_COUNTS, + &blue_raw); + + sensor_channel_get(dev, SENSOR_CHAN_IR, &ir); + sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_IR_RAW_COUNTS, + &ir_raw); + + if (ret == -E2BIG) { + snprintf(result, sizeof(result), "OVERFLOW"); + } else if (ret) { + snprintf(result, sizeof(result), "ERROR"); + } else { + snprintf(result, sizeof(result), ""); + } + + printf("Red: %6d lx (%6d) green: %6d lx (%6d) " + "blue: %6d lx (%6d) IR: %6d lx (%6d) " + " it: %d pdd: %d gain: %d -- %s\n", + red.val1, red_raw.val1, + green.val1, green_raw.val1, + blue.val1, blue_raw.val1, + ir.val1, ir_raw.val1, + it, pdd, gain, + result); +} + +static void read_with_all_attr(const struct device *dev) +{ + for (int it = VEML6046_IT_3_125; it <= VEML6046_IT_400; it++) { + for (int pdd = VEML6046_SIZE_2_2; pdd <= VEML6046_SIZE_1_2; pdd++) { + for (int gain = VEML6046_GAIN_1; gain <= VEML6046_GAIN_0_5; gain++) { + read_with_attr(dev, it, pdd, gain); + } + } + } +} + +int main(void) +{ + const struct device *const veml = DEVICE_DT_GET(DT_NODELABEL(rgbir)); + + if (!device_is_ready(veml)) { + printk("sensor: device not ready.\n"); + return 0; + } + + printf("Test all attributes for a good guess of attribute usage away of saturation.\n"); + read_with_all_attr(veml); + printf("Test finished.\n"); + + return 0; +} From 773fb40f40380f34958508e57b0dfbbdc36fe04d Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Wed, 8 Oct 2025 13:18:04 +0200 Subject: [PATCH 393/397] drivers: sensor: remove redundancies in veml6031 and veml6046 - create common header file veml60xx-common.h for sensors VEML6031 and VEML6046. Signed-off-by: Andreas Klinger --- drivers/sensor/vishay/veml6031/veml6031.c | 98 +++----------- drivers/sensor/vishay/veml6046/veml6046.c | 80 +++--------- include/zephyr/drivers/sensor/veml6031.h | 46 +------ include/zephyr/drivers/sensor/veml6046.h | 50 +------ .../zephyr/drivers/sensor/veml60xx-common.h | 122 ++++++++++++++++++ samples/sensor/veml6031/src/main.c | 4 +- samples/sensor/veml6046/src/main.c | 4 +- 7 files changed, 168 insertions(+), 236 deletions(-) create mode 100644 include/zephyr/drivers/sensor/veml60xx-common.h diff --git a/drivers/sensor/vishay/veml6031/veml6031.c b/drivers/sensor/vishay/veml6031/veml6031.c index b36b0a4c8d909..b2511b2586f79 100644 --- a/drivers/sensor/vishay/veml6031/veml6031.c +++ b/drivers/sensor/vishay/veml6031/veml6031.c @@ -57,33 +57,6 @@ LOG_MODULE_REGISTER(VEML6031, CONFIG_SENSOR_LOG_LEVEL); #define VEML6031_CMDCODE_ID_H 0x15 #define VEML6031_CMDCODE_ALS_INT 0x17 -/* - * ALS integration time struct. - */ -struct veml6031_it_data { - enum veml6031_it num; - uint8_t val; - int us; -}; - -/* - * ALS integration time setting values. - * - * The enumerators of enum veml6031_it provide - * indices into this array to get the related value for the - * ALS_IT configuration bits. - */ -static const struct veml6031_it_data veml6031_it_values[] = { - {VEML6031_IT_3_125, 0x00, 3125}, /* 3.125 - 0b0000 */ - {VEML6031_IT_6_25, 0x01, 6250}, /* 6.25 - 0b0001 */ - {VEML6031_IT_12_5, 0x02, 12500}, /* 12.5 - 0b0010 */ - {VEML6031_IT_25, 0x03, 25000}, /* 25 - 0b0011 */ - {VEML6031_IT_50, 0x04, 50000}, /* 50 - 0b0100 */ - {VEML6031_IT_100, 0x05, 100000}, /* 100 - 0b0101 */ - {VEML6031_IT_200, 0x06, 200000}, /* 200 - 0b0110 */ - {VEML6031_IT_400, 0x07, 400000}, /* 400 - 0b0111 */ -}; - /* * Resolution matrix for values to convert between data provided * by the sensor ("counts") and lux. @@ -93,7 +66,7 @@ static const struct veml6031_it_data veml6031_it_values[] = { * and enum veml6031_als_it are used for indices into this matrix. */ static const float - veml6031_resolution[VEML6031_DIV4_COUNT][VEML6031_GAIN_COUNT][VEML6031_IT_COUNT] = { + veml6031_resolution[VEML6031_DIV4_COUNT][VEML60XX_GAIN_COUNT][VEML60XX_IT_COUNT] = { /*3.125ms 6.25ms 12.5ms 25ms 50ms 100ms 200ms 400ms IT */ /* size 4/4 */ { @@ -131,9 +104,9 @@ struct veml6031_data { uint8_t ir_sd; /* ALS and IR channel shutdown */ uint8_t cal; /* Power on ready */ enum veml6031_div4 div4; /* effective photodiode size */ - enum veml6031_gain gain; /* gain selection */ - enum veml6031_it itim; /* ALS integration time */ - enum veml6031_pers pers; /* ALS persistens protect */ + enum veml60xx_gain gain; /* gain selection */ + enum veml60xx_it itim; /* ALS integration time */ + enum veml60xx_pers pers; /* ALS persistence protect */ uint16_t thresh_high; uint16_t thresh_low; uint16_t als_data; @@ -142,30 +115,15 @@ struct veml6031_data { uint32_t int_flags; }; -static bool veml6031_gain_in_range(int32_t gain) -{ - return (gain >= VEML6031_GAIN_1) && (gain <= VEML6031_GAIN_0_5); -} - -static bool veml6031_itim_in_range(int32_t itim) -{ - return (itim >= VEML6031_IT_3_125) && (itim <= VEML6031_IT_400); -} - static bool veml6031_div4_in_range(int32_t div4) { return (div4 >= VEML6031_SIZE_4_4) && (div4 <= VEML6031_SIZE_1_4); } -static bool veml6031_pers_in_range(int32_t pers) -{ - return (pers >= VEML6031_PERS_1) && (pers <= VEML6031_PERS_8); -} - static void veml6031_sleep_by_integration_time(const struct veml6031_data *data) { - if (veml6031_itim_in_range(data->itim)) { - k_sleep(K_USEC(veml6031_it_values[data->itim].us)); + if (veml60xx_it_in_range(data->itim)) { + k_sleep(K_USEC(veml60xx_it_values[data->itim].us)); } else { LOG_WRN_ONCE("Wrong settings: itim:%d. Most likely an application bug!", data->itim); @@ -174,28 +132,8 @@ static void veml6031_sleep_by_integration_time(const struct veml6031_data *data) static int veml6031_check_settings(const struct veml6031_data *data) { - return veml6031_div4_in_range(data->div4) && veml6031_gain_in_range(data->gain) && - veml6031_itim_in_range(data->itim); -} - -static int veml6031_check_gain(const struct sensor_value *val) -{ - return veml6031_gain_in_range(val->val1); -} - -static int veml6031_check_it(const struct sensor_value *val) -{ - return veml6031_itim_in_range(val->val1); -} - -static int veml6031_check_div4(const struct sensor_value *val) -{ - return veml6031_div4_in_range(val->val1); -} - -static int veml6031_check_pers(const struct sensor_value *val) -{ - return veml6031_pers_in_range(val->val1); + return veml6031_div4_in_range(data->div4) && veml60xx_gain_in_range(data->gain) && + veml60xx_it_in_range(data->itim); } static int veml6031_read(const struct device *dev, uint8_t cmd, uint8_t *data) @@ -368,29 +306,29 @@ static int veml6031_attr_set(const struct device *dev, enum sensor_channel chan, /* SENSOR_ATTR_.*_THRESH are not in enum sensor_attribute_veml6031 */ switch ((int)attr) { case SENSOR_ATTR_VEML6031_IT: - if (veml6031_check_it(val)) { - data->itim = (enum veml6031_it)val->val1; + if (veml60xx_it_in_range(val->val1)) { + data->itim = (enum veml60xx_it)val->val1; } else { return -EINVAL; } break; case SENSOR_ATTR_VEML6031_DIV4: - if (veml6031_check_div4(val)) { + if (veml6031_div4_in_range(val->val1)) { data->div4 = (enum veml6031_div4)val->val1; } else { return -EINVAL; } break; case SENSOR_ATTR_VEML6031_GAIN: - if (veml6031_check_gain(val)) { - data->gain = (enum veml6031_gain)val->val1; + if (veml60xx_gain_in_range(val->val1)) { + data->gain = (enum veml60xx_gain)val->val1; } else { return -EINVAL; } break; case SENSOR_ATTR_VEML6031_PERS: - if (veml6031_check_pers(val)) { - data->pers = (enum veml6031_pers)val->val1; + if (veml60xx_pers_in_range(val->val1)) { + data->pers = (enum veml60xx_pers)val->val1; } else { return -EINVAL; } @@ -651,9 +589,9 @@ static DEVICE_API(sensor, veml6031_api) = { static struct veml6031_data veml6031_data_##n = {.trig = 1, \ .af = 1, \ .div4 = VEML6031_SIZE_4_4, \ - .gain = VEML6031_GAIN_1, \ - .itim = VEML6031_IT_100, \ - .pers = VEML6031_PERS_1, \ + .gain = VEML60XX_GAIN_1, \ + .itim = VEML60XX_IT_100, \ + .pers = VEML60XX_PERS_1, \ .thresh_high = 0xFFFF}; \ \ static const struct veml6031_config veml6031_config_##n = { \ diff --git a/drivers/sensor/vishay/veml6046/veml6046.c b/drivers/sensor/vishay/veml6046/veml6046.c index 9f0b54e1f27cd..89faea0e2d141 100644 --- a/drivers/sensor/vishay/veml6046/veml6046.c +++ b/drivers/sensor/vishay/veml6046/veml6046.c @@ -61,42 +61,16 @@ LOG_MODULE_REGISTER(VEML6046, CONFIG_SENSOR_LOG_LEVEL); #define VEML6046_CMDCODE_INT_L 0x1A #define VEML6046_CMDCODE_INT_H 0x1B -/* - * ALS integration time struct. - */ -struct veml6046_it_data { - enum veml6046_it num; - uint8_t val; - int us; -}; - -/* - * ALS integration time setting values. - * - * The enumerators of enum veml6046_it provide indices into this array to get - * the related value for the ALS_IT configuration bits. - */ -static const struct veml6046_it_data veml6046_it_values[VEML6046_IT_COUNT] = { - {VEML6046_IT_3_125, 0x00, 3125}, /* 3.125 - 0b0000 */ - {VEML6046_IT_6_25, 0x01, 6250}, /* 6.25 - 0b0001 */ - {VEML6046_IT_12_5, 0x02, 12500}, /* 12.5 - 0b0010 */ - {VEML6046_IT_25, 0x03, 25000}, /* 25 - 0b0011 */ - {VEML6046_IT_50, 0x04, 50000}, /* 50 - 0b0100 */ - {VEML6046_IT_100, 0x05, 100000}, /* 100 - 0b0101 */ - {VEML6046_IT_200, 0x06, 200000}, /* 200 - 0b0110 */ - {VEML6046_IT_400, 0x07, 400000}, /* 400 - 0b0111 */ -}; - /* * Resolution matrix for values to convert between data provided * by the sensor ("counts") and lux. * * These values depend on the current size, gain and integration time settings. - * The enumerators of enum veml6046_pdd, enum veml6046_gain and enum + * The enumerators of enum veml6046_pdd, enum veml60xx_gain and enum * veml6046_als_it are used for indices into this matrix. */ static const float - veml6046_resolution[VEML6046_PDD_COUNT][VEML6046_GAIN_COUNT][VEML6046_IT_COUNT] = { + veml6046_resolution[VEML6046_PDD_COUNT][VEML60XX_GAIN_COUNT][VEML60XX_IT_COUNT] = { /*3.125ms 6.25ms 12.5ms 25ms 50ms 100ms 200ms 400ms IT */ /* size 2/2 */ { @@ -131,9 +105,9 @@ struct veml6046_data { uint8_t int_en; /* ALS interrupt enable */ uint8_t trig; /* ALS active force trigger */ enum veml6046_pdd pdd; /* effective photodiode size divider */ - enum veml6046_gain gain; /* gain selection */ - enum veml6046_it itim; /* ALS integration time */ - enum veml6046_pers pers; /* ALS persistens protect */ + enum veml60xx_gain gain; /* gain selection */ + enum veml60xx_it itim; /* ALS integration time */ + enum veml60xx_pers pers; /* ALS persistens protect */ uint16_t thresh_high; uint16_t thresh_low; uint16_t red_data; @@ -146,24 +120,9 @@ struct veml6046_data { uint32_t ir_lux; }; -static int veml6046_check_gain(const struct sensor_value *val) +static bool veml6046_pdd_in_range(int32_t pdd) { - return val->val1 >= VEML6046_GAIN_1 && val->val1 <= VEML6046_GAIN_0_5; -} - -static int veml6046_check_it(const struct sensor_value *val) -{ - return val->val1 >= VEML6046_IT_3_125 && val->val1 <= VEML6046_IT_400; -} - -static int veml6046_check_pdd(const struct sensor_value *val) -{ - return val->val1 >= VEML6046_SIZE_2_2 && val->val1 <= VEML6046_SIZE_1_2; -} - -static int veml6046_check_pers(const struct sensor_value *val) -{ - return val->val1 >= VEML6046_PERS_1 && val->val1 <= VEML6046_PERS_8; + return pdd >= VEML6046_SIZE_2_2 && pdd <= VEML6046_SIZE_1_2; } static int veml6046_read16(const struct device *dev, uint8_t cmd, uint16_t *data) @@ -333,29 +292,29 @@ static int veml6046_attr_set(const struct device *dev, enum sensor_channel chan, /* SENSOR_ATTR_.*_THRESH are not in enum sensor_attribute_veml6046 */ switch ((int)attr) { case SENSOR_ATTR_VEML6046_IT: - if (veml6046_check_it(val)) { - data->itim = (enum veml6046_it)val->val1; + if (veml60xx_it_in_range(val->val1)) { + data->itim = (enum veml60xx_it)val->val1; } else { return -EINVAL; } break; case SENSOR_ATTR_VEML6046_PDD: - if (veml6046_check_pdd(val)) { + if (veml6046_pdd_in_range(val->val1)) { data->pdd = (enum veml6046_pdd)val->val1; } else { return -EINVAL; } break; case SENSOR_ATTR_VEML6046_GAIN: - if (veml6046_check_gain(val)) { - data->gain = (enum veml6046_gain)val->val1; + if (veml60xx_gain_in_range(val->val1)) { + data->gain = (enum veml60xx_gain)val->val1; } else { return -EINVAL; } break; case SENSOR_ATTR_VEML6046_PERS: - if (veml6046_check_pers(val)) { - data->pers = (enum veml6046_pers)val->val1; + if (veml60xx_pers_in_range(val->val1)) { + data->pers = (enum veml60xx_pers)val->val1; } else { return -EINVAL; } @@ -436,7 +395,7 @@ static int veml6046_perform_single_measurement(const struct device *dev) return ret; } - k_sleep(K_USEC(veml6046_it_values[data->itim].us)); + k_sleep(K_USEC(veml60xx_it_values[data->itim].us)); while (1) { ret = veml6046_read16(dev, VEML6046_CMDCODE_INT_L, &val); @@ -452,7 +411,7 @@ static int veml6046_perform_single_measurement(const struct device *dev) return -EAGAIN; } - k_sleep(K_USEC(veml6046_it_values[data->itim].us / 10)); + k_sleep(K_USEC(veml60xx_it_values[data->itim].us / 10)); cnt++; } @@ -552,7 +511,6 @@ static int veml6046_pm_action(const struct device *dev, enum pm_device_action ac default: return -ENOTSUP; } - return 0; } @@ -615,9 +573,9 @@ static DEVICE_API(sensor, veml6046_api) = { #define VEML6046_INIT(n) \ static struct veml6046_data veml6046_data_##n = {.trig = 0, \ .pdd = VEML6046_SIZE_2_2, \ - .gain = VEML6046_GAIN_1, \ - .itim = VEML6046_IT_100, \ - .pers = VEML6046_PERS_1, \ + .gain = VEML60XX_GAIN_1, \ + .itim = VEML60XX_IT_100, \ + .pers = VEML60XX_PERS_1, \ .thresh_high = 0xFFFF}; \ \ static const struct veml6046_config veml6046_config_##n = { \ diff --git a/include/zephyr/drivers/sensor/veml6031.h b/include/zephyr/drivers/sensor/veml6031.h index 8d9ee6874f01e..65808d5a79739 100644 --- a/include/zephyr/drivers/sensor/veml6031.h +++ b/include/zephyr/drivers/sensor/veml6031.h @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /** * @file * @brief Header file for extended sensor API of VEML6031 sensor @@ -24,25 +26,6 @@ extern "C" { #endif -/** - * @brief VEML6031 integration time options for ambient light measurements. - * - * Possible values for @ref SENSOR_ATTR_VEML6031_IT custom attribute. - */ -enum veml6031_it { - VEML6031_IT_3_125, /**< 3.125 ms */ - VEML6031_IT_6_25, /**< 6.25 ms */ - VEML6031_IT_12_5, /**< 12.5 ms */ - VEML6031_IT_25, /**< 25 ms */ - VEML6031_IT_50, /**< 50 ms */ - VEML6031_IT_100, /**< 100 ms */ - VEML6031_IT_200, /**< 200 ms */ - VEML6031_IT_400, /**< 400 ms */ - /** @cond INTERNAL_HIDDEN */ - VEML6031_IT_COUNT, - /** @endcond */ -}; - /** * @brief VEML6031 size options for ambient light measurements. * @@ -56,31 +39,6 @@ enum veml6031_div4 { /** @endcond */ }; -/** - * @brief VEML6031 gain options for ambient light measurements. - */ -enum veml6031_gain { - VEML6031_GAIN_1 = 0x00, /**< 1x gain */ - VEML6031_GAIN_2 = 0x01, /**< 2x gain */ - VEML6031_GAIN_0_66 = 0x02, /**< 0.66x gain */ - VEML6031_GAIN_0_5 = 0x03, /**< 0.5x gain */ - /** @cond INTERNAL_HIDDEN */ - VEML6031_GAIN_COUNT = 4, - /** @endcond */ -}; - -/** - * @brief VEML6031 ALS interrupt persistence protect number options. - * - * Possible values for @ref SENSOR_ATTR_VEML6031_PERS custom attribute. - */ -enum veml6031_pers { - VEML6031_PERS_1 = 0x00, /**< 1 measurement */ - VEML6031_PERS_2 = 0x01, /**< 2 measurements */ - VEML6031_PERS_4 = 0x02, /**< 4 measurements */ - VEML6031_PERS_8 = 0x03, /**< 8 measurements */ -}; - /** * @brief Custom sensor attributes for VEML6031 sensor. * diff --git a/include/zephyr/drivers/sensor/veml6046.h b/include/zephyr/drivers/sensor/veml6046.h index c5641dccc791d..f8c8d39305994 100644 --- a/include/zephyr/drivers/sensor/veml6046.h +++ b/include/zephyr/drivers/sensor/veml6046.h @@ -4,9 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /** * @file - * @brief Header file for extended sensor API of VEML6046 sensor + * @brief Header file for extended sensor API of VEML6046 sensor. * @ingroup veml6046_interface */ @@ -24,25 +26,6 @@ extern "C" { #endif -/** - * @brief VEML6046 integration time options for light measurements. - * - * Possible values for @ref SENSOR_ATTR_VEML6046_IT custom attribute. - */ -enum veml6046_it { - VEML6046_IT_3_125, /**< 3.125 ms */ - VEML6046_IT_6_25, /**< 6.25 ms */ - VEML6046_IT_12_5, /**< 12.5 ms */ - VEML6046_IT_25, /**< 25 ms */ - VEML6046_IT_50, /**< 50 ms */ - VEML6046_IT_100, /**< 100 ms */ - VEML6046_IT_200, /**< 200 ms */ - VEML6046_IT_400, /**< 400 ms */ - /** @cond INTERNAL_HIDDEN */ - VEML6046_IT_COUNT, - /** @endcond */ -}; - /** * @brief VEML6046 size options for light measurements. * @@ -56,33 +39,6 @@ enum veml6046_pdd { /** @endcond */ }; -/** - * @brief VEML6046 gain options for light measurements. - * - * Possible values for @ref SENSOR_ATTR_VEML6046_GAIN custom attribute. - */ -enum veml6046_gain { - VEML6046_GAIN_1 = 0x00, /**< 1x gain */ - VEML6046_GAIN_2 = 0x01, /**< 2x gain */ - VEML6046_GAIN_0_66 = 0x02, /**< 0.66x gain */ - VEML6046_GAIN_0_5 = 0x03, /**< 0.5x gain */ - /** @cond INTERNAL_HIDDEN */ - VEML6046_GAIN_COUNT = 4, - /** @endcond */ -}; - -/** - * @brief VEML6046 interrupt persistence protect number options. - * - * Possible values for @ref SENSOR_ATTR_VEML6046_PERS custom attribute. - */ -enum veml6046_pers { - VEML6046_PERS_1 = 0x00, /**< 1 measurement */ - VEML6046_PERS_2 = 0x01, /**< 2 measurements */ - VEML6046_PERS_4 = 0x02, /**< 4 measurements */ - VEML6046_PERS_8 = 0x03, /**< 8 measurements */ -}; - /** * @brief VEML6046 specific sensor attributes. * diff --git a/include/zephyr/drivers/sensor/veml60xx-common.h b/include/zephyr/drivers/sensor/veml60xx-common.h new file mode 100644 index 0000000000000..0a9aea8dea99f --- /dev/null +++ b/include/zephyr/drivers/sensor/veml60xx-common.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025 Andreas Klinger + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Header file for extended sensor API of VEML60xx sensor family + * @ingroup veml60xx_interface + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEML60XX_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEML60XX_H_ + +/** + * @defgroup veml60xx_interface VEML60XX + * @ingroup sensor_interface_ext + * @brief Vishay VEML60xx sensor family common attributes + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief VEML60xx integration time options for ambient light measurements. + * + * Possible values for @ref SENSOR_ATTR_VEML6031_IT and + * @ref SENSOR_ATTR_VEML6046_IT custom attribute. + */ +enum veml60xx_it { + VEML60XX_IT_3_125, /**< 3.125 ms */ + VEML60XX_IT_6_25, /**< 6.25 ms */ + VEML60XX_IT_12_5, /**< 12.5 ms */ + VEML60XX_IT_25, /**< 25 ms */ + VEML60XX_IT_50, /**< 50 ms */ + VEML60XX_IT_100, /**< 100 ms */ + VEML60XX_IT_200, /**< 200 ms */ + VEML60XX_IT_400, /**< 400 ms */ + /** @cond INTERNAL_HIDDEN */ + VEML60XX_IT_COUNT, + /** @endcond */ +}; + +/* + * @brief VEML60xx integration time struct. + */ +struct veml60xx_it_data { + enum veml60xx_it num; + uint8_t val; + int us; +}; + +/* + * @brief VEML60xx integration time setting values. + * + * The enumerators of enum veml60xx_it provide indices into this array to get + * the related value for the ALS_IT configuration bits. + */ +static const struct veml60xx_it_data veml60xx_it_values[VEML60XX_IT_COUNT] = { + {VEML60XX_IT_3_125, 0x00, 3125}, /* 3.125 - 0b0000 */ + {VEML60XX_IT_6_25, 0x01, 6250}, /* 6.25 - 0b0001 */ + {VEML60XX_IT_12_5, 0x02, 12500}, /* 12.5 - 0b0010 */ + {VEML60XX_IT_25, 0x03, 25000}, /* 25 - 0b0011 */ + {VEML60XX_IT_50, 0x04, 50000}, /* 50 - 0b0100 */ + {VEML60XX_IT_100, 0x05, 100000}, /* 100 - 0b0101 */ + {VEML60XX_IT_200, 0x06, 200000}, /* 200 - 0b0110 */ + {VEML60XX_IT_400, 0x07, 400000}, /* 400 - 0b0111 */ +}; +/** + * @brief VEML60xx gain options for ambient light measurements. + */ +enum veml60xx_gain { + VEML60XX_GAIN_1 = 0x00, /**< 1x gain */ + VEML60XX_GAIN_2 = 0x01, /**< 2x gain */ + VEML60XX_GAIN_0_66 = 0x02, /**< 0.66x gain */ + VEML60XX_GAIN_0_5 = 0x03, /**< 0.5x gain */ + /** @cond INTERNAL_HIDDEN */ + VEML60XX_GAIN_COUNT = 4, + /** @endcond */ +}; + +/** + * @brief VEML60xx ALS interrupt persistence protect number options. + * + * Possible values for @ref SENSOR_ATTR_VEML6031_PERS and + * @ref SENSOR_ATTR_VEML6046_PERS custom attribute. + */ +enum veml60xx_pers { + VEML60XX_PERS_1 = 0x00, /**< 1 measurement */ + VEML60XX_PERS_2 = 0x01, /**< 2 measurements */ + VEML60XX_PERS_4 = 0x02, /**< 4 measurements */ + VEML60XX_PERS_8 = 0x03, /**< 8 measurements */ +}; + + +static inline bool veml60xx_gain_in_range(int32_t gain) +{ + return (gain >= VEML60XX_GAIN_1) && (gain <= VEML60XX_GAIN_0_5); +} + +static inline bool veml60xx_it_in_range(int32_t it) +{ + return (it >= VEML60XX_IT_3_125) && (it <= VEML60XX_IT_400); +} + +static inline bool veml60xx_pers_in_range(int32_t pers) +{ + return (pers >= VEML60XX_PERS_1) && (pers <= VEML60XX_PERS_8); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_VEML60XX_H_ */ diff --git a/samples/sensor/veml6031/src/main.c b/samples/sensor/veml6031/src/main.c index 97239aa32a05d..06168918f9bf9 100644 --- a/samples/sensor/veml6031/src/main.c +++ b/samples/sensor/veml6031/src/main.c @@ -65,9 +65,9 @@ static void read_with_all_attr(const struct device *dev) { int it, div4, gain; - for (it = VEML6031_IT_3_125; it <= VEML6031_IT_400; it++) { + for (it = VEML60XX_IT_3_125; it <= VEML60XX_IT_400; it++) { for (div4 = VEML6031_SIZE_4_4; div4 <= VEML6031_SIZE_1_4; div4++) { - for (gain = VEML6031_GAIN_1; gain <= VEML6031_GAIN_0_5; gain++) { + for (gain = VEML60XX_GAIN_1; gain <= VEML60XX_GAIN_0_5; gain++) { read_with_attr(dev, it, div4, gain); } } diff --git a/samples/sensor/veml6046/src/main.c b/samples/sensor/veml6046/src/main.c index aec830e7d5177..7ac637e37f798 100644 --- a/samples/sensor/veml6046/src/main.c +++ b/samples/sensor/veml6046/src/main.c @@ -85,9 +85,9 @@ static void read_with_attr(const struct device *dev, int it, int pdd, int gain) static void read_with_all_attr(const struct device *dev) { - for (int it = VEML6046_IT_3_125; it <= VEML6046_IT_400; it++) { + for (int it = VEML60XX_IT_3_125; it <= VEML60XX_IT_400; it++) { for (int pdd = VEML6046_SIZE_2_2; pdd <= VEML6046_SIZE_1_2; pdd++) { - for (int gain = VEML6046_GAIN_1; gain <= VEML6046_GAIN_0_5; gain++) { + for (int gain = VEML60XX_GAIN_1; gain <= VEML60XX_GAIN_0_5; gain++) { read_with_attr(dev, it, pdd, gain); } } From 26f000be0f008e8955f4c5ddd495b4c08d3958a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 14 Oct 2025 11:26:28 +0200 Subject: [PATCH 394/397] doc: _scripts: capture boards' compatibles in board catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commits adds a `compatibles` field to each board entry in the board catalog, similar to the `supported_features` field. Signed-off-by: Benjamin Cabé --- doc/_scripts/gen_boards_catalog.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/_scripts/gen_boards_catalog.py b/doc/_scripts/gen_boards_catalog.py index 548576fbbb81f..5fcddddbc176f 100755 --- a/doc/_scripts/gen_boards_catalog.py +++ b/doc/_scripts/gen_boards_catalog.py @@ -290,11 +290,13 @@ def get_catalog(generate_hw_features=False, hw_features_vendor_filter=None): doc_page = guess_doc_page(board) supported_features = {} + compatibles = {} # Use pre-gathered build info and DTS files if board.name in board_devicetrees: for board_target, edt in board_devicetrees[board.name].items(): features = {} + target_compatibles = set() for node in edt.nodes: if node.binding_path is None: continue @@ -328,6 +330,7 @@ def get_catalog(generate_hw_features=False, hw_features_vendor_filter=None): locations.add("soc") existing_feature = features.get(binding_type, {}).get(node.matching_compat) + target_compatibles.add(node.matching_compat) node_info = { "filename": str(filename), @@ -354,8 +357,9 @@ def get_catalog(generate_hw_features=False, hw_features_vendor_filter=None): features.setdefault(binding_type, {})[node.matching_compat] = feature_data - # Store features for this specific target + # Store features and compatibles for this specific target supported_features[board_target] = features + compatibles[board_target] = list(target_compatibles) board_runner_info = {} if board.name in board_runners: @@ -392,6 +396,7 @@ def get_catalog(generate_hw_features=False, hw_features_vendor_filter=None): "socs": list(socs), "revision_default": board.revision_default, "supported_features": supported_features, + "compatibles": compatibles, "image": guess_image(board), # runners "supported_runners": board_runner_info.get("runners", []), From 18d80831484cccc49114ac73bea15cecb0e23fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 16 Oct 2025 10:37:21 +0200 Subject: [PATCH 395/397] doc: _extensions: make tag handling for supported HW caps more generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There might be different UI widgets that deal with tags so make sure that we use identifiers and selectors that are not too generic. Signed-off-by: Benjamin Cabé --- .../zephyr/domain/static/js/board-catalog.js | 33 +++++++++++-------- .../domain/templates/board-catalog.html | 8 ++--- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/doc/_extensions/zephyr/domain/static/js/board-catalog.js b/doc/_extensions/zephyr/domain/static/js/board-catalog.js index 3d433d237e220..37eb68588047b 100644 --- a/doc/_extensions/zephyr/domain/static/js/board-catalog.js +++ b/doc/_extensions/zephyr/domain/static/js/board-catalog.js @@ -41,15 +41,21 @@ function populateFormFromURL() { const features = hashParams.get("features").split(","); setTimeout(() => { features.forEach(feature => { - const tagContainer = document.getElementById('tag-container'); - const tagInput = document.getElementById('tag-input'); + const tagContainer = document.getElementById('hwcaps-tags'); + const tagInput = document.getElementById('hwcaps-input'); const tagElement = document.createElement('span'); tagElement.classList.add('tag'); tagElement.textContent = feature; tagElement.onclick = () => { - const selectedTags = [...document.querySelectorAll('.tag')].map(tag => tag.textContent); - selectedTags.splice(selectedTags.indexOf(feature), 1); + tagElement.remove(); + filterBoards(); + }; + tagContainer.insertBefore(tagElement, tagInput); + }); + filterBoards(); + }, 0); + } tagElement.remove(); filterBoards(); }; @@ -83,8 +89,8 @@ function updateURL() { }); // Add supported features to URL - const selectedTags = [...document.querySelectorAll('.tag')].map(tag => tag.textContent); - selectedTags.length ? hashParams.set("features", selectedTags.join(",")) : hashParams.delete("features"); + const selectedHWTags = [...document.querySelectorAll('#hwcaps-tags .tag')].map(tag => tag.textContent); + selectedHWTags.length ? hashParams.set("features", selectedHWTags.join(",")) : hashParams.delete("features"); window.history.replaceState({}, "", `#${hashParams.toString()}`); } @@ -126,8 +132,8 @@ function fillSocSocSelect(families, series = undefined, selectOnFill = false) { function setupHWCapabilitiesField() { let selectedTags = []; - const tagContainer = document.getElementById('tag-container'); - const tagInput = document.getElementById('tag-input'); + const tagContainer = document.getElementById('hwcaps-tags'); + const tagInput = document.getElementById('hwcaps-input'); const datalist = document.getElementById('tag-list'); const tagCounts = Array.from(document.querySelectorAll('.board-card')).reduce((acc, board) => { @@ -272,8 +278,8 @@ function resetForm() { document.getElementById("show-shields").checked = true; // Clear supported features - document.querySelectorAll('.tag').forEach(tag => tag.remove()); - document.getElementById('tag-input').value = ''; + document.querySelectorAll('#hwcaps-tags .tag').forEach(tag => tag.remove()); + document.getElementById('hwcaps-input').value = ''; filterBoards(); } @@ -297,10 +303,11 @@ function filterBoards() { const showBoards = document.getElementById("show-boards").checked; const showShields = document.getElementById("show-shields").checked; - const selectedTags = [...document.querySelectorAll('.tag')].map(tag => tag.textContent); + // Get selected hardware capability tags + const selectedHWTags = [...document.querySelectorAll('#hwcaps-tags .tag')].map(tag => tag.textContent); const resetFiltersBtn = document.getElementById("reset-filters"); - if (nameInput || archSelect || vendorSelect || socSocSelect.selectedOptions.length || selectedTags.length || !showBoards || !showShields) { + if (nameInput || archSelect || vendorSelect || socSocSelect.selectedOptions.length || selectedHWTags.length || !showBoards || !showShields) { resetFiltersBtn.classList.remove("btn-disabled"); } else { resetFiltersBtn.classList.add("btn-disabled"); @@ -328,7 +335,7 @@ function filterBoards() { !(archSelect && !boardArchs.includes(archSelect)) && !(vendorSelect && boardVendor !== vendorSelect) && (selectedSocs.length === 0 || selectedSocs.some((soc) => boardSocs.includes(soc))) && - (selectedTags.length === 0 || selectedTags.every((tag) => boardSupportedFeatures.includes(tag))); + (selectedHWTags.length === 0 || selectedHWTags.every((tag) => boardSupportedFeatures.includes(tag))); } board.classList.toggle("hidden", !matches); diff --git a/doc/_extensions/zephyr/domain/templates/board-catalog.html b/doc/_extensions/zephyr/domain/templates/board-catalog.html index 32918c97e04dc..54ee28cb52ccf 100644 --- a/doc/_extensions/zephyr/domain/templates/board-catalog.html +++ b/doc/_extensions/zephyr/domain/templates/board-catalog.html @@ -76,11 +76,11 @@

- -
- Supported Hardware Capabilities +
+ Date: Thu, 16 Oct 2025 10:38:13 +0200 Subject: [PATCH 396/397] doc: _extensions: allow to filter boards by compatible strings in catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the ability to filter boards in the catalog by compatible strings. It supports wildcards so e.g. one can quickly find all boards with an "st,lsm*" accelerometer. Signed-off-by: Benjamin Cabé --- .../domain/static/css/board-catalog.css | 4 + .../zephyr/domain/static/js/board-catalog.js | 121 +++++++++++++++++- .../zephyr/domain/templates/board-card.html | 14 +- .../domain/templates/board-catalog.html | 14 ++ 4 files changed, 150 insertions(+), 3 deletions(-) diff --git a/doc/_extensions/zephyr/domain/static/css/board-catalog.css b/doc/_extensions/zephyr/domain/static/css/board-catalog.css index e37c78537d137..8a13b3b183ebd 100644 --- a/doc/_extensions/zephyr/domain/static/css/board-catalog.css +++ b/doc/_extensions/zephyr/domain/static/css/board-catalog.css @@ -106,6 +106,10 @@ margin-right: 8px; } +#compatibles-tags .tag { + font-family: var(--monospace-font-family); +} + .tag:hover { background-color: #0056b3; } diff --git a/doc/_extensions/zephyr/domain/static/js/board-catalog.js b/doc/_extensions/zephyr/domain/static/js/board-catalog.js index 37eb68588047b..94312793bafaa 100644 --- a/doc/_extensions/zephyr/domain/static/js/board-catalog.js +++ b/doc/_extensions/zephyr/domain/static/js/board-catalog.js @@ -56,6 +56,19 @@ function populateFormFromURL() { filterBoards(); }, 0); } + + // Restore compatibles from URL + if (hashParams.has("compatibles")) { + const compatibles = hashParams.get("compatibles").split("|"); + setTimeout(() => { + compatibles.forEach(compatible => { + const tagContainer = document.getElementById('compatibles-tags'); + const tagInput = document.getElementById('compatibles-input'); + + const tagElement = document.createElement('span'); + tagElement.classList.add('tag'); + tagElement.textContent = compatible; + tagElement.onclick = () => { tagElement.remove(); filterBoards(); }; @@ -92,6 +105,10 @@ function updateURL() { const selectedHWTags = [...document.querySelectorAll('#hwcaps-tags .tag')].map(tag => tag.textContent); selectedHWTags.length ? hashParams.set("features", selectedHWTags.join(",")) : hashParams.delete("features"); + // Add compatibles to URL + const selectedCompatibles = [...document.querySelectorAll('#compatibles-tags .tag')].map(tag => tag.textContent); + selectedCompatibles.length ? hashParams.set("compatibles", selectedCompatibles.join("|")) : hashParams.delete("compatibles"); + window.history.replaceState({}, "", `#${hashParams.toString()}`); } @@ -204,6 +221,80 @@ function setupHWCapabilitiesField() { updateDatalist(); } +function setupCompatiblesField() { + let selectedCompatibles = []; + + const tagContainer = document.getElementById('compatibles-tags'); + const tagInput = document.getElementById('compatibles-input'); + const datalist = document.getElementById('compatibles-list'); + + // Collect all unique compatibles from boards + const allCompatibles = Array.from(document.querySelectorAll('.board-card')).reduce((acc, board) => { + (board.getAttribute('data-compatibles') || '').split(' ').forEach(compat => { + if (compat && !acc.includes(compat)) { + acc.push(compat); + } + }); + return acc; + }, []); + + allCompatibles.sort(); + + function addCompatible(compatible) { + if (selectedCompatibles.includes(compatible) || compatible === "") return; + selectedCompatibles.push(compatible); + + const tagElement = document.createElement('span'); + tagElement.classList.add('tag'); + tagElement.textContent = compatible; + tagElement.onclick = () => removeCompatible(compatible); + tagContainer.insertBefore(tagElement, tagInput); + + tagInput.value = ''; + updateDatalist(); + } + + function removeCompatible(compatible) { + selectedCompatibles = selectedCompatibles.filter(c => c !== compatible); + document.querySelectorAll('.tag').forEach(el => { + if (el.textContent === compatible && el.parentElement === tagContainer) { + el.remove(); + } + }); + updateDatalist(); + } + + function updateDatalist() { + datalist.innerHTML = ''; + const filteredCompatibles = allCompatibles.filter(c => !selectedCompatibles.includes(c)); + + filteredCompatibles.forEach(compatible => { + const option = document.createElement('option'); + option.value = compatible; + datalist.appendChild(option); + }); + + filterBoards(); + } + + tagInput.addEventListener('input', () => { + if (allCompatibles.includes(tagInput.value)) { + addCompatible(tagInput.value); + } + }); + + tagInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter' && tagInput.value) { + addCompatible(tagInput.value); + e.preventDefault(); + } else if (e.key === 'Backspace' && tagInput.value === '' && selectedCompatibles.length > 0) { + removeCompatible(selectedCompatibles[selectedCompatibles.length - 1]); + } + }); + + updateDatalist(); +} + document.addEventListener("DOMContentLoaded", function () { const form = document.querySelector(".filter-form"); @@ -224,6 +315,7 @@ document.addEventListener("DOMContentLoaded", function () { populateFormFromURL(); setupHWCapabilitiesField(); + setupCompatiblesField(); socFamilySelect = document.getElementById("family"); socFamilySelect.addEventListener("change", () => { @@ -281,6 +373,10 @@ function resetForm() { document.querySelectorAll('#hwcaps-tags .tag').forEach(tag => tag.remove()); document.getElementById('hwcaps-input').value = ''; + // Clear compatibles + document.querySelectorAll('#compatibles-tags .tag').forEach(tag => tag.remove()); + document.getElementById('compatibles-input').value = ''; + filterBoards(); } @@ -295,6 +391,16 @@ function updateBoardCount() { + ` ${visibleShields.length} of ${shields.length} shields`; } +function wildcardMatch(pattern, str) { + // Convert wildcard pattern to regex + // Escape special regex characters except * + const regexPattern = pattern + .replace(/[.+?^${}()|[\]\\]/g, '\\$&') + .replace(/\*/g, '.*'); + const regex = new RegExp(`^${regexPattern}$`, "i"); + return regex.test(str); +} + function filterBoards() { const nameInput = document.getElementById("name").value.toLowerCase(); const archSelect = document.getElementById("arch").value; @@ -306,8 +412,11 @@ function filterBoards() { // Get selected hardware capability tags const selectedHWTags = [...document.querySelectorAll('#hwcaps-tags .tag')].map(tag => tag.textContent); + // Get selected compatible tags + const selectedCompatibles = [...document.querySelectorAll('#compatibles-tags .tag')].map(tag => tag.textContent); + const resetFiltersBtn = document.getElementById("reset-filters"); - if (nameInput || archSelect || vendorSelect || socSocSelect.selectedOptions.length || selectedHWTags.length || !showBoards || !showShields) { + if (nameInput || archSelect || vendorSelect || socSocSelect.selectedOptions.length || selectedHWTags.length || selectedCompatibles.length || !showBoards || !showShields) { resetFiltersBtn.classList.remove("btn-disabled"); } else { resetFiltersBtn.classList.add("btn-disabled"); @@ -321,6 +430,7 @@ function filterBoards() { const boardVendor = board.getAttribute("data-vendor") || ""; const boardSocs = (board.getAttribute("data-socs") || "").split(" ").filter(Boolean); const boardSupportedFeatures = (board.getAttribute("data-supported-features") || "").split(" ").filter(Boolean); + const boardCompatibles = (board.getAttribute("data-compatibles") || "").split(" ").filter(Boolean); const isShield = board.classList.contains("shield"); let matches = true; @@ -330,12 +440,19 @@ function filterBoards() { if ((isShield && !showShields) || (!isShield && !showBoards)) { matches = false; } else { + // Check if board matches all selected compatibles (with wildcard support) + const compatiblesMatch = selectedCompatibles.length === 0 || + selectedCompatibles.every((pattern) => + boardCompatibles.some((compatible) => wildcardMatch(pattern, compatible)) + ); + matches = !(nameInput && !boardName.includes(nameInput)) && !(archSelect && !boardArchs.includes(archSelect)) && !(vendorSelect && boardVendor !== vendorSelect) && (selectedSocs.length === 0 || selectedSocs.some((soc) => boardSocs.includes(soc))) && - (selectedHWTags.length === 0 || selectedHWTags.every((tag) => boardSupportedFeatures.includes(tag))); + (selectedHWTags.length === 0 || selectedHWTags.every((tag) => boardSupportedFeatures.includes(tag))) && + compatiblesMatch; } board.classList.toggle("hidden", !matches); diff --git a/doc/_extensions/zephyr/domain/templates/board-card.html b/doc/_extensions/zephyr/domain/templates/board-card.html index 0e4808b85a74f..961048e2e9285 100644 --- a/doc/_extensions/zephyr/domain/templates/board-card.html +++ b/doc/_extensions/zephyr/domain/templates/board-card.html @@ -25,7 +25,19 @@ {%- endfor -%} {%- endfor -%} {{- feature_types|join(' ') -}} - " tabindex="0"> + " + data-compatibles=" + {%- set all_compatibles = [] -%} + {%- for target_compatibles in board.compatibles.values() -%} + {%- for compatible in target_compatibles -%} + {%- if compatible not in all_compatibles -%} + {%- set _ = all_compatibles.append(compatible) -%} + {%- endif -%} + {%- endfor -%} + {%- endfor -%} + {{- all_compatibles|join(' ') -}} + " + tabindex="0">
{{ vendors[board.vendor] }}
{% if board.image -%} A picture of the {{ board.full_name }} board
+
+ +
+ + +
+
+
From 2e94b80307f50fac4fdf8164852157419dd977ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 16 Oct 2025 12:10:06 +0200 Subject: [PATCH 397/397] doc: scripts: gen_devicetree_rest: add link to board catalog in sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a link to the board catalog in the sidebar of each binding page, directing users to boards using the compatible. Signed-off-by: Benjamin Cabé --- doc/_scripts/gen_devicetree_rest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/_scripts/gen_devicetree_rest.py b/doc/_scripts/gen_devicetree_rest.py index 9287411b72528..2d12a79587184 100644 --- a/doc/_scripts/gen_devicetree_rest.py +++ b/doc/_scripts/gen_devicetree_rest.py @@ -505,6 +505,8 @@ def make_sidebar(compatible, vendor_name, vendor_ref_target, driver_path=None): "", f" :Name: ``{compatible}``", f" :Vendor: :ref:`{vendor_name} <{vendor_ref_target}>`", + f" :Used in: :zephyr:board-catalog:`List of boards <#compatibles={compatible}>` using", + " this compatible", ] if driver_path: lines.append(f" :Driver: :zephyr_file:`{driver_path}`")